From 32caf51b474892b8a9a8d5b882202ce9ad749af5 Mon Sep 17 00:00:00 2001 From: Tim Davis Date: Tue, 30 Jan 2024 17:51:29 -0600 Subject: [PATCH] SPEX 3.1.0: major API revision from SPEX 2.x; many more features (Cholesky & Backslash) --- ChangeLog | 29 + Example/CMakeLists.txt | 8 +- Example/Include/my.h | 4 +- Example/Source/my.c | 3 +- Example/Source/my_cxx.cc | 3 +- README.md | 2 +- SPEX/CMakeLists.txt | 153 +- SPEX/Config/SPEX.h.in | 1176 +- SPEX/Config/Tcov_Makefile.in | 271 + SPEX/Config/spex_deps.m.in | 22 + .../Utilities/spex_demo_check_solution.c} | 100 +- .../Utilities/spex_demo_determine_error.c | 35 + .../spex_demo_process_command_line.c | 133 + SPEX/Demo/Utilities/spex_demo_read_dense.c | 72 + SPEX/Demo/Utilities/spex_demo_tripread.c | 130 + SPEX/Demo/spex_demo_backslash.c | 123 + SPEX/Demo/spex_demo_cholesky_extended.c | 152 + SPEX/Demo/spex_demo_cholesky_simple.c | 145 + SPEX/Demo/spex_demo_lu_doub.c | 234 + .../spex_demo_lu_extended.c} | 209 +- .../example.c => Demo/spex_demo_lu_simple1.c} | 75 +- .../spex_demo_lu_simple2.c} | 96 +- SPEX/Demo/spex_demo_threaded.c | 183 + SPEX/Demo/spex_demos.h | 95 + SPEX/Doc/ChangeLog | 46 +- SPEX/Doc/Makefile | 5 +- SPEX/Doc/SPEX_UserGuide.bib | 12 + SPEX/Doc/SPEX_UserGuide.pdf | Bin 335801 -> 381370 bytes SPEX/Doc/SPEX_UserGuide.tex | 3906 ++- SPEX/Doc/SPEX_version.tex | 2 +- SPEX/Doc/appendix_A.pdf | Bin 0 -> 100257 bytes SPEX/Doc/appendix_A.tex | 426 + .../10teams.mat.txt} | 0 .../10teams.rhs.txt} | 0 SPEX/ExampleMats/494_bus.mat.txt | 1667 + SPEX/ExampleMats/494_bus.rhs.txt | 495 + SPEX/ExampleMats/LF10.mat.txt | 83 + SPEX/ExampleMats/LFAT5.mat.txt | 47 + .../NSR8K.mat.txt} | 0 .../NSR8K_v.txt => ExampleMats/NSR8K.rhs.txt} | 0 SPEX/ExampleMats/README.txt | 49 + SPEX/ExampleMats/Trefethen_500.mat.txt | 8479 +++++ SPEX/ExampleMats/Trefethen_500.rhs.txt | 501 + SPEX/ExampleMats/example.mat.txt | 9 + SPEX/ExampleMats/example.rhs.txt | 9 + SPEX/ExampleMats/mesh1e1.mat.txt | 307 + SPEX/ExampleMats/mesh1e1.rhs.txt | 49 + .../test_mat.txt => ExampleMats/test.mat.txt} | 0 .../test_rhs.txt => ExampleMats/test.rhs.txt} | 0 SPEX/ExampleMats/test1.mat.txt | 2 + SPEX/ExampleMats/test2.mat.txt | 4 + SPEX/ExampleMats/test3.mat.txt | 3 + SPEX/ExampleMats/test4.mat.txt | 3 + SPEX/ExampleMats/test5.mat.txt | 2 + SPEX/ExampleMats/tomography.mat | 28727 ++++++++++++++++ SPEX/ExampleMats/tomography.rhs | 501 + SPEX/Include/SPEX.h | 1186 +- SPEX/LICENSE.txt | 14 +- SPEX/MATLAB/.gitignore | 3 + SPEX/MATLAB/Source/SPEX_mex.h | 131 + SPEX/MATLAB/Source/spex_mex_check_for_inf.c | 67 + SPEX/MATLAB/Source/spex_mex_error.c | 52 + .../Source/spex_mex_get_A_and_b.c} | 68 +- .../Source/spex_mex_get_matlab_options.c} | 65 +- SPEX/MATLAB/spex_backslash.m | 132 + SPEX/MATLAB/spex_backslash_mex_soln.c | 181 + SPEX/MATLAB/spex_cholesky_backslash.m | 133 + SPEX/MATLAB/spex_cholesky_mex_soln.c | 182 + .../spex_lu_backslash.m} | 22 +- .../spex_lu_mex_soln.c} | 93 +- SPEX/MATLAB/spex_mex_demo.m | 159 + SPEX/MATLAB/spex_mex_install.m | 128 + SPEX/MATLAB/spex_mex_test.m | 224 + SPEX/Makefile | 25 +- SPEX/Python/.gitignore | 7 + SPEX/Python/SPEXpy/Options.py | 47 + SPEX/Python/SPEXpy/SPEX_error.py | 25 + .../SPEXpy/Source/spex_python_connect.c | 168 + .../SPEXpy/Source/spex_python_connect.h | 30 + SPEX/Python/SPEXpy/__init__.py | 33 + SPEX/Python/SPEXpy/backslash.py | 43 + SPEX/Python/SPEXpy/cholesky_backslash.py | 49 + SPEX/Python/SPEXpy/lu_backslash.py | 45 + SPEX/Python/SPEXpy/setup.py | 15 + SPEX/Python/SPEXpy/spex_connect.py | 80 + SPEX/Python/SPEXpy/spex_matrix_from_file.py | 37 + SPEX/Python/spex_python_demo.py | 72 + SPEX/README.md | 74 +- .../License/CONTRIBUTOR-LICENSE.txt | 9 +- .../License/GPLv2.txt | 0 .../License/lesserv3.txt | 0 .../License/license.txt | 7 +- SPEX/SPEX_Backslash/README.md | 14 + SPEX/SPEX_Backslash/Source/SPEX_backslash.c | 163 + .../License/CONTRIBUTOR-LICENSE.txt | 169 + .../License/GPLv2.txt | 0 .../License/lesserv3.txt | 0 SPEX/SPEX_Cholesky/License/license.txt | 39 + SPEX/SPEX_Cholesky/README.txt | 16 + .../Source/SPEX_cholesky_analyze.c | 112 + .../Source/SPEX_cholesky_backslash.c | 180 + .../Source/SPEX_cholesky_factorize.c | 112 + .../Source/SPEX_cholesky_solve.c | 156 + .../Source/spex_cholesky_backward_sub.c | 70 + .../Source/spex_cholesky_counts.c | 124 + .../Source/spex_cholesky_ereach.c | 67 + .../Source/spex_cholesky_etree.c | 79 + .../Source/spex_cholesky_factor.c | 141 + .../Source/spex_cholesky_forward_sub.c | 190 + .../Source/spex_cholesky_internal.h | 355 + .../SPEX_Cholesky/Source/spex_cholesky_leaf.c | 62 + .../Source/spex_cholesky_left_factor.c | 244 + .../spex_cholesky_left_triangular_solve.c | 345 + .../Source/spex_cholesky_permute_A.c | 134 + .../SPEX_Cholesky/Source/spex_cholesky_post.c | 77 + .../Source/spex_cholesky_pre_left_factor.c | 127 + .../Source/spex_cholesky_preorder.c | 185 + .../Source/spex_cholesky_symbolic_analysis.c | 93 + .../SPEX_Cholesky/Source/spex_cholesky_tdfs.c | 46 + .../Source/spex_cholesky_up_factor.c | 259 + .../spex_cholesky_up_triangular_solve.c | 309 + .../License/CONTRIBUTOR-LICENSE.txt | 8 +- SPEX/SPEX_LU/License/GPLv2.txt | 339 + SPEX/SPEX_LU/License/lesserv3.txt | 165 + .../License/license.txt | 9 +- SPEX/{SPEX_Left_LU => SPEX_LU}/README.md | 31 +- SPEX/SPEX_LU/Source/SPEX_lu_analyze.c | 160 + .../Source/SPEX_lu_backslash.c} | 94 +- .../Source/SPEX_lu_factorize.c} | 185 +- SPEX/SPEX_LU/Source/SPEX_lu_solve.c | 142 + .../Source/spex_left_lu_back_sub.c | 31 +- .../Source/spex_left_lu_dfs.c | 24 +- .../Source/spex_left_lu_forward_sub.c | 85 +- .../Source/spex_left_lu_get_largest_pivot.c | 24 +- .../Source/spex_left_lu_get_nonzero_pivot.c | 26 +- .../Source/spex_left_lu_get_pivot.c | 144 +- .../Source/spex_left_lu_get_smallest_pivot.c | 28 +- .../Source/spex_left_lu_reach.c | 20 +- .../spex_left_lu_ref_triangular_solve.c | 106 +- SPEX/SPEX_LU/Source/spex_lu_internal.h | 183 + SPEX/SPEX_Left_LU/Demo/.gitignore | 7 - SPEX/SPEX_Left_LU/Demo/demos.c | 464 - SPEX/SPEX_Left_LU/Demo/demos.h | 76 - SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_demo.m | 109 - .../MATLAB/SPEX_Left_LU_install.m | 85 - SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_test.m | 89 - .../MATLAB/Source/SPEX_Left_LU_mex.h | 94 - .../Source/spex_left_lu_mex_check_for_inf.c | 58 - .../MATLAB/Source/spex_left_lu_mex_error.c | 52 - SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_solve.c | 176 - .../Source/spex_left_lu_internal.h | 199 - .../Source/spex_left_lu_permute_b.c | 68 - .../Source/spex_left_lu_permute_x.c | 69 - SPEX/SPEX_Left_LU/Tcov/.gitignore | 56 - SPEX/SPEX_Left_LU/Tcov/Makefile | 160 - SPEX/SPEX_Left_LU/Tcov/covall | 7 - SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.c | 94 - SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.h | 88 - SPEX/SPEX_Util/Source/SPEX_LU_analysis_free.c | 35 - SPEX/SPEX_Util/Source/SPEX_LU_analyze.c | 187 - SPEX/SPEX_Util/Source/SPEX_finalize.c | 28 - SPEX/SPEX_Util/Source/SPEX_gmp.h | 99 - SPEX/SPEX_Util/Source/SPEX_initialize.c | 48 - SPEX/SPEX_Util/Source/SPEX_matrix_div.c | 86 - SPEX/SPEX_Util/Source/SPEX_matrix_free.c | 114 - SPEX/SPEX_Util/Source/SPEX_version.c | 19 - .../SPEX_Util/Source/spex_expand_mpfr_array.c | 65 - SPEX/SPEX_Util/Source/spex_expand_mpq_array.c | 62 - .../License/CONTRIBUTOR-LICENSE.txt | 170 + SPEX/SPEX_Utilities/License/GPLv2.txt | 339 + SPEX/SPEX_Utilities/License/lesserv3.txt | 165 + SPEX/SPEX_Utilities/License/license.txt | 41 + SPEX/{SPEX_Util => SPEX_Utilities}/README.md | 7 +- .../Source/SPEX_calloc.c | 10 +- .../Source/SPEX_create_default_options.c | 32 +- .../Source/SPEX_determine_symmetry.c | 114 + .../Source/SPEX_factorization_free.c | 48 + SPEX/SPEX_Utilities/Source/SPEX_finalize.c | 34 + .../Source/SPEX_free.c | 9 +- .../Source/SPEX_gmp.c | 1117 +- SPEX/SPEX_Utilities/Source/SPEX_initialize.c | 62 + .../Source/SPEX_initialize_expert.c | 37 +- .../Source/SPEX_malloc.c | 11 +- .../Source/SPEX_matrix_allocate.c | 113 +- .../Source/SPEX_matrix_check.c | 235 +- .../Source/SPEX_matrix_copy.c | 225 +- SPEX/SPEX_Utilities/Source/SPEX_matrix_free.c | 113 + .../Source/SPEX_matrix_nnz.c | 39 +- .../Source/SPEX_realloc.c | 30 +- .../Source/SPEX_symbolic_analysis_free.c | 45 + .../Source/SPEX_thread_finalize.c | 23 + .../Source/SPEX_thread_initialize.c | 22 + SPEX/SPEX_Utilities/Source/SPEX_transpose.c | 106 + SPEX/SPEX_Utilities/Source/SPEX_version.c | 38 + SPEX/SPEX_Utilities/Source/spex_amd.c | 76 + .../Source/spex_cast_array.c | 111 +- .../Source/spex_cast_matrix.c | 31 +- SPEX/SPEX_Utilities/Source/spex_colamd.c | 101 + .../Source/spex_create_mpfr_array.c | 26 +- SPEX/SPEX_Utilities/Source/spex_create_mpq.c | 37 + .../Source/spex_create_mpq_array.c | 20 +- .../Source/spex_create_mpz_array.c | 27 +- .../Source/spex_cumsum.c} | 14 +- .../Source/spex_expand_double_array.c | 82 +- .../Source/spex_expand_mpfr_array.c | 135 + .../Source/spex_expand_mpq_array.c | 56 + SPEX/SPEX_Utilities/Source/spex_gmp.h | 246 + .../Source/spex_matrix_mul.c} | 22 +- .../Source/spex_permute_dense_matrix.c | 70 + .../Source/spex_sparse_collapse.c | 17 +- .../Source/spex_sparse_realloc.c | 21 +- .../Source/spex_util_internal.h | 465 +- SPEX/{SPEX_Left_LU => }/Tcov/README.txt | 6 +- SPEX/{SPEX_Left_LU => }/Tcov/cov.awk | 0 SPEX/Tcov/covall | 6 + SPEX/{SPEX_Left_LU => }/Tcov/cover | 0 SPEX/{SPEX_Left_LU => }/Tcov/covs | 0 SPEX/{SPEX_Left_LU => }/Tcov/gcovs | 4 +- SPEX/Tcov/simple_rand.c | 64 + SPEX/Tcov/simple_rand.h | 34 + SPEX/Tcov/tcov_for_cholesky.c | 564 + .../Tcov/tcov_test.c => Tcov/tcov_for_lu.c} | 473 +- SPEX/Tcov/tcov_for_lu2.c | 183 + SPEX/Tcov/tcov_utilities.c | 245 + SPEX/Tcov/tcov_utilities.h | 164 + SPEX/cmake_modules/FindGMP.cmake | 177 +- SPEX/cmake_modules/FindMPFR.cmake | 151 +- SuiteSparse_config/CMakeLists.txt | 4 +- SuiteSparse_config/SuiteSparse_config.h | 8 +- 229 files changed, 60090 insertions(+), 7494 deletions(-) create mode 100644 SPEX/Config/Tcov_Makefile.in create mode 100644 SPEX/Config/spex_deps.m.in rename SPEX/{SPEX_Util/Source/SPEX_check_solution.c => Demo/Utilities/spex_demo_check_solution.c} (51%) create mode 100644 SPEX/Demo/Utilities/spex_demo_determine_error.c create mode 100644 SPEX/Demo/Utilities/spex_demo_process_command_line.c create mode 100644 SPEX/Demo/Utilities/spex_demo_read_dense.c create mode 100644 SPEX/Demo/Utilities/spex_demo_tripread.c create mode 100644 SPEX/Demo/spex_demo_backslash.c create mode 100644 SPEX/Demo/spex_demo_cholesky_extended.c create mode 100644 SPEX/Demo/spex_demo_cholesky_simple.c create mode 100644 SPEX/Demo/spex_demo_lu_doub.c rename SPEX/{SPEX_Left_LU/Demo/spexlu_demo.c => Demo/spex_demo_lu_extended.c} (65%) rename SPEX/{SPEX_Left_LU/Demo/example.c => Demo/spex_demo_lu_simple1.c} (67%) rename SPEX/{SPEX_Left_LU/Demo/example2.c => Demo/spex_demo_lu_simple2.c} (59%) create mode 100644 SPEX/Demo/spex_demo_threaded.c create mode 100644 SPEX/Demo/spex_demos.h create mode 100644 SPEX/Doc/appendix_A.pdf create mode 100644 SPEX/Doc/appendix_A.tex rename SPEX/{SPEX_Left_LU/ExampleMats/10teams_mat.txt => ExampleMats/10teams.mat.txt} (100%) rename SPEX/{SPEX_Left_LU/ExampleMats/10teams_v.txt => ExampleMats/10teams.rhs.txt} (100%) create mode 100644 SPEX/ExampleMats/494_bus.mat.txt create mode 100644 SPEX/ExampleMats/494_bus.rhs.txt create mode 100644 SPEX/ExampleMats/LF10.mat.txt create mode 100644 SPEX/ExampleMats/LFAT5.mat.txt rename SPEX/{SPEX_Left_LU/ExampleMats/NSR8K_mat.txt => ExampleMats/NSR8K.mat.txt} (100%) rename SPEX/{SPEX_Left_LU/ExampleMats/NSR8K_v.txt => ExampleMats/NSR8K.rhs.txt} (100%) create mode 100644 SPEX/ExampleMats/README.txt create mode 100644 SPEX/ExampleMats/Trefethen_500.mat.txt create mode 100644 SPEX/ExampleMats/Trefethen_500.rhs.txt create mode 100644 SPEX/ExampleMats/example.mat.txt create mode 100644 SPEX/ExampleMats/example.rhs.txt create mode 100644 SPEX/ExampleMats/mesh1e1.mat.txt create mode 100644 SPEX/ExampleMats/mesh1e1.rhs.txt rename SPEX/{SPEX_Left_LU/ExampleMats/test_mat.txt => ExampleMats/test.mat.txt} (100%) rename SPEX/{SPEX_Left_LU/ExampleMats/test_rhs.txt => ExampleMats/test.rhs.txt} (100%) create mode 100644 SPEX/ExampleMats/test1.mat.txt create mode 100644 SPEX/ExampleMats/test2.mat.txt create mode 100644 SPEX/ExampleMats/test3.mat.txt create mode 100644 SPEX/ExampleMats/test4.mat.txt create mode 100644 SPEX/ExampleMats/test5.mat.txt create mode 100644 SPEX/ExampleMats/tomography.mat create mode 100644 SPEX/ExampleMats/tomography.rhs create mode 100644 SPEX/MATLAB/.gitignore create mode 100644 SPEX/MATLAB/Source/SPEX_mex.h create mode 100644 SPEX/MATLAB/Source/spex_mex_check_for_inf.c create mode 100644 SPEX/MATLAB/Source/spex_mex_error.c rename SPEX/{SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_get_A_and_b.c => MATLAB/Source/spex_mex_get_A_and_b.c} (70%) rename SPEX/{SPEX_Left_LU/MATLAB/Source/spex_left_lu_get_matlab_options.c => MATLAB/Source/spex_mex_get_matlab_options.c} (77%) create mode 100644 SPEX/MATLAB/spex_backslash.m create mode 100644 SPEX/MATLAB/spex_backslash_mex_soln.c create mode 100644 SPEX/MATLAB/spex_cholesky_backslash.m create mode 100644 SPEX/MATLAB/spex_cholesky_mex_soln.c rename SPEX/{SPEX_Left_LU/MATLAB/SPEX_Left_LU_backslash.m => MATLAB/spex_lu_backslash.m} (87%) rename SPEX/{SPEX_Left_LU/MATLAB/SPEX_Left_LU_mex_soln.c => MATLAB/spex_lu_mex_soln.c} (65%) create mode 100644 SPEX/MATLAB/spex_mex_demo.m create mode 100644 SPEX/MATLAB/spex_mex_install.m create mode 100644 SPEX/MATLAB/spex_mex_test.m create mode 100644 SPEX/Python/.gitignore create mode 100644 SPEX/Python/SPEXpy/Options.py create mode 100644 SPEX/Python/SPEXpy/SPEX_error.py create mode 100644 SPEX/Python/SPEXpy/Source/spex_python_connect.c create mode 100644 SPEX/Python/SPEXpy/Source/spex_python_connect.h create mode 100644 SPEX/Python/SPEXpy/__init__.py create mode 100644 SPEX/Python/SPEXpy/backslash.py create mode 100644 SPEX/Python/SPEXpy/cholesky_backslash.py create mode 100644 SPEX/Python/SPEXpy/lu_backslash.py create mode 100644 SPEX/Python/SPEXpy/setup.py create mode 100644 SPEX/Python/SPEXpy/spex_connect.py create mode 100644 SPEX/Python/SPEXpy/spex_matrix_from_file.py create mode 100644 SPEX/Python/spex_python_demo.py rename SPEX/{SPEX_Util => SPEX_Backslash}/License/CONTRIBUTOR-LICENSE.txt (97%) rename SPEX/{SPEX_Left_LU => SPEX_Backslash}/License/GPLv2.txt (100%) rename SPEX/{SPEX_Left_LU => SPEX_Backslash}/License/lesserv3.txt (100%) rename SPEX/{SPEX_Util => SPEX_Backslash}/License/license.txt (88%) create mode 100644 SPEX/SPEX_Backslash/README.md create mode 100644 SPEX/SPEX_Backslash/Source/SPEX_backslash.c create mode 100644 SPEX/SPEX_Cholesky/License/CONTRIBUTOR-LICENSE.txt rename SPEX/{SPEX_Util => SPEX_Cholesky}/License/GPLv2.txt (100%) rename SPEX/{SPEX_Util => SPEX_Cholesky}/License/lesserv3.txt (100%) create mode 100644 SPEX/SPEX_Cholesky/License/license.txt create mode 100644 SPEX/SPEX_Cholesky/README.txt create mode 100644 SPEX/SPEX_Cholesky/Source/SPEX_cholesky_analyze.c create mode 100644 SPEX/SPEX_Cholesky/Source/SPEX_cholesky_backslash.c create mode 100644 SPEX/SPEX_Cholesky/Source/SPEX_cholesky_factorize.c create mode 100644 SPEX/SPEX_Cholesky/Source/SPEX_cholesky_solve.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_backward_sub.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_counts.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_ereach.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_etree.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_factor.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_forward_sub.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_internal.h create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_leaf.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_left_factor.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_left_triangular_solve.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_permute_A.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_post.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_pre_left_factor.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_preorder.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_symbolic_analysis.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_tdfs.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_up_factor.c create mode 100644 SPEX/SPEX_Cholesky/Source/spex_cholesky_up_triangular_solve.c rename SPEX/{SPEX_Left_LU => SPEX_LU}/License/CONTRIBUTOR-LICENSE.txt (97%) create mode 100644 SPEX/SPEX_LU/License/GPLv2.txt create mode 100644 SPEX/SPEX_LU/License/lesserv3.txt rename SPEX/{SPEX_Left_LU => SPEX_LU}/License/license.txt (82%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/README.md (68%) create mode 100644 SPEX/SPEX_LU/Source/SPEX_lu_analyze.c rename SPEX/{SPEX_Left_LU/Source/SPEX_Left_LU_backslash.c => SPEX_LU/Source/SPEX_lu_backslash.c} (53%) rename SPEX/{SPEX_Left_LU/Source/SPEX_Left_LU_factorize.c => SPEX_LU/Source/SPEX_lu_factorize.c} (68%) create mode 100644 SPEX/SPEX_LU/Source/SPEX_lu_solve.c rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_back_sub.c (65%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_dfs.c (77%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_forward_sub.c (63%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_get_largest_pivot.c (78%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_get_nonzero_pivot.c (72%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_get_pivot.c (63%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_get_smallest_pivot.c (79%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_reach.c (71%) rename SPEX/{SPEX_Left_LU => SPEX_LU}/Source/spex_left_lu_ref_triangular_solve.c (77%) create mode 100644 SPEX/SPEX_LU/Source/spex_lu_internal.h delete mode 100644 SPEX/SPEX_Left_LU/Demo/.gitignore delete mode 100644 SPEX/SPEX_Left_LU/Demo/demos.c delete mode 100644 SPEX/SPEX_Left_LU/Demo/demos.h delete mode 100644 SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_demo.m delete mode 100644 SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_install.m delete mode 100644 SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_test.m delete mode 100644 SPEX/SPEX_Left_LU/MATLAB/Source/SPEX_Left_LU_mex.h delete mode 100644 SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_check_for_inf.c delete mode 100644 SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_error.c delete mode 100644 SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_solve.c delete mode 100644 SPEX/SPEX_Left_LU/Source/spex_left_lu_internal.h delete mode 100644 SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_b.c delete mode 100644 SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_x.c delete mode 100644 SPEX/SPEX_Left_LU/Tcov/.gitignore delete mode 100644 SPEX/SPEX_Left_LU/Tcov/Makefile delete mode 100755 SPEX/SPEX_Left_LU/Tcov/covall delete mode 100644 SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.c delete mode 100644 SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.h delete mode 100644 SPEX/SPEX_Util/Source/SPEX_LU_analysis_free.c delete mode 100644 SPEX/SPEX_Util/Source/SPEX_LU_analyze.c delete mode 100644 SPEX/SPEX_Util/Source/SPEX_finalize.c delete mode 100644 SPEX/SPEX_Util/Source/SPEX_gmp.h delete mode 100644 SPEX/SPEX_Util/Source/SPEX_initialize.c delete mode 100644 SPEX/SPEX_Util/Source/SPEX_matrix_div.c delete mode 100644 SPEX/SPEX_Util/Source/SPEX_matrix_free.c delete mode 100644 SPEX/SPEX_Util/Source/SPEX_version.c delete mode 100644 SPEX/SPEX_Util/Source/spex_expand_mpfr_array.c delete mode 100644 SPEX/SPEX_Util/Source/spex_expand_mpq_array.c create mode 100644 SPEX/SPEX_Utilities/License/CONTRIBUTOR-LICENSE.txt create mode 100644 SPEX/SPEX_Utilities/License/GPLv2.txt create mode 100644 SPEX/SPEX_Utilities/License/lesserv3.txt create mode 100644 SPEX/SPEX_Utilities/License/license.txt rename SPEX/{SPEX_Util => SPEX_Utilities}/README.md (60%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_calloc.c (64%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_create_default_options.c (55%) create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_determine_symmetry.c create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_factorization_free.c create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_finalize.c rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_free.c (67%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_gmp.c (60%) create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_initialize.c rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_initialize_expert.c (51%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_malloc.c (62%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_matrix_allocate.c (67%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_matrix_check.c (72%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_matrix_copy.c (79%) create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_matrix_free.c rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_matrix_nnz.c (60%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/SPEX_realloc.c (76%) create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_symbolic_analysis_free.c create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_thread_finalize.c create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_thread_initialize.c create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_transpose.c create mode 100644 SPEX/SPEX_Utilities/Source/SPEX_version.c create mode 100644 SPEX/SPEX_Utilities/Source/spex_amd.c rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_cast_array.c (79%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_cast_matrix.c (80%) create mode 100644 SPEX/SPEX_Utilities/Source/spex_colamd.c rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_create_mpfr_array.c (60%) create mode 100644 SPEX/SPEX_Utilities/Source/spex_create_mpq.c rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_create_mpq_array.c (70%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_create_mpz_array.c (56%) rename SPEX/{SPEX_Util/Source/SPEX_cumsum.c => SPEX_Utilities/Source/spex_cumsum.c} (73%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_expand_double_array.c (55%) create mode 100644 SPEX/SPEX_Utilities/Source/spex_expand_mpfr_array.c create mode 100644 SPEX/SPEX_Utilities/Source/spex_expand_mpq_array.c create mode 100644 SPEX/SPEX_Utilities/Source/spex_gmp.h rename SPEX/{SPEX_Util/Source/SPEX_matrix_mul.c => SPEX_Utilities/Source/spex_matrix_mul.c} (66%) create mode 100644 SPEX/SPEX_Utilities/Source/spex_permute_dense_matrix.c rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_sparse_collapse.c (81%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_sparse_realloc.c (78%) rename SPEX/{SPEX_Util => SPEX_Utilities}/Source/spex_util_internal.h (57%) rename SPEX/{SPEX_Left_LU => }/Tcov/README.txt (69%) rename SPEX/{SPEX_Left_LU => }/Tcov/cov.awk (100%) create mode 100755 SPEX/Tcov/covall rename SPEX/{SPEX_Left_LU => }/Tcov/cover (100%) rename SPEX/{SPEX_Left_LU => }/Tcov/covs (100%) rename SPEX/{SPEX_Left_LU => }/Tcov/gcovs (86%) create mode 100644 SPEX/Tcov/simple_rand.c create mode 100644 SPEX/Tcov/simple_rand.h create mode 100644 SPEX/Tcov/tcov_for_cholesky.c rename SPEX/{SPEX_Left_LU/Tcov/tcov_test.c => Tcov/tcov_for_lu.c} (74%) create mode 100644 SPEX/Tcov/tcov_for_lu2.c create mode 100644 SPEX/Tcov/tcov_utilities.c create mode 100644 SPEX/Tcov/tcov_utilities.h diff --git a/ChangeLog b/ChangeLog index 0f1eb87902..a4c5e0a35b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +Feb XX, 2024: version 7.7.0 + + * SPEX 3.1.0: major revision to API, new methods. Added SPEX_Cholesky, + SPEX_Backslash, and python interface. MATLAB interface revised. + * Example 1.7.0: revised for change in SPEX API + * SuiteSparse_config: only version number changed to reflect update to + SPEX. + * Package versions in this release: + SuiteSparse_config 7.7.0 + AMD 3.3.1 + BTF 2.3.1 + CAMD 3.3.1 + CCOLAMD 3.3.2 + CHOLMOD 5.2.0 + COLAMD 3.3.2 + CSparse 4.3.1 + CXSparse 4.3.1 + Example 1.7.0 + GraphBLAS 9.0.1 + KLU 2.3.2 + LDL 3.3.1 + LAGraph 1.1.2 + SuiteSparse_Mongoose 3.3.2 + ParU 0.1.2 + RBio 4.3.1 + SPEX 3.1.0 + SPQR 4.3.2 + UMFPACK 6.3.2 + Jan 20, 2024: version 7.6.0 * CHOLMOD 5.2.0: bug fix (restore ABI compatibility with 5.0.x, i.e., 5.2.0 diff --git a/Example/CMakeLists.txt b/Example/CMakeLists.txt index 85cb7d81e0..72ea5b5a5f 100644 --- a/Example/CMakeLists.txt +++ b/Example/CMakeLists.txt @@ -53,10 +53,10 @@ message ( STATUS "MY prefix path: ${CMAKE_PREFIX_PATH}" ) #------------------------------------------------------------------------------- # cmake inserts the date and version number into Include/my.h: -set ( MY_DATE "Jan 20, 2024" ) +set ( MY_DATE "Feb XX, 2024" ) set ( MY_VERSION_MAJOR 1 ) set ( MY_VERSION_MINOR 6 ) -set ( MY_VERSION_PATCH 2 ) +set ( MY_VERSION_PATCH 3 ) message ( STATUS "Building MY library version: v" ${MY_VERSION_MAJOR}. @@ -87,7 +87,7 @@ project ( my #------------------------------------------------------------------------------- # look for all SuiteSparse packages: -find_package ( SuiteSparse_config 7.6.0 REQUIRED ) +find_package ( SuiteSparse_config 7.7.0 REQUIRED ) find_package ( AMD 3.3.1 REQUIRED ) find_package ( BTF 2.3.1 REQUIRED ) find_package ( CAMD 3.3.1 REQUIRED ) @@ -103,7 +103,7 @@ find_package ( LAGraph 1.1.2 ) find_package ( SuiteSparse_Mongoose 3.3.2 REQUIRED ) find_package ( ParU 0.1.2 REQUIRED ) find_package ( RBio 4.3.1 REQUIRED ) -find_package ( SPEX 2.3.2 REQUIRED ) # requires GMP and MPFR +find_package ( SPEX 3.1.0 REQUIRED ) # requires GMP and MPFR find_package ( SPQR 4.3.2 REQUIRED ) find_package ( UMFPACK 6.3.2 REQUIRED ) diff --git a/Example/Include/my.h b/Example/Include/my.h index 1b3cace009..ef071496ee 100644 --- a/Example/Include/my.h +++ b/Example/Include/my.h @@ -11,10 +11,10 @@ // file, since it is constructed from Config/my.h.in by cmake. // version and date for example user library -#define MY_DATE "Jan 20, 2024" +#define MY_DATE "Feb XX, 2024" #define MY_MAJOR_VERSION 1 #define MY_MINOR_VERSION 6 -#define MY_PATCH_VERSION 2 +#define MY_PATCH_VERSION 3 #ifdef __cplusplus extern "C" { diff --git a/Example/Source/my.c b/Example/Source/my.c index a1cfce66ae..83caa38f13 100644 --- a/Example/Source/my.c +++ b/Example/Source/my.c @@ -374,7 +374,8 @@ int my_function (void) // returns 0 on success, -1 on failure //-------------------------------------------------------------------------- OK (SPEX_initialize ( ) == SPEX_OK) ; - SPEX_version (version) ; + char spex_date [128] ; + OK (SPEX_version (version, spex_date) == SPEX_OK) ; OK (my_check_version ("SPEX", SPEX_VERSION_MAJOR, SPEX_VERSION_MINOR, SPEX_VERSION_SUB, SPEX_DATE, version, SPEX__VERSION)) ; diff --git a/Example/Source/my_cxx.cc b/Example/Source/my_cxx.cc index bb4df525ad..ffeb1484bd 100644 --- a/Example/Source/my_cxx.cc +++ b/Example/Source/my_cxx.cc @@ -381,7 +381,8 @@ int my_function (void) // returns 0 on success, -1 on failure //-------------------------------------------------------------------------- OK (SPEX_initialize ( ) == SPEX_OK) ; - SPEX_version (version) ; + char spex_date [128] ; + OK (SPEX_version (version, spex_date) == SPEX_OK) ; OK (my_check_version ("SPEX", SPEX_VERSION_MAJOR, SPEX_VERSION_MINOR, SPEX_VERSION_SUB, SPEX_DATE, version, SPEX__VERSION)) ; diff --git a/README.md b/README.md index 29c74df122..d352271356 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ SuiteSparse: A Suite of Sparse matrix packages at http://suitesparse.com ----------------------------------------------------------------------------- -Jan 20, 2024, SuiteSparse VERSION 7.6.0 +Feb XX, 2024, SuiteSparse VERSION 7.7.0 SuiteSparse is a set of sparse-matrix-related packages written or co-authored by Tim Davis, available at https://github.com/DrTimothyAldenDavis/SuiteSparse . diff --git a/SPEX/CMakeLists.txt b/SPEX/CMakeLists.txt index bf95b7e4b4..89cb2fd554 100644 --- a/SPEX/CMakeLists.txt +++ b/SPEX/CMakeLists.txt @@ -2,7 +2,7 @@ # SuiteSparse/SPEX/CMakeLists.txt: cmake for SPEX #------------------------------------------------------------------------------- -# SPEX_Left_LU: (c) 2019-2024, Chris Lourenco (US Naval Academy), Jinhao Chen, +# SPEX: (c) 2019-2024, Chris Lourenco (US Naval Academy), Jinhao Chen, # Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. # SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later @@ -12,10 +12,10 @@ cmake_minimum_required ( VERSION 3.22 ) -set ( SPEX_DATE "Jan 20, 2024" ) -set ( SPEX_VERSION_MAJOR 2 CACHE STRING "" FORCE ) -set ( SPEX_VERSION_MINOR 3 CACHE STRING "" FORCE ) -set ( SPEX_VERSION_SUB 2 CACHE STRING "" FORCE ) +set ( SPEX_DATE "Feb XX, 2024" ) # FIXME for 7.7.0 +set ( SPEX_VERSION_MAJOR 3 CACHE STRING "" FORCE ) +set ( SPEX_VERSION_MINOR 1 CACHE STRING "" FORCE ) +set ( SPEX_VERSION_SUB 0 CACHE STRING "" FORCE ) message ( STATUS "Building SPEX version: v" ${SPEX_VERSION_MAJOR}. @@ -45,10 +45,10 @@ include ( SuiteSparsePolicy ) #------------------------------------------------------------------------------- if ( NOT SUITESPARSE_ROOT_CMAKELISTS ) - find_package ( SuiteSparse_config 7.6.0 + find_package ( SuiteSparse_config 7.7.0 PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) - find_package ( SuiteSparse_config 7.6.0 REQUIRED ) + find_package ( SuiteSparse_config 7.7.0 REQUIRED ) endif ( ) find_package ( AMD 3.3.1 @@ -82,8 +82,12 @@ configure_file ( "Config/SPEX_version.tex.in" # include directories #------------------------------------------------------------------------------- -include_directories ( SPEX_Left_LU/Source SPEX_Util/Source Include - SPEX_Left_LU/Demo ) +include_directories ( Include + SPEX_Backslash/Source SPEX_Cholesky/Source SPEX_LU/Source + SPEX_Utilities/Source + ${SUITESPARSE_CONFIG_INCLUDE_DIR} + ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} + ${AMD_INCLUDE_DIR} ${COLAMD_INCLUDE_DIR} ) #------------------------------------------------------------------------------- # dynamic spex library properties @@ -338,6 +342,36 @@ if ( NOT MSVC ) DESTINATION ${SUITESPARSE_PKGFILEDIR}/pkgconfig ) endif ( ) +#------------------------------------------------------------------------------- +# python interface +#------------------------------------------------------------------------------- + +file ( GLOB SPEX_PYTHON_SOURCES "Python/SPEXpy/Source/*.c" ) + +add_library ( spexpython SHARED ${SPEX_PYTHON_SOURCES} ) + +set_target_properties ( spexpython PROPERTIES + VERSION ${SPEX_VERSION_MAJOR}.${SPEX_VERSION_MINOR}.${SPEX_VERSION_SUB} + C_STANDARD 11 + C_STANDARD_REQUIRED ON + SOVERSION ${SPEX_VERSION_MAJOR} + PUBLIC_HEADER "Python/SPEXpy/Source/spex_python_connect.h" ) + +# MPFR: +target_link_libraries ( spexpython PUBLIC ${MPFR_LIBRARIES} ) + +# GMP: +# must occur after MPFR +target_link_libraries ( spexpython PUBLIC ${GMP_LIBRARIES} ) + +target_link_libraries ( spexpython PUBLIC SPEX ) + +install ( TARGETS spexpython + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) + #------------------------------------------------------------------------------- # Demo library and programs #------------------------------------------------------------------------------- @@ -354,21 +388,38 @@ if ( SUITESPARSE_DEMOS ) # Demo programs #--------------------------------------------------------------------------- - add_executable ( spexlu_demo "SPEX_Left_LU/Demo/spexlu_demo.c" - "SPEX_Left_LU/Demo/demos.c" ) - add_executable ( example "SPEX_Left_LU/Demo/example.c" ) - add_executable ( example2 "SPEX_Left_LU/Demo/example2.c" - "SPEX_Left_LU/Demo/demos.c" ) + include_directories ( Demo ) + file ( GLOB SPEX_DEMO_SOURCES "Demo/Utilities/*.c" ) + + add_executable ( spex_demo_backslash "Demo/spex_demo_backslash.c" ${SPEX_DEMO_SOURCES} ) + add_executable ( spex_demo_cholesky_extended "Demo/spex_demo_cholesky_extended.c" ${SPEX_DEMO_SOURCES} ) + add_executable ( spex_demo_cholesky_simple "Demo/spex_demo_cholesky_simple.c" ${SPEX_DEMO_SOURCES} ) + add_executable ( spex_demo_lu_doub "Demo/spex_demo_lu_doub.c" ${SPEX_DEMO_SOURCES} ) + add_executable ( spex_demo_lu_extended "Demo/spex_demo_lu_extended.c" ${SPEX_DEMO_SOURCES} ) + add_executable ( spex_demo_lu_simple1 "Demo/spex_demo_lu_simple1.c" ${SPEX_DEMO_SOURCES} ) + add_executable ( spex_demo_lu_simple2 "Demo/spex_demo_lu_simple2.c" ${SPEX_DEMO_SOURCES} ) + add_executable ( spex_demo_threaded "Demo/spex_demo_threaded.c" ${SPEX_DEMO_SOURCES} ) # Libraries required for Demo programs if ( BUILD_SHARED_LIBS ) - target_link_libraries ( spexlu_demo PUBLIC SPEX ) - target_link_libraries ( example PUBLIC SPEX ) - target_link_libraries ( example2 PUBLIC SPEX ) + target_link_libraries ( spex_demo_backslash PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + target_link_libraries ( spex_demo_cholesky_extended PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + target_link_libraries ( spex_demo_cholesky_simple PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + target_link_libraries ( spex_demo_lu_doub PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + target_link_libraries ( spex_demo_lu_extended PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + target_link_libraries ( spex_demo_lu_simple1 PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + target_link_libraries ( spex_demo_lu_simple2 PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + target_link_libraries ( spex_demo_threaded PUBLIC SPEX SuiteSparse::SuiteSparseConfig ${MPFR_LIBRARIES} ${GMP_LIBRARIES} ) + else ( ) - target_link_libraries ( spexlu_demo PUBLIC SPEX_static ) - target_link_libraries ( example PUBLIC SPEX_static ) - target_link_libraries ( example2 PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_backslash PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_cholesky_extended PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_cholesky_simple PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_lu_doub PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_lu_extended PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_lu_simple1 PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_lu_simple2 PUBLIC SPEX_static ) + target_link_libraries ( spex_demo_threaded PUBLIC SPEX_static ) endif ( ) else ( ) @@ -377,8 +428,70 @@ else ( ) endif ( ) +#------------------------------------------------------------------------------- +# configure MATLAB and Tcov +#------------------------------------------------------------------------------- + +# get paths to libraries +get_filename_component ( GMP_PATH ${GMP_LIBRARY} DIRECTORY ) +get_filename_component ( SUITESPARSE_CONFIG_PATH ${SUITESPARSE_CONFIG_LIBRARY} DIRECTORY ) +get_filename_component ( COLAMD_PATH ${COLAMD_LIBRARY} DIRECTORY ) +get_filename_component ( AMD_PATH ${AMD_LIBRARY} DIRECTORY ) +get_filename_component ( MPFR_PATH ${MPFR_LIBRARY} DIRECTORY ) + +# message ( STATUS "suitesparseconfig path ${SUITESPARSE_CONFIG_PATH}" ) +# message ( STATUS "colamd path ${COLAMD_PATH}" ) +# message ( STATUS "amd path ${AMD_PATH}" ) +# message ( STATUS "gmp path ${GMP_PATH}" ) +# message ( STATUS "mpfr path ${MPFR_PATH}" ) + +# construct the -I list +get_target_property ( INCS SPEX INCLUDE_DIRECTORIES ) +list ( TRANSFORM INCS PREPEND " -I" ) +set ( SPEX_INCS "" ) +foreach ( INC ${INCS} ) +# message ( STATUS "check inc: ${INC}" ) + if ( NOT ${INC} MATCHES "TARGET_PROPERTY" ) +# message ( STATUS "add inc: ${INC}" ) + string ( APPEND SPEX_INCS " " ${INC} ) + endif ( ) +endforeach ( ) +# message ( STATUS "Incs: ${SPEX_INCS}" ) + +# construct the library list for Tcov/Makefile +set ( SPEX_LIB_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}" ) +get_target_property ( LIBS SPEX LINK_LIBRARIES ) +string ( REPLACE "." "\\." LIBSUFFIX ${SPEX_LIB_SUFFIX} ) +set ( SPEX_LIBS "" ) +foreach ( LIB_NAME ${LIBS} ) +# message ( STATUS "Lib: ${LIB_NAME}" ) + if ( LIB_NAME MATCHES "::" ) + # do nothing + elseif ( LIB_NAME MATCHES ${LIBSUFFIX} ) + # message ( STATUS "has suffix" ) + string ( APPEND SPEX_LIBS " " ${LIB_NAME} ) + else ( ) + # message ( STATUS "no suffix" ) + string ( APPEND SPEX_LIBS " -l" ${LIB_NAME} ) + endif ( ) +endforeach ( ) +# message ( STATUS "Libs: ${SPEX_LIBS}" ) + +configure_file ( + "Config/spex_deps.m.in" + "${PROJECT_SOURCE_DIR}/MATLAB/spex_deps.m" + @ONLY + NEWLINE_STYLE LF ) + +configure_file ( + "Config/Tcov_Makefile.in" + "${PROJECT_SOURCE_DIR}/Tcov/Makefile" + @ONLY + NEWLINE_STYLE LF ) + #------------------------------------------------------------------------------- # report status #------------------------------------------------------------------------------- include ( SuiteSparseReport ) + diff --git a/SPEX/Config/SPEX.h.in b/SPEX/Config/SPEX.h.in index 6f46f2f110..11c2455334 100644 --- a/SPEX/Config/SPEX.h.in +++ b/SPEX/Config/SPEX.h.in @@ -1,176 +1,20 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/Include/SPEX.h: user #include file for SPEX_Left_LU. +// SPEX/Include/SPEX.h: Include file for SPEX Library //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2023, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -#ifndef SPEX_LEFT_LU_H -#define SPEX_LEFT_LU_H +#ifndef SPEX_H +#define SPEX_H -// This software package exactly solves a sparse system of linear equations -// using the SPEX Left LU factorization. This code accompanies the paper (submitted -// to ACM Transactions on Mathematical Software): -// "Algorithm 1021: SPEX Left LU: Exactly Solving Sparse Linear Systems via -// A Sparse Left-Looking Integer-Preserving LU Factorization", C. Lourenco, -// J. Chen, E. Moreno-Centeno, T. Davis, ACM Trans. Mathematical Software, -// June 2022. https://doi.org/10.1145/3519024 - -// The theory associated with this software can be found in the paper -// (published in SIAM journal on matrix analysis and applications): - -// "Exact Solution of Sparse Linear Systems via Left-Looking -// Roundoff-Error-Free LU Factorization in Time Proportional to -// Arithmetic Work", C. Lourenco, A. R. Escobedo, E. Moreno-Centeno, -// T. Davis, SIAM J. Matrix Analysis and Applications. pp 609-638, -// vol 40, no 2, 2019. - -// If you use this code, you must first download and install the GMP and -// MPFR libraries. GMP and MPFR can be found at: -// https://gmplib.org/ -// http://www.mpfr.org/ - -// If you use SPEX Left LU for a publication, we request that you please cite -// the above two papers. - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//-------------------------Authors---------------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and Timothy Davis -// - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//-------------------------Contact Information---------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// Please contact Chris Lourenco (chrisjlourenco@gmail.com) -// or Tim Davis (timdavis@aldenmath.com, DrTimothyAldenDavis@gmail.com, -// davis@tamu.edu) - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//-------------------------Copyright-------------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// SPEX Left LU is free software; you can redistribute it and/or modify -// it under the terms of either: -// -// * the GNU Lesser General Public License as published by the -// Free Software Foundation; either version 3 of the License, -// or (at your option) any later version. -// -// or -// -// * the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any -// later version. -// -// or both in parallel, as here. -// -// See license.txt for license info. -// -// This software is copyright by Christopher Lourenco, Jinhao Chen, Erick -// Moreno-Centeno and Timothy A. Davis. All Rights Reserved. -// - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//---------------------------DISCLAIMER----------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// SPEX Left LU is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//--------------------------Summary--------------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// This software package solves the linear system Ax = b exactly. The input -// matrix and right hand side vectors are stored as either integers, double -// precision numbers, multiple precision floating points (through the mpfr -// library) or as rational numbers (as a collection of numerators and -// denominators using the GMP mpq_t data structure). Appropriate routines -// within the code transform the input into an integral matrix in compressed -// column form. - -// This package computes the factorization PAQ = LDU. Note that we store the -// "functional" form of the factorization by only storing L and U. The user -// is given some freedom to select the permutation matrices P and Q. The -// recommended default settings select Q using the COLAMD column ordering -// and select P via a partial pivoting scheme in which the diagonal entry -// in column k is selected if it is the same magnitude as the smallest -// entry, otherwise the smallest entry is selected as the kth pivot. -// Alternative strategies allowed to select Q include the AMD column -// ordering or no column permutation (Q=I). For pivots, there are a variety -// of potential schemes including traditional partial pivoting, diagonal -// pivoting, tolerance pivoting etc. This package does not allow pivoting -// based on sparsity criterion. - -// The factors L and U are computed via integer preserving operations via -// integer-preserving Gaussian elimination. The key part of this algorithm -// is a Roundoff Error Free (REF) sparse triangular solve function which -// exploits sparsity to reduce the number of operations that must be -// performed. - -// Once L and U are computed, a simplified version of the triangular solve -// is performed which assumes the vector b is dense. The final solution -// vector x is gauranteed to be exact. This vector can be output in one of -// three ways: 1) full precision rational arithmetic (as a sequence of -// numerators and denominators) using the GMP mpq_t data type, 2) double -// precision while not exact will produce a solution accurate to machine -// roundoff unless the size of the associated solution exceeds double -// precision (i.e., the solution is 10^500 or something), 3) variable -// precision floating point using the GMP mpfr_t data type. The associated -// precision is user defined. - - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//---------------------Include files required by SPEX Left LU------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -#include -#include -#include -#include -#include -#include -#include -#include "SuiteSparse_config.h" -// #include "SPEX_Util.h" - - -//------------------------------------------------------------------------------ -// SPEX_Util/Include/SPEX_Util.h: Include file for utility functions for SPEX -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -#ifndef SPEX_UTIL_H -#define SPEX_UTIL_H - -// SPEX_Util is a collection of utility functions for the SParse EXact package. -// Included are several routines for memory management, matrix operations, and +// SPEX is a collection of functions for the SParse EXact package. +// Included are several routines for memory management, matrix operations, and // wrappers to the GMP library. // // This is the global include file and should be included in all SPEX_* packages @@ -181,9 +25,10 @@ //-------------------------Authors---------------------------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -// Unless otherwise noted all Utility functions are authored by: +// Unless otherwise noted all functions are authored by: // -// Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and Timothy Davis +// Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Erick Moreno-Centeno, and Timothy A. Davis // //------------------------------------------------------------------------------ @@ -192,8 +37,10 @@ //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -// Please contact Chris Lourenco (chrisjlourenco@gmail.com, lourenco@usna.edu) -// or Tim Davis (timdavis@aldenmath.com, DrTimothyAldenDavis@gmail.com, +// Please contact +// Chris Lourenco (chrisjlourenco@gmail.com, lourenco@usna.edu) +// or +// Tim Davis (timdavis@aldenmath.com, DrTimothyAldenDavis@gmail.com, // davis@tamu.edu) //------------------------------------------------------------------------------ @@ -219,8 +66,9 @@ // // See license.txt for license info. // -// This software is copyright by Christopher Lourenco, Jinhao Chen, Erick -// Moreno-Centeno and Timothy A. Davis. All Rights Reserved. +// This software is copyright by Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Erick Moreno-Centeno and Timothy A. Davis. +// All Rights Reserved. // //------------------------------------------------------------------------------ @@ -234,41 +82,47 @@ // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. - //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //---------------------Include files required by SPEX -------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -// #include -// #include -// #include -// #include -// #include -// #include -// #include -#include -#include -// #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +// #include +// #include +// #include +// #include #include "SuiteSparse_config.h" //------------------------------------------------------------------------------ -// Version +// SPEX Version //------------------------------------------------------------------------------ +// Current version of the code #define SPEX_DATE "@SPEX_DATE@" -#define SPEX_VERSION "@SPEX_VERSION_MAJOR@.@SPEX_VERSION_MINOR@.@SPEX_VERSION_SUB@" +#define SPEX_VERSION_STRING "@SPEX_VERSION_MAJOR@.@SPEX_VERSION_MINOR@.@SPEX_VERSION_SUB@" #define SPEX_VERSION_MAJOR @SPEX_VERSION_MAJOR@ #define SPEX_VERSION_MINOR @SPEX_VERSION_MINOR@ #define SPEX_VERSION_SUB @SPEX_VERSION_SUB@ +#define SPEX_VERSION_NUMBER(major,minor,sub) \ + (((major)*1000ULL + (minor))*1000ULL + (sub)) +#define SPEX_VERSION \ + SPEX_VERSION_NUMBER (SPEX_VERSION_MAJOR, \ + SPEX_VERSION_MINOR, \ + SPEX_VERSION_SUB) + #define SPEX__VERSION SUITESPARSE__VERCODE(@SPEX_VERSION_MAJOR@,@SPEX_VERSION_MINOR@,@SPEX_VERSION_SUB@) #if !defined (SUITESPARSE__VERSION) || \ - (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,6,0)) -#error "SPEX @SPEX_VERSION_MAJOR@.@SPEX_VERSION_MINOR@.@SPEX_VERSION_SUB@ requires SuiteSparse_config 7.6.0 or later" + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,7,0)) +#error "SPEX @SPEX_VERSION_MAJOR@.@SPEX_VERSION_MINOR@.@SPEX_VERSION_SUB@ requires SuiteSparse_config 7.7.0 or later" #endif #if defined ( __cplusplus ) @@ -276,12 +130,6 @@ extern "C" { #endif -//------------------------------------------------------------------------------ -// version -//------------------------------------------------------------------------------ - -void SPEX_version (int version [3]) ; - //------------------------------------------------------------------------------ // Error codes //------------------------------------------------------------------------------ @@ -292,49 +140,100 @@ void SPEX_version (int version [3]) ; typedef enum { - SPEX_OK = 0, // all is well - SPEX_OUT_OF_MEMORY = -1, // out of memory - SPEX_SINGULAR = -2, // the input matrix A is singular - SPEX_INCORRECT_INPUT = -3, // one or more input arguments are incorrect - SPEX_INCORRECT = -4, // The solution is incorrect - SPEX_UNSYMMETRIC = -5, // The input matrix is unsymmetric (for Cholesky) - SPEX_PANIC = -6 // SPEX used without proper initialization + + SPEX_OK = 0, // all is well + SPEX_OUT_OF_MEMORY = -1, // out of memory + SPEX_SINGULAR = -2, // the input matrix A is singular + SPEX_INCORRECT_INPUT = -3, // one or more input arguments are incorrect + SPEX_NOTSPD = -4, // The input matrix is not symmetric positive + // definite (for a Cholesky factorization) + SPEX_INCORRECT_ALGORITHM = -5,// The algorithm is not compatible with + // the factorization + SPEX_PANIC = -6 // SPEX used without proper initialization, + // or other unrecoverable error } SPEX_info ; +//------------------------------------------------------------------------------ +// SPEX Version, continued +//------------------------------------------------------------------------------ + +SPEX_info SPEX_version +( + int version [3], // SPEX major, minor, and sub version + char date [128] // date of this version +) ; + +// Requirements: SPEX requires GMP 6.1.2 or later, and MPFR 4.0.2 or later. +// NOTE that these version numbers are from the original source distributions. +// It is NOT the "number 10" assigned to libgmp.so.10 in the Ubuntu linux +// distro. + +// GMP v6.1.2 or later is required: +#if __GNU_MP_RELEASE < 60102 +#error "GMP v6.1.2 or later is required." +#endif + +// MPFR v4.0.2 or later is required: +#if MPFR_VERSION < MPFR_VERSION_NUM(4,0,2) +#error "MPFR v4.0.2 or later is required." +#endif + //------------------------------------------------------------------------------ // Pivot scheme codes //------------------------------------------------------------------------------ +// SPEX_DEFAULT is only used to define the defaults for the following enums but +// in all other places we use the appropiate default (ie SPEX_DEFAULT_ORDERING) +// for ease of reading +#define SPEX_DEFAULT 0 + // A code in SPEX_options to tell SPEX what type of pivoting to use for pivoting // in unsymmetric LU factorization. typedef enum { - SPEX_SMALLEST = 0, // Smallest pivot + SPEX_SMALLEST = SPEX_DEFAULT, // Smallest pivot (the default method) SPEX_DIAGONAL = 1, // Diagonal pivoting SPEX_FIRST_NONZERO = 2, // First nonzero per column chosen as pivot SPEX_TOL_SMALLEST = 3, // Diagonal pivoting with tol for smallest pivot. - // (Default) SPEX_TOL_LARGEST = 4, // Diagonal pivoting with tol. for largest pivot SPEX_LARGEST = 5 // Largest pivot } SPEX_pivot ; //------------------------------------------------------------------------------ -// Column ordering scheme codes +// Fill-reducing ordering scheme codes +//------------------------------------------------------------------------------ + +// A code in SPEX_options to tell SPEX which fill-reducing ordering to used +// prior to exact factorization + +typedef enum +{ + SPEX_DEFAULT_ORDERING = SPEX_DEFAULT, // Default: colamd for LU + // AMD for Cholesky + SPEX_NO_ORDERING = 1, // None: A is factorized as-is + SPEX_COLAMD = 2, // COLAMD: Default for LU (and QR in the FUTURE) + SPEX_AMD = 3 // AMD: Default for Cholesky +} +SPEX_preorder ; + +//------------------------------------------------------------------------------ +// Factorization type codes //------------------------------------------------------------------------------ -// A code in SPEX_options to tell SPEX which column ordering to used prior to -// exact factorization +// A code in SPEX_options to tell SPEX which factorization algorithm to use typedef enum { - SPEX_NO_ORDERING = 0, // None: A is factorized as-is - SPEX_COLAMD = 1, // COLAMD: Default - SPEX_AMD = 2 // AMD + SPEX_ALGORITHM_DEFAULT = SPEX_DEFAULT, // Defaults: Left for LU, + // Up for Chol + SPEX_LU_LEFT = 1, // Left looking LU factorization + SPEX_CHOL_LEFT = 2, // Left looking Cholesky factorization + SPEX_CHOL_UP = 3 // Up looking Cholesky factorization } -SPEX_col_order ; +SPEX_factorization_algorithm ; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ @@ -344,26 +243,52 @@ SPEX_col_order ; // This struct serves as a global struct to define all user-selectable options. -typedef struct SPEX_options +typedef struct { - SPEX_pivot pivot ; // row pivoting scheme used. - SPEX_col_order order ; // column ordering scheme used - double tol ; // tolerance for the row-pivotin methods + SPEX_pivot pivot ; // row pivoting scheme used (LU only) + SPEX_preorder order ; // ordering scheme used + double tol ; // tolerance for the row-pivoting methods for LU. // SPEX_TOL_SMALLEST and SPEX_TOL_LARGEST int print_level ; // 0: print nothing, 1: just errors, - // 2: terse (basic stats from COLAMD/AMD and - // SPEX Left LU), 3: all, with matrices and results - int32_t prec ; // Precision used to output file if MPFR is chosen + // 2: terse (basic stats from COLAMD/AMD and the + // factorization), 3: all, with matrices and results + uint64_t prec ; // Precision for MPFR mpfr_rnd_t round ; // Type of MPFR rounding used - bool check ; // Set true if the solution to the system should be - // checked. Intended for debugging only; SPEX is - // guaranteed to return the exact solution. -} SPEX_options ; + SPEX_factorization_algorithm algo ; // parameter which tells the function + // which factorization algorithm to use +} SPEX_options_struct ; + +// A SPEX_options object is a pointer to a SPEX_options_struct +typedef SPEX_options_struct *SPEX_options ; // Purpose: Create SPEX_options object with default parameters // upon successful allocation, which are defined in SPEX_util_nternal.h -// To free it, simply use SPEX_FREE (*option). -SPEX_info SPEX_create_default_options (SPEX_options **option) ; +// To free it, simply use SPEX_FREE (option). + +SPEX_info SPEX_create_default_options (SPEX_options *option_handle) ; + + +//------------------------------------------------------------------------------ +// SPEX_vector +//------------------------------------------------------------------------------ + +// NOTE: The SPEX_vector object will be used in a near-future version of SPEX. +// It appears here for future compatibility, but is currently unused. + +typedef struct +{ + int64_t nz; // number of explicit entries in the vector + int64_t nzmax;// size of array i and x, nz <= nzmax + int64_t *i; // array of size nzmax that contains the column/row indices + // of each nnz. + mpz_t *x; // array of size nzmax that contains the values of each nnz + mpq_t scale; // a scale factor that has not applied to entries in this v. + // The real value of the k-th nonzero entry in the list should + // be computed as x[k]*scale. x[k]/den(scale) must be integer. +} SPEX_vector_struct ; + +// A SPEX_vector is a pointer to a SPEX_vector_struct +typedef SPEX_vector_struct *SPEX_vector ; //------------------------------------------------------------------------------ @@ -371,18 +296,19 @@ SPEX_info SPEX_create_default_options (SPEX_options **option) ; //------------------------------------------------------------------------------ // SPEX uses a single matrix data type, SPEX_matrix, which can be held in -// one of three kinds of formats: sparse CSC (compressed sparse column), -// sparse triplet, and dense: +// one of four kinds of formats: sparse CSC (compressed sparse column), +// sparse triplet, dense, and sparse dynamic CSC. typedef enum { SPEX_CSC = 0, // matrix is in compressed sparse column format SPEX_TRIPLET = 1, // matrix is in sparse triplet format - SPEX_DENSE = 2 // matrix is in dense format + SPEX_DENSE = 2, // matrix is in dense format (held by column) } SPEX_kind ; -// Each of the three formats can have values of 5 different data types: mpz_t, +// The last format (SPEX_DYNAMIC_CSC) only support mpz_t type, while each of +// the first three formats can have values of 5 different data types: mpz_t, // mpq_t, mpfr_t, int64_t, and double: typedef enum @@ -395,8 +321,10 @@ typedef enum } SPEX_type ; -// This gives a total of 15 different matrix types. Not all functions accept -// all 15 matrices types, however. +// This gives a total of 16 different matrix types: +// (sparse CSC, triplet, dense) x (5 data types) = 15 formats, + +// Not all functions accept all 16 matrices types, however. // Suppose A is an m-by-n matrix with nz <= nzmax entries. // The p, i, j, and x components are defined as: @@ -419,34 +347,45 @@ SPEX_type ; // are all NULL. A->x.type is a pointer to an array of size m*n, stored // in column-oriented format. The value of A(i,j) is A->x.type [p] // with p = i + j*A->m. A->nz is ignored; nz is A->m * A->n. - +// // The SPEX_matrix may contain 'shallow' components, A->p, A->i, A->j, and // A->x. For example, if A->p_shallow is true, then a non-NULL A->p is a // pointer to a read-only array, and the A->p array is not freed by // SPEX_matrix_free. If A->p is NULL (for a triplet or dense matrix), then -// A->p_shallow has no effect. +// A->p_shallow has no effect. typedef struct { + SPEX_kind kind ; // CSC, triplet, dense + SPEX_type type ; // mpz, mpq, mpfr, int64, or fp64 (double) + + int64_t m ; // number of rows int64_t n ; // number of columns - int64_t nzmax ; // size of A->i, A->j, and A->x + + mpq_t scale ; // scale factor for mpz matrices (never shallow) + // For all matrices whose type is not mpz, + // mpz_scale = 1. + // The real value of the nonzero entry A(i,j) + // should be computed as A(i,j)/scale. + + //-------------------------------------------------------------------------- + // these are used for CSC, triplet or dense matrix + //-------------------------------------------------------------------------- + + int64_t nzmax ; // size of A->i, A->j, and A->x. int64_t nz ; // # nonzeros in a triplet matrix . - // Ignored for CSC and dense matrices. - SPEX_kind kind ; // CSC, triplet, or dense - SPEX_type type ; // mpz, mpq, mpfr, int64, or fp64 (double) + // Ignored for CSC, or dense. int64_t *p ; // if CSC: column pointers, an array size is n+1. // if triplet or dense: A->p is NULL. - bool p_shallow ; // if true, A->p is shallow. int64_t *i ; // if CSC or triplet: row indices, of size nzmax. // if dense: A->i is NULL. - bool i_shallow ; // if true, A->i is shallow. + int64_t *j ; // if triplet: column indices, of size nzmax. // if CSC or dense: A->j is NULL. - bool j_shallow ; // if true, A->j is shallow. union // A->x.type has size nzmax. { @@ -456,45 +395,71 @@ typedef struct int64_t *int64 ; // A->x.int64 double *fp64 ; // A->x.fp64 } x ; + + //-------------------------------------------------------------------------- + // This component is only used for SPEX_DYNAMIC_CSC matrix, and ignored for + // CSC, triplet and dense matrix, for a future version of SPEX. + //-------------------------------------------------------------------------- + + SPEX_vector *v; // In this version of SPEX, v is always NULL, and + // should not be used. + + //-------------------------------------------------------------------------- + // flags to indicate if any component is shallow + //-------------------------------------------------------------------------- + + bool p_shallow ; // if true, A->p is shallow. + bool i_shallow ; // if true, A->i is shallow. + bool j_shallow ; // if true, A->j is shallow. bool x_shallow ; // if true, A->x.type is shallow. - mpq_t scale ; // scale factor for mpz matrices (never shallow) - // For all matrices who's type is not mpz, - // mpz_scale = 1. +} SPEX_matrix_struct ; -} SPEX_matrix ; +// A SPEX_matrix is a pointer to a SPEX_matrix_struct +typedef SPEX_matrix_struct *SPEX_matrix ; //------------------------------------------------------------------------------ // SPEX_matrix_allocate: allocate an m-by-n SPEX_matrix //------------------------------------------------------------------------------ +// Allocate an m-by-n SPEX_matrix, in one of 15 data structures: +// (sparse CSC, sparse triplet, or dense) x +// (mpz, mpz, mfpr, int64, or double). + +// The matrix may be created as 'shallow', in +// which case A->p, A->i, A->j, and A->x are all returned as NULL, and all +// A->*_shallow flags are returned as true. The user can then set A->p, A->i, +// A->j, and/or A->x accordingly, from their own arrays. For non-shallow +// matrix, the components (p,i,j,x) are allocated according to the kind, type +// and size (m, n, nzmax) of the matrix. + + // if shallow is false: All components (p,i,j,x) are allocated and set to zero, // and then shallow flags are all false. // if shallow is true: All components (p,i,j,x) are NULL, and their shallow -// flags are all true. The user can then set A->p, -// A->i, A->j, and/or A->x accordingly, from their own -// arrays. +// flags are all true. SPEX_info SPEX_matrix_allocate ( - SPEX_matrix **A_handle, // matrix to allocate - SPEX_kind kind, // CSC, triplet, or dense + SPEX_matrix *A_handle, // matrix to allocate + SPEX_kind kind, // CSC, triplet, dense (and a future dynamic CSC) SPEX_type type, // mpz, mpq, mpfr, int64, or double int64_t m, // # of rows int64_t n, // # of columns - int64_t nzmax, // max # of entries + int64_t nzmax, // max # of entries for CSC or triplet + // (ignored if A is dense) bool shallow, // if true, matrix is shallow. A->p, A->i, A->j, // A->x are all returned as NULL and must be set // by the caller. All A->*_shallow are returned - // as true. + // as true. Ignored if kind is dynamic_CSC. bool init, // If true, and the data types are mpz, mpq, or // mpfr, the entries are initialized (using the // appropriate SPEX_mp*_init function). If false, - // the mpz, mpq, and mpfr arrays are allocated but - // not initialized. Meaningless for data types - // FP64 or INT64 - const SPEX_options *option + // the mpz, mpq, and mpfr arrays are malloced but + // not initialized. Utilized internally to reduce + // memory. Ignored if shallow is true. + const SPEX_options option ) ; //------------------------------------------------------------------------------ @@ -503,19 +468,29 @@ SPEX_info SPEX_matrix_allocate SPEX_info SPEX_matrix_free ( - SPEX_matrix **A_handle, // matrix to free - const SPEX_options *option + SPEX_matrix *A_handle, // matrix to free + const SPEX_options option ) ; //------------------------------------------------------------------------------ // SPEX_matrix_nnz: # of entries in a matrix //------------------------------------------------------------------------------ -SPEX_info SPEX_matrix_nnz // find the # of entries in A +SPEX_info SPEX_matrix_nnz // find the # of entries in A +( + int64_t *nnz, // # of entries in A, -1 if A is NULL + const SPEX_matrix A, // matrix to query + const SPEX_options option // command options, currently unused +) ; + +//------------------------------------------------------------------------------ +// SPEX_matrix_check: check and print a SPEX_matrix +//------------------------------------------------------------------------------ + +SPEX_info SPEX_matrix_check // returns a SPEX status code ( - int64_t *nnz, // # of entries in A, -1 if A is NULL - const SPEX_matrix *A, // matrix to query - const SPEX_options *option + const SPEX_matrix A, // matrix to check + const SPEX_options option ) ; //------------------------------------------------------------------------------ @@ -524,68 +499,174 @@ SPEX_info SPEX_matrix_nnz // find the # of entries in A // SPEX_matrix_copy: make a copy of a SPEX_matrix, into another kind and type. +// SPEX supports 16 matrix formats: 15 of them are all combinations of +// (CSC, triplet, dense) x (mpz, mpq, mpfr, int64, double). + SPEX_info SPEX_matrix_copy ( - SPEX_matrix **C_handle, // matrix to create (never shallow) + SPEX_matrix *C_handle, // matrix to create (never shallow) // inputs, not modified: - SPEX_kind C_kind, // C->kind: CSC, triplet, or dense + SPEX_kind C_kind, // C->kind: CSC, triplet, dense, + // (or future dynamic CSC) SPEX_type C_type, // C->type: mpz_t, mpq_t, mpfr_t, int64_t, or double - SPEX_matrix *A, // matrix to make a copy of (may be shallow) - const SPEX_options *option + const SPEX_matrix A, // matrix to make a copy of (may be shallow) + const SPEX_options option ) ; //------------------------------------------------------------------------------ -// SPEX_matrix macros +// SPEX symbolic analysis and factorization //------------------------------------------------------------------------------ -// These macros simplify the access to entries in a SPEX_matrix. -// The type parameter is one of: mpq, mpz, mpfr, int64, or fp64. - -// To access the kth entry in a SPEX_matrix using 1D linear addressing, -// in any matrix kind (CSC, triplet, or dense), in any type: -#define SPEX_1D(A,k,type) ((A)->x.type [k]) - -// To access the (i,j)th entry in a 2D SPEX_matrix, in any type: -#define SPEX_2D(A,i,j,type) SPEX_1D (A, (i)+(j)*((A)->m), type) +typedef enum +{ + SPEX_LU_FACTORIZATION = 0, // LU factorization + SPEX_CHOLESKY_FACTORIZATION = 1, // Cholesky factorization + SPEX_QR_FACTORIZATION = 2 // QR factorization (FUTURE) +} +SPEX_factorization_kind ; //------------------------------------------------------------------------------ -// SPEX_LU_analysis: symbolic pre-analysis +// SPEX_symbolic_analysis: symbolic pre-analysis //------------------------------------------------------------------------------ -// This struct stores the column permutation for LU and the estimate of the -// number of nonzeros in L and U. +// This struct stores the results of symbolic analysis + +// This object is constructed by SPEX_lu_analyze and SPEX_cholesky_analyze. +// All these functions allocate space and assign values, and thus do not +// require user to perform any memory allocation. Certain components of this +// object can still be NULL after it is constructed. User can access (read or +// print) components of this object, but should not try to modify any of them +// other than calling SPEX_symbolic_analysis_free to free the memory space. typedef struct { - int64_t *q ; // Column permutation for LU factorization, representing - // the permutation matrix Q. The matrix A*Q is factorized. - // If the kth column of L, U, and A*Q is column j of the - // unpermuted matrix A, then j = S->q [k]. - int64_t lnz ; // Approximate number of nonzeros in L. - int64_t unz ; // Approximate number of nonzeros in U. - // lnz and unz are used to allocate the initial space for - // L and U; the space is reallocated as needed. -} SPEX_LU_analysis ; - -// The symbolic analysis object is created by SPEX_LU_analyze. - -// SPEX_LU_analysis_free frees the SPEX_LU_analysis object. -SPEX_info SPEX_LU_analysis_free + SPEX_factorization_kind kind; // LU, Cholesky (or QR in the FUTURE) + + //-------------------------------------------------------------------------- + // The permutations of the matrix that are found during the symbolic + // analysis process. One or more of these permutations could be NULL for + // some SPEX_symbolic_analysis_kind. Specifically, + // For kind == SPEX_LU_FACTORIZATION, only Q_perm is not NULL. + // For kind == SPEX_CHOLESKY_FACTORIZATION, both Q_perm and Qinv_perm are + // NULL. + //-------------------------------------------------------------------------- + int64_t *P_perm; // row permutation + int64_t *Pinv_perm; // inverse of row permutation + + int64_t *Q_perm; // column permutation + int64_t *Qinv_perm; // inverse of column permutation + + //-------------------------------------------------------------------------- + // estimates of nonzeros that will apprear in the factorization + //-------------------------------------------------------------------------- + + int64_t lnz ; // Approximate number of nonzeros in L. + // Available only for SPEX_LU_FACTORIZATION + // or SPEX_CHOLESKY_FACTORIZATION. + int64_t unz ; // Approximate number of nonzeros in U. + // lnz and unz are used to allocate + // the initial space for L and U; the + // space is reallocated as needed. + // Available only for SPEX_LU_FACTORIZATION. + + //-------------------------------------------------------------------------- + // These are only used in the Cholesky analysis process + //-------------------------------------------------------------------------- + int64_t *parent; // Elimination tree of target matrix + // for Cholesky factorization. + int64_t *cp; // column pointers of L for Cholesky + // factorization. + +} SPEX_symbolic_analysis_struct ; + +// A SPEX_symbolic_analysis object is a pointer to a +// SPEX_symbolic_analysis_struct +typedef SPEX_symbolic_analysis_struct *SPEX_symbolic_analysis ; + +//------------------------------------------------------------------------------ +// SPEX_symbolic_analysis_free frees the SPEX_symbolic_analysis object. +//------------------------------------------------------------------------------ + +SPEX_info SPEX_symbolic_analysis_free ( - SPEX_LU_analysis **S, // Structure to be deleted - const SPEX_options *option + SPEX_symbolic_analysis *S_handle, // Structure to be deleted + const SPEX_options option ) ; -// SPEX_LU_analyze performs the symbolic ordering and analysis for LU factorization. -// Currently, there are three options: no ordering, COLAMD, and AMD. -SPEX_info SPEX_LU_analyze +//------------------------------------------------------------------------------ +// SPEX_factorization: data structure for factorization +//------------------------------------------------------------------------------ + +// The SPEX_factorization object holds an LU, Cholesky, or (in the future) QR +// numerical factorization, in either non-updatable (static) or updatable form +// (also future work). +// +// NOTE: +// The components of the factorization structure are accessible to the user +// application. However, they should only be modified by calling SPEX_* +// methods. Changing them directly can lead to undefined behavior. + +// To create this object, users can call SPEX_lu_factorize, or +// SPEX_cholesky_factorize. All these function will create a +// static factorization of corresponding kind. +// +// To free the factorization object, simply call SPEX_factorization_free. + +typedef struct +{ + SPEX_factorization_kind kind; // LU, Cholesky, QR factorization + + bool updatable; // flag to denote if the factorization + // is in the updatable format + // (for a future SPEX version) + + mpq_t scale_for_A; // the scale of the target matrix + + //-------------------------------------------------------------------------- + // These are used for LU or Cholesky factorization, but ignored for QR + // factorization. + //-------------------------------------------------------------------------- + + SPEX_matrix L; // The lower-triangular matrix from LU + // or Cholesky factorization. + SPEX_matrix U; // The upper-triangular matrix from LU + // factorization. NULL for Cholesky + // factorization. + SPEX_matrix rhos; // A n-by-1 dense matrix for the + // pivot values + + + //-------------------------------------------------------------------------- + // The permutations of the matrix that are used during the factorization. + // These are currently used only for LU or Cholesky factorization. + // One or more of these permutations could be NULL for some + // SPEX_factorization_kind. Specifically, + // For kind == SPEX_LU_FACTORIZATION, Qinv_perm can be NULL + // For kind == SPEX_CHOLESKY_FACTORIZATION, both Q_perm and Qinv_perm are + // NULL. + //-------------------------------------------------------------------------- + + int64_t *P_perm; // row permutation + int64_t *Pinv_perm; // inverse of row permutation + + int64_t *Q_perm; // column permutation + int64_t *Qinv_perm; // inverse of column permutation + +} SPEX_factorization_struct ; + +// A SPEX_factorization is a pointer to a SPEX_factorization_struct +typedef SPEX_factorization_struct *SPEX_factorization ; + +//------------------------------------------------------------------------------ +// SPEX_factorization_free frees the SPEX_factorization object. +//------------------------------------------------------------------------------ + +SPEX_info SPEX_factorization_free ( - SPEX_LU_analysis **S, // symbolic analysis (column permutation and nnz L,U) - const SPEX_matrix *A, // Input matrix - const SPEX_options *option // Control parameters + SPEX_factorization *F_handle, // Structure to be deleted + const SPEX_options option ) ; - //------------------------------------------------------------------------------ // Memory management //------------------------------------------------------------------------------ @@ -595,6 +676,7 @@ SPEX_info SPEX_LU_analyze // SuiteSparse_free. // Allocate and initialize memory space for SPEX + void *SPEX_calloc ( size_t nitems, // number of items to allocate @@ -602,12 +684,14 @@ void *SPEX_calloc ) ; // Allocate memory space for SPEX + void *SPEX_malloc ( size_t size // size of memory space to allocate ) ; // Free the memory allocated by SPEX_calloc, SPEX_malloc, or SPEX_realloc. + void SPEX_free ( void *p // pointer to memory space to free @@ -655,81 +739,73 @@ void *SPEX_realloc // pointer to reallocated block, or original block ) ; //------------------------------------------------------------------------------ -// SPEX memory environment routines +// SPEX environment routines //------------------------------------------------------------------------------ // SPEX_initialize: initializes the working evironment for SPEX library. // It must be called prior to calling any other SPEX_* function. -SPEX_info SPEX_initialize (void) ; + +SPEX_info SPEX_initialize ( void ) ; // SPEX_initialize_expert is the same as SPEX_initialize, except that it allows // for a redefinition of custom memory functions that are used for SPEX and // GMP. The four inputs to this function are pointers to four functions with // the same signatures as the ANSI C malloc, calloc, realloc, and free. + SPEX_info SPEX_initialize_expert ( - void* (*MyMalloc) (size_t), // user-defined malloc - void* (*MyCalloc) (size_t, size_t), // user-defined calloc - void* (*MyRealloc) (void *, size_t), // user-defined realloc + void *(*MyMalloc) (size_t), // user-defined malloc + void *(*MyCalloc) (size_t, size_t), // user-defined calloc + void *(*MyRealloc) (void *, size_t), // user-defined realloc void (*MyFree) (void *) // user-defined free ) ; // SPEX_finalize: This function finalizes the working evironment for SPEX // library, and frees any internal workspace created by SPEX. It must be // called as the last SPEX_* function called. -SPEX_info SPEX_finalize (void) ; - -// SPEX_matrix_check: check and print a SPEX_sparse matrix -SPEX_info SPEX_matrix_check // returns a SPEX status code +SPEX_info SPEX_finalize ( - const SPEX_matrix *A, // matrix to check - const SPEX_options* option // defines the print level + void ) ; +// SPEX is thread-safe but it requires each user thread to call +// SPEX_thread_initialize when it starts, and SPEX_thread_finalize when it +// finishes. These two functions must be called after the user's primary thread +// calls SPEX_initialize (or SPEX_initialize_experm) and before the user's +// primary thread calls SPEX_finalize. -/* Purpose: This function takes as input a mpz_t SPEX_matrix and divides - * it by an mpz_t constant storing the solution in a mpq_t dense SPEX_matrix - * array. - */ -SPEX_info SPEX_matrix_div // divides the x matrix by a scalar -( - SPEX_matrix **x2_handle, // x2 = x/scalar - SPEX_matrix* x, // input vector x - const mpz_t scalar, // the scalar - const SPEX_options *option -) ; +SPEX_info SPEX_thread_initialize ( void ) ; + +SPEX_info SPEX_thread_finalize ( void ) ; -/* Purpose: This function multiplies matrix x a scalar - */ -SPEX_info SPEX_matrix_mul // multiplies x by a scalar +//------------------------------------------------------------------------------ +// SPEX matrix utilities +//------------------------------------------------------------------------------ + +// Purpose: This function sets C = A', where A must be a SPEX_CSC matrix +// C_handle is NULL on input. On output, C_handle contains a pointer to A' + +SPEX_info SPEX_transpose ( - SPEX_matrix *x, // matrix to be multiplied - const mpz_t scalar // scalar to multiply by + SPEX_matrix *C_handle, // C = A' + SPEX_matrix A, // Matrix to be transposed + const SPEX_options option ) ; +// Purpose: Determine if the input A is symmetric. Since SPEX is an exact +// framework, the method checks if the matrix is symmetric both numerically +// and in its symbolic pattern. The method has no option for checking just +// pattern symmetry. -/* SPEX_check_solution: checks the solution of the linear system. Performs a - * quick rational arithmetic check of A*x=b. - */ -SPEX_info SPEX_check_solution -( - const SPEX_matrix *A, // input matrix - const SPEX_matrix *x, // solution vector - const SPEX_matrix *b, // right hand side - const SPEX_options* option // Command options -); - -/* Purpose: p [0..n] = cumulative sum of c [0..n-1], and then copy p [0..n-1] - * into c. This function is lightly modified from CSparse. - */ -SPEX_info SPEX_cumsum +SPEX_info SPEX_determine_symmetry ( - int64_t *p, // vector to store the sum of c - int64_t *c, // vector which is summed - int64_t n // size of c -); + bool *is_symmetric, // true if matrix is symmetric, false otherwise + const SPEX_matrix A, // Input matrix to be checked for symmetry + const SPEX_options option // Command options +) ; +// ended HERE on Apr 10. //------------------------------------------------------------------------------ //---------------------------SPEX GMP/MPFR Functions---------------------------- @@ -749,7 +825,7 @@ SPEX_info SPEX_cumsum // allocated by that function. The list is started fresh each time a GMP // function is called. If any allocation fails, the NULL pointer is not // returned to GMP. Instead, all allocated blocks in the list are freed, -// and spex_gmp_allocate returns directly to wrapper. +// and the allocation routine passed to GMP returns directly to the wrapper. SPEX_info SPEX_mpfr_asprintf (char **str, const char *format, ... ) ; @@ -757,7 +833,7 @@ SPEX_info SPEX_gmp_fscanf (FILE *fp, const char *format, ... ) ; SPEX_info SPEX_mpz_init (mpz_t x) ; -SPEX_info SPEX_mpz_init2(mpz_t x, const size_t size) ; +SPEX_info SPEX_mpz_init2(mpz_t x, const uint64_t size) ; SPEX_info SPEX_mpz_set (mpz_t x, const mpz_t y) ; @@ -765,28 +841,38 @@ SPEX_info SPEX_mpz_set_ui (mpz_t x, const uint64_t y) ; SPEX_info SPEX_mpz_set_si (mpz_t x, const int64_t y) ; +SPEX_info SPEX_mpz_swap (mpz_t x, mpz_t y); + SPEX_info SPEX_mpz_get_d (double *x, const mpz_t y) ; SPEX_info SPEX_mpz_get_si (int64_t *x, const mpz_t y) ; -SPEX_info SPEX_mpz_set_q (mpz_t x, const mpq_t y) ; - SPEX_info SPEX_mpz_mul (mpz_t a, const mpz_t b, const mpz_t c) ; -#if 0 +SPEX_info SPEX_mpz_mul_si (mpz_t a, const mpz_t b, const int64_t c) ; + +SPEX_info SPEX_mpz_sub (mpz_t a, const mpz_t b, const mpz_t c) ; + SPEX_info SPEX_mpz_add (mpz_t a, const mpz_t b, const mpz_t c) ; SPEX_info SPEX_mpz_addmul (mpz_t x, const mpz_t y, const mpz_t z) ; -#endif SPEX_info SPEX_mpz_submul (mpz_t x, const mpz_t y, const mpz_t z) ; +SPEX_info SPEX_mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d) ; + +SPEX_info SPEX_mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d) ; + +SPEX_info SPEX_mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) ; + SPEX_info SPEX_mpz_divexact (mpz_t x, const mpz_t y, const mpz_t z) ; SPEX_info SPEX_mpz_gcd (mpz_t x, const mpz_t y, const mpz_t z) ; SPEX_info SPEX_mpz_lcm (mpz_t lcm, const mpz_t x, const mpz_t y) ; +SPEX_info SPEX_mpz_neg (mpz_t x, const mpz_t y) ; + SPEX_info SPEX_mpz_abs (mpz_t x, const mpz_t y) ; SPEX_info SPEX_mpz_cmp (int *r, const mpz_t x, const mpz_t y) ; @@ -795,6 +881,8 @@ SPEX_info SPEX_mpz_cmpabs (int *r, const mpz_t x, const mpz_t y) ; SPEX_info SPEX_mpz_cmp_ui (int *r, const mpz_t x, const uint64_t y) ; +SPEX_info SPEX_mpz_cmpabs_ui (int *r, const mpz_t x, const uint64_t y) ; + SPEX_info SPEX_mpz_sgn (int *sgn, const mpz_t x) ; SPEX_info SPEX_mpz_sizeinbase (size_t *size, const mpz_t x, int64_t base) ; @@ -805,6 +893,8 @@ SPEX_info SPEX_mpq_set (mpq_t x, const mpq_t y) ; SPEX_info SPEX_mpq_set_z (mpq_t x, const mpz_t y) ; +SPEX_info SPEX_mpq_canonicalize (mpq_t x); + SPEX_info SPEX_mpq_set_d (mpq_t x, const double y) ; SPEX_info SPEX_mpq_set_ui (mpq_t x, const uint64_t y, const uint64_t z) ; @@ -815,10 +905,10 @@ SPEX_info SPEX_mpq_set_num (mpq_t x, const mpz_t y) ; SPEX_info SPEX_mpq_set_den (mpq_t x, const mpz_t y) ; -SPEX_info SPEX_mpq_get_den (mpz_t x, const mpq_t y) ; - SPEX_info SPEX_mpq_get_d (double *x, const mpq_t y) ; +SPEX_info SPEX_mpq_neg (mpq_t x, const mpq_t y) ; + SPEX_info SPEX_mpq_abs (mpq_t x, const mpq_t y) ; SPEX_info SPEX_mpq_add (mpq_t x, const mpq_t y, const mpq_t z) ; @@ -874,83 +964,352 @@ SPEX_info SPEX_mpfr_free_cache (void) ; SPEX_info SPEX_mpfr_free_str (char *str) ; -#if 0 -// These functions are currently unused, but kept here for future reference. -SPEX_info SPEX_gmp_asprintf (char **str, const char *format, ... ) ; -SPEX_info SPEX_gmp_printf (const char *format, ... ) ; -SPEX_info SPEX_mpfr_printf ( const char *format, ... ) ; -SPEX_info SPEX_gmp_fprintf (FILE *fp, const char *format, ... ) ; -SPEX_info SPEX_mpfr_fprintf (FILE *fp, const char *format, ... ) ; -SPEX_info SPEX_mpz_set_d (mpz_t x, const double y) ; -SPEX_info SPEX_mpfr_log2(mpfr_t x, const mpfr_t y, const mpfr_rnd_t rnd) ; -#endif +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------SPEX Left LU----------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This portion of the SPEX library solves a sparse system of linear equations +// using the SPEX Left LU factorization. This code accompanies the paper +// (submitted to ACM Transactions on Mathematical Software): + +// "Algorithm 1021: SPEX Left LU, Exactly Solving Sparse Linear Systems via +// a Sparse Left-looking Integer-preserving LU Factorization", +// C. Lourenco, J. Chen, E. Moreno-Centeno, T. Davis, +// ACM Trans. Mathematical Software. pp 1-23, vol 48, no 2, 2022. + +// The theory associated with this software can be found in the paper +// (published in SIAM journal on matrix analysis and applications): + +// "Exact Solution of Sparse Linear Systems via Left-Looking +// Roundoff-Error-Free LU Factorization in Time Proportional to +// Arithmetic Work", C. Lourenco, A. R. Escobedo, E. Moreno-Centeno, +// T. Davis, SIAM J. Matrix Analysis and Applications. pp 609-638, +// vol 40, no 2, 2019. + +// If you use this code, you must first download and install the GMP and +// MPFR libraries. GMP and MPFR can be found at: +// https://gmplib.org/ +// http://www.mpfr.org/ + +// If you use SPEX Left LU for a publication, we request that you please cite +// the above two papers. + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------Authors---------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// Christopher Lourenco, Jinhao Chen, Timothy A. Davis, and Erick Moreno-Centeno + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//--------------------------Summary--------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This software package solves the linear system Ax = b exactly. The input +// matrix and right hand side vectors are stored as either integers, double +// precision numbers, multiple precision floating points (through the mpfr +// library) or as rational numbers (as a collection of numerators and +// denominators using the GMP mpq_t data structure). Appropriate routines +// within the code transform the input into an integral matrix in compressed +// column form. + +// This package computes the factorization PAQ = LDU. Note that we store the +// "functional" form of the factorization by only storing L and U. The user +// is given some freedom to select the permutation matrices P and Q. The +// recommended default settings select Q using the COLAMD column ordering +// and select P via a partial pivoting scheme in which the diagonal entry +// in column k is selected if it is the same magnitude as the smallest +// entry, otherwise the smallest entry is selected as the kth pivot. +// Alternative strategies allowed to select Q include the AMD column +// ordering or no column permutation (Q=I). For pivots, there are a variety +// of potential schemes including traditional partial pivoting, diagonal +// pivoting, tolerance pivoting etc. This package does not allow pivoting +// based on sparsity criterion. + +// The factors L and U are computed via integer preserving operations via +// integer-preserving Gaussian elimination. The key part of this algorithm +// is a Roundoff Error Free (REF) sparse triangular solve function which +// exploits sparsity to reduce the number of operations that must be +// performed. + +// Once L and U are computed, a simplified version of the triangular solve +// is performed which assumes the vector b is dense. The final solution +// vector x is gauranteed to be exact. This vector can be output in one of +// three ways: 1) full precision rational arithmetic (as a sequence of +// numerators and denominators) using the GMP mpq_t data type, 2) double +// precision while not exact will produce a solution accurate to machine +// roundoff unless the size of the associated solution exceeds double +// precision (i.e., the solution is 10^500 or something), 3) variable +// precision floating point using the GMP mpfr_t data type. The associated +// precision is user defined. -#endif //------------------------------------------------------------------------------ // Primary factorization & solve routines //------------------------------------------------------------------------------ -// SPEX_backslash solves the linear system Ax = b. This is the simplest way to -// use the SPEX Left LU package. This function encompasses both factorization and -// solve and returns the solution vector in the user desired type. It can be -// thought of as an exact version of MATLAB sparse backslash. -SPEX_info SPEX_Left_LU_backslash +// SPEX_lu_backslash solves the linear system Ax = b via LU factorization +// of A. This is the simplest way to use the SPEX Left LU package. This +// function encompasses both factorization and solve and returns the solution +// vector in the user desired type. It can be thought of as an exact version +// of MATLAB sparse backslash. +// x and b be can be single vectors, or matrices. + +SPEX_info SPEX_lu_backslash ( // Output - SPEX_matrix **X_handle, // Final solution vector + SPEX_matrix *x_handle, // Final solution vector // Input - SPEX_type type, // Type of output desired: - // Must be SPEX_MPQ, SPEX_MPFR, - // or SPEX_FP64 - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *b, // Right hand side vector(s) - const SPEX_options* option + SPEX_type type, // Type of output desired. Must be + // SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 + const SPEX_matrix A, // Input matrix + const SPEX_matrix b, // Right hand side vector(s) + const SPEX_options option // Command options ) ; -// SPEX_Left_LU_factorize performs the SPEX Left LU factorization. -// This factorization is done via n iterations of the sparse REF -// triangular solve function. The overall factorization is -// PAQ = LDU. The determinant can be obtained as rhos->x.mpz[n-1]. -// -// L: undefined on input, created on output -// U: undefined on input, created on output -// rhos: undefined on input, created on output -// pinv: undefined on input, created on output -// -// A: input only, not modified -// S: input only, not modified -// option: input only, not modified -SPEX_info SPEX_Left_LU_factorize +SPEX_info SPEX_lu_analyze +( + SPEX_symbolic_analysis *S_handle, // symbolic analysis including + // column perm. and nnz of L and U + const SPEX_matrix A, // Input matrix + const SPEX_options option // Control parameters, if NULL, use default +) ; + +SPEX_info SPEX_lu_factorize ( // output: - SPEX_matrix **L_handle, // lower triangular matrix - SPEX_matrix **U_handle, // upper triangular matrix - SPEX_matrix **rhos_handle, // sequence of pivots - int64_t **pinv_handle, // inverse row permutation + SPEX_factorization *F_handle, // LU factorization // input: - const SPEX_matrix *A, // matrix to be factored - const SPEX_LU_analysis *S, // column permutation and estimates - // of nnz in L and U - const SPEX_options* option + const SPEX_matrix A, // matrix to be factored + const SPEX_symbolic_analysis S, // symbolic analysis + const SPEX_options option // command options ) ; -// SPEX_Left_LU_solve solves the linear system LD^(-1)U x = b. -SPEX_info SPEX_Left_LU_solve // solves the linear system LD^(-1)U x = b +// solves the linear system Ax = b via LU factorization. +// x and b be can be single vectors, or matrices. + +SPEX_info SPEX_lu_solve // solves the linear system LD^(-1)U x = b ( // Output - SPEX_matrix **X_handle, // rational solution to the system + SPEX_matrix *x_handle, // rational solution to the system + // input/output: + SPEX_factorization F, // The LU factorization. + // Mathematically, F is unchanged. // input: - const SPEX_matrix *b, // right hand side vector - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *L, // lower triangular matrix - const SPEX_matrix *U, // upper triangular matrix - const SPEX_matrix *rhos, // sequence of pivots - const SPEX_LU_analysis *S, // symbolic analysis struct - const int64_t *pinv, // inverse row permutation - const SPEX_options* option + const SPEX_matrix b, // right hand side vector(s) + const SPEX_options option // Command options +) ; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------SPEX Cholesky---------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This portion of the SPEX library exactly solves a sparse symmetric positive +// definite (SPD) system of linear equations using one of two Integer- +// Preserving Cholesky factorizations. This code accompanies the paper (to be +// submitted to ACM TOMs) + +// "Algorithm 1xxx: Exactly Solving Sparse Symmetric Positive Definite +// Linear Systems via SPEX Cholesky factorization," C. Lourenco, L. Mejia +// Domenzain, E. Moreno-Centeno, T. Davis, to be submitted ACM TOMS. + +// The theory associated with this paper is found at: + +// "Exactly Solving Sparse Rational Linear Systems via Roundoff-Error-Free +// Cholesky Factorizations", C. Lourenco, E. Moreno-Centeno, +// SIAM J. Matrix Analysis and Applications. +// pp 609-638, vol 43, no 1, 2022. + +// To use this code you must first download and install the GMP, +// MPFR, AMD, and COLAMD libraries. GMP and MPFR can be found at: +// https://gmplib.org/ +// http://www.mpfr.org/ +// +// SPEX_Utilities, AMD, and COLAMD are distributed along with SPEX_Cholesky. +// The easiest way ensure these dependencies are met is to only access this +// package through the SPEX repository. +// +// All of these codes are components of the SPEX software library. This code +// may be found at: +// https://github.com/clouren/spex +// www.suitesparse.com +// +// + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------Authors---------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//--------------------------Summary--------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This software package solves the SPD linear system Ax = b exactly. The +// key property of this package is that it can exactly solve any SPD input +// system. The input matrix and right hand side vectors are stored as +// either integers, double precision numbers, multiple precision floating +// points (through the mpfr library) or as rational numbers (as a collection +// of numerators and denominators using the GMP mpq_t data structure). +// Appropriate routines within the code transform the input into an integral +// matrix in compressed column form. + +// This package computes the factorization PAP' = LDL'. Note that we store +// the "functional" form of the factorization by only storing the matrix L. +// The user is given some freedom to select the permutation matrix P. The +// recommended default settings select P using the AMD ordering. +// Alternative strategies allowed to select P include the COLAMD +// ordering or no column permutation (P=I). + +// The factor L is computed via integer preserving operations via +// integer-preserving Gaussian elimination. The key part of this algorithm +// is a REF Sparse triangular solve function which exploits sparsity and +// symmetry to reduce the number of operations that must be performed. + +// Once L is computed, a simplified version of the triangular solve +// is performed which assumes the vector b is dense. The final solution +// vector x is gauranteed to be exact. This vector can be output in one of +// three ways: 1) full precision rational arithmetic (as a sequence of +// numerators and denominators) using the GMP mpq_t data type, 2) double +// precision while not exact will produce a solution accurate to machine +// roundoff unless the size of the associated solution exceeds double +// precision (i.e., the solution is 10^500 or something), 3) variable +// precision floating point using the GMP mpfr_t data type. The associated +// precision is user defined. + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-----------------------Primary SPEX Cholesky routines------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// Purpose: Compute the exact solution of Ax = b via Cholesky factorization of A +// On input, A is expected to be SPD and x is NULL +// On output, x contains the solution of the linear system + +SPEX_info SPEX_cholesky_backslash +( + // Output + SPEX_matrix *x_handle, // On input: undefined. + // On output: solution vector(s) + // Input + SPEX_type type, // Type of output desired + // Must be SPEX_FP64, SPEX_MPFR, or SPEX_MPQ + const SPEX_matrix A, // Input matrix. Must be SPEX_MPZ and SPEX_CSC + const SPEX_matrix b, // Right hand side vector(s). Must be + // SPEX_MPZ and SPEX_DENSE + const SPEX_options option // Command options (Default if NULL) +) ; + +SPEX_info SPEX_cholesky_analyze +( + // Output + SPEX_symbolic_analysis *S_handle, // Symbolic analysis data structure + // Input + const SPEX_matrix A, // Input matrix. Must be SPEX_MPZ and SPEX_CSC + const SPEX_options option // Command options (Default if NULL) +) ; + +SPEX_info SPEX_cholesky_factorize +( + // Output + SPEX_factorization *F_handle, // Cholesky factorization struct + //Input + const SPEX_matrix A, // Matrix to be factored. Must be SPEX_MPZ + // and SPEX_CSC + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column + // pointers of L, and the exact number of + // nonzeros of L. + const SPEX_options option // command options. + // Notably, option->chol_type indicates + // whether CHOL_UP (default) or CHOL_LEFT + // is used. +) ; + +// Purpose: After computing the REF Cholesky factorization A = LDL', +// this function solves the associated linear system LDL' x = b. +// +// On input x is undefined, F contains the REF Cholesky factorization +// of A (including L, rhos, and row permutation), b contains +// the user's right hand side. +// +// On output x contains the rational solution of the system LDL' x = b +// x and b be can be single vectors, or matrices. + + +SPEX_info SPEX_cholesky_solve +( + // Output + SPEX_matrix *x_handle, // On input: undefined. + // On output: Rational solution (SPEX_MPQ) + // to the system. + // input/output: + SPEX_factorization F, // The Cholesky factorization. + // Mathematically, F is unchanged. + // input: + const SPEX_matrix b, // Right hand side vector + const SPEX_options option // command options +) ; + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//--------------------------SPEX Backslash-------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// SPEX_backslash is a wrapper for the exact routines contained within the +// SPEX software package. + +// SPEX_BACKSLASH: solve Ax=b via sparse integer-preserving factorization. +// SPEX_backslash: computes the exact solution to the sparse linear system Ax = +// b. A and b may be stored as either int64, double precision, arbitrary +// precision floating point (mpfr_t), arbitrary sized integer (mpz_t), or +// arbitrary size rational numbers (mpq_t). The result x is computed exactly, +// represented in arbitrary-precision rational values. This solution vector +// may be returned in either this rational form, or in double precision or in +// arbitrary precision floating point. +// +// A must be square. If A is SPD, an exact up-looking Cholesky factorization is +// applied. Otherwise, an exact left-looking LU functionality is applied. +// x and b be can be single vectors, or matrices. + +//------------------------------------------------------------------------------ +// Purpose: Solve Ax = b by analyzing the input matrix and applying the +// appropiate factorization approach +//------------------------------------------------------------------------------ + +SPEX_info SPEX_backslash +( + // Output + SPEX_matrix *x_handle, // On output: Final solution vector(s) + // On input: undefined + // Input + const SPEX_type type, // Type of output desired + // Must be SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 + const SPEX_matrix A, // Input matrix + const SPEX_matrix b, // Right hand side vector(s) + SPEX_options option // Command options (NULL: means use defaults) ) ; #if defined ( __cplusplus ) @@ -958,3 +1317,4 @@ SPEX_info SPEX_Left_LU_solve // solves the linear system LD^(-1)U x = b #endif #endif + diff --git a/SPEX/Config/Tcov_Makefile.in b/SPEX/Config/Tcov_Makefile.in new file mode 100644 index 0000000000..c0a921c52f --- /dev/null +++ b/SPEX/Config/Tcov_Makefile.in @@ -0,0 +1,271 @@ +#------------------------------------------------------------------------------- +# SPEX/Tcov/Makefile: compile and run SPEX test coverage +#------------------------------------------------------------------------------- + +# SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------- + +default: cov + +SUITESPARSE ?= $(realpath $(CURDIR)/../..) + +################################################################################ + +# configured by CMake: +INC = @SPEX_INCS@ +LIBS = ../../SuiteSparse_config/build/libsuitesparseconfig.so \ + ../../AMD/build/libamd.so \ + ../../COLAMD/build/libcolamd.so \ + @SPEX_LIBS@ + +SUITESPARSE_CONFIG_PATH = @SUITESPARSE_CONFIG_PATH@ +COLAMD_PATH = @COLAMD_PATH@ +AMD_PATH = @AMD_PATH@ +GMP_PATH = @GMP_PATH@ +MPFR_PATH = @MPFR_PATH@ + +################################################################################ + + # use 8 jobs by default + JOBS ?= 8 + + LDFLAGS = --coverage + LDFLAGS += -Wl,-rpath=$(SUITESPARSE_CONFIG_PATH):$(AMD_PATH):$(COLAMD_PATH):$(GMP_PATH):$(MPFR_PATH) + + # remove object files, but keep compiled libraries via 'make clean' + CLEAN = *.o *.obj *.ln *.bb *.bbg *.da *.tcov *.gcov gmon.out *.bak *.d \ + *.gcda *.gcno *.aux *.bbl *.blg *.log *.toc *.dvi *.lof *.lot + + # also remove compiled libraries, via 'make distclean' + PURGE = *.so* *.a *.dll *.dylib *.dSYM + +################################################################################ + +# select the thread-safety mechanism to test: none, openmp, or pthreads. +# THREADS = +# THREADS = -fopenmp + THREADS = -DSPEX_USE_PTHREADS -pthread + +# Linux test coverage (gcc is required for test coverage) +CC = gcc +CFLAGS = -g -fprofile-arcs -ftest-coverage \ + -Wall -W -Wshadow -Wmissing-prototypes -Wstrict-prototypes \ + -Wredundant-decls -Wnested-externs -Wdisabled-optimization -std=c99 \ + -Wno-unused-parameter \ + $(INC) -I../Demo \ + -DSPEX_GMP_LIST_INIT=2 -DSPEX_GMP_TEST_COVERAGE $(THREADS) + +# run all statement coverage tests, and then check for 100% coverage +cov: runtests + ./covall + +all: tcov_for_lu spex_demo_lu_extended tcov_for_cholesky tcov_for_lu2 + +#------------------------------------------------------------------------------- +# compile .c file in this folder + +OBJ_Tcov = tcov_utilities.o + +$(OBJ_Tcov): tcov_utilities.h + +#------------------------------------------------------------------------------- +# link and compile each .c file in SPEX_Utilities/Source + +OBJ_Util = \ + SPEX_version.o \ + SPEX_calloc.o \ + spex_cast_array.o \ + spex_cast_matrix.o \ + SPEX_create_default_options.o \ + spex_create_mpfr_array.o \ + spex_create_mpq_array.o \ + spex_create_mpz_array.o \ + spex_cumsum.o \ + spex_expand_double_array.o \ + spex_expand_mpfr_array.o \ + spex_expand_mpq_array.o \ + SPEX_finalize.o \ + SPEX_free.o \ + SPEX_gmp.o \ + SPEX_initialize.o \ + SPEX_initialize_expert.o \ + SPEX_malloc.o \ + SPEX_matrix_allocate.o \ + SPEX_matrix_check.o \ + SPEX_matrix_copy.o \ + SPEX_matrix_free.o \ + spex_matrix_mul.o \ + SPEX_matrix_nnz.o \ + spex_permute_dense_matrix.o \ + SPEX_realloc.o \ + spex_sparse_collapse.o \ + spex_sparse_realloc.o \ + SPEX_symbolic_analysis_free.o \ + SPEX_factorization_free.o \ + SPEX_determine_symmetry.o \ + SPEX_transpose.o \ + spex_amd.o \ + spex_colamd.o \ + spex_create_mpq.o + +$(OBJ_Util): ../Include/SPEX.h ../SPEX_Utilities/Source/spex_util_internal.h + +.PRECIOUS: SPEX_%.c spex_%.c + +SPEX_%.c: + - ln -s ../SPEX_Utilities/Source/$@ + +spex_%.c: + - ln -s ../SPEX_Utilities/Source/$@ + +#------------------------------------------------------------------------------- +# link and compile each .c file in SPEX_LU/Source + +OBJ_LU = \ + SPEX_lu_analyze.o \ + SPEX_lu_backslash.o \ + spex_left_lu_back_sub.o \ + spex_left_lu_dfs.o \ + SPEX_lu_factorize.o \ + spex_left_lu_forward_sub.o \ + spex_left_lu_get_largest_pivot.o \ + spex_left_lu_get_nonzero_pivot.o \ + spex_left_lu_get_pivot.o \ + spex_left_lu_get_smallest_pivot.o \ + spex_left_lu_reach.o \ + spex_left_lu_ref_triangular_solve.o \ + SPEX_lu_solve.o + +.PRECIOUS: SPEX_lu_%.c SPEX_lu_%.c spex_left_lu_%.c + +SPEX_lu_%.c: + - ln -s ../SPEX_LU/Source/$@ + +SPEX_lu_%.c: + - ln -s ../SPEX_LU/Source/$@ + +spex_left_lu_%.c: + - ln -s ../SPEX_LU/Source/$@ + +#------------------------------------------------------------------------------- +# compile each .c file in Demo/Utilities + +DEMO_SRC = \ + ../Demo/Utilities/spex_demo_check_solution.c \ + ../Demo/Utilities/spex_demo_determine_error.c \ + ../Demo/Utilities/spex_demo_process_command_line.c \ + ../Demo/Utilities/spex_demo_read_dense.c \ + ../Demo/Utilities/spex_demo_tripread.c + +#------------------------------------------------------------------------------- +# link and compile each .c file in SPEX_Cholesky/Source + +OBJ_Cholesky = \ + SPEX_cholesky_analyze.o \ + SPEX_cholesky_backslash.o \ + spex_cholesky_backward_sub.o \ + spex_cholesky_counts.o \ + spex_cholesky_ereach.o \ + spex_cholesky_etree.o \ + spex_cholesky_factor.o \ + SPEX_cholesky_factorize.o \ + spex_cholesky_forward_sub.o \ + spex_cholesky_leaf.o \ + spex_cholesky_left_factor.o \ + spex_cholesky_left_triangular_solve.o \ + spex_cholesky_permute_A.o \ + spex_cholesky_post.o \ + spex_cholesky_pre_left_factor.o \ + spex_cholesky_preorder.o \ + SPEX_cholesky_solve.o \ + spex_cholesky_symbolic_analysis.o \ + spex_cholesky_tdfs.o \ + spex_cholesky_up_factor.o \ + spex_cholesky_up_triangular_solve.o + +$(OBJ_Cholesky): ../Include/SPEX.h + +.PRECIOUS: SPEX_cholesky_%.c spex_cholesky_%.c + +SPEX_cholesky_%.c: + - ln -s ../SPEX_Cholesky/Source/$@ + +spex_cholesky_%.c: + - ln -s ../SPEX_Cholesky/Source/$@ + +#chol_demos.c: +# - ln -s ../SPEX_Cholesky/Demo/$@ + +#------------------------------------------------------------------------------- + +tcov_for_lu: $(OBJ_Tcov) $(OBJ_Util) $(OBJ_LU) tcov_for_lu.c + $(CC) $(LDFLAGS) tcov_for_lu.c $(CFLAGS) -o tcov_for_lu $(OBJ_Tcov) $(OBJ_Util) $(OBJ_LU) $(LIBS) + +tcov_for_lu2: $(OBJ_Tcov) $(OBJ_Util) $(OBJ_Cholesky) tcov_for_lu2.c simple_rand.c simple_rand.h $(DEMO_SRC) + $(CC) $(LDFLAGS) $(CFLAGS) tcov_for_lu2.c simple_rand.c $(DEMO_SRC) -o tcov_for_lu2 $(OBJ_Tcov) $(OBJ_Util) $(OBJ_LU) $(LIBS) + +spex_demo_lu_extended: $(OBJ_Util) $(OBJ_LU) ../Demo/spex_demo_lu_extended.c $(DEMO_SRC) ../Demo/spex_demos.h + $(CC) $(LDFLAGS) ../Demo/spex_demo_lu_extended.c $(DEMO_SRC) $(CFLAGS) -o spex_demo_lu_extended $(OBJ_Tcov) $(OBJ_Util) $(OBJ_LU) $(LIBS) + +tcov_for_cholesky: $(OBJ_Tcov) $(OBJ_Util) $(OBJ_Cholesky) tcov_for_cholesky.c simple_rand.c simple_rand.h $(DEMO_SRC) + $(CC) $(LDFLAGS) $(CFLAGS) tcov_for_cholesky.c simple_rand.c $(DEMO_SRC) -o tcov_for_cholesky $(OBJ_Tcov) $(OBJ_Util) $(OBJ_Cholesky) $(LIBS) + +#------------------------------------------------------------------------------- + +# run all statement coverage tests +runtests: runtests4llu runtests4chol + +# only run test for SPEX_LU +runtests4llu: all + - ./spex_demo_lu_extended p 2 q 1 f ../ExampleMats/10teams.mat.txt ../ExampleMats/10teams.rhs.txt > lu1.out + - ./spex_demo_lu_extended p 3 q 2 o 1 f ../ExampleMats/10teams.mat.txt ../ExampleMats/10teams.rhs.txt > lu2.out + - ./spex_demo_lu_extended p 4 q 3 o 1 f ../ExampleMats/test.mat.txt ../ExampleMats/test.rhs.txt > lu3.out + - ./spex_demo_lu_extended p 5 f ../ExampleMats/10teams.mat.txt ../ExampleMats/10teams.rhs.txt > lu4.out + - ./tcov_for_lu > test_for_lu.out + - ./tcov_for_lu 0 1 1 > lu5.out + - ./tcov_for_lu2 ../ExampleMats/Trefethen_500.mat.txt ../ExampleMats/Trefethen_500.rhs.txt > test_for_lu2.out + + +# only run test for SPEX_Cholesky +runtests4chol: all + - ./tcov_for_cholesky ../ExampleMats/mesh1e1.mat.txt ../ExampleMats/mesh1e1.rhs.txt > test_for_cholesky.out + +#------------------------------------------------------------------------------- + +# To run with valgrind: +# V = valgrind +V = valgrind --leak-check=full --show-leak-kinds=all + +# run all statement coverage tests but with valgrind +vtests: vtests4llu vtests4chol + +# run test for SPEX_LU with valgrind +vtests4llu: all + - $(V) ./spex_demo_lu_extended p 2 q 0 f ../ExampleMats/10teams_mat.txt ../ExampleMats/10teams_v.txt > lu1.out + - $(V) ./spex_demo_lu_extended p 3 q 1 o 1 f ../ExampleMats/10teams_mat.txt ../ExampleMats/10teams_v.txt > lu2.out + - $(V) ./spex_demo_lu_extended p 4 q 2 o 1 f ../ExampleMats/test_mat.txt ../ExampleMats/test_rhs.txt > lu3.out + - $(V) ./spex_demo_lu_extended p 5 f ../ExampleMats/10teams_mat.txt ../ExampleMats/10teams_v.txt > lu4.out + - $(V) ./tcov_for_lu > test_for_lu.out + - $(V) ./tcov_for_lu 0 1 1 > lu5.out + + +# run test for SPEX_Cholesky with valgrind +vtests4chol: all + - $(V) ./tcov_for_cholesky ../ExampleMats/872.mat.txt > test_for_cholesky.out + +#------------------------------------------------------------------------------- + +# remove all files not in the original distribution, including symbolic links +clean: + - $(RM) *.o *.bbg *.da *.gcov *.gcda *gcno + - $(RM) tcov_for_lu spex_demo_lu_extended *.out *.a out tcov_for_lu2 + - $(RM) -r SPEX_*.c spex_*.c *.dSYM + - $(RM) -r tcov_for_cholesky + +purge: distclean + +distclean: clean diff --git a/SPEX/Config/spex_deps.m.in b/SPEX/Config/spex_deps.m.in new file mode 100644 index 0000000000..6c20211e54 --- /dev/null +++ b/SPEX/Config/spex_deps.m.in @@ -0,0 +1,22 @@ +function [suitesparse_libdir, suitesparse_incdir, gmp_lib, gmp_include, mpfr_lib, mpfr_include] = spex_deps +%SPEX_DEPS: return location of GMP and MPFR libraries and include files +% The SPEX/MATLAB/spex_deps.m function is configured by cmake, from the +% source file SPEX/Config/spex_deps.m.in. +% +% On Linux you may need to add the following to your shell script (typically +% .bashrc), start a new shell, and then start MATLAB again. +% +% LD_LIBRARY_PATH=$LD_LIBRARY_PATH:@SUITESPARSE_LIBDIR@ + +% SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +% Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +% All Rights Reserved. +% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +suitesparse_libdir = '@libdir@' ; +suitesparse_incdir = '@includedir@' ; +gmp_lib = '@GMP_LIBRARY@' ; +gmp_include = '@GMP_INCLUDE_DIR@' ; +mpfr_lib = '@MPFR_LIBRARY@' ; +mpfr_include = '@MPFR_INCLUDE_DIR@' ; + diff --git a/SPEX/SPEX_Util/Source/SPEX_check_solution.c b/SPEX/Demo/Utilities/spex_demo_check_solution.c similarity index 51% rename from SPEX/SPEX_Util/Source/SPEX_check_solution.c rename to SPEX/Demo/Utilities/spex_demo_check_solution.c index 573333f7b1..9e2a8c8a13 100644 --- a/SPEX/SPEX_Util/Source/SPEX_check_solution.c +++ b/SPEX/Demo/Utilities/spex_demo_check_solution.c @@ -1,58 +1,63 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_check_solution: check solution to Ax=b +// Demo/spex_check_solution: checks whether a given vector exactly solves Ax=b //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -/* Purpose: Given a solution vector x, check the solution of the linear system - * Ax = b. This is done by computing a rational-arthmetic A*x == b. This function - * is only used for debugging purposes, as the routines within SPEX are gauranteed - * to be exact. - */ -#define SPEX_FREE_ALL \ +#include "spex_demos.h" + +#undef FREE_WORKSPACE +#define FREE_WORKSPACE \ +{ \ SPEX_MPQ_CLEAR(temp); \ - SPEX_matrix_free(&b2, NULL); + SPEX_MPQ_CLEAR(scale); \ + SPEX_matrix_free(&b2, NULL); \ +} -#include "spex_util_internal.h" -SPEX_info SPEX_check_solution +SPEX_info spex_demo_check_solution ( - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *x, // Solution vectors - const SPEX_matrix *b, // Right hand side vectors - const SPEX_options* option // Command options + const SPEX_matrix A, // Input matrix + const SPEX_matrix x, // Solution vectors + const SPEX_matrix b, // Right hand side vectors + const SPEX_options option // Command options ) { - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!SPEX_initialize ( )) return (SPEX_PANIC); //-------------------------------------------------------------------------- // check inputs. Input are also checked by the two callers //-------------------------------------------------------------------------- SPEX_info info ; - SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ) ; - SPEX_REQUIRE (x, SPEX_DENSE, SPEX_MPQ) ; - SPEX_REQUIRE (b, SPEX_DENSE, SPEX_MPZ) ; + /*SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ); + SPEX_REQUIRE (x, SPEX_DENSE, SPEX_MPQ); + SPEX_REQUIRE (b, SPEX_DENSE, SPEX_MPZ);*/ //-------------------------------------------------------------------------- // Declare vars //-------------------------------------------------------------------------- - int64_t p, j, i ; - SPEX_matrix *b2 = NULL; // b2 stores the solution of A*x + int64_t p, j, i, nz; + SPEX_matrix b2 = NULL; // b2 stores the solution of A*x mpq_t temp; SPEX_MPQ_SET_NULL(temp); + mpq_t scale; SPEX_MPQ_SET_NULL(scale); - SPEX_CHECK (SPEX_mpq_init(temp)); + SPEX_MPQ_INIT(temp); + SPEX_MPQ_INIT(scale); SPEX_CHECK (SPEX_matrix_allocate(&b2, SPEX_DENSE, SPEX_MPQ, b->m, b->n, b->nzmax, false, true, option)); + //-------------------------------------------------------------------------- - // perform SPEX_mpq_addmul in loops to compute b2 = A*x + // perform SPEX_mpq_addmul in loops to compute b2 = A'*x, where A' is the + // scaled matrix with all entries in integer //-------------------------------------------------------------------------- for (j = 0; j < b->n; j++) @@ -63,19 +68,37 @@ SPEX_info SPEX_check_solution { // temp = A[p][i] (note this must be done seperately since A is // mpz and temp is mpq) - SPEX_CHECK(SPEX_mpq_set_z(temp, A->x.mpz[p])); + SPEX_MPQ_SET_Z(temp, A->x.mpz[p]); // temp = temp*x[i] - SPEX_CHECK(SPEX_mpq_mul(temp, temp, - SPEX_2D(x, i, j, mpq))); + SPEX_MPQ_MUL(temp, temp, + SPEX_2D(x, i, j, mpq)); // b2[p] = b2[p]-temp - SPEX_CHECK(SPEX_mpq_add(SPEX_2D(b2, A->i[p], j, mpq), - SPEX_2D(b2, A->i[p], j, mpq),temp)); + SPEX_MPQ_ADD(SPEX_2D(b2, A->i[p], j, mpq), + SPEX_2D(b2, A->i[p], j, mpq),temp); } } } + //-------------------------------------------------------------------------- + // Apply scales of A and b to b2 before comparing the b2 with scaled b' + //-------------------------------------------------------------------------- + + SPEX_MPQ_DIV(scale, b->scale, A->scale); + + // Apply scaling factor, but ONLY if it is not 1 + int r; + SPEX_MPQ_CMP_UI(&r, scale, 1, 1); + if (r != 0) + { + nz = x->m * x->n; + for (i = 0; i < nz; i++) + { + SPEX_MPQ_MUL(b2->x.mpq[i], b2->x.mpq[i], scale); + } + } + //-------------------------------------------------------------------------- // check if b==b2 //-------------------------------------------------------------------------- @@ -85,14 +108,14 @@ SPEX_info SPEX_check_solution for (i = 0; i < b->m; i++) { // temp = b[i] (correct b) - SPEX_CHECK(SPEX_mpq_set_z(temp, SPEX_2D(b, i, j, mpz))); + SPEX_MPQ_SET_Z(temp, SPEX_2D(b, i, j, mpz)); // set check false if b!=b2 - int r ; - SPEX_CHECK(SPEX_mpq_equal(&r, temp, SPEX_2D(b2, i, j, mpq))); + SPEX_MPQ_EQUAL(&r, temp, SPEX_2D(b2, i, j, mpq)); if (r == 0) { - info = SPEX_INCORRECT; + //printf("ERROR\n"); + info = SPEX_PANIC; j = b->n; break; } @@ -103,23 +126,22 @@ SPEX_info SPEX_check_solution // Print info //-------------------------------------------------------------------------- - int pr = SPEX_OPTION_PRINT_LEVEL (option) ; + int pr = SPEX_OPTION_PRINT_LEVEL (option); if (info == SPEX_OK) { - SPEX_PR1 ("Solution is verified to be exact.\n") ; + SPEX_PR1 ("Solution is verified to be exact.\n"); } - else if (info == SPEX_INCORRECT) + else if (info == SPEX_PANIC) { // This can never happen. SPEX_PR1 ("ERROR! Solution is wrong. This is a bug; please " - "contact the authors of SPEX.\n") ; + "contact the authors of SPEX.\n"); } //-------------------------------------------------------------------------- // Free memory //-------------------------------------------------------------------------- - SPEX_FREE_ALL; + FREE_WORKSPACE ; return info; } - diff --git a/SPEX/Demo/Utilities/spex_demo_determine_error.c b/SPEX/Demo/Utilities/spex_demo_determine_error.c new file mode 100644 index 0000000000..3cc1d9806e --- /dev/null +++ b/SPEX/Demo/Utilities/spex_demo_determine_error.c @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// Demo/spex_determine_error: auxiliary file for test coverage (tcov) +//------------------------------------------------------------------------------ + +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: Determine why a SPEX function failed + */ + +#include "spex_demos.h" + + +void spex_demo_determine_error +( + SPEX_info ok +) +{ + if (ok == SPEX_OUT_OF_MEMORY) + { + printf("\nOut of memory\n"); + } + else if (ok == SPEX_SINGULAR) + { + printf("\nInput matrix is singular OR no diagonal pivot. Please ensure input is SPD\n"); + } + else if (ok == SPEX_INCORRECT_INPUT) + { + printf("\nIncorrect input for a SPEX_Chol Function\n"); + } +} diff --git a/SPEX/Demo/Utilities/spex_demo_process_command_line.c b/SPEX/Demo/Utilities/spex_demo_process_command_line.c new file mode 100644 index 0000000000..c05bcf25c4 --- /dev/null +++ b/SPEX/Demo/Utilities/spex_demo_process_command_line.c @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +// Demo/spex_process_command_line: processes command line for user specified options +//------------------------------------------------------------------------------ + +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This processes the command line for user specified options */ + +#include "spex_demos.h" + +SPEX_info spex_demo_process_command_line //processes the command line +( + int64_t argc, // number of command line arguments + char *argv[], // set of command line arguments + SPEX_options option, // struct containing the command options + char **mat_name, // Name of the matrix to be read in + char **rhs_name, // Name of the RHS vector to be read in + int64_t *rat // data type of output solution. + // 1: mpz, 2: double, 3: mpfr +) +{ + //SPEX_info ok; + for (int64_t i = 1; i < argc; i++) + { + char *arg = (char*) argv[i]; + if ( strcmp(arg,"help") == 0) + { + //SPEX_show_usage(); + return SPEX_INCORRECT_INPUT; + } + else if ( strcmp(arg, "q") == 0 || strcmp(arg,"col") == 0) + { + if (!argv[++i]) + { + printf("\n****ERROR! There must be an argument between 0-2" + "following q\n"); + return SPEX_INCORRECT_INPUT; + } + option->order = atoi(argv[i]); + if (option->order < 0 || option->order > 2) + { + printf("\n****ERROR! Invalid column ordering" + "\nDefaulting to COLAMD\n\n"); + option->order = SPEX_COLAMD; + } + } + else if ( strcmp(arg,"out2") == 0 || strcmp(arg, "o2") == 0) + { + if (!argv[++i]) + { + printf("\n****ERROR! o2 or out2 must be followed by" + " 0 (print nothing) 1 (print err) or 2 (terse) \n"); + return SPEX_INCORRECT_INPUT; + } + else if (!atoi(argv[i])) + { + printf("\n****ERROR! o2 or out2 must be followed by" + " 0 (print nothing) 1 (print err) or 2 (terse) \n"); + return SPEX_INCORRECT_INPUT; + } + option->print_level = atoi(argv[i]); + } + else if ( strcmp(arg, "out") == 0 || strcmp(arg, "o") == 0) + { + if (!argv[++i]) + { + printf("\n****ERROR! o or out must be followed by" + " 1 (rational) 2 (double) or 3 (variable precision) \n"); + return SPEX_INCORRECT_INPUT; + } + else if (!atoi(argv[i])) + { + printf("\n****ERROR! o or out must be followed by" + " 1 (rational) 2 (double) or 3 (variable precision) \n"); + return SPEX_INCORRECT_INPUT; + } + *rat = atoi(argv[i]); + if (*rat < 1 || *rat > 3) + { + printf("\n\n****ERROR! Invalid output type!\n" + "Defaulting to rational"); + *rat = 1; + } + if (*rat == 3) + { + if (!argv[++i]) + { + printf("\n****ERROR! Precision must be specified\n"); + return SPEX_INCORRECT_INPUT; + } + else if (!atoi(argv[i])) + { + printf("\n****ERROR! Precision must be specified\n"); + return SPEX_INCORRECT_INPUT; + } + option->prec = atoi(argv[i]); + if (option->prec < 2) + { + printf("\n\n****ERROR! Invalid precision. prec >= 2\n"); + return SPEX_INCORRECT_INPUT; + } + } + } + else if ( strcmp(arg, "f") == 0 || strcmp(arg, "file") == 0) + { + if (!argv[++i]) + { + printf("\n****ERROR! Matrix name must be entered\n"); + return SPEX_INCORRECT_INPUT; + } + *mat_name = argv[i]; + if (!argv[++i]) + { + printf("\n****ERROR! Right hand side vector name must" + " be entered\n"); + return SPEX_INCORRECT_INPUT; + } + *rhs_name = argv[i]; + } + else + { + printf("\n\n**ERROR! Unknown command line parameter: %s" + "\nIgnoring this parameter\n",arg); + return SPEX_INCORRECT_INPUT; + } + } + return SPEX_OK; +} diff --git a/SPEX/Demo/Utilities/spex_demo_read_dense.c b/SPEX/Demo/Utilities/spex_demo_read_dense.c new file mode 100644 index 0000000000..19faff8a54 --- /dev/null +++ b/SPEX/Demo/Utilities/spex_demo_read_dense.c @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// Demo/spex_read_dense: reads an integral dense matrix +//------------------------------------------------------------------------------ + +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: Read a dense matrix for RHS vectors. + * the values in the file must be integers + */ + +#include "spex_demos.h" + + +SPEX_info spex_demo_read_dense +( + SPEX_matrix *b_handle, // Matrix to be constructed + FILE *file, // file to read from (must already be open) + SPEX_options option +) +{ + + if (file == NULL) + { + printf ("invalid inputs\n"); + return SPEX_INCORRECT_INPUT; + } + int64_t nrows, ncols; + SPEX_info info ; + + // First, we obtain the dimension of the matrix + int s = fscanf(file, "%"PRId64" %"PRId64, &nrows, &ncols); + if (feof(file) || s < 2) + { + printf ("premature end-of-file\n"); + return SPEX_INCORRECT_INPUT; + } + + // Now, we create our dense mpz_t matrix + SPEX_matrix A = NULL; + info = SPEX_matrix_allocate(&A, SPEX_DENSE, SPEX_MPZ, nrows, ncols, + nrows*ncols, false, true, option); + if (info != SPEX_OK) + { + return (info); + } + + // We now populate the matrix b. + for (int64_t i = 0; i < nrows; i++) + { + for (int64_t j = 0; j < ncols; j++) + { + info = SPEX_gmp_fscanf(file, "%Zd", &(A->x.mpz[i+j*nrows])); + if (info != SPEX_OK) + { + printf("\n\nhere at i = %"PRId64" and j = %"PRId64"", i, j); + return SPEX_INCORRECT_INPUT; + } + } + } + + //-------------------------------------------------------------------------- + // Success, set b_handle = A + //-------------------------------------------------------------------------- + + (*b_handle) = A; + return (info); +} diff --git a/SPEX/Demo/Utilities/spex_demo_tripread.c b/SPEX/Demo/Utilities/spex_demo_tripread.c new file mode 100644 index 0000000000..eb8bd8cdbf --- /dev/null +++ b/SPEX/Demo/Utilities/spex_demo_tripread.c @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// Demo/spex_demo_tripread: reads a matrix stored in triplet format of a given type +//------------------------------------------------------------------------------ + +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function reads a matrix stored in triplet format of a given type + * This format used is illustrated in the example mat files. + * + * The first line of the file contains three integers: m, n, nnz, + * where the matrix is m-by-n with nnz entries. + * + * Each of the following nnz lines contains a single triplet: i, j, aij, + * which defines the row index (i), column index (j), and value (aij) of + * the entry A(i,j). + */ + + +#include "spex_demos.h" + +SPEX_info spex_demo_tripread +( + SPEX_matrix *A_handle, // Matrix to be populated + FILE *file, // file to read from (must already be open) + SPEX_type C_type, // C->type: mpz_t or double + SPEX_options option +) +{ + SPEX_info info ; + ASSERT(A_handle!=NULL); + ASSERT(file!=NULL); + + (*A_handle) = NULL ; + + int64_t m, n, nz; + + if (C_type != SPEX_FP64 && C_type != SPEX_MPZ ) + { + printf("%d\n",C_type); + printf ("this function only supports double or mpz matrices\n"); + } + + // Read in size of matrix & number of nonzeros + int s = fscanf(file, "%"PRId64" %"PRId64" %"PRId64"\n", &m, &n, &nz); + if (feof(file) || s < 3) + { + printf ("premature end-of-file 1\n"); + return SPEX_INCORRECT_INPUT; + } + + // Allocate memory for A + // A is a triplet mpz_t or double matrix + SPEX_matrix A = NULL; + info = SPEX_matrix_allocate(&A, SPEX_TRIPLET, C_type, m, n, nz, + false, true, option); + + if (info != SPEX_OK) + { + printf ("unable to allocate matrix\n"); + return (info); + } + + // Read in the values from file + + switch(C_type) + { + case SPEX_FP64: + for (int64_t k = 0; k < nz; k++) + { + s = fscanf(file, "%"PRId64" %"PRId64" %lf\n", + &(A->i[k]), &(A->j[k]), &(A->x.fp64[k])); + if ((feof(file) && k != nz-1) || s < 3) + { + printf ("premature end-of-file\n"); + SPEX_matrix_free(&A, option); + return SPEX_INCORRECT_INPUT; + } + //Conversion from 1 based to 0 based + A->i[k] -= 1; + A->j[k] -= 1; + } + break; + + case SPEX_MPZ: + for (int64_t k = 0; k < nz; k++) + { + info = SPEX_gmp_fscanf(file, "%"PRId64" %"PRId64" %Zd\n", + &A->i[k], &A->j[k], &A->x.mpz[k]); + if ((feof(file) && k != nz-1) || info != SPEX_OK) + { + printf ("premature end-of-file 2\n"); + SPEX_matrix_free(&A, option); + return SPEX_INCORRECT_INPUT; + } + A->i[k] -= 1; + A->j[k] -= 1; + } + break; + default: + printf ("type not supported\n"); + return SPEX_INCORRECT_INPUT; + } + + // the triplet matrix now has nz entries + A->nz = nz; + + info = SPEX_matrix_check (A, option); + if (info != SPEX_OK) + { + printf ("invalid matrix\n"); + return (info); + } + + // A now contains our input matrix in triplet format. We now + // do a matrix copy to get it into CSC form + // C is a copy of A which is CSC and mpz_t + SPEX_matrix C = NULL; + SPEX_matrix_copy(&C, SPEX_CSC, SPEX_MPZ, A, option); + + // Free A, set A_handle + SPEX_matrix_free(&A, option); + (*A_handle) = C; + + return SPEX_OK; +} diff --git a/SPEX/Demo/spex_demo_backslash.c b/SPEX/Demo/spex_demo_backslash.c new file mode 100644 index 0000000000..31e838bbf3 --- /dev/null +++ b/SPEX/Demo/spex_demo_backslash.c @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// Demo/spex_demo_backslash: example of SPEX_Blackslash +//------------------------------------------------------------------------------ + +// SPEX: (c) 2021-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + + +/* A demo of SPEX_Backslash in C + */ + +# include "spex_demos.h" + +#define FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&A,NULL); \ + SPEX_matrix_free(&b,NULL); \ + SPEX_matrix_free(&x,NULL); \ + SPEX_matrix_free(&x2, NULL); \ + SPEX_FREE(option); \ + SPEX_finalize(); \ +} \ + + +int main( int argc, char *argv[] ) +{ + + //-------------------------------------------------------------------------- + // Prior to using SPEX, its environment must be initialized. This is done + // by calling the SPEX_initialize() function. + //-------------------------------------------------------------------------- + SPEX_initialize(); + + //-------------------------------------------------------------------------- + // Declare memory & Process Command Line + //-------------------------------------------------------------------------- + int64_t n = 0, ok; + + SPEX_matrix A = NULL; + SPEX_matrix b = NULL; + SPEX_matrix x = NULL; + SPEX_matrix x2 = NULL; + + // Set default options + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); + + char *mat_name = NULL, *rhs_name = NULL; + int64_t rat = 1; + + // Process the command line + DEMO_OK(spex_demo_process_command_line(argc, argv, option, + &mat_name, &rhs_name, &rat)); + + //-------------------------------------------------------------------------- + // Allocate memory + //-------------------------------------------------------------------------- + + // Read in A + FILE *mat_file = fopen(mat_name,"r"); + if( mat_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + + // Note, there are a few matrices in BasisLIB that dont fit in double + // Need to use the other tripread for those. + DEMO_OK(spex_demo_tripread(&A, mat_file, SPEX_MPZ, option)); + fclose(mat_file); + n = A->n; + + // Read in b. The output of this demo function is b in dense format with + // mpz_t entries + FILE *rhs_file = fopen(rhs_name,"r"); + if( rhs_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + DEMO_OK(spex_demo_read_dense(&b, rhs_file, option)); + fclose(rhs_file); + + //-------------------------------------------------------------------------- + // Solve Ax = b + //-------------------------------------------------------------------------- + + printf("solving Ax=b ...\n"); + fflush (stdout); + fflush (stderr); + double start = SuiteSparse_time (); + + option->print_level = 0; + + DEMO_OK( SPEX_backslash(&x, SPEX_MPQ, A, b, option)); + + double end = SuiteSparse_time (); + + double t_tot = (end - start) ; + + printf("\nSPEX Backslash Factor & Solve time: %lf\n", t_tot); + + option->print_level=1; + DEMO_OK( spex_demo_check_solution(A,x,b,option)); + + + // x2 is a copy of the solution. x2 is a dense matrix with double entries + // Note: roundoff will have occured in converting the exact solution + // to the double x. + DEMO_OK ( SPEX_matrix_copy(&x2, SPEX_DENSE, SPEX_FP64, x, option)); + + //-------------------------------------------------------------------------- + // Free Memory + //-------------------------------------------------------------------------- + FREE_WORKSPACE; +} + diff --git a/SPEX/Demo/spex_demo_cholesky_extended.c b/SPEX/Demo/spex_demo_cholesky_extended.c new file mode 100644 index 0000000000..cbfd154bd8 --- /dev/null +++ b/SPEX/Demo/spex_demo_cholesky_extended.c @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// Demo/spex_demo_cholesky_extended: example of extended call of SPEX_Cholesky +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + + +#include "spex_demos.h" + +#define FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&A,NULL); \ + SPEX_matrix_free(&b,NULL); \ + SPEX_matrix_free(&x,NULL); \ + SPEX_symbolic_analysis_free (&S, option); \ + SPEX_factorization_free(&F, option); \ + SPEX_FREE(option); \ + SPEX_finalize(); \ +} + +int main( int argc, char *argv[] ) +{ + + //-------------------------------------------------------------------------- + // Prior to using SPEX-Chol, its environment must be initialized. This is + // done by calling the SPEX_initialize() function. + //-------------------------------------------------------------------------- + + SPEX_initialize(); + + //-------------------------------------------------------------------------- + // Declare memory & Process Command Line + //-------------------------------------------------------------------------- + int64_t n = 0, ok; + + SPEX_symbolic_analysis S = NULL; + SPEX_factorization F = NULL ; + SPEX_matrix A = NULL; + SPEX_matrix b = NULL; + SPEX_matrix x = NULL; + + char *mat_name, *rhs_name; + int64_t rat = 1; + + // Default options. + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); + + // Process the command line + DEMO_OK(spex_demo_process_command_line(argc, argv, option, + &mat_name, &rhs_name, &rat)); + + //-------------------------------------------------------------------------- + // Allocate memory + //-------------------------------------------------------------------------- + + // Read in A + FILE *mat_file = fopen(mat_name,"r"); + if( mat_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + + DEMO_OK(spex_demo_tripread(&A, mat_file, SPEX_FP64, option)); + fclose(mat_file); + n = A->n; + // For this code, we utilize a vector of all ones as the RHS vector + SPEX_matrix_allocate(&b, SPEX_DENSE, SPEX_MPZ, n, 1, n, false, true, + option); + + // Read in b. The output of this demo function is b in dense format with + // mpz_t entries + FILE *rhs_file = fopen(rhs_name,"r"); + if( rhs_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + DEMO_OK(spex_demo_read_dense(&b, rhs_file, option)); + fclose(rhs_file); + + //-------------------------------------------------------------------------- + // Perform Analysis of A + //-------------------------------------------------------------------------- + + double start_col = SuiteSparse_time (); + + // Symmetric ordering of A. Uncomment the desired one, AMD is recommended + //option->order = SPEX_NO_ORDERING; // No ordering + option->order = SPEX_AMD; // AMD + //option->order = SPEX_COLAMD; // COLAMD + DEMO_OK(SPEX_cholesky_analyze(&S, A, option)); + + double end_col = SuiteSparse_time (); + + //-------------------------------------------------------------------------- + // Factorize PAP + //-------------------------------------------------------------------------- + + //option->algo=SPEX_CHOL_LEFT; + double start_factor = SuiteSparse_time (); + + DEMO_OK( SPEX_cholesky_factorize(&F, A, S, option)); + + double end_factor = SuiteSparse_time (); + + option->print_level=3; + //DEMO_OK(SPEX_matrix_check(F->L,option)); + + //-------------------------------------------------------------------------- + // Solve linear system + //-------------------------------------------------------------------------- + + double start_solve = SuiteSparse_time (); + + DEMO_OK( SPEX_cholesky_solve(&x, F, b, option)); + + double end_solve = SuiteSparse_time (); + + //-------------------------------------------------------------------------- + // Output & Timing Stats + //-------------------------------------------------------------------------- + + double t_col = (end_col-start_col) ; + double t_factor = (end_factor - start_factor) ; + double t_solve = (end_solve - start_solve) ; + + printf("\nNumber of L nonzeros: \t\t\t%ld", + (F->L->p[F->L->n]) ); + printf("\nSymbolic Analysis Check time: \t\t%lf", t_col); + printf("\nIP Chol Factorization time: \t\t%lf", t_factor); + printf("\nFB Substitution time: \t\t\t%lf\n\n", t_solve); + + // Check solution + option->print_level=1; + //DEMO_OK ( SPEX_check_solution(A,x,b,option)); + + //-------------------------------------------------------------------------- + // Free Memory + //-------------------------------------------------------------------------- + + FREE_WORKSPACE; +} + diff --git a/SPEX/Demo/spex_demo_cholesky_simple.c b/SPEX/Demo/spex_demo_cholesky_simple.c new file mode 100644 index 0000000000..2cf702914c --- /dev/null +++ b/SPEX/Demo/spex_demo_cholesky_simple.c @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// Demo/spex_demo_cholesky_simple.c: example of simple call of SPEX_Cholesky +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* This example shows how to use SPEX Chol with a given input matrix and a + * double output. The input is read from a file */ + +// usage: +// example > out +// out is file for output calculated result + +#include "spex_demos.h" + +#define FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&A, option); \ + SPEX_matrix_free(&b, option); \ + SPEX_matrix_free(&x, option); \ + SPEX_matrix_free(&x2, option); \ + SPEX_FREE(option); \ + SPEX_finalize(); \ +} + + +int main (int argc, char **argv) +{ + //-------------------------------------------------------------------------- + // Prior to using SPEX Chol, its environment must be initialized. This is + // done by calling the SPEX_initialize() function. + //-------------------------------------------------------------------------- + SPEX_initialize(); + + //-------------------------------------------------------------------------- + // Get matrix file name + //-------------------------------------------------------------------------- + + char *mat_name; + char *rhs_name; //this is actually ignored and we're using a rhs of 1s + int64_t rat = 1; + if (argc > 2) + { + mat_name = argv[1]; + } + + //-------------------------------------------------------------------------- + // Declare our data structures + //-------------------------------------------------------------------------- + SPEX_info ok; + SPEX_matrix A = NULL ; // input matrix with mpz values + SPEX_matrix b = NULL ; // Right hand side vector + SPEX_matrix x = NULL ; // Solution vectors + SPEX_matrix x2 = NULL ; // copy of solution vectors + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); + if (option == NULL) + { + fprintf (stderr, "Error! OUT of MEMORY!\n"); + FREE_WORKSPACE; + return 0; + } + option->order = SPEX_AMD; //AMD is default for Cholesky + + // Process the command line + DEMO_OK(spex_demo_process_command_line(argc, argv, option, + &mat_name, &rhs_name, &rat)); + + //-------------------------------------------------------------------------- + // Allocate memory, read in A and b + //-------------------------------------------------------------------------- + + // Read in A. The output of this demo function is A in CSC format with + // double entries. + FILE *mat_file = fopen(mat_name,"r"); + if( mat_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + + DEMO_OK(spex_demo_tripread(&A, mat_file, SPEX_FP64, option)); + fclose(mat_file); + + int64_t n = A->n; + SPEX_matrix_allocate(&b, SPEX_DENSE, SPEX_MPZ, n, 1, n, false, true, + option); + + // Read in b. The output of this demo function is b in dense format with + // mpz_t entries + FILE *rhs_file = fopen(rhs_name,"r"); + if( rhs_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + DEMO_OK(spex_demo_read_dense(&b, rhs_file, option)); + fclose(rhs_file); + + // Check if the size of A matches b + if (A->n != b->m) + { + printf("%"PRId64" %"PRId64" \n", A->m,b->m); + fprintf (stderr, "Error! Size of A and b do not match!\n"); + FREE_WORKSPACE; + return 0; + } + //-------------------------------------------------------------------------- + // solve + //-------------------------------------------------------------------------- + double start_s = SuiteSparse_time (); + option->algo=SPEX_CHOL_LEFT; + + DEMO_OK(SPEX_cholesky_backslash( &x, SPEX_MPQ, A, b, option)); + + double end_s = SuiteSparse_time (); + + double t_s = (end_s - start_s) ; + + printf("\nSPEX Chol Factor & Solve time: %lf\n", t_s); + + // x2 is a copy of the solution. x2 is a dense matrix with mpfr entries + DEMO_OK ( SPEX_matrix_copy(&x2, SPEX_DENSE, SPEX_FP64, x, option)); + + // check solution + option->print_level=1; + DEMO_OK ( spex_demo_check_solution(A,x,b,option)); + + //-------------------------------------------------------------------------- + // Free memory + //-------------------------------------------------------------------------- + FREE_WORKSPACE; + + printf ("\n%s: all tests passed\n\n", __FILE__); + + return 0; +} + diff --git a/SPEX/Demo/spex_demo_lu_doub.c b/SPEX/Demo/spex_demo_lu_doub.c new file mode 100644 index 0000000000..203f90793f --- /dev/null +++ b/SPEX/Demo/spex_demo_lu_doub.c @@ -0,0 +1,234 @@ +//------------------------------------------------------------------------------ +// Demo/spex_demo_lu_doub.c: example of simple SPEX_LU call on a double matrix +//------------------------------------------------------------------------------ + +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* This program will exactly solve the sparse linear system Ax = b by + * performing the SPEX Left LU factorization. This is intended to be a + * demonstration of the "advanced interface" of SPEX Left LU. Refer to + * README.txt for information on how to properly use this code + */ + +// usage: +// spex_lu_demo Followed by the listed args: +// +// f (or file) Filename. e.g., spex_lu_demo f MATRIX_NAME RHS_NAME, which +// indicates spex_lu_demo will read matrix from MATRIX_NAME and right hand side +// from RHS_NAME. The matrix must be stored in Matrix Market format. Refer to +// http://math.nist.gov/MatrixMarket/formats.html for information on Matrix +// Market format. The right hand side vector must be stored as a dense vector. +// +// p (or piv) Pivot_param. e.g., spex_lu_demo p 0, which indicates SPEX_LU will +// use smallest pivot for pivot scheme. Other available options are listed as +// follows: +// +// 0: Smallest pivot: Default and recommended +// 1: Diagonal pivoting +// 2: First nonzero per column chosen as pivot +// 3: Diagonal pivoting with tolerance for smallest pivot +// 4: Diagonal pivoting with tolerance for largest pivot +// 5: Largest pivot +// +// q (or col) Column_order_param. e.g., spex_lu_demo q 1, which indicates +// SPEX_LU will use COLAMD for column ordering. Other available options are: +// +// 0: None: Not recommended for sparse matrices 1: COLAMD: Default 2: +// AMD +// +// t (or tol) tolerance_param. e.g., spex_lu_demo t 1e-10, which indicates +// SPEX_LU will use 1e-10 as the tolerance for pivot scheme 3 and 4 mentioned +// above. Therefore, it is only necessary if pivot scheme 3 or 4 is used. +// +// o (or out). e.g., spex_lu_demo o 1, which indicates SPEX_LU will output the +// errors and warnings during the process. Other available options are: 0: +// print nothing 1: just errors and warnings: Default 2: terse, with basic +// stats from COLAMD/AMD and SPEX and solution +// +// If none of the above args is given, they are set to the following default: +// + +#include "spex_demos.h" + +#define FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&A, option); \ + SPEX_factorization_free(&F, option); \ + SPEX_symbolic_analysis_free(&S, option); \ + SPEX_FREE(option); \ + SPEX_finalize(); \ +} + +int main (int argc, char *argv[]) +{ + + //-------------------------------------------------------------------------- + // Prior to using SPEX Left LU, its environment must be initialized. This + // is done by calling the SPEX_initialize() function. + //-------------------------------------------------------------------------- + + SPEX_initialize(); + + //-------------------------------------------------------------------------- + // We first initialize the default parameters. These parameters are modified + // either via command line arguments or when reading in data. The important + // initializations are in the block below. + // + // First, we initialize 6 SPEX_matrices. Note that these matrices must + // simply be declared, they will be created and allocated within their + // respective functions. These matrices are: + // + // A: User input matrix. Must be SPEX_CSC and SPEX_MPZ for routines + // + // L: Lower triangular matrix. Will be output as SPEX_CSC and SPEX_MPZ + // + // U: Upper triangular matrix. Will be output as SPEX_CSC and SPEX_MPZ + // + // x: Solution to the linear system. Will be output as SPEX_DENSE and + // SPEX_MPQ + // + // b: Set of right hand side vectors. Must be SPEX_DENSE and SPEX_MPZ + // + // Additionally, two other data structures are declared here: + // + // pinv: Inverse row permutation used for LDU factorization and + // permutation + // + // S: Symbolic analysis struct. + // + // Lastly, the following parameter is created: + // + // option: Command options for the factorization. In general, this can be + // set to default values and is almost always the last input + // argument for SPEX Left LU functions (except SPEX_malloc and + // such) + //-------------------------------------------------------------------------- + SPEX_matrix A = NULL; + SPEX_symbolic_analysis S = NULL; + SPEX_factorization F = NULL; + SPEX_info ok ; + + // Initialize option, command options for the factorization + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); + + // Extra parameters used to obtain A, b, etc + char *mat_name, *rhs_name; + int64_t rat = 1; + + //-------------------------------------------------------------------------- + // After initializing memory, we process the command line for this function. + // Such a step is optional, a user can also manually set these parameters. + // For example, if one wished to use the AMD ordering, they can just set + // option->order = SPEX_AMD. + //-------------------------------------------------------------------------- + + DEMO_OK(spex_demo_process_command_line(argc, argv, option, + &mat_name, &rhs_name, &rat)); + + //-------------------------------------------------------------------------- + // In this demo file, we now read in the A and b matrices from external + // files. Refer to the example.c file or the user guide for other + // methods of creating the input matrix. In general, the user can create + // his/her matrix (say in double form) and then create a copy of it with + // SPEX_matrix_copy + //-------------------------------------------------------------------------- + + // Read in A + FILE *mat_file = fopen(mat_name,"r"); + if( mat_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + + DEMO_OK(spex_demo_tripread(&A, mat_file, SPEX_FP64, option)); + fclose(mat_file); + +#if 0 + // Read in right hand side + FILE *rhs_file = fopen(rhs_name,"r"); + if( rhs_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + DEMO_OK(SPEX_read_dense(&b, rhs_file, option)); + fclose(rhs_file); + + // Check if the size of A matches b + if (A->n != b->m) + { + fprintf (stderr, "Error! Size of A and b do not match!\n"); + FREE_WORKSPACE; + return 0; + } +#endif + + //-------------------------------------------------------------------------- + // We now perform symbolic analysis by getting the column preordering of + // the matrix A. This is done via the SPEX_lu_analyze function. The output + // of this function is a column permutation Q where we factor the matrix AQ + // and an estimate of the number of nonzeros in L and U. + // + // Note that in the simple interface demostrated in the example*.c files, + // all of the following code is condensed into the single SPEX_backslash + // function. + //-------------------------------------------------------------------------- + + double start_col = SuiteSparse_time (); + + // Column ordering using either AMD, COLAMD or nothing + DEMO_OK(SPEX_lu_analyze(&S, A, option)); + + double end_col = SuiteSparse_time (); + + //-------------------------------------------------------------------------- + // Now we perform the SPEX Left LU factorization to obtain matrices L and U + // and a row permutation P such that PAQ = LDU. Note that the D matrix is + // never explicitly constructed or used. + //-------------------------------------------------------------------------- + + double start_factor = SuiteSparse_time (); + + ok = SPEX_lu_factorize(&F, A, S, option); + if (ok != SPEX_OK) + { + if (ok == SPEX_SINGULAR) + { + printf("\nSingular"); + } + return 0; + } + + double end_factor = SuiteSparse_time (); + + //-------------------------------------------------------------------------- + // We now solve the system Ax=b using the L and U factors computed above. + //-------------------------------------------------------------------------- + + // Timing stats + double t_sym = (end_col-start_col) ; + double t_factor = (end_factor - start_factor) ; + + printf("\nNumber of L+U nonzeros: \t\t%"PRId64, + (F->L->p[F->L->n]) + (F->U->p[F->U->n]) - (F->L->m)); + printf("\nSymbolic analysis time: \t\t%lf", t_sym); + printf("\nSPEX Left LU Factorization time: \t%lf", t_factor); + + //-------------------------------------------------------------------------- + // Free Memory + //-------------------------------------------------------------------------- + + FREE_WORKSPACE; + printf ("\n%s: all tests passed\n\n", __FILE__); + return 0; +} + diff --git a/SPEX/SPEX_Left_LU/Demo/spexlu_demo.c b/SPEX/Demo/spex_demo_lu_extended.c similarity index 65% rename from SPEX/SPEX_Left_LU/Demo/spexlu_demo.c rename to SPEX/Demo/spex_demo_lu_extended.c index b6ca44fa5b..b0d67ccdb2 100644 --- a/SPEX/SPEX_Left_LU/Demo/spexlu_demo.c +++ b/SPEX/Demo/spex_demo_lu_extended.c @@ -1,34 +1,33 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/Demo/spex_lu_demo.c: example main program for SPEX +// Demo/spex_demo_lu_extended.c: example of extended SPEX_LU call for a double matrix. //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -#include "demos.h" - /* This program will exactly solve the sparse linear system Ax = b by - * performing the SPEX Left LU factorization. This is intended to be a demonstration - * of the "advanced interface" of SPEX Left LU. Refer to README.txt for - * information on how to properly use this code + * performing the SPEX Left LU factorization. This is intended to be a + * demonstration of the "advanced interface" of SPEX Left LU. Refer to + * README.txt for information on how to properly use this code */ // usage: -// spex_lu_demo Followed by the listed args: +// spexlu_demo Followed by the listed args: +// +// f (or file) Filename. e.g., spex_lu_demo f MATRIX_NAME RHS_NAME, which +// indicates spex_lu_demo will read matrix from MATRIX_NAME and right hand side +// from RHS_NAME. The matrix must be stored in Matrix Market format. Refer to +// http://math.nist.gov/MatrixMarket/formats.html for information on Matrix +// Market format. The right hand side vector must be stored as a dense vector. // -// f (or file) Filename. e.g., spex_lu_demo f MATRIX_NAME RHS_NAME, which indicates -// spex_lu_demo will read matrix from MATRIX_NAME and right hand side from RHS_NAME. -// The matrix must be stored in Matrix Market format. Refer to -// http://math.nist.gov/MatrixMarket/formats.html for information on -// Matrix Market format. -// The right hand side vector must be stored as a dense vector. +// p (or piv) Pivot_param. e.g., spex_lu_demo p 0, which indicates SPEX_LU will +// use smallest pivot for pivot scheme. Other available options are listed as +// follows: // -// p (or piv) Pivot_param. e.g., spex_lu_demo p 0, which indicates SPEX_Left_LU will use -// smallest pivot for pivot scheme. Other available options are listed -// as follows: // 0: Smallest pivot: Default and recommended // 1: Diagonal pivoting // 2: First nonzero per column chosen as pivot @@ -36,18 +35,21 @@ // 4: Diagonal pivoting with tolerance for largest pivot // 5: Largest pivot // -// q (or col) Column_order_param. e.g., spex_lu_demo q 1, which indicates SPEX_Left_LU -// will use COLAMD for column ordering. Other available options are: -// 0: None: Not recommended for sparse matrices -// 1: COLAMD: Default -// 2: AMD +// q (or col) Column_order_param. e.g., spex_lu_demo q 1, which indicates +// SPEX_LU will use COLAMD for column ordering. Other available options are: +// +// 0: Default: COLAMD +// 1: None: Not recommended for sparse matrices +// 2: COLAMD +// 3: AMD // -// t (or tol) tolerance_param. e.g., spex_lu_demo t 1e-10, which indicates SPEX_Left_LU -// will use 1e-10 as the tolerance for pivot scheme 3 and 4 mentioned above. -// Therefore, it is only necessary if pivot scheme 3 or 4 is used. +// t (or tol) tolerance_param. e.g., spex_lu_demo t 1e-10, which indicates +// SPEX_LU will use 1e-10 as the tolerance for pivot scheme 3 and 4 mentioned +// above. Therefore, it is only necessary if pivot scheme 3 or 4 is used. // -// o (or out). e.g., spex_lu_demo o 1, which indicates SPEX_Left_LU will output the +// o (or out). e.g., spex_lu_demo o 1, which indicates SPEX_LU will output the // errors and warnings during the process. Other available options are: +// // 0: print nothing // 1: just errors and warnings: Default // 2: terse, with basic stats from COLAMD/AMD and SPEX and solution @@ -55,31 +57,30 @@ // // If none of the above args is given, they are set to the following default: // -// mat_name = "../ExampleMats/10teams_mat.txt" -// rhs_name = "../ExampleMats/10teams_v.txt" + // p = 0, i.e., using smallest pivot // q = 1, i.e., using COLAMD // t = 0.1, not being using since p != 3 or 4 +#include "spex_demos.h" #define FREE_WORKSPACE \ +{ \ SPEX_matrix_free(&A, option); \ - SPEX_matrix_free(&L, option); \ - SPEX_matrix_free(&U, option); \ + SPEX_symbolic_analysis_free(&S, option); \ + SPEX_factorization_free(&F, option); \ SPEX_matrix_free(&x, option); \ SPEX_matrix_free(&b, option); \ - SPEX_matrix_free(&rhos, option); \ - SPEX_FREE(pinv); \ - SPEX_LU_analysis_free(&S, option); \ SPEX_FREE(option); \ - SPEX_finalize( ) ; + SPEX_finalize(); \ +} -int main (int argc, char* argv[]) +int main (int argc, char *argv[]) { //-------------------------------------------------------------------------- - // Prior to using SPEX Left LU, its environment must be initialized. This is done - // by calling the SPEX_initialize() function. + // Prior to using SPEX Left LU, its environment must be initialized. This + // is done by calling the SPEX_initialize() function. //-------------------------------------------------------------------------- SPEX_initialize(); @@ -94,47 +95,47 @@ int main (int argc, char* argv[]) // respective functions. These matrices are: // // A: User input matrix. Must be SPEX_CSC and SPEX_MPZ for routines - // + // // L: Lower triangular matrix. Will be output as SPEX_CSC and SPEX_MPZ // - // U: Upper triangular matrix. Will be output as SPEX_CSC and SPEX_MPZ + // U: Upper triangular matrix. Will be output as SPEX_CSC and SPEX_MPZ // - // x: Solution to the linear system. Will be output as SPEX_DENSE and SPEX_MPQ + // x: Solution to the linear system. Will be output as SPEX_DENSE and + // SPEX_MPQ // // b: Set of right hand side vectors. Must be SPEX_DENSE and SPEX_MPZ // // Additionally, two other data structures are declared here: // - // pinv: Inverse row permutation used for LDU factorization and permutation + // pinv: Inverse row permutation used for LDU factorization and + // permutation // // S: Symbolic analysis struct. // // Lastly, the following parameter is created: // - // option: Command options for the factorization. In general, this can be - // set to default values and is almost always the last input argument - // for SPEX Left LU functions (except SPEX_malloc and such) + // option: Command options for the factorization. In general, this can be + // set to default values and is almost always the last input + // argument for SPEX Left LU functions (except SPEX_malloc and + // such) //-------------------------------------------------------------------------- - SPEX_matrix *A = NULL; - SPEX_matrix *L = NULL; - SPEX_matrix *U = NULL; - SPEX_matrix *x = NULL; - SPEX_matrix *b = NULL; - SPEX_matrix *rhos = NULL; - int64_t* pinv = NULL; - SPEX_LU_analysis* S = NULL; + SPEX_matrix A = NULL; + SPEX_symbolic_analysis S = NULL; + SPEX_factorization F = NULL; + SPEX_matrix x = NULL; + SPEX_matrix b = NULL; SPEX_info ok ; - + // Initialize option, command options for the factorization - SPEX_options *option = NULL; - OK(SPEX_create_default_options(&option)); - + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); + option->order=SPEX_NO_ORDERING; + // Extra parameters used to obtain A, b, etc char *mat_name, *rhs_name; - SPEX_type rat; - mat_name = "../ExampleMats/10teams_mat.txt";// Set demo matrix and RHS name - rhs_name = "../ExampleMats/10teams_v.txt"; - + int64_t rat=1; + + //-------------------------------------------------------------------------- // After initializing memory, we process the command line for this function. // Such a step is optional, a user can also manually set these parameters. @@ -142,37 +143,36 @@ int main (int argc, char* argv[]) // option->order = SPEX_AMD. //-------------------------------------------------------------------------- - OK(SPEX_process_command_line(argc, argv, option, + DEMO_OK(spex_demo_process_command_line(argc, argv, option, &mat_name, &rhs_name, &rat)); //-------------------------------------------------------------------------- // In this demo file, we now read in the A and b matrices from external // files. Refer to the example.c file or the user guide for other - // methods of creating the input matrix. In general, the user can create + // methods of creating the input matrix. In general, the user can create // his/her matrix (say in double form) and then create a copy of it with // SPEX_matrix_copy //-------------------------------------------------------------------------- - // Read in A - FILE* mat_file = fopen(mat_name,"r"); + FILE *mat_file = fopen(mat_name,"r"); if( mat_file == NULL ) { perror("Error while opening the file"); FREE_WORKSPACE; return 0; } - OK(SPEX_tripread(&A, mat_file, option)); + DEMO_OK(spex_demo_tripread(&A, mat_file, SPEX_MPZ, option)); fclose(mat_file); // Read in right hand side - FILE* rhs_file = fopen(rhs_name,"r"); + FILE *rhs_file = fopen(rhs_name,"r"); if( rhs_file == NULL ) { perror("Error while opening the file"); FREE_WORKSPACE; return 0; } - OK(SPEX_read_dense(&b, rhs_file, option)); + DEMO_OK(spex_demo_read_dense(&b, rhs_file, option)); fclose(rhs_file); // Check if the size of A matches b @@ -185,7 +185,7 @@ int main (int argc, char* argv[]) //-------------------------------------------------------------------------- // We now perform symbolic analysis by getting the column preordering of - // the matrix A. This is done via the SPEX_LU_analyze function. The output + // the matrix A. This is done via the SPEX_lu_analyze function. The output // of this function is a column permutation Q where we factor the matrix AQ // and an estimate of the number of nonzeros in L and U. // @@ -194,62 +194,52 @@ int main (int argc, char* argv[]) // function. //-------------------------------------------------------------------------- - clock_t start_col = clock(); + double start_col = SuiteSparse_time (); // Column ordering using either AMD, COLAMD or nothing - OK(SPEX_LU_analyze(&S, A, option)); - if (option->print_level > 0) - { - SPEX_print_options(option); - } + DEMO_OK(SPEX_lu_analyze(&S, A, option)); - clock_t end_col = clock(); + double end_col = SuiteSparse_time (); //-------------------------------------------------------------------------- - // Now we perform the SPEX Left LU factorization to obtain matrices L and U and a - // row permutation P such that PAQ = LDU. Note that the D matrix is never - // explicitly constructed or used. + // Now we perform the SPEX Left LU factorization to obtain matrices L and U + // and a row permutation P such that PAQ = LDU. Note that the D matrix is + // never explicitly constructed or used. //-------------------------------------------------------------------------- - clock_t start_factor = clock(); + double start_factor = SuiteSparse_time (); - OK(SPEX_Left_LU_factorize(&L, &U, &rhos, &pinv, A, S, option)); + DEMO_OK(SPEX_lu_factorize(&F, A, S, option)); - clock_t end_factor = clock(); + double end_factor = SuiteSparse_time (); //-------------------------------------------------------------------------- // We now solve the system Ax=b using the L and U factors computed above. //-------------------------------------------------------------------------- - clock_t start_solve = clock(); + double start_solve = SuiteSparse_time (); - // SPEX Left LU has an optional check step which can verify that the solution - // vector x satisfies Ax=b in perfect precision intended for debugging. + // SPEX Left LU has an optional check step which can verify that the + // solution vector x satisfies Ax=b in perfect precision intended for + // debugging. // // Note that this is entirely optional and not necessary. The solution // returned is guaranteed to be exact. It appears here just as a - // verification that SPEX Left LU is computing its expected result. This test - // can fail only if it runs out of memory, or if there is a bug in the + // verification that SPEX Left LU is computing its expected result. This + // test can fail only if it runs out of memory, or if there is a bug in the // code. Also, note that this function can be quite time consuming; thus // it is not recommended to be used in general. - // - // To enable said check, the following bool is set to true // - option->check = true; - + // To enable said check, the following bool is set to true + + //option->check = true; + // Solve LDU x = b - OK(SPEX_Left_LU_solve(&x, b, - (const SPEX_matrix *) A, - (const SPEX_matrix *) L, - (const SPEX_matrix *) U, - (const SPEX_matrix *) rhos, - S, - (const int64_t *) pinv, - option)); - - clock_t end_solve = clock(); - - // Done, x now contains the exact solution of the linear system Ax=b in + DEMO_OK(SPEX_lu_solve(&x, F, b, option)); + + double end_solve = SuiteSparse_time (); + + // Done, x now contains the exact solution of the linear system Ax=b in // dense rational form. There is an optional final step here where the user // can cast their solution to a different data type or matrix format. // Below, we have a block of code which illustrates how one would do this. @@ -259,17 +249,17 @@ int main (int argc, char* argv[]) // SPEX_kind my_kind = SPEX_DENSE; // SPEX_CSC, SPEX_TRIPLET or SPEX_DENSE // SPEX_type my_type = SPEX_FP64; // SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 // - // SPEX_matrix* my_x = NULL; // New output + // SPEX_matrix my_x = NULL; // New output // Create copy which is stored as my_kind and my_type: // SPEX_matrix_copy( &my_x, my_kind, my_type, x, option); // Timing stats - double t_sym = (double) (end_col-start_col)/CLOCKS_PER_SEC; - double t_factor = (double) (end_factor - start_factor) / CLOCKS_PER_SEC; - double t_solve = (double) (end_solve - start_solve) / CLOCKS_PER_SEC; + double t_sym = (end_col-start_col) ; + double t_factor = (end_factor - start_factor) ; + double t_solve = (end_solve - start_solve) ; printf("\nNumber of L+U nonzeros: \t\t%"PRId64, - (L->p[L->n]) + (U->p[U->n]) - (L->m)); + (F->L->p[F->L->n]) + (F->U->p[F->U->n]) - (F->L->m)); printf("\nSymbolic analysis time: \t\t%lf", t_sym); printf("\nSPEX Left LU Factorization time: \t%lf", t_factor); printf("\nFB Substitution time: \t\t\t%lf\n\n", t_solve); @@ -279,7 +269,8 @@ int main (int argc, char* argv[]) //-------------------------------------------------------------------------- FREE_WORKSPACE; - printf ("\n%s: all tests passed\n\n", __FILE__) ; + printf ("\n%s: all tests passed\n\n", __FILE__); + //fprintf (stderr, "%s: all tests passed\n\n", __FILE__); return 0; } diff --git a/SPEX/SPEX_Left_LU/Demo/example.c b/SPEX/Demo/spex_demo_lu_simple1.c similarity index 67% rename from SPEX/SPEX_Left_LU/Demo/example.c rename to SPEX/Demo/spex_demo_lu_simple1.c index 466d7bf734..cd92f8e41b 100644 --- a/SPEX/SPEX_Left_LU/Demo/example.c +++ b/SPEX/Demo/spex_demo_lu_simple1.c @@ -1,58 +1,56 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/Demo/example.c: example main program for SPEX_Left_LU +// Demo/example.c: example of simple SPEX_LU call using as input a random matrix //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ - -#include "demos.h" - - -/* This example shows how to use SPEX Left LU with a given input matrix and a double - output. The input is a randomly generate dense matrix */ +/* This example shows how to use SPEX Left LU with a given input matrix and a + * double output. The input is a randomly generate dense matrix */ // usage: // example > out // out is file for output calculated result +#include "spex_demos.h" + #define FREE_WORKSPACE \ +{ \ SPEX_matrix_free(&A,option); \ SPEX_matrix_free(&x,option); \ SPEX_matrix_free(&b,option); \ SPEX_matrix_free(&Rb,option); \ SPEX_matrix_free(&R,option); \ SPEX_FREE(option); \ - SPEX_finalize() ; \ + SPEX_finalize(); \ +} - - int main (void) { - + //-------------------------------------------------------------------------- - // Prior to using SPEX Left LU, its environment must be initialized. This is done - // by calling the SPEX_initialize() function. + // Prior to using SPEX Left LU, its environment must be initialized. This + // is done by calling the SPEX_initialize() function. //-------------------------------------------------------------------------- - SPEX_initialize(); + SPEX_info ok = SPEX_initialize(); //-------------------------------------------------------------------------- // Declare and initialize essential variables //-------------------------------------------------------------------------- - SPEX_info ok; int64_t n = 50, nz = 2500, num=0; - SPEX_matrix *A = NULL ; // input matrix - SPEX_matrix *R = NULL ; // Random matrix to create A - SPEX_matrix *Rb = NULL; // Random matrix to create b - SPEX_matrix *b = NULL ; // Right hand side vector - SPEX_matrix *x = NULL ; // Solution vectors - SPEX_options *option = NULL; - OK(SPEX_create_default_options(&option)); + SPEX_matrix A = NULL ; // input matrix + SPEX_matrix R = NULL ; // Random matrix to create A + SPEX_matrix Rb = NULL; // Random matrix to create b + SPEX_matrix b = NULL ; // Right hand side vector + SPEX_matrix x = NULL ; // Solution vectors + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); //-------------------------------------------------------------------------- // Generate a random dense 50*50 matrix @@ -61,11 +59,11 @@ int main (void) // R is a n*n triplet matrix whose entries are FP64 Note that the first // boolean parameter says that the matrix is not shallow, so that A->i, // A->j, and A->x are calloc'd. The second boolean parameter is meaningless - // for FP64 matrices, but it tells SPEX Left LU to allocate the values of A->x - // for the mpz_t, mpq_t, and mpfr_t entries + // for FP64 matrices, but it tells SPEX Left LU to allocate the values of + // A->x for the mpz_t, mpq_t, and mpfr_t entries SPEX_matrix_allocate(&R, SPEX_TRIPLET, SPEX_FP64, n, n, nz, false, true, option); - + // Rb is a n*1 dense matrix whose entries are FP64 SPEX_matrix_allocate(&Rb, SPEX_DENSE, SPEX_FP64, n, 1, n, false, true, option); @@ -92,25 +90,22 @@ int main (void) //-------------------------------------------------------------------------- // A is a copy of the R matrix. A is a CSC matrix with mpz_t entries - OK ( SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, R, option)); - // b is a copy of the Rb matrix. b is dense with mpz_t entries. - OK ( SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, Rb, option)); + DEMO_OK ( SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, R, option)); + // b is a copy of the Rb matrix. b is dense with mpz_t entries. + DEMO_OK ( SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, Rb, option)); //-------------------------------------------------------------------------- // Solve //-------------------------------------------------------------------------- - clock_t start_s = clock(); - - // SPEX Left LU has an optional check, to enable it, one can set the following - // parameter to be true. - option->check = true; + double start_s = SuiteSparse_time (); + // Solve the system and give double solution - OK(SPEX_Left_LU_backslash( &x, SPEX_FP64, A, b, option)); - - clock_t end_s = clock(); + DEMO_OK(SPEX_lu_backslash( &x, SPEX_FP64, A, b, option)); + + double end_s = SuiteSparse_time (); - double t_s = (double) (end_s - start_s) / CLOCKS_PER_SEC; + double t_s = (end_s - start_s) ; printf("\nSPEX Left LU Factor & Solve time: %lf\n", t_s); @@ -119,7 +114,7 @@ int main (void) //-------------------------------------------------------------------------- FREE_WORKSPACE; - printf ("\n%s: all tests passed\n\n", __FILE__) ; + printf ("\n%s: all tests passed\n\n", __FILE__); return 0; } diff --git a/SPEX/SPEX_Left_LU/Demo/example2.c b/SPEX/Demo/spex_demo_lu_simple2.c similarity index 59% rename from SPEX/SPEX_Left_LU/Demo/example2.c rename to SPEX/Demo/spex_demo_lu_simple2.c index 955a6830d6..674a2d7ea5 100644 --- a/SPEX/SPEX_Left_LU/Demo/example2.c +++ b/SPEX/Demo/spex_demo_lu_simple2.c @@ -1,35 +1,38 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/Demo/example2.c: example main program for SPEX_Left_LU +// Demo/spex_demo_lu_simple2.c: example of simple SPEX_LU call for triplet format //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -#include "demos.h" - -// This example shows how to use SPEX Left LU within your code -// Unlike example1, the input matrix here is directly read in from the -// triplet formmat. Also, differs from example1 in that the output solution -// is given in mpq_t precision +// This example shows how to use SPEX Left LU within your code. Unlike +// example1, the input matrix here is directly read in from the triplet +// formmat. Also, differs from example1 in that the output solution is given in +// mpq_t precision // usage: -// example2 mat_file rhs_file > out +// SPEX_LU_demo2 mat_file rhs_file > out // mat_file is the Matrix Market file containing the A matrix // rhs_file is a list of entries for right hand side dense matrix // if input file names are not specified, they are defaulted to // ../ExampleMats/10teams.mat and ../ExampleMats/10teams.v, respectively. // out is file for output calculated result -#define FREE_WORKSPACE \ - SPEX_LU_analysis_free(&S, option);\ - SPEX_matrix_free(&A, option); \ - SPEX_FREE(option); \ - SPEX_matrix_free(&b, option); \ - SPEX_matrix_free(&x, option); \ - SPEX_finalize(); +#include "spex_demos.h" + +#define FREE_WORKSPACE \ +{ \ + SPEX_symbolic_analysis_free(&S, option); \ + SPEX_matrix_free(&A, option); \ + SPEX_FREE(option); \ + SPEX_matrix_free(&b, option); \ + SPEX_matrix_free(&x, option); \ + SPEX_finalize(); \ +} int main (int argc, char **argv) { @@ -42,25 +45,28 @@ int main (int argc, char **argv) //-------------------------------------------------------------------------- // Get matrix and right hand side file names //-------------------------------------------------------------------------- - char *mat_name, *rhs_name; - mat_name = "../ExampleMats/10teams_mat.txt"; - rhs_name = "../ExampleMats/10teams_v.txt"; - if (argc > 2) - { - mat_name = argv[1]; - rhs_name = argv[2]; + + char *mat_name = NULL, *rhs_name = NULL; + if (argc < 3) + { + perror ("usage: spex_demo_lu_simple2 matfile rhsfile"); + return 0 ; } + mat_name = argv[1]; + rhs_name = argv[2]; + + //-------------------------------------------------------------------------- // Declare our data structures //-------------------------------------------------------------------------- SPEX_info ok; - SPEX_matrix *A = NULL ; // input matrix - SPEX_matrix *b = NULL ; // Right hand side vector - SPEX_matrix *x = NULL ; // Solution vectors - SPEX_LU_analysis *S = NULL ; // Column permutation - SPEX_options *option = NULL; - OK(SPEX_create_default_options(&option)); + SPEX_matrix A = NULL ; // input matrix + SPEX_matrix b = NULL ; // Right hand side vector + SPEX_matrix x = NULL ; // Solution vectors + SPEX_symbolic_analysis S = NULL ; // Column permutation + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); //-------------------------------------------------------------------------- // Allocate memory, read in A and b @@ -68,26 +74,26 @@ int main (int argc, char **argv) // Read in A. The output of this demo function is A in CSC format with // mpz_t entries. - FILE* mat_file = fopen(mat_name,"r"); + FILE *mat_file = fopen(mat_name,"r"); if( mat_file == NULL ) { perror("Error while opening the file"); FREE_WORKSPACE; return 0; } - OK(SPEX_tripread(&A, mat_file, option)); + DEMO_OK(spex_demo_tripread(&A, mat_file, SPEX_MPZ, option)); fclose(mat_file); // Read in b. The output of this demo function is b in dense format with // mpz_t entries - FILE* rhs_file = fopen(rhs_name,"r"); + FILE *rhs_file = fopen(rhs_name,"r"); if( rhs_file == NULL ) { perror("Error while opening the file"); FREE_WORKSPACE; return 0; } - OK(SPEX_read_dense(&b, rhs_file, option)); + DEMO_OK(spex_demo_read_dense(&b, rhs_file, option)); fclose(rhs_file); // Check if the size of A matches b @@ -103,18 +109,18 @@ int main (int argc, char **argv) // solve //-------------------------------------------------------------------------- - clock_t start_s = clock(); - - // SPEX Left LU has an optional check, to enable it, one can set the following - // parameter to be true. - option->check = true; - + double start_s = SuiteSparse_time (); + + // SPEX Left LU has an optional check, to enable it, one can set the + // following parameter to be true. + // option->check = true; + // Solve the system and give MPQ solution - OK(SPEX_Left_LU_backslash( &x, SPEX_MPQ, A, b, option)); - - clock_t end_s = clock(); + DEMO_OK(SPEX_lu_backslash( &x, SPEX_MPQ, A, b, option)); + + double end_s = SuiteSparse_time (); - double t_s = (double) (end_s - start_s) / CLOCKS_PER_SEC; + double t_s = (end_s - start_s) ; printf("\nSPEX Left LU Factor & Solve time: %lf\n", t_s); @@ -124,7 +130,7 @@ int main (int argc, char **argv) FREE_WORKSPACE; - printf ("\n%s: all tests passed\n\n", __FILE__) ; + printf ("\n%s: all tests passed\n\n", __FILE__); return 0; } diff --git a/SPEX/Demo/spex_demo_threaded.c b/SPEX/Demo/spex_demo_threaded.c new file mode 100644 index 0000000000..64eefa863a --- /dev/null +++ b/SPEX/Demo/spex_demo_threaded.c @@ -0,0 +1,183 @@ +//------------------------------------------------------------------------------ +// Demo/spex_demo_threaded: example of SPEX_backslash with multiple threads +//------------------------------------------------------------------------------ + +// SPEX: (c) 2021-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* A demo of SPEX_backslash in C: solving the same system with many different + * user threads, just to test user multithreading. + */ + +# include "spex_demos.h" + +#define FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&A,NULL); \ + SPEX_matrix_free(&b,NULL); \ + SPEX_FREE(option); \ + SPEX_finalize(); \ +} \ + +#ifdef _OPENMP +#include +#endif + +int main( int argc, char *argv[] ) +{ + + //-------------------------------------------------------------------------- + // Prior to using SPEX, its environment must be initialized. This is done + // by calling the SPEX_initialize() function. + //-------------------------------------------------------------------------- + SPEX_initialize(); + + //-------------------------------------------------------------------------- + // Declare memory & Process Command Line + //-------------------------------------------------------------------------- + int64_t n = 0, ok ; + + SPEX_matrix A = NULL; + SPEX_matrix b = NULL; + + // Set default options + SPEX_options option = NULL; + DEMO_OK(SPEX_create_default_options(&option)); + + char *mat_name = NULL, *rhs_name = NULL; + int64_t rat = 1; + + // Process the command line + DEMO_OK(spex_demo_process_command_line(argc, argv, option, + &mat_name, &rhs_name, &rat)); + + //-------------------------------------------------------------------------- + // Allocate memory + //-------------------------------------------------------------------------- + + // Read in A + FILE *mat_file = fopen(mat_name,"r"); + if( mat_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + + // Note, there are a few matrices in BasisLIB that dont fit in double + // Need to use the other tripread for those. + DEMO_OK(spex_demo_tripread(&A, mat_file, SPEX_MPZ, option)); + fclose(mat_file); + n = A->n; + + // Read in b. The output of this demo function is b in dense format with + // mpz_t entries + FILE *rhs_file = fopen(rhs_name,"r"); + if( rhs_file == NULL ) + { + perror("Error while opening the file"); + FREE_WORKSPACE; + return 0; + } + DEMO_OK(spex_demo_read_dense(&b, rhs_file, option)); + fclose(rhs_file); + + //-------------------------------------------------------------------------- + // Solve Ax = b + //-------------------------------------------------------------------------- + + // This demo solves the same system many times, which isn't very useful, + // since each thread should compute the same solution each time. However, + // it serves as a useful test for the thread safety feature of SPEX. If + // there is a race condition, then it's likely that one thread will fail + // to properly solve one of its systems. + + fflush (stdout); + fflush (stderr); + + option->print_level = 0; + + int nthreads = 1 ; + #ifdef _OPENMP + nthreads = omp_get_max_threads ( ) ; + #endif + + #define NTRIALS 10 + + printf("solving Ax=b with nthreads: %d, with %d trials per thread\n" + "Please wait...\n", nthreads, NTRIALS); + + bool test_pass = true ; + + #pragma omp parallel for num_threads(nthreads) schedule(static,1) \ + reduction(&&:test_pass) + for (int id = 0 ; id < nthreads ; id++) + { + SPEX_info info = SPEX_thread_initialize ( ) ; + if (info != SPEX_OK) + { + printf ("SPEX thread %d: failed to initialize its context\n", id) ; + test_pass = false ; + SPEX_thread_finalize ( ) ; + continue ; + } + + // this thread solves the same system many times, just to + // hammer the thread-safety aspect of SPEX + bool my_test_pass = true ; + for (int ntrials = 0 ; ntrials < NTRIALS ; ntrials++) + { + SPEX_matrix myx = NULL ; + info = SPEX_backslash (&myx, SPEX_MPQ, A, b, option) ; + if (info != SPEX_OK) + { + printf ("SPEX thread %d: backslash failed\n", id) ; + my_test_pass = false ; + test_pass = false ; + break ; + } + info = spex_demo_check_solution (A,myx,b,option) ; + SPEX_matrix_free (&myx, NULL) ; + if (info != SPEX_OK) + { + printf ("SPEX thread %d: wrong solution\n", id) ; + my_test_pass = false ; + test_pass = false ; + break ; + } + } + + info = SPEX_thread_finalize ( ) ; + if (info != SPEX_OK) + { + printf ("SPEX thread %d: failed to finalize its context\n", id) ; + my_test_pass = false ; + test_pass = false ; + } + + if (my_test_pass) + { + printf ("SPEX thread %d: ok. All systems solved exactly.\n", id) ; + } + } + + if (!test_pass) + { + printf ("SPEX thread test failed\n\n") ; + } + else + { + printf ("SPEX thread test passed\n\n") ; + } + + //-------------------------------------------------------------------------- + // Free Memory + //-------------------------------------------------------------------------- + + FREE_WORKSPACE; +} + diff --git a/SPEX/Demo/spex_demos.h b/SPEX/Demo/spex_demos.h new file mode 100644 index 0000000000..8d8a847343 --- /dev/null +++ b/SPEX/Demo/spex_demos.h @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +// Demo/spex_demos.h: #include file the demo programs +//------------------------------------------------------------------------------ + +// SPEX: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + + +#include "SPEX.h" +#include "spex_util_internal.h" +#include "spex_gmp.h" + +#define DEMO_OK(method) \ +{ \ + ok = method ; \ + if (ok != SPEX_OK) \ + { \ + spex_demo_determine_error (ok) ; \ + FREE_WORKSPACE ; \ + return 0 ; \ + } \ +} + +#define SPEX_MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* Purpose: This processes the command line for user specified options */ +SPEX_info spex_demo_process_command_line //processes the command line +( + int64_t argc, // number of command line arguments + char *argv[], // set of command line arguments + SPEX_options option, // struct containing the command options + char **mat_name, // Name of the matrix to be read in + char **rhs_name, // Name of the RHS vector to be read in + int64_t *rat // data type of output solution. + // 1: mpz, 2: double, 3: mpfr +); + +/* Purpose: This function reads in a matrix stored in a triplet format. + * This format used can be seen in any of the example mat files. + */ +SPEX_info spex_demo_tripread +( + SPEX_matrix *A_handle, // Matrix to be constructed + FILE *file, // file to read from (must already be open) + SPEX_type C_type, // C->type: mpz_t, mpq_t, mpfr_t, int64_t, or double + SPEX_options option +) ; + +/* Purpose: This function reads in a double matrix stored in a triplet format. + * This format used can be seen in any of the example mat files. + */ +SPEX_info spex_demo_tripread_double +( + SPEX_matrix *A_handle, // Matrix to be constructed + FILE *file, // file to read from (must already be open) + SPEX_options option +) ; + +/* Purpose: This function reads in a matrix stored in a triplet format. + * This format used can be seen in any of the example mat files. + */ +SPEX_info spex_demo_tripread_mpz +( + SPEX_matrix *A_handle, // Matrix to be constructed + FILE *file, // file to read from (must already be open) + SPEX_options option +) ; + +/* Purpose: SPEX_read_dense: read a dense matrix. */ +SPEX_info spex_demo_read_dense +( + SPEX_matrix *b_handle, // Matrix to be constructed + FILE *file, // file to read from (must already be open) + SPEX_options option +) ; + +/* Purpose: Determine why a SPEX_Chol function failed + */ +void spex_demo_determine_error +( + SPEX_info ok +); + + +SPEX_info spex_demo_check_solution +( + const SPEX_matrix A, // Input matrix + const SPEX_matrix x, // Solution vectors + const SPEX_matrix b, // Right hand side vectors + const SPEX_options option // Command options +); diff --git a/SPEX/Doc/ChangeLog b/SPEX/Doc/ChangeLog index 16ab050aeb..8dcdc0e2db 100644 --- a/SPEX/Doc/ChangeLog +++ b/SPEX/Doc/ChangeLog @@ -1,28 +1,24 @@ -Jan 10, 2024: version 2.3.1 - - * minor updates to build system - -Dec 30, 2023: version 2.3.0 - - * major change to build system: by Markus Mützel - * SPEX_version: added to return version of SPEX - -Sept 18, 2023: version 2.2.1 - - * cmake update: add "None" build type, from Antonio Rojas, for Arch Linux - -Sept 8, 2023: version 2.2.0 - - * cmake updates: SuiteSparse:: namespace by Markus Muetzel - -June 16, 2023: version 2.0.4 - - * cmake build system updates: update by Markus Muetzel. - Includes changes to FindMPFR.cmake and FindGMP.cmake. - -Jan 17, 2023: version 2.0.3 - - * SuiteSparse_config: now v7.0.0 +Feb XX, 2024: version 3.1.0 + + * major update to build system + +Jul 26, 2023: version 3.0.0 + + * major change to the API: new SPEX_factorization and SPEX_symbolic_analysis + objects. Uniform analyze/factorize/solve functions for all kinds of + factorizations. + * thread-safe: SPEX 2.0 was not thread-safe if the user application called + it in parallel; v3.0 is now thread-safe with SPEX_thread_initialize + and SPEX_thread_finalize. + * SPEX_Cholesky: robust implementation of sparse REF Cholesky. + * SPEX_Backslash: automatically determines (between SPEX LU and SPEX + Cholesky) the best exact algorithm to use when solving a SLE. + * python interface: SPEX can now be used to solve SLEs in python with only + one line. There are separate functions for SPEX LU, SPEX Cholesky and + SPEX Backslash. + * MATLAB interface: SPEX can now be used to solve SLEs in MATLAB with only + one line. There are separate functions for SPEX LU, SPEX Cholesky and + SPEX Backslash. Dec 9, 2022: version 2.0.2 diff --git a/SPEX/Doc/Makefile b/SPEX/Doc/Makefile index cc226a1b9d..2d933eea0f 100644 --- a/SPEX/Doc/Makefile +++ b/SPEX/Doc/Makefile @@ -2,8 +2,9 @@ # SPEX/Doc/Makefile #------------------------------------------------------------------------------- -# SPEX: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -# Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +# SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. # SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later #------------------------------------------------------------------------------- diff --git a/SPEX/Doc/SPEX_UserGuide.bib b/SPEX/Doc/SPEX_UserGuide.bib index 49fbddab01..83ffe4dc5e 100644 --- a/SPEX/Doc/SPEX_UserGuide.bib +++ b/SPEX/Doc/SPEX_UserGuide.bib @@ -78,3 +78,15 @@ @article{lourenco2019exact year={2019}, publisher={SIAM} } + + +@article{lourenco2022exactly, + title={Exactly Solving Sparse Rational Linear Systems via Roundoff-Error-Free Cholesky Factorizations}, + author={Lourenco, Christopher J and Moreno-Centeno, Erick}, + journal={SIAM Journal on Matrix Analysis and Applications}, + volume={43}, + number={1}, + pages={439--463}, + year={2022}, + publisher={SIAM} +} \ No newline at end of file diff --git a/SPEX/Doc/SPEX_UserGuide.pdf b/SPEX/Doc/SPEX_UserGuide.pdf index e7fc49d102afb30781cb10cc32c9d3ad81601f5d..add589916bd1ab91e07ed49bf70c5becbe262f55 100644 GIT binary patch delta 323759 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 k$1b#n9b@Dq6Ex;0RE~*J^%m! diff --git a/SPEX/Doc/SPEX_UserGuide.tex b/SPEX/Doc/SPEX_UserGuide.tex index 641053a4fd..dc8c7676cb 100644 --- a/SPEX/Doc/SPEX_UserGuide.tex +++ b/SPEX/Doc/SPEX_UserGuide.tex @@ -1,5 +1,5 @@ -\documentclass[12pt]{report} -\batchmode +\documentclass[12pt,oneside]{book} + \usepackage{amsmath,amssymb,amsthm,latexsym,paralist,comment} \usepackage{graphicx} \usepackage{psfrag} @@ -8,7 +8,6 @@ \usepackage{multirow} \usepackage{algorithm} \usepackage{algpseudocode} -\usepackage{cprotect} \usepackage{graphicx} \usepackage{subcaption} \usepackage{listings} @@ -22,7 +21,7 @@ linkcolor = blue, urlcolor = Maroon } -\usepackage{geometry} +\usepackage[letterpaper,margin=1in]{geometry} \theoremstyle{definition} \newcommand{\N}{\mathbf{N}} @@ -30,146 +29,111 @@ \newcommand{\Z}{\mathbf{Z}} \newcommand{\import}{\textcolor{red}{\textbf{**IMPORTANT**}}} -\begin{document} - -\begin{center} -\begin{large} -\textbf{User Guide for the SPEX Software Package} \\ -\vspace{5mm} -\input{SPEX_version.tex} -\vspace{20mm} +% Whether to include SPEX update or not +% If update is set to true, then all of the text on updates is shown +% if update is set to false, then all of the text on updates is hidden +\usepackage{ifthen} +\newboolean{update} +\setboolean{update}{false} +\newcommand{\update}[1]{\ifthenelse{\boolean{update}}{#1}{}} -Christopher Lourenco, Jinhao Chen, \\ Erick Moreno-Centeno, Timothy A. Davis \\ +\usepackage[Glenn]{fncychap} %Fancy Chapter Headers -US Naval Academy, Texas A\&M University +\usepackage{cprotect} -\vspace{20mm} -Contact Information: Contact Chris Lourenco, \href{mailto:chrisjlourenco@gmail.com}{chrisjlourenco@gmail.com} \href{mailto:lourenco@usna.edu}{lourenco@usna.edu}, or Tim Davis, -\href{mailto:timdavis@aldenmath.com}{timdavis@aldenmath.com}, -\href{mailto:davis@tamu.edu}{davis@tamu.edu}, -\href{DrTimothyAldenDavis@gmail.com}{DrTimothyAldenDavis@gmail.com} +% ------------------------------------------------------ +% Centered Tabular Environment, with default small size +% ------------------------------------------------------ +% Example 1 (small): \begin{SizedCenteredTabular}|l|l|l|} +% Example 2 (scriptsize): \begin{SizedCenteredTabular}[\scriptsize]{|l|l|l|} +\newenvironment{SizedCenteredTabular}[2][\small] + { + #1\begin{center}\begin{tabular}{#2} + }{ + \end{tabular}\end{center} + } -\end{large} -\end{center} -\newpage -\tableofcontents +\begin{document} -\newpage +\thispagestyle{empty} +\begin{center}\begin{large} + \phantom{.}\\[1in] + \textbf{User Guide for the SPEX Software Package} \\ + \vspace{5mm} -\chapter{SPEX Overview} - -SPEX is a software package comprising several state-of-the-art SParse EXact -linear algebra routines. It currently is comprised of the following: + Version 3.0, July 2023 % VERSION + \vspace{20mm} + + Jinhao Chen, Timothy A. Davis, Christopher Lourenco, Lorena Mejia-Domenzain, Erick Moreno-Centeno \\ + Texas A\&M University and US Naval Academy + \vspace{20mm} + + Contact Information: Contact Chris Lourenco, \href{mailto:chrisjlourenco@gmail.com}{chrisjlourenco@gmail.com}, \href{mailto:lourenco@usna.edu}{lourenco@usna.edu}, or Tim Davis, + \href{mailto:timdavis@aldenmath.com}{timdavis@aldenmath.com}, + \href{mailto:davis@tamu.edu}{davis@tamu.edu}, + \href{DrTimothyAldenDavis@gmail.com}{DrTimothyAldenDavis@gmail.com} +\end{large}\end{center} -\begin{description} -\item[SPEX Utilities] Utility and auxiliary functions for all SPEX routines: interface to the GMP/MPFR library, memory management functions, the \verb|SPEX_matrix| data structure, and various functions that are auxiliary to the factorization and solve functions. Please refer to Chapter \ref{ch:Util} for further details. -\item[SPEX Left LU] Sparse exact left-looking LU factorization to solve the linear system $A \mathbf{x} = \mathbf{b}$. The solution time is proportional to the arithmetic work in the bit-complexity model; this is an asymptotically efficient complexity bound. Please refer to Chapter \ref{ch:LeftLU} for further details. -\end{description} -\noindent \textbf{Location:} \url{https://github.com/clouren/SPEX} and -\url{www.suitesparse.com}\\ -\noindent \textbf{Required Packages:} SPEX depends on the following packages: - \begin{itemize} - \item AMD \cite{amestoy1996approximate,amestoy2004algorithmamd}, available under a BSD -3-clause license and distributed along with SPEX. May be independently obtained at \url{www.suitesparse.com} - \item COLAMD \cite{davis2004column,davis2004algorithmcolamd}, available under a BSD -3-clause license and distributed along with SPEX. May be independently obtained at \url{www.suitesparse.com} - \item - \verb|SuiteSparse_config| \cite{davis2020suitesparse}, no license restrictions and distributed along with SPEX. May be independently obtained at \url{www.suitesparse.com} - \item GNU GMP \cite{granlund2015gnu} and MPFR -\cite{fousse2007mpfr} libraries. Distributed under the LGPL3 and GPL2 and can be acquired and installed -from \url{https://gmplib.org/} and \url{http://www.mpfr.org/}, respectively. +%------------------------------------------------------------------------------- +\newpage +\tableofcontents +%------------------------------------------------------------------------------- - \end{itemize} -Within a Debian/Ubuntu based Linux system, a compatible version of GMP and MPFR can be installed with the following terminal commands: +%------------------------------------------------------------------------------- +\chapter{SPEX Overview}\vspace{-0.75in} +%------------------------------------------------------------------------------- +SPEX is a software package comprising several state-of-the-art SParse EXact +linear algebra routines. It currently consists of the following: -{\small -\begin{verbatim} - sudo apt-get install libgmp-dev - sudo apt-get install libmpfr-dev libmpfr-doc -\end{verbatim} } - -SPEX requires GMP 6.1.2 or later, and MPFR 4.0.2 or later. -Be aware that the Debian package versions differ. -The Debian \verb'libgmp.so.10.3.2' corresponds to GMP 6.1.2, -and \verb'libmpfr.so.6.0.2' corresponds to MPFR 4.0.2. -The same is true for the spack package manager. -Do not rely on the suffix \verb'X.Y.Z' in the \verb'lib*.so.X.Y.Z' to -determine the version. The CMake script will display the correct -version numbers of GMP and MPFR, and report an error if they are not -recent enough. - -\chapter{SPEX Utilities} \label{ch:Util} +\begin{description} + \item[SPEX Utilities] Utility and auxiliary functions for all SPEX routines: interface to the GMP/MPFR library, memory management functions, the \verb|SPEX_matrix|, \linebreak \verb|SPEX_factorization|, and \verb|SPEX_symbolic_analysis| data structures, and various functions that are auxiliary to the factorization and solve functions. Please refer to Chapter \ref{ch:Util} for further details. -\section{Overview} \label{s:util:overview} -%------------------------------------------------------------------------------- + \item[SPEX LU] Sparse exact left-looking LU factorization to solve the linear system $A \mathbf{x} = \mathbf{b}$. The solution time is proportional to the arithmetic work in the bit-complexity model; which is asymptotically efficient. Please refer to Chapter \ref{ch:LeftLU} for further details. -SPEX Util is a software package containing utility and auxiliary functions for the SPEX -factorizations. Additionally, SPEX Util provides a wrapper class for -the GNU Multiple Precision Arithmetic (GMP) \cite{granlund2015gnu} and GNU -Multiple Precision Floating Point Reliable (MPFR) \cite{fousse2007mpfr} -libraries that prevent memory leaks and improve the overall stability of -these external libraries. SPEX Util is written in ANSI C. + \item[SPEX Cholesky] Sparse exact left-looking and up-looking Cholesky factorizations to solve the symmetric positive definite (SPD) linear system $A \mathbf{x} = \mathbf{b}$. The solution time is proportional to the arithmetic work in the bit-complexity model; this is an asymptotically efficient complexity bound. Please refer to Chapter \ref{ch:Chol} for further details. -SPEX operates on matrices stored in any of the following 15 combinations of matrix formats and entry data-types: -$\{$Compressed Sparse Column (CSC), triplet, dense$\} \times \{$ \verb|mpz_t|, -\verb|mpq_t|, \verb|mpfr_t|, \verb|int64_t|, or \verb|double|$\}$. Using the SPEX matrix copy function, a matrix of any given form and data-type can be copied and converted into a matrix of any one of the 15 matrix-form and data-type combinations. + \item[SPEX Backslash] Routines to exactly solve the system $A \mathbf{x} = \mathbf{b}$ using either LU or Cholesky factorization. This is the simplest way to access the SPEX software package. Please refer to Chapter \ref{ch:Backslash} for further details. -Most routines require the matrix to be in CSC form with \verb|mpz_t| (i.e., arbitrary-sized integer) data -type. This data structure stores the matrix $A$ as a sequence of three arrays: + \update{ + \item[SPEX Update] Sparse exact factorization update. Currently consists of LU and Cholesky column replacement updates and Cholesky rank 1 update. Please refer to Chapter \ref{ch:Update} for further details.} +\end{description} -\begin{itemize} -\item -\verb|A->p|: Column pointers; an array of size \verb|n+1|. The row indices of -column $j$ are located in positions \verb|A->p[j]| to \verb|A->p[j+1]-1| of the -array \verb|A->i|. Data type: \verb|int64_t|. +\noindent \textbf{Location:} \url{https://github.com/clouren/SPEX} and +\url{www.suitesparse.com}\\ -\item -\verb|A->i|: Row indices; an array of size equal to the number of entries in -the matrix. The entry \verb|A->i[k]| is the row index of the $k$th nonzero in -the matrix. Data type: \verb|int64_t|. +\noindent \textbf{Required Packages:} SPEX depends on the following packages: +\begin{itemize} + \item GNU GMP \cite{granlund2015gnu} and MPFR \cite{fousse2007mpfr} libraries. Distributed under the LGPL3 and GPL2 and can be acquired and installed from \url{https://gmplib.org/} and \url{http://www.mpfr.org/}, respectively. -\item -\verb|A->x|: Numeric entries. The entry \verb|A->x[k]| is the numeric value of -the $k$th nonzero in the matrix. The array \verb|A->x| has a union type and -must be accessed via a suffix according to the type of \verb|A|. For details, -please refer to Section~\ref{ss:SPEX_matrix}. + \item CMake, available under a BSD 3-clause license. May be independently obtained at \url{https://cmake.org}. + + \item AMD \cite{amestoy1996approximate,amestoy2004algorithmamd}, available under a BSD 3-clause license and distributed along with SPEX. May be independently obtained at \url{www.suitesparse.com} + + \item COLAMD \cite{davis2004column,davis2004algorithmcolamd}, available under a BSD 3-clause license and distributed along with SPEX. May be independently obtained at \url{www.suitesparse.com} + %COMMENTED OUT because (1) no license, (2) distributed in SPEX, and (3) consistency with paper + %\item \verb|SuiteSparse_config| \cite{davis2020suitesparse}, no license restrictions and distributed along with SPEX. May be independently obtained at \url{www.suitesparse.com} \end{itemize} -An example matrix $A$ with \verb|mpz_t| type is stored as follows (note that indexing is zero based as per the C convention). -\[ -A = \begin{bmatrix} -1 & 0 & 0 & 1 \\ -2 & 0 & 4 & 12 \\ -7 & 1 & 1 & 1 \\ -0 & 2 & 3 & 0 \\ -\end{bmatrix} -\] - -\begin{verbatim} -A->p = [0, 3, 5, 8, 11] -A->i = [0, 1, 2, 2, 3, 1, 2, 3, 0, 1, 2] -A->x.mpz = [1, 2, 7, 1, 2, 4, 1, 3, 1, 12, 1] -\end{verbatim} -For example, the last column appears in positions 8 to 10 of \verb|A->i| and \verb|A->x.mpz|, with row indices 0, 1, and 2, and values $a_{03}=1$, $a_{13}=12$, and $a_{23}=1$. +%------------------------------------------------------------------------------- +\chapter{Setting up SPEX}\vspace{-0.75in} +%------------------------------------------------------------------------------- %------------------------------------------------------------------------------- \section{Licensing} \label{s:util:licensing} %------------------------------------------------------------------------------- +\textbf{Copyright:} The copyright of this software is held by Christopher Lourenco, Jinhao Chen, Lorena Mejia-Domenzain, Erick Moreno-Centeno, and Timothy A. Davis.\\ -\textbf{Copyright:} The copyright of this software is held by Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and Timothy A. Davis.\\ - -\noindent \textbf{Contact Info:} Contact Chris Lourenco, +\noindent \textbf{Contact Info:} Chris Lourenco, \href{mailto:chrisjlourenco@gmail.com}{chrisjlourenco@gmail.com} \href{mailto:lourenco@usna.edu}{lourenco@usna.edu}, or Tim Davis, \href{mailto:timdavis@aldenmath.com}{timdavis@aldenmath.com}, -\href{mailto:davis@tamu.edu}{davis@tamu.edu}, or -\href{DrTimothyAldenDavis@gmail.com}{DrTimothyAldenDavis@gmail.com}\\ +\href{DrTimothyAldenDavis@gmail.com}{DrTimothyAldenDavis@gmail.com}, or \href{mailto:davis@tamu.edu}{davis@tamu.edu}\\ \noindent \textbf{License:} This software package is dual licensed under the GNU General Public License version 2 or the GNU Lesser General Public License version 3. Details of this license are in \verb|SPEX/License/license.txt|. For alternative licenses, please contact the authors. @@ -177,1218 +141,1435 @@ \section{Licensing} \label{s:util:licensing} %------------------------------------------------------------------------------- \section{Installation} \label{s:util:install} %------------------------------------------------------------------------------- +Installation of SPEX requires the \verb|cmake| utility in Linux, MacOS, and Windows. +With the appropriate compiler and version of cmake, typing \verb|make| under the main +directory will compile AMD, COLAMD, and SPEX to their respective \verb|build| folder. +All shared library files can be found in the top level \verb|build| folder. To further +install the libraries onto your computer, simply type \verb|make install|. Thereafter, +to use the code inside of your program, precede your code with \newline \verb|#include "SPEX.h"|. -Installation of SPEX requires cmake. An optional top-level \verb'Makefile' -is provided to simplify its use (just do \verb'make ; make install'). +SPEX is also distributed with MATLAB and Python interfaces. Note that these interfaces have been thoroughly tested in Linux and are tuned to work ``out of the box'' on these types of machines. However, if the end user wishes to utilize the MATLAB or Python interfaces within a MacOS or Windows system, they may require additional library linkage in order to function properly. For example, on the MacOS, MATLAB R2022 does not currently support binaries compiled on ARM architecture, thus the code would have to be compiled with x-86. + +To install the MATLAB interface, +navigate to the \verb|SPEX/MATLAB| folder from the MATLAB command window and type +\verb|spex_mex_install| which will install the MATLAB interfaces to all SPEX packages. +These packages can then be used outside of the \verb|SPEX/MATLAB| folder by using the +MATLAB addpath tool. The Python interface does not need any additional installation, but does require the \texttt{Numpy}, \texttt{SciPy}, and \texttt{ctypes} libraries. Note that + +\chapter{General SPEX Data Structures and Macros}\vspace{-0.75in} + +The following macros/data structures are defined in \verb|SPEX.h| and are used in all SPEX functions. -\newpage -%------------------------------------------------------------------------------- -\section{Managing the SPEX environment} \label{s:user:setup} -%------------------------------------------------------------------------------- %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_VERSION|: the software package version} +%\cprotect\section{\verb|SPEX_VERSION|: the software package version} +\section{\texttt{SPEX\_VERSION}: the software package version} %------------------------------------------------------------------------------- - SPEX defines the following strings with \verb|#define|. Refer to the \verb|SPEX.h| file for details. -%---------------------------------------- -\begin{center} -\begin{tabular}{ll} -\hline -Macro & purpose \\ -\hline -\verb|SPEX_VERSION| & current version of the code (as a string)\\ -\verb|SPEX_VERSION_MAJOR| & major version of the code\\ -\verb|SPEX_VERSION_MINOR| & minor version of the code \\ -\verb|SPEX_VERSION_SUB| & sub version of the code\\ -\hline -\end{tabular} -\end{center} +\begin{SizedCenteredTabular}{ll} \hline + Macro & Purpose \\ \hline + \verb|SPEX_VERSION| & Current version of the code (as a string)\\ + \verb|SPEX_VERSION_MAJOR| & Major version of the code \\ + \verb|SPEX_VERSION_MINOR| & Minor version of the code \\ + \verb|SPEX_VERSION_SUB| & Sub version of the code \\ \hline +\end{SizedCenteredTabular} + %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_info|: status codes returned by SPEX} -\label{ss:SPEX_info} +%\cprotect\section{\verb|SPEX_info|: status codes returned by SPEX} +\section{\texttt{SPEX\_info}: status codes returned by SPEX} \label{ss:SPEX_info} %------------------------------------------------------------------------------- - Most SPEX functions return their status to the caller as their return value, an enumerated type called \verb|SPEX_info|. All current possible values for \verb|SPEX_info| are listed as follows: -\begin{center} -\begin{tabular}{rll} -\hline - 0& \verb|SPEX_OK|& The function was successfully executed.\\ -\hline - -1& \verb|SPEX_OUT_OF_MEMORY|& out of memory\\ -\hline - -2& \verb|SPEX_SINGULAR|& The input matrix $A$ is exactly singular.\\ -\hline - -3& \verb|SPEX_INCORRECT_INPUT|& One or more input arguments are incorrect.\\ -\hline - -4& \verb|SPEX_INCORRECT|& The solution is incorrect.\\ -\hline - -5& \verb|SPEX_UNSYMMETRIC|& The input matrix is unsymmetric (for Cholesky)\\ -\hline - -5& \verb|SPEX_PANIC| & SPEX environment error \\ -\hline -\end{tabular} -\end{center} - -Either \verb|SPEX_initialize| or \verb|SPEX_initialize_expert| (but not both) -must be called prior to using any other SPEX function. \verb|SPEX_finalize| -must be called as the last SPEX function. +\begin{SizedCenteredTabular}{rll} \hline + 0 & \verb|SPEX_OK|& The function was successfully executed.\\ \hline + -1 & \verb|SPEX_OUT_OF_MEMORY|& Out of memory\\ \hline + -2 & \verb|SPEX_SINGULAR|& The input matrix $A$ is exactly singular.\\ \hline + -3 & \verb|SPEX_INCORRECT_INPUT|& One or more input arguments are incorrect.\\ \hline + -4 & \verb|SPEX_NOTSPD| & The input matrix is not SPD (thus can't use Cholesky) \\ \hline + -5 & \verb|SPEX_INCORRECT_ALGORITHM| & The algorithm is not compatible with the factorization \\ \hline + -6 & \verb|SPEX_PANIC| & SPEX environment error \\ \hline +\end{SizedCenteredTabular} -Subsequent SPEX sessions can be restarted after a call to -\verb|SPEX_finalize|, by calling either \verb|SPEX_initialize| or -\verb|SPEX_initialize_expert| (but not both), followed by a final call to -\verb|SPEX_finalize| when finished. %------------------------------------------------------------------------------- -\newpage -\cprotect\subsection{\verb|SPEX_initialize|: initialize the working environment} +%\cprotect\section{\verb|SPEX_pivot|: enum for pivoting schemes} +\section{\texttt{SPEX\_pivot}: enum for pivoting schemes}\label{ss:SPEX_pivot} %------------------------------------------------------------------------------- +There are six available pivoting schemes provided in SPEX that can be +selected with the \verb|SPEX_options| structure. If the matrix is non-singular +(in an exact sense), then the pivot is always nonzero, and is chosen as the +{\em smallest} nonzero entry, with the smallest magnitude. This may seem +counter-intuitive, but selecting a small nonzero pivot leads to smaller growth +in the number of digits in the entries of \verb|L| and \verb|U|. This choice +does not lead to any kind of numerical inaccuracy, since SPEX is guaranteed +to find an exact roundoff-error free factorization of a non-singular matrix +(unless it runs out of memory), for any nonzero pivot choice. -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - SPEX_info SPEX_initialize - ( - void - ) ; -\end{verbatim} -} \end{mdframed} +The pivot tolerance for two of the pivoting schemes is specified by the +\verb|tol| component in \verb|SPEX_options|. The pivoting schemes are as +follows: + +\begin{SizedCenteredTabular}{llp{4in}}\hline + 0 & \verb|SPEX_SMALLEST| & The $k$-th pivot is selected as the smallest + entry in the $k$-th column.\\ \hline + 1 & \verb|SPEX_DIAGONAL| & The $k$-th pivot is selected as the diagonal + entry. If the diagonal entry is zero, + this method instead selects the smallest + pivot in the column.\\ \hline + 2 & \verb|SPEX_FIRST_NONZERO| & The $k$-th pivot is selected as the first + eligible nonzero in the column. \\ \hline + 3 & \verb|SPEX_TOL_SMALLEST| & The $k$-th pivot is selected as the diagonal + entry if the diagonal is within a + specified tolerance of the smallest entry in + the column. Otherwise, the smallest + entry in the $k$-th column is selected. + This is the default pivot selection + strategy. \\ \hline + 4 & \verb|SPEX_TOL_LARGEST| & The $k$-th pivot is selected as the diagonal + entry if the diagonal is within a + specified tolerance of the largest entry in + the column. Otherwise, the largest + entry in the $k$-th column is selected. \\ \hline + 5 & \verb|SPEX_LARGEST| & The $k$-th pivot is selected as the largest + entry in the $k$-th column. \\ \hline +\end{SizedCenteredTabular} + +%------------------------------------------------------------------------------- +%\cprotect\section{\verb|SPEX_preorder|} \label{ss:SPEX_preorder} +\section{\texttt{SPEX\_preorder}} \label{ss:SPEX_preorder} +%------------------------------------------------------------------------------- +The SPEX Library provides three ordering schemes: no ordering, COLAMD, and AMD. In LU factorization, the ordering is applied only to the columns, that is this ordering gives the matrix Q. In Cholesky factorizations, the ordering is applied to both the rows and columns, that is the ordering gives the matrices P and Q. + +\begin{SizedCenteredTabular}{llp{4in}} \hline + 1 & \verb|SPEX_NO_ORDERING| & No pre-ordering is performed on the matrix $A$, + that is $Q = I$. \\ \hline + 2 & \verb|SPEX_COLAMD| & The rows and/or columns of $A$ are permuted prior to + factorization using the COLAMD + \cite{davis2004algorithmcolamd} ordering. + This is recommended for LU factorization. \\ \hline + 3 & \verb|SPEX_AMD| & The rows and/or columns of $A$ are permuted prior + to the factorization using the the AMD + \cite{amestoy2004algorithmamd}. + This is recommended for Cholesky factorization. \\ \hline +\end{SizedCenteredTabular} + + +%------------------------------------------------------------------------------- +%\cprotect\section{\verb|SPEX_factorization_algorithm|} \label{ss:SPEX_factorization_algorithm} +\section{\texttt{SPEX\_factorization\_algorithm}} \label{ss:SPEX_factorization_algorithm} +%------------------------------------------------------------------------------- +This code tells SPEX which factorization is being used. Importantly, this is only used within a given solver. That is, this code is only used within LU/Cholesky factorization codes themselves. This is \textbf{NOT} used in the SPEX Backslash routines as that code selects the type of factorization using its own logic. + +\begin{SizedCenteredTabular}{llp{4in}} \hline + 1 & \verb|SPEX_LU_LEFT| & Left-looking LU factorization \\ \hline + 2 & \verb|SPEX_CHOL_LEFT| & Left-looking Chokesy factorization\\ \hline + 3 & \verb|SPEX_CHOL_UP| & Up-looking Cholesky factorization \\ \hline +\end{SizedCenteredTabular} + + +%------------------------------------------------------------------------------- +%\cprotect\section{ \verb|SPEX_options| structure} +\section{\texttt{SPEX\_options} structure} \label{ss:SPEX_options_struct} +%------------------------------------------------------------------------------- +The \verb|SPEX_options| struct stores key command parameters for various +functions used in the SPEX package. The \verb|SPEX_options* option| struct +contains the following components: + +\begin{itemize} + \item \verb|option->pivot|: An enum \verb|SPEX_pivot| type which controls the type of pivoting used. Default value: \verb|SPEX_SMALLEST| (3). + + \item \verb|option->order|: An enum \verb|SPEX_preorder| type which controls what column ordering is used. Default value: \verb|SPEX_COLAMD| for LU and \verb|SPEX_AMD| for Cholesky. + + \item \verb|option->tol|: A \verb|double| tolerance for the tolerance-based pivoting scheme, i.e., \newline \verb|SPEX_TOL_SMALLEST| or \verb|SPEX_TOL_LARGEST|. \verb|option->tol| must be in the range of $(0,1]$. Default value: 1 meaning that the diagonal entry will be selected if it has the same magnitude as the smallest entry in the $k$ the column. + + \item \verb|option->print_level|: An \verb|int| which controls the amount of output: 0: print nothing, 1: just errors, 2: terse, with basic stats from COLAMD/AMD and SPEX, 3: all, with matrices and results. Default value: 0. + + \item \verb|option->prec|: An \verb|int32_t| which specifies the precision used for multiple precision floating point numbers, (i.e., MPFR). This can be any integer larger than \verb|MPFR_PREC_MIN| (value of 1 in MPFR 4.0.2 and 2 in some legacy versions) and smaller than \verb|MPFR_PREC_MAX| (usually the largest possible integer available in your system). Default value: 128 (quad precision). + + \item \verb|option->round|: A \verb|mpfr_rnd_t| which determines the type of MPFR rounding to be used by SPEX. This is a parameter of the MPFR library. The options for this parameter are: + + \begin{itemize} + \item \verb|MPFR_RNDN|: Round to nearest (roundTiesToEven in IEEE 754-2008) + \item \verb|MPFR_RNDZ|: Round toward zero (roundTowardZero in IEEE 754-2008) + \item \verb|MPFR_RNDU|: Round toward plus infinity (roundTowardPositive in IEEE 754-2008) + \item \verb|MPFR_RNDD|: Round toward minus infinity (roundTowardNegative in IEEE 754-2008) + \item \verb|MPFR_RNDA|: Round away from zero + \item \verb|MPFR_RNDF|: Faithful rounding. This is not stable. + \end{itemize} + + \noindent Refer to the MPFR User Guide available at \url{https://www.mpfr.org/mpfr-current/mpfr.pdf} for details on the MPFR rounding style and any other utilized MPFR convention. Default value: \verb|MPFR_RNDN|. + + \item \verb|option->algo|: A \verb|SPEX_factorization_algorithm| which indicates which type of factorization is being used. +\end{itemize} + +All SPEX routines except basic memory management routines in Sections \ref{ss:SPEX_finalize}-\ref{ss:SPEX_calloc} and \verb|SPEX_options| allocation routine in \ref{ss:create_default_options} require \verb|option| as an input argument. The construction of the \verb|option| struct can be avoided by passing \verb|NULL| for the default settings. Otherwise, the following functions create and destroy a \verb|SPEX_options| structure: + +\begin{SizedCenteredTabular}{lp{2.5in}l} \hline + Function/Macro Name & Description & Section \\ \hline + \verb|SPEX_create_default_options| + & create and return \verb|SPEX_options| pointer with default parameters upon successful allocation + & \ref{ss:create_default_options} \\ \hline + \verb|SPEX_FREE| + & destroy \verb|SPEX_options| structure + & \ref{ss:SPEX_free} \\ \hline +\end{SizedCenteredTabular} -\verb|SPEX_initialize| initializes the working environment for SPEX -functions. SPEX utilizes a specialized memory management scheme in order to -prevent potential memory failures caused by GMP and MPFR libraries. Either -this function or \verb|SPEX_initialize_expert| must be called prior to using -any other function in the library. Returns \verb|SPEX_PANIC| if SPEX has -already been initialized, or \verb|SPEX_OK| if successful. %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_initialize_expert|: initialize environment -(expert version)}\label{ss:SPEX_initialize_expert} +%\cprotect\section{\verb|SPEX_vector|} \label{ss:SPEX_vector} +\section{\texttt{SPEX\_vector}} \label{ss:SPEX_vector} %------------------------------------------------------------------------------- +SPEX vector is a compressed sparse vector data structure which will be used for SPEX dynamic CSC matrices. This struct is not used in SPEX version 3.0 and its funcionality will be fully developed in a future release of SPEX; however the struct is provided here so that future versions of SPEX have backward compatibility. -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - SPEX_info SPEX_initialize_expert - ( - void* (*MyMalloc) (size_t), // user-defined malloc - void* (*MyCalloc) (size_t, size_t), // user-defined calloc - void* (*MyRealloc) (void *, size_t), // user-defined realloc - void (*MyFree) (void *) // user-defined free - ) ; -\end{verbatim} -} \end{mdframed} +\update{ +This is only used publicly when calling the functions in SPEX Update to construct the vector to modify original matrix A, (either \verb|w| for $A'=A+\sigma ww^T$ in rank-1 update/downdate or \verb|vk| to be swapped with \verb|A->v[k]| in the update for column replacement). +} +This is \textbf{NOT} intended to be used for building any n-by-1 vector (e.g., the right-hand-side vector b in Ax=b), which should be considered as a n-by-1 \verb|SPEX_matrix|. This struct contains the following components: -\verb|SPEX_initialize_expert| is the same as \verb|SPEX_initialize| except that -it allows for a redefinition of custom memory functions that are used for SPEX -and GMP/ MPFR. The four inputs to this function are pointers to four -functions with the same signatures as the ANSI C \verb'malloc', \verb'calloc', -\verb'realloc', and \verb'free' functions. That is: +\begin{itemize} + \item \verb|vector->nz|: The number of explicit entries in the vector. Data Type: \verb|int64_t|. -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - #include - void *malloc (size_t size) ; - void *calloc (size_t nmemb, size_t size) ; - void *realloc (void *ptr, size_t size) ; - void free (void *ptr) ; -\end{verbatim} -} \end{mdframed} + \item \verb|vector->nzmax|: The size of the \verb|i| and \verb|x| arrays. Note that \verb|nz| $\le$ \verb|nzmax|. Data Type: \verb|int64_t|. + + \item \verb|vector->i|: An array of size \verb|nzmax| containing the row indices of all explicit entries in the vector. The last \verb|(nzmax-nz)| entries are undefined. Data Type: \verb|int64_t*|. + + \item \verb|vector->x|: An array of size \verb|nzmax| containing the numeric values of all explicit entries in the vector. The last \verb|(nzmax-nz)| entries are undefined. Data Type: \verb|mpz_t*|. + + \item \verb|vector->scale|: Scaling parameter. The actual value of the $k$-th nonzero should be computed as \verb|x[k]*scale|. Both \verb|x[k]*scale| and \verb|x[k]/mpq_denref(scale)| must be integer for all entries, where \verb|mpq_denref(scale)| is a GMP macro that gives the denominator of \verb|scale|. This is used to skip explicit update(s) for a column/row of the factorization matrix, when all entries are to be multiplied with the same scaling factor(s). Data Type: \verb|mpq_t|. +\end{itemize} + +In the current release, the \verb|SPEX_vector| is only used as a part of the \verb|SPEX_matrix| struct and is always a NULL pointer. +\update{ +The SPEX package has a set of functions to allocate, +destroy and reallocate a SPEX vector, \verb|SPEX_vector|, as shown in the following table. + +\begin{SizedCenteredTabular}{lll} \hline + Function Name & Description & Section \\ \hline + \verb|SPEX_vector_allocate| + & allocate \verb|SPEX_vector| with \verb|nzmax| entries + & \ref{ss:spex_vector_allocate} \\ \hline + \verb|SPEX_vector_realloc| + & reallocate \verb|SPEX_vector| with \verb|new_size| entries + & \ref{ss:spex_vector_realloc} \\ \hline + \verb|SPEX_vector_free| + & destroy a \verb|SPEX_vector| and free its allocated + & \ref{ss:spex_vector_free} \\& memory&\\ \hline +\end{SizedCenteredTabular} + +}%End Update -Returns \verb|SPEX_PANIC| if SPEX has already been initialized, -or \verb|SPEX_OK| if successful. %------------------------------------------------------------------------------- -\newpage -\cprotect\subsection{\verb|SPEX_finalize|: free the working environment} -\label{ss:SPEX_finalize} +%\cprotect\section{The \verb|SPEX_matrix| structure} \label{ss:SPEX_matrix} +\section{The \texttt{SPEX\_matrix} structure} \label{ss:SPEX_matrix} %------------------------------------------------------------------------------- +SPEX operates on matrices stored in any of the 16 different matrix formats: 15 of which are combinations of matrix formats and entry data-types: +$\{$Static Compressed Sparse Column (CSC), triplet, dense$\} \times \{$ \verb|mpz_t|, +\verb|mpq_t|, \verb|mpfr_t|, \verb|int64_t|, or \verb|double|$\}$, and the 16th of which is the dynamic CSC matrix with \verb|mpz_t| entries. Using the SPEX matrix copy function, a matrix of any given form and data-type can be copied and converted into a matrix of any one of the 16 matrix-form and data-type combinations. + +Most routines require the matrix to be in CSC form with \verb|mpz_t| (i.e., arbitrary-sized integer) data +type. This data structure stores the matrix $A$ as a sequence of three arrays: + +\begin{itemize} + \item \verb|A->p|: Column pointers; an array of size \verb|n+1|. The row indices of column $j$ are located in positions \verb|A->p[j]| to \verb|A->p[j+1]-1| of the array \verb|A->i|. Data type: \verb|int64_t|. + + \item \verb|A->i|: Row indices; an array of size equal to the number of entries in the matrix. The entry \verb|A->i[k]| is the row index of the $k$th nonzero in the matrix. Data type: \verb|int64_t|. + + \item \verb|A->x|: Numeric entries. The entry \verb|A->x[k]| is the numeric value of the $k$th nonzero in the matrix. The array \verb|A->x| has a union type and must be accessed via a suffix according to the type of \verb|A|. For details, please refer to Section~\ref{ss:SPEX_matrix}. +\end{itemize} + +An example matrix $A$ with \verb|mpz_t| type is stored as follows (note that indexing is zero based as per the C convention). +\[A = \begin{bmatrix} + 1 & 0 & 0 & 1 \\ + 2 & 0 & 4 & 12 \\ + 7 & 1 & 1 & 1 \\ + 0 & 2 & 3 & 0 \\ +\end{bmatrix}\] -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize \begin{verbatim} - SPEX_info SPEX_finalize - ( - void - ) ; +A->p = [0, 3, 5, 8, 11] +A->i = [0, 1, 2, 2, 3, 1, 2, 3, 0, 1, 2] +A->x.mpz = [1, 2, 7, 1, 2, 4, 1, 3, 1, 12, 1] \end{verbatim} -} \end{mdframed} -\verb|SPEX_finalize| finalizes the working environment for SPEX -library, and frees any internal workspace created by SPEX. It must be -called as the last \verb|SPEX_*| function called, except that a subsequent -call to \verb|SPEX_initialize*| may be used to start another SPEX session. -Returns \verb|SPEX_PANIC| if SPEX has not been initialized, -or \verb|SPEX_OK| if successful. +For example, the last column appears in positions 8 to 10 of \verb|A->i| and \verb|A->x.mpz|, with row indices 0, 1, and 2, and values $a_{03}=1$, $a_{13}=12$, and $a_{23}=1$. + %------------------------------------------------------------------------------- -\section{Memory Management} \label{s:user:memmanag} +%\cprotect\subsection{\verb|SPEX_kind|: enum for matrix formats} +\subsection{\texttt{SPEX\_kind}: enum for matrix formats} \label{ss:SPEX_kind} %------------------------------------------------------------------------------- +The SPEX library provides four available matrix formats: sparse CSC +(compressed sparse column), sparse triplet, dense and sparse dynamic CSC. + +\begin{SizedCenteredTabular}{llp{4in}} \hline + 0 & \verb|SPEX_CSC| & Matrix is in compressed sparse column format. \\ \hline + 1 & \verb|SPEX_TRIPLET| & Matrix is in sparse triplet format. \\ \hline + 2 & \verb|SPEX_DENSE| & Matrix is in dense format.\\ \hline + 3 & \verb|SPEX_DYNAMIC_CSC| & Matrix is in dynamic CSC format. \\ \hline +\end{SizedCenteredTabular} -The routines in this section are used to allocate and free memory for the data -structures used in SPEX. By default, SPEX relies on the SuiteSparse -memory management functions, \verb|SuiteSparse_malloc|, -\verb|SuiteSparse_calloc|, \verb|SuiteSparse_realloc|, and -\verb|SuiteSparse_free|. By default, those functions rely on the ANSI C -\verb|malloc|, \verb|calloc|, \verb|realloc|, and \verb|free|, but this may be -changed by initializing the SPEX environment with -\verb|SPEX_initialize_expert|. %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_calloc|: allocate initialized memory} -\label{ss:SPEX_calloc} +%\cprotect\subsection{\verb|SPEX_type|: enum for data types of matrix entries} +\subsection{\texttt{SPEX\_type}: enum for data types of matrix entries} +\label{ss:SPEX_type} %------------------------------------------------------------------------------- +The SPEX library provides five data types for matrix entries: \verb|mpz_t|, +\verb|mpq_t|, \verb|mpfr_t|, \verb|int64_t| and \verb|double|. -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - void *SPEX_calloc - ( - size_t nitems, // number of items to allocate - size_t size // size of each item - ) ; -\end{verbatim} -} \end{mdframed} +\begin{SizedCenteredTabular}{llp{4in}} \hline + 0 & \verb|SPEX_MPZ| & Matrix entries are in \verb|mpz_t| type: an integer + of arbitrary size. \\ \hline + 1 & \verb|SPEX_MPQ| & Matrix entries are in \verb|mpq_t| type: a rational + number with arbitrary-sized integer numerator and + denominator. \\ \hline + 2 & \verb|SPEX_MPFR| & Matrix entries are in \verb|mpfr_t| type: a + floating-point number of arbitrary precision. \\ \hline + 3 & \verb|SPEX_INT64| & Matrix entries are in \verb|int64_t| type. \\ \hline + 4 & \verb|SPEX_FP64| & Matrix entries are in \verb|double| type. \\ \hline +\end{SizedCenteredTabular} -\verb|SPEX_calloc| allocates a block of memory for an array of \verb|nitems| -elements, each of them \verb|size| bytes long, and initializes all its bits to -zero. If any input is less than 1, it is treated as if equal to 1. If the -function failed to allocate the requested block of memory, then a \verb|NULL| -pointer is returned. -Returns \verb|NULL| if SPEX has not been initialized. %------------------------------------------------------------------------------- -\newpage -\cprotect\subsection{\verb|SPEX_malloc|: allocate uninitialized memory} -\label{ss:SPEX_malloc} +%\cprotect\subsection{\verb|SPEX_matrix| structure} +\subsection{\texttt{SPEX\_matrix} structure} %------------------------------------------------------------------------------- +A matrix \verb|SPEX_matrix *A| has the following components: -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - void *SPEX_malloc - ( - size_t size // size of memory space to allocate - ) ; -\end{verbatim} -} \end{mdframed} +\begin{itemize} + \item \verb|A->kind|: Indicating the kind of matrix A: CSC, triplet, dense or dynamic CSC. Data Type: \verb|SPEX_kind|. -\verb|SPEX_malloc| allocates a block of \verb|size| bytes of memory, returning -a pointer to the beginning of the block. The content of the newly allocated -block of memory is not initialized, remaining with indeterminate values. -If \verb|size| is less than 1, it is treated as if equal to 1. If the function -fails to allocate the requested block of memory, then a \verb|NULL| pointer is -returned. -Returns \verb|NULL| if SPEX has not been initialized. + \item \verb|A->type|: Indicating the type of entries in matrix A: \verb|mpz_t|, \verb|mpq_t|, \verb|mpfr_t|, \verb|int64_t| or \verb|double|. Data Type: \verb|SPEX_type|. -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_realloc|: resize allocated memory} -\label{ss:SPEX_realloc} -%------------------------------------------------------------------------------- + \item \verb|A->m|: Number of rows in the matrix. Data Type: \verb|int64_t|. -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - void *SPEX_realloc // pointer to reallocated block, or original block - // if the realloc failed - ( - int64_t nitems_new, // new number of items - int64_t nitems_old, // previous/old number of items - size_t size_of_item, // size of each item - void *p, // pointer to reallocate - bool *ok // true if success, false on failure - ) ; -\end{verbatim} -} \end{mdframed} + \item \verb|A->n|: Number of columns in the matrix. Data Type: \verb|int64_t|. -\verb|SPEX_realloc| is a wrapper for realloc. If \verb|p| is non-\verb|NULL| on -input, it points to a previously allocated array of size \verb|nitems_old| -$\times$ \verb|size_of_item|. The array is reallocated to be of size -\verb|nitems_new| $\times$ \verb|size_of_item|. If \verb|p| is \verb|NULL| on input, -then a new array of that size is allocated. On success, a pointer to the new -array is returned. Returns \verb|ok| as \verb|false| if SPEX has not been -initialized. - -If the reallocation fails, \verb|p| is not modified, and \verb|ok| is returned -as \verb|false| to indicate that the reallocation failed. If the size -decreases or remains the same, then the method always succeeds (\verb|ok| is -returned as \verb|true|), unless SPEX has not been initialized. - -Typical usage: the following code fragment allocates an array of 10 -\verb|int|'s, and then increases the size of the array to 20 \verb|int|'s. If -the \verb|SPEX_malloc| succeeds but the \verb|SPEX_realloc| fails, then the -array remains unmodified, of size 10. - -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - int *p ; - p = SPEX_malloc (10 * sizeof (int)) ; - if (p == NULL) { error here ... } - printf ("p points to an array of size 10 * sizeof (int)\n") ; - bool ok ; - p = SPEX_realloc (20, 10, sizeof (int), p, &ok) ; - if (ok) printf ("p has size 20 * sizeof (int)\n") ; - else printf ("realloc failed; p still has size 10 * sizeof (int)\n") ; - SPEX_free (p) ; -\end{verbatim} -} \end{mdframed} - -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_free|: free allocated memory} -\label{ss:SPEX_free} -%------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - void SPEX_free - ( - void *p // Pointer to memory space to free - ) ; -\end{verbatim} -} \end{mdframed} - -\verb|SPEX_free| deallocates the memory previously allocated by a call to -\verb|SPEX_calloc|, \verb|SPEX_malloc|, or \verb|SPEX_realloc|. If \verb|p| is -\verb|NULL| on input, then no action is taken (this is not an error condition). -To guard against freeing the same memory space twice, the following macro -\verb|SPEX_FREE| is provided, which calls \verb|SPEX_free| and then sets the -freed pointer to \verb|NULL|. - -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - #define SPEX_FREE(p) \ - { \ - SPEX_free (p) ; \ - (p) = NULL ; \ - } -\end{verbatim} -} \end{mdframed} + \item \verb|A->scale|: A scaling parameter for matrix of \verb|mpz_t| type. For all matrices whose entries are stored in data type other than \verb|mpz_t|, SPEX assumes and maintains \verb|A->scale = 1|. This is used to ensure that entry can be represented as an integer in an \verb|mpz_t| matrix if these entries are converted from non-integer type data (such as double, variable precision floating point, or rational). Data Type: \verb|mpq_t|. -No action is taken if SPEX has not been initialized. + \item \verb|A->nzmax|: The allocated size of the vectors \verb|A->i|, \verb|A->j| and \verb|A->x|. Note that \verb|A->nzmax| $\geq$ \verb|nnz(A)|, where \verb|nnz(A)| is the return value of \verb|SPEX_matrix_nnz(A,option)|. Data Type: \verb|int64_t|. -%------------------------------------------------------------------------------- -\cprotect\section{The \verb|SPEX_options| structure: -parameter settings for SPEX} \label{ss:SPEX_options} -%------------------------------------------------------------------------------- + \item \verb|A->nz|: The number of nonzeros in the matrix $A$, if $A$ is a triplet matrix (ignored for matrices in CSC, dense or dynamic CSC formats). Data Type: \verb|int64_t|. -The \verb|SPEX_options| structure contains numerous parameters that may be -modified to change the behavior of the SPEX functions. Default values of -these parameters will lead to good performance in most cases. Modifying this -struct provides control of column orderings, pivoting schemes, and other -components of the factorization. + \item \verb|A->p|: An array of size \verb|A->n|$+1$ which contains column pointers of $A$, if $A$ is a CSC matrix (\verb|NULL| for matrices in triplet or dense formats). Data Type: \verb|int64_t*|. -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_pivot|: enum for pivoting schemes} -\label{ss:SPEX_pivot} -%------------------------------------------------------------------------------- + \item \verb|A->p_shallow|: A boolean indicating whether \verb|A->p| is shallow. A {\em shallow} pointer is one that refers to a component of another matrix or data structure. If \verb|A->p| is shallow, then it should not be modified as part of the \verb|A| matrix, and it is not freed if \verb|A| is freed. Data Type: \verb|bool|. -There are six available pivoting schemes provided in SPEX that can be -selected with the \verb|SPEX_options| structure. If the matrix is non-singular -(in an exact sense), then the pivot is always nonzero, and is chosen as the -{\em smallest} nonzero entry, with the smallest magnitude. This may seem -counter-intuitive, but selecting a small nonzero pivot leads to smaller growth -in the number of digits in the entries of \verb|L| and \verb|U|. This choice -does not lead to any kind of numerical inaccuracy, since SPEX is guaranteed -to find an exact roundoff-error free factorization of a non-singular matrix -(unless it runs out of memory), for any nonzero pivot choice. + \item \verb|A->i|: An array of size \verb|A->nzmax| which contains the row indices of the nonzeros in $A$, if $A$ is a CSC or triplet matrix (\verb|NULL| for dense matrices). The matrix is zero-based, so row indices are in the range of $[0,$ \verb|A->m|$-1]$. Data Type: \verb|int64_t*|. -The pivot tolerance for two of the pivoting schemes is specified by the -\verb|tol| component in \verb|SPEX_options|. The pivoting schemes are as -follows: + \item \verb|A->i_shallow|: A boolean indicating whether \verb|A->i| is shallow. Data Type: \verb|bool|. -%---------------------------------------- -{\small -\begin{center} -\begin{tabular}{llp{4in}} -\hline -0 & \verb|SPEX_SMALLEST| & The $k$-th pivot is selected as the smallest - entry in the $k$-th column.\\ -\hline -1 & \verb|SPEX_DIAGONAL| & The $k$-th pivot is selected as the diagonal - entry. If the diagonal entry is zero, - this method instead selects the smallest - pivot in the column.\\ -\hline -2 & \verb|SPEX_FIRST_NONZERO| & The $k$-th pivot is selected as the first - eligible nonzero in the column. \\ -\hline -3 & \verb|SPEX_TOL_SMALLEST| & The $k$-th pivot is selected as the diagonal - entry if the diagonal is within a - specified tolerance of the smallest entry in - the column. Otherwise, the smallest - entry in the $k$-th column is selected. - This is the default pivot selection - strategy. \\ -\hline -4 & \verb|SPEX_TOL_LARGEST| & The $k$-th pivot is selected as the diagonal - entry if the diagonal is within a - specified tolerance of the largest entry in - the column. Otherwise, the largest - entry in the $k$-th column is selected. \\ -\hline -5 & \verb|SPEX_LARGEST| & The $k$-th pivot is selected as the largest - entry in the $k$-th column. \\ -\hline -\end{tabular} -\end{center} -} + \item \verb|A->j|: An array of size \verb|A->nzmax| which contains the column indices of the nonzeros in $A$, if $A$ is a triplet matrix (\verb|NULL| for matrices in CSC or dense formats). The matrix is zero-based, so column indices are in the range of $[0,$ \verb|A->n|$-1]$. Data Type: \verb|int64_t*|. -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_col_order|: enum for column ordering schemes} -\label{ss:SPEX_col_order} -%------------------------------------------------------------------------------- + \item \verb|A->j_shallow|: A boolean indicating whether \verb|A->j| is shallow. Data Type: \verb|bool|. -The SPEX library provides three column ordering schemes: no pre-ordering, -COLAMD, and AMD, selected via the \verb|order| -component in the \verb|SPEX_options| structure described in Section -\ref{ss:SPEX_options_struct}. + \item \verb|A->x|: An array of size \verb|A->nzmax| which contains the numeric values of the matrix. This array is a union, and must be accessed via one of: \verb|A->x.mpz|, \verb|A->x.mpq|, \verb|A->x.mpfr|, \verb|A->x.int64|, or \verb|A->x.fp64|, depending on the \verb|A->type| parameter. Data Type: \verb|union|. -{\small -\begin{center} -\begin{tabular}{llp{4in}} -\hline -0 & \verb|SPEX_NO_ORDERING| & No pre-ordering is performed on the matrix $A$, - that is $Q = I$. \\ -\hline -1 & \verb|SPEX_COLAMD| & The columns of $A$ are permuted prior to - factorization using the COLAMD - \cite{davis2004algorithmcolamd} ordering. - This is the default ordering. \\ -\hline -2 & \verb|SPEX_AMD| & The nonzero pattern of $A + A^T$ is analyzed and - the columns of $A$ are permuted prior to - factorization based on the AMD - \cite{amestoy2004algorithmamd} ordering of - $A+A^T$. This works well if $A$ has a mostly - symmetric pattern, but tends to be worse - than COLAMD on matrices with unsymmetric pattern. - \cite{davis2004column}.\\ -\hline -\end{tabular} -\label{tab:SPEX_pivot} -\end{center} -} + \item \verb|A->x_shallow|: A boolean indicating whether \verb|A->x| is shallow. Data Type: \verb|bool|. -%------------------------------------------------------------------------------- -\cprotect\subsection{ \verb|SPEX_options| structure} -\label{ss:SPEX_options_struct} -%------------------------------------------------------------------------------- + \item \verb|A->v|: If the matrix is a \verb|SPEX_DYNAMIC_CSC| this is an array of size \verb|A->n|, each of which is a dynamic column vector. Data Type: \verb|SPEX_vector**|. Always NULL in SPEX 3.0 +\end{itemize} -The \verb|SPEX_options| struct stores key command parameters for various -functions used in the SPEX package. The \verb|SPEX_options* option| struct -contains the following components: +Specifically, for different kinds of \verb|A| of size \verb|A->m| $\times$ \verb|A->n| +with \verb|nz| nonzero entries, its components are defined as: \begin{itemize} \item -\verb|option->pivot|: An enum \verb|SPEX_pivot| type (discussed in Section -\ref{ss:SPEX_pivot}) which controls the type of pivoting used. Default value: -\verb|SPEX_TOL_SMALLEST| (3). - -\item -\verb|option->order|: An enum \verb|SPEX_col_order| type (discussed in Section -\ref{ss:SPEX_col_order}) which controls what column ordering is used. Default -value: \verb|SPEX_COLAMD| (1). - -\item -\verb|option->tol|: A \verb|double| tolerance for -the tolerance-based pivoting scheme, i.e., \verb|SPEX_TOL_SMALLEST| or -\verb|SPEX_TOL_LARGEST|. \verb|option->tol| must be in the range of $(0,1]$. -Default value: 1 meaning that the diagonal entry will be selected if it has the -same magnitude as the smallest entry in the $k$ the column. + (0) \verb|SPEX_CSC|: A sparse matrix in CSC (compressed sparse column) format. + \verb|A->p| is an \verb|int64_t| array of size \verb|A->n|+1, \verb|A->i| + is an \verb|int64_t| array of size \verb|A->nzmax| (with $nz$ $\le$ + \verb|A->nzmax|), and \verb|A->x.TYPE| is an array of size + \verb|A->nzmax| of matrix entries (\verb'TYPE' is one of \verb|mpz|, + \verb|mpq|, \verb|mpfr|, \verb|int64|, or \verb|fp64|). The row indices + of column $j$ appear in \verb|A->i [A->p [j] ... A->p [j+1]-1]|, and the + values appear in the same locations in \verb|A->x.TYPE|. The \verb|A->j| + array is \verb|NULL|. \verb|A->nz| is ignored; the number of entries in + \verb|A| is given by \verb|A->p [A->n]|. + Row indices need not be sorted in each column, but duplicates cannot + appear. \item -\verb|option->print_level|: An \verb|int| which controls the amount of -output: -0: print nothing, 1: just errors, 2: terse, with basic stats from -COLAMD/AMD and SPEX, 3: all, with matrices and results. Default value: 0. + (1) \verb|SPEX_TRIPLET|: A sparse matrix in triplet format. \verb|A->i| and + \verb|A->j| are both \verb|int64_t| arrays of size \verb|A->nzmax|, and + \verb|A->x.TYPE| is an array of values of the same size. The $k$th tuple + has row index \verb|A->i [k]|, column index \verb|A->j [k]|, and value + \verb|A->x.TYPE [k]|, with 0 $\le$ $k <$ \verb|A->nz|. + The \verb|A->p| array is \verb|NULL|. + Triplets can be unsorted, but duplicates cannot appear. \item -\verb|option->prec|: An \verb|int32_t| which specifies the precision used -for multiple precision floating point numbers, (i.e., MPFR). This -can be any integer larger than \verb|MPFR_PREC_MIN| (value of 1 in MPFR 4.0.2 -and 2 in some legacy versions) and smaller than \verb|MPFR_PREC_MAX| (usually -the largest possible integer available in your system). Default value: 128 -(quad precision). + (2) \verb|SPEX_DENSE|: A dense matrix. The integer arrays \verb|A->p|, + \verb|A->i|, and \verb|A->j| are all \verb|NULL|. \verb|A->x.TYPE| is a + pointer to an array of size \verb|A->m|*\verb|A->n|, stored in + column-oriented format. The value of $A(i,j)$ is \verb|A->x.TYPE [p]| + with \verb|p| = $i + j*$\verb|A->m|. \verb|A->nz| is ignored; the number + of entries in \verb|A| is \verb|A->m| $\times$ \verb|A->n|. \item -\verb|option->round|: A \verb|mpfr_rnd_t| which determines the type -of MPFR rounding to be used by SPEX. This is a parameter of the MPFR -library. The options for this parameter are: - - \begin{itemize} - \item \verb|MPFR_RNDN|: round to nearest - (roundTiesToEven in IEEE 754-2008) - \item \verb|MPFR_RNDZ|: round toward zero - (roundTowardZero in IEEE 754-2008) - \item \verb|MPFR_RNDU|: round toward plus infinity - (roundTowardPositive in IEEE 754-2008) - \item \verb|MPFR_RNDD|: round toward minus infinity - (roundTowardNegative in IEEE 754-2008) - \item \verb|MPFR_RNDA|: round away from zero - \item \verb|MPFR_RNDF|: faithful rounding. This is not stable. - \end{itemize} + (3) \verb|SPEX_DYNAMIC_CSC|: Currently unused + \update{ + A sparse matrix in dynamic CSC + format with the number of nonzeros in each column changing + independently and dynamically, which is only used in the SPEX update + functions. The matrix is held as an array of \verb|A->n| SPEX vectors, one per + column. Each column is held as a \verb|SPEX_vector|, containing \verb|mpz_t| values + and its own scale factor. For this kind, \verb|A->nzmax|, \verb|A->nz|, \verb|A->p|, \verb|A->i|, + \verb|A->x| and \verb|A->*_shallow| are ignored and pointers \verb|p|, \verb|i| and \verb|x| are remained + as NULL pointers. To access entries in column $j$, \verb|A->v[j]->i[0 ... A->v[j]->nz-1]| + give the row indices of all nonzeros, and the \verb|mpz_t| values + of these entries appear in the same locations in \verb|A->v[j]->x|. + \verb|A->v[j]->nzmax| is the max number of nonzeros allocated for the $j$th column, while \verb|A->v[j]->nz| is the number of existing nonzeros in the $j$th column. Therefore, the total number + of existing nonzeros is computed as $\sum_{j=0}^{n-1}$(\verb|A->v[j]->nz|).} -\noindent Refer to the MPFR User Guide available at -\url{https://www.mpfr.org/mpfr-current/mpfr.pdf} for details on the MPFR -rounding style and any other utilized MPFR convention. Default value: -\verb|MPFR_RNDN|. +\end{itemize} -\item -\verb|option->check|: A \verb|bool| which indicates whether the solution to the -system should be checked. Intended for debugging only; the SPEX library is -guaranteed to return the exact solution. Default value: \verb|false|. +\verb|A| may contain shallow components, \verb|A->p|, \verb|A->i|, \verb|A->j|, +and \verb|A->x|. For example, if \verb|A->p_shallow| is true, then a +non-\verb|NULL| \verb|A->p| is a pointer to a read-only array, and the +\verb|A->p| array is not freed by \verb|SPEX_matrix_free|. If \verb|A->p| is +\verb|NULL| (for a triplet or dense matrix), then \verb|A->p_shallow| has no +effect. -\end{itemize} +%removed +%To simplify the access the entries in \verb|A|, SPEX package provides the +%following macros (Note that the \verb|TYPE| parameter in the macros is one of: +%\verb|mpz|, \verb|mpq|, \verb|mpfr|, \verb|int64| or \verb|fp64|): + +%\begin{itemize} + +%\item +%\verb|SPEX_1D(A,k,TYPE)|: used to access the $k$th entry in +% \verb|SPEX_matrix *A| using 1D linear addressing for +% any matrix kind (CSC, triplet or dense), in any type +% with \verb|TYPE| specified corresponding +% +%\item +%\verb|SPEX_2D(A,i,j,TYPE)|: used to access the $(i,j)$th entry in a dense +% \verb|SPEX_matrix *A|. +% +%\end{itemize} -All SPEX routines except basic memory management routines in Sections -\ref{ss:SPEX_finalize}-\ref{ss:SPEX_calloc} and \verb|SPEX_options| allocation -routine in \ref{ss:create_default_options} require \verb|option| as an input -argument. The construction of the \verb|option| struct can be avoided by -passing \verb|NULL| for the default settings. Otherwise, the following -functions create and destroy a \verb|SPEX_options| structure: - -%---------------------------------------- -\begin{center} -\begin{tabular}{lp{2.5in}l} -\hline -function/macro name & description & section \\ -\hline -\verb|SPEX_create_default_options| - & create and return \verb|SPEX_options| pointer - with default parameters upon successful allocation - & \ref{ss:create_default_options} \\ -\hline -\verb|SPEX_FREE| - & destroy \verb|SPEX_options| structure - & \ref{ss:SPEX_free} \\ -\hline -\end{tabular} -\end{center} - -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_create_default_options|: create default \verb|SPEX_options| structure} -\label{ss:create_default_options} -%------------------------------------------------------------------------------- +The SPEX package has a set of functions to allocate, copy(convert), query and +destroy a SPEX matrix, \verb|SPEX_matrix|, as shown in the following table. -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} - SPEX_options* SPEX_create_default_options - ( - void - ) ; -\end{verbatim} -} \end{mdframed} +\begin{SizedCenteredTabular}{lp{2.5in}l} \hline + Function Name & Description & Section \\ \hline + \verb|SPEX_matrix_allocate| + & allocate a $m$-by-$n$ \verb|SPEX_matrix| + & \ref{s:user:matrix_allocate} \\ \hline + \verb|SPEX_matrix_free| + & destroy a \verb|SPEX_matrix| and free its allocated memory + & \ref{s:user:matrix_free} \\ \hline + \verb|SPEX_matrix_copy| + & make a copy of a matrix, into another kind and/or type + & \ref{s:user:matrix_copy} \\ \hline + \verb|SPEX_matrix_nnz| + & get the number of entries in a matrix + & \ref{s:user:matrix_nnz} \\ \hline + \verb|SPEX_matrix_check| + & check the validity of a matrix and print it + & \ref{s:user:matrix_check} \\ \hline +\end{SizedCenteredTabular} -\verb|SPEX_create_default_options| creates and returns a pointer to a -\verb|SPEX_options| struct with default parameters upon successful allocation, -which are discussed in Section \ref{ss:SPEX_options_struct}. To safely free -the \verb|SPEX_options* option| structure, simply use \newline \verb|SPEX_FREE(option)|. -All functions that require \verb|SPEX_options *option| as an input argument can -have a \verb'NULL' pointer passed instead. In this case, the default value of -the corresponding command option is used. For example, if a \verb'NULL' pointer -is passed to the symbolic analysis routines, COLAMD is used. As a result, -defaults are desired, the \verb|SPEX_options| struct need not be allocated. -Returns \verb|NULL| if SPEX has not been initialized. %------------------------------------------------------------------------------- -\cprotect\section{The \verb|SPEX_matrix| structure} \label{ss:SPEX_matrix} +%\cprotect\section{The \verb|SPEX_symbolic_analysis| struct} \label{s:spex_symbolic_analysis} +\section{The \texttt{SPEX\_symbolic\_analysis} struct} \label{s:spex_symbolic_analysis} %------------------------------------------------------------------------------- +The symbolic analysis structure handles all preorderings and graphical struture information for each factorization within SPEX. First, section \ref{ss:spex_factorization_kind} discusses an enum for the type of factorization and next section \ref{ss:SPEX_symbolic_struct} discusses the components of this data structure. -All matrices for SPEX are stored as a \verb|SPEX_matrix| structure (a pointer -to a \verb'struct'). The matrix can be held in three formats: CSC, triplet or -dense matrix (as discussed in Section \ref{ss:SPEX_kind}) with entries stored -as 5 different types: \verb|mpz_t|, \verb|mpq_t|, \verb|mpfr_t|, \verb|int64_t| -and \verb|double| (as discussed in Section \ref{ss:SPEX_type}). This gives a -total of 15 different combinations of matrix format and entry type. Note that -not all functions accept all 15 matrix types. Indeed, most functions expect the -input matrix $A$ to be a CSC \verb|mpz_t| matrix while vectors (such as $x$ and -$b$) are in dense format. %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_kind|: enum for matrix formats} -\label{ss:SPEX_kind} +%\cprotect\subsection{\verb|SPEX_factorization_kind|: enum for kind of factorization} +\subsection{\texttt{SPEX\_factorization\_kind}: enum for kind of factorization} \label{ss:spex_factorization_kind} %------------------------------------------------------------------------------- -The SPEX library provides three available matrix formats: sparse CSC -(compressed sparse column), sparse triplet and dense. +The SPEX library currently provides two types of factorizations: LU and Cholesky. The value +\verb|SPEX_QR_FACTORIZATION| is reserved for future development. + +\begin{SizedCenteredTabular}{lll} \hline +0 & \verb|SPEX_LU_FACTORIZATION| & LU factorization is being used \\ \hline +1 & \verb|SPEX_CHOLESKY_FACTORIZATION| & Cholesky factorization is being used\\ \hline +2 & \verb|SPEX_QR_FACTORIZATION| & QR factorization is being used \\ + & & (reserved for future use)\\ \hline +\end{SizedCenteredTabular} -{\small -\begin{center} -\begin{tabular}{llp{4in}} -\hline -0 & \verb|SPEX_CSC| & Matrix is in compressed sparse column format. \\ -\hline -1 & \verb|SPEX_TRIPLET| & Matrix is in sparse triplet format. \\ -\hline -2 & \verb|SPEX_DENSE| & Matrix is in dense format.\\ -\hline -\end{tabular} -\label{tab:SPEX_kind} -\end{center} -} %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_type|: enum for data types of matrix entries} -\label{ss:SPEX_type} +%\cprotect\subsection{\verb|SPEX_symbolic_analysis| Data Structure} +\subsection{\texttt{SPEX\_symbolic\_analysis} Data Structure} \label{ss:SPEX_symbolic_struct} %------------------------------------------------------------------------------- +A symbolic analysis \verb|SPEX_symbolic_analysis *S| has the following components: -The SPEX library provides five data types for matrix entries: \verb|mpz_t|, -\verb|mpq_t|, \verb|mpfr_t|, \verb|int64_t| and \verb|double|. +\begin{itemize} +\item \verb|S->kind|: Indicating the kind of factorization either LU or Cholesky. Data type: \verb|SPEX_factorization_kind| -{\small -\begin{center} -\begin{tabular}{llp{4in}} -\hline -0 & \verb|SPEX_MPZ| & Matrix entries are in \verb|mpz_t| type: an integer - of arbitrary size. \\ -\hline -1 & \verb|SPEX_MPQ| & Matrix entries are in \verb|mpq_t| type: a rational - number with arbitrary-sized integer numerator and - denominator. \\ -\hline -2 & \verb|SPEX_MPFR| & Matrix entries are in \verb|mpfr_t| type: a - floating-point number of arbitrary precision. \\ -\hline -3 & \verb|SPEX_INT64| & Matrix entries are in \verb|int64_t| type. \\ -\hline -4 & \verb|SPEX_FP64| & Matrix entries are in \verb|double| type. \\ -\hline -\end{tabular} -\label{tab:SPEX_type} -\end{center} -} +\item \verb|S->P_perm|: Row permutation for Cholesky and LU factorization. Data type: \verb|int64_t*| -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_matrix| structure} -%------------------------------------------------------------------------------- +\item \verb|S->Pinv_perm|: Inverse row permutation for Cholesky and LU factorization. Data type: \verb|int64_t*| -A matrix \verb|SPEX_matrix *A| has the following components: +\item \verb|S->Q_perm|: Column permutation for LU factorization. This is always \verb|NULL| and ignored for Cholesky factorization since its row and column permutations are the same. Data type: \verb|int64_t*| -\begin{itemize} -\item \verb|A->m|: Number of rows in the matrix. Data Type: \verb|int64_t|. +\item \verb|S->Qinv_perm|: Inverse column permutation for LU factorization. This is always \verb|NULL| and ignored for Cholesky factorization since its inverse row and column permutations are the same. Data type: \verb|int64_t*| -\item \verb|A->n|: Number of columns in the matrix. Data Type: \verb|int64_t|. +\item \verb|S->lnz|: Approximate number of nonzeros in $L$. In LU factorization, this is a crude estimate based on either AMD or COLAMD. In Cholesky factorization, if AMD is used, this is the exact number of nonzeros in $L$. Data type: \verb|int64_t| -\item \verb|A->nz|: The number of nonzeros in the matrix $A$, if $A$ is -a triplet matrix (ignored for matrices in CSC or dense formats). Data Type: -\verb|int64_t|. +\item \verb|S->unz|: Approximate number of nonzeros in $U$. In LU factorization, this is a crude estimate based on either AMD or COLAMD. In Cholesky factorization this is not used. Data type: \verb|int64_t| -\item \verb|A->nzmax|: The allocated size of the vectors \verb|A->i|, -\verb|A->j| and \verb|A->x|. Note that \verb|A->nzmax| $\geq$ \verb|nnz(A)|, -where \verb|nnz(A)| is the return value of \verb|SPEX_matrix_nnz(A,option)|. -Data Type: \verb|int64_t|. +\item \verb|S->parent|: This is the elimination tree of the input matrix for Cholesky factorization. This is always \verb|NULL| for LU factorization. Data type: \verb|int64_t*| -\item \verb|A->kind|: Indicating the kind of matrix A: CSC, triplet or dense. -Data Type: \verb|SPEX_kind|. +\item \verb|S->cp|: Column pointers of L for Cholesky factorization. This is always \verb|NULL| for LU factorization. Data type: \verb|int64_t*| +\end{itemize} -\item \verb|A->type|: Indicating the type of entries in matrix A: \verb|mpz_t|, -\verb|mpq_t|, \verb|mpfr_t|, \verb|int64_t| or \verb|double|. -Data Type: \verb|SPEX_type|. +This data type is constructed when analysis is called in the appropriate factorizations. See sections \ref{ss:spex_lu_analyze} and \ref{ss:spex_chol_analyze} for further details. To free this data structure, the function \verb|SPEX_symbolic_analysis_free| is used and discussed further in section \ref{s:spex_symbolic_analysis_helper}. -\item \verb|A->p|: An array of size \verb|A->n|$+1$ which contains column pointers -of $A$, if $A$ is a CSC matrix (\verb|NULL| for matrices in triplet or dense -formats). Data Type: \verb|int64_t*|. -\item \verb|A->p_shallow|: A boolean indicating whether \verb|A->p| is shallow. -A {\em shallow} pointer is one that refers to a component of another matrix or -data structure. If \verb|A->p| is shallow, then it should not be modified -as part of the \verb|A| matrix, and it is not freed if \verb|A| is freed. -Data Type: \verb|bool|. +%------------------------------------------------------------------------------- +%\cprotect\section{The \verb|SPEX_factorization| data structure} +\section{The \texttt{SPEX\_factorization} data structure} +%------------------------------------------------------------------------------- +The \verb|SPEX_factorization| object holds an LU or Cholesky numerical factorization. \update{in either non-updatable or updatable form} The introduction of this structure is one of the largest API update for SPEX 2.0, as the components of all factorizations are now held in this structure instead of being carried around by the user. The components of the factorization structure are accessible to the user application. However, they should only be modified by calling SPEX methods. Changing them directly can lead to undefined behavior. -\item \verb|A->i|: An array of size \verb|A->nzmax| which contains the row -indices of the nonzeros in $A$, if $A$ is a CSC or triplet matrix (\verb|NULL| -for dense matrices). The matrix is zero-based, so row indices are -in the range of $[0,$ \verb|A->m|$-1]$. Data Type: \verb|int64_t*|. +The components of a \verb|SPEX_factorization* F| are as follows: -\item \verb|A->i_shallow|: A boolean indicating whether \verb|A->i| is shallow. -Data Type: \verb|bool|. +\begin{itemize} +\item \verb|F->kind|: Indicating the kind of factorization either LU or Cholesky. Data type: \verb|SPEX_factorization_kind| -\item \verb|A->j|: An array of size \verb|A->nzmax| which contains the column -indices of the nonzeros in $A$, if $A$ is a triplet matrix (\verb|NULL| for -matrices in CSC or dense formats). -The matrix is zero-based, so column indices are -in the range of $[0,$ \verb|A->n|$-1]$. Data Type: \verb|int64_t*|. +\item \verb|F->updatable|: a flag that indicates whether the factorization is in an updatable format. Reserved for future development. Data type: \verb|bool| -\item \verb|A->j_shallow|: A boolean indicating whether \verb|A->j| is shallow. -Data Type: \verb|bool|. +\item \verb|F->scale_for_A|: Scaling factor of the input matrix $A$. As discussed in section \ref{ss:SPEX_matrix}, all matrices in SPEX are integral, thus, if A must be scaled the scaling factor applied is stored here. Data type: \verb|mpq_t| -\item \verb|A->x|: An array of size \verb|A->nzmax| which contains the -numeric values of the matrix. This array is a union, and must be accessed via -one of: \verb|A->x.mpz|, \verb|A->x.mpq|, \verb|A->x.mpfr|, \verb|A->x.int64|, -or \verb|A->x.fp64|, depending on the \verb|A->type| parameter. -Data Type: \verb|union|. +\item \verb|F->L|: The lower triangular matrix for either LU or Cholesky factorization. Data type: \verb|SPEX_matrix*| -\item \verb|A->x_shallow|: A boolean indicating whether \verb|A->x| is -shallow. Data Type: \verb|bool|. +\item \verb|F->U|: The upper triangular matrix for LU factorization. This is always \verb|NULL| for Cholesky factorization. Data type: \verb|SPEX_matrix*| -\item \verb|A->scale|: A scaling parameter for matrix of \verb|mpz_t| type. For -all matrices whose entries are stored in data type other than \verb|mpz_t|, -\verb|A->scale = 1|. This is used to ensure that entry can be represented as an -integer in an \verb|mpz_t| matrix if these entries are converted from non-integer type -data (such as double, variable precision floating point, or rational). Data -Type: \verb|mpq_t|. +\item \verb|F->Q|: The matrix for (future) QR factorization. Provided here so that future versions of SPEX have backward compatibility. Data type: \verb|SPEX_matrix*| -\end{itemize} +\item \verb|F->R|: The right triangular matrix for (future) QR factorization. Provided here so that future versions of SPEX have backward compatibility. Data type: \verb|SPEX_matrix*| -Specifically, for different kinds of \verb|A| of size \verb|A->m| $\times$ \verb|A->n| -with \verb|nz| nonzero entries, its components are defined as: +\item \verb|F->rhos|: An $n \times 1$ dense matrix containing the pivot values used for LU or Cholesky factorization. Data type: \verb|SPEX_matrix*| -\begin{itemize} -\item - (0) \verb|SPEX_CSC|: A sparse matrix in CSC (compressed sparse column) format. - \verb|A->p| is an \verb|int64_t| array of size \verb|A->n|+1, \verb|A->i| - is an \verb|int64_t| array of size \verb|A->nzmax| (with $nz$ $\le$ - \verb|A->nzmax|), and \verb|A->x.TYPE| is an array of size - \verb|A->nzmax| of matrix entries (\verb'TYPE' is one of \verb|mpz|, - \verb|mpq|, \verb|mpfr|, \verb|int64|, or \verb|fp64|). The row indices - of column $j$ appear in \verb|A->i [A->p [j] ... A->p [j+1]-1]|, and the - values appear in the same locations in \verb|A->x.TYPE|. The \verb|A->j| - array is \verb|NULL|. \verb|A->nz| is ignored; the number of entries in - \verb|A| is given by \verb|A->p [A->n]|. - Row indices need not be sorted in each column, but duplicates cannot - appear. +\item \verb|F->P_perm|: Row permutation of the LU or Cholesky factors. Data type: \verb|int64_t*| -\item - (1) \verb|SPEX_TRIPLET|: A sparse matrix in triplet format. \verb|A->i| and - \verb|A->j| are both \verb|int64_t| arrays of size \verb|A->nzmax|, and - \verb|A->x.TYPE| is an array of values of the same size. The $k$th tuple - has row index \verb|A->i [k]|, column index \verb|A->j [k]| , and value - \verb|A->x.TYPE [k]|, with 0 $\le$ $k <$ \verb|A->nz|. - The \verb|A->p| array is \verb|NULL|. - Triplets can be unsorted, but duplicates cannot appear. +\item \verb|F->Pinv_perm|: Inverse row permutation of the LU or Cholesky factors. Data type: \verb|int64_t*| -\item - (2) \verb|SPEX_DENSE|: A dense matrix. The integer arrays \verb|A->p|, - \verb|A->i|, and \verb|A->j| are all \verb|NULL|. \verb|A->x.TYPE| is a - pointer to an array of size \verb|A->m|*\verb|A->n|, stored in - column-oriented format. The value of $A(i,j)$ is \verb|A->x.TYPE [p]| - with \verb|p| = $i + j*$\verb|A->m|. \verb|A->nz| is ignored; the number - of entries in \verb|A| is \verb|A->m| $\times$ \verb|A->n|. +\item \verb|F->Q_perm|: Column permutation of the LU factors. This is \verb|NULL| and ignored for Cholesky factorization. Data type: \verb|int64_t*| +\item \verb|F->Qinv_perm|: Inverse column permutation of the LU factors. This is \verb|NULL| and ignored for Cholesky factorization. Data type: \verb|int64_t*| \end{itemize} -\verb|A| may contain shallow components, \verb|A->p|, \verb|A->i|, \verb|A->j|, -and \verb|A->x|. For example, if \verb|A->p_shallow| is true, then a -non-\verb|NULL| \verb|A->p| is a pointer to a read-only array, and the -\verb|A->p| array is not freed by \verb|SPEX_matrix_free|. If \verb|A->p| is -\verb|NULL| (for a triplet or dense matrix), then \verb|A->p_shallow| has no -effect. +\update{ +As mentioned in the above description, one or more of these components could be \verb|NULL| for certain factorization. For example, \verb|F->U|, \verb|F->Q_perm| and \verb|F->Qinv_perm| are \verb|NULL| for Cholesky factorization. Moreover, \verb|F->Qinv_perm| can be \verb|NULL| for a non-updatable LU factorization with \verb|F->updatable=false|, but it will be generated when the LU factorization converted to the updatable form. -To simplify the access the entries in \verb|A|, SPEX package provides the -following macros (Note that the \verb|TYPE| parameter in the macros is one of: -\verb|mpz|, \verb|mpq|, \verb|mpfr|, \verb|int64| or \verb|fp64|): +Aside from that \verb|Qinv_perm| will be generated for the updatable LU factorization, +the only difference between non-updatable and updatable factorizations is +the way that $L$ (and $U$ if exists) is stored. Specifically, a updatable factorization must meet the following conditions. \begin{itemize} + \item Both \verb|F->L| and \verb|F->U| are \verb|SPEX_DYNAMIC_CSC| matrices. Notably, \verb|F->U| in the updatable + factorization is actually the transpose of $U$ (or equivalently, $U$ is stored + as compressed sparse row (CSR) form instead), since $U$ will be updated one row at a time. + + \item $A = LDU$, which means $L$ and $U$ are properly permuted. (Recall that + $PAQ = LDU$ or $PAP^T = LDL^T$ holds for static factorization). That is, for a + updatable factorization, the rows of $L$ are in the same order as the rows + of $A$, while the $j$-th column of $L$ (\verb|F->L->v[j]|) contains the $j$-th pivot, + which would be \verb|F->L->v[j]->x[0]|, (i.e., \verb|F->L->v[j]->i[0] == F->P_perm[j]|); the columns of $U$ (i.e., the rows of $U^T$) are in the same order + as the columns of $A$, while the $j$-th row of $U$ (i.e., the $j$-th column of $U^T$) + (\verb|F->U->v[j]|) contains the $j$-th pivot, which would be \verb|F->U->v[j]->x[0]|, + (i.e., \verb|F->U->v[j]->i[0] == F->Q_perm[j]|). +\end{itemize} -\item -\verb|SPEX_1D(A,k,TYPE)|: used to access the $k$th entry in - \verb|SPEX_matrix *A| using 1D linear addressing for - any matrix kind (CSC, triplet or dense), in any type - with \verb|TYPE| specified corresponding +Due to these non-trivial conditions, users cannot simply perform +\verb|SPEX_matrix_copy| to obtain \verb|F->L| and/or \verb|F->U| in \verb|SPEX_DYNAMIC_CSC SPEX_MPZ| format and +claim that it is updatable, and vice versa. To correctly convert the +factorization, user should call \verb|SPEX_factorization_convert| to perform in-place conversion for a +given \verb|F| to either updatable or non-updatable as specified. +} -\item -\verb|SPEX_2D(A,i,j,TYPE)|: used to access the $(i,j)$th entry in a dense - \verb|SPEX_matrix *A|. +A \verb|SPEX_factorization| is constructed by the appropriate factorizations (see sections \ref{ss:spex_left_lu_factorize} and \ref{ss:spex_chol_factorize} for further details). To free this data structure, the function \verb|SPEX_factorization_free| is used and discussed further in section \ref{ss:spex_factorization_free}.\update{, and updated by appropriate \verb|SPEX_Update_*| functions (see sections \ref{ss:SPEX_Update_Chol_Rank1} and \ref{ss:SPEX_Update_LU_ColRep} for further details). In addition, the SPEX package has a set of functions to convert, query and +destroy a SPEX factorization, \verb|SPEX_factorization|, as shown in the following table.} +\update{ +\begin{SizedCenteredTabular}{lp{2.5in}l} \hline + Function Name & Description & Section \\ \hline + \verb|SPEX_factorization_check| + & check the validity of a factorization and print it + & \ref{ss:spex_factorization_check} \\ \hline + \verb|SPEX_factorization_convert| + & convert a factorization to non-/updatable as specified + & \ref{ss:spex_factorization_convert} \\ \hline + \verb|SPEX_factorization_free| + & destroy a \verb|SPEX_factorization| and free its allocated memory + & \ref{ss:spex_factorization_free} \\ \hline +\end{SizedCenteredTabular} +} + +\update{It should be noted that all solvers (except +\verb|SPEX_Update_(t)solve|) and functions that create factorization return +non-updatable factorization with \verb|F->L| (and \verb|F->U| if exists) in \verb|SPEX_CSC SPEX_MPZ| form. On the other hand, all \verb|SPEX_Update_*| functions require and output updatable factorization with \verb|F->L| +(and \verb|F->U| if exists) in \verb|SPEX_DYNAMIC_CSC SPEX_MPZ| form. These \verb|SPEX_Update_*| functions check the input factorization, convert it (if not updatable) automatically, and output updatable factorization.} -\end{itemize} -The SPEX package has a set of functions to allocate, copy(convert), query and -destroy a SPEX matrix, \verb|SPEX_matrix|, as shown in the following table. -%---------------------------------------- -{\small -\begin{center} -\begin{tabular}{lp{2.5in}l} -\hline -function name & description & section \\ -\hline -\verb|SPEX_matrix_allocate| - & allocate a $m$-by-$n$ \verb|SPEX_matrix| - & \ref{s:user:matrix_allocate} \\ -\hline -\verb|SPEX_matrix_free| - & destroy a \verb|SPEX_matrix| and free its allocated memory - & \ref{s:user:matrix_free} \\ -\hline -\verb|SPEX_matrix_copy| - & make a copy of a matrix, into another kind and/or type - & \ref{s:user:matrix_copy} \\ -\hline -\verb|SPEX_matrix_nnz| - & get the number of entries in a matrix - & \ref{s:user:matrix_nnz} \\ -\hline -\end{tabular} -\end{center} -} %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_matrix_allocate|: allocate an $m$-by-$n$ -\verb|SPEX_matrix|} -\label{s:user:matrix_allocate} +\chapter{SPEX Utilities}\vspace{-0.75in} \label{ch:Util} +%------------------------------------------------------------------------------- + +%------------------------------------------------------------------------------- +\section{Overview} \label{s:util:overview} +%------------------------------------------------------------------------------- +SPEX Util contains utility and auxiliary functions for the SPEX +factorizations. Additionally, SPEX Util provides a wrapper class for +the GNU Multiple Precision Arithmetic (GMP) \cite{granlund2015gnu} and GNU +Multiple Precision Floating Point Reliable (MPFR) \cite{fousse2007mpfr} +libraries that prevent memory leaks and improve the overall stability of +these external libraries. SPEX Util is written in ANSI C. + + +%------------------------------------------------------------------------------- +\section{Managing the SPEX environment} \label{s:user:setup} %------------------------------------------------------------------------------- +Either \verb|SPEX_initialize| or \verb|SPEX_initialize_expert| (but not both) +must be called prior to using any other SPEX functions. Otherwise, all SPEX user-callable functions would return \verb|SPEX_PANIC|. \verb|SPEX_finalize| +must be called as the last SPEX function. +Note that if a user is working in a multi threaded environment then only one user thread should call the \verb|SPEX_initialize| and \verb|SPEX_finalize| functions. + +Subsequent SPEX sessions can be restarted after a call to +\verb|SPEX_finalize|, by calling either \verb|SPEX_initialize| or +\verb|SPEX_initialize_expert| (but not both), followed by a final call to +\verb|SPEX_finalize| when finished. -\begin{mdframed}[userdefinedwidth=6in] + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_initialize|: initialize the working environment} +\subsection{\texttt{SPEX\_initialize}: initialize the working environment} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_matrix_allocate + SPEX_info SPEX_initialize ( - SPEX_matrix **A_handle, // matrix to allocate - SPEX_kind kind, // CSC, triplet, or dense - SPEX_type type, // mpz, mpq, mpfr, int64, or double (fp64) - int64_t m, // # of rows - int64_t n, // # of columns - int64_t nzmax, // max # of entries - bool shallow, // if true, matrix is shallow. A->p, A->i, - // A->j, A->x are all returned as NULL and must - // be set by the caller. All A->*_shallow are - // returned as true. - bool init, // If true, and the data types are mpz, mpq, or - // mpfr, the entries are initialized (using the - // appropriate SPEX_mp*_init function). If - // false, the mpz, mpq, and mpfr arrays are - // allocated but not initialized. - const SPEX_options *option + void ) ; \end{verbatim} } \end{mdframed} -\verb|SPEX_matrix_allocate| allocates memory space for a $m$-by-$n$ -\verb|SPEX_matrix| whose kind (CSC, triplet or dense) and data type -(\verb|mpz|, \verb|mpq|, \verb|mpfr|, \verb|int64| or \verb|fp64|) is -specified. If \verb|shallow| is true, all components (\verb|A->p|, \verb|A->i|, -\verb|A->j|, \verb|A->x|) are returned as \verb|NULL|, and their shallow flags -are all true. The pointers \verb|A->p|, \verb|A->i|, \verb|A->j|, -and/or \verb|A->x| can then be assigned from arrays in the calling application. - -If \verb|shallow| is false, the appropriate individual arrays are allocated -(via \verb|SPEX_calloc|). The second boolean parameter is used if the entries -are \verb|mpz_t|, \verb|mpq_t|, or \verb|mpfr_t|. Specifically, if \verb|init| -is true, the individual entries within \verb|A->x.TYPE| are initialized using -the appropriate \verb|SPEX_mp*_init|) function. Otherwise, if \verb|init| is -false, the \verb|A->x.TYPE| array is allocated (via \verb|SPEX_calloc|) and -left that way. They are not otherwise initialized, and attempting to access -the values of these uninitialized entries will lead to undefined behavior. -Returns \verb|SPEX_PANIC| if SPEX has not been initialized. +\verb|SPEX_initialize| initializes the working environment for SPEX +functions. SPEX utilizes a specialized memory management scheme in order to +prevent potential memory failures caused by GMP and MPFR libraries. Either +this function or \verb|SPEX_initialize_expert| must be called prior to using +any other function in the library. Returns \verb|SPEX_PANIC| if SPEX has +already been initialized, or \verb|SPEX_OK| if successful. + %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_matrix_free|: free a \verb|SPEX_matrix|} -\label{s:user:matrix_free} +%\cprotect\subsection{\verb|SPEX_initialize_expert|: initialize environment (expert version)}\label{ss:SPEX_initialize_expert} +\subsection{\texttt{SPEX\_initialize\_expert}: initialize environment (expert version)} \label{ss:SPEX_initialize_expert} %------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_matrix_free + SPEX_info SPEX_initialize_expert ( - SPEX_matrix **A_handle, // matrix to free - const SPEX_options *option + void* (*MyMalloc) (size_t), // user-defined malloc + void* (*MyCalloc) (size_t, size_t), // user-defined calloc + void* (*MyRealloc) (void *, size_t), // user-defined realloc + void (*MyFree) (void *) // user-defined free ) ; \end{verbatim} } \end{mdframed} -\verb|SPEX_matrix_free| frees the \verb|SPEX_matrix *A|. Note that the input -of the function is the pointer to the pointer of a \verb|SPEX_matrix| -structure. This is because this function internally sets the pointer of a -\verb|SPEX_matrix| to be \verb|NULL| to prevent potential segmentation fault -that could be caused by double \verb|free|. If default settings are desired, -\verb|option| can be input as \verb|NULL|. - -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_matrix_copy|: make a copy of a \verb|SPEX_matrix| with a potentially different matrix-format and data-type} -\label{s:user:matrix_copy} -%------------------------------------------------------------------------------- +\verb|SPEX_initialize_expert| is the same as \verb|SPEX_initialize| except that +it allows for a redefinition of custom memory functions that are used for SPEX +and GMP/ MPFR. The four inputs to this function are pointers to four +functions with the same signatures as the ANSI C \verb'malloc', \verb'calloc', +\verb'realloc', and \verb'free' functions. That is: -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_matrix_copy - ( - SPEX_matrix **C, // matrix to create (never shallow) - // inputs, not modified: - SPEX_kind kind, // CSC, triplet, or dense - SPEX_type type, // mpz_t, mpq_t, mpfr_t, int64_t, or fp64 - SPEX_matrix *A, // matrix to make a copy of (may be shallow) - const SPEX_options *option - ) ; + #include + void *malloc (size_t size) ; + void *calloc (size_t nmemb, size_t size) ; + void *realloc (void *ptr, size_t size) ; + void free (void *ptr) ; \end{verbatim} } \end{mdframed} -\verb|SPEX_matrix_copy| creates a \verb|SPEX_matrix *C| which is a modified -copy of a \verb|SPEX_matrix *A|. This function can convert between any pair of -the 15 kinds of matrices, so the new matrix \verb|C| can be of any type or kind -different than \verb|A|. On input \verb|C| must be non-\verb|NULL|, and the -value of \verb|*C| is ignored; it is overwritten, output with the matrix -\verb|C|, which is a copy of \verb|A| of kind \verb|kind| and type \verb|type|. +Returns \verb|SPEX_PANIC| if SPEX has already been initialized, +or \verb|SPEX_OK| if successful. -The input matrix is assumed to be valid. It can be checked first with -\verb|SPEX_matrix_check| (Section \ref{s:user:matrix_check}), if desired. -Results are undefined for an invalid input matrix \verb|A|. Returns -\verb|SPEX_PANIC| if SPEX has not been initialized. %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_matrix_nnz|: get the number of entries in a -\verb|SPEX_matrix|} -\label{s:user:matrix_nnz} +%\cprotect\subsection{\verb|SPEX_finalize|: free the working environment} +\subsection{\texttt{SPEX\_finalize}: free the working environment} \label{ss:SPEX_finalize} %------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_matrix_nnz // return # of entries in A, or -1 on error + SPEX_info SPEX_finalize ( - int64_t *nnz, - const SPEX_matrix *A, // matrix to query - const SPEX_options *option + void ) ; \end{verbatim} } \end{mdframed} -\verb|SPEX_matrix_nnz| returns an integer, \verb|nnz|, which is equal to the number of entries in a \verb|SPEX_matrix *A|. -For details regarding how the number of entries is obtained for different kinds -of matrices, refer to Section \ref{ss:SPEX_matrix}. -For any matrix with invalid dimension(s), nnz is returned as -1. -If default settings are desired, \verb|option| can be input as \verb|NULL|. -Returns \verb|SPEX_PANIC| if the SPEX working environment has not been initialized (e.g. via \verb|SPEX_initialize|). +\verb|SPEX_finalize| finalizes the working environment for SPEX +library, and frees any internal workspace created by SPEX. It must be +called as the last \verb|SPEX_*| function called, except that a subsequent +call to \verb|SPEX_initialize*| may be used to start another SPEX session. +Returns \verb|SPEX_PANIC| if SPEX has not been initialized, +or \verb|SPEX_OK| if successful. -%------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_matrix_check|: check and optionally print a \verb|SPEX_matrix|} -\label{s:user:matrix_check} -%------------------------------------------------------------------------------- +\subsection{\texttt{SPEX\_thread\_initialize}: initialize working environment for a single thread} -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_matrix_check // returns a SPEX status code - ( - const SPEX_matrix *A, // matrix to check - const SPEX_options* option // defines the print level - ) ; + SPEX_info SPEX_thread_initialize + ( + void + ); \end{verbatim} } \end{mdframed} -\verb|SPEX_matrix_check| checks the validity of a \verb|SPEX_matrix *A| in any -of the 15 different matrix types (CSC, triplet, dense) $\times$ (\verb|mpz|, -\verb|mpq|, \verb|mpfr|, \verb|int64|, \verb|fp64|). The print level can be -changed via \verb|option->print_level| (refer to Section \ref{ss:SPEX_options} -for more details). If default settings are desired, \verb|option| can be input -as \verb|NULL|. Returns \verb|SPEX_PANIC| if SPEX has not been initialized. +\verb|SPEX_thread_initialize| initializes the working environment of SPEX for a single +user thread. If the user is working in a multithreaded environment, they must call +this function at the beginning of each user thread. Returns \verb|SPEX_OK| if successful +or \verb|SPEX_PANIC| if SPEX was already initialized. + +This function is only required for a multithreaded user application that +calls SPEX functions from threads other than the primary thread that +called \verb'SPEX_initialize'. + +When the primary thread of the user application starts, it must call +\verb'SPEX_initialize'. When the user application enters a parallel +region (say with OpenMP) or creates its own threads with a threading library, +each user thread must call \verb'SPEX_thread_initialize' when it starts, +and \verb'SPEX_thread_finalize' when it finishes. + +An example usage can be found in the \verb'SPEX/Demo' folder in the +\verb'spex_demo_threaded.c' main program. + +\subsection{\texttt{SPEX\_thread\_finalize}: finalize the working environment for a single thread} + +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_thread_finalize + ( + void + ); +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_thread_finalize| finalizes the working environment and frees any +internal workspace created by SPEX for a single user thread. If the user is working +in a multithreaded environment, they must call this function at the end of each +user thread. Returns \verb|SPEX_OK| if successful or \verb|SPEX_PANIC| if SPEX was not +initialized. %------------------------------------------------------------------------------- -\newpage -\cprotect\subsection{\verb|SPEX_matrix_div|: Divide dense matrix by scalar} +\section{Memory Management} \label{s:user:memmanag} %------------------------------------------------------------------------------- +The routines in this section are used to allocate and free memory for the data +structures used in SPEX. By default, SPEX relies on the SuiteSparse +memory management functions, \verb|SuiteSparse_malloc|, +\verb|SuiteSparse_calloc|, \verb|SuiteSparse_realloc|, and +\verb|SuiteSparse_free|. By default, those functions rely on the ANSI C +\verb|malloc|, \verb|calloc|, \verb|realloc|, and \verb|free|, but this may be +changed by initializing the SPEX environment with +\verb|SPEX_initialize_expert|. + -\begin{mdframed}[userdefinedwidth=6in] +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_calloc|: allocate initialized memory} +\subsection{\texttt{SPEX\_calloc}: allocate initialized memory} \label{ss:SPEX_calloc} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} -SPEX_info SPEX_matrix_div // divides the x matrix by a scalar -( - SPEX_matrix **x2_handle, // x2 = x/scalar - SPEX_matrix* x, // input vector x - const mpz_t scalar, // the scalar - const SPEX_options *option -); + void *SPEX_calloc + ( + size_t nitems, // number of items to allocate + size_t size // size of each item + ) ; \end{verbatim} } \end{mdframed} -This function divides the matrix \verb|x| by the scalar \verb|scalar|. On input, \verb|x2_handle| is NULL and \verb|x| must be \verb|SPEX_DENSE| of \verb|SPEX_MPZ| type. On success, \verb|x2_handle| is returned as \verb|SPEX_DENSE| with \verb|SPEX_MPQ| entries each of which is equal to \verb|x / scalar|. +\verb|SPEX_calloc| allocates a block of memory for an array of \verb|nitems| +elements, each of them \verb|size| bytes long, and initializes all its bits to +zero. If any input is less than 1, it is treated as if equal to 1. If the +function failed to allocate the requested block of memory, then a \verb|NULL| +pointer is returned. +Returns \verb|NULL| if SPEX has not been initialized. + %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_matrix_mul|: Multiply dense matrix by scalar} +\newpage +%\cprotect\subsection{\verb|SPEX_malloc|: allocate uninitialized memory} +\subsection{\texttt{SPEX\_malloc}: allocate uninitialized memory} \label{ss:SPEX_malloc} %------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} -SPEX_matrix_mul // multiplies x by a scalar -( - SPEX_matrix *x, // matrix to be multiplied - const mpz_t scalar // scalar to multiply by -); + void *SPEX_malloc + ( + size_t size // size of memory space to allocate + ) ; \end{verbatim} } \end{mdframed} -This function divides the matrix \verb|x| by the scalar \verb|scalar|. On input, \verb|x| must be \verb|SPEX_DENSE| of \verb|SPEX_MPZ| type. On success, \verb|x| is overwritten by \verb|x * scalar|. +\verb|SPEX_malloc| allocates a block of \verb|size| bytes of memory, returning +a pointer to the beginning of the block. The content of the newly allocated +block of memory is not initialized, remaining with indeterminate values. +If \verb|size| is less than 1, it is treated as if equal to 1. If the function +fails to allocate the requested block of memory, then a \verb|NULL| pointer is +returned. +Returns \verb|NULL| if SPEX has not been initialized. %------------------------------------------------------------------------------- -\cprotect\section{\verb|SPEX_LU_analysis| structure} -\label{ss:SPEX_LU_analysis} +%\cprotect\subsection{\verb|SPEX_realloc|: resize allocated memory} +\subsection{\texttt{SPEX\_realloc}: resize allocated memory} \label{ss:SPEX_realloc} %------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + void *SPEX_realloc // pointer to reallocated block, or original block + // if the realloc failed + ( + int64_t nitems_new, // new number of items + int64_t nitems_old, // previous/old number of items + size_t size_of_item, // size of each item + void *p, // pointer to reallocate + bool *ok // true if success, false on failure + ) ; +\end{verbatim} +} \end{mdframed} -The \verb|SPEX_LU_analysis| data structure is used for storing the column -permutation for LU factorization and the estimate of the number of nonzeros -that may appear in $L$ and $U$. This need not be modified or accessed in the -user application; it simply needs to be passed in directly to the other -functions that take it as in input parameter. A \verb|SPEX_LU_analysis| -structure has the following components: +\verb|SPEX_realloc| is a wrapper for realloc. If \verb|p| is non-\verb|NULL| on +input, it points to a previously allocated array of size \verb|nitems_old| +$\times$ \verb|size_of_item|. The array is reallocated to be of size +\verb|nitems_new| $\times$ \verb|size_of_item|. If \verb|p| is \verb|NULL| on input, +then a new array of that size is allocated. On success, a pointer to the new +array is returned. Returns \verb|ok| as \verb|false| if SPEX has not been +initialized. -\begin{itemize} -\item \verb|S->q|: The column permutation stored as a dense \verb|int64_t| -vector of size $n+1$, where $n$ is the number of columns of the analyzed matrix. -Currently this vector is obtained via COLAMD, AMD, or is set to no ordering -(i.e., $[0, 1, \hdots, n-1]$). - -\item \verb|S->lnz|: An \verb|int64_t| which is an estimate of the number of -nonzeros in $L$. \verb|S->lnz| must be in the range of $[n, n^2]$. If -\verb|S->lnz| is too small, the program may waste time performing extra memory -reallocations. This is set during the symbolic analysis. - -\item \verb|S->unz|: An \verb|int64_t| which is an estimate of the number of -nonzeros in $U$. \verb|S->unz| must be in the range of $[n, n^2]$. If -\verb|S->unz| is too small, the program may waste time performing extra memory -reallocations. This is set during the symbolic analysis. -\end{itemize} +If the reallocation fails, \verb|p| is not modified, and \verb|ok| is returned +as \verb|false| to indicate that the reallocation failed. If the size +decreases or remains the same, then the method always succeeds (\verb|ok| is +returned as \verb|true|), unless SPEX has not been initialized. -The SPEX package provides the following functions to create and destroy a -\verb|SPEX_LU_analysis| structure: +Typical usage: the following code fragment allocates an array of 10 +\verb|int|'s, and then increases the size of the array to 20 \verb|int|'s. If +the \verb|SPEX_malloc| succeeds but the \verb|SPEX_realloc| fails, then the +array remains unmodified, of size 10. + +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + int *p ; + p = SPEX_malloc (10 * sizeof (int)) ; + if (p == NULL) { error here ... } + printf ("p points to an array of size 10 * sizeof (int)\n") ; + bool ok ; + p = SPEX_realloc (20, 10, sizeof (int), p, &ok) ; + if (ok) printf ("p has size 20 * sizeof (int)\n") ; + else printf ("realloc failed; p still has size 10 * sizeof (int)\n") ; + SPEX_free (p) ; +\end{verbatim} +} \end{mdframed} -%---------------------------------------- -{\small -\begin{center} -\begin{tabular}{lll} -\hline -function/macro name & description & section \\ -\hline -\verb|SPEX_LU_analyze| - & create \verb|SPEX_LU_analysis| structure - & \ref{s:SPEX_LU_analyze} \\ -\hline -\verb|SPEX_LU_analysis_free| - & destroy \verb|SPEX_LU_analysis| structure - & \ref{ss:LU_analysis_free} \\ -\hline -\end{tabular} -\end{center} -} %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_LU_analyze|: perform symbolic analysis} -\label{s:SPEX_LU_analyze} +%\cprotect\subsection{\verb|SPEX_free|: free allocated memory} +\newpage +\subsection{\texttt{SPEX\_free}: free allocated memory} \label{ss:SPEX_free} %------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_LU_analyze + void SPEX_free ( - SPEX_LU_analysis **S, // symbolic analysis (column permutation - // and nnz L,U) - const SPEX_matrix *A, // Input matrix - const SPEX_options *option // Control parameters + void *p // Pointer to memory space to free ) ; \end{verbatim} } \end{mdframed} -\verb|SPEX_LU_analyze| performs the symbolic ordering for any LU factorzation in SPEX package. Currently, -there are three options: no ordering, COLAMD, or AMD, which are passed in by -\verb|SPEX_options| \verb|*option|. For more details, refer to -Section \ref{ss:SPEX_options}. +\verb|SPEX_free| frees the memory previously allocated by a call to +\verb|SPEX_calloc|, \verb|SPEX_malloc|, or \verb|SPEX_realloc|. If \verb|p| is +\verb|NULL| on input, then no action is taken (this is not an error condition). +To guard against freeing the same memory space twice, the following macro +\verb|SPEX_FREE| is provided, which calls \verb|SPEX_free| and then sets the +freed pointer to \verb|NULL|. + +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + #define SPEX_FREE(p) \ + { \ + SPEX_free (p) ; \ + (p) = NULL ; \ + } +\end{verbatim} +} \end{mdframed} -The \verb|SPEX_LU_analysis *S| is created by calling -\verb|SPEX_LU_analyze(&S, A, option)| with \verb|SPEX_matrix *A| properly -initialized as CSC matrix and \verb|option| be \verb|NULL| if default ordering -(COLAMD) is desired. The value of \verb|S| is ignored on input. On output, -\verb|S| is a pointer to the newly created symbolic analysis structure and -\verb|SPEX_OK| is returned upon successful completion, or \verb|S = NULL| with -error status returned if a failure occurred. Returns \verb|SPEX_PANIC| if SPEX -has not been initialized. +No action is taken if SPEX has not been initialized. -The analysis \verb|S| is freed by \verb|SPEX_LU_analysis_free|. %------------------------------------------------------------------------------- -\newpage -\cprotect\subsection{\verb|SPEX_LU_analysis_free|: free \verb|SPEX_LU_analysis| structure} -\label{ss:LU_analysis_free} +%\cprotect\section{\verb|SPEX_options| helper functions} \label{ss:SPEX_options} +\section{\texttt{SPEX\_options} helper function} \label{ss:SPEX_options} %------------------------------------------------------------------------------- +The \verb|SPEX_options| structure contains numerous parameters that may be +modified to change the behavior of the SPEX functions. Default values of +these parameters will lead to good performance in most cases. The following helper functions +are provided. -\begin{mdframed}[userdefinedwidth=6in] + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_create_default_options|: create default \verb|SPEX_options| structure} +\subsection{\texttt{SPEX\_create\_default\_options}: create default \texttt{SPEX\_options} structure} +\label{ss:create_default_options} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_LU_analysis_free + SPEX_options* SPEX_create_default_options ( - SPEX_LU_analysis **S, // Structure to be deleted - const SPEX_options *option + void ) ; \end{verbatim} } \end{mdframed} +\verb|SPEX_create_default_options| creates and returns a pointer to a +\verb|SPEX_options| struct with default parameters upon successful allocation, +which are discussed in Section \ref{ss:SPEX_options_struct}. To safely free +the \verb|SPEX_options* option| structure, simply use \newline \verb|SPEX_FREE(option)|. +All functions that require \verb|SPEX_options *option| as an input argument can +have a \verb'NULL' pointer passed instead. In this case, the default value of +the corresponding command option is used. -\verb|SPEX_LU_analysis_free| frees a \verb|SPEX_LU_analysis| structure. -Note that the input of the function is the pointer to the pointer of a -\verb|SPEX_LU_analysis| structure. This is because this function internally -sets the pointer of a \verb|SPEX_LU_analysis| to be \verb|NULL| to prevent -potential segmentation fault that could be caused by double \verb|free|. -If default settings are desired, \verb|option| can be input as \verb|NULL|. -Returns \verb|SPEX_PANIC| if SPEX has not been initialized. +\update{ +%-------------------------------------------------------------------------------%\cprotect\section{\verb|SPEX_vector| helper functions} \label{s:spex_vector_helper} +\section{\texttt{SPEX\_vector} helper functions} \label{s:spex_vector_helper} +%------------------------------------------------------------------------------- %------------------------------------------------------------------------------- -\section{SPEX wrapper functions for GMP and MPFR} +%\cprotect\subsection{\verb|SPEX_vector_allocate|: Allocate a spex vector} \label{ss:spex_vector_allocate} +\subsection{\texttt{SPEX\_vector\_allocate}: Allocate a SPEX vector} \label{ss:spex_vector_allocate} %------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_vector_allocate + ( + SPEX_vector **v_handle, // vector to be allocated + const int64_t nzmax, // number of nnz entries in v + const SPEX_options *option + ); +\end{verbatim} +} \end{mdframed} -SPEX provides a wrapper class for all GMP and MPFR functions used by SPEX. -The wrapper class provides error-handling for out-of-memory conditions -that are not handled by the GMP and MPFR libraries. These wrapper functions -are used inside all SPEX functions, wherever any GMP or MPFR functions are -used. These functions may also be called by the end-user application. - -Each wrapped function has the same name as its corresponding GMP/MPFR function -with the added prefix \verb|SPEX_|. For example, the default GMP function -\verb|mpz_mul| is changed to \verb|SPEX_mpz_mul|. Each SPEX GMP/MPFR function -returns \verb|SPEX_OK| if successful or the correct error code if not. The -following table gives a brief list of each currently covered SPEX GMP/MPFR -function. For a detailed description of each function, refer to -\verb|SPEX/SPEX/SPEX_Util/Source/SPEX_gmp.c|. - -If additional GMP and MPFR functions are needed in the end-user application, -this wrapper mechanism can be extended to those functions. Below are -instructions on how to do this. +\verb|SPEX_vector_allocate| creates and initializes a \verb|SPEX_vector| of size \verb|nzmax|. On input, the \verb|SPEX_vector| \verb|*v| that \verb|v_handle| points to is \verb|NULL|. On output, \verb|SPEX_vector| \verb|*v| is allocated with \verb|v->nz|=0, \verb|v->nzmax|=\verb|nzmax|, \verb|v->scale|=1, \verb|v->i| being an \verb|int64_t| array of size \verb|nzmax| and \verb|v->x| being an array containing \verb|nzmax| initialized \verb|mpz_t| entries. -Given a GMP function \verb|void gmpfunc(TYPEa a, TYPEb b, ...)|, where -\verb|TYPEa| and \verb|TYPEb| can be GMP type data (\verb|mpz_t|, -\verb|mpq_t| and \verb|mpfr_t|, for example) or non-GMP type data (\verb|int|, -\verb|double|, for example), and they need not to be the same. -A wrapper for a new GMP or MPFR function can be created by following -this outline: -\newpage -\begin{mdframed}[userdefinedwidth=6in] +%-------------------------------------------------------------------------------%\cprotect\subsection{\verb|SPEX_vector_realloc|: Reallocate a spex vector} \label{ss:spex_vector_realloc} +\subsection{\texttt{SPEX\_vector\_realloc}: Reallocate a SPEX vector} \label{ss:spex_vector_realloc} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} -SPEX_info SPEX_gmpfunc -( - TYPEa a, - TYPEb b, - ... -) -{ - // Start the GMP Wrappter - // uncomment one of the following: - // If this function is not modifying any GMP/MPFR type variable, then use - //SPEX_GMP_WRAPPER_START; - // If this function is modifying mpz_t type (say TYPEa = mpz_t), then use - //SPEX_GMPZ_WRAPPER_START(a) ; - // If this function is modifying mpq_t type (say TYPEa = mpq_t), then use - //SPEX_GMPQ_WRAPPER_START(a) ; - // If this function is modifying mpfr_t type (say TYPEa = mpfr_t), then use - //SPEX_GMPFR_WRAPPER_START(a) ; - - // Call the GMP function - gmpfunc(a,b,...) ; - - //Finish the wrapper and return ok if successful. - SPEX_GMP_WRAPPER_FINISH; - return SPEX_OK; -} + SPEX_info SPEX_vector_realloc + ( + SPEX_vector* v, // the vector to be expanded + const int64_t new_size, // desired new size for v + const SPEX_options *option + ); \end{verbatim} } \end{mdframed} -Note that, other than \verb|SPEX_mpfr_fprintf|, \verb|SPEX_gmp_fprintf|, -\verb|SPEX_gmp_printf| and \verb|SPEX_gmp_fscanf|, all of the wrapped GMP/MPFR -functions always return \verb|SPEX_info| to the caller. Therefore, for some -GMP/MPFR functions that have their own return value. For example, for -\verb|int mpq_cmp(const mpq_t a, const mpq_t b)|, the return value becomes a -parameter of the wrapped function. In general, a GMP/MPFR function in the form -of \verb|TYPEr gmpfunc(TYPEa a, TYPEb b, ...)|, the wrapped -function can be constructed as follows: +\verb|SPEX_vector_realloc| either expands or shrinks the given \verb|SPEX_vector *v| of size \verb|v->nzmax| so that its new size is \verb|new_size|. If \verb|new_size > v->nzmax|, all newly allocated \verb|mpz_t| entries are initialized. -\begin{mdframed}[userdefinedwidth=6in] +%-------------------------------------------------------------------------------%\cprotect\subsection{\verb|SPEX_vector_free|: Free a spex vector} \label{ss:spex_vector_free} +\subsection{\texttt{SPEX\_vector\_free}: Free a SPEX vector} \label{ss:spex_vector_free} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} -SPEX_info SPEX_gmpfunc -( - TYPEr *r, // return value of the GMP/MPFR function - TYPEa a, - TYPEb b, - ... -) -{ - // Start the GMP Wrappter - //SPEX_GMP_WRAPPER_START; - - // Call the GMP function - *r = gmpfunc(a,b,...) ; - - //Finish the wrapper and return ok if successful. - SPEX_GMP_WRAPPER_FINISH; - return SPEX_OK; -} + SPEX_info SPEX_vector_free + ( + SPEX_vector **v_handle, // vector to be deleted + const SPEX_options *option + ); \end{verbatim} } \end{mdframed} -% \newpage -\thispagestyle{empty} -{\scriptsize -\begin{center} -\begin{tabular}{|l|l|l|} -\hline -%---------------------------------------- -{\bf MPFR Function} & \verb|SPEX_MPFR| {\bf Function} & {\bf Description} \\ -%---------------------------------------- -\hline\hline -\verb|n = mpfr_asprintf(&buff, fmt, ...)| - & \verb|n = SPEX_mpfr_asprintf(&buff, fmt, ...)| - & Print format to allocated string \\ \hline -\verb|mpfr_free_str(buff)| - & \verb|SPEX_mpfr_free_str(buff)| - & Free string allocated by MPFR \\ \hline -\verb|mpfr_init2(x, size)| - & \verb|SPEX_mpfr_init2(x, size)| - & Initialize x with size bits \\ \hline -\verb|mpfr_set(x, y, rnd)| +\verb|SPEX_vector_free| frees the \verb|SPEX_vector *v| that \verb|v_handle| points to. On output, the memory associated with \verb|v| is freed and \verb|v| is set to \verb|NULL|. +} + +%-------------------------------------------------------------------------------%\cprotect\section{\verb|SPEX_matrix| helper functions} \label{s:spex_matrix_functions} +\newpage +\section{\texttt{SPEX\_matrix} helper functions} \label{s:spex_matrix_functions} +%------------------------------------------------------------------------------- +These functions provide several utilities for a \verb|SPEX_matrix|. + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_matrix_allocate|: allocate an $m$-by-$n$ \verb|SPEX_matrix|} +\subsection{\texttt{SPEX\_matrix\_allocate}: allocate an m-by-n \texttt{SPEX\_matrix}} +\label{s:user:matrix_allocate} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_matrix_allocate + ( + SPEX_matrix **A_handle, // matrix to allocate + SPEX_kind kind, // CSC, triplet, dense or SPEX_DYNAMIC_CSC + SPEX_type type, // mpz, mpq, mpfr, int64, or double + int64_t m, // # of rows + int64_t n, // # of columns + int64_t nzmax, // max # of entries + bool shallow, // if true, matrix is shallow. A->p, A->i, A->j, + // A->x are all returned as NULL and must be set + // by the caller. All A->*_shallow are returned + // as true. Ignored for SPEX_DYNAMIC_CSC + // kind matrix. + bool init, // If true, and the data types are mpz, mpq, or + // mpfr, the entries of A->x are initialized + // (using the proper SPEX_mp*_init function). + // If false, the mpz, mpq, and mpfr arrays are + // allocated but not initialized. Meaningless + // for data types FP64 or INT64. Ignored if kind + // is SPEX_DYNAMIC_CSC or shallow is true. + const SPEX_options *option + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_matrix_allocate| allocates memory space for a $m$-by-$n$ +\verb|SPEX_matrix| whose kind (CSC, triplet, dense, or dynamic CSC) and data type +(\verb|mpz|, \verb|mpq|, \verb|mpfr|, \verb|int64| or \verb|fp64|) is +specified. On input, the SPEX matrix that \verb|A_handle| points to is \verb|NULL|. +On output, \verb|A_handle| points to a SPEX matrix of specified type, kind and size. +%Returns SPEX_PANIC if SPEX has not been initialized. + +For a CSC, triplet or dense matrix, if \verb|shallow| is true, all components (\verb|A->p|, \verb|A->i|, +\verb|A->j|, \verb|A->x|) are returned as \verb|NULL|, and their shallow flags +are all true. The pointers \verb|A->p|, \verb|A->i|, \verb|A->j|, +and/or \verb|A->x| can then be assigned from arrays in the calling application. +If \verb|shallow| is false, the appropriate individual arrays are allocated +(via \verb|SPEX_calloc|). The second boolean parameter \verb|init| is used if the entries +are \verb|mpz_t|, \verb|mpq_t|, or \verb|mpfr_t|. Specifically, if \verb|init| +is true, the individual entries within \verb|A->x.TYPE| are initialized using +the appropriate \verb|SPEX_mp*_init| function. Otherwise, if \verb|init| is +false, the \verb|A->x.TYPE| array is allocated (via \verb|SPEX_calloc|) and +left that way. They are not otherwise initialized, and attempting to access +the values of these uninitialized entries will lead to undefined behavior. + +For a \verb|SPEX_DYNAMIC_CSC| matrix, \verb|type|, \verb|shallow| and \verb|init| are ignored (since it only allows \verb|mpz_t| entries). Moreover, each column of the returned \verb|SPEX_DYNAMIC_CSC| matrix will be +allocated as \verb|SPEX_vector| with zero available entry. Additional reallocation +for each column will be needed. + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_matrix_free|: free a \verb|SPEX_matrix|} +\newpage +\subsection{\texttt{SPEX\_matrix\_free}: free a \texttt{SPEX\_matrix}} \label{s:user:matrix_free} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_matrix_free + ( + SPEX_matrix **A_handle, // matrix to free + const SPEX_options *option + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_matrix_free| frees the \verb|SPEX_matrix *A|. Note that the input +of the function is the pointer to the pointer of a \verb|SPEX_matrix| +structure. This is because this function internally sets the pointer of a +\verb|SPEX_matrix| to be \verb|NULL| to prevent potential segmentation fault +that could be caused by double \verb|free|. +%If default settings are desired, +%\verb|option| can be input as \verb|NULL|. + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_matrix_copy|: make a copy of a \verb|SPEX_matrix| with a potentially different matrix-format and data-type} +\subsection{\texttt{SPEX\_matrix\_copy}: make a copy of a \texttt{SPEX\_matrix} with a potentially different matrix-format and data-type} \label{s:user:matrix_copy} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_matrix_copy + ( + SPEX_matrix **C_handle, // matrix to create (never shallow) + // inputs, not modified: + SPEX_kind C_kind, // C->kind: CSC, triplet, dense, or dynamic + SPEX_type C_type, // C->type: mpz_t, mpq_t, mpfr_t, int64_t, or double + const SPEX_matrix *A, // matrix to make a copy of (may be shallow) + const SPEX_options *option + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_matrix_copy| makes a deep copy of a \verb|SPEX_matrix *A| as a new \verb|SPEX_matrix *C|, which can be any of the 16 matrix formats discussed in Section \ref{ss:SPEX_matrix}. That is, the new matrix \verb|C| can be exactly the same as \verb|A| or any other type or kind +different than \verb|A|. On input, the SPEX matrix that \verb|C_handle| points to must be \verb|NULL| and will be ignored, and \verb|A| is a valid matrix that can be potentially shallow. On output, \verb|C_handle| points to the matrix +\verb|C|, which is a copy of \verb|A| of kind \verb|kind| and type \verb|type|. + + +Results are undefined for an invalid input matrix \verb|A|. Though all matrices generated from any SPEX user-callable functions are valid, they could become invalid when user directly modifies their component(s). To check the validity of the input matrix, call +\verb|SPEX_matrix_check| (Section \ref{s:user:matrix_check}). + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_matrix_nnz|: get the number of entries in a \verb|SPEX_matrix|} +\subsection{\texttt{SPEX\_matrix\_nnz}: get the number of entries in a \texttt{SPEX\_matrix}} +\label{s:user:matrix_nnz} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_matrix_nnz // return # of entries in A, or -1 on error + ( + int64_t *nnz, + const SPEX_matrix *A, // matrix to query + const SPEX_options *option + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_matrix_nnz| returns an integer, \verb|nnz|, which is equal to the number of entries in a \verb|SPEX_matrix *A|. +For details regarding how the number of entries is obtained for different kinds +of matrices, refer to Section \ref{ss:SPEX_matrix}. +For any matrix with invalid dimension(s), nnz is returned as -1. +%If default settings are desired, \verb|option| can be input as \verb|NULL|. +%Returns \verb|SPEX_PANIC| if the SPEX working environment has not been initialized (e.g. via %\verb|SPEX_initialize|). + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_matrix_check|: check and optionally print a \verb|SPEX_matrix|} +\subsection{\texttt{SPEX\_matrix\_check}: check and optionally print a \texttt{SPEX\_matrix}} \label{s:user:matrix_check} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_matrix_check // returns a SPEX status code + ( + const SPEX_matrix *A, // matrix to check + const SPEX_options* option // defines the print level + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_matrix_check| checks the validity of a \verb|SPEX_matrix *A| in any +of the 16 matrix formats discussed in Section \ref{ss:SPEX_matrix}. +%the 15 different matrix types (CSC, triplet, dense) $\times$ (\verb|mpz|, +%\verb|mpq|, \verb|mpfr|, \verb|int64|, \verb|fp64|). +In addition, it prints the matrix and any error found with proper print level specified by +\verb|option->print_level|. Specifically, \verb|SPEX_matrix_check| prints nothing for \verb|print_level|=0 (default); or just errors for \verb|print_level|=1; or errors and terse output of the matrix for \verb|print_level|=2; or errors and detailed output of the matrix for \verb|print_level|=3. +%(refer to Section \ref{ss:SPEX_options} for more details). +As mentioned, if default settings are desired, \verb|option| can be input as \verb|NULL|. +% Returns \verb|SPEX_PANIC| if SPEX has not been initialized. + + +%-------------------------------------------------------------------------------%\cprotect\section{\verb|SPEX_symbolic_analysis| helper functions} \label{s:spex_symbolic_analysis_helper} +\section{\texttt{SPEX\_symbolic\_analysis} helper function} \label{s:spex_symbolic_analysis_helper} +%------------------------------------------------------------------------------- + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_symbolic_analysis_free|: free a symbolic analysis struct} +\subsection{\texttt{SPEX\_symbolic\_analysis\_free}: free a symbolic analysis struct} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_symbolic_analysis_free + ( + SPEX_symbolic_analysis **S_handle, // Structure to be deleted + const SPEX_options *option + ); +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_symbolic_analysis_free| frees the memory of the \verb|SPEX_symbolic_analysis| \verb|*S| that \verb|S_handle| points to. On output, the symbolic analysis \verb|S| is set to \verb|NULL|. + + +%-------------------------------------------------------------------------------%\cprotect\section{\verb|SPEX_factorization| helper functions} \label{s:spex_factorization_helper} +\section{\texttt{SPEX\_factorization} helper functions} \label{s:spex_factorization_helper} +%------------------------------------------------------------------------------- +These functions provide several utilities for a \verb|SPEX_factorization| + + +\update{ +%-------------------------------------------------------------------------------%\cprotect\subsection{\verb|SPEX_factorization_check|: check correctness of a factorizations struct} +\subsection{\texttt{SPEX\_factorization\_check}: check correctness of a factorizations struct} \label{ss:spex_factorization_check} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_factorization_check + ( + SPEX_factorization *F, // The factorization to check + const SPEX_options* option + ); +\end{verbatim} +} \end{mdframed} + + +\verb|SPEX_factorization_check| checks if a given factorization \verb|F| is correctly formatted. Specifically, it checks the following 5 conditions: +\begin{enumerate} + \item All required components of \verb|F| are present (e.g., an array was not erroneously freed) + \item The sizes of all matrices match (e.g., \verb|F->L| and \verb|F->U| are square matrices of the same dimension) + \item \verb|F->L| (and \verb|F->U| if exists) is correctly formatted via \verb|SPEX_matrix_check| + \item \verb|F->L|, \verb|F->U|, and \verb|F->rhos| have the correct and same pivot values. Additionally, when \verb|F->updatable=true|, \verb|F->L| (and \verb|F->U| if exists) is of \verb|SPEX_DYNAMIC_CSC|, and the $i$-th pivot is the first entry in the nonzero list of $i$-th vector of \verb|L| (and \verb|U| if exists), i.e., \verb|F->L->v[i]->i[0] == F->P_perm[i]| and \verb|F->U->v[i]->i[0] ==| \verb|F->Q_perm[i]| + \item Each permutation has no repeated indices and maps from $[0..n-1]$ to $[0..n-1]$; \verb|P_perm| and \verb|Pinv_perm| are mutually inverse vectors, same applied to \verb|(Q_perm,| \verb|Qinv_perm)| if exists +\end{enumerate} + + +Similar to \verb|SPEX_matrix_check|, \verb|SPEX_factorization_check| also prints values of the factorization, together with any error found, with proper print level specified by +\verb|option->print_level|. Specifically, \verb|SPEX_factorization_check| prints nothing for \verb|print_level|=0 (default); or just errors for \verb|print_level|=1; or errors and terse output of the factorization for \verb|print_level|=2; or errors and detailed output of the factorization for \verb|print_level|=3. +As mentioned, if default settings are desired, \verb|option| can be input as \verb|NULL|. } + +%-------------------------------------------------------------------------------%\cprotect\subsection{\verb|SPEX_factorization_convert|: Convert between updatable and non updatable} +\update{\subsection{\texttt{SPEX\_factorization\_convert}: Convert between updatable and non-updatable} \label{ss:spex_factorization_convert} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_factorization_convert + ( + SPEX_factorization *F, // The factorization to be converted + bool updatable, // if true, make F updatable. false: make non-updatable + const SPEX_options* option // Command options + ); +\end{verbatim} +} \end{mdframed} + + +\verb|SPEX_factorization_convert| performs in-place conversion between updatable and +non-updatable factorization as specified by the boolean +input argument \verb'updatable'. If \verb|F->updatable == updatable| holds upon input, +this function does nothing. Otherwise, it performs the corresponding +in-place conversion. In case of any error, the returned factorization should be considered as +undefined. + +Upon input, \verb|F->L| (and \verb|F->U| if exists) must be non-shallow \verb|SPEX_CSC SPEX_MPZ| matrix for +non-updatable (static) factorization (i.e., \verb|F->updatalbe == false|), +otherwise, the input format is considered as incorrect and \verb|SPEX_INCORRECT_INPUT| is returned. Likewise, \verb|F->L| (and \verb|F->U| +if exists) must be \verb|SPEX_DYNAMIC_CSC SPEX_MPZ| matrix for updatable factorization. All +SPEX functions output factorization in either of these two formats and +non-shallow. Therefore, these input requirements can be met easily if users +do not try to modify any individual component of \verb|F|. +} + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_factorization_free|: Free a SPEX factorization} \label{ss:spex_factorization_free} +\subsection{\texttt{SPEX\_factorization\_free}: Free a SPEX factorization} \label{ss:spex_factorization_free} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_factorization_free + ( + SPEX_factorization **F_handle, // Structure to be deleted + const SPEX_options *option + ); +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_factorization_free| frees the memory of the \verb|SPEX_factorization *F| that \verb|F_handle| points to, and sets \verb|F| to \verb|NULL|. + +%------------------------------------------------------------------------------- +\newpage +\section{Misc Utilty Functions} +%------------------------------------------------------------------------------- + +%------------------------------------------------------------------------------- +\subsection{\texttt{SPEX\_version}: Return version of the code} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_version + ( + int version [3], // SPEX major, minor, and sub version + char date [128] // date of this version + ) +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_version| returns the library version and date. +The \verb'version' array contains the three version +numbers that are available at compile-time \verb'#define''d values: +\verb'SPEX_VERSION_MAJOR', +\verb'SPEX_VERSION_MINOR', and +\verb'SPEX_VERSION_SUB', in that order. The \verb'SPEX_version' function +allows the user application to check which version of SPEX it has been +linked with. The three \verb'#define''d values allow the user application +to know which version of SPEX was used at compile-time, which might not +be the same version that was linked later on. +The \verb'date' is the string \verb'SPEX_DATE', in the form +\verb'"Mar 31, 2023"' for example. The string is null-terminated. + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_determine_symmetry|: Determine if a matrix is symmetric} +\subsection{\texttt{SPEX\_determine\_symmetry}: Determine if a matrix is symmetric} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_determine_symmetry + ( + bool *is_symmetric, // true if symmetric + SPEX_matrix* A, // Input matrix to be checked for symmetry + const SPEX_options* option // Command options + ); +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_determine_symmetry| checks if \verb|A| is pattern and numerically symmetric. It first checks for pattern symmetry. If it is pattern symmetric, it is checked for numerical symmetry. If $A$ is a symmetric matrix, \verb|is_symmetric| is returned as \verb|true|. + +% removed +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_scale|: Scale a matrix by a constant} +%\subsection{\texttt{SPEX\_scale}: Scale a matrix by a constant} +%------------------------------------------------------------------------------- +%\begin{mdframed}[userdefinedwidth=\textwidth] +%{\footnotesize +%\begin{verbatim} +% SPEX_info SPEX_scale +% ( +% // Output +% SPEX_matrix* x, +% // Input +% const mpq_t scaling_num, //numerator +% const mpq_t scaling_den, //denominator +% const SPEX_options* option // command options +% ); +%\end{verbatim} +%} \end{mdframed} + +%This function scales the matrix \verb|x| by the term \verb|scaling_num|/\verb|scaling_den|. This is %primarily used during forward and backward solve routines. + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_transpose|: Transpose a csc mpz matrix} +\subsection{\texttt{SPEX\_transpose}: Transpose a CSC mpz matrix} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_transpose + ( + SPEX_matrix **C_handle, // C = A' + SPEX_matrix *A, // Matrix to be transposed + const SPEX_options *option + ); +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_transpose| sets $C = A^T$. Currently, it is only supported if $A$ is CSC and \verb|mpz_t|. Returns \verb|SPEX_OK| if successful otherwise returns the appropriate error code. + + +%------------------------------------------------------------------------------- +\newpage +\section{\texttt{SPEX\_gmp}: SPEX wrapper functions for GMP/MPFR} +%------------------------------------------------------------------------------- +SPEX provides a wrapper class for all GMP and MPFR functions used by SPEX. +The wrapper class provides error-handling for out-of-memory conditions +that are not handled by the GMP and MPFR libraries. These wrapper functions +are used inside all SPEX functions, wherever any GMP or MPFR functions are +used. These functions may also be called by the end-user application. + +Each wrapped function has the same name as its corresponding GMP/MPFR function +with the added prefix \verb|SPEX_|. For example, the default GMP function +\verb|mpz_mul| is changed to \verb|SPEX_mpz_mul|. Each SPEX GMP/MPFR function +returns \verb|SPEX_OK| if successful or the correct error code if not. The +following table gives a brief list of each currently covered SPEX GMP/MPFR +function. Each function is declared in \verb|SPEX.h| and defined in +\verb|SPEX/SPEX_Util/Source/SPEX_gmp.c|. + + +% \newpage +\thispagestyle{empty} +\begin{SizedCenteredTabular}[\scriptsize]{|l|l|l|} \hline +{\bf MPFR Function} & \verb|SPEX_MPFR| {\bf Function} & {\bf Description} \\ \hline\hline +\verb|n = mpfr_asprintf(&buff, fmt, ...)| + & \verb|n = SPEX_mpfr_asprintf(&buff, fmt, ...)| + & Print format to allocated string \\ \hline +\verb|mpfr_free_str(buff)| + & \verb|SPEX_mpfr_free_str(buff)| + & Free string allocated by MPFR \\ \hline +\verb|mpfr_init2(x, size)| + & \verb|SPEX_mpfr_init2(x, size)| + & Initialize x with size bits \\ \hline +\verb|mpfr_set(x, y, rnd)| & \verb|SPEX_mpfr_set(x, y, rnd)| & $x = y$ \\ \hline \verb|mpfr_set_d(x, y, rnd)| & \verb|SPEX_mpfr_set_d(x, y, rnd)| & $x = y$ (double) \\ \hline +\verb|mpfr_set_si(x, y, rnd)| + & \verb|SPEX_mpfr_set_si(x, y, rnd)| + & $x = y$ (\verb|int64_t|) \\ \hline \verb|mpfr_set_q(x, y, rnd)| & \verb|SPEX_mpfr_set_q(x, y, rnd)| & $x = y$ (\verb|mpq_t|) \\ \hline \verb|mpfr_set_z(x, y, rnd)| & \verb|SPEX_mpfr_set_z(x, y, rnd)| & $x = y$ (\verb|mpz_t|) \\ \hline -\verb|mpfr_get_z(x, y, rnd)| +\verb|r = mpfr_get_z(x, y, rnd)| & \verb|SPEX_mpfr_get_z(x, y, rnd)| & (\verb|mpz_t|) $x = y$\\ \hline +\verb|mpfr_get_q(x, y)| + & \verb|SPEX_mpfr_get_q(x, y, rnd)| + & (\verb|mpq_t|) $x = y$\\ \hline \verb|x = mpfr_get_d(y, rnd)| & \verb|SPEX_mpfr_get_d(x, y, rnd)| & (double) $x = y$\\ \hline +\verb|x = mpfr_get_si(y, rnd)| + & \verb|SPEX_mpfr_get_si(x, y, rnd)| + & (\verb|int64_t|) $x = y$\\ \hline \verb|mpfr_mul(x, y, z, rnd)| & \verb|SPEX_mpfr_mul(x, y, z, rnd)| - & $x = y*z$ \\ \hline + & $x = y*z$ (\verb|mpfr_t|) \\ \hline \verb|mpfr_mul_d(x, y, z, rnd)| & \verb|SPEX_mpfr_mul_d(x, y, z, rnd)| - & $x = y*z$ \\ \hline + & $x = y*z$ (double) \\ \hline \verb|mpfr_div_d(x, y, z, rnd)| & \verb|SPEX_mpfr_div_d(x, y, z, rnd)| - & $x = y/z$ \\ \hline + & $x = y/z$ (double) \\ \hline \verb|mpfr_ui_pow_ui(x, y, z, rnd)| & \verb|SPEX_mpfr_ui_pow_ui(x, y, z, rnd)| - & $x = y^z$ \\ \hline -\verb|mpfr_log2(x, y, rnd)| - & \verb|SPEX_mpfr_log2(x, y, rnd )| - & $x = \log_2 (y)$ \\ \hline + & $x = y^z$ (\verb|uint64_t|) \\ \hline +\verb|sgn = mpfr_sgn(x)| + & \verb|SPEX_mpfr_sgn(sgn, x)| + & $sgn =\text{sgn}(x)$ \\ \hline +%\verb|mpfr_log2(x, y, rnd)| +% & \verb|SPEX_mpfr_log2(x, y, rnd )| +% & $x = \log_2 (y)$ \\ \hline \verb|mpfr_free_cache()| & \verb|SPEX_mpfr_free_cache()| - & Free cache after log2 \\ \hline -\hline -%---------------------------------------- -{\bf GMP Function} & \verb|SPEX_GMP| {\bf Function} & {\bf Description} \\ -%---------------------------------------- -\hline\hline + & Free all caches and pools used by \\&&MPFR internally \\ \hline +\end{SizedCenteredTabular} + +\begin{SizedCenteredTabular}[\scriptsize]{|l|l|l|} \hline +{\bf GMP Function} & \verb|SPEX_GMP| {\bf Function} & {\bf Description} \\ \hline\hline \verb|n = gmp_fscanf(fp, fmt, ...)| & \verb|n = SPEX_gmp_fscanf(fp, fmt, ...)| & Read from file fp \\ \hline @@ -1403,55 +1584,82 @@ \section{SPEX wrapper functions for GMP and MPFR} & $x = y$ (\verb|mpz_t|) \\ \hline \verb|mpz_set_ui(x, y)| & \verb|SPEX_mpz_set_ui(x, y)| - & $x = y$ (signed int) \\ \hline + & $x = y$ (\verb|uint64_t|) \\ \hline \verb|mpz_set_si(x, y)| & \verb|SPEX_mpz_set_si(x, y)| - & $x = y$ (unsigned int) \\ \hline -\verb|mpz_set_d(x, y)| - & \verb|SPEX_mpz_set_d(x, y)| - & $x = y$ (double)\\ \hline + & $x = y$ (\verb|int64_t|) \\ \hline +%\verb|mpz_swap(x, y)| +% & \verb|SPEX_mpz_swap(x, y)| +% & Swap the values of $x$ and $y$ \\ \hline +%\verb|mpz_set_d(x, y)| +% & \verb|SPEX_mpz_set_d(x, y)| +% & $x = y$ (double)\\ \hline +%\verb|mpz_set_q(x, y)| +% & \verb|SPEX_mpz_set_q(x, y)| +% & $x = y$ (\verb|mpz_t|) \\ \hline \verb|x = mpz_get_d(y)| & \verb|SPEX_mpz_get_d(x, y)| - & $x = y$ (double out) \\ \hline -\verb|mpz_set_q(x, y)| - & \verb|SPEX_mpz_set_q(x, y)| - & $x = y$ (\verb|mpz_t|) \\ \hline + & (double) $x = y$\\ \hline +\verb|x = mpz_get_si(y)| + & \verb|SPEX_mpz_get_si(x, y)| + & (\verb|int64_t|) $x = y$ \\ \hline \verb|mpz_mul(x, y, z)| & \verb|SPEX_mpz_mul(x, y, z)| & $x = y*z$ \\ \hline -\verb|mpz_add(x, y, z)| - & \verb|SPEX_mpz_add(x, y, z)| - & $x = y+z$ \\ \hline -\verb|mpz_addmul(x, y, z)| - & \verb|SPEX_mpz_addmul(x, y, z)| - & $x = x+y*z$ \\ \hline +\verb|mpz_mul_si(x, y, z)| + & \verb|SPEX_mpz_mul(x, y, z)| + & $x = y*z (\verb|int64_t|)$ \\ \hline +%\verb|mpz_add(x, y, z)| +% & \verb|SPEX_mpz_add(x, y, z)| +% & $x = y+z$ \\ \hline +%\verb|mpz_addmul(x, y, z)| +% & \verb|SPEX_mpz_addmul(x, y, z)| +% & $x = x+y*z$ \\ \hline +\verb|mpz_sub(x, y, z)| + & \verb|SPEX_mpz_sub(x, y, z)| + & $x = y-z$ \\ \hline \verb|mpz_submul(x, y, z)| & \verb|SPEX_mpz_submul(x, y, z)| & $x = x-y*z$ \\ \hline +%\verb|mpz_fdiv_q(q, x, y)| +% & \verb|SPEX_mpz_fdiv_q(q, x, y)| +% & $q = \text{floor}(x/y)$ \\ \hline +%\verb|mpz_cdiv_q(q, x, y)| +% & \verb|SPEX_mpz_cdiv_q(q, x, y)| +% & $q = \text{ceil}(x/y)$ \\ \hline +\verb|mpz_cdiv_qr(q, r, x, y)| + & \verb|SPEX_mpz_cdiv_qr(q, r, x, y)| + & $q = \text{ceil}(x/y), r = x-q*y$ \\ \hline \verb|mpz_divexact(x, y, z)| & \verb|SPEX_mpz_divexact(x, y, z)| & $x = y/z$ \\ \hline \verb|gcd = mpz_gcd(x, y)| & \verb|SPEX_mpz_gcd(gcd, x, y)| - & $gcd = gcd(x,y)$\\ \hline + & $gcd = \text{gcd}(x,y)$\\ \hline \verb|lcm = mpz_lcm(x, y)| & \verb|SPEX_mpz_lcm(lcm, x, y)| - & $lcm = lcm(x,y)$ \\ \hline + & $lcm = \text{lcm}(x,y)$ \\ \hline +\verb|mpz_neg(x, y)| + & \verb|SPEX_mpz_neg(x, y)| + & $x = -y$ \\ \hline \verb|mpz_abs(x, y)| & \verb|SPEX_mpz_abs(x, y)| & $x = |y|$ \\ \hline \verb|r = mpz_cmp(x, y)| & \verb|SPEX_mpz_cmp(r, x, y)| - & $r = 0$ if $x=y$, $r\neq 0$ if $x\neq y$ \\ \hline -\verb|r = mpz_cmpabs(x, y)| - & \verb|SPEX_mpz_cmpabs(r, x, y)| - & $r = 0$ if $|x|=|y|$, $r\neq 0$ if $|x|\neq |y|$\\ \hline + & $r = \text{sgn}(x-y)$ \\ \hline +%\verb|r = mpz_cmpabs(x, y)| +% & \verb|SPEX_mpz_cmpabs(r, x, y)| +% & $r = \text{sgn}(|x|-|y|)$\\ \hline \verb|r = mpz_cmp_ui(x, y)| & \verb|SPEX_mpz_cmp_ui(r, x, y)| - & $r = 0$ if $x=y$, $r\neq 0$ if $x\neq y$ \\ \hline + & $r = \text{sgn}(x-y)$ (\verb|uint64_t|) \\ \hline +\verb|r = mpz_cmpabs_ui(x, y)| + & \verb|SPEX_mpz_cmpabs_ui(r, x, y)| + & $r = \text{sgn}(|x|-|y|)$ (\verb|uint64_t|) \\ \hline \verb|sgn = mpz_sgn(x)| & \verb|SPEX_mpz_sgn(sgn, x)| - & $sgn = 0$ if $x = 0$ \\ \hline + & $sgn = \text{sgn}(x)$ \\ \hline \verb|size = mpz_sizeinbase(x, base)| & \verb|SPEX_mpz_sizeinbase(size, x, base)| & size of x in base \\ \hline @@ -1469,19 +1677,28 @@ \section{SPEX wrapper functions for GMP and MPFR} & $x=y$ (double) \\ \hline \verb|mpq_set_ui(x, y, z)| & \verb|SPEX_mpq_set_ui(x, y, z)| - & $x = y/z$ (unsigned int) \\ \hline + & $x = y/z$ (\verb|uint64_t|/\verb|uint64_t|) \\ \hline +\verb|mpq_set_si(x, y, z)| + & \verb|SPEX_mpq_set_si(x, y, z)| + & $x = y/z$ (\verb|int64_t|/\verb|uint64_t|) \\ \hline \verb|mpq_set_num(x, y)| & \verb|SPEX_mpq_set_num(x, y)| & $num(x) = y$ \\ \hline \verb|mpq_set_den(x, y)| & \verb|SPEX_mpq_set_den(x, y)| & $den(x) = y$ \\ \hline -\verb|mpq_get_den(x, y)| - & \verb|SPEX_mpq_get_den(x, y)| - & $x = den(y)$ \\ \hline +%\verb|mpq_canonicalize(x)| +% & \verb|SPEX_mpq_canonicalize(x)| +% & Canonicalize x \\ \hline +%\verb|mpq_get_den(x, y)| +% & \verb|SPEX_mpq_get_den(x, y)| +% & $x = den(y)$ \\ \hline \verb|x = mpq_get_d(y)| & \verb|SPEX_mpq_get_d(x, y)| & (double) $x = y$ \\ \hline +\verb|mpq_neg(x, y)| + & \verb|SPEX_mpq_neg(x, y)| + & $x = -y$ \\ \hline \verb|mpq_abs(x, y)| & \verb|SPEX_mpq_abs(x, y)| & $x = |y|$ \\ \hline @@ -1496,115 +1713,585 @@ \section{SPEX wrapper functions for GMP and MPFR} & $x = y/z$ \\ \hline \verb|r = mpq_cmp(x, y)| & \verb|SPEX_mpq_cmp(r, x, y)| - & $r = 0$ if $x=y$, $r\neq 0$ if $x\neq y$ \\ \hline + & $r = \text{sgn}(x-y)$ \\ \hline \verb|r = mpq_cmp_ui(x, n, d)| & \verb|SPEX_mpq_cmp_ui(r, x, n, d)| - & $r = 0$ if $x=n/d$, $r\neq 0$ if $x\neq n/d$ \\ \hline + & $r = \text{sgn}(x-n/d)$ (\verb|uint64_t|/\verb|uint64_t|) \\ \hline +\verb|sgn = mpq_sgn(x)| + & \verb|SPEX_mpq_sgn(sgn, x)| + & $sgn = \text{sgn}(x)$ \\ \hline \verb|r = mpq_equal(x, y)| & \verb|SPEX_mpq_equal(r, x, y)| - & $r = 0$ if $x=y$, $r\neq 0$ if $x\neq y$ \\ \hline -\end{tabular} -\end{center} -} + & $r \neq 0$ if $x=y$, $r= 0$ if $x\neq y$ \\ \hline +\end{SizedCenteredTabular} -\section{Additional Useful SPEX Utility Functions} -\cprotect\subsection{\verb|SPEX_cumsum|: Cumulative sum of a vector} +If additional GMP and MPFR functions are needed in the end-user application, +this wrapper mechanism can be extended to those functions, which \ul{requires user to edit the source files} of the SPEX library, (i.e., both \verb|SPEX.h| and \verb|SPEX_gmp.c|). Below are +instructions on how to do this. -%------------------------------------------------------------------------------- +Given a GMP function \verb|void gmpfunc(TYPEa a, TYPEb b, ...)|, where +\verb|TYPEa| and \verb|TYPEb| can be GMP type data (\verb|mpz_t|, +\verb|mpq_t| and \verb|mpfr_t|, for example) or non-GMP type data (\verb|int|, +\verb|double|, for example), and they need not to be the same. +\pagebreak +A wrapper for a new GMP or MPFR function can be created by following +this outline: + +%\newpage +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_gmpfunc + ( + TYPEa a, + TYPEb b, + ... + ) + { + // Start the GMP Wrappter + // uncomment one of the following: + // If this function is not modifying any GMP/MPFR type variable, use + //SPEX_GMP_WRAPPER_START; + // If this function is modifying mpz_t type (say TYPEa = mpz_t), use + //SPEX_GMPZ_WRAPPER_START(a) ; + // If this function is modifying two variables of mpz_t type (say + // TYPEa = mpz_t, TYPEb = mpz_t), use + //SPEX_GMPZ_WRAPPER_START2(a, b) ; + // If this function is modifying mpq_t type (say TYPEa = mpq_t), use + //SPEX_GMPQ_WRAPPER_START(a) ; + // If this function is modifying mpfr_t type (say TYPEa = mpfr_t), use + //SPEX_GMPFR_WRAPPER_START(a) ; + + // Call the GMP function + gmpfunc(a,b,...) ; + + //Finish the wrapper and return ok if successful. + SPEX_GMP_WRAPPER_FINISH; + return SPEX_OK; + } +\end{verbatim} +} \end{mdframed} + +\newpage +Note that, other than \verb|SPEX_mpfr_fprintf|, \verb|SPEX_gmp_fprintf|, +\verb|SPEX_gmp_printf| and \verb|SPEX_gmp_fscanf|, all of the wrapped GMP/MPFR +functions always return \verb|SPEX_info| to the caller. Therefore, for some +GMP/MPFR functions that have their own return value. For example, for +\verb|int mpq_cmp(const mpq_t a, const mpq_t b)|, the return value becomes a +parameter of the wrapped function. In general, a GMP/MPFR function in the form +of \verb|TYPEr gmpfunc(TYPEa a, TYPEb b, ...)|, the wrapped +function can be constructed as follows: + +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_gmpfunc + ( + TYPEr *r, // return value of the GMP/MPFR function + TYPEa a, + TYPEb b, + ... + ) + { + // Start the GMP Wrappter + //SPEX_GMP_WRAPPER_START; + + // Call the GMP function + *r = gmpfunc(a,b,...) ; + + //Finish the wrapper and return ok if successful. + SPEX_GMP_WRAPPER_FINISH; + return SPEX_OK; + } +\end{verbatim} +} \end{mdframed} + + +%------------------------------------------------------------------------------- +\chapter{SPEX LU}\vspace{-0.75in} \label{ch:LeftLU} +%------------------------------------------------------------------------------- + +%------------------------------------------------------------------------------- +\section{Overview} \label{s:LeftLU:intro} +%------------------------------------------------------------------------------- +SPEX LU is a software package designed to exactly solve unsymmetric sparse +linear systems, $ A x = b$, where $A \in \mathbb{Q}^{n \times +n}$, $b \in \mathbb{Q}^{n \times r}$, and $x \in \mathbb{Q}^{n \times +r}$. This package performs a left-looking, roundoff-error-free (REF) LU +factorization $P A Q = L D U$, where $L$ and $U$ are integer, $D$ is diagonal, +and $P$ and $Q$ are row and column permutations, respectively. +Note that, in order to solve a linear system, the matrix $D$ is never explicitly computed nor needed; thus this +package uses only the matrices $L$ and $U$. The theory associated with this code is the Sparse Left-looking Integer-Preserving (SLIP) LU factorization + \cite{lourenco2019exact}. Aside from +solving sparse linear systems exactly, one of the key goals of this package is +to provide a framework for other solvers to benchmark the reliability and +stability of their linear solvers, as our final solution vector $x$ is +\ul{guaranteed} to be exact. SPEX LU is written in ANSI C and is accompanied by a MATLAB interface. + +Version 1.1.2 of SPEX Left LU was published in ACM TOMS as: +Lourenco, C., Chen, J., Moreno-Centeno, E., \& Davis, T. A. (2022). Algorithm 1021: SPEX Left LU, Exactly Solving Sparse Linear Systems via a Sparse Left-looking Integer-preserving LU Factorization. ACM Transactions on Mathematical Software (TOMS), 48(2), 1-23. + + +%------------------------------------------------------------------------------- +\section{Licensing} \label{s:LeftLU:licensing} +%------------------------------------------------------------------------------- +\textbf{Copyright:} The copyright of this software is held by Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and Timothy A. Davis.\\ + +\noindent \textbf{Contact Info:} Contact Chris Lourenco, +\href{mailto:chrisjlourenco@gmail.com}{chrisjlourenco@gmail.com}, or Tim Davis, +\href{mailto:timdavis@aldenmath.com}{timdavis@aldenmath.com}, +\href{mailto:davis@tamu.edu}{davis@tamu.edu}, or +\href{DrTimothyAldenDavis@gmail.com}{DrTimothyAldenDavis@gmail.com}\\ + +\noindent \textbf{License:} This software package is dual licensed under the GNU General Public License version 2 or the GNU Lesser General Public License version 3. Details of this license are in \verb|SPEX/License/license.txt|. For alternative licenses, please contact the authors. + + +\section{Factorization and Solve Routines} + +To factorize and solve a linear system $A \mathbf{x} = \mathbf{b}$ via the SPEX Left LU factorization, a user must call analyze, factorize, and solve. The functions are explained below: + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_LU_analyze|: symbolic analysis for LU factorization} \label{ss:spex_lu_analyze} +\subsection{\texttt{SPEX\_lu\_analyze}: symbolic analysis for LU factorization} \label{ss:spex_lu_analyze} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_lu_analyze + ( + SPEX_symbolic_analysis** S_handle, // symbolic analysis including + // column perm. and nnz of L and U + const SPEX_matrix *A, // Input matrix + const SPEX_options *option // Control parameters, if NULL, use default + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_lu_analyze| performs symbolic analysis for the REF LU factorization. On input, the \verb|SPEX_symbolic_analysis *S| that \verb|S_handle| points to is undefined; \verb|A| must be a square matrix of \verb|SPEX_CSC| kind; and \verb|option| contains any command parameters (default settings are used if +\verb|option| is input as \verb|NULL|). On output, \verb|S| contains the column preordering of \verb|A| and estimates on the number of nonzeros in $L$ and $U$. The type of ordering can be chosen with \verb|option->order|. It is suggested that COLAMD is used. + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_Left_LU_factorize|: Compute the LU factorization of A} \label{ss:spex_left_lu_factorize} +\subsection{\texttt{SPEX\_lu\_factorize}: Compute the LU factorization of A} \label{ss:spex_left_lu_factorize} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_lu_factorize + ( + // output: + SPEX_factorization **F_handle, // LU factorization + // input: + const SPEX_matrix *A, // matrix to be factored + const SPEX_symbolic_analysis *S, // symbolic analysis + const SPEX_options* option // command options + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_lu_factorize| performs the left-looking LU factorization. On input, the \linebreak +\verb|SPEX_factorization *F| that \verb|F_handle| points to is undefined; \verb|A| must be a square matrix of \verb|SPEX_CSC SPEX_MPZ| format; \verb|S| is obtained from \verb|SPEX_lu_analyze| that contains the column ordering of \verb|A|; and \verb|option| contains any command parameters (default settings are used if +\verb|option| is input as \verb|NULL|). On output, \verb|A|, \verb|S|, and \verb|option| are unmodified and \verb|F| contains the REF LU factorization of \verb|A|. + +%Returns \verb|SPEX_PANIC| if SPEX has not been initialized. Otherwise, if another +If any error occurs, \verb|F| is returned as \verb|NULL|, and an appropriate error code is returned. + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_Left_LU_solve|: solve the linear system $Ax=b$} +\newpage +\subsection{\texttt{SPEX\_lu\_solve}: solve the linear system} \label{ss:SPEX_Left_LU_solve} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_lu_solve // solves the linear system LD^(-1)U x = b + ( + // Output + SPEX_matrix **x_handle, // rational solution to the system + // input/output: + SPEX_factorization *F, // The LU factorization. + // input: + const SPEX_matrix *b, // right hand side vector + const SPEX_options* option // Command options + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_lu_solve| obtains the solution of \verb|mpq_t| type to the +linear system $Ax=b$ upon a successful factorization. This function may be +called after a successful return from \linebreak \verb|SPEX_lu_factorize|. + +On input, \verb|SPEX_matrix *x| that \verb|x_handle| points to is undefined; \verb|F| must be a valid LU factorization; and \verb|b| must be a dense \verb|mpz_t| matrix with same number of rows as \verb|F->L|; Default settings are used if +\verb|option| is input as \verb|NULL|. Upon successful completion, the function returns \verb|SPEX_OK|, and \verb|x| contains the solution of \verb|mpq_t| type with dense format to the linear system $Ax=b$. +\update{ +\verb|F| is mathematically unchanged on output. However, if \verb|F| is updatable on input, it is converted to non-updatable. If \verb|F| is already non-updatable, it is not modified.} +In case of failure, \verb|x| is returned as \verb|NULL| and the appropriate error code is returned. + + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_Left_LU_backslash|: solve $Ax=b$} +\subsection{\texttt{SPEX\_lu\_backslash}: solve a linear system} +\label{ss:SPEX_Left_LU_backslash} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_lu_backslash + ( + // Output + SPEX_matrix **X_handle, // Final solution vector + // Input + SPEX_type type, // Type of output desired. Must be + // SPEX_FP64, SPEX_MPFR, or SPEX_MPQ + const SPEX_matrix* A, // Input matrix of SPEX_CSC SPEX_MPZ + const SPEX_matrix* b, // Right hand side vector(s). Must be + // SPEX_DENSE SPEX_MPZ + const SPEX_options* option // Command options (Default if NULL) + ) ; +\end{verbatim} +} \end{mdframed} + +\verb|SPEX_lu_backslash| solves the linear system $Ax=b$ and returns the solution +as a dense matrix of \verb|mpq_t|, \verb|mpfr_t| or \verb|double| entries. This +function performs symbolic analysis, factorization, and solving all in one line. +It can be thought of as an exact version of MATLAB sparse backslash. + +On input, \verb|SPEX_matrix *x| that \verb|X_handle| points to is undefined. \verb|type| must be one of: +\verb|SPEX_MPQ|, \verb|SPEX_MPFR| or \verb|SPEX_FP64| to specify the data type +of the solution entries. \verb|A| should be a square CSC \verb|mpz_t| matrix +while \verb|b| should be a dense \verb|mpz_t| matrix. In addition, \verb|A->m| +should be equal to \verb|b->m|. Default settings are used if +\verb|option| is input as \verb|NULL|. + +Upon successful completion, the function returns \verb|SPEX_OK|, and +\verb|x| contains the solution of data type specified by +\verb|type| to the linear system $Ax=b$. In case of failure, \verb|x| is returned as \verb|NULL| and the appropriate error code is returned. +%Returns \verb|SPEX_PANIC| if SPEX has not been initialized. + + + +\begin{comment} +%------------------------------------------------------------------------------- +\cprotect\section{Using SPEX Left LU in C} \label{s:Using} +%------------------------------------------------------------------------------- +Using SPEX Left LU in C has three steps: + +\begin{enumerate} +\item initialize and populate data structures, +\item perform symbolic analysis, +factorize the matrix $A$ and solve the linear +system for each $b$ vector, and +\item free all used memory and finalize. +\end{enumerate} + +Step 1 is discussed in Section \ref{s:Using:init}. For Step 2, performing +symbolic analysis and factorizing $A$ and solving the linear $A x =b$ can be +done in one of two ways. If only the solution vector $x$ is required, SPEX Left LU +provides a simple interface for this purpose which is discussed in Section +\ref{s:Using:simple}. Alternatively, if the $L$ and $U$ factors are required, +refer to Section \ref{s:Using:expert}. Finally, step 3 is discussed in Section +\ref{s:Using:free}. For the remainder of this section, \verb|n| will indicate +the dimension of $A$ (that is, $A \in \mathbb{Z}^{n \times n}$) and +\verb|numRHS| will indicate the number of right hand side vectors being solved +(that is, if \verb|numRHS|$= r$, then $b \in \mathbb{Z}^{n \times r}$). + +%------------------------------------------------------------------------------- +\cprotect\subsection{SPEX Left LU initialization and population of data structures} +\label{s:Using:init} +%------------------------------------------------------------------------------- +This section discusses how to initialize and populate the global data +structures required for SPEX Left LU. + + +%------------------------------------------------------------------------------- +\subsubsection{Initializing the environment} +%------------------------------------------------------------------------------- +SPEX is built upon the GNU Multiple Precision Arithmetic (GMP) +\cite{granlund2015gnu} and GNU Multiple Precision Floating Point Reliable +(MPFR) \cite{fousse2007mpfr} libraries and provides wrappers to all GMP/MPFR +functions it uses. This allows SPEX to properly handle memory management +failures, which GMP/MPFR does not handle. To enable this mechanism, SPEX +requires initialization. The following must be done before using any other +SPEX function: + +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_initialize ( ) ; + // or SPEX_initialize_expert (...); if custom memory functions are desired +\end{verbatim} +} \end{mdframed} + + +%------------------------------------------------------------------------------- +\subsubsection{Initializing data structures} +\label{ss:init} +%------------------------------------------------------------------------------- +SPEX assumes three specific input options for all functions. These are: + +\begin{itemize} +\item \verb|SPEX_matrix* A| and \verb|SPEX_matrix *b|: \verb|A| contains the +input coefficient matrix, while \verb|b| contains the right hand side vector(s) +of the linear system $Ax=b$. + +\item \verb|SPEX_LU_analysis* S|: \verb|S| contains the column permutation used +for $A$ as well as estimates of the number of nonzeros in $L$ and $U$. + +\item \verb|SPEX_options* option|: \verb|option| contains various control +options for the factorization including column ordering used, pivot selection +scheme, and others. For a full list of the contents of the \verb|SPEX_options| +structure, refer to Section \ref{ss:SPEX_options}. +If default settings are desired, \verb|option| can be set to \verb|NULL|. + +\end{itemize} + + +%------------------------------------------------------------------------------- +\subsubsection{Populating data structures} +\label{ss:populate_Ab} +%------------------------------------------------------------------------------- +Of the three data structures discussed in Section~\ref{ss:init}, \verb|S| is +constructed during symbolic analysis (Section \ref{s:SPEX_LU_analyze}), and +\verb|option| is an optional parameter for selecting non-default parameters. +Refer to Section \ref{ss:SPEX_options} for the contents of \verb|option|. + +SPEX allows the input numerical data for \verb|A| and \verb|b| to come in +one of 5 types: \verb|int64_t|, \verb|double|, \verb|mpfr_t|, \verb|mpq_t|, +and \verb|mpz_t|. Moreover, both \verb|A| and \verb|b| can be stored in +CSC form, sparse triplet form or dense form. CSC form is discussed in Section +\ref{s:util:overview}. The triplet form stores the contents of the matrix $A$ +in three arrays \verb|i|, \verb|j|, and \verb|x| where the $k$th nonzero entry +is stored as $A ( i[k], j[k]) = x[k]$. SPEX stores its dense matrices in +in column-oriented format, that is, the $(i,j)$th entry in \verb|A| +is \verb|A->x.TYPE[p]| with $p = i+j$*\verb|A->m|. + +If the data for matrices are in file format to be read, refer to +\newline \verb|SPEX/SPEX/SPEX_Left_LU/Demo| \verb|/example2.c| on how to read in data and construct +\verb|A| and \verb|b|. If the data for matrices are already stored in vectors +corresponding to CSC form, sparse triplet form or dense form, allocate a +shallow \verb|SPEX_matrix| and assign vectors accordingly, then use +\verb|SPEX_matrix_copy| to get a \verb|SPEX_matrix| in the desired kind and +type. For more details, refer to \verb|SPEX/SPEX/SPEX_Left_LU/Demo/example.c|. In a case when +\verb|A| is available in format other than CSC \verb|mpz|, and/or \verb|b| is +available in format other than dense \verb|mpz|, the following code snippet +shows how to get \verb|A| and \verb|b| in a required format. + +{\small +\begin{verbatim} + /* Get the matrix A. Assume that A1 is stored in CSC form + with mpfr_t entries, while b1 is stored in triplet form + with mpq_t entries. (for A1 and b1 in any other form, + the exact same code will work) */ + + SPEX_matrix *A, *b; + // A is a copy of the A1. A is a CSC matrix with mpz_t entries + SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, A1, option); + // b is a copy of the b1. b is a dense matrix with mpz_t entries. + SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, b1, option); + \end{verbatim} } + + +%------------------------------------------------------------------------------- +\cprotect\subsection{Simple SPEX Left LU routines for solving linear systems} +\label{s:Using:simple} +%------------------------------------------------------------------------------- +After initializing the necessary data structures, SPEX obtains the solution +to $Ax=b$ using the simple interface of SPEX Left LU, \verb|SPEX_Left_LU_backslash|. The +\newline \verb|SPEX_Left_LU_backslash| function can return \verb|x| as \verb|double|, +\verb|mpq_t|, or \verb|mpfr_t| with an associated precision. See Section +\ref{ss:SPEX_Left_LU_backslash} for more details. The following code snippet shows how +to get solution as a dense \verb|mpq_t| matrix. + +{\small +\begin{verbatim} + SPEX_matrix *x; + SPEX_type my_type = SPEX_MPQ; // SPEX_MPQ, SPEX_MPFR, SPEX_FP64 + SPEX_Left_LU_backslash(&x, my_type, A, b, option) ; \end{verbatim} } + +On successful return, this function returns \verb|SPEX_OK| (see Section +\ref{ss:SPEX_info}). + + +%------------------------------------------------------------------------------- +\cprotect\subsection{Expert SPEX Left LU routines} +\label{s:Using:expert} +%------------------------------------------------------------------------------- +If the $L$ and $U$ factors from the SPEX Left LU factorization of the matrix $A$ +are required, the steps performed by \verb|SPEX_Left_LU_backslash| can be done with +a sequence of calls to SPEX functions: + +\begin{enumerate} +\item declare \verb|L|, \verb|U|, the solution matrix \verb|x|, and others, +\item perform symbolic analysis, +\item compute the factorization $PAQ = L D U$, +\item solve the linear system $Ax =b$, and +\item convert the final solution into the final desired form. +\end{enumerate} + +\noindent These steps are discussed below, along with examples. + + +%------------------------------------------------------------------------------- +\subsubsection{Declare workspace} +%------------------------------------------------------------------------------- +Using SPEX in this form requires the intermediate variables be declared, such as \verb|L|, \verb|U|, etc. The following code snippet shows the detailed list. + +{\small +\begin{verbatim} + // A and b are in required type and ready to use + SPEX_matrix *L = NULL; + SPEX_matrix *U = NULL; + SPEX_matrix *x = NULL; + SPEX_matrix *rhos = NULL; + int64_t* pinv = NULL; + SPEX_LU_analysis* S = NULL; + + // option needs no declaration if default setting is desired + // only declare option for further modification on default setting + SPEX_options *option = SPEX_create_default_options(); + \end{verbatim} } + + +%------------------------------------------------------------------------------- +\subsubsection{SPEX Left LU symbolic analysis} +%------------------------------------------------------------------------------- +The symbolic analysis phase of an LU factorization entails computing the symbolic column ordering and estimating the number of nonzeros in $L$ and $U$. This is performed by calling the following function: + +{\small + \begin{verbatim} + SPEX_LU_analyze (&S, A, option) ; \end{verbatim} } + + +%------------------------------------------------------------------------------- +\subsubsection{Computing the factorization} +%------------------------------------------------------------------------------- +The matrices \verb|L| and \verb|U|, the pivot sequence \verb|rhos|, and the row +permutation \verb|pinv| are computed via the \verb|SPEX_Left_LU_factorize| function +(Section \ref{s:LeftLU:SPEX_Left_LU_factorize}). Upon successful completion, this +function returns \verb|SPEX_OK|. + + +%------------------------------------------------------------------------------- +\subsubsection{Solving the linear system} +%------------------------------------------------------------------------------- +After factorization, the next step is to solve the linear system and store the +solution as a dense matrix \verb|x| with entries of rational number +\verb|mpq_t|. This solution is done via the \verb|SPEX_Left_LU_solve| +function (Section \ref{ss:SPEX_Left_LU_solve}). +Upon successful completion, this function returns \verb|SPEX_OK|. + +In this step, \verb|option->check| can be set to \verb|true| to enable the +solution check process as discussed in Section \ref{ss:SPEX_Left_LU_solve}. The +process can verify that the solution vector x satisfies $Ax=b$ in perfect +precision intended for debugging. This step is not needed, since the solution +returned is guaranteed to be exact. It appears here simply as debugging tool, +and as a verification that SPEX is computing its expected result. This test +can fail only if it runs out of memory, or if there is a bug in the code (in +which case, please notify the authors). Also, note that this process can be +quite time consuming; thus it is not recommended to be used in general. + + +%------------------------------------------------------------------------------- +\subsubsection{Converting the solution vector to the final desired form} +%------------------------------------------------------------------------------- +Upon completion of the above routines, the solution to the linear system is in +a dense \verb|mpq_t| matrix. SPEX allows this to be converted into any form +of matrix in the set of (CSC, sparse triplet, dense) $\times$ (\verb|mpfr_t|, +\verb|mpq_t|, \verb|double|) using \verb|SPEX_matrix_copy|. The following code +snippet shows how to get solution as a dense \verb|double| matrix; since this +involves a floating-point representation, the solution \verb|my_x| will no +longer be exact, even though \verb|x| is the exact solution. + +{\small +\begin{verbatim} + SPEX_kind my_kind = SPEX_DENSE; // SPEX_CSC, SPEX_TRIPLET or SPEX_DENSE + SPEX_type my_type = SPEX_FP64; // SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 + SPEX_matrix* my_x = NULL; // New output + // Create copy which is stored as my_kind and my_type: + SPEX_matrix_copy( &my_x, my_kind, my_type, x, option);\end{verbatim} } + + +%------------------------------------------------------------------------------- +\cprotect\subsection{Freeing memory} +\label{s:Using:free} +%------------------------------------------------------------------------------- +As described in Section \ref{s:user:memmanag}, SPEX provides a number +of functions/macros to free SPEX structures: + +\begin{itemize} +\item \verb|SPEX_matrix*|: A \verb|SPEX_matrix* A| data structure can be freed +with a call to \verb|SPEX_matrix_free(&A, NULL) ;| + +\item \verb|SPEX_LU_analysis*|: A \verb|SPEX_LU_analysis* S| data structure can +be freed with a call to \verb|SPEX_LU_analysis_free(&S, NULL) ;| -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} -SPEX_info SPEX_cumsum -( - int64_t *p, // vector to store the sum of c - int64_t *c, // vector which is summed - int64_t n // size of c -); -\end{verbatim} -} \end{mdframed} +\item All others including \verb|SPEX_options*|: These data structures can be +freed with a call to the macro \verb|SPEX_FREE()|, for example, +\verb|SPEX_FREE(option)| for \newline +\verb|SPEX_options* option|. +\end{itemize} -\verb|SPEX_cumsum| computes the cumulative sum of the array \verb|c| and stores it in the array \verb|p|. Specifically, $p_i = \sum_{j = 1}^i c_j$. This is mainly used for matrix copy and some factorizations. On input, \verb|p| and \verb|c| must not be NULL and \verb|n| must be at least 0. On completion, the contents of \verb|p| are overwritten with the cumulative sum of \verb|c| and \verb|SPEX_OK| is returned. +After all usage of the SPEX routines is finished, \verb|SPEX_finalize()| +must be called (Section \ref{ss:SPEX_finalize}) to finalize usage of the +library. -\cprotect\subsection{\verb|SPEX_check_solution|: Validate solution vector (for debugging)} +%------------------------------------------------------------------------------- +\cprotect\subsection{Examples} +\label{s:Using:Examples} +%------------------------------------------------------------------------------- +The \verb|SPEX/SPEX/SPEX_Left_LU/Demo| folder contains three sample C codes +which utilize SPEX. These files demonstrate the usage of SPEX as +follows: -\begin{mdframed}[userdefinedwidth=6in] -{\footnotesize -\begin{verbatim} -SPEX_info SPEX_check_solution -( - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *x, // Solution vectors - const SPEX_matrix *b, // Right hand side vectors - const SPEX_options* option // Command options -); -\end{verbatim} -} \end{mdframed} +\begin{itemize} +\item \verb|example.c|: This example generates a random dense $50 \times 50$ +matrix and a random dense $50 \times 1$ right hand side vector $b$ and +solves the linear system. In this function, the \verb|SPEX_Left_LU_backslash| +function is used; and the output is given as a double matrix. +\item \verb|example2.c|: This example reads in a matrix stored in triplet +format from the \verb|ExampleMats| folder. Additionally, it reads in a +right hand side vector from this folder and solves the associated linear system +via the \verb|SPEX_Left_LU_backslash| function, and, the solution is given as a matrix +of rational numbers. -Given a solution vector \verb|x|, check the solution of the linear system \verb|Ax = b|. This is done by computing a rational-arthmetic \verb|A*x == b|. Since all routines in SPEX are gauranteed to be exact, this function is for debugging purposes. On input, \verb|A| is \verb|SPEX_CSC| of \verb|SPEX_MPZ| type, \verb|x| is \verb|SPEX_DENSE| of \verb|SPEX_MPQ| type and \verb|b| is \verb|SPEX_DENSE| of \verb|SPEX_MPZ| type. On success, \verb|SPEX_OK| is returned. +\item \verb|spexlu_demo.c|: This example reads in a matrix and right hand side +vector from a file and solves the linear system $A x = b$ +using the techniques discussed in Section \ref{s:Using:expert}. This file also +allows command line arguments (discussed in \verb|README.md|) and can be used +to replicate the results from \cite{lourenco2019exact}. +\end{itemize} +\end{comment} -\chapter{SPEX Left LU} \label{ch:LeftLU} %------------------------------------------------------------------------------- -\section{Overview} \label{s:LeftLU:intro} +\chapter{SPEX Cholesky}\vspace{-0.75in} \label{ch:Chol} %------------------------------------------------------------------------------- -SPEX Left LU is a software package designed to exactly solve unsymmetric sparse -linear systems, $ A x = b$, where $A \in \mathbb{Q}^{n \times +%------------------------------------------------------------------------------- +\section{Overview} \label{s:Chol:intro} +%------------------------------------------------------------------------------- +SPEX Cholesky is a software package designed to exactly solve symmetric positive definite +linear systems, $A x = b$ where $A \in \mathbb{Q}^{n \times n}$, $b \in \mathbb{Q}^{n \times r}$, and $x \in \mathbb{Q}^{n \times -r}$. This package performs a left-looking, roundoff-error-free (REF) LU -factorization $P A Q = L D U$, where $L$ and $U$ are integer, $D$ is diagonal, -and $P$ and $Q$ are row and column permutations, respectively. -Note that, in order to solve a linear system, the matrix $D$ is never explicitly computed nor needed; thus this -package uses only the matrices $L$ and $U$. The theory associated with this code is the Sparse Left-looking Integer-Preserving (SLIP) LU factorization - \cite{lourenco2019exact}. Aside from -solving sparse linear systems exactly, one of the key goals of this package is -to provide a framework for other solvers to benchmark the reliability and -stability of their linear solvers, as our final solution vector $x$ is -\ul{guaranteed} to be exact. SPEX Left LU is written in ANSI C and is accompanied by a MATLAB interface. - -For all primary computational routines in Section \ref{s:LeftLU:SPEX_Left_LU_factorize}, the input -argument $A$ must be stored in a compressed sparse column (CSC) matrix with -entries in \verb|mpz_t| type (referred to as CSC \verb|mpz_t| matrix henceforth), while $b$ must be stored as a dense \verb|mpz_t| matrix (i.e., a -dense matrix with entries in \verb|mpz_t| type). However, the original data type of entries in the input matrix $A$ and right hand side (RHS) vectors $b$ can be any one of: \verb|double|, \verb|int64_t|, \verb|mpq_t|, -\verb|mpz_t|, or \verb|mpfr_t|, and their format(s) are allowed to be -CSC, sparse triplet, or dense. Section \ref{ss:populate_Ab} discusses the \verb|SPEX_matrix| structure, the allowed matrix formats and types, and how to perform conversions across different formats/types. - -The matrices $L$ and $U$ are computed using integer-preserving -routines with the arbitrary-sized integer (\verb|mpz_t|) data type from the GMP Library -\cite{granlund2015gnu}. The matrices $L$ and $U$ are computed in a left-looking fashion: one column at a -time via the sparse REF triangular solve -detailed in \cite{lourenco2019exact}. All divisions performed in the algorithm -are \textit{guaranteed} to be exact (i.e., with zero reminder); therefore, no greatest common -divisor algorithms are needed. - -The permutation matrices $P$ and $Q$ define the pivot ordering; $Q$ is a given -fill-reducing column ordering, and $P$ is determined dynamically during the -factorization. For the matrix $P$, the default option is to use a partial -pivoting scheme in which the (non-zero) entry with the smallest magnitude in column $k$ is selected as pivot; where ties are broken in favor of the diagonal entry (and arbitrarily otherwise). In addition to this scheme, -the code allows diagonal pivoting, partial pivoting selecting the entry with largest magnitude, or various tolerance-based diagonal pivoting schemes. For the matrix -$Q$, the default ordering is obtained via the Column Approximate Minimum Degree (COLAMD) -algorithm \cite{davis2004algorithmcolamd,davis2004column}. Other approaches -include using the Approximate Minimum Degree (AMD) ordering -\cite{amestoy1996approximate,amestoy2004algorithmamd}, or no ordering ($Q=I$). Section \ref{s:SPEX_LU_analyze} discusses how to select the desired column ordering prior to factorization. - -Once the factorization $L D U = P A Q$ is computed, the solution vector -$x$ is computed via the sparse REF forward and backward substitution algorithms \cite{lourenco2019exact}. -Forward substitution is a variant of the sparse REF triangular solve discussed above. Backward substitution is a typical column-oriented sparse backward substitution. Both of these routines require $b$ to be given as a dense \verb|mpz_t| matrix. At the conclusion of the forward and -backward substitution routines, the final solution vector(s) $x$ are guaranteed to be exact. The solution $x$ is returned as a dense \verb|mpq_t| matrix. - -A key advantage of utilizing SPEX Left LU with floating-point output is that the solution is guaranteed to be exact until the final (and only) rational-to-floating point conversion. Note that this final conversion is done in higher precision. Thus, the solution $x$ output in \verb|double| precision are accurate to machine roundoff (approximately $10^{-16}$). In addition, the returned solution can also be accurate to any user-specified precision by using MPFR output. +r}$. This package performs either a left-looking or up-looking sparse +roundoff-error-free Cholesky factorization $P A P^T = L D L^T$ where $L$ is integer, +and $P$ is the symmetric permutation. +Note that, in order to solve a linear system, the matrix $D$ is never explicitly computed nor needed; thus this package uses only the matrix $L$. The theory associated with this code can be found at + \cite{lourenco2022exactly}. SPEX Cholesky is written in ANSI C and is accompanied by MATLAB and Python interfaces. + + %------------------------------------------------------------------------------- -\section{Licensing} \label{s:LeftLU:licensing} +\section{Licensing} \label{s:Chol:licensing} %------------------------------------------------------------------------------- - -\textbf{Copyright:} The copyright of this software is held by Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and Timothy A. Davis.\\ +\textbf{Copyright:} The copyright of this software is held by Christopher Lourenco, Lorena Mejia Domenzain, Jinhao Chen, Erick Moreno-Centeno, and Timothy A. Davis.\\ \noindent \textbf{Contact Info:} Contact Chris Lourenco, \href{mailto:chrisjlourenco@gmail.com}{chrisjlourenco@gmail.com}, or Tim Davis, @@ -1614,195 +2301,127 @@ \section{Licensing} \label{s:LeftLU:licensing} \noindent \textbf{License:} This software package is dual licensed under the GNU General Public License version 2 or the GNU Lesser General Public License version 3. Details of this license are in \verb|SPEX/License/license.txt|. For alternative licenses, please contact the authors. +\section{Factorization and Solve Routines} -%------------------------------------------------------------------------------- -\section{Installation} \label{s:install} -%------------------------------------------------------------------------------- - -Installation of SPEX requires cmake. An optional top-level \verb'Makefile' -is provided to simplify its use (just do \verb'make ; make install'). - -To run the statement coverage tests (Linux required), go to the \verb|Tcov| folder and -type \verb|make|. The last line of output should read: - -\begin{verbatim} - statements not yet tested: 0 -\end{verbatim} - -If you want to use SPEX Left LU within MATLAB, -\verb|cd| in MATLAB to the folder \verb|SPEX/SPEX/SPEX_Left_LU/MATLAB| then type -\newline \verb|SPEX_Left_LU_install|. This compiles the necessary code so that you can use -the \verb|SPEX_Left_LU_backslash| function within MATLAB. Note that -\newline \verb|SPEX_Left_LU_install| does not add the correct directory to your path; therefore, -if you want to use \verb|SPEX_Left_LU_backslash| in future sessions, type -\verb|pathtool| and save your path for future MATLAB sessions. If you cannot -save your path because of file permissions, edit your \verb|startup.m| by -adding \verb|addpath| commands (for more information on how this is done, -please type \verb|doc startup| and \verb|doc addpath|). +To factorize and solve a linear system $A \mathbf{x} = \mathbf{b}$ via the SPEX Cholesky factorization, a user must call analyze, factorize, and solve. The functions are explained below: -\newpage %------------------------------------------------------------------------------- -% \cprotect\section{\verb|SPEX_Left_LU_VERSION|: the software package version} +%\cprotect\subsection{\verb|SPEX_Chol_analyze|: symbolic analysis for Cholesky factorization} \label{ss:spex_chol_analyze} +\newpage +\subsection{\texttt{SPEX\_cholesky\_analyze}: symbolic analysis for Cholesky factorization} \label{ss:spex_chol_analyze} %------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_cholesky_analyze + ( + // Output + SPEX_symbolic_analysis** S_handle, // Symbolic analysis data structure + // Input + const SPEX_matrix* A, // Input matrix of SPEX_CSC + const SPEX_options* option // Command options (Default if NULL) + ); + \end{verbatim} +} \end{mdframed} -% SPEX Left LU defines the following strings with \verb|#define|. Refer to -% the \verb|SPEX_Left_LU.h| file for details. +\verb|SPEX_cholesky_analyze| performs symbolic analysis for the REF Cholesky factorization. On input, the \verb|SPEX_symbolic_analysis *S| that \verb|S_handle| points to is undefined; \verb|A| must be an SPD matrix of \verb|SPEX_CSC| kind; and \verb|option| contains any command parameters (default settings are used if +\verb|option| is input as \verb|NULL|). On output, \verb|S| contains the row and column ordering of \verb|A|, the exact number of nonzeros in $L$, the elimination tree of \verb|A|, and the column pointers of $L$. The type of ordering can be chosen with \verb|option->order|. It is suggested that AMD is used. -%---------------------------------------- -% \begin{center} -% \begin{tabular}{ll} -% \hline -% Macro & purpose \\ -% \hline -% \verb|SPEX_Left_LU_VERSION| & current version of the code (as a string)\\ -% \verb|SPEX_Left_LU_VERSION_MAJOR| & major version of the code\\ -% \verb|SPEX_Left_LU_VERSION_MINOR| & minor version of the code \\ -% \verb|SPEX_Left_LU_VERSION_SUB| & sub version of the code\\ -% \hline -% \end{tabular} -% \end{center} -\section{Factorization and Solve Routines} %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_Left_LU_factorize|: perform LU factorization} -\label{s:LeftLU:SPEX_Left_LU_factorize} +%\cprotect\subsection{\verb|SPEX_Chol_factorize|: Compute the Cholesky factorization of A} \label{ss:spex_chol_factorize} +\subsection{\texttt{SPEX\_cholesky\_factorize}: Compute the Cholesky factorization of A} \label{ss:spex_chol_factorize} %------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_Left_LU_factorize + SPEX_info SPEX_cholesky_factorize ( - // output: - SPEX_matrix **L_handle, // lower triangular matrix - SPEX_matrix **U_handle, // upper triangular matrix - SPEX_matrix **rhos_handle, // sequence of pivots - int64_t **pinv_handle, // inverse row permutation - // input: - const SPEX_matrix *A, // matrix to be factored - const SPEX_LU_analysis *S, // column permutation and estimates - // of nnz in L and U - const SPEX_options* option - ) ; + // Output + SPEX_factorization **F_handle, // Cholesky factorization struct + //Input + const SPEX_matrix* A, // CSC MPZ Matrix to be factored + const SPEX_symbolic_analysis* S,// Symbolic analysis struct from + // SPEX_Chol_analyze. + const SPEX_options* option // command options, option->chol_type can be + // either CHOL_UP (default) or CHOL_LEFT. + ); \end{verbatim} } \end{mdframed} -\verb|SPEX_Left_LU_factorize| performs the SPEX Left-looking LU factorization. -This factorization is done via $n$ (number of rows or columns of the square -matrix $A$) iterations of the sparse REF triangular solve function. The overall -factorization is $PAQ = LDU$. This routine allows the factorization and solve -to be split into separate phases. For example codes, refer to either -\verb|SPEX/SPEX/SPEX_Left_LU/Demos/spexlu_denmo.c| or Section \ref{s:Using:expert}. - -On input, \verb|L|, \verb|U|, \verb|rhos|, and \verb|pinv| are undefined and -ignored. \verb|A| must be a CSC \verb|mpz| matrix. Default settings are used -if \verb|option| is input as \verb|NULL|. - -Upon successful completion, the function returns \verb|SPEX_OK|, and \verb|L| -and \verb|U| are lower and upper triangular matrices, respectively, which are -CSC matrices of type \verb|mpz|. \verb|rhos| contains the sequence of pivots -as an \verb|n|-by-1 dense vector of type \verb|mpz|. - -After factorizing the matrix, the determinant of $A$ can be obtained from -\verb|rhos[n-1]| and \verb|A->scale| as follows: - -\begin{verbatim} - mpq_t determinant ; - SPEX_mpq_init (determinant) ; - SPEX_mpq_set_z (determinant, rhos->x.mpz[rhos->n-1]) ; - SPEX_mpq_div (determinant, determinant, A->scale) ; -\end{verbatim} +\verb|SPEX_cholesky_factorize| performs the REF Cholesky factorization via either the up-looking (default) or left-looking manner (specified by \verb|option->chol_type|). On input, the \verb|SPEX_factorization *F| that \verb|F_handle| points to is undefined; \verb|A| must be an SPD matrix of \verb|SPEX_CSC SPEX_MPZ| format; \verb|S| is obtained from \verb|SPEX_Chol_analyze| that contains the column/row ordering of \verb|A|; and \verb|option| contains any command parameters (default settings are used if +\verb|option| is input as \verb|NULL|). On output, \verb|A|, \verb|S|, and \verb|option| are unmodified and \verb|F| contains the REF Cholesky factorization of \verb|A|. -The output array \verb|pinv| contains the inverse row permutation (that is, the -row index in the permuted matrix $PA$. For the $i$th row in $A$, \verb|pinv[i]| -gives the row index in $PA$). -Returns \verb|SPEX_PANIC| if SPEX has not been initialized. Otherwise, if -another error occurs, \verb|L|, \verb|U|, \verb|rhos|, and \verb|pinv| are all -returned as \verb|NULL|, and an error code will be returned correspondingly. +%Returns \verb|SPEX_PANIC| if SPEX has not been initialized. Otherwise, if another +If error occurs, \verb|F| is returned as \verb|NULL|, and an appropriate error code is returned. %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_Left_LU_solve|: solve the linear system $Ax=b$} -\label{ss:SPEX_Left_LU_solve} +%\cprotect\subsection{\verb|SPEX_Chol_solve|: solve the linear system $Ax=b$} +\newpage +\subsection{\texttt{SPEX\_cholesky\_solve}: solve the linear system} \label{ss:SPEX_Chol_solve} %------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_Left_LU_solve // solves the linear system LD^(-1)U x = b + SPEX_info SPEX_cholesky_solve // solves the linear system LD^(-1)L^T x = b ( // Output - SPEX_matrix **X_handle, // rational solution to the system + SPEX_matrix** x_handle, // rational solution to the system. + // input/output: + SPEX_factorization *F, // The non-updatable Cholesky factorization. // input: - const SPEX_matrix *b, // right hand side vector - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *L, // lower triangular matrix - const SPEX_matrix *U, // upper triangular matrix - const SPEX_matrix *rhos, // sequence of pivots - const SPEX_LU_analysis *S, // symbolic analysis struct - const int64_t *pinv, // inverse row permutation - const SPEX_options* option - ) ; + const SPEX_matrix* b, // Right hand side vector + const SPEX_options* option // command options + ); \end{verbatim} } \end{mdframed} -\verb|SPEX_Left_LU_solve| obtains the solution of \verb|mpq_t| type to the +\verb|SPEX_cholesky_solve| obtains the solution of \verb|mpq_t| type to the linear system $Ax=b$ upon a successful factorization. This function may be -called after a successful return from \verb|SPEX_Left_LU_factorize|, which -computes \verb|L|, \verb|U|, \verb|rhos|, and \verb|pinv|. - -On input, \verb|SPEX_matrix *x| is undefined. \verb|A|, \verb|L| and \verb|U| -must be CSC \verb|mpz_t| matrices while \verb|b| and \verb|rhos| must be dense -\verb|mpz_t| matrices. All matrices must have matched dimensions: the matrices -\verb|L| and \verb|U| must be square lower and upper triangular matrices the -same size as \verb|A|, and \verb|rhos| must be a dense \verb|n|-by-1 vector. -The input matrix \verb|b| must have same number of rows as \verb|A|. Default -settings are used if \verb|option| is input as \verb|NULL|. - -Upon successful completion, the function returns \verb|SPEX_OK|, and \verb|x| +called after a successful return from \verb|SPEX_Chol_factorize|. + +On input, \verb|SPEX_matrix *x| that \verb|x_handle| points to is undefined; \verb|F| must be a valid Cholesky factorization and \verb|b| must be dense \verb|mpz_t| with same number of rows as \verb|F->L|. Default settings are used if +\verb|option| is input as \verb|NULL|. Upon successful completion, the function returns \verb|SPEX_OK|, and \verb|x| contains the solution of \verb|mpq_t| type with dense format to the linear -system $Ax=b$. If desired, \verb|option->check| can be set to \verb|true| to -enable a post-check of the solution of this function. However, this is -intended for debugging only; the SPEX library is guaranteed to return the -exact solution. Otherwise (in case of error occurred), the function returns -corresponding error code. +system $Ax=b$. +\update{ +\verb|F| is mathematically unchanged on output. However, if \verb|F| is updatable on input, it is converted to non-updatable. If \verb|F| is already non-updatable, it is not modified.} +In case of failure, \verb|x| is returned as \verb|NULL| and the appropriate error code is returned. -This function is primarily for applications that require intermediate results. -For additional information, refer to either \verb|SPEX/SPEX/SPEX_Left_LU/Demos/spexlu_demo.c| or -Section \ref{s:Using:expert}. Returns \verb|SPEX_PANIC| if SPEX has not -been initialized. %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_Left_LU_backslash|: solve $Ax=b$} -\label{ss:SPEX_Left_LU_backslash} +%\cprotect\subsection{\verb|SPEX_Chol_backslash|: solve $Ax=b$} +\subsection{\texttt{SPEX\_cholesky\_backslash}: solve a linear system} +\label{ss:SPEX_Chol_backslash} %------------------------------------------------------------------------------- - -\begin{mdframed}[userdefinedwidth=6in] +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_info SPEX_Left_LU_backslash + SPEX_info SPEX_cholesky_backslash ( // Output - SPEX_matrix **X_handle, // Final solution vector + SPEX_matrix** x_handle, // Final solution vector(s) // Input - SPEX_type type, // Type of output desired: - // Must be SPEX_MPQ, SPEX_MPFR, - // or SPEX_FP64 - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *b, // Right hand side vector(s) - const SPEX_options* option - ) ; + SPEX_type type, // Type of output desired. Must be + // SPEX_FP64, SPEX_MPFR, or SPEX_MPQ + const SPEX_matrix* A, // Input matrix of SPEX_CSC SPEX_MPZ + const SPEX_matrix* b, // Right hand side vector(s). Must be + // SPEX_DENSE SPEX_MPZ + const SPEX_options* option // Command options (Default if NULL) + ); \end{verbatim} } \end{mdframed} -\verb|SPEX_Left_LU_backslash| solves the linear system $Ax=b$ and returns the solution -as a dense matrix of \verb|mpq_t|, \verb|mpfr_t| or \verb|double| numbers. This +\verb|SPEX_cholesky_backslash| solves the linear system $Ax=b$ and returns the solution +as a dense matrix of \verb|mpq_t|, \verb|mpfr_t| or \verb|double| entries. This function performs symbolic analysis, factorization, and solving all in one line. -It can be thought of as an exact version of MATLAB sparse backslash. +It can be thought of as an exact version of MATLAB sparse backslash for SPD matrices. +If $A$ is not SPD, this function will not work and LU factorization must be used. -On input, \verb|SPEX_matrix *x| is undefined. \verb|type| must be one of: +On input, \verb|SPEX_matrix *x| that \verb|x_handle| points to is undefined. \verb|type| must be one of: \verb|SPEX_MPQ|, \verb|SPEX_MPFR| or \verb|SPEX_FP64| to specify the data type of the solution entries. \verb|A| should be a square CSC \verb|mpz_t| matrix while \verb|b| should be a dense \verb|mpz_t| matrix. In addition, \verb|A->m| @@ -1811,349 +2430,310 @@ \section{Factorization and Solve Routines} Upon successful completion, the function returns \verb|SPEX_OK|, and \verb|x| contains the solution of data type specified by -\verb|type| to the linear system $Ax=b$. If desired, \verb|option->check| can -be set to \verb|true| to enable solution checking process in this function. -However, this is intended for debugging only; SPEX library is guaranteed to -return the exact solution. Otherwise (in case of error occurred), the function -returns corresponding error code. - -Returns \verb|SPEX_PANIC| if SPEX has not been initialized. +\verb|type| to the linear system $Ax=b$. In case of failure, \verb|x| is returned as \verb|NULL| and the appropriate error code is returned. +%Returns \verb|SPEX_PANIC| if SPEX has not been initialized. -For a complete example, refer to \verb|SPEX/SPEX/SPEX_Left_LU/Demos/example.c|, \\ -\verb|SPEX/SPEX/SPEX_Left_LU/Demos/example2.c|, or Section \ref{s:Using:simple}. %------------------------------------------------------------------------------- -\cprotect\section{Using SPEX Left LU in C} \label{s:Using} +\chapter{SPEX Backslash}\vspace{-0.75in} \label{ch:Backslash} %------------------------------------------------------------------------------- -Using SPEX Left LU in C has three steps: - -\begin{enumerate} -\item initialize and populate data structures, -\item perform symbolic analysis, -factorize the matrix $A$ and solve the linear -system for each $b$ vector, and -\item free all used memory and finalize. -\end{enumerate} - -Step 1 is discussed in Section \ref{s:Using:init}. For Step 2, performing -symbolic analysis and factorizing $A$ and solving the linear $A x =b$ can be -done in one of two ways. If only the solution vector $x$ is required, SPEX Left LU -provides a simple interface for this purpose which is discussed in Section -\ref{s:Using:simple}. Alternatively, if the $L$ and $U$ factors are required, -refer to Section \ref{s:Using:expert}. Finally, step 3 is discussed in Section -\ref{s:Using:free}. For the remainder of this section, \verb|n| will indicate -the dimension of $A$ (that is, $A \in \mathbb{Z}^{n \times n}$) and -\verb|numRHS| will indicate the number of right hand side vectors being solved -(that is, if \verb|numRHS|$= r$, then $b \in \mathbb{Z}^{n \times r}$). - %------------------------------------------------------------------------------- -\cprotect\subsection{SPEX Left LU initialization and population of data structures} -\label{s:Using:init} +\section{Overview} \label{s:Backslash:intro} %------------------------------------------------------------------------------- +SPEX Backslash is a software package designed to exactly solve sparse +linear systems, $A x = b$ where $A \in \mathbb{Q}^{n \times +n}$, $b \in \mathbb{Q}^{n \times r}$, and $x \in \mathbb{Q}^{n \times +r}$. This package determines the appropraite factorization to apply based on the +structure of the input matrix. -This section discusses how to initialize and populate the global data -structures required for SPEX Left LU. +SPEX Backslash is written in ANSI C and is accompanied by MATLAB and Python interfaces. + %------------------------------------------------------------------------------- -\subsubsection{Initializing the environment} +\section{Licensing} \label{s:Backslash:licensing} %------------------------------------------------------------------------------- +\textbf{Copyright:} The copyright of this software is held by Christopher Lourenco, Lorena Mejia Domenzain, Jinhao Chen, Erick Moreno-Centeno, and Timothy A. Davis.\\ -SPEX is built upon the GNU Multiple Precision Arithmetic (GMP) -\cite{granlund2015gnu} and GNU Multiple Precision Floating Point Reliable -(MPFR) \cite{fousse2007mpfr} libraries and provides wrappers to all GMP/MPFR -functions it uses. This allows SPEX to properly handle memory management -failures, which GMP/MPFR does not handle. To enable this mechanism, SPEX -requires initialization. The following must be done before using any other -SPEX function: +\noindent \textbf{Contact Info:} Contact Chris Lourenco, +\href{mailto:chrisjlourenco@gmail.com}{chrisjlourenco@gmail.com}, or Tim Davis, +\href{mailto:timdavis@aldenmath.com}{timdavis@aldenmath.com}, +\href{mailto:davis@tamu.edu}{davis@tamu.edu}, or +\href{DrTimothyAldenDavis@gmail.com}{DrTimothyAldenDavis@gmail.com}\\ -\begin{mdframed}[userdefinedwidth=6in] +\noindent \textbf{License:} This software package is dual licensed under the GNU General Public License version 2 or the GNU Lesser General Public License version 3. Details of this license are in \verb|SPEX/License/license.txt|. For alternative licenses, please contact the authors. + +%------------------------------------------------------------------------------- +%\cprotect\section{\verb|SPEX_Backslash|: Exactly solve sparse linear systems} +\newpage +\section{\texttt{SPEX\_backslash}: Exactly solve sparse linear systems} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] {\footnotesize \begin{verbatim} - SPEX_initialize ( ) ; - // or SPEX_initialize_expert (...); if custom memory functions are desired + SPEX_info SPEX_backslash + ( + // Output + SPEX_matrix **X_handle, // On output: Final solution vector + // On input: undefined + // Input + SPEX_type type, // Type of output desired. Must be + // SPEX_FP64, SPEX_MPFR, or SPEX_MPQ + const SPEX_matrix* A, // Input matrix of SPEX_CSC SPEX_MPZ + const SPEX_matrix* b, // Right hand side vector(s). Must be + // SPEX_DENSE SPEX_MPZ + const SPEX_options* option // Command options (Default if NULL) + ); \end{verbatim} } \end{mdframed} -%------------------------------------------------------------------------------- -\subsubsection{Initializing data structures} -\label{ss:init} -%------------------------------------------------------------------------------- +\verb|SPEX_backslash| exactly solves the linear system $A \mathbf{x} = \mathbf{b}$ using the appropriate factorization. On input, \verb|SPEX_matrix *x| that \verb|X_handle| points to is undefined. \verb|type| must be one of: +\verb|SPEX_MPQ|, \verb|SPEX_MPFR| or \verb|SPEX_FP64| to specify the data type +of the solution entries. \verb|A| should be a square CSC \verb|mpz_t| matrix +while \verb|b| should be a dense \verb|mpz_t| matrix. In addition, \verb|A->m| +should be equal to \verb|b->m|. Default settings are used if +\verb|option| is input as \verb|NULL|. -SPEX assumes three specific input options for all functions. These are: -\begin{itemize} -\item \verb|SPEX_matrix* A| and \verb|SPEX_matrix *b|: \verb|A| contains the -input coefficient matrix, while \verb|b| contains the right hand side vector(s) -of the linear system $Ax=b$. +This function first checks the symmetry of \verb|A|. If \verb|A| is numerically and pattern symmetric, SPEX Cholesky factorization is attempted. If the Cholesky factorization is successful, it is used to solve $A x = b$. Otherwise, LU factorization is used. -\item \verb|SPEX_LU_analysis* S|: \verb|S| contains the column permutation used -for $A$ as well as estimates of the number of nonzeros in $L$ and $U$. +Upon successful completion, the function returns \verb|SPEX_OK|, and +\verb|x| contains the solution of data type specified by +\verb|type| to the linear system $Ax=b$. If an error occurs, \verb|x| is freed and the appropriate error code is returned. -\item \verb|SPEX_options* option|: \verb|option| contains various control -options for the factorization including column ordering used, pivot selection -scheme, and others. For a full list of the contents of the \verb|SPEX_options| -structure, refer to Section \ref{ss:SPEX_options}. -If default settings are desired, \verb|option| can be set to \verb|NULL|. +\update{ +\chapter{SPEX Update}\vspace{-0.75in} \label{ch:Update} -\end{itemize} %------------------------------------------------------------------------------- -\subsubsection{Populating data structures} -\label{ss:populate_Ab} +\section{Overview} \label{s:Update:intro} %------------------------------------------------------------------------------- +SPEX Update is a software package designed to exactly update +an available REF LU/Cholesky factorization for the sparse matrix $A$ when a low-rank modification is performed on $A$. The low-rank modification could be either column/row replacement or rank-1 update/downdate. Currently, SPEX provides functions for column-replacement LU update and rank-1 Cholesky update/downdate. The theoretical basis for this code is to be submitted as +\begin{itemize} + \item J. Chen, T. A. Davis, “Sparse Exact LU +Update for Column Replacement,” SIAM Journal on Matrix Analysis and Applications. + \item J. Chen, T. A. Davis, “Sparse Exact Rank-1 +Cholesky Update,” SIAM Journal on Matrix Analysis and Applications. +\end{itemize} +SPEX Update is written in ANSI C. -Of the three data structures discussed in Section~\ref{ss:init}, \verb|S| is -constructed during symbolic analysis (Section \ref{s:SPEX_LU_analyze}), and -\verb|option| is an optional parameter for selecting non-default parameters. -Refer to Section \ref{ss:SPEX_options} for the contents of \verb|option|. - -SPEX allows the input numerical data for \verb|A| and \verb|b| to come in -one of 5 types: \verb|int64_t|, \verb|double|, \verb|mpfr_t|, \verb|mpq_t|, -and \verb|mpz_t|. Moreover, both \verb|A| and \verb|b| can be stored in -CSC form, sparse triplet form or dense form. CSC form is discussed in Section -\ref{s:util:overview}. The triplet form stores the contents of the matrix $A$ -in three arrays \verb|i|, \verb|j|, and \verb|x| where the $k$th nonzero entry -is stored as $A ( i[k], j[k]) = x[k]$. SPEX stores its dense matrices in -in column-oriented format, that is, the $(i,j)$th entry in \verb|A| -is \verb|A->x.TYPE[p]| with $p = i+j$*\verb|A->m|. - -If the data for matrices are in file format to be read, refer to -\newline \verb|SPEX/SPEX/SPEX_Left_LU/Demo| \verb|/example2.c| on how to read in data and construct -\verb|A| and \verb|b|. If the data for matrices are already stored in vectors -corresponding to CSC form, sparse triplet form or dense form, allocate a -shallow \verb|SPEX_matrix| and assign vectors accordingly, then use -\verb|SPEX_matrix_copy| to get a \verb|SPEX_matrix| in the desired kind and -type. For more details, refer to \verb|SPEX/SPEX/SPEX_Left_LU/Demo/example.c|. In a case when -\verb|A| is available in format other than CSC \verb|mpz|, and/or \verb|b| is -available in format other than dense \verb|mpz|, the following code snippet -shows how to get \verb|A| and \verb|b| in a required format. - -{\small -\begin{verbatim} - - /* Get the matrix A. Assume that A1 is stored in CSC form - with mpfr_t entries, while b1 is stored in triplet form - with mpq_t entries. (for A1 and b1 in any other form, - the exact same code will work) */ - - SPEX_matrix *A, *b; - // A is a copy of the A1. A is a CSC matrix with mpz_t entries - SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, A1, option); - // b is a copy of the b1. b is a dense matrix with mpz_t entries. - SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, b1, option); - \end{verbatim} } - + %------------------------------------------------------------------------------- -\cprotect\subsection{Simple SPEX Left LU routines for solving linear systems} -\label{s:Using:simple} +\section{Licensing} \label{s:Update:licensing} %------------------------------------------------------------------------------- +\textbf{Copyright:} The copyright of this software is held by Jinhao Chen, Christopher Lourenco, Lorena Mejia Domenzain, Erick Moreno-Centeno, and Timothy A. Davis.\\ -After initializing the necessary data structures, SPEX obtains the solution -to $Ax=b$ using the simple interface of SPEX Left LU, \verb|SPEX_Left_LU_backslash|. The -\newline \verb|SPEX_Left_LU_backslash| function can return \verb|x| as \verb|double|, -\verb|mpq_t|, or \verb|mpfr_t| with an associated precision. See Section -\ref{ss:SPEX_Left_LU_backslash} for more details. The following code snippet shows how -to get solution as a dense \verb|mpq_t| matrix. +\noindent \textbf{Contact Info:} Contact Jinhao Chen +\href{mailto:cjh10644@hotmail.com}{cjh10644@hotmail.com}, or Chris Lourenco, +\href{mailto:chrisjlourenco@gmail.com}{chrisjlourenco@gmail.com}, or Tim Davis, +\href{mailto:timdavis@aldenmath.com}{timdavis@aldenmath.com}, +\href{mailto:davis@tamu.edu}{davis@tamu.edu}, or +\href{DrTimothyAldenDavis@gmail.com}{DrTimothyAldenDavis@gmail.com}\\ -{\small -\begin{verbatim} - SPEX_matrix *x; - SPEX_type my_type = SPEX_MPQ; // SPEX_MPQ, SPEX_MPFR, SPEX_FP64 - SPEX_Left_LU_backslash(&x, my_type, A, b, option) ; \end{verbatim} } +\noindent \textbf{License:} This software package is dual licensed under the GNU General Public License version 2 or the GNU Lesser General Public License version 3. Details of this license are in \verb|SPEX/License/license.txt|. For alternative licenses, please contact the authors. -On successful return, this function returns \verb|SPEX_OK| (see Section -\ref{ss:SPEX_info}). %------------------------------------------------------------------------------- -\cprotect\subsection{Expert SPEX Left LU routines} -\label{s:Using:expert} +\section{SPEX Factorization Update Functions} %------------------------------------------------------------------------------- +SPEX update provides the following functions to perform factorization updates. -If the $L$ and $U$ factors from the SPEX Left LU factorization of the matrix $A$ -are required, the steps performed by \verb|SPEX_Left_LU_backslash| can be done with -a sequence of calls to SPEX functions: - -\begin{enumerate} -\item declare \verb|L|, \verb|U|, the solution matrix \verb|x|, and others, -\item perform symbolic analysis, -\item compute the factorization $PAQ = L D U$, -\item solve the linear system $Ax =b$, and -\item convert the final solution into the final desired form. -\end{enumerate} +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_Update_Chol_Rank1|: rank 1 update to REF Cholesky} +\subsection{\texttt{SPEX\_Update\_Chol\_Rank1}: rank-1 REF Cholesky update/downdate}\label{ss:SPEX_Update_Chol_Rank1} +%------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_Update_Chol_Rank1 + ( + // input/output + SPEX_factorization *F, // The SPEX Cholesky factorization of A. + SPEX_matrix *w, // a n-by-1 SPEX_DYNAMIC_CSC matrix that + // contains the vector to modify the original + // matrix A, the resulting A is A+sigma*w*w^T. + // input + const int64_t sigma, // a nonzero scalar that determines whether + // this is an update (sigma > 0) or downdate + // (sigma < 0). + const SPEX_options* option // Command options + ); +\end{verbatim} +} \end{mdframed} -\noindent These steps are discussed below, along with examples. +\verb|SPEX_Update_Chol_Rank1| performs the rank-1 REF Cholesky update/downdate for a $n$-by-$n$ sparse matrix $A$. On input, \verb|F| contains the valid Cholesky factorization to be updated that consists of \verb|L|, \verb|rhos|, \verb|P_perm| and \verb|Pinv_perm|; \verb|w| must be a $n$-by-$1$ matrix of \verb|SPEX_DYNAMIC_CSC| kind; \verb|sigma| is a nonzero scalar, where \verb|sigma > 0| indicates update and \verb|sigma < 0| indicates downdate; and \verb|option| contains command options (default settings are used if \verb|option| is input as \verb|NULL|). -%------------------------------------------------------------------------------- -\subsubsection{Declare workspace} -%------------------------------------------------------------------------------- +This function requires that the rows of \verb|w| are in the same order as that of $A$ (and \verb|F->L| if \verb|F| is updatable). In addition, \verb|w| and \verb|SPEX_matrix *A| that contains $A$ are scaled with same factor, i.e., \verb|w->scale = A->scale|, while \verb|w->v[0]->scale = 1|. (Users can refer to section \ref{ss:SPEX_matrix} for the difference between \verb|w->scale| and \verb|w->v[0]->scale|.) As for \verb|F|, if it is input in a non-updatable format, it is first converted to updatable format. -Using SPEX in this form requires the intermediate variables be declared, such as \verb|L|, \verb|U|, etc. The following code snippet shows the detailed list. +On success \verb|SPEX_OK| is returned, and \verb|F| contains the updatable REF Cholesky factorization of $A + \sigma w w^T$, and \verb|w| contains the solution $w_{out}$ to $LD^{-1}w_{out} = w_{in}$, where $A=LD^{-1}L^T$ and $w_{in}$ is the input matrix \verb|w|. It should be noted that $w_{out}$ is also the solution to $\bar{L}\bar{D}^{-1}w_{out} = w_{in}$, where $A+ \sigma w w^T=\bar{L}\bar{D}^{-1}\bar{L}^T$. Otherwise, if this function fails for any reason, the appropriate error code is returned and \verb|F| is undefined on output (since the modification for the factorization is done in place during the update process). -{\small -\begin{verbatim} - // A and b are in required type and ready to use - SPEX_matrix *L = NULL; - SPEX_matrix *U = NULL; - SPEX_matrix *x = NULL; - SPEX_matrix *rhos = NULL; - int64_t* pinv = NULL; - SPEX_LU_analysis* S = NULL; - // option needs no declaration if default setting is desired - // only declare option for further modification on default setting - SPEX_options *option = SPEX_create_default_options(); - \end{verbatim} } +This function does not require/use/modify the original matrix $A$. Therefore, if the updated matrix $\bar{A}$ is needed, users should implement it by their own {\bf BEFORE} using this function (since \verb|w| will be modified by this function). + %------------------------------------------------------------------------------- -\subsubsection{SPEX Left LU symbolic analysis} +%\cprotect\subsection{\verb|SPEX_Update_LU_ColRep|: Column replacement update for REF LU} +\subsection{\texttt{SPEX\_Update\_LU\_ColRep}: Column-replacement REF LU update}\label{ss:SPEX_Update_LU_ColRep} %------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_Update_LU_ColRep + ( + // input/output + SPEX_factorization* F, // The SPEX LU factorization of A. + // input + SPEX_matrix *vk, // a n-by-1 SPEX_DYNAMIC_CSC matrix that + // contains the column to be inserted. + int64_t k, // The column index that vk will be inserted + const SPEX_options *option// Command parameters + ); +\end{verbatim} +} \end{mdframed} -The symbolic analysis phase of an LU factorization entails computing the symbolic column ordering and estimating the number of nonzeros in $L$ and $U$. This is performed by calling the following function: +\verb|SPEX_Update_LU_ColRep| exactly updates the REF LU factorization of a $n$-by-$n$ sparse matrix $A$ when one column of $A$ is replaced. On input \verb|F| contains the valid LU factorization to be updated that consists of \verb|L, U, rhos, P_perm, Pinv_perm| and \verb|Q_perm| (and \verb|Qinv_perm| for an updatable \verb|F|); \verb|vk| is a $n$-by-$1$ \verb|SPEX_DYNAMIC_CSC| matrix that contains the column to be inserted; \verb|k| is the index of the column of $A$ to be replaced and thus must be in the range of $[0,n-1]$; and option contains command parameters (default settings are used if \verb|option| is input as \verb|NULL|). -{\small - \begin{verbatim} - SPEX_LU_analyze (&S, A, option) ; \end{verbatim} } +This function requires that the rows of \verb|vk| are in the same order as that of $A$ (and \verb|F->L| if \verb|F| is updatable). In addition, \verb|vk| and \verb|SPEX_matrix *A| that contains $A$ are scaled with same factor, i.e., \verb|vk->scale = A->scale|, while \verb|vk->v[0]->scale = 1|. (Users can refer to section \ref{ss:SPEX_matrix} for the difference between \verb|vk->scale| and \verb|vk->v[0]->scale|.) As for \verb|F|, if it is input in a non-updatable format, it is first converted to updatable format. -%------------------------------------------------------------------------------- -\subsubsection{Computing the factorization} -%------------------------------------------------------------------------------- +On success \verb|SPEX_OK| is returned, and \verb|F| contains the updatable REF LU factorization of $\bar{A}$ which is obtained by replacing column $k$ of $A$ with \verb|vk|, while \verb|vk| is unmodified. +Otherwise, if this function fails for any reason, the appropriate error code is returned and \verb|F| is undefined on output (since the modification for the factorization is done in place during the update process). + +This function does not require/use/modify the original matrix $A$. Therefore, if the updated matrix $\bar{A}$ is needed, users should call \verb|SPEX_Update_matrix_colrep| {\bf AFTER} using this function (since \verb|vk| will be modified by \verb|SPEX_Update_matrix_colrep|). -The matrices \verb|L| and \verb|U|, the pivot sequence \verb|rhos|, and the row -permutation \verb|pinv| are computed via the \verb|SPEX_Left_LU_factorize| function -(Section \ref{s:LeftLU:SPEX_Left_LU_factorize}). Upon successful completion, this -function returns \verb|SPEX_OK|. %------------------------------------------------------------------------------- -\subsubsection{Solving the linear system} +\section{SPEX Update Solve Routines} %------------------------------------------------------------------------------- +When factorization is updated iteratively, it should not be converted back and forth between updatable and non-updatable formats. However, this happens when users use the default LU/Cholesky solves (i.e., \verb|SPEX_Left_LU_solve| or \verb|SPEX_Chol_solve|) after using either \verb|SPEX_Update_Chol_Rank1| or \verb|SPEX_Update_LU_ColRep|, since the default LU/Cholesky solves always convert factorization to non-updatable format while the SPEX Update functions require and output updatable factorization. To avoid this, SPEX Update provides functions to solve the linear equation $Ax=b$ based on the updatable LU/Cholesky factorization of $A$. In particular, both a normal solve and a transpose solve using the updatable factorizations are provided. -After factorization, the next step is to solve the linear system and store the -solution as a dense matrix \verb|x| with entries of rational number -\verb|mpq_t|. This solution is done via the \verb|SPEX_Left_LU_solve| -function (Section \ref{ss:SPEX_Left_LU_solve}). -Upon successful completion, this function returns \verb|SPEX_OK|. - -In this step, \verb|option->check| can be set to \verb|true| to enable the -solution check process as discussed in Section \ref{ss:SPEX_Left_LU_solve}. The -process can verify that the solution vector x satisfies $Ax=b$ in perfect -precision intended for debugging. This step is not needed, since the solution -returned is guaranteed to be exact. It appears here simply as debugging tool, -and as a verification that SPEX is computing its expected result. This test -can fail only if it runs out of memory, or if there is a bug in the code (in -which case, please notify the authors). Also, note that this process can be -quite time consuming; thus it is not recommended to be used in general. %------------------------------------------------------------------------------- -\subsubsection{Converting the solution vector to the final desired form} +%\cprotect\subsection{\verb|SPEX_Update_solve|: Solve $Ax=b$ with the updatable factorization} +\subsection{\texttt{SPEX\_Update\_solve}: Solve linear system with the updatable factorization}\label{ss:SPEX_Update_solve} %------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_Update_solve // solves Ax = b + ( + // Output + SPEX_matrix **x_handle, // rational solution to the system + // input/output + SPEX_factorization *F, // The updatable LU/Cholesky factorization of A + // input: + const SPEX_matrix *b, // Right hand side vector + const SPEX_options* option // Command options + ); +\end{verbatim} +} \end{mdframed} -Upon completion of the above routines, the solution to the linear system is in -a dense \verb|mpq_t| matrix. SPEX allows this to be converted into any form -of matrix in the set of (CSC, sparse triplet, dense) $\times$ (\verb|mpfr_t|, -\verb|mpq_t|, \verb|double|) using \verb|SPEX_matrix_copy|. The following code -snippet shows how to get solution as a dense \verb|double| matrix; since this -involves a floating-point representation, the solution \verb|my_x| will no -longer be exact, even though \verb|x| is the exact solution. +\verb|SPEX_Update_solve| obtains the solution of \verb|mpq_t| type to the +linear system $Ax=b$ upon a valid LU/Cholesky factorization of $A$. + +On input, \verb|SPEX_matrix *x| that \verb|x_handle| points to is undefined; \verb|F| must be a valid LU/Cholesky factorization; \verb|b| must be dense \verb|mpz_t| with same number of rows as \verb|F->L|; and default settings are used if +\verb|option| is input as \verb|NULL|. Upon successful completion, the function returns \verb|SPEX_OK|, and the dense \verb|mpq_t| matrix \verb|x| +contains the solution to the linear +system $Ax=b$. \verb|F| is mathematically unchanged on output. However, if \verb|F| is non-updatable on input, it is converted to updatable. If \verb|F| is already updatable, it is not modified. +In case of failure, \verb|x| is returned as \verb|NULL| and the appropriate error code is returned. -{\small -\begin{verbatim} - SPEX_kind my_kind = SPEX_DENSE; // SPEX_CSC, SPEX_TRIPLET or SPEX_DENSE - SPEX_type my_type = SPEX_FP64; // SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 - SPEX_matrix* my_x = NULL; // New output - // Create copy which is stored as my_kind and my_type: - SPEX_matrix_copy( &my_x, my_kind, my_type, x, option);\end{verbatim} } %------------------------------------------------------------------------------- -\cprotect\subsection{Freeing memory} -\label{s:Using:free} +%\cprotect\subsection{\verb|SPEX_Update_tsolve|: Solve $A^Tx=b$ with the updatable factorization} +\subsection{\texttt{SPEX\_Update\_tsolve}: Solve transposed linear system with the updatable factorization} \label{ss:SPEX_Update_tsolve} %------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_Update_tsolve // solves A^T x = b + ( + // Output + SPEX_matrix **x_handle, // rational solution to the system + // input/output + SPEX_factorization *F, // The updatable LU/Cholesky factorization of A + // input: + const SPEX_matrix *b, // Right hand side vector + const SPEX_options* option // Command options + ); +\end{verbatim} +} \end{mdframed} -As described in Section \ref{s:user:memmanag}, SPEX provides a number -of functions/macros to free SPEX structures: - -\begin{itemize} -\item \verb|SPEX_matrix*|: A \verb|SPEX_matrix* A| data structure can be freed -with a call to \verb|SPEX_matrix_free(&A, NULL) ;| -\item \verb|SPEX_LU_analysis*|: A \verb|SPEX_LU_analysis* S| data structure can -be freed with a call to \verb|SPEX_LU_analysis_free(&S, NULL) ;| +\verb|SPEX_Update_tsolve| obtains the solution of \verb|mpq_t| type to the +linear system $A^Tx=b$ upon a valid LU/Cholesky factorization of $A$. -\item All others including \verb|SPEX_options*|: These data structures can be -freed with a call to the macro \verb|SPEX_FREE()|, for example, -\verb|SPEX_FREE(option)| for \newline -\verb|SPEX_options* option|. +On input, \verb|SPEX_matrix *x| that \verb|x_handle| points to is undefined; \verb|F| must be a valid LU/Cholesky factorization; \verb|b| must be dense \verb|mpz_t| with same number of rows as \verb|F->L|; and default settings are used if +\verb|option| is input as \verb|NULL|. Upon successful completion, the function returns \verb|SPEX_OK|, and the dense \verb|mpq_t| matrix \verb|x| +contains the solution to the linear +system $A^Tx=b$. \verb|F| is mathematically unchanged on output. However, if \verb|F| is non-updatable on input, it is converted to updatable. If \verb|F| is already updatable, it is not modified. +In case of failure, \verb|x| is returned as \verb|NULL| and the appropriate error code is returned. -\end{itemize} -After all usage of the SPEX routines is finished, \verb|SPEX_finalize()| -must be called (Section \ref{ss:SPEX_finalize}) to finalize usage of the -library. +%------------------------------------------------------------------------------- +\section {SPEX Update Helper Functions} +%------------------------------------------------------------------------------- %------------------------------------------------------------------------------- -\cprotect\subsection{Examples} -\label{s:Using:Examples} +\subsection{\texttt{SPEX\_Update\_matrix\_colrep}: Swap the columns of a matrix} \label{ss:SPEX_Update_matrix_colrep} %------------------------------------------------------------------------------- +\begin{mdframed}[userdefinedwidth=\textwidth] +{\footnotesize +\begin{verbatim} + SPEX_info SPEX_Update_matrix_colrep// performs column replacement + ( + // input/output + SPEX_matrix *A, // m-by-n target matrix of SPEX_DYNAMIC_CSC + SPEX_matrix *vk, // m-by-1 SPEX_DYNAMIC_CSC matrix that contains + // the column vector to replace the k-th column + // of A + // input + int64_t k, // The column index that vk will be inserted + const SPEX_options *option// Command parameters + ); +\end{verbatim} +} \end{mdframed} -The \verb|SPEX/SPEX/SPEX_Left_LU/Demo| folder contains three sample C codes -which utilize SPEX. These files demonstrate the usage of SPEX as -follows: +\verb|SPEX_Update_matrix_colrep| simply serves as a helper function in the column-replacement scenario where users wish to obtain the matrix after one of its columns is replaced. It should be noted that this does {\bf NOT} update the factorization of \verb|A|, and thus users should call \verb|SPEX_Update_LU_ColRep| to update the REF LU factorization for column replacement. To be more specific, this function swaps column \verb|k| of the matrix \verb|A| with column of \verb|vk| (i.e., swaps \verb|A->v[k]| and \verb|vk->v[0]|). Therefore, both \verb|A| and \verb|vk| are modified by this function, which requires users to call this function {\bf BEFORE} using \verb|SPEX_Update_LU_ColRep|. -\begin{itemize} -\item \verb|example.c|: This example generates a random dense $50 \times 50$ -matrix and a random dense $50 \times 1$ right hand side vector $b$ and -solves the linear system. In this function, the \verb|SPEX_Left_LU_backslash| -function is used; and the output is given as a double matrix. +On input, \verb|A| and \verb|vk| must be matrices of \verb|SPEX_DYNAMIC_CSC| kind with the same number of rows $m$; \verb|k| is the index of the column of $A$ to be replaced and thus must be in the range of $[0,m-1]$; and option contains command parameters (default settings are used if \verb|option| is input as \verb|NULL|). -\item \verb|example2.c|: This example reads in a matrix stored in triplet -format from the \verb|ExampleMats| folder. Additionally, it reads in a -right hand side vector from this folder and solves the associated linear system -via the \verb|SPEX_Left_LU_backslash| function, and, the solution is given as a matrix -of rational numbers. +This function requires that the rows of \verb|vk| are in the same order as that of \verb|A|. In addition, \verb|vk| and \verb|A| are scaled with the same factor, i.e., \verb|vk->scale = A->scale|, while \verb|vk->v[0]->scale = 1|. (Users can refer to section \ref{ss:SPEX_matrix} for the difference between \verb|vk->scale| and \verb|vk->v[0]->scale|.) Different from \verb|SPEX_Update_LU_ColRep|, this function does not require \verb|A| to be a square matrix, as long as it has the same number of rows as \verb|vk|. -\item \verb|spexlu_demo.c|: This example reads in a matrix and right hand side -vector from a file and solves the linear system $A x = b$ -using the techniques discussed in Section \ref{s:Using:expert}. This file also -allows command line arguments (discussed in \verb|README.md|) and can be used -to replicate the results from \cite{lourenco2019exact}. +On output, \verb|A->v[k]| and \verb|vk->v[0]| are simply swapped. +} -\end{itemize} %------------------------------------------------------------------------------- -\cprotect\section{Using SPEX Left LU in MATLAB} -\label{s:Use:MATLAB} +\chapter{Using SPEX in MATLAB}\vspace{-0.75in} \label{s:Use:MATLAB} %------------------------------------------------------------------------------- - -After following the installation steps discussed in Section \ref{s:install}, -using the SPEX Left LU factorization within MATLAB can be done via the -\verb|SPEX_Left_LU_backslash.m| function. First, this section describes the +The MATLAB interface of SPEX can be installed by navigating to the \verb|MATLAB| folder and typing \verb|spex_mex_install|. +Doing so installs SPEX and allows the use of 3 mex functions \verb|spex_lu_backslash.m|, \verb|spex_cholesky_backslash.m|, and \verb|spex_backslash.m|. First, this section describes the \verb|option| struct in Section \ref{s:Use:MATLAB:setup}. The use of the factorization is discussed in Section \ref{s:Use:MATLAB:factor}. -The \verb|SPEX/SPEX/SPEX_Left_LU/MATLAB| folder must be in your MATLAB path. +The \verb|SPEX/SPEX/MATLAB| folder must be in your MATLAB path. + %------------------------------------------------------------------------------- -\cprotect\subsection{Optional parameter settings} -\label{s:Use:MATLAB:setup} +\section{Optional parameter settings} \label{s:Use:MATLAB:setup} %------------------------------------------------------------------------------- - -The SPEX Left LU MATLAB interface includes an \verb|option| struct as in optional +The SPEX MATLAB interface includes an \verb|option| struct as in optional input parameter that modifies behavior. If this parameter is not provided, default parameter settings are used. The elements of the \verb'option' struct are listed below. Any fields not present in the struct are treated as their default values. \begin{itemize} - \item \verb|option.pivot|: This parameter is a string that controls the pivoting scheme used. When selecting a pivot entry in a given column, the -factorization method uses one of the following pivoting strategies: +factorization method uses one of the following pivoting strategies. Note that +importantly this is only valid for LU factorization: \begin{itemize} - \item \verb|'smallest'|: smallest pivot, + \item \verb|'smallest'|: (default) smallest pivot, \item \verb|'diagonal'|: diagonal pivot if possible, otherwise smallest pivot, \item \verb|'first'|: first nonzero pivot in each column, - \item \verb|'tol smallest'|: (default) diagonal pivot with a tolerance (\verb|option.tol|) + \item \verb|'tol smallest'|: diagonal pivot with a tolerance (\verb|option.tol|) for the smallest pivot, \item \verb|'tol largest'|: diagonal pivot with a tolerance (\verb|option.tol|) for the largest pivot, @@ -2161,21 +2741,19 @@ \subsubsection{Converting the solution vector to the final desired form} \end{itemize} \item \verb|option.order|: This parameter is a string controls the -fill-reducing column preordering used. +fill-reducing column preordering used. This is valid for either LU +or Cholesky as Backslash will choose its own ordering. \begin{itemize} \item \verb|'none'|: no column ordering; factorize \verb'A' as-is. - \item \verb|'colamd'|: COLAMD ordering (default) - \item \verb|'amd'|: AMD ordering + \item \verb|'colamd'|: COLAMD ordering (default for LU) + \item \verb|'amd'|: AMD ordering (default for Cholesky) \end{itemize} -The \verb|'colamd'| is recommended for most cases. The \verb|'AMD'| ordering -is suitable if the nonzero pattern of \verb'A' is mostly symmetric. In this -case, \verb|option.pivot = 'diagonal'| is a useful option. - \item \verb|option.tol|: This parameter determines the tolerance used if one of the threshold pivoting schemes is chosen. The default value is 1 and this -parameter can take any value in the range $(0,1]$. +parameter can take any value in the range $(0,1]$. This is only valid +for LU factorization. \item \verb|option.solution|: a string determining how \verb|x| is to be returned: @@ -2204,31 +2782,101 @@ \subsubsection{Converting the solution vector to the final desired form} \item \verb|option.print|: display the inputs and outputs (0: nothing (default), 1: just errors, 2: terse, 3: all). +\end{itemize} + + +%------------------------------------------------------------------------------- +\section{SPEX m files for use} \label{s:Use:MATLAB:factor} +%------------------------------------------------------------------------------- + +%------------------------------------------------------------------------------- +%\cprotect\subsection{\verb|SPEX_Left_LU_backslash.m|} +\subsection{\texttt{spex\_lu\_backslash.m}} +%------------------------------------------------------------------------------- +The \verb|spex_lu_backslash.m| function solves the linear system $A x = b$ where +$A \in \mathtt{R}^{n \times n}$, $x \in \mathtt{R}^{n \times m}$ and $b \in +\mathtt{R}^{n \times m}$. The final solution vector(s) obtained via this +function are exact prior to their conversion to double precision. + +This function expects as input a sparse matrix $A$ and dense set of +right hand side vectors $b$. Optionally, \verb|option| struct can be passed in. +Currently, there are 2 ways to use this function outlined below: + +\begin{itemize} + +\item \verb|x = spex_lu_backslash(A,b)| returns the solution to $A x = +b$ using default settings. The solution vectors are more accurate than +the solution obtained via \verb|x = A \ b|. The solution \verb|x| is +returned as a MATLAB double matrix. + +\item \verb|x = spex_lu_backslash(A,b,option)| returns the solution to $A x = +b$ using non-default settings from the \verb|option| struct. \end{itemize} +If the result \verb|x| is held as a MATLAB double matrix, in conventional +floating-point representation (\verb|double|), it is guaranteed to be exact +only if the exact solution can be held in \verb|double| without modification. + +The solution \verb|x| may also be returned as a MATLAB \verb|vpa| array, or as +a cell array of strings; See Section \ref{s:Use:MATLAB:setup} for details. + + %------------------------------------------------------------------------------- -\cprotect\subsection{\verb|SPEX_Left_LU_backslash.m|} -\label{s:Use:MATLAB:factor} +\subsection{\texttt{spex\_cholesky\_backslash.m}} %------------------------------------------------------------------------------- +The \verb|spex_cholesky_backslash.m| function solves the linear system $A x = b$ where +$A \in \mathtt{R}^{n \times n}$, $x \in \mathtt{R}^{n \times m}$ and $b \in +\mathtt{R}^{n \times m}$. The final solution vector(s) obtained via this +function are exact prior to their conversion to double precision. Note that +A must be SPD otherwise this function returns an error. + +This function expects as input a sparse matrix $A$ and dense set of +right hand side vectors $b$. Optionally, \verb|option| struct can be passed in. +Currently, there are 2 ways to use this function outlined below: + +\begin{itemize} + +\item \verb|x = spex_cholesky_backslash(A,b)| returns the solution to $A x = +b$ using default settings. The solution vectors are more accurate than +the solution obtained via \verb|x = A \ b|. The solution \verb|x| is +returned as a MATLAB double matrix. + +\item \verb|x = spex_cholesky_backslash(A,b,option)| returns the solution to $A x = +b$ using non-default settings from the \verb|option| struct. + +\end{itemize} + +If the result \verb|x| is held as a MATLAB double matrix, in conventional +floating-point representation (\verb|double|), it is guaranteed to be exact +only if the exact solution can be held in \verb|double| without modification. + +The solution \verb|x| may also be returned as a MATLAB \verb|vpa| array, or as +a cell array of strings; See Section \ref{s:Use:MATLAB:setup} for details. -The \verb|SPEX_Left_LU_backslash.m| function solves the linear system $A x = b$ where + +%------------------------------------------------------------------------------- +\subsection{\texttt{spex\_backslash.m}} +%------------------------------------------------------------------------------- +The \verb|spex_backslash.m| function solves the linear system $A x = b$ where $A \in \mathtt{R}^{n \times n}$, $x \in \mathtt{R}^{n \times m}$ and $b \in \mathtt{R}^{n \times m}$. The final solution vector(s) obtained via this function are exact prior to their conversion to double precision. -The SPEX Left LU function expects as input a sparse matrix $A$ and dense set of +This function expects as input a sparse matrix $A$ and dense set of right hand side vectors $b$. Optionally, \verb|option| struct can be passed in. +If A is numerically symmetric, it attempts a Cholesky factorization. If the Cholesky +fails or if the matrix is not numerically symmetric it performs an LU factorization. Currently, there are 2 ways to use this function outlined below: \begin{itemize} -\item \verb|x = SPEX_Left_LU_backslash(A,b)| returns the solution to $A x = +\item \verb|x = spex_backslash(A,b)| returns the solution to $A x = b$ using default settings. The solution vectors are more accurate than the solution obtained via \verb|x = A \ b|. The solution \verb|x| is returned as a MATLAB double matrix. -\item \verb|x = SPEX_Left_LU_backslash(A,b,option)| returns the solution to $A x = +\item \verb|x = spex_backslash(A,b,option)| returns the solution to $A x = b$ using non-default settings from the \verb|option| struct. \end{itemize} @@ -2240,10 +2888,114 @@ \subsubsection{Converting the solution vector to the final desired form} The solution \verb|x| may also be returned as a MATLAB \verb|vpa| array, or as a cell array of strings; See Section \ref{s:Use:MATLAB:setup} for details. + +%------------------------------------------------------------------------------- +\subsection{\texttt{spex\_mex\_demo.m}} +%------------------------------------------------------------------------------- +This function provides a demo of the SPEX library. It shows the usage for an exact +solution as well as error checking and tuning the parameters. The typical output +of this function may be seen in the provided \verb|MATLAB/html| folder. + + + +%------------------------------------------------------------------------------- +\chapter{Using SPEX in Python}\vspace{-0.75in} +%------------------------------------------------------------------------------- +The Python interface of SPEX can be installed by navigating to the Python folder and typing make. Doing so allows the use of the Python SPEX library. First, this section describes the \verb|Option| object in Section \ref{s:Python:option}. The use of SPEX to solve $Ax=b$ is discussed in Section \ref{s:Python:Funcs}. + + +%------------------------------------------------------------------------------- +\section{Optional parameter settings}\label{s:Python:option} +%------------------------------------------------------------------------------- +The SPEX Python interface includes an object as an optional input parameter that modifies behaviour. If this is not provided, default parameter settings are used. +\begin{itemize} + \item output: This parameter is a string that determines how the solution is to be returned + \begin{itemize} + \item \verb|'double'|: \verb|x| is converted to a 64-bit + floating-point approximate solution. This is the default. + \item \verb|'string'|: \verb|x| is returned as an array of strings. + \end{itemize} + \item ordering: This parameter is a string that controls the fill-reducing column preordering used. By default it is initialized as None, if this option is chosen, the solve functions use the appropriate default ordering (AMD for Cholesky and COLAMD for Left LU). + \begin{itemize} + \item \verb|'none'|: no column ordering; factorize $A$ as-is. + \item \verb|'colamd'|: COLAMD ordering + \item \verb|'amd'|: AMD ordering + \end{itemize} +\end{itemize} + + +%------------------------------------------------------------------------------- +\section{Functions in Python SPEX}\label{s:Python:Funcs} +%------------------------------------------------------------------------------- + +%------------------------------------------------------------------------------- +\subsection{\texttt{lu\_backslash}} +%------------------------------------------------------------------------------- +The \verb|lu_backslash| function solves the linear system $Ax=b$ where$A \in \mathtt{R}^{n \times n}$, $x \in \mathtt{R}^{n \times 1}$ and $b \in \mathtt{R}^{n \times 1}$. The final solution vector(s) obtained via this function are exact prior to their conversion to double precision. + +The LU function expects as input a \verb|scipy| sparse matrix $A$ and a right hand side vector $b$. Optionally, \verb|option| object can be passed in. +Currently, there are 2 ways to use this function outlined below: + +\begin{itemize} + \item \verb|x=SPEX.lu_backslash(A,b)| returns the solution to $A x = b$ using default settings. The solution \verb|x| is returned as a \verb|numpy| double array. + \item \verb|x=SPEX.lu_backslash(A,b,options)| returns the solution to $A x = b$ using non-default settings from the \verb|option| object. +\end{itemize} + +If the result \verb|x| is held as a \verb|numpu| double array, in conventional floating-point representation (\verb|double|), it is guaranteed to be exact only if the exact solution can be held in \verb|double| without modification. + +The solution \verb|x| may also be returned as a list of strings; See Section \ref{s:Python:option} for details. + + +%------------------------------------------------------------------------------- +\subsection{\texttt{cholesky\_backslash}} +%------------------------------------------------------------------------------- +The \verb|cholesky_backslash| function solves the linear system $Ax=b$ where$A \in \mathtt{R}^{n \times n}$, $x \in \mathtt{R}^{n \times 1}$ and $b \in \mathtt{R}^{n \times 1}$. The final solution vector(s) obtained via this function are exact prior to their conversion to double precision. Note that $A$ must be symmetric positive definite. + +The Cholesky function expects as input a \verb|scipy| sparse matrix $A$ and a right hand side vector $b$. Optionally, \verb|option| object can be passed in. +Currently, there are 2 ways to use this function outlined below: + +\begin{itemize} + \item \verb|x=SPEX.cholesky_backslash(A,b)| returns the solution to $A x = b$ using default settings. The solution \verb|x| is returned as a \verb|numpy| double array. + \item \verb|x=SPEX.cholesky_backslash(A,b,options)| returns the solution to $A x = b$ using non-default settings from the \verb|option| object. +\end{itemize} + +If the result \verb|x| is held as a \verb|numpu| double array, in conventional floating-point representation (\verb|double|), it is guaranteed to be exact only if the exact solution can be held in \verb|double| without modification. + +The solution \verb|x| may also be returned as a list of strings; See Section \ref{s:Python:option} for details. + + +%------------------------------------------------------------------------------- +\subsection{\texttt{backslash}} +%------------------------------------------------------------------------------- +The \verb|backslash| function solves the linear system $Ax=b$ where$A \in \mathtt{R}^{n \times n}$, $x \in \mathtt{R}^{n \times 1}$ and $b \in \mathtt{R}^{n \times 1}$. The final solution vector(s) obtained via this function are exact prior to their conversion to double precision. Note that $A$ must be symmetric positive definite. + +The Backslash function expects as input a \verb|scipy| sparse matrix $A$ and a right hand side vector $b$. Optionally, \verb|option| object can be passed in. If A is numerically symmetric, it attempts a Cholesky factorization. If the Cholesky fails or if the matrix is not numerically symmetric it performs an LU factorization. +Currently, there are 2 ways to use this function outlined below: + +\begin{itemize} + \item \verb|x=SPEX.backslash(A,b)| returns the solution to $A x = b$ using default settings. The solution \verb|x| is returned as a \verb|numpy| double array. + \item \verb|x=SPEX.backslash(A,b,options)| returns the solution to $A x = b$ using non-default settings from the \verb|option| object. +\end{itemize} + +If the result \verb|x| is held as a \verb|numpu| double array, in conventional floating-point representation (\verb|double|), it is guaranteed to be exact only if the exact solution can be held in \verb|double| without modification. + +The solution \verb|x| may also be returned as a list of strings; See Section \ref{s:Python:option} for details. + + +%------------------------------------------------------------------------------- +\section{Demo} +%------------------------------------------------------------------------------- +There is a file that provides a demo of the SPEX library in Python \verb|demo.py|. It shows the usage for an exact +solution as well as tuning the parameters. + + %------------------------------------------------------------------------------- % References %------------------------------------------------------------------------------- + + + \bibliographystyle{siam} \bibliography{SPEX_UserGuide.bib} \end{document} diff --git a/SPEX/Doc/SPEX_version.tex b/SPEX/Doc/SPEX_version.tex index 041cc55a18..7120d15bd7 100644 --- a/SPEX/Doc/SPEX_version.tex +++ b/SPEX/Doc/SPEX_version.tex @@ -1,2 +1,2 @@ % version of SuiteSparse/SPEX -VERSION 2.3.2, Jan 20, 2024 +VERSION 3.1.0, Feb XX, 2024 diff --git a/SPEX/Doc/appendix_A.pdf b/SPEX/Doc/appendix_A.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2781a79dd7525dec1985cfd5c0cf198bf87278e6 GIT binary patch literal 100257 zcmb5VWmHse_%1wjryw0lmvl-DARy8m(p>@)(j_UPAl)e)L#i~AA~AGINp}n|z%awR z{r%5b>s{+TAI{6Cz4kn7?|a{IUH5%G4{X{ml=%doiQ=+WB(I0!KA|$@zFDD z)+)Z~iJhMZF_CZo4Shl-*OBB{u+|lFJ`1lh;p9npbNTmpMS+GTc={RbZnT*D`SrW= zk&B#a*V5+Kq2JfKp4TwVwQufp8!7Y68_f?6&1#j;IybG=GHzDQA8t->?)zUYFBf#( zb(v$5(XROHj|{XJ7SD2*-CtLUj?A7W9c3=6TEyG>xo5EFc5d2$`=f3|txDMt^h_PMyMm#b^9 z@oP1Bg(*JMXN?@1-l<<)8S>)Fp&WI2@+pSpP9`jENrt~8xmVto1W{4#%5Z;S{ou2g zp1qBFRwpTa{5O8up*@E1D(&g9S9{lr^qWmtCKwHgs^lTbJ%el^t){ts2a^kCw(HAl znjerA_p}4GkmF|0Z+s(ND@Scn`I-!qv6&_}30cw6yiILHBb(n8>lm5ZYu|iXJE`F9 zKD!DComZ^l4$Ymm{cJ5ytWnhHg5BYi+82nr3s7|0+m!XddAa|iYw^@QvC=0*W3MpU z`N~9m@1vXCH?8}}uo=jSFv9Wvv07+pI-*YD4!^#x0+Q@mngvmh_~sbM6(ym9$&mm9JR=Tx&gBk{aA zlJn)trq;vy-|{ANZ?_@3i+v4x29+qaDGIUGBc_6H?Y4jXyNAVz@G7?5TQpQ97lQ~~ z#kH&3m#<=Pj!){>218cwDdaqil5%F>?xnLRtSMk92rQp6_lfPZ84-CO6Newg8bI=_&6yFYt(BEpO036*6)d|u@njI!SN5gIi< zM}^hZd3YAuDtD!^bh`X3u>o{=?D@<2ftrdnwdBj##q5Fq!Cj^KyDLtExil+&x%3r@ zB=DNkFzTJLT%G1XnK4;?B_uA?z|!aD9_|p*zFPOLj~MS9p8`>R%9BSJWjjB2vkgT| zJ7Fn;_XZ+x={6m|XJQUQ&SA(tcG1AFo;EqK8g4%vp=i`v9(ycUCslU}IW-iZAIvj~ zO}#$eaoDpr&!&sBNPBM2YD`xUA$V$oELhf2}YP8*zUQ7cc+e%IjKiGt~G_ z)yMugqqq<;WZh>i!@cK>+?a{|Ma93?bz@ucB#m81jB_K;{Y8%1pI+sc3Yinn zR^jdLRC6Xp?c70T9RcT1Xj%+OZ#1|Rt$pa7gqETjPpYV|voYIOA7AHY(`GUKQfp?W zqS|T_43_#v4FlS_ph=YF@f38yJF)G=npH&0HOd9&lSRhl$ins^^`Nx?O|So=wfS=I zQA?f8#kfOtyQ@7uQEsQPkzT`Z%nii5^y26bA@oTI9g(>$XmvxjdfUt{xSH8?e}w)> zImw9%gPhy&_L{I2;ffhAHK+I~wHL=op?i6VOGi}$U08bqb6&1`#r^SBZv5|gz1kTC z=hwQim5(kft=-Xj-%bCCRg|+0OD~|1rM|$hE@^S}eRwMilhy`fNI<7L^R9X&4T@vA z9+4F}L=KfiMqSr@5}0-FA%3IHtMj|1_x+C$Hd>AkJ^CcGzwy|7@!oWNf8l0RD7Els zp{bbGgO4nay8dTBXRfVGZdCWZF3nSg*%TsN^6aK>1`6W*-Kj)mr3b@v*hRf2S!oo8 z2;wXo+Ts<^qh;nDScN(xfxgY{QT1f_MDjO3za(uSKkaN9No zDfw8sISNUr-~52iy(E_-Wz+p-LdQQQ)Hd4HlY*ECSgsF8g449^pD>f(30vtrkRL|Q zN1+JKX5@BFt)C-Bi+~627o_9~;9rVIp|0$f3ov4m3C(NSjtVqFLiq$&KaTQqNYzHq zw2l5+R2n$1KMQD_?zt~~<6wugIdF88&`&^F_{`sdK)d$S6g59R8UH~Mm&MjZrT@?H z0e>AEj=xwKRGUiUq5_uLaa31Z6#QNnSm(w0xqp>3iEZ3yv;Pjb9n|=Laoj5QKM!b( zJpcRm$f_eVFYk;0lg^}k$51qU@$sSi!v+(Nc&e)jpLbsrKc!{kQW5GCQb`)nICnhl z1zymnq%%-R9Q82<_ung?#RtaBM7VwM)X~!1c*^mev?30;)Zn0!q%6D5mT0vq{5w2= zrJoumcGY^%9{wWUz7aHp%m0?y`)>L|7_5UrKj;uINH2(#GBe_>un1870gYhz!(U&& zw_k~lL9@dD>(w4eFZz1=L^x>@*(5Y_<_xE)*b9}%A{Z-Q*)1eKu~cCAQ=rB0w!58V zv?O%7hl4nVoAkg)IOSGydaohJa`--wGrmBPZaz>Y&QeS1)SEluHk%Q4_)`^8Y#tpG z&LUG3A}V205ZOun97}!9NHOJ7GPNtC2c)#iA6^XeE@Jr|0-?O%3oMk6cdEaZCaqGSU;m*fbnr@*O+Ik|IG_*uZyk<2V=}rjExW($qxl7odW%7 zXxJ`7a^+KcA;jEOVQ7@I1sV)**RYBLW;_ZZbOr9!kN%g*G#W(kD{Tt7Sg|_17}DJ7x^b+MeOuNT<+oTtimd^kLeNUnK) zD*C^yrIVNW`3tPEvpa(aqp7GsVd?9KiTU=2Y=TCLyPTCKh{i8Jlw%)c4d3VPmwHFt z0@ikOR;2R1#Yu|zXDu78_*(-AZEiF4r)OvpM>7PQ|62rdlz1Ppy8OSLW zhDMQBK)|45L1%56zhNQ%)So_pPxR0HKll461Ok4wr11UE)B;=i_a~B1w45xpG*@@G z2s$7f9OolKDO4~=J^r@IXBg@=<3blovcKp==MFiSM!IBE=C*?NEGLi!c#o37GXz~8d znGv}*%9=3)F>y3kGa|2lRX&2FQ&&is{|JviftJboS^9;|t_O^heT^ui>CIs5loI~| z1!H%w>P!aLcpXU_c z&X~ZWrCBUlg@)WHtCxdEXhw0EMc}J6+RfI7XFQm9rPhnFh`2Rfr6%0#34AJo=DKv z@Uwu!==kKz(KF2+idZ&>8|Ku$BzbA8(H`|DEVi022(dYp69}a!1*j{i1%#@|O((xI zQ}=LLP^=Go>W~1n?O`TmIvO(`|JX$K8PVec4n=BS2RmHbfg{3C{qciw$`_;jwEX%# zn)a2qN-`o?AL(CNCaxFSGy{&CXOXCG;3f2e@NYUB z1|>v=LjNuh6UX-l<6At+mH&#v_j|Yh4j$=1^T0CI%ywL$gRY$I!MC)iTS9FSxyUNR zLvS3B)91o2MjMxpUJqA3{o9_^(9LSo77k3X88KTV{!Tp~?T1Gv&i__(fNKZU_JH z%8Kp*M1%U5>V2`%7da)XLUx!pH?kQWhjLb~g#5uxs6gs(*EMsU_1iUYIW;PIdu8Ws zm`kU>A2Z75OGKUmc+hZMcT*OFf(48%DwJS8r-oLTzqI1)uAz#2>!(ry?ZK>8n4l8S zxeIhimbG=+s6-H7O>6~Y=TRTi6jt1eP<$#NVi06ZJ?DcuLEZ~6s$kBNR{`a6AgSM8 z#%AVNSbQis+phd5%x*AZU{ZF-bdOG8>AAvfpcn1&$8X0EgW9SJ_kmvI-A-0TabZF> z|MLNI4)pr^0HL)3g!Z@VXpl62(jw5>fHNkj_aV^pLJp@|`H>c4|0wNqsiBG9E#wp^3&24F}OI=87@&fT9t%0gM0kvPcv zN8f1b)c-*I`n5jORG2DmgLx?RH}N(l3+u=>Ix601_Z!F%b2s}{Lo0i;Gb~*crTKfp zm5&KTDrGPzTKEg&J1U02O2-7;wK6!q6Dab7LS*nk+%;okp$T@-EbWF}j~pcnHV|au zORSkdjocY;?bwJe-m28}A2mY}4D5GUj~`nXd%RXa1PWEVX+bpHJ?bNsbes_+iWBm42CEY_H^QRvwpiNICm0kSR^J#N59D z;NJ#v`wNppy{_})Tl3&P{p{0eqf44!T%fJ3^Y5%yAgl1dxpJ}CC6x^T_H*1~rAZI( zhW~X7qm7^X4;%HrKsbTq+xI@`cPog9pRxoi?K|oXef29g@a1RBEl@spIe_gqySMup z3{ip8Ac>zLP+iMSga#smq`UpVVr!94W}Se!Jwt)9J^JX_AA8Mkh3PmQ67yZYFNSHl zoddSZdj9ARBlD1IzV7hx&EQHC2loR`-T*ZrzP-EM{~D};tA9he;QwJd7ZDQ^{=c8j zUwhMkZwOzz;<^6PtcH7%Aw5`{@`~GV`&ZSgs=v|#e@!>=T76#res?=xkZ)dy#oN$H z?|1m2k!z!Gblp|NT{sZ-wnRKExbzVE&?R)H=P^1cQLa0hLtVmM>L&ZA^KMA)YKJ!T zcK4HE-PRZs(H;2xoU4K~JCK^X8fku-^(TWtIt!XE&RPaY z0=fRT4%fG59%||}LLJY3FZA$~*p+^IAhN&TKvu6IwN@#95YmaChAm+FOE2+eq^9{f zz)*p(#E*W<%hlyM1<&4eEm(BD8@KF0G`~izKU-b<^M?Q776pZ@cARokY!v5m)qFgl zdwm(PW^)_uUmYx%yX-1Wfprxp%bhp1aUB|Tb?FHk*$D0G%wEw-jj_aVP5FISf!&VR zD9Ik4;0dGBz}`BU$7@y{j+Mgjle#6l8$+JlNm7bFE*vaQ9%i{ZM)s|EbH_u=10SU> z%2j{9Td`cbM^2RGKURS+g+d~`+82M42v=%l8k*VMVXYJSZAiSI>8 zGUbz@8aHW|)v(s3kee&impHxZpRhfveIbj-HaF1{wFzo965E9g2wWxkFLO-po14dp zT8R%&iXRoY*6KNYHFZQM%g4+l&5!qEnGHAifWfq$hc=FEs9GdB98Y`d4vCoue>A)Bmz*XS|)Xbp(4j>PL2Av zr>n1<_`NJ)iOYFUYIgN%qa87o2=yHaiaJ5f&TERFCfUiCU=8C+X=7y9TJ21@8(4)( z)ybm-g`Cn%@x5^E)3onVXTiMqYqp~Ikm+6maP`@47U#Xo-V1+*C!a@rF12e*O&HtE z@^IH~CzeLwFZBpZ+d)nHt9p69rKD}J2IBaak_^@cUTXYW68zxL>-R!4^!YX1*JJah zkN(1jIZ>Wt#O_>AWSKtxg&QYL6g;*BnGVQ7Uz{5$7JOuiHxi@4J6BXqdfy^DA3gn- z08H|i{K8w^7pSIu~SG?};ubcaV_GCog3ziAs%kTE?g+@oz2n%p1|sD{f-#+dL&tr7_2 zz-4BQcRvtYf!mY0kI*%iXnLf&w54niuh`PwDfJ`ID$%M(|9YuY}ebPm( z_)^?@YB@`ZurS!!M(nEa zq<>ej`UXQ6$0hSgkK13kKApyJ)J-sN{F-gXNA&X#1B!TFkHUUf*@sK#h$)}n+EIl0 z_avF=$^1_OcvmX() zK3vaLtt-`hCu0oyWaMW=0#Af6Ra7d8{RmvM{lwB9EZYcF#)giuiW9WVCU#9P zg7xceG=7X{ zzLxTSkeA_S+GSX!Q;62=gq_xFAgh*`1S`{`W+!%6`TdA0$d_EJYbwtV&i4;0`wQ-! z;kWBmp^3iQS;2nBDFqJ~Hf^ zt;aanUaa$%m=%1ag!;Aj`@-nt6N;=7HsdjM)OY|)6@lD6$t9nzPba4jh&7$!UM-Hk z16x@EDY-)+;5siSQ0td{7NTqCc|pL-E1cr#Eb47Fft)j$*-VN@ zPo$YX4#JHIH0<)dOU}`^%I-aXCS{EK5fxno3rWd|aCy0Cg~w09_4h)wpvS7<>Z{!> zCnNxWh(d!or58a?o^><+zJ6ifSNK{{)8)^rhIThyG50nmY%0_(!xx`|wM4DE-V`Z; zWWO=s(bsQ%0pmHzkoz+N08+FULPGSL3=xG@0X#hVsb&F5Qn=wMRCw}Vj>0`FO&qwO z{HHI@L~W33@BEPUNbslA+pVf#s3?~XEC_wHELh8TmBOa44)m>dgJhxjy`@x$OS~4y zeEtkaq&0>g1e9w<>=fQPkO^V_Ke+Sr=Q6?#&w(Pi2VQV9^7iA?>5b>L!R{EVmAGR8 zvdvO!EJefiy#Z(rQF5otzADie*ZFeN#-$jYwp!r{OYklG zQ&5piLHrV2pW68m><)dR3P~nRz66QUY!+98vrVt%)F=dPE_XB5eJbc;!(Z7=c`Mt^ zk+b)-Aw&gzc?X8$Hn*sU5h6>40fx4m9SXy40b~OydtEs0z;5jbK{AUP2K}I(avRWI zk+vJi?f z$LHM)GXPr%oFi*Gh6ZP&_kWH~hb^4dJa)*KOOP_R3CLjXr8T`G+^2_B;f4sn_b8yq zuG2=N}7dzf+5QOGF9lBoSv^N}r=h@PQ zGt{?(W;0(0`k^W(!b$ldHB9DGySHy>Y=h(!3tC40|KK&ZV1gk!)Czt&f?JpYvgLBr;ZQg@HrnX9n(vNsCGx?0^ z_4b{9;@CFt{nT8vC(D-@;+J>d_#1aL-cKM)vpFzPmC7>rFt2BXmC*In%4uauK{
FP^>Sswx*ZA#U4TRnhonN$!QOz47Z@?XgX5kjLDnr++yM_ijeg#V2FrZaG6 zl_u9|{qlVPwSKNj@l|!!qeDe)_TQ}dPpT zs6*ZJ8#6Gc5K|I+JDF~HgdCMKpPi{e%3N}-Se@-&Dt~IEXT*jdqSW>37%Y^<8JvaR z@?ztM0>3JS;k*;MkhBlFGP};1&MXx@vg1g&E$l}pdoMPVS>K>z&G$)CdByMr-6*KK ztws?#Hd8!JuOsIrpS3D!MF1|Ery8kjHPT z$(n>FpYW@sW%^#v9C%9JOsEZ-5UpG?(YZ4j8n@J%-Y}e44S*08bv1v0I?q?ZCZ=Vv z-wn6TmNcLL4w7vSTw@UqaDVxJvE#II_0A6We_D${m?Aow7p#jTC*}01;_0p3Whkp2 z6D?^Wc9H^<;{K`yC|i_J>bG#!6HW4(A48y0;x@wm@}xy$HeTGUBieXC~y)$R|HrO-Om#K@9J zsUdunwlW)|akOwu&@d-rzuJO=v^oRK-kYR+j&ND;j)UalS}iyC#u+?|M5Zsy z@BEZPbH6;xfgC*99lR=(R6arV3<>Df0V3Hjs;SV0vb+MYGvE>K$UFI&{y0qQ9 zl^={qfQ}RG?+c;dmguvIz1hgD@k48|+k3poy$q%lRL4h@6`RT|oh|q)r z<^H%(#;GcyaR;vHUHSM=cL0TdnwZ%yyK@DguCvKv>i)T&w$wK~Y{iabb&zT2=@-xE zar&131?3}L-x6pj;4;@(s{m`mWp1(l>jXWkolkG|FT2Xe8QfL@li(`qHi6bMK7VBh zUq_B|sK3FaJXg&4{QLZN;vgjPs~_DrXKw7410ol0((7*% zDKgCqw;4u)4rhQMHt71UU+61{vMD4erwHF zw|D)WU$|J6C`UYA2Yq{&we^>hEIIy<(C_3bY(tun^gq-x)r3yv+^!BZ1Bw;5e2Lqw zS4sQ3gx}d*oiJkOQ0_rNSIy0P!A_H?zboY{Mb6#btvR_DA9^Mt;K6rg*z-dkkb8x~ z9N*7yG3;(avUTerOp~CHFQea$v`ECe=}&f-s~3@Ozt4EA82;e?_+5nFj@LlL93t$%hW^j~#+KJKL8uvQ5Lw(rbR@;f~;O z`OUOFpm!cZ;E69%O^Nb{uvthg7wmhIYVE!Vrs7%4eSLn@)){mk5NcX7$S%9kWqoHdZ-x{#>_(QS zpn?RlLXIFg^Yeb(o*^5|y@rv(m^cvn%wx3A7142^>dF+{`Wl&E!I;0p6B|1Fb~X;U za?=Y)%m-Qa<4j)uH(W5f)O`D*4Kxo|LA-Xs+cV-8)ptOD7^)R>t|QyfS6m6@D7ots zJ>1_>*8gu+jbRi2Qt=)7Oc^SGyQ(`|N@tDNGM!Rztw$?w=_}~+zCczp(cKWaxNfg0 znkMr8Q({v-8V0Cf>Hf4*_C*fv!=nC7*bl?fO&a9wxs(hxePA9M;4J1ni%Zw#~Osm31^D;DW3*FbrV_d>Q<0gzQ#n$2fAVZ1$ ze-DX>Nc{gfB=S0uUd2m!?Uv_G$Mk(`KzGMdAr|CKZ#wQm&x!14GRu2x$C#%oQ#N6p zC2c(KzlfSl@;aU=v5Mr%rp@|xb?93h?XL{yhx$9r%Y_B(tZM~%aZtVIYR&f=FKc-h z=nX%DhP9M`KkJjrtHGej|u;>Z~Tnn2D50_U$aVxWPH)kAQ7^%0U6igO3oIJo;)! zY&dJ0=I&~uf4T66pWd?GCLM;IdY)nguQHK8&0 z_&eYz%ZeU%fSlGR#(ZcS*P+(K?M2wL#F@?Fy~U;O1v|OEus`cw0tyt*aJmNOyuu_O zkf`h9sQ1GT6G=gIsuUrkV`PTh<{`QRO7VSkkan3a zw}{@;;K&h`Uh$?F%>D<+X~#-pc|aq{cr z$FX3!@Ud^5MVUtPN~trjhF1?p(9q(ouiUagjZnAeI}O`we?mc{kz61N2@?*iaCAzH zaJ^0<3;gf^UM$d%!=tH@-Jb+#h2TNZ`j$&a*zF%RGy$zL(7IjywEYv%P6Gvqp1@BI z4_Gk(TF@>b1;tiIg6e6yUgfcezbR{*zzSa@2@j};FQys>*2CUVWT%4gjnzS)Kg}+& zv-U`*lNa*THfWP2K20PCM@2OgCHmdMSS zh`ZUG^~U%+Uz%}K#ly|m9MY<-2We`a2jU}_kA}D)EVmfY%Qul%Pn3(0ke*W9y&q?+ zVDS!oGQd~3>vklap3Ff{(07I@&=_dkD=E-m#_{1O!(Gl7fR9C1?p7WVMl zNQttcUJn zZ?RK~``^>oja_qr_yG?mYQe?x%#?Z=o~fZO^(NeIqpQ|KPp<3X?92%TcaQ_^{2XD8 zZrms{!$eYMO5pYs73p&<$Y~KxW^V=Vb+10~`a^o6MxgsVnRfTmDG9sU1*1+$DG3Eb z$>;P0OdD96lod|*G2FAav6UE`MfDB)Gq=`RWn274q3|;#LB-YDYG{(w1I)APT9V!r zrFmun?CN^Ed=|r9h3Z9Wu*=8R^H+1Z)4c!q9)-VW5T==aRp6M6qCY74vjw~ZMNbgn ziiM=CsCe+@-Ve)^npg`;DUL@@PBpBDy zt1Md6(WuxoIsvSvUcRNz9Y3XhL*86~opNRVp}NwbJ~aE)ls9+t_fn}aV7J?&P~H>8 z=~E~zty{@XxoaNvY?#*21IaJey_gZosOBp(Bt=&$)`d=a7^tbCM8BC+u4}%QM(NHv zb7ergV+4ly%5aSMBBfJmPUByH%D}$aZTKoP^y~wV69lYu3eg)z^v#t29l}n0seQg0 zxXIuE^GqI7x(i^PyUaCiJaf=O`_Sv{z%8FSBTP~n-__ot&6i*aDLKKns@ap2pmrRB zJes@>5a3!%`$1ejUwi@67s}VGl_-ROlr|uWIyZe25vQU#X8PQB3+c{Kwp{%;Qp2Yl4y~G`MEqYK&Wl)%f@Do zK#msL#|saFBg|XMifZKRs)Wopl&(fS4aeNE)^>qP-E4@8y5`;j5A*y% zm+jqDl(;`kJ2_vm32#KYi}j@(iSn+b#C!A$!qtCv%c!4a61e*BRN6_Ge_kv3at_m` z2*se>Ib(<+4u&$KW-3o$jrsjWXKyWU0@!JxUmDNx)%EigA)InrY`cU_GdJqL<7f!bE) zK^w+Z`Hw{_oaD-P?4q*}`1o~G);H&5Il~+SSONJj#=sx%D z3j;8ce!pw%nmsdNR9O5lU%B;QebDoutuY($fht3T=x?@}2jf!LJxo2hK)4fyuq-UJjSQ1{^*3EMiu<@sYoAs9RmoeNAON`;OFrhM z7`zm%*h9r|6P+`Z5&wZN&XnoFW4Fo1R=y&UH0}6SZnxg<48**}C;&PUk|L?>MCW6A z!=akK?C+5#RdMf1z z8U}tZ2P-2b7jurbuB7norn-5WV&BCU0?xSvoYPTnqZJu{2Lu2G1OQnZ>+nf)+oMU9 ztv2l;r{E!U*W#wT^H=Z0nslyEc%R-#Z!!ZB_ccgjw(o(G{esJi3sYh)%W7LGh}MoU zqOK={q3^5sJY4A|++M81@WbV;Z+ z5Sc!Os$s<1TDsot-@`l=O>$j2PN%DmaT5?>(E5Ts0bc9UJhLsj4_24yF;5Z~dYjPm8~-O5I}NF5^mK(O zd{F?8C|W6|>8=a-CZUg%4OrNVd2r69woH@vqWWdASSz7PlP1H#Se)6=kt|oT9T>N^ zYOr#&SYig%iBtGw5O&Pnd?F6rOGJQxGqmT7&Lp!J0@h%(dxZ>%xgK;fORF&|d`5So z50BzD0U)womTj|9bA?39Ox4w*^KO6W&I9oms;3&PsUaV@ST3&wlN5Exh-!I`Z>(Ej zi)r;DJD_XQmI)IsC`L)?SI| z8M%()0UZWxG;$1wIFNo{~EIjdb(Jr+(t__vbJ( z`jyRv%;?S^qL~sMLq$q|;l}(nl#`*NIM9+pWoVN}`9e+V1dvwsN~uyye?S+C$e-uOIB@*4i^WInrI-lu?Z- zq4w{U<*M<5xrkGy?%pJVCx!xFZHz!ueSkn1Po!d@XYV(SUTQWq%-F@o(@oN&Co5{; zJ*}Oaou}7x5+_z`MN%v;vv1!n->9XtlXGc1n-wA67k%eHdZ>*Uh=?Zoh7Tc2w8g2k zeR5R%d!K1UcuAoj=6TIQ#v{;B`t!>qUOUPKxSC9Birf4Ezky-fFs*}KTztYK1ld7hY_(KQK-pX1L6zrzO?|d9Z z#Q#BP^Nfv1s6@h_*_W2keo?z|Bj%^y_uWWz#<0$1rd<8PO@Db6xTX}Zeq{U`Y|XJ@ zyw}8>+FUYijlJdF!HiM%v9xyTB%1FgO0m4irfl=o_kRv2G4_&{qNgnpg#_f)yVhe< zE)&TZNO7J?_$Hw_2PpV15otrDr2kIDB0t39tGkK&ylhx0>@gd{d+yXR<(4^=d_({G zlle96mwtevZUBlJiwO|=u$Cc-D@;mJ!75vBni9P|NUKlrAeGiHr_K<^^ifqRC;k?5 zKMsdJUxna$o|emMGDH*TBsjFKZ1UC=YwH(`Biizbr{o8wT5eXr7w`*D?om?#o9HFR~9m&E`7Xg7uJly5g+Qjze>v%_Vk}e z)aA|(;_S5QPkKL-Mmu?>1OX4m=cg2T2X3UH@#KNAzWg{30ZIx<}7)5E9X7)k$;hNX983C@i5nPKd?splmemnk5J= z9bNx}-~HBJT_?f}JXHF2DkU%Iwio|7F#wFh60Mn>^la~P1386nqIog=5AVDsg}cVs ztQ{^hQs3IzNeUBNPB9Cw?<(!C>yY?OZAN_Xc(_J=N}`47)2eOFNUUn&dMif6+v4XQ zMEc)nqNm$L+RoG9YQ_;^35kieExYL^&5Lj)afwN^Qgd|1XO`=7*m{>oSE|tJAKAHe zTNb6f&AihO#nEz_l=P;cm1f7J*OOoZ`y=)@`j%I4wXJOXB1%e{+vFoZU=YwB=uz%4 za%(%ID;ViN%5YF5zZRSVZ(?G8e$2tl2_6n1=KH%}g0JsYpm*%K#_D4k8Gm9~UW^#3 z#DJr{_R(bWeIxmp#INlo;t?rDW;KjK_lVa?V1B%}EZ56XKH_6b=#Z}`m-Zn+(`S)i zu8u|BV`rJa^RTdlve&+hoQZ&i9t5slIu^Aj!9a?gt0p(f8O`q==bKGQ?Q0(K(szHA zcc9qgQA)dh&olNy+W*{jPKCF-K6vo{E{^!Pf8{YHegZP}Gp#p;*z4KCI%H~BO_D~h z#R$IfE8fpU?8*V3qOb#w%YC*EU0Er9r5fj&#mHd4stMq(`?A-)zJ2di)KDC5PREn8 zY!?0f$xvnFdIar{1Nz(pFF`V`&|sKn7F?wMZ^G#I{i*j`;ntL6Ks+rH49(Tp^q z*hhJMy27dvZSOuwakJ*tODIOX`ZAq1>o2$JnD$g9BH>Hl@G2`u!E_C{?AOMYv>Chn z7h$b|6CGeHjlUyow$SFUTZJxs58z7)ywJKv@)@?h_RZlG%Xfiv`Tou9Jt8^i;Z3%* zpEz_tqlyhw*)9z0z*jWQI#IXbppg-ru19EUuko1JtYUW>^IfvI|boyv4 zSRbS*R@T6^>nNQ)a0u!5efrgdr#_NhZUbDLa!}UYpt20^5G-!PyWH$52}UU`w*B_T zeDT-hD#{eUoMbq}AJw_t7K7Q3+n>uw??g2h0DWifK`ah;G8`Y+K2)Uq>?5hkka=3& zz^%v2@GFzg5dY1C#-4O?$L=qlRj8s)5V3}+8bAUPOMH5H)(Qp&xRju;DJl{@hS-%#? zV(-G-_+?s3ri2A_%|%aGD~kb>E^-4GeFjudWhj5`Npm=+EdQ{S9|wp%P*bx{P%Jq# z|J9s#72Ws|>me{%A!E4R&few5pDJNPW+NjwB@CQ;CQ*~iMqCd#nwtp;{|ALk^8cWa zi35nuI%P=5{{s|lQi>(`}4F&x#QtHGu*PRz~7QNb4&XxebwEl zmHgE{OVo~?hSSyM^sNz-W&_2hYk0w_R#@QG(8H3Fu864e{?oI=@#a(uv%VnLs)F_x z-0V<`648|4>^9|>vs?7#b!6s(vzitqO13KxyDj&p%SI2d>i?0)Ji;W{a6HPN4d`kR zo?Kod_aSS+VSZtV?M=DvtE-%LkF_Y$?pqX7;t0t`&UYrJlP)A;d99-@V8ophqra?` zs{hdRvvXJPxFu`gqnsQr3##e{%GLkWF|JiWObbBWK-2DOa3z(Bb zZtU=9a9`Q$T)G{vxiuDSFu8j^r&geF$62*;ZSBsJ3+o69gL@(*DqQfYOwYO5zIX{* zxhA5Hk2l-HMHC>4U(_H8 zn!u>-S0F%%0c0^;kOeLXrjHNGb@>EW00Au#Ad5wkf{68S(0UyFh4N-Raw?zIh&IiI z0EZdA$~s!8A^|}KnVapBtotCHHhTJ-DxO|9jC2&B{abS`#XL+{o)tfYI?*W>);?ecw#R4hN^WWp2!E<6FM+tT%T45mb<}i!_gnxf@7}+O$7u`hd@LZv=~xCKGNy$V%HMU@a+=N7$mbe z36+4s2-`=Wpzhz216qtwY)adnw+GDF`f={hs{6y+5^QzYpCJyQ!m7x8F8eT|gKXq; z?t3-zQ2;A$bF-nxp;TBfV2qUIQ0#0l8ZF>RxiweqW5a~)R@%vy_Zl==0n*3Vns)WS z#;xbRG_FbW8i(K1%yzDCS`yja-R|cuhdJ8Eh3P5b)0;zzPEkRPF43~3gI`7}pjArR zQ#t;ERM7tkCTEf$rl(iZS6@x5=f74P=j7u~r zpjzRgjRe=us-kE@Ypu^*-mcvTuxCNDjFP(nYj*VmW-KFK?f7j6wH!j^m0|6=T}xL+ z%>PW!nMAPtvpv*ussV3@M|<*~$bkCtIRMN|O&?S_ZaE0H4Lv8coUWn5!@=VnHvhhE zcSb*Ulh6t1tw(ofoc@UZ^GB%BZ+1&zV5HuGLvy3$<*>N3)@JSWs{WTdqUE~*`SJD) zP`$S9>uc05oI;ny!}3*kymu&JfG#Fm{{B`+AS@p+66#Xi4ZMbCY9cLW0Gx)Mquy9l9+!T1ivpc0N%KcO1x}K;ln*_U^1m>9m?%eNv6=X}!YY>-oyBK>w(AY8y#Q zuHXE9)j#(96*aU#rT8otm!yfm1D!nNG`|t6$XAY}R0LW?oSfg0V1$<7+=UY>?QU6k z0kaaykECjXe=3MgK0{7BSc_<(#dmoW+ONR@aqC1BLxF8<$l((-Uwr`{lK+7Z@tN!U zk!S_bR~ax403~*bY_ga;A$Su+bm0=BQpav)(pC*tK7KBA=@_LGjKv+;UF2YmR)FnG z8Ky=#c=1^eXD0(!tMF-Pgp@UGdl1-Y2@Jgv5a>-5GqazH z!sVM%uC=$99S>Za_prdd@H9iQKNB5i1L5et=0XcPky<)8R#y41(w<&!NQ)e-;|*g%e46VZmymOY2OB=)0%f@wx2iV%*z`;tB_Yd4f5)o zo6F=#xshpAHBSiOZV{Cb1^<22Z&YaW+E$SgoATdRawJWPQNpH$8emOybZ5(zY@Y_P zcb|RwgiI2CsGphIE1XPc?Wf1$6%&iB}hrXV#1K(z&tz!RH!F4%5 zMdqQCLt>3C(6xUUBO<<%6#aQ0z?}uH-1xIVH6;A6!r&c)&j`Lol@86BDodPdbf&C&{`_JG)1f#?(DIj4h9SZmorm#mg4@*>}B&>d2_a=I`!8 zl4<(of0FTQ4T8-sSwPDIM5_Q39!~z(+RQ1a+#?PA_b8bDR2Zy7egfETxP#BImLmIR zB2dq=ANx*qRiC-c^<4RPLx6*EO|l$w?DiqRU=u=oHKw`*)q6XsprTP0v)#n(tgMI@ zV$wYEWk87lUtOq+$L>*+)xC6D!tM++2VgX9cM-m88sPfDWi@__KK~pIZfA{~M7W@X z^>(jxhBB3;_#!pdIb}uWnWX5B;n#dXs3Q-J6&)WzkOGSShWACIcugt|=-L8-T|GMFE56kJ0YpMVZ{aO2I&Ic%+Goo;~{%(gr zOGP*vQu15A9A3I1g;UaGnC5kv@-L(Tz^!)pAQ?$qy^r|%@t|DV*py(3|A;|Mzi2-! zS1Jx|1bfuN{-;;?cY`_Ek@j+AXDnq>CXA*bz`C;$o7`L0*1_mKGg6wO{f?ei-8`Mh z$T~_ZGI)RAyMAHP2%LPJfT!VJR0ILBEe2K8Z^vO%n4cE)er6de!kB#|Le-?%78`Fk zMf+8DWi5T;8qTP_u3NVI$1deeBN>}gSf*V029kUUGyZ)^|C&Dth1VHOB;*jNNxTcC z_-fIGp7m$f&Lg)zP&?w)g-1m)K>f{OifKXs#(^KGnd|oL?lLuwyHx%#ZR+*de0zBH z#vpTIn%SoDAzpn>Z3#e01Z33S4!+Zp(FVsiOGWX_=Vg%kTdx$NXQV#-#=?sl8=%Z& zl@6O@u34S5Dn6OdWJOr-fZx5$l-=I~G%#`(^KIVd!`-aZUCHU?$)jhBb>IPMXeDtd zxiXBho>h8C;j8yVTgF8PI!)SXJk4m*{4rOO>K&2E!aHz8{NeQ-RcGaTN!K!ScjWDA1SR4%5tk^%#|Z*>8+5s~0};909i{+D+yXsRx$f%j%sD)13*chmFfF293q@e^Me3T7VopQ!}@VUj+*89o?;Yzj&5ylB|5(GRDtbb0F2D}HXobj zYIjSim*)+u;t*@^G1n!NY9IXgpq6V z#QZ-qVWnj*&u#v zJFTneOCA>U4nIHqCKz!pd)L+-s)eTBS`ZmB+UwMf?R$Ler@!Z9Y>muE2lg};JXd2z z@n1*&Ka_oST$5k;_6Cd&gH}SN5ou{QP*FM+l^9BhAld5T@%#Jp{r&O2e{Fm=wrA(u=RViD?)$o){}$|x%&yxX*ZyJXmJc_zvL-AG z(g1x{cM49SbQ37M;Q>y0AIh2Tdwd1U@SWrRwX*~A-vs<~m3yHGV;P9@O^~vh@bWev ziwN+H-Tijfo_T>;2`Xe9s~XG|U4v5`QPJ+3Q}zTUy2HZpZiTxPs<@*{##csn@P*@9zFgr&GQ?Q>dia!xaW*pXgxXM zoh8ivJKDKVVIYpWYdm3VxJZ|@$HEr3pi2spC_@F=Er-~!NR%&`-!)hM2w-Da*eT(I zkFS`JW@+j;no@^Kwgkuj&66*xS4^S3IDs~ScXzf2N%$SBD838WI50DZMg$PU2{RPwnhWS}ankqH)^#-O;tNl_!lU z#>>mAqF&UV5M@UMYk+_K{p+zH7KvDpk)bAi%Mn0)(s;Vac* zNl@LWW2ybvPUX+Hjj8?IAkqX)0h(-ff@)Yr2XW6+EltJ-FUc^Hn?&KAz>34huO0Q7{2&ua{9i#yn?N7u&v-L|=+$ z!Ms}OSq|a-k(6eTBwFz)f+P&tSM zgw+U_s<5W3%_2w3YGnHubC{gR=)idS-HUE4HGAo_^R!8u=Y!X@er^gxW{G|voKvB6 z=6sl%qQ*R#Uh^7fws$PxsiT`HBmstJzoA;3*g|>0=F@hH{;!Q7u!IV z`EZ%I!ZH&KBC!t8$*EVX6VFSe%3=bFL&Fk1^9=TU=Z{!V)46y_V-5y{%a@CVwHWXDqUJuzfHyo=;@P{>c0 z-VOU(fq=-B4fpHso*xHR1tCmV-zo^m#$=ZJTiXJkR(v}Pl$t_aFB>&<8vaRsGshE4 z0o6ay+yB2=D>=FUm98rCe@2|4&}HVOl2`dvcHilYJ_r{gmk*XpU`r;dN~v z|KV2cGF;%;z_M(5p!z{vapunVioxE!zcuB38-;8hY-jts7d0qE+^aGuuJdxDk3@Iq zOWAU>pUa2G{VCAxuKT3b0JMW|SsV z;pn^hPpTfwB!}I;Cy^YkBQ7y5bHsDQful&^jM*dYXYjs!yyYwr3LnUaL-Av9Y+>mI zH}%$VANo(>YC+9XkAj}D*3_^S!>X$fsnbf|>ZPwKdL_Q?ZIo}P`<^5MKD@no zbHUitsTDkVXMOwrO_p!l=d@(O4&_NT2=~_k2;YJ~Ys%yIt3vCfj-*clEK|yyKZ6t@ z_m5W0;0w@s%}*arRxLcXvDsWxXI)S@8BM$wmc_2|h>*^D7Df^nd(IktE@ETc<8#LJ zP4v=KZ^i0vw+-5q31_PRV9h8x%c7y-4u!O`cbGyrG02!@+3TepK=fonvJTk1nir!K z*o&=A`=>lS&-%`W-np;tlD=>$g01;Heg-3XpBaNCq(<&oiD)y(q??bX|Us;g=0nE9R7pcnD#-swy?3_4Wf?=lkh^h>#4`J1be0i7XE`#ZwbNFc}sPuN~vhR-vrlCf62wWDu z)6y^q@HjAy%ANfTzw20Ka6EO#arKuJ!UqwekVsm6SfBsY^+9qXiOQlj-^@_2UFJB& zew4iN)YW~u7LH^-HupAZwy1luBOqEt%CJt_2mZ&RKHsd(JK{4O$#~pok;_8}Fc+8; z*b4j7e{WjgXU2uYx?|&tD=?(S6q%*je|?e~N#j#Zx>P!(RYQ=5`Kgu`EJT)jH`God zw!ttezLG*20{wfDdUy(m%K0UTB?ox4cnL~iVs+G@x@Ur>uPxB|bhc!?dmE{allgFu zrfugoeoicB@GLQ%5Vj@M13tUm0cNIl?yfAMrU;u0Lj zqpnyH`d(MNyg)+FRAK zN|^II=`Bn>6(9TbJxjX7V4_SMV(xq+;voETd{Dmj_6dAf{_OyP%DImqH9O6~$BpeB zb=JJ&kp+xCR=h#Alm`nbwIfIVJR+Q!t8Ex#TpJ7)Q*ikljg`dgHR!Kc5Ny=e2Mj|p zyn)8#Sj$}m_mpvi#Tvxk!!;XYd5$w-nP<=39v@XCSSAuyO?>mU8yE+(@ONp)zIKw| zAQA=Q&?mD1+SmlN!f^eV@OOzfp|zIYg;HsBJdTIU0m?+DG;6%tMY_I3h)Cc6`wj2 zHa$w-$XbY|d>b&5Hpe zKkiZ1)-G3$$~~J7gKzn)+#a8L@JPP5@+8wE9Hl6|)5X-tPt`L6%;H>N{^T`4Kv}05 z6U&`t+U_N`WnB1x!!o_*(G(oSeBAg)z0GoP`#2@aG@P+o=}Pqgl=aSuxI+0N4WlO< z#JJTs(s6_hxTUs%E`55T|E%5Fu_(rJ!F}P>Yr}d&>0VK`96VB`geYtwZyroj`zJKv z{^ujni6Si3+M~1Bos6nc9r-alkQ~BpO)li!d<->$>}Ce!h#w1=emP-sd20I?Q{w-_ zxZO75<%zgt$!gPbeqPM!(Te*5>B)5m0&Q;Vave#TeZIuR^{La_!$fn_Fg@H)qeoNn zTPabU#0`FrTqrXzM1i-6PsDHRDg9;Gp~`Zwk>JCMj$%)KjZc9T9rjsBZf+M$2bdN8MEbNyO7h~tMx zSvJq|obm2UjJM;<)?w_}SK4saM_g=_w#i^pQXYtFt>ocF6+9#hE3`50aE18`~Mc| zwp*oekwJ5Sx$Sq~nyDm#XORaiX@)0M2KP?bx0HSZp*W_|%~`yv)669}wfK=Wf$7&+ zxEn9M5FSl$>rFsyDfyp=3f_7`KU`cI(S1Msv`IF7Ny0(8S!D z`$&IL2><;_KstY1;&YBH|En=k6>xqdp}uV!7Vz3-S+P+y5xaYWXzd6&!_BspNY5*v z7|+r9$M>0`HV>)P?d6;CMc(g72m8DBjlve{=E4Eu*SW z-QE&~j=sfoGS>0k!zt{}XAln+9eD1$fod8|yBL;rgSXm@JMQVYph?lw=~8x@4ioWn zfJs;SvP6uROb;_vH6I9Bdwkqhin%H2?a!)fZwn#`Oy%}#z{2apl(f4ie$ z*@?Nx!dwoccLa&bV|a{CGqlwv-%Sh_M-N->_Tqsf8O|fM-6X7OxJ$nKcE!46WY@Jn zyUFwxHXIWBm8+6iZ`g#^BYP?IfZ`Wlf>$jP!5KNzO+6PZUV^0*?9kjc})J83qX&ke<}rIfL8Ccwta+Fo!xS`z5dkBj4`K z>!cvwC7uC4;a79R0Zhht zrJ#`4|Mh1YKUT25#6_xObG0jiYU_@_7#nbm3h%s6$z9#Ju4cmOc+;6j!LQ(+P_RhW z60B`?5ZJTv8NrLK=~jV)TC`a4rk_vnd^8ZCDk%IvfM-t4EsNvs1q&I3mSYbY_}~pu za{zy?&}J^M5cnnw155OP^crwa!tnF5 zbFXw$uh5#*nLkl2QkIpqdzUDS1d@khmTWGlTYe{f|xnb>L9Jkk%O&d? zMko6|;A2;SaOclWSOLD8*!|w=6H(Vhi|8g151^}uq2~D`LOur0RrfP|no#y5-7f6s zoWZxjv&ggkn!8{Ik=tO#23`3t;WVY(5Z`a1Ja%>ntLR56@QP~X*LDK^AvXLzl`t_ zoUlDKXsUf-T!r>}X-xLvQH&x+rs(UQY&n zv}9YJJlG1%bGdQZC-UQT8TnP?NaihbZ&kxH$1wnwPn4{&;DC$}jwRLA5QR$%!U-gA z4kRMa~9Ea3J1ND&&2{f<#K%=|=fD|hT;tFAk`QuXEA*~{8s3EvB16R|7bjK0fo zP}3F%JKjv@~*P{l4?JN#nEJCsX18(Tmq z0ogRqzhT{2@S>nSO@Tudv(NZ95QiG$?)wcRK>&~3eUcl0-cG6EBGsp95jn+?Z_l^u zRQzqo&F%Ol3Ar43)Mb)&VH!5{oK5CpQ$(lNAs+OBc90*Y zkbHYa+~?Nu6S3w+b-h~MfF+!lSm~m6n3Kg4({7gghu?C~l6d7c_^`1tmYEw)3&6{L zM%gMdmq7PqI{g`|VtAA|m5sXDjmvQ7`!9*xBALbW(grrJ6j3?U=K-lrksmbtG5JngcWCY)7-i|GDLtV1Wjg z;emVHW^HF*+nX)7yGo)oiF1-b!_|@{EqR>IN9I=O3@V4*54Z;`~#Rp)LABU?Ut$VY+xYe;2g91`_}olm96q|CsT1K zTcWQ|2%dq934-UiCvNsC# z<%&7RoQ7|wgXC2>s&)%MMGrcRsZVI}Y-egC&CNK{o zeC>D6b?MQ9r}Wi#JuH=IZcM7uqb-6zjP|^^n@rQ7V}y9G+p^ntzToMa@AyXr3uX1O z*;K))zQ33{y^&uB25a=Gvfiq40xDGFc1&4+raa!rd8zpb)y`=+dBcryMWK6>tai3-QSO8VDX0f&pR6ARM2M6gZ z)fDccJf7u!Yl_I5A1`t69FgA|Hvjzf^M`+Y6|AZui9_*{4se)?I318mmTO?y|8Sb~ z$kbpyl7?1Z@hwvHL3m!v2Eo`nEtMjz6~H5l{@EKlhr zRSyiObR7pMBJ$!l%$*;0se#FORrc3d|ARxVU8wn((SNDDbX zSmGeFB)2ha4p=ZL(g65VA_tK-JGf*BH1`!9YJJ*d7uWtt+MF z?zCHNz-Cn2J$+7meFA!qj)wp;=BHtk%pox5;fxL8d~$Be#?zuxmds@LxzQsAXARovVWsML%+dOia`XEa z-LPB=_1s3jlRb@z?}`W)gP<%}Z0s$27EM;{*WW-4d;c|vLhvWXAOafDbA+)!B2Y;F zYXt9Xd^ls0gm)DwNbD_9L&0kW6T{jXrzEi^c(wiD=SSX0aLvc*zrP-0ANuB*kxG|Z zRHT7Iwm5rr`u0X{$<1x?2ADnDnolB*%3-{{rC%ae-j5vQjm=9N4*WM-Cl&(}cu1); zIX;I68(hp3*!yY)l&gW!l^1OXU1%#AJO>!vZj#jNpBon% z;eQy5TmTi}*qITAtF2nw=uX36M%usG5EksnhI&lS754XB$Pb5-V)Cz@m3-|&WAzL! zi0_0&AmbG)_V{g44fvI_jY+o<=y3H)fb+8~TTKQhMN|~82k;EQLrZXp)^yAwyHOa} z+Yfc^7WSgVS&R>`_74LbQsF@EFb8~w-f!rIGPq123>}+KPRx7B1a>s1U|6q~=MYxE z!l^_%!AYO8FtszzYQ+% zzm9qsI1x$u1({x+j#BVr4xDg%r%rp%<*iV*axBx{X78Y^`n+2WI{EX*+x|;FiJ4mj z=D5fXFCCRkQ~=~_N-yM&Jl7rg*A5_`FHYm5vOI}g^0@TcK?HKnwN7FNL15gG7$WjK z%uE@3-y%Q#Ffz>70K{`elf1P@ohojyieq}>DR@&((x#@`*A?QA3(spF zvED0$bJu?Kje-4w)LrbEkW+D=Q7;*6BVhOx}4<6}ESaupeszJIzOu*=h=-Rade2o(JNgE!0JlO zvp9~|HQv6?g@1crYPWVIb~;DVlv*Eoxvg&U$btSBvqM+(q`FE+%8;3uiMOeWjII#O zaNw{!{-Rb(nRIsmWUqiExK&BvLTZPsx<1_}26x&LvG8@4&TZ><{RhfIa?Tszzwik=zjVU_vuA^;pF`nPoneVKI~^aS9sP6`Z9@| zG8xi^rnvn!->H-2XK%^=48X(lT%@f?tegw>ZN)ZVkaMh&z3n$`tiiW@Ft&V@neT#V z*Ii(B8?fk}NI1Ur;D%cOs?p@s@Rt~GjjyltuhL(ce0iq&i3`sZ?j?dcJsh_fu1L43 zmxz2{4eb2{NYqRWn7?1PoRF2FNoBAY|772@{L{@KA;?Le>AQjijBf!Va-F8*;hoJ6 zo*dyB`A4#B?vJ!Of|LhmKWKw^nXIk03T!L-CeCk^dCdqb^l({xva*Bv6|}+^)2@F| ze>YjzPyt4ODPyPMdr?> ztg6cA08Iv1lo|CLml&*a0Std7;_~Y($l*(#OiDWMj8g=N>wU?*qxPHiGpdcIp;N#I zG&K3Z2Kj1Tz3IWotX%W(Ei2h2Ev6}s+Dodn3+xaMrt@=GYT|o+nXQ+W)Y)xH4B90D zBFhFWDK^I;lj7E6UTGdIj&5Rwf#v)mCf*Nq_)e>lLEc~T(pCdYE&!n2&(ad4@mhe< ze-LW}M)mV(S(!EADkxobQC8&GcH}~d!b@frtzt(Bde7N`>I66YH+|7P>YTTt%x={i zIMd6xazx0zZ?tw8yk+HJQf{jHo=5(ipuJ*5TEg$M!GccpraQF4y$5?v+&okkFL+J1 zvTsBLxw!IHmRdVLQNk7DzeZns&_Q&}j_~*UG?CdGhfZN@oSFj=R|SzzS?H6rNn}tO z%6`^s#R3m00Q7r9y-ifBF>gij!hQG2$(Qdd1E7s(9sc^Fysw~E)nS0eh>ZJyH0%z3 zYP?p8621i^?_@|{?QS1p`1yg?3hrK0Q^-h)c>OOYn|pc=Ue{u9dXq25q7Km^2RWzb zn=SXg#R#Sf77-V4{4FAtj%&b{j2Gv58YhkyE^SCJKrJdSK4#d>?|rJ&$@JpM(NYrM zWL-NhN$q$dK@A)P4ZnJGI2M?oKVf1LeWA6_|3c+I z>r5_;-S78+BAx)(C7o~buvtyDZYW0b6jIudUt4s86g}971bv0T;xyczK$QctEuls2&4k{InTi@1{9Gr)OmCuZ4 zdboNJV5j%=<62{$*V#$=aVskYWW6^G11o|90G>OmS1!F4!hx$(7Lx~HoI4mc>P6(a z#tZ^W(1MC@%yG&62kvS==!k#-kPog6t()u1Alwv>6F}g-k0@JFPef@LMyzo8zmphV z_k+MLRn#WV;#XvNWZ2yN03NTTTXpayP+Z&wW$dK1Gi4|Ri6 z>6QNb7#D|y@FvB%6($p_Y~!+KJ|snSa^yB?CYQ0a~>t0dc z*z!HxJ)~7A=+1^em~S&O10bO+QG%M&y|;h&02oB#^LupX7Z>runhWCY&64>iE=1t? zk3x;<$q#^qN*n&bm;Mg+L5;g30W8ByA^I8 zoT0*(GI*C zxft=86sXM1waBRthhX9R}+-YZO^=1!;L&px%C>*u4lCR*5!#~(fvbVddE9k2nLtko$VUS zlsGOEpmosyxaxDZ>prH3b*J&s^Xy@9t-^|{;q)7S@yiE$>0z$0W9gK^DMlJ2kQ%Aw z;`DUZMIRXQu@6$4^sN!>W5+-1UC?52dhkuiT}2SqbGcxxfSCQ9Ottowdg1+pYc2y| zu*3$axVhtmFl2AVT3I`PeTg)!#hSIAP<2(-?vHVjfZ04T+NA-(n{Xebhl_nQEs3n$ zF#p*9HhV>W_{B=V6vLhFY{m|C?lufy#{zeMhv1*DFR^pp@U{=bnpENghTjVO&5ivU z4~wshB|7EK#r~JQ=N6K>lAGYc? zK737Hu^50nD*pO4`p=~-s}}Z58&}Jf`x4c4VVxY}*&MH}(=F;2;R1syV{J*d_BHYf ze6E!Vx#ZzH#*#dyyU{!1GF0+V&Oni?@y{p{*fUG-|fXkI=is zSIMBSK^#7~i(%~#x;UFM+m+dM;z1@+cCP}4R@VS6t=F@+{{(vk2W>x}se9e0>Oo1u zyy&iRMQz4iP2#xX(~!B*UpCibjuBmybzaoj{sx@fz|Z-`A)ie^lh3Sj*R0H@JcoOJ zxeK>E>;Yir^)37{3Uz?n9a6$*zx1G-;=)O{0tw5sd)mj$4He zPX=U%GNY2q48J~svK0uet1HwGKi3~7;<`vUeKD&_kkq75$ni%+U|?&At|JCrHahV@ zHF)y`kUkriT)-_1m7vq>mq@*TJ@PD{r6A4{43GE9NL#jxf^={2mkdU8w$3gQhv#y) zb6YA1TBG{! z7K@gTDJ4^6p=jonlmut*VPY)VhUy1*&-*^6->O|Sa^5` zQmUi`y#ZsZ7b)An`ZbljL8GpD?`EMbifZ?~of)X3g&;1r21DzK%~|KP)N^{BEDZ+n zkgvh#lKk!IWDAPvrx@SrFz@dL_ODh!HPsj9LjWt0skr%ey%aY^b3qi9Pddu}t2X0W zeq0?f?XiKOp%&X3pz9*0T~4&>ad?Z!8$3K&yNm=h2z590-}<;zb&!Hwj&~cn&mtcq z&w#9ib8{E46eZ1ZmRTz=;BiCfTmoo3ADwn~!Rjf^mZXdlPFOx^m8A^I=7=MV21@vR45zrQY$l+TZq%A|wN8O~H!KaO-xTAx= z%~V+QXNUHWXDoQrY@{+}EAn@`Ou{970S31T`vZO5QI$r_2rI^2Y(MZGF$ zsL>L}3O8^}(*QERIzWQ>%#Q31sQ2oUWj7s2b^bslYrEHD5r1}k_SdGNgA$~SJMr7^ zW((mF2kfSNzDQozn2?f1@pu=a{)Dxrt9w13RD9JHvujBEVLO1 z?CDskWIQ#J3Ol}!$x;y=*|$X2k<(@ugPICZfcOQ|kJIjgM+~0ndxumr9$6Ncar{Z# ziXdVws;Q1F=$e6+E4r;l*Y1zzkb9HUwMp-Qrv3G0l|`x(bmv<8S~EzMq>zFOz}KJ{xrDf60(_>yp1!yG@kz>chZA)FPP>qjzy(i0OSpG3e93eL7%W0&+0MVQ zA{{TTd`LgOrSW!T^*w^v+beD7l1BA*Fw+A58qa9pa;onv#gPSs5mtCSd%Aql5xgOp z+8?T`nRN697I2&Bch1SD zeRGJQeA=cW=9hSrF=b3HIAAFpLBERjY286=Ck0roH8+RV+r?tk-?V0q{E0YW>@y5` z!Jq(rK1b*;$M=BmA8S-Km>@{d9ps(QZ8w$mj9vv;hu z(cDe9roQ_J2&{(8KYqG=BjNnbRhxfNRUS%IAM-!`j?D9Mq4{zK%xw?)f!CmFHdKiz zU2TBK^plA7{6)NA%Soq7P%O>B3s0WqdpAli8x=C<{w_j=e$Yn+dooW&M>zJO^AdbyzWd<yHt9ubHWMFTw?O){as)t3Ofm#%a`{=@DJ?i@5o*Du{!}iey{QE z&;`G`b}M)fXM?7VhQ^#ieC7*^diGA{A7|i}L%f4S;r+f$yt_cUA*D6DQ@jgTfs}Bp zf7nb}jd20qxQkg-xV$@6V77u;^3_hF1W61mK_wq=H0Gm*{zt!kr9${Mz zP<;Q(2Xwha#zD6{54s^vKjQGM8RDL9N&>-d7)WG;nEqbbIOhM-fd)^`f4QJx!e<1z zr2b|IT15LVE9+ysez!XSih@FpW3D1H!x3J*wrtqAZY(W=!aGtmV66S#nCam{1*{k} zVw#lnt;?9Y6))Y{`Ge^d9BgoQVw~tibcQuPMnykRvUa?CENSw56O-7Cyg?z2N01z4 zzgln*DwI?_ytWUvj+rX4lE}uvC9fiCc_5NYR1v*LlabZo5U~X5vR%a+-+t9-iC~3Q z^8L@>-WpDS6sFt$r=7}gfXLUdZYR@a8KIX=*?Dv=Yx7IKswXtlo?*fh_0YWZm4X;| z@B5#-f6<)ks$S)z(^Dtv9x)-hd|nEbn~&qGbz`!yUUNaZiB5K{701e2R^UfbUcE>h zQ=N?uyW3wvnu%#x2V69OU)cOIfpkA_E#q2hXHN?eq4NX}aVa^D zfy{|}Ki$8{m{ou__N5Zc6MhQ@OTx-FM2bxLhuMoZHH_DDthlI`W3K}hi_Q0D3FlQ6 z8!ZfV=k2j$*r6i)!TIaM5A4j>4L_`UhSQhTbj*)u8ld%Q_JFAi(`6B9kQk55abt8y zgQsnKeR>EP`0_8NPd*vab}8~&{6-bswCXrBfLtdaV)>+W(4g8&YV@GbZ`e!B!(1C1 zc7^>;YW?PkL^vxAGUz4*2_Mlc`kG7SwcWtcmu5QP#@~NPiS!kz()h|+TGJtn6P~Ie zHHhsF`#d7<1$7#@0T(b6{-nB?R~b6I#+mEz!SLaUJl*#=+@&oCqNl3fws(|NJyl}w zTk;HT?(OfKbLwf2UtD;V`vPm=Ql~58{>4zfX-FiS>EVMKlgMwtGffeh@oKFF7k3*T z7cEvAOpq8ICOJ3<9sln~GA@OISu>j#Hu^7j2+t(ZwTVYdnv`u!a+EWQ&WhPJZA?Cq zSHEo!FdlsizauM*hN^@=%s&0G4%@pWIe7nCs=g5O8ulLJ+J#rtc=dFuCWqN8KK)g) z4bC!|#g5Ul@?My^(DN(zZWJ!EV(IR9L$)~kg%w&Lm2V#)y@fD~9t07tt4&ndSA*b@ zq?n1{j1I|bB>B6wvgNdIt_E3_&U<30lGm^glh>X-toQT=E~DS=dD6o-tErK$4c)cE zh15^Ri;86=<_`F|gK7FG3IeXXg2w1ws$xH zYms<(2AjtU+-<@&CRk5IpB2_i-ZVsHa@th$XV_OXMS146y5d?9jlAYK1eYCS-$Y9fB1 z?-CnVC~h)C$>W8kECGm`@=sOBFw?lC@qX>>bl=y9&1qiT6WDcdtP^;SEUP_CR)3Vn z1@?l<_K(%Pf0i{_c0wv4unty6c)x$ zIvw5@rM7v*wkb2JM1m0zWtP)`{RhMjB%r%Y09|-|P4%K7_~&_;8MdrZ;0_2PcL$_v zd&2r{WD9^-G^uOHmYlbNAemGTH(AU54d+Fws&7qUIp#kS7FAI>3U+4f1B7X%k6nNTL})#%Kar;lI>bE58}Q3l zWXca{3kD`o`d}Ko@EQ?9VYmk!azG3Fv`&H40PDo{7R#O9Yl$C;3U87yO#Azr!Z*XE z{RBhD{6RtL97tE{Uv_641J@blJhTFPsJ^ zj1GDyY44IXNHPomZS=O8tzh8LYcZ8Meh?I037Da5pV^c}w#e@Q1+U(}!q~1ms3bjSA*bk!%cUq%wk~+upfcn|tjY}0ipgJG@ig(|_%`j}vW;Imreq_E- zF0+i%od{)!Ne6EISlJ$Jn>SveC34aNEO_7@z<4{TX+~$Q0q17Y0$QcJ1K^g0mX3q@q~2v0$YNWOJ!W60IP7oH;V{;zf5!G);4t_ zDHm!J)*RSMK56`n@WJhFXB;Xa&X$i)rwsR{yDEQ+>;0}b20;L;U+Aiff2XR#! z9}rJ*T>bm^rL=rPZbcyA17j?QRqx#~m>c|<8ieY?@DhA*PgJ*vLL=*EsmBZL+@*Py z%p>UPqpx{)F+3Y)s;8mQIrVq0k2tZgyY3_Q=mp4akpnUL8?c#QQU?szf?Zho@{-S= zp`oq#xxcT@$Xi{jy0aLH_gQXl(HCRHS)4R^102pW3>AcMkm#<@wD9+^olb363{>PM z%=H&pat7W`f8{a3g$}tqx&)tZr+A+TMprHT395a0s2FbhV-zlgFM06%`-8{U0~|LX znTdGcO9GnGyDPTz4}#qdCW_Uc+B0d_%h^rtJyo}N!o)Zi$BBd*(Miy}R9eDckG@Xr zJv1^ela_9EAvNmU*P}HmC~I$hNB=po59bn?OLrfpUBA}Q0cY^KXIypO-D(dV&?Iz) ze)p5nc--K*KcDMNps^+Td1)sT3%581r|d^Vjaa0ZHZI9nV(Fazrs0Fd01K7=;v$5u z%n~wj!$)r30QICDa4GURjK$MhDCC=`)IcKf!T+3A3Uto_tu^nnFp{B7H+7e!P1=fU zHkekn%VZ&$dIDv#>tdxIFq;YV$V%po(wexmvv-Wa(wB6B&)s6%^=qS^VcOd6|EMV% zGL=)%4sM{T`uZiV{F^Z2-u7ojh0N`2t@F0AErJyH9UnZCdXb5URUiEAM)0Gq$u?=} z77vh3I=RF8`(YiPb1)rGeeuSO?ad`n{07_jPUxGVM!}j5wl&|YO#i-agUvw()%v0x z;-`ox&@KuNnF*!7o`XoXiLOTpsL7)4ib<8f!t<>Z!J{TW7j1l?>kQZ6mZyMXjjuU` zGi_}_<9cp}@Ci|Hz|LphsSO=Qt)aj?B!OAN)okKadOyO5mXiJl1?C_L@R$D~UOlbp zO`|-UHld*e*o%@IS5G4iH$3{Kf>>z0pmV%iz4fkpnUkc^+<8X4p05gIoH)`tD;OscPx?3uFc$JA#wQzM#w_O7+C z9k_)!dOX$IF!C(;dKpE&_9NMS=XTgPpP+?S%ukdvf^Do^m5r(K+l} zOH)pmuLV4%*icetMV9GMX{0Q7whe9WJnh&9{l)8er zOV5*yxY6<*Pid5Uf9WWSQ|?veSezy*%zP?V7fARW|1Oy~`#pWd8 z6%pu(?21Nsg#?6!%>Q0C1=fhN4(J!FKF3ug_~Mvm+}HoZ*jt6g^#p(3g9e8X+(~eE z*AUzx1cEyRcZb0VPH=aJAi>>&1()FN?m95=p8VeZ@6GPTay2|N&zv*W-Bs0fsy|;z zf^|-RHTaE5r1QKuzak_CioPdsWcVB@9HRfaKM?XcD6q& zbh=9M>aI@vQgYTh1~L$_vyPjebiLjk=?Y@29`ujY^M&Ib)%=_Hj5x~;b+$zDeY-O+ z0kE=9OY*yru84u2SEW$VxyNI~VPI7~XP)TcAwB@tcnP~}e6%sH2PVjksA1j_R`S*9 zpwdn3-`jo~DD8t2gs8a{?0zZXMf*_w#^h*!MJ2dQ7*9a~N|IiDi?{?#P$=9DJ&c8s z!+K!U9p?Q)1MJTG1>h3U%;#Q9;w5`A$tU0vhf+kQU1aiiIVSi$FRKgTP|7yyWvbWh zHWa%9x5qPxNbAIX?-vt9%bT186MVPxTEnWv98L*)wL4%uz)H*)xqlM8nT8HtC-w24 z+s`OoZ%waq5_&L<_;V0&<-tlJOpHk{UJOYuAGqaOfc{G3u2{Q6o|bh@O>KVPt9$&M z^J;|aTP+~=NW>rc!O@ueVKD2b{eI$MCUp0pDZx;#@hq+eQ4e0g7tPzCT?_KyMPbCrzdqw9vRZ@I z0YXJSF;Ok3xLq&+w__4sG|A%jtH0){^u^qJeKwX$r>@_mtWV2 zpIu&}mO^g5pUU3tE^ql9)BL$Vu+l5|yZd*rLdQru76$+4{sNz#Z0r)?^H2FXM(z6;_utDG76sX3}>?gn%>-_ zcbf{s_2CAO`=ZkAdHZD)$g6eEtJAN?&eFM@ot7vSvi65qC7jE<|E%0RTJ2Yk)$F|@ zg=5j4sI5f`g5W94W=r&Icq0PLbqVELH=N>2?Ksuvyq2oICts|!bM&EqmIlJSBmiK; zX+qNTM$~e8MbioH?0_zWKNDsr8YWzBn%q`HA-$=cFgRnce{iI4n7$uCHBBdaO-10S zzP{q7=?y#CcOu|tS-9WVt2Lnv9JiQ0YqIEyX*HVkd|LmilX3mgJ{u;{hCEkRtGJC^ zz)=_hKT7N@qQZKR$Y3F5 zBoJ^09EG`Noy=I_z!ZPTJSn+el=X%Chc&F1 z?CBU)tF35r|R7^}0>iE|_bu_aQg* z!;gS}h4S-pm07R*w;YMG1>q+j6N|}$m7-Z}P9{ynrJ!MVt?fl!*$NOK8v}y&EZEW> zpZ9>HJN^Z(Q9+PL=5=*pA2PVxd>k|!zl!8;^38e&a@p*$f3`e-bG#eNDh(TiSt}K| z$r;RWbF0HP&l>=vT{!%Vs1gNlBCj`oK|@iw(LhoC!;pe@UN|lUcwS^01rN74!Fff5 z%v5SkMR3mbtV^&9xO^&tnyJWlkUJCFAGx$Cwn|%39sJ~FSPz@3sei2fCGYvUWv{)M zQcD;N4MXXEZgBz+D>G3Pt*(WC4g10Y-E+fl^&|F=-wgW-12nW9^m}wbrDAf8Pft|> z$o}|xMGf~kzsvp$SrByW?_;u=wLKrS=Sy9mE&#UjC2w~=B$FtA62`LUcl|`3*;_9t zdTyaeSYU#rA50CP>65vlB#hasl>?JDyKgEgoD~nOr+i2sr^com%F%Ic;@zM$p`HH* zkcs?;{%SUM#))`jaIh&(RZ;}A#6?4>46AP}eflOgZwEq4ZeQbU3y1&Am zGsgm}!fh=8(~88OZj`e|S8k(>Ln;UnU1brEbwnQ}4no7$T(|i4BLLFsKHtHJSFJZd)SH z?TaKsgc1R~971u|+xwWiq8c>@m{L#tnk*0?e}ZNbdL^_z-Tt!*qYy1|IFP~LIXgL( z*-`xaD^Fe&bs67afMya=NwHKGV=YOUBTVOhi;DtoiNvl_ixOR#232yKoMuL z%)+Myl$G1S-s22&$LYQN+41nfi`ajb-h&39>^5-q4}v1EVzoTm02dJc{8OxybNDHb znPvN1;GpA6H0cxC_=waNBDvd{N&2&KI`D- zHhi8Nwr&%ojT?dx>Q21ThG+8JB3WvGGC4|riJ2LWb-EA`90$Po!l?3~u%LuL7{-C+ z^ZWo$03g&H7-V>lm5Q-|`Hk!lI@U|*`&64ipt7+~GXnicUlr`;CbjNUfF1?1;zIaaZZEJOL zJfts$xS#piO`Ucxs3~&nGV?;RMQt$yjF&lYqUxnIHa$Rwr%<0Qu?tAiCD!jx9$3YP zJpqY@Fm2A4NBKTqL{sdX1m54kS_jC(G140-d&jk(A25}Zjz5Bd2Gmc`g)H8*P5f!c zKZithYrc?Y$d;d%F~*;2#Db?x;$JmY6QJ-TXLEd1KkkIl{ZSLqS*es9vZyU*w)P}1 z&wVA~)b@SD^FX$y`G5H}olu2d>Pkt8S}%DidN6kVx_p)vdHFRDt#fEibHqN1zDRpp z%L|hXkf+{~5Eq#NnHLaD<#Ek#iN%J!F@#-j<-@MEfM~i&CVEO2M}2u~$^qQ|=zp#% z3xh?D5LoT^6E$Cn_Lrk?!(uNqyV8UWkXh0&pdPTBtpOW{;RCO*IU8Mj?DP`$Y&`@udv`;*4Eq309T3-ZJvU;Pq}%!0TqO1 ztWQ;$bJQQIYAD&;^yy#!pc7%04Ua!L>l;54@wP}gfA!hlXj^T`LhVV^b?3L>RGc}3 zoUOV8dZFmgm)BX`M&)f_QcAPP;UyGsuLDHvF@*_JA^*c}Z$3B*R z6iI5je_dH;SLXMti}O#hniD`T)st7FXcrP?wl8!W`YgfM*50w40|q}nwkfkNBL3Hs zWm)23GQu9+v~cN0xF44Bt#nyOVb>pp3PmJ=m0}Kw?Ey~;N(yfQ`x<`YzNB6 z-HP(FAjI#wMETXrO4Z;5>>(oi)ZbLHE;KPt28Lt+4Ot+A)noKR6~gsyoS$V?tKD5I zXZCmQn)g}7DKwV<(~s43z*==y4ff3n_n_<{ySJih>@}4eRl&hI z+%6-+BqsyQh+14fP*KnEt%TWpv{|I4ru>DI+Cp@$Q_RSY@`D=#eL;)3{PJ#QU5j-m z8J1sqL2o`j&jr(z(R7}Vzb9vPh1Y>2Q9DEoXyF>3)zv;?>cF42B+1ZYXYZOElH@!1 zh-W+Ch7A%xdV?AF0 zxeYDICbX}D6TU{pnT1Kh-+J9Tb?1c-2!x;KD_EQi0>aOnEi2;z1d>zNqB`G|p&`x+ z0Ns1aJc-T-BUN$$X9DoLs|Y}~%cX14;EgfLS**!06n}xDrHk-s2?}pJi(j(ommX2} zE&OLmSl>%$J98JT`;V?30fRLF0NFCMF6NvGyn>0i;#Elv2<{A|12hJIbWzf($1`=o z67Jd$QGk7P{LqiygC#=tvbLA60I9*3M*2Pv6EB^Y(}kGl|1<`lxzmQ#247uD@m~(} zHSH5Y+YSn#@jH4{WI$yF*l+H%#{pK717Wz*=y)Dfix0qC4o}?<1D`XM11agt0uOm; z#GF0y9^O-R^8t#A-~N0df!GhaVdsu&lDM>ju}mW5J%mM;yl#h^Qr3}PVhaGCu3HcC z3nLp)6+suj0+YzS@OoPrCx*QenF2ex{p=F(+>d8++Jx6kp`26fXMpMVs;D^eM(qMj zBLBjx#ftITWFq)7f$#Kl9EqZDkcJ3GNJw~1WCaxxo1hBDNWKLGd|pV>E7_iaUbPnz z?Whc~UZ#WU{{+8?tutS+qYSgG{OM_}9RJFXBx*hxZC$u&lFI9f6O83zNbssKb{ z1>EFE+rdty0Hn6KAUPy0`*xizKw)?5@Nzpg>=^ZYP08O8i0~F|TI(1f1S-fx8awic z&tO`is0H3TY?r>?G7$u}rS+4ODL>lEOX4>P&m?G9sJx_fVpF~tS<0ozDUSnXg(4-8 z$Ni?i>k6l-26e-dMX#|5!i~Jz8;oQ3xXqEb=yTq~UI=^nzHqqs5AeqAA# z52;lZv3(4KZkBTjIrEd87iNlP>_om>Q*g~EPS989Jb9`VDG@<3;%v`JL7e+x!;{y|YB%4eH08Z6ELGvR(U8bKTS+l9E$rgi= zXP-2T99BcK8E|v@*Q`|-4~I;X^N!dS-l+b^UcO@cJ);z!;zy1op$*w+)s`efuR_^gvJumOQ?vz zRHQglzNcaQaS6E8G|ea~_2(+HfycYEgWvU(03+)_q@*^|FjF(ISne}~ z_1ppQ>{-)}#{J;%4zLKD0pY)Ueq2Az%#9bm3?i&t0vZBG`NZ(%Lo+OGmLh=p zUI8dCqy3alH;popg%+nX@==#|5iYB)OL9tP*{zQ?Y%b_U20m^7+Xm>J7ZSGs-+j+N ztI7D^?Gl%!p)?!7-veScBD9*EV{jNoxB347-8;DVxTObvbzMrjjg|hu?}A(DQjAzx zk2-C(SAOS-es9ZDR*3J;B*-e+%}4sdzi*W)%jC16F}#Ci>9j_uBb}sJU5WYCl>{o+ z5CKf4P*xQu(sAm)9+Av;Y#5Z!QT~mJx5~E0@KGl8uzYTQGVu<_y>2JRNJt5sJf$wL zFzJH&5qj7g+CJt1u-?d^7`N#Q1GtuliL|ZXKum);)6{z~E?2|opX?jjJ0)v!0!lxA z7-y{e()ZlCkxyfJA?f(Z?0{#5hHCfYMlAyvml0DydvI^QMUg4bwFBJRfx;Vjw+&Q@ zob|BgSgqNnyfMb6)lqPBsYJpc+w}(8Lxq6yMTP((oaQVL1b|xp7GUgE`@4Bpdm@_0 z!CESCP{Y>ZzX%3xAz3aBh4!Zh*1hb9m9$~Ld?dJIj8g?8;@RuWiseJ24xO=f$SvZZ zqmWNmM|hd7{HJ{Ndx~)$VTw=;)p7zfM*(rT$LC3@cOfucut~oyJ`-5ul+6R~!6PR= z;O(!7`?B=-lfY8-RJ(#qg zKoCu>E#FSrbbvQR`+4c3*)cG6`>(U0mqj_O|sR)mvb=Ae+y{OQ;+i|*}1lv3e zUoo@peSm%BvUHPi-=qvAHvi4+_yHgyy5vYiy67px$er}8-Y zeE)k^iR^k8iO1xS$bPV5aeSg<4?FlrC^E1Rs8F`7ou6o*T&)=T%$8UVHT=m!=d3JGwfy~{fc6OmWBTV zq8-)GOV`=8x=x-={WREPDY_pKi!o`K4<$KDa0meGap!EwFN~vg@XS4ADN4IP^Vc`; z8fZm^W}@9$^!(E>U9YEqz#o2bWD<#O?oryx_}-{4c!h6~KQ1Wa8$gpz>*LDr0u}X( z)0Zgq2WoU*+b2tUK0*1pWH4zpfZS#*JCO9M53on6DDB|P2!NO$94-{4tp<`Ey=!eu@Gr#D2i-Mj4A;z@FlkpCF7?rM;z75V3o3UxyMjunE}ow9p;P znvEUA$E8*FN*<;La-h4xF{1uYX(%%@&*f3_)4$#?rA8=sBLSereDa#nm!a_1?gT&| z!*VS=Dt`C~Ycp{7j>6;eNIZQ#44%9pJ!E0^&BJ3|jQ;iVU+mAHeyQA*k+Doz^R;=s zI)eS)e&mbn672fUp6z?(aQ{&MDyYC|2Nt;BwRyare}aRb*nG%yar5*hiG22fER!3_ zIk|#6L`kf1d11TGh1ld5^_ou%k1z3(_v##|Uf@>9s(Svu(PuPkmY}WD6CT7Y+THoC|IRzj9knN< z3-NUD^v`-d`0*6WHevE5c;SzPo~{^H>YD-bTYCRhah?h1``wo(rz{E;`|s;rRDx{3 z=gwkzY=re%&?yXgmE+2L*Lfze2D;e2vCt@n`uaXFQNe;*V8ldtFjl}+llQI&P+&_9 z=XXZgJ%M|KQsZq0hXZPa6Mi*(@C0>;fl}LO>AKHFabKB@F0Np0dU)9UxrfNmdLG#;9%Ajfn>*h4TA>~SljAOqXMFxVLC`}cXGk9RlZU{3 z`vPC@r5F80i_3xyz7YKu^m~yfCc*|eXz6cbP`OYJToD~K6~WMPvPxc(?-Iq=wi{GEFxU2=z_X2j$$qcqfxFw%}Fo* zFNvQXU{<_dWng_kcDaMsRNZ7sul^HXn_ttrMThDVNFUN3UqKUoZYs+6V7Ok8-H@~3 zYYY?0M(9h)Gs)~NKj!S+x=0|%4l{24`so_;{Y8|JeZMFNt3UDH1_mVd_rzFtd)_Ms zBkYDBy3;G_Lv`(a?0$+P%1{?(^UjDkE4ePD}ZR!V5LmZko*SSqCuS>YMF^hqN3vf(eKm_`fQ`oy76@CB8dP;wY=K5nNJ(zx_Zj*cA{R3RlO%- z-a3$s80=X5>cMvxeDZ4em@~1>NC=mPOpm*T+cQL!kh9YBhCAM~D_)uXIR1LE_k631 zIpmIJyqq|G3c)I&H7wal&K%L&1)IZX?6Ps##hs^~a2}S8eP*`cF@!ytZkbwR3Nu;D zTs1Jrj{LCf20MDwc5%6_w2Lf<$mQ1~?EoOyHE86Sfuc~g^mWd zKJn?rVG~u0z`opXCg@YRjzjR-W?_~)ckof?;i6@-57KmD4CLV?T{X#W`&`IdP&SQ(SRacGvM9%vHqF3zrAj;Z+31xK^hI&SwjUD3@T zui*QVMdQhH;~exMVN~3B1qHon=H@OK;u6ifz&&`iDWWV^gih-5&V`U~GVmNz1ZKe+ z9@ZeqQ{?)o))f*S*FeqzCj%eXoAPv1bV1JhQrDRx@61v%qyn%ED9f)1lIisH-6o%` z@Tb$unjXFSR!Y9M->PpYU;hAA%9jn*Z#A1P(ZuPYL~XlN>Dw-Sc!(#5NhuIx5kzuJSKY>6b;E#5)XT*5l}Tx{2cf0_jg#7^l5wA^lYgWn*V$%A_%m9HD;f1Y)$!vcr(Z=^Wl5hkC2! zYlNB3D`yQqrBR<{cbT^ zj*Zhd$m1?29|w0ouihbfU-~s^KG-x_m(Z4(CZqo?6npnjm;cadDl1PHO5N96mMb?Kv7K ztUp+EQB$Vcp&@1E*563)e4U=t^6+lvQ^aJ+q;uyiZeppDl&M>C;s{!aVTFKN$Sv(z zt349E5)*t-xZ|bLH;<~nd~6lgk>^gr?r#fq>Ke=$>|rqt-fHWoV9@diy)9UMx5Vbx zk8Vntuh*+`oqpflgDyji<(hH5ma%ZLJdTS(TS|0IAm2NWrYPNIG`)G^=-W2&97E5b zmr$nE4AVvU3O8yBB^w^iVi+=DldOA)q|k%vG{#u1D3xy)Nrb1T*5ZUTr+USFiAEKa zzT3GUlpsCL>bsbi<`4Sn0-Sd3A~|?FGB2!XmJG{-iFdg7kqyySW1aC=o->F<@P70j z(%#%^C^BaGyXe3oTq#1YI`g_h6k$Qi!7*@_?f&>p)y_LLl^_w>>BMsTF3Zo|Zo!`` zrXR5hrBw`n(s4bmvo!#Rz;*d$N&V}VTJd8qH@+kJS{cVwW(c|s0eS&H$>+jYv8~>ED3CB{K3wx`zu1Ulh zjC+l|y<$Ip$N632R4II~T5CUU1;08@GIc_`aE>=v!^uhK=Z5#T%5q?;cZSyGD!X=L zdhyngbK;x*^0yIJZxvxVckk8N^U<5*YH$m7b$B10`|d9w{5d1)gW*8+wgc-&`w-dQRH)+xw*>)?wC9`v(Qq=QqDl z4dXNp%8ZqLexvC^y1Jg7#L_1AN!nxPobQ9*>E7DAl=Lm?_uZPAH%9k{r+p+L>{Aa< zT$;X3`d}15T|SYA|COoEy+po{`Au@`LK+`~fS~?e1lQ+u?gUqd@{nR~4NChBUmWp# zad8=G0YMXq!;=!Pk|MdPZ4D*{|BKe!d%=K50~UJ+7_7Hn7(y!hT&=GI`fX;{u`LP^ zneN&&QJbupLcXv*sug6Aqspcj=v;rewlTplaEw19o_lD}C|K7j&!qmO^C{KMA1P}W zv9Ym6eY=zl-niZ`7{;x0O|sK6IsPaSei!HZm`c&XobCESsVXNieh+9>Ez2W>@tB;` z{6HT(cGibvxF4v&X!=|`9M9z_Y+`GQ$}B@g-Ms4jQrt?I(V!M+|JejtV&vC~sDaVr z2LEUNhiN-OLX2bI3hWq_{`M*N2gF(B*7w>WWayobxI}|$A!eq>M!8-eJk9-hvtmjP zMWZt>*S?$%oM@!6D7E~uXFIci(ZOqX{rO<~ht>1_`sWw9j$!-bw%UQ!^akag zCn_?RTqL!FiCN2vx>JA9{ZMS6@Rzi(gbp(OEc1~|nv*WTQsHVA zYksV~#Lv3C=WraIRuC9R;$gaEj?!u8$E)~Zr=0R@+N`0Cfi|Jxs5OyJoqc>1n(>zP z%lwV$d#)DCK&)|h@3YnS6)Q5cEnmY%#B+4Rv5I_+4;io$%*p{F&s9BPHhq(P6Up%n{?9}c=BsN@=%hS7`OMG->q=z3D@Vhih1^bPUk>cB*_zH>C z_V}K2310fNb8c~(hu#j zQBvVAIMR*n7JZ+#<{~?6kczY={7SgZqB?@DzQR*xAHePYwC75ReV#Q2W6Ufo1;r=& zOLG3zyOMEFugq(s#OC%!sjRHdF!mlnnJ(NZlJNiZIe9c^=Rr@GJf;lZB-*vMvN`2^ zN&Z@KdwZ|+e^29)e)}l z0edXjsE@e5Xu`J~E7HFMQ%c<6VX_#5H-@>;thtaag zQ|>(exR7f3!jI{DCa)wrmFfP%nH1;L^`yc_`*@@5V)Pk-f)Do*h;a3Zg}!~}T-L~B z!D|s+tac3L_^~0{f1>wH*!z%OKTXyuA5qs3_-3Z9soV4VDLj1#TBWp*;y;D7N znZ}*rd;+gH|ED=fOU@xP>248{ua7LsG{C~Fg=;+5dL+x~2lIp}z25u0sW9c&QIp(U zgf*Ag4&|d(*kb2{`9=j644CKox;I8!6Us||_cwVN@|kinu>pejS3j38_I1NiBMmub zS%a}K<1KH9m1_Gh^yK<5^c)66a)~1^hwrX3F3Y4FKhwmcCeZi8^ttrk>UQ^;>7}=x z%2@v*rTy?$uQ?0~uo@c9Gq2H(&!t-hy00FSyvQ~m+=k{g;P4MVL+F>@8&GDVf3yNw zJIvj^92cUqb09x28CYnJuEOe9&R@Vp- z{_yUsx3<4;i(7eP>%7RZW^{T9)Fi1ol@ap2MIUM;UT%;TtN%_cIn;<*a!<7dA9lvdiE3wkGIqz>jG)LT zWwML&d)1);rFGbwUU0CUj(+hoWl?^HeAjMiDk!FCuIZWx)^DWz!Bt)VVuOOYQ@p?w z5;<8`p&I&fN3Z289@+y|?J4CD_JYLg=v0vP8@~_9iI#?1?T_8B4JN%zRKm=B*RWdW zK0PcZfIt7_r{xB;7J6R{^P)JHTI_C&o68qOH^fBO?VS~ULa8)b-K@Nr?sJ#W`6J2& zrlI^&#NIeO{nCK-aK_1+yCFz)vA;|jnJ*F`y(LarerWndx;!N(+5fk{K1CzK>^=M3 z`zD_V*+d87+g0497cqVlzmnkK`!C^z2`*OzTUQAM3L%Z6MKiaN6albBCEE_MAfD~P zY=m3onEpe2o~k|ZfW!CL24;=#TBjc}P)IV|AAh}H<0$TqM6r&};%vuIs5v-`_!#Fj zbucx#ga_SyIxFprWO^n*#{gwoND`K?dl+hL#FJ$OWxTT;DQ|o?*|Enc7@5IkXGhi} zbzNLC&@k((7+}t^HGI_AviYX@L;FC>$8Gn8IYIr2m3f-AZcTzC`5SQ~T=5K%Gf8>l zO!?C_#Yy&*)PTE~1;tNq#uv@xT77L^6$&?m2^(S%&rnyF~;i1CrlkH~4Zyboxk%!(LD-UAE?q>)juf}(}tikWA@LnmWPvD8n)9mr#d?3 zl1%isuK~oTLM(-mi7;1ncg8!$z1GO&rO5L$6k|45C@E*-WxVa?>NvD|U8F?R{Y`-! zUMlY}j^sGmJ1H(t--k1C^2q(=(yc^}Vf z$5ux{%~Xj5WE4{NDe>Fv&SM^=CjgIM!Ynx#{Q@KWFvhC(M`iG6O3H_vAtl9{m^a;RNPq zGh3CCUEUY=y;UWDy++uO-&*jw8T+KN81_uf$%R(86Ps{`q2if!v$pyy0n`* zP#Bn8J1TD}XzH<4_Z8dj&Fc1*M2?xiVps9a!Wqi?hbxeFQ7_+!5P6p2=Oy^+RNb)i zoRvtcgoGkXn+*7N=mRY%znN6)7O{y<=L^ozzDXLv6p}T=M$Z2@i0Sf7Ae4n%%57y_#aRt^Tm@54FS#Jl0G7MLe^dY-om{_4B`OBLQjoZB}tvS};Lp`%S*Y0LJ=W0Y*U0U{Dnd-Abk3Hn! zWe{#Hc9zOaf#_Ug7f>%P~qSQanV$;PbEs;wj2@{$1Cw zDUyuM5f7^|xrJ$xu(g&B>hvN{6BcEy&wnXPuHr6F#*QIyZf38a>V*VHKDj$f?%t0a zi#6@WI^H4ovmDgzMW@FFu9sQrGjXH1uAryL6V2^Dh_4sy+cu5kxia>rBykoM1y~7( zLYgy_JMrF(Bz1`{<2S?GnQHw_yXYseQThat{-FGDI#j+`cyzFaW85Nc^L5T4MHEu} z`s{}S?MT}uS*n@C_>`S?I`nikAI7T34#gW4T)@{ zJ^otFT|^VumX~Ok7hXA&uM!359vwcAK$Eo8dalAd3C8Iydq)>p++*#% zYlJUmK5NmxRMBdXHp{%rEPW|27G_p3fI zsz1u!a@n+`FWA}(LELjue5i$aivdcu&qjqVHjJSOJ*2NXLJStzLjZ$)$Q zbGlYa1{qyP4ZmIQ<*zDMh}PCqN%*~D^VQbx;XM?ThHRkxJ1}^cCzZr_Fc?j0N0OE%3rxr?asV0TVmdT-lm2&XBHxz|q}rCz@Z>QkJm&Xzvv; zbX2RT3~W@V{f5+Mf|tlTM6}D<8V&HVk2;Qu6SDAj)(mI|zUZk<`Y75YMe16=m;0oD zs=u+pZIRO6A@Zx-Jgp-Z@2WZWhBEcSJ!s~@C-$uWcV=99)IEs-wR_xN-zIMpp>)mz z9P?4lr5;kAL7ph_6xE+3KUlDQcgs1^k;vN77k`5OcLszFWba#@NABV`HD(AD+Xyq- z?FIyKA3A=1pvwIulg?tR#;xrg zm)t#_Rq^-Em#NTbR26#;S@jFCHGJjF*iO$K_BN$@?U`Q924};pbPz7T&B!U{zS-Ut z@Z{;4LE}nYZNT;<8^Jh({@z1z?!$yg?1Gm24k-rfg zwhn{w3S|@gG1V^}W?TRF5B@h|vIh|#6FvcxFkNX zTN0s{nDe^L?-3U^ctH^eIAZ=GnE6$y<=8hpqQ?$~RZ=u6zxs{sgv7idng#|7-8-_}QrQT)!iuiRgr3vX{0FXxcGvyv4~&~~j4ni^n}`^=Zn;^dKx z7#{urGG%7E>dDt7TI!OTxhM?@KPDXsZyB7_A=$_ zU7{?8?)vs_#Na{ovG;ir^O*`{QYgCqDCCWhsT1{6m@7lR2@a;$TxQK!DI{pB1>I}8!`(BDMc3Ax(moZ0=aHTS}P0X`Q zvE2u!Fu#VvDJ6rprNFqxv%v{9pVWo!E8;(lkzdR3(HF0T>~V{Jl;yX6Qqi@xU$K)o zVHtZ$i{ddpn{cH~*%e7rAee7#Gs(O(tkCV3iqI|`(_tv3={T>7Umw6WW?8qlE%Zv` zY-?u?EY6&chc|emEJp3O@?3!|fWm(!n&+)Ib(yPfv!SI|^qo)4Pl4ganeutpVRWR8 z5sjx!^2lJ1JgN0kduTKEM3=*TPqzGVLI@V+~b7ccsi< z{AS`j>|39sYMe!w?+ca6^RY1&<(CkY&X=A;C`~U%muN&jkInp`@`k8~@1H@*i`uO} z=v7ePMp52*D~pEdhL7)`YwCNnq)bb9oP+M9T%6X?jHtMu~G}d0~#Q3KrZ;n9Oi0OQF zRmO*GX4dhsS!hwXCIe?b@p_S>U*M8o=SKGILQs`)1$L&##Xm8I7i!h zMw_(w$kzN!UMJ%`KyTi$%b8NOm)nS@-;|uS6*gmmh1J=^ZC7D)z4aoWx`%vXevi%Nh?#~sLm`(X@q>pUY=Ff7oF(uOs?%-&5^FiJzm zOumI23#POh9#{z)Ll>+~3Uy()B`i#6Nvs_UtVR018rcoTXVn>v)N?ic5aw$+4PqEK z3-Inw;hITYUpM@Qr!mYUe89Kk3Atz#2#!P!EvR^g4Natb{gir7De@!Y8m7c>+N!pE zeT*~Py+KVNAdQ~f{30drK&^mbl&lfCR}ls-k{eeNldi42I}nKIUmfr za&kU+EzRLahUb2tAgYQu7WzI~*WPRNqX{+j064W_8|O{NkaW@rz2{vgitTm*(%Y-| z@`gXpO;DG|5hgg&AeHLU{6beb(xY#&Cv*K4IJ}-Yq@(G=X?{O=|7NdN9Y&C{cYfP& z#;6+!y|lIsQAIqL=}#789G7lCoRRQrQXf5w>3XLBK2|VqD(122~&I&RwfHYTTFp& z-sIn+%XysAC!=RCK{i!4#CQfq7?jT$Be+H`6e1<>7<>Pe!BU?u&NOI^^IF#986m}| zl2ro&NE3P+j+uT68S5&+!?!84jqqGR5tsdPer2q7~vZz7y*Sg2@;4#3O2fc9cAX)x@D0(&)@#p!X(sq z{LJ^;w*O+hxUnb9FOEema
i;3{=i`?*oe!J#7U4yX>?xnqtFn5 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
hL6k9UzqC=wD2s>Ub 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 literal 0 HcmV?d00001 diff --git a/SPEX/Doc/appendix_A.tex b/SPEX/Doc/appendix_A.tex new file mode 100644 index 0000000000..59559da2ed --- /dev/null +++ b/SPEX/Doc/appendix_A.tex @@ -0,0 +1,426 @@ +\documentclass[10pt]{article} +\usepackage{longtable} +\usepackage{xcolor} + +\newcommand{\blu}{ + \color{blue} + } + +\newcommand{\red}{ + \color{red} + } + +\begin{document} + +\appendix + +\section{Comprehensive Computational Results} \label{s:ResultsALL} + +Tables \ref{supptab:all_large}, \ref{supptab:all_medium}, \ref{supptab:all_small}, and \ref{supptab:all_tiny} present exhaustive computational results for large (those requiring $\geq1$ hour of run time), medium (those requiring between 1 hour and 1 minute of run time), small (those requiring between 1 minute and $0.1$ seconds of run time) and tiny (those requiring less than $0.1$ seconds) instances, respectively. In each table, the first five columns give the name (or index from SJ database), dimension, number of nonzeros, MATLAB estimated condition number, and MATLAB estimated sparse norm in each matrix. Column 6 gives the run time of SPEX Left LU using the selected pivoting scheme tol 0. Lastly, columns 7 and 8 give the relative run time of Wiedemann and Lanczos, respectively. Note that those instances in which these algorithms seg-fault are indicated with {\bf \red SF} and those instances whose solutions were incorrect are indicated with bold red text. + +\begin{longtable}{|l|r|r|r|r|r|r|r|} +\hline +& & & & & & \multicolumn{2}{c|}{Relative Run Time} \\ \hline +\multicolumn{1}{|c|}{Matrix Name} & \multicolumn{1}{c|}{n} & \multicolumn{1}{c|}{nnz} & \multicolumn{1}{c|}{Cond} & \multicolumn{1}{c|}{norm} & \multicolumn{1}{c|}{SPEX time (hr)} & \multicolumn{1}{c|}{Wiedemann} & \multicolumn{1}{c|}{Lanczos} \\ \hline \endhead +350 & 6774 & 33744 & 7.68E+13 & 1.26E+06 & 10.40 & 0.01 & 0.01 \\ +367 & 7337 & 156508 & 7.64E+13 & 1.83E+01 & 10.12 & 0.04 & 0.04 \\ +696 & 14454 & 147972 & 4.44E+12 & 5.31E+03 & 9.78 & {\bf \red SF} & {\bf \red SF} \\ +695 & 14454 & 147972 & 3.10E+12 & 5.31E+03 & 9.67 & {\bf \red SF} & {\bf \red SF} \\ +213 & 3402 & 130371 & 2.67E+16 & 3.98E+14 & 8.31 & 0.02 & 0.02 \\ +352 & 5773 & 71701 & 8.77E+12 & 1.29E+08 & 8.09 & 0.03 & 0.03 \\ +119 & 3251 & 65875 & 2.62E+16 & 1.27E+07 & 7.54 & 0.01 & 0.01 \\ +344 & 3363 & 99471 & 4.08E+13 & 3.79E+09 & 7.37 & 0.02 & 0.02 \\ +337 & 5321 & 65693 & 2.10E+13 & 4.68E+06 & 6.74 & 0.02 & 0.02 \\ +117 & 3973 & 79077 & 1.49E+19 & 1.28E+02 & 6.51 & 0.02 & 0.02 \\ +346 & 7055 & 30082 & 1.65E+12 & 4.02E+02 & 6.35 & 0.03 & 0.03 \\ +347 & 7055 & 30082 & 6.34E+17 & 4.02E+02 & 6.09 & {\bf \red *0.02} & {\bf \red *0.02} \\ +140 & 3937 & 25407 & 1.04E+17 & 3.27E+11 & 5.06 & 0.01 & 0.01 \\ +221 & 4257 & 37465 & 2.52E+16 & 1.46E+02 & 4.50 & {\bf \red *0.01} & {\bf \red *0.01} \\ +222 & 4257 & 37465 & 2.52E+16 & 1.46E+02 & 4.49 & {\bf \red *0.01} & {\bf \red *0.01} \\ +223 & 4257 & 37465 & 1.21E+19 & 1.46E+02 & 4.49 & {\bf \red *0.01} & {\bf \red *0.01} \\ +142 & 3937 & 25407 & 1.04E+17 & 3.27E+11 & 4.41 & 0.01 & 0.01 \\ +341 & 2880 & 18229 & 9.74E+13 & 1.39E+04 & 4.25 & 0.01 & 0.01 \\ +349 & 4101 & 82682 & 1.44E+13 & 1.34E+01 & 3.54 & 0.03 & 0.04 \\ +pilot87.pre & 1540 & 30916 & Inf & Inf & 2.70 & 0.01 & 0.01 \\ +118 & 2568 & 75628 & 4.01E+15 & 1.26E+10 & 2.18 & 0.04 & 0.04 \\ +pilot87 & 1625 & 31396 & Inf & Inf & 1.85 & 0.01 & 0.01 \\ +gen4 & 375 & 8919 & 8.43E+236 & Inf & 1.25 & 0.01 & 0.01 \\ +217 & 4720 & 20042 & 3.51E+48 & 1.89E+02 & 1.16 & 0.06 & 0.06 \\ +self & 924 & 157411 & 1.20E+07 & 1.57E+11 & 1.15 & 0.02 & 0.02 \\ +gen4.pre & 367 & 9322 & Inf & Inf & 1.12 & 0.01 & 0.01 \\ +\hline +\caption{Comprehensive Results: Large Instances} +\small +\centering +\label{supptab:all_large} +\end{longtable} + + +\begin{longtable}{|l|r|r|r|r|r|r|r|} +\hline +& & & & & & \multicolumn{2}{c|}{Relative Run Time} \\ \hline +\multicolumn{1}{|c|}{Matrix Name} & \multicolumn{1}{c|}{n} & \multicolumn{1}{c|}{nnz} & \multicolumn{1}{c|}{Cond} & \multicolumn{1}{c|}{Norm} & \multicolumn{1}{c|}{SPEX time (min)} & \multicolumn{1}{c|}{Wiedemann} & \multicolumn{1}{c|}{Lanczos} \\ \hline \endhead +slptsk & 2315 & 34430 & 4.35E+185 & NaN & 54.85 & 0.19 & 0.19 \\ +gen1 & 329 & 11016 & Inf & Inf & 44.42 & 0.03 & 0.03 \\ +207 & 1919 & 32399 & 3.73E+18 & 2.92E+00 & 33.82 & 0.04 & 0.04 \\ +335 & 6747 & 29195 & 2.22E+18 & 5.41E+08 & 32.89 & 0.21 & 0.21 \\ +87 & 2500 & 12349 & 4.35E+17 & 9.83E+03 & 26.86 & 0.05 & 0.05 \\ +pla8\_sig185 & 39835 & 196256 & 4.29E+09 & 1.04E+03 & 17.17 & 0.16 & 0.17 \\ +355 & 1409 & 42760 & 2.28E+13 & 2.67E+05 & 13.90 & 0.08 & 0.08 \\ +159 & 1050 & 26198 & 9.00E+15 & 2.10E+07 & 12.37 & 0.04 & 0.04 \\ +pilot & 1132 & 16624 & 1.12E+175 & NaN & 10.04 & 0.03 & 0.03 \\ +maros-r7 & 1350 & 31923 & 7.43E+06 & 3.99E+10 & 8.62 & 0.03 & 0.03 \\ +320 & 1733 & 22189 & 1.20E+13 & 1.18E+11 & 8.30 & 0.14 & 0.15 \\ +stat96v4 & 3139 & 23752 & 9.62E+17 & 1.63E+21 & 6.47 & 0.17 & 0.17 \\ +pla85900.nov21 & 40304 & 230558 & 5.46E+08 & 9.76E+02 & 6.17 & 0.49 & 0.50 \\ +153 & 765 & 24382 & 1.67E+14 & 1.35E+17 & 5.68 & 0.08 & 0.08 \\ +58 & 3083 & 11767 & 2.30E+21 & 1.21E+09 & 5.62 & 0.23 & 0.23 \\ +momentum3 & 3254 & 15159 & Inf & Inf & 5.36 & 0.31 & 0.31 \\ +jendrec1 & 1779 & 34196 & 9.54E+217 & NaN & 4.12 & 3.64 & 3.64 \\ +296 & 1258 & 7682 & 1.03E+13 & 2.05E+07 & 3.99 & 0.07 & 0.06 \\ +brd14051 & 16360 & 180847 & 2.96E+08 & 2.74E+02 & 3.07 & 0.41 & 0.41 \\ +fome13 & 24884 & 70839 & 7.99E+15 & 4.02E+11 & 3.07 & 0.34 & 0.34 \\ +240 & 1000 & 1000000 & 1.61E+21 & 6.46E+00 & 2.69 & {\bf \red *6.22} & {\bf \red *6.09} \\ +236 & 1000 & 1000000 & 3.25E+19 & 3.23E+00 & 2.38 & {\bf \red *6.53} & {\bf \red *6.73} \\ +mod2.pre & 4422 & 12914 & 3.72E+246 & NaN & 2.29 & 1.48 & 1.48 \\ +260 & 1000 & 1000000 & 1.15E+14 & 5.36E-01 & 2.23 & {\bf \red *7.04} & {\bf \red *7.03} \\ +world & 4261 & 12190 & 5.65E+241 & NaN & 2.18 & 1.26 & 1.27 \\ +l30 & 2492 & 12653 & 1.73E+08 & 2.61E+09 & 2.15 & 0.21 & 0.22 \\ +340 & 8765 & 42471 & 6.15E+14 & 1.00E+15 & 1.82 & 11.26 & 11.13 \\ +cont11\_l & 58936 & 179556 & 3.65E+26 & 7.37E+00 & 1.80 & 9.68 & 9.67 \\ +mod2 & 4435 & 12985 & 1.38E+223 & NaN & 1.74 & 1.77 & 1.79 \\ +309 & 2837 & 10967 & 5.85E+12 & 7.41E+05 & 1.58 & 0.82 & 0.81 \\ +314 & 2836 & 10965 & 5.85E+12 & 7.41E+05 & 1.58 & 0.81 & 0.83 \\ +232 & 1000 & 1000000 & 1.85E+21 & 8.11E-01 & 1.44 & {\bf \red *10.48} & {\bf \red *10.32} \\ +gen2 & 328 & 8894 & 1.84E+11 & 4.51E+18 & 1.35 & 0.04 & 0.04 \\ +scfxm1-2r-256 & 11812 & 44985 & 3.12E+12 & 2.84E+08 & 1.11 & 2.95 & 2.94 \\ +\hline +\caption{Comprehensive Results: Medium Instances} +\small +\centering +\label{supptab:all_medium} +\end{longtable} + + + + + + +\begin{longtable}{|l|r|r|r|r|r|r|r|} +\hline +& & & & & & \multicolumn{2}{c|}{Relative Run Time} \\ \hline +\multicolumn{1}{|c|}{Matrix Name} & \multicolumn{1}{c|}{n} & \multicolumn{1}{c|}{nnz} & \multicolumn{1}{c|}{Cond} & \multicolumn{1}{c|}{Norm} & \multicolumn{1}{c|}{SPEX time (s)} & \multicolumn{1}{c|}{Wiedemann} & \multicolumn{1}{c|}{Lanczos} \\ \hline \endhead +nemswrld & 2205 & 13323 & NaN & Inf & 53.50 & 0.34 & 0.34 \\ +cont4 & 2802 & 11862 & 3.85E+05 & 3.98E+03 & 44.81 & 0.28 & 0.29 \\ +rat5 & 902 & 12026 & 4.19E+06 & 7.48E+05 & 40.77 & 0.10 & 0.10 \\ +nug30 & 14681 & 45627 & 1.06E+06 & 7.88E+00 & 37.07 & 0.68 & 0.63 \\ +nug20 & 7733 & 31455 & 8.84E+07 & 7.26E+00 & 35.20 & 0.26 & 0.28 \\ +stat96v1 & 5013 & 20325 & 6.35E+32 & 8.22E+20 & 34.16 & 0.45 & 0.44 \\ +stat96v2 & 12928 & 48009 & 1.06E+13 & 1.32E+10 & 32.85 & 1.07 & 1.08 \\ +210 & 1484 & 6110 & 5.57E+17 & 1.26E+16 & 29.97 & 0.95 & 0.96 \\ +pla33810 & 18940 & 123445 & 1.05E+08 & 2.20E+02 & 29.57 & 1.64 & 1.61 \\ +stat96v3 & 13485 & 49917 & 3.93E+12 & 6.98E+09 & 27.62 & 1.29 & 1.31 \\ +nug15 & 5486 & 24736 & 2.41E+07 & 7.73E+00 & 26.99 & 0.19 & 0.17 \\ +pilot.ja & 567 & 3781 & Inf & Inf & 25.13 & 0.32 & 0.31 \\ +model10 & 1341 & 6403 & 1.71E+164 & Inf & 24.62 & 0.50 & 0.50 \\ +rat7a & 641 & 10542 & 1.38E+20 & 5.06E+05 & 18.88 & 0.12 & 0.13 \\ +d2q06c & 1047 & 5717 & 1.82E+188 & Inf & 18.27 & 0.48 & 0.48 \\ +128 & 760 & 5739 & 1.12E+16 & 3.10E+08 & 18.26 & 0.29 & 0.29 \\ +d15112 & 9197 & 47335 & 2.33E+18 & 2.25E+11 & 17.95 & 2.21 & 2.23 \\ +141 & 511 & 2796 & 6.37E+15 & 4.21E+10 & 16.60 & 0.17 & 0.16 \\ +144 & 511 & 2796 & 6.37E+15 & 4.21E+10 & 16.49 & 0.17 & 0.17 \\ +progas & 1167 & 6500 & 8.15E+103 & 6.78E+100 & 14.19 & 0.91 & 0.91 \\ +co9 & 2287 & 13481 & 2.32E+49 & 1.56E+42 & 13.06 & 0.98 & 0.99 \\ +stat96v5 & 812 & 3795 & 1.42E+63 & 3.93E+64 & 13.00 & 1.11 & 1.11 \\ +l30.pre & 1199 & 6030 & 1.79E+06 & 2.61E+09 & 12.56 & 0.24 & 0.24 \\ +scfxm1-2b-64 & 5966 & 22682 & 1.30E+12 & 2.84E+08 & 12.11 & 3.96 & 3.94 \\ +158 & 416 & 8562 & 2.41E+25 & 2.54E+03 & 12.08 & 0.24 & 0.25 \\ +scfxm1-2r-128 & 5671 & 21943 & 1.64E+12 & 2.84E+08 & 11.80 & 3.89 & 3.85 \\ +332 & 4101 & 36879 & 6.72E+20 & 2.02E+06 & 11.67 & 12.63 & 12.65 \\ +NSR8K & 5387 & 46157 & 2.64E+07 & 2.06E+03 & 11.62 & 0.66 & 0.66 \\ +qap12 & 2740 & 12014 & 2.46E+07 & 6.84E+00 & 10.96 & 0.11 & 0.11 \\ +newman2 & 468 & 7917 & 1.39E+225 & Inf & 10.85 & 0.23 & 0.23 \\ +watson\_1 & 5729 & 14544 & 7.98E+58 & 9.72E+55 & 9.00 & 10.75 & 10.84 \\ +209 & 415 & 2779 & 1.04E+18 & 6.47E+00 & 8.66 & 0.23 & 0.25 \\ +pilotnov & 549 & 3337 & 2.82E+264 & NaN & 8.64 & 0.54 & 0.54 \\ +239 & 500 & 250000 & 3.27E+20 & 6.46E+00 & 8.38 & {\bf \red *15.04} & {\bf \red *15.55} \\ +momentum2 & 2113 & 6516 & 2.52E+39 & 1.88E+37 & 8.35 & 1.10 & 1.08 \\ +238 & 200 & 40000 & 8.07E+19 & 6.46E+00 & 8.32 & 0.68 & 0.68 \\ +pilot4 & 289 & 2805 & Inf & Inf & 7.75 & 0.57 & 0.57 \\ +235 & 500 & 250000 & 1.01E+19 & 3.23E+00 & 7.52 & {\bf \red *16.55} & {\bf \red *16.30} \\ +231 & 500 & 250000 & 8.95E+20 & 8.11E-01 & 7.43 & {\bf \red *15.82} & {\bf \red *16.21} \\ +dbic1 & 4795 & 23403 & 1.04E+11 & 4.53E+06 & 7.18 & 1.05 & 1.04 \\ +perold & 440 & 2584 & 4.45E+256 & NaN & 7.13 & 0.56 & 0.56 \\ +259 & 500 & 250000 & 1.65E+14 & 5.36E-01 & 7.12 & {\bf \red *16.58} & {\bf \red *16.49} \\ +watson\_1.pre & 4642 & 12991 & 3.44E+58 & 9.72E+55 & 7.05 & 10.03 & 9.87 \\ +cont1\_l & 1070 & 4649 & 1.22E+09 & 2.51E+05 & 6.23 & 0.47 & 0.46 \\ +scfxm1-2r-96 & 4504 & 17205 & 1.35E+12 & 2.84E+08 & 6.22 & 4.32 & 4.30 \\ +126 & 1220 & 5884 & 1.06E+14 & 9.34E+00 & 5.99 & 2.16 & 2.19 \\ +291 & 1220 & 5860 & 1.80E+13 & 8.78E+00 & 5.91 & 2.14 & 2.16 \\ +212 & 882 & 3354 & 7.98E+16 & 6.69E+12 & 5.87 & 1.52 & 1.51 \\ +125 & 1220 & 5892 & 1.58E+17 & 2.88E+00 & 5.69 & 2.25 & 2.24 \\ +nug12 & 2736 & 12037 & 2.25E+07 & 6.97E+00 & 5.62 & 0.22 & 0.23 \\ +288 & 1220 & 5852 & 2.74E+13 & 1.23E+01 & 5.55 & 2.35 & 2.29 \\ +pcb3038 & 3588 & 46560 & 2.00E+06 & 1.55E+02 & 5.41 & 0.72 & 0.72 \\ +127 & 1220 & 5855 & 6.25E+14 & 3.70E+02 & 5.39 & 2.36 & 2.38 \\ +model11 & 2039 & 7606 & 1.40E+32 & 3.38E+29 & 5.28 & 1.11 & 1.10 \\ +294 & 1220 & 5892 & 2.74E+13 & 1.23E+01 & 5.20 & 2.49 & 2.43 \\ +287 & 1220 & 5888 & 4.14E+13 & 1.63E+01 & 4.65 & 2.78 & 2.79 \\ +289 & 1220 & 5884 & 1.42E+13 & 4.95E+00 & 4.39 & 2.87 & 2.86 \\ +292 & 1220 & 5888 & 3.45E+13 & 2.02E+01 & 4.29 & 2.94 & 2.93 \\ +nemspmm2 & 949 & 6478 & 2.61E+222 & Inf & 4.24 & 1.02 & 1.02 \\ +211 & 768 & 2934 & 1.29E+17 & 1.36E+13 & 4.01 & 1.69 & 1.67 \\ +293 & 1220 & 5892 & 1.58E+13 & 8.37E+00 & 3.40 & 3.65 & 3.69 \\ +stormg2\_1000.pre & 13926 & 32547 & 2.13E+11 & 2.59E+05 & 3.27 & 31.02 & 31.19 \\ +124 & 1220 & 5892 & 2.24E+34 & 2.87E+00 & 2.91 & 3.98 & 3.92 \\ +stormg2\_1000 & 14075 & 32597 & 3.77E+09 & 1.05E+04 & 2.90 & 32.90 & 32.98 \\ +152 & 180 & 2659 & 3.59E+17 & 2.04E+19 & 2.60 & 0.32 & 0.32 \\ +fome12 & 12652 & 35969 & 8.93E+05 & 4.65E+01 & 2.53 & 4.63 & 4.58 \\ +nl & 890 & 2919 & 5.83E+293 & Inf & 2.46 & 3.32 & 3.33 \\ +fnl4461 & 5044 & 46977 & 4.12E+06 & 2.35E+02 & 2.36 & 2.28 & 2.31 \\ +model6 & 790 & 3425 & 5.17E+63 & 4.11E+61 & 2.35 & 1.22 & 1.21 \\ +scfxm1-2r-64 & 1870 & 11122 & 8.23E+11 & 2.84E+08 & 2.31 & 4.92 & 4.93 \\ +co5 & 928 & 6173 & 3.86E+185 & Inf & 2.26 & 2.21 & 2.20 \\ +pla7397 & 5059 & 42683 & 8.55E+06 & 3.36E+02 & 2.17 & 2.11 & 2.13 \\ +nemspmm1 & 982 & 5023 & 4.94E+23 & 1.59E+20 & 2.12 & 1.30 & 1.30 \\ +315 & 2053 & 18447 & 6.71E+16 & 2.03E+04 & 2.09 & 16.27 & 16.18 \\ +rl11849 & 6769 & 40885 & 1.21E+08 & 1.92E+02 & 2.09 & 3.40 & 3.36 \\ +d18512 & 10815 & 55880 & 8.61E+05 & 2.09E+02 & 1.99 & 7.06 & 7.00 \\ +cq9 & 1187 & 5786 & 4.94E+165 & Inf & 1.52 & 3.14 & 3.13 \\ +qap10 & 1510 & 6381 & 4.45E+06 & 6.13E+00 & 1.49 & 0.21 & 0.20 \\ +de080285 & 368 & 1493 & 1.06E+78 & 1.36E+79 & 1.41 & 1.12 & 1.11 \\ +rail4284 & 2463 & 11802 & 3.58E+04 & 7.23E+00 & 1.37 & 0.63 & 0.63 \\ +pilot.we & 554 & 2367 & 5.11E+137 & 4.03E+133 & 1.27 & 2.60 & 2.63 \\ +newman & 334 & 2156 & 6.20E+233 & Inf & 1.24 & 0.97 & 0.98 \\ +ge & 1675 & 4758 & 3.29E+130 & 7.56E+127 & 1.14 & 7.58 & 7.65 \\ +rat1 & 452 & 2893 & 3.93E+27 & 2.26E+30 & 1.10 & 0.70 & 0.68 \\ +dano3mip.pre & 1091 & 5239 & 3.46E+10 & 1.36E+05 & 1.08 & 0.41 & 0.41 \\ +342 & 10001 & 49999 & 4.17E+18 & 5.00E+03 & 0.98 & {\bf \red *846.53} & {\bf \red *845.32} \\ +t0331-4l & 520 & 5034 & 2.75E+04 & 1.10E+01 & 0.91 & 0.25 & 0.25 \\ +132 & 216 & 812 & 8.10E+14 & 1.39E+00 & 0.89 & 0.48 & 0.44 \\ +model5 & 492 & 2247 & 7.35E+109 & 1.03E+108 & 0.88 & 2.13 & 2.09 \\ +dano3mip & 1135 & 5390 & 2.47E+10 & 1.36E+05 & 0.85 & 0.55 & 0.52 \\ +grow22 & 434 & 4711 & 2.09E+17 & 4.39E+16 & 0.85 & 1.29 & 1.30 \\ +rl5915 & 3853 & 28829 & 3.43E+06 & 1.03E+02 & 0.82 & 3.22 & 3.24 \\ +model9 & 902 & 4361 & 3.90E+23 & 6.53E+20 & 0.75 & 2.31 & 2.31 \\ +siena1 & 1265 & 11573 & 6.40E+05 & 7.85E+02 & 0.67 & 0.63 & 0.62 \\ +fome11 & 6226 & 17749 & 6.31E+05 & 5.09E+01 & 0.64 & 4.35 & 4.28 \\ +model7 & 646 & 2850 & 2.89E+137 & 2.87E+134 & 0.64 & 2.59 & 2.61 \\ +rl5934 & 3773 & 23917 & 2.94E+06 & 1.11E+02 & 0.63 & 3.26 & 3.21 \\ +nesm & 279 & 895 & 1.01E+127 & 1.12E+125 & 0.63 & 3.20 & 3.22 \\ +model4 & 409 & 1898 & 9.08E+213 & NaN & 0.57 & 2.61 & 2.59 \\ +de063155 & 313 & 1233 & 1.09E+95 & 6.12E+69 & 0.54 & 2.33 & 2.30 \\ +lp22.pre & 1811 & 13146 & 3.89E+05 & 1.27E+01 & 0.52 & 1.44 & 1.36 \\ +orna1 & 810 & 2842 & 2.66E+13 & 2.55E+15 & 0.51 & 3.36 & 3.38 \\ +lp22 & 1796 & 13076 & 1.32E+05 & 1.29E+01 & 0.49 & 1.60 & 1.55 \\ +scfxm1-2r-32 & 1447 & 5658 & 2.93E+11 & 2.84E+08 & 0.46 & 6.37 & 6.50 \\ +233 & 100 & 10000 & 1.69E+20 & 3.23E+00 & 0.44 & 1.66 & 1.71 \\ +van & 7417 & 21681 & 4.24E+04 & 7.23E+00 & 0.44 & 7.33 & 7.27 \\ +usa13509 & 3595 & 19919 & 2.89E+08 & 1.70E+02 & 0.43 & 6.23 & 6.11 \\ +237 & 100 & 10000 & 1.08E+19 & 6.46E+00 & 0.40 & 1.92 & 1.85 \\ +arki001 & 160 & 893 & 4.46E+299 & Inf & 0.37 & 4.08 & 4.07 \\ +230 & 200 & 40000 & 9.06E+19 & 8.11E-01 & 0.37 & {\bf \red *15.47} & {\bf \red *15.07} \\ +greenbeb & 713 & 3278 & 1.17E+25 & 9.16E+21 & 0.36 & 3.26 & 3.27 \\ +234 & 200 & 40000 & 1.74E+18 & 3.23E+00 & 0.35 & {\bf \red *15.54} & {\bf \red *16.51} \\ +280 & 430 & 1544 & 2.91E+13 & 2.00E+06 & 0.35 & 4.89 & 4.87 \\ +258 & 200 & 40000 & 1.40E+14 & 5.36E-01 & 0.35 & {\bf \red *15.23} & {\bf \red *15.24} \\ +grow15 & 297 & 3614 & 1.65E+13 & 4.24E+16 & 0.34 & 1.62 & 1.60 \\ +complex & 327 & 10738 & 9.05E+04 & 5.39E+01 & 0.33 & 0.44 & 0.43 \\ +scfxm1-2r-27 & 1222 & 4753 & 5.08E+10 & 2.84E+08 & 0.33 & 6.63 & 6.65 \\ +newman3 & 369 & 3662 & 1.58E+23 & 3.91E+19 & 0.30 & 1.45 & 1.47 \\ +momentum1 & 932 & 2792 & 1.18E+146 & 2.49E+141 & 0.30 & 7.92 & 7.89 \\ +dfl001 & 3271 & 9276 & 4.54E+05 & 4.33E+01 & 0.27 & 2.82 & 2.81 \\ +dfl001.pre & 2097 & 6501 & 4.10E+05 & 3.99E+01 & 0.27 & 1.33 & 1.31 \\ +stair & 324 & 3431 & 1.27E+19 & 4.02E+15 & 0.27 & 1.18 & 1.15 \\ +stocfor3 & 1782 & 4562 & 2.03E+31 & 3.50E+27 & 0.26 & 23.01 & 22.94 \\ +large000 & 823 & 2282 & 1.39E+31 & 1.02E+34 & 0.25 & 14.33 & 14.49 \\ +ulevimin & 697 & 1879 & 8.89E+103 & 5.41E+96 & 0.24 & 5.86 & 5.95 \\ +t1717 & 549 & 3657 & 1.89E+04 & 7.40E+00 & 0.24 & 0.40 & 0.44 \\ +de063157 & 282 & 1102 & 1.10E+97 & 6.45E+77 & 0.24 & 4.26 & 4.30 \\ +car4 & 122 & 4384 & 1.30E+14 & 4.51E+15 & 0.22 & 1.35 & 1.35 \\ +greenbea & 664 & 2706 & 2.17E+38 & 2.38E+32 & 0.21 & 4.38 & 4.46 \\ +pcb3000 & 3058 & 27446 & 5.01E+04 & 6.24E+01 & 0.21 & 6.87 & 6.91 \\ +25fv47 & 416 & 2061 & 1.42E+35 & 7.33E+32 & 0.21 & 2.01 & 1.94 \\ +277 & 183 & 1069 & 2.69E+13 & 1.15E+09 & 0.20 & {\bf \red *1.46} & {\bf \red *1.45} \\ +stp3d & 10642 & 25936 & 4.12E+05 & 4.28E+00 & 0.20 & 28.09 & 27.93 \\ +trento1 & 1070 & 10010 & 1.54E+05 & 6.57E+02 & 0.19 & 1.23 & 1.23 \\ +cq5 & 570 & 2615 & 1.05E+164 & Inf & 0.19 & 5.51 & 5.48 \\ +dc1l & 851 & 5171 & 1.68E+05 & 9.70E+02 & 0.18 & 0.72 & 0.72 \\ +gran & 284 & 1958 & 7.38E+32 & 1.25E+27 & 0.17 & 3.00 & 3.00 \\ +dg012142 & 892 & 3627 & 9.32E+07 & 2.13E+04 & 0.15 & 2.51 & 2.42 \\ +nug08 & 732 & 3004 & 2.49E+05 & 5.71E+00 & 0.15 & 0.42 & 0.43 \\ +watson\_2 & 1011 & 2703 & 7.02E+42 & 1.78E+40 & 0.15 & 10.16 & 10.25 \\ +dc1c & 808 & 4698 & 1.26E+06 & 9.63E+02 & 0.14 & 0.79 & 0.81 \\ +scfxm1-2r-16 & 752 & 2962 & 1.94E+10 & 2.84E+08 & 0.13 & 5.99 & 6.02 \\ +air04 & 630 & 4187 & 1.29E+04 & 8.67E+00 & 0.12 & 0.55 & 0.55 \\ +aa01 & 630 & 4187 & 1.29E+04 & 8.67E+00 & 0.12 & 0.57 & 0.56 \\ +nemsemm2 & 789 & 2440 & 1.78E+124 & 1.79E+123 & 0.12 & 16.53 & 16.46 \\ +scfxm1-2b-16 & 784 & 2975 & 3.37E+10 & 2.84E+08 & 0.12 & 6.69 & 6.76 \\ +pf2177 & 406 & 1772 & 9.40E+03 & 4.65E+00 & 0.12 & 0.27 & 0.28 \\ +dolom1 & 806 & 5681 & 3.47E+05 & 2.27E+03 & 0.11 & 1.11 & 1.13 \\ +model3 & 310 & 1417 & 3.11E+95 & 6.44E+93 & 0.10 & 3.27 & 3.25 \\ +\hline +\caption{Comprehensive Results: Small Instances} +\small +\centering +\label{supptab:all_small} +\end{longtable} + + + +\begin{longtable}{|l|r|r|r|r|r|r|r|} +\hline +& & & & & & \multicolumn{2}{c|}{Relative Run Time} \\ \hline +\multicolumn{1}{|c|}{Matrix Name} & \multicolumn{1}{c|}{n} & \multicolumn{1}{c|}{nnz} & \multicolumn{1}{c|}{Cond} & \multicolumn{1}{c|}{Norm} & \multicolumn{1}{c|}{SPEX Left LU time (ms)} & \multicolumn{1}{c|}{Wiedemann} & \multicolumn{1}{c|}{Lanczos} \\ \hline \endhead +ds & 647 & 12193 & 1.01E+04 & 2.08E+01 & 9.85 & 2.83 & 2.68 \\ +ch & 393 & 1304 & 4.36E+110 & 3.12E+106 & 9.21 & 8.74 & 8.84 \\ +nug07 & 450 & 1780 & 5.45E+04 & 5.28E+00 & 8.92 & 0.80 & 0.31 \\ +229 & 100 & 10000 & 6.48E+18 & 8.11E-01 & 8.51 & {\bf \red *8.37} & {\bf \red *8.24} \\ +cr42 & 304 & 608 & 1.52E+35 & 1.86E+84 & 8.10 & 40.60 & 40.68 \\ +143 & 131 & 536 & 1.49E+15 & 9.77E+09 & 8.05 & 2.95 & 1.90 \\ +delf000 & 593 & 1606 & 1.27E+18 & 1.44E+20 & 7.23 & 18.52 & 18.91 \\ +257 & 100 & 10000 & 3.09E+14 & 5.36E-01 & 6.99 & {\bf \red *9.84} & {\bf \red *10.18} \\ +air06 & 562 & 3420 & 1.07E+04 & 9.00E+00 & 6.79 & 0.60 & 0.61 \\ +protfold & 574 & 2562 & 8.36E+03 & 6.50E+00 & 6.71 & 0.66 & 0.65 \\ +pldd000b & 537 & 1448 & 9.92E+18 & 1.27E+22 & 6.59 & 16.57 & 16.59 \\ +279 & 261 & 2319 & 7.54E+16 & 2.03E+04 & 6.46 & 9.95 & 9.87 \\ +msc98-ip & 2897 & 10006 & 1.63E+07 & 4.26E+02 & 6.32 & 21.45 & 21.58 \\ +l9 & 241 & 1381 & 7.65E+21 & 1.74E+19 & 6.18 & 2.44 & 2.44 \\ +model2 & 149 & 757 & 1.15E+112 & 4.60E+108 & 6.16 & 2.54 & 2.56 \\ +pcb1000 & 1156 & 9955 & 2.28E+04 & 4.37E+01 & 6.15 & 3.06 & 3.11 \\ +aa03 & 562 & 3420 & 1.07E+04 & 9.00E+00 & 5.79 & 0.72 & 0.71 \\ +lpl1 & 2692 & 7211 & 8.18E+08 & 1.02E+04 & 5.16 & 16.99 & 17.30 \\ +biella1 & 813 & 5726 & 2.72E+04 & 1.18E+01 & 5.03 & 2.78 & 2.76 \\ +grow7 & 138 & 1744 & 8.45E+12 & 3.53E+16 & 4.91 & 2.86 & 2.83 \\ +bg512142 & 560 & 2140 & 6.92E+06 & 1.95E+03 & 4.71 & 3.18 & 3.20 \\ +139 & 131 & 536 & 1.49E+15 & 9.77E+09 & 4.53 & 3.45 & 3.40 \\ +rosen10 & 989 & 6916 & 2.01E+03 & 1.35E+03 & 4.23 & 10.79 & 10.86 \\ +stormg2-125.pre & 1780 & 4138 & 1.96E+09 & 5.43E+04 & 4.04 & 35.78 & 35.58 \\ +df2177 & 414 & 1825 & 4.61E+03 & 4.74E+00 & 3.96 & 1.99 & 0.60 \\ +stormg2-125 & 1886 & 4372 & 2.63E+07 & 2.26E+03 & 3.94 & 39.34 & 39.82 \\ +rosen2 & 431 & 4143 & 7.85E+02 & 3.19E+02 & 3.63 & 3.88 & 3.87 \\ +degen3 & 744 & 5431 & 1.66E+04 & 2.00E+01 & 3.52 & 1.70 & 1.71 \\ +10teams & 177 & 885 & 1.12E+03 & 5.63E+00 & 3.50 & 0.87 & 0.81 \\ +scsd8 & 247 & 655 & 9.59E+18 & 1.58E+17 & 3.44 & 5.35 & 5.26 \\ +pds-80 & 9225 & 19432 & 1.12E+04 & 5.66E+00 & 3.36 & 115.71 & 115.40 \\ +bas1lp & 502 & 6651 & 9.77E+04 & 9.80E+01 & 3.28 & 3.22 & 3.12 \\ +pilot4i & 134 & 1220 & 1.50E+33 & 4.19E+28 & 3.15 & 4.41 & 4.41 \\ +cycle & 284 & 878 & 1.46E+79 & 3.19E+75 & 2.99 & 6.23 & 5.80 \\ +pds-100 & 8377 & 17555 & 1.79E+04 & 5.48E+00 & 2.97 & 109.88 & 108.16 \\ +scfxm1-2r-8 & 403 & 1608 & 7.45E+09 & 2.84E+08 & 2.94 & 7.89 & 7.92 \\ +air05 & 323 & 1789 & 2.79E+04 & 6.94E+00 & 2.87 & 1.90 & 0.62 \\ +pds-60 & 7586 & 16067 & 8.18E+03 & 4.48E+00 & 2.56 & 104.72 & 104.84 \\ +gosh & 379 & 1379 & 8.05E+27 & 4.51E+24 & 2.49 & 12.14 & 12.47 \\ +pds-90 & 7914 & 16673 & 1.48E+04 & 4.13E+00 & 2.43 & 114.84 & 117.41 \\ +pds-70 & 7822 & 16545 & 1.11E+04 & 5.84E+00 & 2.14 & 132.65 & 133.20 \\ +maros & 289 & 1143 & 2.76E+14 & 2.54E+11 & 2.13 & 4.07 & 4.08 \\ +ganges & 344 & 1123 & 4.19E+26 & 3.03E+25 & 2.01 & 10.46 & 9.90 \\ +fast0507 & 401 & 1908 & 3.72E+03 & 6.99E+00 & 1.94 & 3.54 & 1.26 \\ +bandm & 122 & 609 & 1.12E+27 & 1.05E+26 & 1.94 & 3.02 & 3.03 \\ +pds-50 & 5962 & 12592 & 1.04E+04 & 3.49E+00 & 1.87 & 81.12 & 81.91 \\ +rail507 & 413 & 2005 & 5.39E+03 & 6.85E+00 & 1.87 & 3.09 & 1.44 \\ +30\_70\_4.5\_0.95\_100 & 2754 & 8381 & 6.12E+03 & 4.34E+00 & 1.83 & 36.49 & 30.40 \\ +baxter.pre & 470 & 1274 & 3.55E+94 & 8.48E+88 & 1.61 & 13.78 & 13.99 \\ +modszk1 & 263 & 765 & 1.52E+21 & 1.25E+20 & 1.59 & 9.74 & 9.81 \\ +30\_70\_4.5\_0.95\_98 & 2451 & 7364 & 7.84E+03 & 4.35E+00 & 1.54 & 28.46 & 26.87 \\ +30\_70\_4.5\_0.5\_100 & 2098 & 6197 & 1.98E+03 & 4.28E+00 & 1.48 & 21.62 & 21.47 \\ +d6cube & 223 & 1424 & 9.56E+05 & 4.24E+02 & 1.47 & 2.78 & 2.44 \\ +rentacar & 327 & 1080 & 3.64E+05 & 1.01E+03 & 1.41 & 2.27 & 1.70 \\ +qiulp & 603 & 1717 & 8.25E+10 & 1.31E+09 & 1.38 & 9.67 & 9.95 \\ +nug06 & 267 & 1007 & 1.04E+04 & 4.81E+00 & 1.35 & 2.36 & 2.46 \\ +qiu & 603 & 1717 & 5.99E+10 & 1.31E+09 & 1.33 & 10.16 & 9.95 \\ +scfxm1-2c-4 & 233 & 965 & 5.92E+09 & 2.84E+08 & 1.23 & 6.22 & 6.34 \\ +rosen1 & 217 & 2528 & 1.23E+03 & 5.80E+02 & 1.15 & 3.85 & 3.82 \\ +pds-40 & 4028 & 8478 & 6.64E+03 & 3.02E+00 & 1.10 & 50.46 & 50.21 \\ +bnl2 & 459 & 1488 & 1.22E+15 & 1.10E+12 & 1.07 & 20.38 & 20.21 \\ +mitre & 801 & 2466 & 4.18E+05 & 2.81E+03 & 1.07 & 37.24 & 36.80 \\ +pds-30 & 2643 & 5641 & 3.27E+03 & 3.04E+00 & 1.07 & 30.21 & 30.34 \\ +rail516 & 268 & 936 & 1.31E+03 & 5.64E+00 & 0.98 & 4.05 & 3.70 \\ +fome21 & 3291 & 7240 & 9.21E+03 & 3.18E+00 & 0.98 & 48.53 & 48.54 \\ +south31 & 112 & 460 & 1.68E+265 & Inf & 0.95 & 12.15 & 11.65 \\ +rail582 & 384 & 1387 & 4.55E+03 & 5.10E+00 & 0.93 & 7.41 & 1.87 \\ +seymour & 537 & 1881 & 5.24E+03 & 5.81E+00 & 0.92 & 4.72 & 3.52 \\ +scfxm1-2b-4 & 233 & 965 & 5.92E+09 & 2.84E+08 & 0.84 & 9.50 & 9.27 \\ +sp97ar & 271 & 2400 & 2.40E+04 & 3.93E+01 & 0.82 & 5.84 & 3.53 \\ +neos6 & 174 & 1580 & 3.33E+03 & 7.20E+01 & 0.82 & 4.64 & 5.31 \\ +neos & 2342 & 5098 & 3.29E+04 & 5.88E+00 & 0.77 & 25.92 & 27.98 \\ +r05 & 919 & 2717 & 4.06E+04 & 3.06E+01 & 0.75 & 12.87 & 12.91 \\ +manna81 & 1392 & 2784 & 3.00E+00 & 2.00E+00 & 0.73 & 11.09 & 11.15 \\ +p05 & 919 & 2717 & 4.06E+04 & 3.06E+01 & 0.67 & 14.18 & 14.56 \\ +scfxm1-2r-4 & 233 & 965 & 5.92E+09 & 2.84E+08 & 0.65 & 12.17 & 12.22 \\ +bnl1 & 223 & 824 & 3.34E+23 & 2.35E+20 & 0.65 & 13.63 & 13.63 \\ +rosen8 & 264 & 1850 & 2.53E+02 & 8.87E+01 & 0.57 & 6.49 & 6.40 \\ +scagr7-2r-864 & 680 & 1697 & 6.99E+06 & 3.42E+03 & 0.57 & 49.66 & 48.56 \\ +sp98ar & 223 & 1782 & 1.69E+04 & 4.43E+01 & 0.55 & 10.46 & 4.20 \\ +fome20 & 1718 & 3811 & 5.39E+03 & 3.14E+00 & 0.55 & 27.11 & 26.91 \\ +scrs8-2r-512 & 992 & 1984 & 1.92E+01 & 9.13E+00 & 0.54 & 29.88 & 29.67 \\ +disctom & 192 & 565 & 5.92E+02 & 3.41E+00 & 0.52 & 3.41 & 3.34 \\ +scfxm3 & 262 & 1005 & 1.67E+17 & 7.58E+13 & 0.52 & 18.62 & 18.57 \\ +danoint & 196 & 790 & 2.11E+07 & 6.31E+03 & 0.51 & 9.36 & 4.55 \\ +mzzv11 & 1098 & 3189 & 8.92E+05 & 2.46E+02 & 0.47 & 27.67 & 28.68 \\ +80bau3b & 154 & 396 & 3.31E+46 & 1.75E+45 & 0.46 & 17.53 & 17.59 \\ +dbir2.pre & 281 & 1879 & 5.86E+06 & 1.10E+05 & 0.43 & 8.86 & 8.28 \\ +capri & 138 & 507 & 3.72E+68 & 3.01E+65 & 0.43 & 23.65 & 23.64 \\ +p010 & 839 & 2486 & 3.96E+04 & 3.06E+01 & 0.41 & 19.48 & 19.82 \\ +degen2 & 217 & 1138 & 2.58E+03 & 1.15E+01 & 0.40 & 4.24 & 4.93 \\ +scfxm2 & 178 & 658 & 1.67E+17 & 7.58E+13 & 0.37 & 12.38 & 12.29 \\ +baxter & 256 & 697 & 3.06E+21 & 6.81E+15 & 0.37 & 15.96 & 15.58 \\ +dbir1 & 154 & 845 & 4.54E+06 & 1.42E+06 & 0.35 & 17.05 & 17.36 \\ +small000 & 140 & 383 & 6.77E+19 & 5.59E+23 & 0.34 & 29.03 & 29.08 \\ +stormg2-27 & 449 & 1019 & 3.67E+06 & 1.77E+03 & 0.34 & 21.32 & 21.95 \\ +roll3000 & 177 & 1101 & 2.19E+06 & 1.47E+03 & 0.34 & 18.49 & 15.37 \\ +woodw & 168 & 589 & 1.44E+12 & 3.80E+10 & 0.32 & 19.94 & 20.28 \\ +route & 339 & 1290 & 7.27E+08 & 2.03E+07 & 0.32 & 22.68 & 8.86 \\ +nsct1 & 120 & 595 & 4.25E+06 & 7.67E+05 & 0.31 & 16.26 & 12.14 \\ +neos.pre & 2080 & 4578 & 1.60E+04 & 5.86E+00 & 0.29 & 56.91 & 56.44 \\ +mzzv42z & 787 & 2124 & 5.68E+05 & 2.01E+02 & 0.27 & 24.22 & 24.24 \\ +crew1 & 127 & 861 & 7.82E+02 & 8.18E+00 & 0.27 & 7.76 & 11.03 \\ +neos7 & 590 & 1434 & 1.46E+08 & 1.00E+06 & 0.26 & 54.87 & 55.02 \\ +sgpf5y6 & 787 & 1870 & 6.24E+02 & 3.37E+00 & 0.22 & 34.46 & 12.04 \\ +neos1 & 309 & 944 & 8.24E+02 & 4.83E+00 & 0.22 & 8.65 & 14.13 \\ +neos11 & 365 & 1116 & 3.06E+03 & 5.06E+00 & 0.22 & 23.94 & 24.55 \\ +nsct2.pre & 156 & 1140 & 3.84E+06 & 3.22E+05 & 0.21 & 18.44 & 7.87 \\ +stocfor2 & 224 & 576 & 3.54E+26 & 1.50E+24 & 0.21 & 46.90 & 46.41 \\ +scrs8-2r-256 & 416 & 832 & 1.92E+01 & 9.13E+00 & 0.20 & 38.34 & 12.82 \\ +neos4 & 454 & 944 & 2.63E+08 & 5.59E+06 & 0.20 & 38.63 & 9.84 \\ +blp-ar98 & 148 & 876 & 3.94E+03 & 9.40E+01 & 0.19 & 25.82 & 27.74 \\ +dsbmip & 220 & 568 & 3.06E+46 & 2.19E+41 & 0.19 & 31.23 & 31.43 \\ +sgpf5y6.pre & 755 & 1744 & 1.20E+02 & 3.22E+00 & 0.18 & 42.42 & 14.08 \\ +neos823206 & 220 & 547 & 3.15E+05 & 2.24E+03 & 0.15 & 24.58 & 26.84 \\ +sc205 & 184 & 487 & 1.18E+04 & 2.10E+01 & 0.15 & 21.46 & 21.34 \\ +rosen7 & 127 & 649 & 8.23E+01 & 5.75E+01 & 0.14 & 39.64 & 14.59 \\ +scrs8-2r-64 & 256 & 512 & 1.60E+05 & 1.41E+05 & 0.14 & 54.87 & 20.84 \\ +pp08aCUTS & 131 & 332 & 1.44E+04 & 4.27E+02 & 0.13 & 14.12 & 12.34 \\ +scorpion & 131 & 507 & 7.19E+06 & 2.00E+05 & 0.13 & 39.44 & 35.93 \\ +lpl3 & 212 & 461 & 3.06E+02 & 2.61E+00 & 0.13 & 4.52 & 8.85 \\ +p19 & 117 & 555 & 4.13E+05 & 4.37E+04 & 0.12 & 64.73 & 20.09 \\ +iiasa & 113 & 262 & 6.06E+18 & 6.37E+17 & 0.12 & 28.25 & 28.10 \\ +pds-20.pre & 370 & 851 & 1.07E+03 & 3.38E+00 & 0.12 & 25.30 & 23.88 \\ +rd-rplusc-21 & 148 & 454 & 7.35E+16 & 4.38E+13 & 0.11 & 58.47 & 22.21 \\ +neos19 & 228 & 487 & 7.19E+04 & 5.23E+01 & 0.11 & 59.49 & 35.86 \\ +gesa2\_o & 102 & 214 & 6.47E+09 & 4.13E+08 & 0.11 & 51.49 & 38.52 \\ +boeing1 & 122 & 415 & 7.36E+10 & 6.29E+07 & 0.11 & 46.04 & 47.62 \\ +gesa3\_o & 148 & 365 & 1.73E+29 & 1.19E+26 & 0.10 & 52.90 & 32.00 \\ +gesa3 & 134 & 336 & 1.73E+29 & 1.19E+26 & 0.10 & 69.71 & 27.82 \\ +UMTS & 268 & 828 & 4.40E+20 & 3.24E+18 & 0.10 & 67.24 & 38.74 \\ +scrs8 & 109 & 280 & 2.97E+27 & 8.93E+24 & 0.10 & 81.52 & 24.12 \\ +scrs8-2r-128 & 192 & 384 & 1.92E+01 & 9.13E+00 & 0.10 & 19.11 & 24.55 \\ +scrs8-2c-64 & 168 & 336 & 4.80E+01 & 2.66E+01 & 0.09 & 35.05 & 38.88 \\ +ceria3d & 130 & 647 & 2.40E+04 & 1.09E+01 & 0.09 & 11.93 & 10.00 \\ +stormg2-8 & 117 & 263 & 4.82E+05 & 1.77E+03 & 0.09 & 24.41 & 35.78 \\ +nsct2 & 107 & 544 & 2.74E+06 & 2.40E+05 & 0.09 & 20.69 & 24.29 \\ +mkc & 106 & 250 & 1.27E+06 & 2.89E+04 & 0.09 & 16.57 & 13.55 \\ +scrs8-2r-32 & 128 & 256 & 4.16E+01 & 3.54E+01 & 0.09 & 26.58 & 46.92 \\ +dbir2 & 157 & 784 & 1.71E+06 & 7.27E+04 & 0.09 & 30.31 & 33.46 \\ +neos818918 & 265 & 678 & 4.29E+02 & 3.22E+00 & 0.09 & 26.79 & 25.53 \\ +mkc1 & 106 & 250 & 1.27E+06 & 2.89E+04 & 0.08 & 13.77 & 15.81 \\ +bienst1 & 102 & 253 & 7.61E+02 & 6.09E+00 & 0.06 & 11.97 & 9.59 \\ +nug05 & 107 & 362 & 1.14E+03 & 4.15E+00 & 0.06 & 5.53 & 11.20 \\ +dcmulti & 120 & 303 & 7.03E+03 & 6.26E+02 & 0.05 & 35.72 & 38.40 \\ +\hline +\caption{Comprehensive Results: Tiny Instances} +\small +\centering +\label{supptab:all_tiny} +\end{longtable} +\end{document} \ No newline at end of file diff --git a/SPEX/SPEX_Left_LU/ExampleMats/10teams_mat.txt b/SPEX/ExampleMats/10teams.mat.txt similarity index 100% rename from SPEX/SPEX_Left_LU/ExampleMats/10teams_mat.txt rename to SPEX/ExampleMats/10teams.mat.txt diff --git a/SPEX/SPEX_Left_LU/ExampleMats/10teams_v.txt b/SPEX/ExampleMats/10teams.rhs.txt similarity index 100% rename from SPEX/SPEX_Left_LU/ExampleMats/10teams_v.txt rename to SPEX/ExampleMats/10teams.rhs.txt diff --git a/SPEX/ExampleMats/494_bus.mat.txt b/SPEX/ExampleMats/494_bus.mat.txt new file mode 100644 index 0000000000..7b31f77ca0 --- /dev/null +++ b/SPEX/ExampleMats/494_bus.mat.txt @@ -0,0 +1,1667 @@ +494 494 1666 +1 1 2220.874000 +16 1 -9.960159 +46 1 -8.196721 +267 1 -4.051864 +2 2 5.410670 +4 2 -5.410670 +3 3 13.570860 +52 3 -5.665723 +186 3 -7.905138 +2 4 -5.410670 +4 4 618.396800 +8 4 -91.996320 +120 4 -100.000000 +158 4 -294.117600 +429 4 -53.504550 +432 4 -73.367570 +5 5 8.000000 +115 5 -8.000000 +6 6 5.251112 +150 6 -1.526718 +433 6 -3.724395 +7 7 12.509810 +18 7 -0.500000 +165 7 -2.619172 +367 7 -3.603604 +426 7 -5.787037 +4 8 -91.996320 +8 8 91.996320 +9 9 10.214500 +422 9 -10.214500 +10 10 277.376600 +205 10 -127.226500 +277 10 -150.150100 +11 11 79.800340 +412 11 -50.301810 +436 11 -29.498530 +12 12 13.015570 +13 12 -1.333333 +14 12 -2.158429 +16 12 -9.523809 +12 13 -1.333333 +13 13 1.333333 +12 14 -2.158429 +14 14 2.158429 +15 15 7.012623 +16 15 -7.012623 +1 16 -9.960159 +12 16 -9.523809 +15 16 -7.012623 +16 16 60.125760 +17 16 -21.786490 +19 16 -7.037297 +57 16 -4.805382 +16 17 -21.786490 +17 17 100.122400 +20 17 -17.605630 +21 17 -17.605630 +281 17 -14.306150 +334 17 -28.818450 +7 18 -0.500000 +18 18 0.500000 +16 19 -7.037297 +19 19 7.037297 +17 20 -17.605630 +20 20 17.605630 +17 21 -17.605630 +21 21 17.605630 +22 22 105.806600 +23 22 -37.313430 +140 22 -68.493150 +22 23 -37.313430 +23 23 238.159600 +140 23 -81.967220 +155 23 -108.695600 +197 23 -10.183300 +24 24 7.806402 +25 24 -7.806402 +24 25 -7.806402 +25 25 25.047990 +157 25 -4.741584 +170 25 -12.500000 +26 26 72.584360 +99 26 -42.372880 +425 26 -30.211480 +27 27 423.728800 +28 27 -423.728800 +27 28 -423.728800 +28 28 1022.734000 +85 28 -3.767472 +173 28 -595.238100 +29 29 7.613696 +307 29 -4.387889 +316 29 -3.225806 +30 30 5.428882 +31 30 -5.428882 +30 31 -5.428882 +31 31 28.912680 +182 31 -17.094020 +186 31 -6.389777 +32 32 16.376570 +376 32 -5.000000 +444 32 -11.376560 +33 33 106.164700 +34 33 -62.111800 +239 33 -44.052860 +33 34 -62.111800 +34 34 62.111800 +35 35 13.605440 +222 35 -13.605440 +36 36 1122.904000 +325 36 -1111.111000 +419 36 -11.792450 +37 37 208.561600 +147 37 -8.561644 +262 37 -200.000000 +38 38 19.286960 +39 38 -11.049720 +398 38 -8.237232 +38 39 -11.049720 +39 39 50.429810 +40 39 -22.573360 +281 39 -16.806720 +39 40 -22.573360 +40 40 107.319100 +417 40 -84.745760 +41 41 1125.308000 +47 41 -11.655010 +328 41 -1111.111000 +413 41 -2.541942 +42 42 40.630240 +172 42 -34.843200 +328 42 -5.787037 +43 43 32.258060 +175 43 -32.258060 +44 44 50.451940 +102 44 -11.990410 +286 44 -38.461540 +45 45 21.890110 +174 45 -6.293266 +203 45 -4.997501 +264 45 -5.336179 +285 45 -5.263158 +1 46 -8.196721 +46 46 14.953480 +253 46 -6.756757 +41 47 -11.655010 +47 47 29.279530 +153 47 -3.419973 +285 47 -14.204550 +48 48 1682.986000 +205 48 -114.025100 +271 48 -1333.333000 +283 48 -180.180200 +306 48 -55.447740 +49 49 65.393370 +50 49 -47.619050 +114 49 -6.009615 +455 49 -11.764710 +49 50 -47.619050 +50 50 168.412500 +238 50 -111.111100 +331 50 -5.076142 +442 50 -4.606173 +51 51 39.446350 +82 51 -24.271840 +409 51 -15.174510 +3 52 -5.665723 +52 52 10.485000 +397 52 -4.819277 +53 53 89.160840 +271 53 -37.878790 +310 53 -51.282050 +54 54 14.702950 +162 54 -6.896552 +406 54 -7.806402 +55 55 40.845950 +269 55 -21.978020 +363 55 -18.867930 +56 56 20.844680 +124 56 -9.633911 +224 56 -11.210760 +16 57 -4.805382 +57 57 19.214610 +84 57 -14.409220 +58 58 8.290816 +59 58 -6.250000 +60 58 -2.040816 +58 59 -6.250000 +59 59 63.998540 +347 59 -13.888890 +377 59 -43.859650 +58 60 -2.040816 +60 60 2.040816 +61 61 25.706270 +332 61 -18.181820 +418 61 -7.524455 +62 62 8.084074 +438 62 -8.084074 +63 63 17.001380 +64 63 -0.670241 +89 63 -3.341130 +190 63 -9.523809 +394 63 -3.466204 +63 64 -0.670241 +64 64 0.670241 +65 65 68.635110 +66 65 -56.179780 +428 65 -5.643341 +436 65 -6.811989 +65 66 -56.179780 +66 66 56.179780 +67 67 794.435900 +69 67 -9.727627 +70 67 -714.285800 +71 67 -70.422530 +68 68 63.740790 +70 68 -23.419200 +72 68 -15.076140 +73 68 -10.752690 +214 68 -14.492750 +67 69 -9.727627 +69 69 9.727627 +67 70 -714.285800 +68 70 -23.419200 +70 70 898.173600 +71 70 -64.102570 +72 70 -8.467401 +142 70 -49.627790 +311 70 -15.015010 +320 70 -23.255810 +67 71 -70.422530 +70 71 -64.102570 +71 71 309.751400 +74 71 -22.522520 +75 71 -22.522520 +76 71 -27.027030 +91 71 -57.471260 +353 71 -45.682960 +68 72 -15.076140 +70 72 -8.467401 +72 72 44.659610 +212 72 -8.291874 +213 72 -8.424600 +440 72 -2.173913 +464 72 -2.225684 +68 73 -10.752690 +73 73 10.752690 +71 74 -22.522520 +74 74 22.522520 +71 75 -22.522520 +75 75 22.522520 +71 76 -27.027030 +76 76 27.027030 +77 77 43.256960 +78 77 -11.627910 +187 77 -25.641030 +264 77 -5.988024 +77 78 -11.627910 +78 78 14.954860 +123 78 -1.324152 +265 78 -2.002804 +79 79 59.783590 +80 79 -18.993350 +214 79 -18.518520 +421 79 -22.271720 +79 80 -18.993350 +80 80 76.989320 +147 80 -9.765625 +252 80 -3.332223 +355 80 -9.661836 +393 80 -33.333340 +437 80 -1.902950 +81 81 54.865130 +396 81 -34.246570 +457 81 -20.618560 +51 82 -24.271840 +82 82 130.654800 +287 82 -106.383000 +83 83 8.651169 +387 83 -4.880430 +423 83 -3.770739 +57 84 -14.409220 +84 84 18.529540 +173 84 -4.120313 +28 85 -3.767472 +85 85 318.494700 +88 85 -294.117600 +116 85 -14.025250 +275 85 -3.544842 +454 85 -3.039514 +86 86 11.614400 +88 86 -11.614400 +87 87 55.873020 +88 87 -40.000000 +236 87 -15.873020 +85 88 -294.117600 +86 88 -11.614400 +87 88 -40.000000 +88 88 345.732100 +63 89 -3.341130 +89 89 8.151134 +326 89 -4.810005 +90 90 215.090100 +91 90 -125.000000 +386 90 -90.090100 +71 91 -57.471260 +90 91 -125.000000 +91 91 295.428500 +93 91 -38.759690 +94 91 -38.910510 +95 91 -11.534030 +371 91 -23.752970 +92 92 79.781510 +95 92 -74.626870 +387 92 -5.154639 +91 93 -38.759690 +93 93 38.759690 +91 94 -38.910510 +94 94 38.910510 +91 95 -11.534030 +92 95 -74.626870 +95 95 94.053560 +96 95 -7.892660 +95 96 -7.892660 +96 96 7.892660 +97 97 17.551330 +326 97 -10.799140 +422 97 -6.752194 +98 98 15.573290 +150 98 -5.892752 +156 98 -9.680542 +26 99 -42.372880 +99 99 76.271190 +224 99 -33.898300 +100 100 1230.337000 +158 100 -116.279100 +220 100 -769.230800 +391 100 -344.827600 +101 101 26.041670 +102 101 -26.041670 +44 102 -11.990410 +101 102 -26.041670 +102 102 79.669890 +178 102 -22.471910 +233 102 -10.000000 +286 102 -9.165903 +103 103 104.405000 +306 103 -55.648300 +429 103 -48.756710 +104 104 85.535790 +105 104 -4.716981 +191 104 -17.793590 +257 104 -18.382350 +263 104 -44.642860 +104 105 -4.716981 +105 105 4.716981 +106 106 14.409220 +255 106 -14.409220 +107 107 41.132950 +246 107 -20.080320 +334 107 -21.052630 +108 108 91.694530 +191 108 -72.463770 +380 108 -19.230770 +109 109 9.784736 +112 109 -9.784736 +110 110 1.029866 +112 110 -1.029866 +111 111 2.164502 +112 111 -2.164502 +109 112 -9.784736 +110 112 -1.029866 +111 112 -2.164502 +112 112 26.689960 +123 112 -3.492840 +179 112 -6.802721 +298 112 -3.415300 +113 113 140.110500 +263 113 -36.764710 +337 113 -37.313430 +378 113 -46.948360 +416 113 -19.083970 +49 114 -6.009615 +114 114 14.010440 +115 114 -2.604167 +285 114 -5.396654 +5 115 -8.000000 +114 115 -2.604167 +115 115 13.984830 +354 115 -3.380663 +85 116 -14.025250 +116 116 32.240180 +117 116 -18.214940 +116 117 -18.214940 +117 117 36.767810 +119 117 -18.552880 +118 118 29.756330 +124 118 -19.083970 +346 118 -10.672360 +117 119 -18.552880 +119 119 28.715480 +346 119 -10.162600 +4 120 -100.000000 +120 120 176.923100 +429 120 -76.923070 +121 121 16.949150 +123 121 -16.949150 +122 122 33.941960 +123 122 -5.783690 +187 122 -12.903230 +264 122 -9.633911 +297 122 -5.621135 +78 123 -1.324152 +112 123 -3.492840 +121 123 -16.949150 +122 123 -5.783690 +123 123 38.087050 +179 123 -7.518797 +265 123 -3.018412 +56 124 -9.633911 +118 124 -19.083970 +124 124 28.717880 +125 125 3.294893 +126 125 -3.294893 +125 126 -3.294893 +126 126 10.283010 +385 126 -6.988121 +127 127 39.109090 +129 127 -19.841270 +226 127 -19.267820 +128 128 56.252830 +225 128 -18.939390 +438 128 -37.313430 +127 129 -19.841270 +129 129 19.841270 +130 130 15.974440 +141 130 -15.974440 +131 131 15.974440 +141 131 -15.974440 +132 132 18.382350 +141 132 -18.382350 +133 133 62.111800 +142 133 -62.111800 +134 134 54.347820 +143 134 -54.347820 +135 135 22.573360 +140 135 -22.573360 +136 136 405.785200 +141 136 -333.333300 +142 136 -59.171600 +144 136 -13.280210 +137 137 444.034100 +141 137 -370.370400 +142 137 -60.240960 +145 137 -13.422820 +138 138 125.490200 +199 138 -58.823520 +340 138 -66.666670 +139 139 13.568520 +147 139 -13.568520 +22 140 -68.493150 +23 140 -81.967220 +135 140 -22.573360 +140 140 173.033700 +130 141 -15.974440 +131 141 -15.974440 +132 141 -18.382350 +136 141 -333.333300 +137 141 -370.370400 +141 141 754.034900 +70 142 -49.627790 +133 142 -62.111800 +136 142 -59.171600 +137 142 -60.240960 +142 142 643.315400 +143 142 -188.679200 +473 142 -188.679200 +478 142 -12.180270 +487 142 -22.624440 +134 143 -54.347820 +142 143 -188.679200 +143 143 274.582800 +242 143 -31.555690 +136 144 -13.280210 +144 144 13.280210 +137 145 -13.422820 +145 145 13.422820 +146 146 86.175740 +183 146 -8.576329 +245 146 -6.878052 +339 146 -70.721360 +37 147 -8.561644 +80 147 -9.765625 +139 147 -13.568520 +147 147 31.895790 +148 148 19.607840 +434 148 -9.803922 +443 148 -9.803922 +149 149 36.061350 +150 149 -20.607790 +217 149 -15.453560 +6 150 -1.526718 +98 150 -5.892752 +149 150 -20.607790 +150 150 38.128270 +397 150 -10.101010 +151 151 52.868480 +153 151 -5.371435 +154 151 -2.452002 +155 151 -45.045050 +152 152 55.509490 +153 152 -5.443658 +154 152 -2.446783 +155 152 -47.619050 +47 153 -3.419973 +151 153 -5.371435 +152 153 -5.443658 +153 153 29.860070 +203 153 -15.625000 +151 154 -2.452002 +152 154 -2.446783 +154 154 4.898785 +23 155 -108.695600 +151 155 -45.045050 +152 155 -47.619050 +155 155 218.720900 +241 155 -17.361110 +98 156 -9.680542 +156 156 10009.680000 +157 156 -10000.000000 +25 157 -4.741584 +156 157 -10000.000000 +157 157 10004.740000 +4 158 -294.117600 +100 158 -116.279100 +158 158 410.396700 +159 159 95.742790 +160 159 -40.734680 +183 159 -10.023050 +248 159 -21.168500 +388 159 -16.463620 +392 159 -7.352941 +159 160 -40.734680 +160 160 202.015000 +369 160 -19.436350 +399 160 -141.844000 +161 161 2.209945 +410 161 -2.209945 +54 162 -6.896552 +162 162 8.668659 +355 162 -1.772107 +163 163 132.412600 +167 163 -22.522520 +246 163 -109.890100 +164 164 1076.971000 +167 164 -999.999900 +231 164 -15.598190 +417 164 -27.359780 +470 164 -34.013600 +7 165 -2.619172 +165 165 2.619172 +166 166 11.866090 +341 166 -8.071025 +423 166 -3.795066 +163 167 -22.522520 +164 167 -999.999900 +167 167 1022.522000 +168 168 66.800270 +169 168 -66.800270 +168 169 -66.800270 +169 169 77.049900 +344 169 -4.973145 +400 169 -5.276488 +25 170 -12.500000 +170 170 179.166700 +325 170 -166.666700 +171 171 76.923070 +172 171 -76.923070 +42 172 -34.843200 +171 172 -76.923070 +172 172 111.766300 +28 173 -595.238100 +84 173 -4.120313 +173 173 618.791000 +202 173 -19.432570 +45 174 -6.293266 +174 174 41.110850 +175 174 -9.242133 +285 174 -25.575450 +43 175 -32.258060 +174 175 -9.242133 +175 175 41.500200 +176 176 3.676470 +464 176 -3.676470 +177 177 5.420054 +226 177 -5.420054 +102 178 -22.471910 +178 178 36.943690 +340 178 -14.471780 +112 179 -6.802721 +123 179 -7.518797 +179 179 14.321520 +180 180 14.641290 +181 180 -14.641290 +180 181 -14.641290 +181 181 89.829260 +233 181 -75.187970 +31 182 -17.094020 +182 182 17.094020 +146 183 -8.576329 +159 183 -10.023050 +183 183 48.701150 +184 183 -3.319943 +185 183 -10.176050 +248 183 -16.605780 +183 184 -3.319943 +184 184 3.319943 +183 185 -10.176050 +185 185 10.176050 +3 186 -7.905138 +31 186 -6.389777 +186 186 14.294920 +77 187 -25.641030 +122 187 -12.903230 +187 187 38.544250 +188 188 4.097813 +198 188 -2.428363 +212 188 -1.669449 +189 189 0.170358 +190 189 -0.170358 +63 190 -9.523809 +189 190 -0.170358 +190 190 12.439160 +401 190 -2.744990 +104 191 -17.793590 +108 191 -72.463770 +191 191 209.335800 +192 191 -8.000000 +195 191 -12.014900 +196 191 -17.844400 +374 191 -30.487800 +380 191 -14.168320 +416 191 -36.563070 +191 192 -8.000000 +192 192 29.547830 +193 192 -10.200960 +194 192 -11.346870 +192 193 -10.200960 +193 193 10.200960 +192 194 -11.346870 +194 194 11.346870 +191 195 -12.014900 +195 195 12.014900 +191 196 -17.844400 +196 196 17.844400 +23 197 -10.183300 +197 197 28.498320 +465 197 -18.315020 +188 198 -2.428363 +198 198 10.611670 +201 198 -8.183307 +138 199 -58.823520 +199 199 101.376700 +364 199 -42.553190 +200 200 4.805382 +280 200 -4.805382 +198 201 -8.183307 +201 201 8.183307 +173 202 -19.432570 +202 202 40.313760 +247 202 -20.881190 +45 203 -4.997501 +153 203 -15.625000 +203 203 124.789200 +297 203 -104.166700 +204 204 1214.533000 +205 204 -1123.595000 +206 204 -5.758379 +207 204 -85.178880 +10 205 -127.226500 +48 205 -114.025100 +204 205 -1123.595000 +205 205 1543.608000 +208 205 -15.498710 +283 205 -93.283580 +357 205 -53.106750 +369 205 -16.871940 +204 206 -5.758379 +206 206 5.758379 +204 207 -85.178880 +207 207 149.570400 +278 207 -64.391490 +205 208 -15.498710 +208 208 21.777360 +209 208 -6.278646 +208 209 -6.278646 +209 209 6.278646 +210 210 8.795074 +211 210 -8.795074 +210 211 -8.795074 +211 211 45.570150 +457 211 -20.876830 +465 211 -15.898250 +72 212 -8.291874 +188 212 -1.669449 +212 212 9.961323 +72 213 -8.424600 +213 213 16.737150 +444 213 -8.312551 +68 214 -14.492750 +79 214 -18.518520 +214 214 33.011270 +215 215 10.294730 +390 215 -5.701254 +440 215 -4.593477 +216 216 243.995100 +217 216 -181.818200 +218 216 -11.415530 +219 216 -50.761420 +149 217 -15.453560 +216 217 -181.818200 +217 217 278.138400 +277 217 -46.663560 +286 217 -5.467469 +429 217 -28.735630 +216 218 -11.415530 +218 218 11.415530 +216 219 -50.761420 +219 219 77.571080 +235 219 -26.809650 +100 220 -769.230800 +220 220 978.008300 +271 220 -59.523810 +449 220 -149.253700 +221 221 14.175270 +367 221 -10.504200 +464 221 -3.671072 +35 222 -13.605440 +222 222 24.752130 +240 222 -3.993610 +436 222 -7.153076 +223 223 27.514140 +345 223 -14.705880 +398 223 -5.711022 +407 223 -7.097232 +56 224 -11.210760 +99 224 -33.898300 +224 224 74.144000 +377 224 -24.390240 +454 224 -4.644682 +128 225 -18.939390 +225 225 238.167400 +226 225 -200.000000 +282 225 -8.116883 +377 225 -11.111110 +127 226 -19.267820 +177 226 -5.420054 +225 226 -200.000000 +226 226 224.687900 +227 227 15.243900 +228 227 -15.243900 +227 228 -15.243900 +228 228 19.758580 +420 228 -4.514673 +229 229 36.496350 +230 229 -36.496350 +229 230 -36.496350 +230 230 95.454160 +315 230 -55.248620 +436 230 -3.709199 +164 231 -15.598190 +231 231 100.692700 +386 231 -19.305020 +473 231 -65.789470 +232 232 329.623100 +233 232 -200.000000 +234 232 -11.976050 +235 232 -117.647000 +102 233 -10.000000 +181 233 -75.187970 +232 233 -200.000000 +233 233 285.188000 +232 234 -11.976050 +234 234 11.976050 +219 235 -26.809650 +232 235 -117.647000 +235 235 144.456700 +87 236 -15.873020 +236 236 165.723800 +301 236 -62.208400 +399 236 -87.642420 +237 237 82.188440 +300 237 -58.004640 +308 237 -24.183800 +50 238 -111.111100 +238 238 151.433700 +294 238 -40.322580 +33 239 -44.052860 +239 239 48.515160 +322 239 -4.462294 +222 240 -3.993610 +240 240 8.230898 +422 240 -4.237288 +155 241 -17.361110 +241 241 26.750780 +329 241 -9.389671 +143 242 -31.555690 +242 242 329.219400 +258 242 -186.567200 +431 242 -38.580250 +480 242 -72.516310 +243 243 28.624240 +244 243 -27.173910 +309 243 -1.450326 +243 244 -27.173910 +244 244 27.173910 +146 245 -6.878052 +245 245 36.980400 +300 245 -30.102350 +107 246 -20.080320 +163 246 -109.890100 +246 246 129.970400 +202 247 -20.881190 +247 247 99.006190 +333 247 -78.125000 +159 248 -21.168500 +183 248 -16.605780 +248 248 45.486760 +249 248 -7.712479 +248 249 -7.712479 +249 249 20007.710000 +250 249 -10000.000000 +251 249 -10000.000000 +249 250 -10000.000000 +250 250 10000.000000 +249 251 -10000.000000 +251 251 10000.000000 +80 252 -3.332223 +252 252 10.845370 +363 252 -7.513148 +46 253 -6.756757 +253 253 14.756760 +256 253 -8.000000 +254 254 1.459854 +256 254 -1.459854 +106 255 -14.409220 +255 255 103.428800 +256 255 -40.000000 +385 255 -49.019610 +253 256 -8.000000 +254 256 -1.459854 +255 256 -40.000000 +256 256 49.459850 +104 257 -18.382350 +257 257 141.792300 +266 257 -10.967320 +336 257 -22.271720 +402 257 -48.154090 +427 257 -42.016810 +242 258 -186.567200 +258 258 545.168400 +259 258 -90.744100 +260 258 -90.009000 +261 258 -89.126560 +431 258 -28.661510 +466 258 -60.060060 +258 259 -90.744100 +259 259 90.744100 +258 260 -90.009000 +260 260 90.009000 +258 261 -89.126560 +261 261 89.126560 +37 262 -200.000000 +262 262 204.904400 +443 262 -4.904365 +104 263 -44.642860 +113 263 -36.764710 +263 263 172.726200 +336 263 -63.694270 +378 263 -27.624310 +45 264 -5.336179 +77 264 -5.988024 +122 264 -9.633911 +264 264 26.741800 +265 264 -5.783690 +78 265 -2.002804 +123 265 -3.018412 +264 265 -5.783690 +265 265 10.804910 +257 266 -10.967320 +266 266 10.967320 +1 267 -4.051864 +267 267 12.330010 +407 267 -8.278146 +268 268 6.802721 +269 268 -6.802721 +55 269 -21.978020 +268 269 -6.802721 +269 269 33.414660 +422 269 -4.633920 +270 270 146.164200 +372 270 -72.254330 +404 270 -73.909830 +48 271 -1333.333000 +53 271 -37.878790 +220 271 -59.523810 +271 271 1493.041000 +272 271 -17.241380 +310 271 -26.881720 +377 271 -18.181820 +271 272 -17.241380 +272 272 43.925950 +273 272 -13.315580 +274 272 -13.368980 +272 273 -13.315580 +273 273 13.315580 +272 274 -13.368980 +274 274 13.368980 +85 275 -3.544842 +275 275 27.820970 +345 275 -9.541985 +375 275 -8.340283 +407 275 -6.393862 +276 276 12.322530 +315 276 -4.677269 +394 276 -7.645260 +10 277 -150.150100 +217 277 -46.663560 +277 277 278.513100 +432 277 -81.699350 +207 278 -64.391490 +278 278 273.046600 +279 278 -86.206890 +431 278 -104.166700 +479 278 -18.281540 +278 279 -86.206890 +279 279 86.206890 +200 280 -4.805382 +280 280 15.758280 +281 280 -10.952900 +17 281 -14.306150 +39 281 -16.806720 +280 281 -10.952900 +281 281 42.065780 +225 282 -8.116883 +282 282 8.116883 +48 283 -180.180200 +205 283 -93.283580 +283 283 273.463800 +284 284 39.028030 +285 284 -3.492840 +287 284 -18.083180 +288 284 -17.452010 +45 285 -5.263158 +47 285 -14.204550 +114 285 -5.396654 +174 285 -25.575450 +284 285 -3.492840 +285 285 151.971900 +289 285 -49.019610 +290 285 -49.019610 +44 286 -38.461540 +102 286 -9.165903 +217 286 -5.467469 +286 286 65.028080 +289 286 -5.966587 +290 286 -5.966587 +82 287 -106.383000 +284 287 -18.083180 +287 287 124.466200 +284 288 -17.452010 +288 288 17.452010 +285 289 -49.019610 +286 289 -5.966587 +289 289 59.067830 +291 289 -4.081633 +285 290 -49.019610 +286 290 -5.966587 +290 290 59.067830 +292 290 -4.081633 +289 291 -4.081633 +291 291 4.081633 +290 292 -4.081633 +292 292 4.081633 +293 293 10.799140 +294 293 -10.799140 +238 294 -40.322580 +293 294 -10.799140 +294 294 81.424740 +419 294 -30.303030 +295 295 39.062500 +447 295 -39.062500 +296 296 507.685800 +297 296 -5.681818 +298 296 -500.000000 +299 296 -2.004008 +122 297 -5.621135 +203 297 -104.166700 +296 297 -5.681818 +297 297 328.235600 +456 297 -212.766000 +112 298 -3.415300 +296 298 -500.000000 +298 298 503.415300 +296 299 -2.004008 +299 299 2.004008 +237 300 -58.004640 +245 300 -30.102350 +300 300 100.909400 +372 300 -12.802460 +236 301 -62.208400 +301 301 5112.385000 +302 301 -2000.000000 +304 301 -2000.000000 +306 301 -500.000000 +310 301 -500.000000 +323 301 -8.510638 +429 301 -41.666670 +301 302 -2000.000000 +302 302 2077.786000 +303 302 -11.560690 +493 302 -66.225170 +302 303 -11.560690 +303 303 11.560690 +301 304 -2000.000000 +304 304 2077.786000 +305 304 -11.560690 +494 304 -66.225170 +304 305 -11.560690 +305 305 11.560690 +48 306 -55.447740 +103 306 -55.648300 +301 306 -500.000000 +306 306 1166.652000 +310 306 -555.555500 +29 307 -4.387889 +307 307 17.597930 +434 307 -13.210040 +237 308 -24.183800 +308 308 57.285420 +373 308 -33.101620 +243 309 -1.450326 +309 309 46.699200 +409 309 -45.248870 +53 310 -51.282050 +271 310 -26.881720 +301 310 -500.000000 +306 310 -555.555500 +310 310 2286.153000 +317 310 -370.370400 +318 310 -370.370400 +319 310 -370.370400 +391 310 -41.322320 +70 311 -15.015010 +311 311 238.110800 +317 311 -60.240960 +318 311 -60.240960 +319 311 -60.240960 +320 311 -42.372880 +312 312 13.422820 +317 312 -13.422820 +313 313 13.422820 +318 313 -13.422820 +314 314 13.422820 +319 314 -13.422820 +230 315 -55.248620 +276 315 -4.677269 +315 315 59.925880 +29 316 -3.225806 +316 316 9.660813 +428 316 -6.435007 +310 317 -370.370400 +311 317 -60.240960 +312 317 -13.422820 +317 317 444.034100 +310 318 -370.370400 +311 318 -60.240960 +313 318 -13.422820 +318 318 444.034100 +310 319 -370.370400 +311 319 -60.240960 +314 319 -13.422820 +319 319 444.034100 +70 320 -23.255810 +311 320 -42.372880 +320 320 69.474850 +321 320 -3.846154 +320 321 -3.846154 +321 321 13.564330 +401 321 -9.718173 +239 322 -4.462294 +322 322 16.510490 +323 322 -12.048190 +301 323 -8.510638 +322 323 -12.048190 +323 323 10029.630000 +340 323 -9.074409 +435 323 -10000.000000 +324 324 18.181820 +325 324 -18.181820 +36 325 -1111.111000 +170 325 -166.666700 +324 325 -18.181820 +325 325 1295.959000 +89 326 -4.810005 +97 326 -10.799140 +326 326 15.609140 +327 327 3.105590 +328 327 -3.105590 +41 328 -1111.111000 +42 328 -5.787037 +327 328 -3.105590 +328 328 1120.004000 +241 329 -9.389671 +329 329 74.324740 +396 329 -64.935070 +330 330 4.587156 +331 330 -4.587156 +50 331 -5.076142 +330 331 -4.587156 +331 331 9.663299 +61 332 -18.181820 +332 332 23.896100 +335 332 -5.714286 +247 333 -78.125000 +333 333 92.809290 +392 333 -14.684290 +17 334 -28.818450 +107 334 -21.052630 +334 334 49.871080 +332 335 -5.714286 +335 335 12.233190 +434 335 -6.518905 +257 336 -22.271720 +263 336 -63.694270 +336 336 85.965990 +113 337 -37.313430 +337 337 81.956300 +343 337 -44.642860 +338 338 2.164502 +394 338 -2.164502 +146 339 -70.721360 +339 339 74.335910 +342 339 -3.614545 +138 340 -66.666670 +178 340 -14.471780 +323 340 -9.074409 +340 340 90.212860 +166 341 -8.071025 +341 341 10.469110 +423 341 -2.398082 +339 342 -3.614545 +342 342 3.614545 +337 343 -44.642860 +343 343 63.836720 +416 343 -19.193860 +169 344 -4.973145 +344 344 4.973145 +223 345 -14.705880 +275 345 -9.541985 +345 345 90.858520 +348 345 -3.620565 +350 345 -12.033690 +352 345 -29.069770 +353 345 -21.886630 +118 346 -10.672360 +119 346 -10.162600 +346 346 86.783690 +347 346 -24.213080 +349 346 -3.810976 +351 346 -12.195120 +353 346 -21.739130 +375 346 -3.990423 +59 347 -13.888890 +346 347 -24.213080 +347 347 38.101970 +345 348 -3.620565 +348 348 3.620565 +346 349 -3.810976 +349 349 3.810976 +345 350 -12.033690 +350 350 12.033690 +346 351 -12.195120 +351 351 12.195120 +345 352 -29.069770 +352 352 49.903100 +395 352 -20.833330 +71 353 -45.682960 +345 353 -21.886630 +346 353 -21.739130 +353 353 10089.310000 +403 353 -10000.000000 +115 354 -3.380663 +354 354 9.430269 +420 354 -6.049607 +80 355 -9.661836 +162 355 -1.772107 +355 355 11.433940 +356 356 192.307700 +385 356 -192.307700 +205 357 -53.106750 +357 357 141.234600 +358 357 -15.785320 +359 357 -7.358893 +361 357 -7.873395 +399 357 -57.110220 +357 358 -15.785320 +358 358 32.048440 +360 358 -8.167265 +362 358 -8.095855 +357 359 -7.358893 +359 359 7.358893 +358 360 -8.167265 +360 360 8.167265 +357 361 -7.873395 +361 361 7.873395 +358 362 -8.095855 +362 362 8.095855 +55 363 -18.867930 +252 363 -7.513148 +363 363 26.381070 +199 364 -42.553190 +364 364 42.553190 +365 365 21.231420 +438 365 -21.231420 +366 366 1.169727 +367 366 -1.169727 +7 367 -3.603604 +221 367 -10.504200 +366 367 -1.169727 +367 367 30.373970 +376 367 -3.522367 +426 367 -11.574070 +368 368 262.983900 +369 368 -188.679200 +370 368 -13.698630 +371 368 -60.606060 +160 369 -19.436350 +205 369 -16.871940 +368 369 -188.679200 +369 369 277.779400 +372 369 -26.308860 +373 369 -26.483050 +368 370 -13.698630 +370 370 13.698630 +91 371 -23.752970 +368 371 -60.606060 +371 371 84.359030 +270 372 -72.254330 +300 372 -12.802460 +369 372 -26.308860 +372 372 111.365700 +308 373 -33.101620 +369 373 -26.483050 +373 373 108.604300 +392 373 -49.019610 +191 374 -30.487800 +374 374 123.080400 +408 374 -92.592590 +275 375 -8.340283 +346 375 -3.990423 +375 375 12.330710 +32 376 -5.000000 +367 376 -3.522367 +376 376 8.522367 +59 377 -43.859650 +224 377 -24.390240 +225 377 -11.111110 +271 377 -18.181820 +377 377 121.017000 +395 377 -23.474180 +113 378 -46.948360 +263 378 -27.624310 +378 378 74.572670 +379 379 127.641200 +380 379 -35.211270 +381 379 -84.033620 +383 379 -8.396306 +108 380 -19.230770 +191 380 -14.168320 +379 380 -35.211270 +380 380 78.423900 +384 380 -9.813543 +379 381 -84.033620 +381 381 249.754800 +417 381 -153.846100 +430 381 -11.875070 +382 382 123.456800 +384 382 -123.456800 +379 383 -8.396306 +383 383 8.396306 +380 384 -9.813543 +382 384 -123.456800 +384 384 133.270300 +126 385 -6.988121 +255 385 -49.019610 +356 385 -192.307700 +385 385 248.315400 +90 386 -90.090100 +231 386 -19.305020 +386 386 109.395100 +83 387 -4.880430 +92 387 -5.154639 +387 387 10.035070 +159 388 -16.463620 +388 388 18.112910 +389 388 -1.649294 +388 389 -1.649294 +389 389 1.649294 +215 390 -5.701254 +390 390 8.220146 +439 390 -2.518892 +100 391 -344.827600 +310 391 -41.322320 +391 391 386.149900 +159 392 -7.352941 +333 392 -14.684290 +373 392 -49.019610 +392 392 209.369400 +404 392 -138.312600 +80 393 -33.333340 +393 393 38.333340 +439 393 -5.000000 +63 394 -3.466204 +276 394 -7.645260 +338 394 -2.164502 +394 394 13.275970 +352 395 -20.833330 +377 395 -23.474180 +395 395 44.307510 +81 396 -34.246570 +329 396 -64.935070 +396 396 133.293100 +457 396 -10.582010 +465 396 -23.529410 +52 397 -4.819277 +150 397 -10.101010 +397 397 14.920290 +38 398 -8.237232 +223 398 -5.711022 +398 398 13.948250 +160 399 -141.844000 +236 399 -87.642420 +357 399 -57.110220 +399 399 286.596600 +169 400 -5.276488 +400 400 19.088640 +442 400 -13.812150 +190 401 -2.744990 +321 401 -9.718173 +401 401 12.463160 +257 402 -48.154090 +402 402 85.607280 +403 402 -37.453190 +353 403 -10000.000000 +402 403 -37.453190 +403 403 10037.450000 +270 404 -73.909830 +392 404 -138.312600 +404 404 212.222400 +405 405 4.235493 +406 405 -4.235493 +54 406 -7.806402 +405 406 -4.235493 +406 406 12.041890 +223 407 -7.097232 +267 407 -8.278146 +275 407 -6.393862 +407 407 21.769240 +374 408 -92.592590 +408 408 117.284000 +427 408 -24.691360 +51 409 -15.174510 +309 409 -45.248870 +409 409 60.423380 +161 410 -2.209945 +410 410 12.372550 +418 410 -10.162600 +411 411 31.565660 +412 411 -31.565660 +11 412 -50.301810 +411 412 -31.565660 +412 412 83.281910 +437 412 -1.414447 +41 413 -2.541942 +413 413 2.541942 +414 414 119.866300 +415 414 -8.333334 +416 414 -34.013600 +417 414 -77.519380 +414 415 -8.333334 +415 415 8.333334 +113 416 -19.083970 +191 416 -36.563070 +343 416 -19.193860 +414 416 -34.013600 +416 416 108.854500 +40 417 -84.745760 +164 417 -27.359780 +381 417 -153.846100 +414 417 -77.519380 +417 417 343.471100 +61 418 -7.524455 +410 418 -10.162600 +418 418 17.687060 +36 419 -11.792450 +294 419 -30.303030 +419 419 42.095480 +228 420 -4.514673 +354 420 -6.049607 +420 420 19.046040 +424 420 -8.481764 +79 421 -22.271720 +421 421 51.322930 +422 421 -6.779501 +435 421 -22.271720 +9 422 -10.214500 +97 422 -6.752194 +240 422 -4.237288 +269 422 -4.633920 +421 422 -6.779501 +422 422 32.617410 +83 423 -3.770739 +166 423 -3.795066 +341 423 -2.398082 +423 423 9.963887 +420 424 -8.481764 +424 424 8.481764 +26 425 -30.211480 +425 425 30.211480 +7 426 -5.787037 +367 426 -11.574070 +426 426 17.361110 +257 427 -42.016810 +408 427 -24.691360 +427 427 66.708170 +65 428 -5.643341 +316 428 -6.435007 +428 428 12.078350 +4 429 -53.504550 +103 429 -48.756710 +120 429 -76.923070 +217 429 -28.735630 +301 429 -41.666670 +429 429 490.550500 +431 429 -240.963900 +381 430 -11.875070 +430 430 91.875080 +431 430 -80.000000 +242 431 -38.580250 +258 431 -28.661510 +278 431 -104.166700 +429 431 -240.963900 +430 431 -80.000000 +431 431 492.372300 +4 432 -73.367570 +277 432 -81.699350 +432 432 155.066900 +6 433 -3.724395 +433 433 3.724395 +148 434 -9.803922 +307 434 -13.210040 +335 434 -6.518905 +434 434 39.502960 +437 434 -9.970090 +323 435 -10000.000000 +421 435 -22.271720 +435 435 10032.620000 +436 435 -10.344850 +11 436 -29.498530 +65 436 -6.811989 +222 436 -7.153076 +230 436 -3.709199 +435 436 -10.344850 +436 436 57.517640 +80 437 -1.902950 +412 437 -1.414447 +434 437 -9.970090 +437 437 13.287490 +62 438 -8.084074 +128 438 -37.313430 +365 438 -21.231420 +438 438 66.628940 +390 439 -2.518892 +393 439 -5.000000 +439 439 7.518892 +72 440 -2.173913 +215 440 -4.593477 +440 440 6.767390 +441 441 7.757952 +442 441 -7.757952 +50 442 -4.606173 +400 442 -13.812150 +441 442 -7.757952 +442 442 26.176280 +148 443 -9.803922 +262 443 -4.904365 +443 443 14.708290 +32 444 -11.376560 +213 444 -8.312551 +444 444 19.689120 +445 445 69.858070 +446 445 -27.247960 +447 445 -26.455030 +449 445 -16.155090 +445 446 -27.247960 +446 446 83.551830 +450 446 -39.062500 +455 446 -17.241380 +295 447 -39.062500 +445 447 -26.455030 +447 447 82.758900 +455 447 -17.241380 +448 448 10000.000000 +450 448 -10000.000000 +220 449 -149.253700 +445 449 -16.155090 +449 449 185.103200 +451 449 -6.622517 +452 449 -6.535948 +453 449 -6.535948 +446 450 -39.062500 +448 450 -10000.000000 +450 450 10039.060000 +449 451 -6.622517 +451 451 6.622517 +449 452 -6.535948 +452 452 6.535948 +449 453 -6.535948 +453 453 6.535948 +85 454 -3.039514 +224 454 -4.644682 +454 454 73.473670 +455 454 -65.789470 +49 455 -11.764710 +446 455 -17.241380 +447 455 -17.241380 +454 455 -65.789470 +455 455 112.036900 +297 456 -212.766000 +456 456 10219.710000 +457 456 -6.944445 +458 456 -10000.000000 +81 457 -20.618560 +211 457 -20.876830 +396 457 -10.582010 +456 457 -6.944445 +457 457 80.496800 +459 457 -9.259259 +460 457 -2.272727 +461 457 -2.272727 +462 457 -3.780719 +463 457 -3.889537 +456 458 -10000.000000 +458 458 10000.000000 +457 459 -9.259259 +459 459 9.259259 +457 460 -2.272727 +460 460 2.272727 +457 461 -2.272727 +461 461 2.272727 +457 462 -3.780719 +462 462 3.780719 +457 463 -3.889537 +463 463 3.889537 +72 464 -2.225684 +176 464 -3.676470 +221 464 -3.671072 +464 464 9.573227 +197 465 -18.315020 +211 465 -15.898250 +396 465 -23.529410 +465 465 57.742680 +258 466 -60.060060 +466 466 6796.340000 +467 466 -69.613650 +480 466 -6666.667000 +466 467 -69.613650 +467 467 313.516100 +481 467 -243.902400 +468 468 78.336490 +472 468 -68.027210 +478 468 -10.309280 +469 469 56.028910 +473 469 -11.976050 +478 469 -44.052860 +164 470 -34.013600 +470 470 69.984830 +471 470 -35.971230 +470 471 -35.971230 +471 471 60.125820 +472 471 -24.154590 +468 472 -68.027210 +471 472 -24.154590 +472 472 92.181790 +142 473 -188.679200 +231 473 -65.789470 +469 473 -11.976050 +473 473 418.993900 +474 473 -33.898300 +475 473 -29.761910 +476 473 -44.444440 +477 473 -44.444440 +473 474 -33.898300 +474 474 33.898300 +473 475 -29.761910 +475 475 29.761910 +473 476 -44.444440 +476 476 44.444440 +473 477 -44.444440 +477 477 44.444440 +142 478 -12.180270 +468 478 -10.309280 +469 478 -44.052860 +478 478 66.542410 +278 479 -18.281540 +479 479 18.281540 +242 480 -72.516310 +466 480 -6666.667000 +480 480 6841.905000 +481 480 -32.051280 +483 480 -70.671380 +467 481 -243.902400 +480 481 -32.051280 +481 481 662.705000 +482 481 -265.604200 +483 481 -32.258060 +486 481 -88.888890 +481 482 -265.604200 +482 482 318.880800 +486 482 -53.276500 +480 483 -70.671380 +481 483 -32.258060 +483 483 204.970300 +484 483 -51.020410 +485 483 -51.020410 +483 484 -51.020410 +484 484 51.020410 +483 485 -51.020410 +485 485 51.020410 +481 486 -88.888890 +482 486 -53.276500 +486 486 142.165400 +142 487 -22.624440 +487 487 22.624440 +488 488 162.303800 +490 488 -72.167850 +493 488 -45.413260 +494 488 -44.722720 +489 489 64.799750 +490 489 -44.052860 +491 489 -20.746890 +488 490 -72.167850 +489 490 -44.052860 +490 490 170.274800 +492 490 -54.054050 +489 491 -20.746890 +491 491 20.746890 +490 492 -54.054050 +492 492 54.054050 +302 493 -66.225170 +488 493 -45.413260 +493 493 111.638400 +304 494 -66.225170 +488 494 -44.722720 +494 494 110.947900 \ No newline at end of file diff --git a/SPEX/ExampleMats/494_bus.rhs.txt b/SPEX/ExampleMats/494_bus.rhs.txt new file mode 100644 index 0000000000..3407b3cb27 --- /dev/null +++ b/SPEX/ExampleMats/494_bus.rhs.txt @@ -0,0 +1,495 @@ +494 1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/SPEX/ExampleMats/LF10.mat.txt b/SPEX/ExampleMats/LF10.mat.txt new file mode 100644 index 0000000000..f0c6d62dcc --- /dev/null +++ b/SPEX/ExampleMats/LF10.mat.txt @@ -0,0 +1,83 @@ +18 18 82 +1 1 3.53448 +2 1 -477.1548 +3 1 1.76724 +1 2 -477.1548 +2 2 171775.728 +4 2 -85887.864 +5 2 477.1548 +1 3 1.76724 +3 3 7.06896 +4 3 -477.1548 +5 3 1.76724 +2 4 -85887.864 +3 4 -477.1548 +4 4 171775.728 +6 4 -85887.864 +7 4 477.1548 +2 5 477.1548 +3 5 1.76724 +5 5 7.06896 +6 5 -477.1548 +7 5 1.76724 +4 6 -85887.864 +5 6 -477.1548 +6 6 171775.728 +8 6 -85887.864 +9 6 477.1548 +4 7 477.1548 +5 7 1.76724 +7 7 7.06896 +8 7 -477.1548 +9 7 1.76724 +6 8 -85887.864 +7 8 -477.1548 +8 8 171775.728 +10 8 -85887.864 +11 8 477.1548 +6 9 477.1548 +7 9 1.76724 +9 9 7.06896 +10 9 -477.1548 +11 9 1.76724 +8 10 -85887.864 +9 10 -477.1548 +10 10 171775.728 +12 10 -85887.864 +13 10 477.1548 +8 11 477.1548 +9 11 1.76724 +11 11 7.06896 +12 11 -477.1548 +13 11 1.76724 +10 12 -85887.864 +11 12 -477.1548 +12 12 171775.728 +14 12 -85887.864 +15 12 477.1548 +10 13 477.1548 +11 13 1.76724 +13 13 7.06896 +14 13 -477.1548 +15 13 1.76724 +12 14 -85887.864 +13 14 -477.1548 +14 14 171775.728 +16 14 -85887.864 +17 14 477.1548 +12 15 477.1548 +13 15 1.76724 +15 15 7.06896 +16 15 -477.1548 +17 15 1.76724 +14 16 -85887.864 +15 16 -477.1548 +16 16 171775.728 +18 16 477.1548 +14 17 477.1548 +15 17 1.76724 +17 17 7.06896 +18 17 1.76724 +16 18 477.1548 +17 18 1.76724 +18 18 3.53448 diff --git a/SPEX/ExampleMats/LFAT5.mat.txt b/SPEX/ExampleMats/LFAT5.mat.txt new file mode 100644 index 0000000000..ef2c9bf284 --- /dev/null +++ b/SPEX/ExampleMats/LFAT5.mat.txt @@ -0,0 +1,47 @@ +14 14 46 +1 1 1.57088 +4 1 -94.2528 +5 1 0.78544 +2 2 12566400 +6 2 -6283200 +3 3 0.608806201550388 +7 3 -0.304403100775194 +1 4 -94.2528 +4 4 15080.448 +8 4 -7540.224 +9 4 94.2528 +1 5 0.78544 +5 5 3.14176 +8 5 -94.2528 +9 5 0.78544 +2 6 -6283200 +6 6 12566400 +10 6 -6283200 +3 7 -0.304403100775194 +7 7 0.608806201550388 +11 7 -0.304403100775194 +4 8 -7540.224 +5 8 -94.2528 +8 8 15080.448 +12 8 -7540.224 +13 8 94.2528 +4 9 94.2528 +5 9 0.78544 +9 9 3.14176 +12 9 -94.2528 +13 9 0.78544 +6 10 -6283200 +10 10 12566400 +7 11 -0.304403100775194 +11 11 0.608806201550388 +8 12 -7540.224 +9 12 -94.2528 +12 12 15080.448 +14 12 94.2528 +8 13 94.2528 +9 13 0.78544 +13 13 3.14176 +14 13 0.78544 +12 14 94.2528 +13 14 0.78544 +14 14 1.57088 diff --git a/SPEX/SPEX_Left_LU/ExampleMats/NSR8K_mat.txt b/SPEX/ExampleMats/NSR8K.mat.txt similarity index 100% rename from SPEX/SPEX_Left_LU/ExampleMats/NSR8K_mat.txt rename to SPEX/ExampleMats/NSR8K.mat.txt diff --git a/SPEX/SPEX_Left_LU/ExampleMats/NSR8K_v.txt b/SPEX/ExampleMats/NSR8K.rhs.txt similarity index 100% rename from SPEX/SPEX_Left_LU/ExampleMats/NSR8K_v.txt rename to SPEX/ExampleMats/NSR8K.rhs.txt diff --git a/SPEX/ExampleMats/README.txt b/SPEX/ExampleMats/README.txt new file mode 100644 index 0000000000..f8bc054175 --- /dev/null +++ b/SPEX/ExampleMats/README.txt @@ -0,0 +1,49 @@ +Example matrices for SPEX demos and testing. + +All these matrices 1-based. + +Files: + + README.txt + + matrix right-hand-side description + ------ --------------- ----------- + 10teams.mat.txt 10teams.rhs.txt Basislib matrix + tomography.mat tomography.mat.rhs Earth science matrix from + MathWorks + LF10.mat.txt LF10.rhs.txt SPD linear 1D beam matrix + from Oberwolfach model + reduction benchmark collection + (collected from the SuiteSparse + Matrix Collection) + LFAT5.mat.txt LFAT5.rhs.txt SPD linear 1D beam matrix + from Oberwolfach model + reduction benchmark collection + (collected from the SuiteSparse + Matrix Collection) + Trefethen_500.mat.txt Trefethen_500.rhs.txt Diagonal matrix with primes + (collected from the SuiteSparse + Matrix Collection) + 494_bus.mat.txt 494_bus.rhs.txt SPD matrix from the Harwell + -Boeing collection (collected + from the SuiteSparse Matrix + Collection) + mesh1e1.mat.txt mesh1e1.rhs.txt SPD matrix from NASA + (collected from the SuiteSparse + Matrix Collection) + example.mat.txt example.rhs.txt Integer matrix + NSR8K.mat.txt NSR8K.rhs.txt Matrix from a real-world + mixed integer program + (collected from MIPLIB) + test1.mat.txt test1.rhs.txt Unsymmetric double matrix + created to test SPEX Cholesky + test2.mat.txt test2.rhs.txt Unsymmetric integer matrix + created to test SPEX Cholesky + test3.mat.txt test3.rhs.txt Unsymmetric matrix created + to test SPEX Cholesky + test4.mat.txt test4.rhs.txt Symmetric indefinite matrix + created to test SPEX Cholesky + test5.mat.txt test5.rhs.txt Small rectangular matrix + created to test SPEX + test.mat.txt test.rhs.txt Integer matrix to test SPEX LU + diff --git a/SPEX/ExampleMats/Trefethen_500.mat.txt b/SPEX/ExampleMats/Trefethen_500.mat.txt new file mode 100644 index 0000000000..2a389e324e --- /dev/null +++ b/SPEX/ExampleMats/Trefethen_500.mat.txt @@ -0,0 +1,8479 @@ +500 500 8478 +1 1 2 +2 1 1 +3 1 1 +5 1 1 +9 1 1 +17 1 1 +33 1 1 +65 1 1 +129 1 1 +257 1 1 +1 2 1 +2 2 3 +3 2 1 +4 2 1 +6 2 1 +10 2 1 +18 2 1 +34 2 1 +66 2 1 +130 2 1 +258 2 1 +1 3 1 +2 3 1 +3 3 5 +4 3 1 +5 3 1 +7 3 1 +11 3 1 +19 3 1 +35 3 1 +67 3 1 +131 3 1 +259 3 1 +2 4 1 +3 4 1 +4 4 7 +5 4 1 +6 4 1 +8 4 1 +12 4 1 +20 4 1 +36 4 1 +68 4 1 +132 4 1 +260 4 1 +1 5 1 +3 5 1 +4 5 1 +5 5 11 +6 5 1 +7 5 1 +9 5 1 +13 5 1 +21 5 1 +37 5 1 +69 5 1 +133 5 1 +261 5 1 +2 6 1 +4 6 1 +5 6 1 +6 6 13 +7 6 1 +8 6 1 +10 6 1 +14 6 1 +22 6 1 +38 6 1 +70 6 1 +134 6 1 +262 6 1 +3 7 1 +5 7 1 +6 7 1 +7 7 17 +8 7 1 +9 7 1 +11 7 1 +15 7 1 +23 7 1 +39 7 1 +71 7 1 +135 7 1 +263 7 1 +4 8 1 +6 8 1 +7 8 1 +8 8 19 +9 8 1 +10 8 1 +12 8 1 +16 8 1 +24 8 1 +40 8 1 +72 8 1 +136 8 1 +264 8 1 +1 9 1 +5 9 1 +7 9 1 +8 9 1 +9 9 23 +10 9 1 +11 9 1 +13 9 1 +17 9 1 +25 9 1 +41 9 1 +73 9 1 +137 9 1 +265 9 1 +2 10 1 +6 10 1 +8 10 1 +9 10 1 +10 10 29 +11 10 1 +12 10 1 +14 10 1 +18 10 1 +26 10 1 +42 10 1 +74 10 1 +138 10 1 +266 10 1 +3 11 1 +7 11 1 +9 11 1 +10 11 1 +11 11 31 +12 11 1 +13 11 1 +15 11 1 +19 11 1 +27 11 1 +43 11 1 +75 11 1 +139 11 1 +267 11 1 +4 12 1 +8 12 1 +10 12 1 +11 12 1 +12 12 37 +13 12 1 +14 12 1 +16 12 1 +20 12 1 +28 12 1 +44 12 1 +76 12 1 +140 12 1 +268 12 1 +5 13 1 +9 13 1 +11 13 1 +12 13 1 +13 13 41 +14 13 1 +15 13 1 +17 13 1 +21 13 1 +29 13 1 +45 13 1 +77 13 1 +141 13 1 +269 13 1 +6 14 1 +10 14 1 +12 14 1 +13 14 1 +14 14 43 +15 14 1 +16 14 1 +18 14 1 +22 14 1 +30 14 1 +46 14 1 +78 14 1 +142 14 1 +270 14 1 +7 15 1 +11 15 1 +13 15 1 +14 15 1 +15 15 47 +16 15 1 +17 15 1 +19 15 1 +23 15 1 +31 15 1 +47 15 1 +79 15 1 +143 15 1 +271 15 1 +8 16 1 +12 16 1 +14 16 1 +15 16 1 +16 16 53 +17 16 1 +18 16 1 +20 16 1 +24 16 1 +32 16 1 +48 16 1 +80 16 1 +144 16 1 +272 16 1 +1 17 1 +9 17 1 +13 17 1 +15 17 1 +16 17 1 +17 17 59 +18 17 1 +19 17 1 +21 17 1 +25 17 1 +33 17 1 +49 17 1 +81 17 1 +145 17 1 +273 17 1 +2 18 1 +10 18 1 +14 18 1 +16 18 1 +17 18 1 +18 18 61 +19 18 1 +20 18 1 +22 18 1 +26 18 1 +34 18 1 +50 18 1 +82 18 1 +146 18 1 +274 18 1 +3 19 1 +11 19 1 +15 19 1 +17 19 1 +18 19 1 +19 19 67 +20 19 1 +21 19 1 +23 19 1 +27 19 1 +35 19 1 +51 19 1 +83 19 1 +147 19 1 +275 19 1 +4 20 1 +12 20 1 +16 20 1 +18 20 1 +19 20 1 +20 20 71 +21 20 1 +22 20 1 +24 20 1 +28 20 1 +36 20 1 +52 20 1 +84 20 1 +148 20 1 +276 20 1 +5 21 1 +13 21 1 +17 21 1 +19 21 1 +20 21 1 +21 21 73 +22 21 1 +23 21 1 +25 21 1 +29 21 1 +37 21 1 +53 21 1 +85 21 1 +149 21 1 +277 21 1 +6 22 1 +14 22 1 +18 22 1 +20 22 1 +21 22 1 +22 22 79 +23 22 1 +24 22 1 +26 22 1 +30 22 1 +38 22 1 +54 22 1 +86 22 1 +150 22 1 +278 22 1 +7 23 1 +15 23 1 +19 23 1 +21 23 1 +22 23 1 +23 23 83 +24 23 1 +25 23 1 +27 23 1 +31 23 1 +39 23 1 +55 23 1 +87 23 1 +151 23 1 +279 23 1 +8 24 1 +16 24 1 +20 24 1 +22 24 1 +23 24 1 +24 24 89 +25 24 1 +26 24 1 +28 24 1 +32 24 1 +40 24 1 +56 24 1 +88 24 1 +152 24 1 +280 24 1 +9 25 1 +17 25 1 +21 25 1 +23 25 1 +24 25 1 +25 25 97 +26 25 1 +27 25 1 +29 25 1 +33 25 1 +41 25 1 +57 25 1 +89 25 1 +153 25 1 +281 25 1 +10 26 1 +18 26 1 +22 26 1 +24 26 1 +25 26 1 +26 26 101 +27 26 1 +28 26 1 +30 26 1 +34 26 1 +42 26 1 +58 26 1 +90 26 1 +154 26 1 +282 26 1 +11 27 1 +19 27 1 +23 27 1 +25 27 1 +26 27 1 +27 27 103 +28 27 1 +29 27 1 +31 27 1 +35 27 1 +43 27 1 +59 27 1 +91 27 1 +155 27 1 +283 27 1 +12 28 1 +20 28 1 +24 28 1 +26 28 1 +27 28 1 +28 28 107 +29 28 1 +30 28 1 +32 28 1 +36 28 1 +44 28 1 +60 28 1 +92 28 1 +156 28 1 +284 28 1 +13 29 1 +21 29 1 +25 29 1 +27 29 1 +28 29 1 +29 29 109 +30 29 1 +31 29 1 +33 29 1 +37 29 1 +45 29 1 +61 29 1 +93 29 1 +157 29 1 +285 29 1 +14 30 1 +22 30 1 +26 30 1 +28 30 1 +29 30 1 +30 30 113 +31 30 1 +32 30 1 +34 30 1 +38 30 1 +46 30 1 +62 30 1 +94 30 1 +158 30 1 +286 30 1 +15 31 1 +23 31 1 +27 31 1 +29 31 1 +30 31 1 +31 31 127 +32 31 1 +33 31 1 +35 31 1 +39 31 1 +47 31 1 +63 31 1 +95 31 1 +159 31 1 +287 31 1 +16 32 1 +24 32 1 +28 32 1 +30 32 1 +31 32 1 +32 32 131 +33 32 1 +34 32 1 +36 32 1 +40 32 1 +48 32 1 +64 32 1 +96 32 1 +160 32 1 +288 32 1 +1 33 1 +17 33 1 +25 33 1 +29 33 1 +31 33 1 +32 33 1 +33 33 137 +34 33 1 +35 33 1 +37 33 1 +41 33 1 +49 33 1 +65 33 1 +97 33 1 +161 33 1 +289 33 1 +2 34 1 +18 34 1 +26 34 1 +30 34 1 +32 34 1 +33 34 1 +34 34 139 +35 34 1 +36 34 1 +38 34 1 +42 34 1 +50 34 1 +66 34 1 +98 34 1 +162 34 1 +290 34 1 +3 35 1 +19 35 1 +27 35 1 +31 35 1 +33 35 1 +34 35 1 +35 35 149 +36 35 1 +37 35 1 +39 35 1 +43 35 1 +51 35 1 +67 35 1 +99 35 1 +163 35 1 +291 35 1 +4 36 1 +20 36 1 +28 36 1 +32 36 1 +34 36 1 +35 36 1 +36 36 151 +37 36 1 +38 36 1 +40 36 1 +44 36 1 +52 36 1 +68 36 1 +100 36 1 +164 36 1 +292 36 1 +5 37 1 +21 37 1 +29 37 1 +33 37 1 +35 37 1 +36 37 1 +37 37 157 +38 37 1 +39 37 1 +41 37 1 +45 37 1 +53 37 1 +69 37 1 +101 37 1 +165 37 1 +293 37 1 +6 38 1 +22 38 1 +30 38 1 +34 38 1 +36 38 1 +37 38 1 +38 38 163 +39 38 1 +40 38 1 +42 38 1 +46 38 1 +54 38 1 +70 38 1 +102 38 1 +166 38 1 +294 38 1 +7 39 1 +23 39 1 +31 39 1 +35 39 1 +37 39 1 +38 39 1 +39 39 167 +40 39 1 +41 39 1 +43 39 1 +47 39 1 +55 39 1 +71 39 1 +103 39 1 +167 39 1 +295 39 1 +8 40 1 +24 40 1 +32 40 1 +36 40 1 +38 40 1 +39 40 1 +40 40 173 +41 40 1 +42 40 1 +44 40 1 +48 40 1 +56 40 1 +72 40 1 +104 40 1 +168 40 1 +296 40 1 +9 41 1 +25 41 1 +33 41 1 +37 41 1 +39 41 1 +40 41 1 +41 41 179 +42 41 1 +43 41 1 +45 41 1 +49 41 1 +57 41 1 +73 41 1 +105 41 1 +169 41 1 +297 41 1 +10 42 1 +26 42 1 +34 42 1 +38 42 1 +40 42 1 +41 42 1 +42 42 181 +43 42 1 +44 42 1 +46 42 1 +50 42 1 +58 42 1 +74 42 1 +106 42 1 +170 42 1 +298 42 1 +11 43 1 +27 43 1 +35 43 1 +39 43 1 +41 43 1 +42 43 1 +43 43 191 +44 43 1 +45 43 1 +47 43 1 +51 43 1 +59 43 1 +75 43 1 +107 43 1 +171 43 1 +299 43 1 +12 44 1 +28 44 1 +36 44 1 +40 44 1 +42 44 1 +43 44 1 +44 44 193 +45 44 1 +46 44 1 +48 44 1 +52 44 1 +60 44 1 +76 44 1 +108 44 1 +172 44 1 +300 44 1 +13 45 1 +29 45 1 +37 45 1 +41 45 1 +43 45 1 +44 45 1 +45 45 197 +46 45 1 +47 45 1 +49 45 1 +53 45 1 +61 45 1 +77 45 1 +109 45 1 +173 45 1 +301 45 1 +14 46 1 +30 46 1 +38 46 1 +42 46 1 +44 46 1 +45 46 1 +46 46 199 +47 46 1 +48 46 1 +50 46 1 +54 46 1 +62 46 1 +78 46 1 +110 46 1 +174 46 1 +302 46 1 +15 47 1 +31 47 1 +39 47 1 +43 47 1 +45 47 1 +46 47 1 +47 47 211 +48 47 1 +49 47 1 +51 47 1 +55 47 1 +63 47 1 +79 47 1 +111 47 1 +175 47 1 +303 47 1 +16 48 1 +32 48 1 +40 48 1 +44 48 1 +46 48 1 +47 48 1 +48 48 223 +49 48 1 +50 48 1 +52 48 1 +56 48 1 +64 48 1 +80 48 1 +112 48 1 +176 48 1 +304 48 1 +17 49 1 +33 49 1 +41 49 1 +45 49 1 +47 49 1 +48 49 1 +49 49 227 +50 49 1 +51 49 1 +53 49 1 +57 49 1 +65 49 1 +81 49 1 +113 49 1 +177 49 1 +305 49 1 +18 50 1 +34 50 1 +42 50 1 +46 50 1 +48 50 1 +49 50 1 +50 50 229 +51 50 1 +52 50 1 +54 50 1 +58 50 1 +66 50 1 +82 50 1 +114 50 1 +178 50 1 +306 50 1 +19 51 1 +35 51 1 +43 51 1 +47 51 1 +49 51 1 +50 51 1 +51 51 233 +52 51 1 +53 51 1 +55 51 1 +59 51 1 +67 51 1 +83 51 1 +115 51 1 +179 51 1 +307 51 1 +20 52 1 +36 52 1 +44 52 1 +48 52 1 +50 52 1 +51 52 1 +52 52 239 +53 52 1 +54 52 1 +56 52 1 +60 52 1 +68 52 1 +84 52 1 +116 52 1 +180 52 1 +308 52 1 +21 53 1 +37 53 1 +45 53 1 +49 53 1 +51 53 1 +52 53 1 +53 53 241 +54 53 1 +55 53 1 +57 53 1 +61 53 1 +69 53 1 +85 53 1 +117 53 1 +181 53 1 +309 53 1 +22 54 1 +38 54 1 +46 54 1 +50 54 1 +52 54 1 +53 54 1 +54 54 251 +55 54 1 +56 54 1 +58 54 1 +62 54 1 +70 54 1 +86 54 1 +118 54 1 +182 54 1 +310 54 1 +23 55 1 +39 55 1 +47 55 1 +51 55 1 +53 55 1 +54 55 1 +55 55 257 +56 55 1 +57 55 1 +59 55 1 +63 55 1 +71 55 1 +87 55 1 +119 55 1 +183 55 1 +311 55 1 +24 56 1 +40 56 1 +48 56 1 +52 56 1 +54 56 1 +55 56 1 +56 56 263 +57 56 1 +58 56 1 +60 56 1 +64 56 1 +72 56 1 +88 56 1 +120 56 1 +184 56 1 +312 56 1 +25 57 1 +41 57 1 +49 57 1 +53 57 1 +55 57 1 +56 57 1 +57 57 269 +58 57 1 +59 57 1 +61 57 1 +65 57 1 +73 57 1 +89 57 1 +121 57 1 +185 57 1 +313 57 1 +26 58 1 +42 58 1 +50 58 1 +54 58 1 +56 58 1 +57 58 1 +58 58 271 +59 58 1 +60 58 1 +62 58 1 +66 58 1 +74 58 1 +90 58 1 +122 58 1 +186 58 1 +314 58 1 +27 59 1 +43 59 1 +51 59 1 +55 59 1 +57 59 1 +58 59 1 +59 59 277 +60 59 1 +61 59 1 +63 59 1 +67 59 1 +75 59 1 +91 59 1 +123 59 1 +187 59 1 +315 59 1 +28 60 1 +44 60 1 +52 60 1 +56 60 1 +58 60 1 +59 60 1 +60 60 281 +61 60 1 +62 60 1 +64 60 1 +68 60 1 +76 60 1 +92 60 1 +124 60 1 +188 60 1 +316 60 1 +29 61 1 +45 61 1 +53 61 1 +57 61 1 +59 61 1 +60 61 1 +61 61 283 +62 61 1 +63 61 1 +65 61 1 +69 61 1 +77 61 1 +93 61 1 +125 61 1 +189 61 1 +317 61 1 +30 62 1 +46 62 1 +54 62 1 +58 62 1 +60 62 1 +61 62 1 +62 62 293 +63 62 1 +64 62 1 +66 62 1 +70 62 1 +78 62 1 +94 62 1 +126 62 1 +190 62 1 +318 62 1 +31 63 1 +47 63 1 +55 63 1 +59 63 1 +61 63 1 +62 63 1 +63 63 307 +64 63 1 +65 63 1 +67 63 1 +71 63 1 +79 63 1 +95 63 1 +127 63 1 +191 63 1 +319 63 1 +32 64 1 +48 64 1 +56 64 1 +60 64 1 +62 64 1 +63 64 1 +64 64 311 +65 64 1 +66 64 1 +68 64 1 +72 64 1 +80 64 1 +96 64 1 +128 64 1 +192 64 1 +320 64 1 +1 65 1 +33 65 1 +49 65 1 +57 65 1 +61 65 1 +63 65 1 +64 65 1 +65 65 313 +66 65 1 +67 65 1 +69 65 1 +73 65 1 +81 65 1 +97 65 1 +129 65 1 +193 65 1 +321 65 1 +2 66 1 +34 66 1 +50 66 1 +58 66 1 +62 66 1 +64 66 1 +65 66 1 +66 66 317 +67 66 1 +68 66 1 +70 66 1 +74 66 1 +82 66 1 +98 66 1 +130 66 1 +194 66 1 +322 66 1 +3 67 1 +35 67 1 +51 67 1 +59 67 1 +63 67 1 +65 67 1 +66 67 1 +67 67 331 +68 67 1 +69 67 1 +71 67 1 +75 67 1 +83 67 1 +99 67 1 +131 67 1 +195 67 1 +323 67 1 +4 68 1 +36 68 1 +52 68 1 +60 68 1 +64 68 1 +66 68 1 +67 68 1 +68 68 337 +69 68 1 +70 68 1 +72 68 1 +76 68 1 +84 68 1 +100 68 1 +132 68 1 +196 68 1 +324 68 1 +5 69 1 +37 69 1 +53 69 1 +61 69 1 +65 69 1 +67 69 1 +68 69 1 +69 69 347 +70 69 1 +71 69 1 +73 69 1 +77 69 1 +85 69 1 +101 69 1 +133 69 1 +197 69 1 +325 69 1 +6 70 1 +38 70 1 +54 70 1 +62 70 1 +66 70 1 +68 70 1 +69 70 1 +70 70 349 +71 70 1 +72 70 1 +74 70 1 +78 70 1 +86 70 1 +102 70 1 +134 70 1 +198 70 1 +326 70 1 +7 71 1 +39 71 1 +55 71 1 +63 71 1 +67 71 1 +69 71 1 +70 71 1 +71 71 353 +72 71 1 +73 71 1 +75 71 1 +79 71 1 +87 71 1 +103 71 1 +135 71 1 +199 71 1 +327 71 1 +8 72 1 +40 72 1 +56 72 1 +64 72 1 +68 72 1 +70 72 1 +71 72 1 +72 72 359 +73 72 1 +74 72 1 +76 72 1 +80 72 1 +88 72 1 +104 72 1 +136 72 1 +200 72 1 +328 72 1 +9 73 1 +41 73 1 +57 73 1 +65 73 1 +69 73 1 +71 73 1 +72 73 1 +73 73 367 +74 73 1 +75 73 1 +77 73 1 +81 73 1 +89 73 1 +105 73 1 +137 73 1 +201 73 1 +329 73 1 +10 74 1 +42 74 1 +58 74 1 +66 74 1 +70 74 1 +72 74 1 +73 74 1 +74 74 373 +75 74 1 +76 74 1 +78 74 1 +82 74 1 +90 74 1 +106 74 1 +138 74 1 +202 74 1 +330 74 1 +11 75 1 +43 75 1 +59 75 1 +67 75 1 +71 75 1 +73 75 1 +74 75 1 +75 75 379 +76 75 1 +77 75 1 +79 75 1 +83 75 1 +91 75 1 +107 75 1 +139 75 1 +203 75 1 +331 75 1 +12 76 1 +44 76 1 +60 76 1 +68 76 1 +72 76 1 +74 76 1 +75 76 1 +76 76 383 +77 76 1 +78 76 1 +80 76 1 +84 76 1 +92 76 1 +108 76 1 +140 76 1 +204 76 1 +332 76 1 +13 77 1 +45 77 1 +61 77 1 +69 77 1 +73 77 1 +75 77 1 +76 77 1 +77 77 389 +78 77 1 +79 77 1 +81 77 1 +85 77 1 +93 77 1 +109 77 1 +141 77 1 +205 77 1 +333 77 1 +14 78 1 +46 78 1 +62 78 1 +70 78 1 +74 78 1 +76 78 1 +77 78 1 +78 78 397 +79 78 1 +80 78 1 +82 78 1 +86 78 1 +94 78 1 +110 78 1 +142 78 1 +206 78 1 +334 78 1 +15 79 1 +47 79 1 +63 79 1 +71 79 1 +75 79 1 +77 79 1 +78 79 1 +79 79 401 +80 79 1 +81 79 1 +83 79 1 +87 79 1 +95 79 1 +111 79 1 +143 79 1 +207 79 1 +335 79 1 +16 80 1 +48 80 1 +64 80 1 +72 80 1 +76 80 1 +78 80 1 +79 80 1 +80 80 409 +81 80 1 +82 80 1 +84 80 1 +88 80 1 +96 80 1 +112 80 1 +144 80 1 +208 80 1 +336 80 1 +17 81 1 +49 81 1 +65 81 1 +73 81 1 +77 81 1 +79 81 1 +80 81 1 +81 81 419 +82 81 1 +83 81 1 +85 81 1 +89 81 1 +97 81 1 +113 81 1 +145 81 1 +209 81 1 +337 81 1 +18 82 1 +50 82 1 +66 82 1 +74 82 1 +78 82 1 +80 82 1 +81 82 1 +82 82 421 +83 82 1 +84 82 1 +86 82 1 +90 82 1 +98 82 1 +114 82 1 +146 82 1 +210 82 1 +338 82 1 +19 83 1 +51 83 1 +67 83 1 +75 83 1 +79 83 1 +81 83 1 +82 83 1 +83 83 431 +84 83 1 +85 83 1 +87 83 1 +91 83 1 +99 83 1 +115 83 1 +147 83 1 +211 83 1 +339 83 1 +20 84 1 +52 84 1 +68 84 1 +76 84 1 +80 84 1 +82 84 1 +83 84 1 +84 84 433 +85 84 1 +86 84 1 +88 84 1 +92 84 1 +100 84 1 +116 84 1 +148 84 1 +212 84 1 +340 84 1 +21 85 1 +53 85 1 +69 85 1 +77 85 1 +81 85 1 +83 85 1 +84 85 1 +85 85 439 +86 85 1 +87 85 1 +89 85 1 +93 85 1 +101 85 1 +117 85 1 +149 85 1 +213 85 1 +341 85 1 +22 86 1 +54 86 1 +70 86 1 +78 86 1 +82 86 1 +84 86 1 +85 86 1 +86 86 443 +87 86 1 +88 86 1 +90 86 1 +94 86 1 +102 86 1 +118 86 1 +150 86 1 +214 86 1 +342 86 1 +23 87 1 +55 87 1 +71 87 1 +79 87 1 +83 87 1 +85 87 1 +86 87 1 +87 87 449 +88 87 1 +89 87 1 +91 87 1 +95 87 1 +103 87 1 +119 87 1 +151 87 1 +215 87 1 +343 87 1 +24 88 1 +56 88 1 +72 88 1 +80 88 1 +84 88 1 +86 88 1 +87 88 1 +88 88 457 +89 88 1 +90 88 1 +92 88 1 +96 88 1 +104 88 1 +120 88 1 +152 88 1 +216 88 1 +344 88 1 +25 89 1 +57 89 1 +73 89 1 +81 89 1 +85 89 1 +87 89 1 +88 89 1 +89 89 461 +90 89 1 +91 89 1 +93 89 1 +97 89 1 +105 89 1 +121 89 1 +153 89 1 +217 89 1 +345 89 1 +26 90 1 +58 90 1 +74 90 1 +82 90 1 +86 90 1 +88 90 1 +89 90 1 +90 90 463 +91 90 1 +92 90 1 +94 90 1 +98 90 1 +106 90 1 +122 90 1 +154 90 1 +218 90 1 +346 90 1 +27 91 1 +59 91 1 +75 91 1 +83 91 1 +87 91 1 +89 91 1 +90 91 1 +91 91 467 +92 91 1 +93 91 1 +95 91 1 +99 91 1 +107 91 1 +123 91 1 +155 91 1 +219 91 1 +347 91 1 +28 92 1 +60 92 1 +76 92 1 +84 92 1 +88 92 1 +90 92 1 +91 92 1 +92 92 479 +93 92 1 +94 92 1 +96 92 1 +100 92 1 +108 92 1 +124 92 1 +156 92 1 +220 92 1 +348 92 1 +29 93 1 +61 93 1 +77 93 1 +85 93 1 +89 93 1 +91 93 1 +92 93 1 +93 93 487 +94 93 1 +95 93 1 +97 93 1 +101 93 1 +109 93 1 +125 93 1 +157 93 1 +221 93 1 +349 93 1 +30 94 1 +62 94 1 +78 94 1 +86 94 1 +90 94 1 +92 94 1 +93 94 1 +94 94 491 +95 94 1 +96 94 1 +98 94 1 +102 94 1 +110 94 1 +126 94 1 +158 94 1 +222 94 1 +350 94 1 +31 95 1 +63 95 1 +79 95 1 +87 95 1 +91 95 1 +93 95 1 +94 95 1 +95 95 499 +96 95 1 +97 95 1 +99 95 1 +103 95 1 +111 95 1 +127 95 1 +159 95 1 +223 95 1 +351 95 1 +32 96 1 +64 96 1 +80 96 1 +88 96 1 +92 96 1 +94 96 1 +95 96 1 +96 96 503 +97 96 1 +98 96 1 +100 96 1 +104 96 1 +112 96 1 +128 96 1 +160 96 1 +224 96 1 +352 96 1 +33 97 1 +65 97 1 +81 97 1 +89 97 1 +93 97 1 +95 97 1 +96 97 1 +97 97 509 +98 97 1 +99 97 1 +101 97 1 +105 97 1 +113 97 1 +129 97 1 +161 97 1 +225 97 1 +353 97 1 +34 98 1 +66 98 1 +82 98 1 +90 98 1 +94 98 1 +96 98 1 +97 98 1 +98 98 521 +99 98 1 +100 98 1 +102 98 1 +106 98 1 +114 98 1 +130 98 1 +162 98 1 +226 98 1 +354 98 1 +35 99 1 +67 99 1 +83 99 1 +91 99 1 +95 99 1 +97 99 1 +98 99 1 +99 99 523 +100 99 1 +101 99 1 +103 99 1 +107 99 1 +115 99 1 +131 99 1 +163 99 1 +227 99 1 +355 99 1 +36 100 1 +68 100 1 +84 100 1 +92 100 1 +96 100 1 +98 100 1 +99 100 1 +100 100 541 +101 100 1 +102 100 1 +104 100 1 +108 100 1 +116 100 1 +132 100 1 +164 100 1 +228 100 1 +356 100 1 +37 101 1 +69 101 1 +85 101 1 +93 101 1 +97 101 1 +99 101 1 +100 101 1 +101 101 547 +102 101 1 +103 101 1 +105 101 1 +109 101 1 +117 101 1 +133 101 1 +165 101 1 +229 101 1 +357 101 1 +38 102 1 +70 102 1 +86 102 1 +94 102 1 +98 102 1 +100 102 1 +101 102 1 +102 102 557 +103 102 1 +104 102 1 +106 102 1 +110 102 1 +118 102 1 +134 102 1 +166 102 1 +230 102 1 +358 102 1 +39 103 1 +71 103 1 +87 103 1 +95 103 1 +99 103 1 +101 103 1 +102 103 1 +103 103 563 +104 103 1 +105 103 1 +107 103 1 +111 103 1 +119 103 1 +135 103 1 +167 103 1 +231 103 1 +359 103 1 +40 104 1 +72 104 1 +88 104 1 +96 104 1 +100 104 1 +102 104 1 +103 104 1 +104 104 569 +105 104 1 +106 104 1 +108 104 1 +112 104 1 +120 104 1 +136 104 1 +168 104 1 +232 104 1 +360 104 1 +41 105 1 +73 105 1 +89 105 1 +97 105 1 +101 105 1 +103 105 1 +104 105 1 +105 105 571 +106 105 1 +107 105 1 +109 105 1 +113 105 1 +121 105 1 +137 105 1 +169 105 1 +233 105 1 +361 105 1 +42 106 1 +74 106 1 +90 106 1 +98 106 1 +102 106 1 +104 106 1 +105 106 1 +106 106 577 +107 106 1 +108 106 1 +110 106 1 +114 106 1 +122 106 1 +138 106 1 +170 106 1 +234 106 1 +362 106 1 +43 107 1 +75 107 1 +91 107 1 +99 107 1 +103 107 1 +105 107 1 +106 107 1 +107 107 587 +108 107 1 +109 107 1 +111 107 1 +115 107 1 +123 107 1 +139 107 1 +171 107 1 +235 107 1 +363 107 1 +44 108 1 +76 108 1 +92 108 1 +100 108 1 +104 108 1 +106 108 1 +107 108 1 +108 108 593 +109 108 1 +110 108 1 +112 108 1 +116 108 1 +124 108 1 +140 108 1 +172 108 1 +236 108 1 +364 108 1 +45 109 1 +77 109 1 +93 109 1 +101 109 1 +105 109 1 +107 109 1 +108 109 1 +109 109 599 +110 109 1 +111 109 1 +113 109 1 +117 109 1 +125 109 1 +141 109 1 +173 109 1 +237 109 1 +365 109 1 +46 110 1 +78 110 1 +94 110 1 +102 110 1 +106 110 1 +108 110 1 +109 110 1 +110 110 601 +111 110 1 +112 110 1 +114 110 1 +118 110 1 +126 110 1 +142 110 1 +174 110 1 +238 110 1 +366 110 1 +47 111 1 +79 111 1 +95 111 1 +103 111 1 +107 111 1 +109 111 1 +110 111 1 +111 111 607 +112 111 1 +113 111 1 +115 111 1 +119 111 1 +127 111 1 +143 111 1 +175 111 1 +239 111 1 +367 111 1 +48 112 1 +80 112 1 +96 112 1 +104 112 1 +108 112 1 +110 112 1 +111 112 1 +112 112 613 +113 112 1 +114 112 1 +116 112 1 +120 112 1 +128 112 1 +144 112 1 +176 112 1 +240 112 1 +368 112 1 +49 113 1 +81 113 1 +97 113 1 +105 113 1 +109 113 1 +111 113 1 +112 113 1 +113 113 617 +114 113 1 +115 113 1 +117 113 1 +121 113 1 +129 113 1 +145 113 1 +177 113 1 +241 113 1 +369 113 1 +50 114 1 +82 114 1 +98 114 1 +106 114 1 +110 114 1 +112 114 1 +113 114 1 +114 114 619 +115 114 1 +116 114 1 +118 114 1 +122 114 1 +130 114 1 +146 114 1 +178 114 1 +242 114 1 +370 114 1 +51 115 1 +83 115 1 +99 115 1 +107 115 1 +111 115 1 +113 115 1 +114 115 1 +115 115 631 +116 115 1 +117 115 1 +119 115 1 +123 115 1 +131 115 1 +147 115 1 +179 115 1 +243 115 1 +371 115 1 +52 116 1 +84 116 1 +100 116 1 +108 116 1 +112 116 1 +114 116 1 +115 116 1 +116 116 641 +117 116 1 +118 116 1 +120 116 1 +124 116 1 +132 116 1 +148 116 1 +180 116 1 +244 116 1 +372 116 1 +53 117 1 +85 117 1 +101 117 1 +109 117 1 +113 117 1 +115 117 1 +116 117 1 +117 117 643 +118 117 1 +119 117 1 +121 117 1 +125 117 1 +133 117 1 +149 117 1 +181 117 1 +245 117 1 +373 117 1 +54 118 1 +86 118 1 +102 118 1 +110 118 1 +114 118 1 +116 118 1 +117 118 1 +118 118 647 +119 118 1 +120 118 1 +122 118 1 +126 118 1 +134 118 1 +150 118 1 +182 118 1 +246 118 1 +374 118 1 +55 119 1 +87 119 1 +103 119 1 +111 119 1 +115 119 1 +117 119 1 +118 119 1 +119 119 653 +120 119 1 +121 119 1 +123 119 1 +127 119 1 +135 119 1 +151 119 1 +183 119 1 +247 119 1 +375 119 1 +56 120 1 +88 120 1 +104 120 1 +112 120 1 +116 120 1 +118 120 1 +119 120 1 +120 120 659 +121 120 1 +122 120 1 +124 120 1 +128 120 1 +136 120 1 +152 120 1 +184 120 1 +248 120 1 +376 120 1 +57 121 1 +89 121 1 +105 121 1 +113 121 1 +117 121 1 +119 121 1 +120 121 1 +121 121 661 +122 121 1 +123 121 1 +125 121 1 +129 121 1 +137 121 1 +153 121 1 +185 121 1 +249 121 1 +377 121 1 +58 122 1 +90 122 1 +106 122 1 +114 122 1 +118 122 1 +120 122 1 +121 122 1 +122 122 673 +123 122 1 +124 122 1 +126 122 1 +130 122 1 +138 122 1 +154 122 1 +186 122 1 +250 122 1 +378 122 1 +59 123 1 +91 123 1 +107 123 1 +115 123 1 +119 123 1 +121 123 1 +122 123 1 +123 123 677 +124 123 1 +125 123 1 +127 123 1 +131 123 1 +139 123 1 +155 123 1 +187 123 1 +251 123 1 +379 123 1 +60 124 1 +92 124 1 +108 124 1 +116 124 1 +120 124 1 +122 124 1 +123 124 1 +124 124 683 +125 124 1 +126 124 1 +128 124 1 +132 124 1 +140 124 1 +156 124 1 +188 124 1 +252 124 1 +380 124 1 +61 125 1 +93 125 1 +109 125 1 +117 125 1 +121 125 1 +123 125 1 +124 125 1 +125 125 691 +126 125 1 +127 125 1 +129 125 1 +133 125 1 +141 125 1 +157 125 1 +189 125 1 +253 125 1 +381 125 1 +62 126 1 +94 126 1 +110 126 1 +118 126 1 +122 126 1 +124 126 1 +125 126 1 +126 126 701 +127 126 1 +128 126 1 +130 126 1 +134 126 1 +142 126 1 +158 126 1 +190 126 1 +254 126 1 +382 126 1 +63 127 1 +95 127 1 +111 127 1 +119 127 1 +123 127 1 +125 127 1 +126 127 1 +127 127 709 +128 127 1 +129 127 1 +131 127 1 +135 127 1 +143 127 1 +159 127 1 +191 127 1 +255 127 1 +383 127 1 +64 128 1 +96 128 1 +112 128 1 +120 128 1 +124 128 1 +126 128 1 +127 128 1 +128 128 719 +129 128 1 +130 128 1 +132 128 1 +136 128 1 +144 128 1 +160 128 1 +192 128 1 +256 128 1 +384 128 1 +1 129 1 +65 129 1 +97 129 1 +113 129 1 +121 129 1 +125 129 1 +127 129 1 +128 129 1 +129 129 727 +130 129 1 +131 129 1 +133 129 1 +137 129 1 +145 129 1 +161 129 1 +193 129 1 +257 129 1 +385 129 1 +2 130 1 +66 130 1 +98 130 1 +114 130 1 +122 130 1 +126 130 1 +128 130 1 +129 130 1 +130 130 733 +131 130 1 +132 130 1 +134 130 1 +138 130 1 +146 130 1 +162 130 1 +194 130 1 +258 130 1 +386 130 1 +3 131 1 +67 131 1 +99 131 1 +115 131 1 +123 131 1 +127 131 1 +129 131 1 +130 131 1 +131 131 739 +132 131 1 +133 131 1 +135 131 1 +139 131 1 +147 131 1 +163 131 1 +195 131 1 +259 131 1 +387 131 1 +4 132 1 +68 132 1 +100 132 1 +116 132 1 +124 132 1 +128 132 1 +130 132 1 +131 132 1 +132 132 743 +133 132 1 +134 132 1 +136 132 1 +140 132 1 +148 132 1 +164 132 1 +196 132 1 +260 132 1 +388 132 1 +5 133 1 +69 133 1 +101 133 1 +117 133 1 +125 133 1 +129 133 1 +131 133 1 +132 133 1 +133 133 751 +134 133 1 +135 133 1 +137 133 1 +141 133 1 +149 133 1 +165 133 1 +197 133 1 +261 133 1 +389 133 1 +6 134 1 +70 134 1 +102 134 1 +118 134 1 +126 134 1 +130 134 1 +132 134 1 +133 134 1 +134 134 757 +135 134 1 +136 134 1 +138 134 1 +142 134 1 +150 134 1 +166 134 1 +198 134 1 +262 134 1 +390 134 1 +7 135 1 +71 135 1 +103 135 1 +119 135 1 +127 135 1 +131 135 1 +133 135 1 +134 135 1 +135 135 761 +136 135 1 +137 135 1 +139 135 1 +143 135 1 +151 135 1 +167 135 1 +199 135 1 +263 135 1 +391 135 1 +8 136 1 +72 136 1 +104 136 1 +120 136 1 +128 136 1 +132 136 1 +134 136 1 +135 136 1 +136 136 769 +137 136 1 +138 136 1 +140 136 1 +144 136 1 +152 136 1 +168 136 1 +200 136 1 +264 136 1 +392 136 1 +9 137 1 +73 137 1 +105 137 1 +121 137 1 +129 137 1 +133 137 1 +135 137 1 +136 137 1 +137 137 773 +138 137 1 +139 137 1 +141 137 1 +145 137 1 +153 137 1 +169 137 1 +201 137 1 +265 137 1 +393 137 1 +10 138 1 +74 138 1 +106 138 1 +122 138 1 +130 138 1 +134 138 1 +136 138 1 +137 138 1 +138 138 787 +139 138 1 +140 138 1 +142 138 1 +146 138 1 +154 138 1 +170 138 1 +202 138 1 +266 138 1 +394 138 1 +11 139 1 +75 139 1 +107 139 1 +123 139 1 +131 139 1 +135 139 1 +137 139 1 +138 139 1 +139 139 797 +140 139 1 +141 139 1 +143 139 1 +147 139 1 +155 139 1 +171 139 1 +203 139 1 +267 139 1 +395 139 1 +12 140 1 +76 140 1 +108 140 1 +124 140 1 +132 140 1 +136 140 1 +138 140 1 +139 140 1 +140 140 809 +141 140 1 +142 140 1 +144 140 1 +148 140 1 +156 140 1 +172 140 1 +204 140 1 +268 140 1 +396 140 1 +13 141 1 +77 141 1 +109 141 1 +125 141 1 +133 141 1 +137 141 1 +139 141 1 +140 141 1 +141 141 811 +142 141 1 +143 141 1 +145 141 1 +149 141 1 +157 141 1 +173 141 1 +205 141 1 +269 141 1 +397 141 1 +14 142 1 +78 142 1 +110 142 1 +126 142 1 +134 142 1 +138 142 1 +140 142 1 +141 142 1 +142 142 821 +143 142 1 +144 142 1 +146 142 1 +150 142 1 +158 142 1 +174 142 1 +206 142 1 +270 142 1 +398 142 1 +15 143 1 +79 143 1 +111 143 1 +127 143 1 +135 143 1 +139 143 1 +141 143 1 +142 143 1 +143 143 823 +144 143 1 +145 143 1 +147 143 1 +151 143 1 +159 143 1 +175 143 1 +207 143 1 +271 143 1 +399 143 1 +16 144 1 +80 144 1 +112 144 1 +128 144 1 +136 144 1 +140 144 1 +142 144 1 +143 144 1 +144 144 827 +145 144 1 +146 144 1 +148 144 1 +152 144 1 +160 144 1 +176 144 1 +208 144 1 +272 144 1 +400 144 1 +17 145 1 +81 145 1 +113 145 1 +129 145 1 +137 145 1 +141 145 1 +143 145 1 +144 145 1 +145 145 829 +146 145 1 +147 145 1 +149 145 1 +153 145 1 +161 145 1 +177 145 1 +209 145 1 +273 145 1 +401 145 1 +18 146 1 +82 146 1 +114 146 1 +130 146 1 +138 146 1 +142 146 1 +144 146 1 +145 146 1 +146 146 839 +147 146 1 +148 146 1 +150 146 1 +154 146 1 +162 146 1 +178 146 1 +210 146 1 +274 146 1 +402 146 1 +19 147 1 +83 147 1 +115 147 1 +131 147 1 +139 147 1 +143 147 1 +145 147 1 +146 147 1 +147 147 853 +148 147 1 +149 147 1 +151 147 1 +155 147 1 +163 147 1 +179 147 1 +211 147 1 +275 147 1 +403 147 1 +20 148 1 +84 148 1 +116 148 1 +132 148 1 +140 148 1 +144 148 1 +146 148 1 +147 148 1 +148 148 857 +149 148 1 +150 148 1 +152 148 1 +156 148 1 +164 148 1 +180 148 1 +212 148 1 +276 148 1 +404 148 1 +21 149 1 +85 149 1 +117 149 1 +133 149 1 +141 149 1 +145 149 1 +147 149 1 +148 149 1 +149 149 859 +150 149 1 +151 149 1 +153 149 1 +157 149 1 +165 149 1 +181 149 1 +213 149 1 +277 149 1 +405 149 1 +22 150 1 +86 150 1 +118 150 1 +134 150 1 +142 150 1 +146 150 1 +148 150 1 +149 150 1 +150 150 863 +151 150 1 +152 150 1 +154 150 1 +158 150 1 +166 150 1 +182 150 1 +214 150 1 +278 150 1 +406 150 1 +23 151 1 +87 151 1 +119 151 1 +135 151 1 +143 151 1 +147 151 1 +149 151 1 +150 151 1 +151 151 877 +152 151 1 +153 151 1 +155 151 1 +159 151 1 +167 151 1 +183 151 1 +215 151 1 +279 151 1 +407 151 1 +24 152 1 +88 152 1 +120 152 1 +136 152 1 +144 152 1 +148 152 1 +150 152 1 +151 152 1 +152 152 881 +153 152 1 +154 152 1 +156 152 1 +160 152 1 +168 152 1 +184 152 1 +216 152 1 +280 152 1 +408 152 1 +25 153 1 +89 153 1 +121 153 1 +137 153 1 +145 153 1 +149 153 1 +151 153 1 +152 153 1 +153 153 883 +154 153 1 +155 153 1 +157 153 1 +161 153 1 +169 153 1 +185 153 1 +217 153 1 +281 153 1 +409 153 1 +26 154 1 +90 154 1 +122 154 1 +138 154 1 +146 154 1 +150 154 1 +152 154 1 +153 154 1 +154 154 887 +155 154 1 +156 154 1 +158 154 1 +162 154 1 +170 154 1 +186 154 1 +218 154 1 +282 154 1 +410 154 1 +27 155 1 +91 155 1 +123 155 1 +139 155 1 +147 155 1 +151 155 1 +153 155 1 +154 155 1 +155 155 907 +156 155 1 +157 155 1 +159 155 1 +163 155 1 +171 155 1 +187 155 1 +219 155 1 +283 155 1 +411 155 1 +28 156 1 +92 156 1 +124 156 1 +140 156 1 +148 156 1 +152 156 1 +154 156 1 +155 156 1 +156 156 911 +157 156 1 +158 156 1 +160 156 1 +164 156 1 +172 156 1 +188 156 1 +220 156 1 +284 156 1 +412 156 1 +29 157 1 +93 157 1 +125 157 1 +141 157 1 +149 157 1 +153 157 1 +155 157 1 +156 157 1 +157 157 919 +158 157 1 +159 157 1 +161 157 1 +165 157 1 +173 157 1 +189 157 1 +221 157 1 +285 157 1 +413 157 1 +30 158 1 +94 158 1 +126 158 1 +142 158 1 +150 158 1 +154 158 1 +156 158 1 +157 158 1 +158 158 929 +159 158 1 +160 158 1 +162 158 1 +166 158 1 +174 158 1 +190 158 1 +222 158 1 +286 158 1 +414 158 1 +31 159 1 +95 159 1 +127 159 1 +143 159 1 +151 159 1 +155 159 1 +157 159 1 +158 159 1 +159 159 937 +160 159 1 +161 159 1 +163 159 1 +167 159 1 +175 159 1 +191 159 1 +223 159 1 +287 159 1 +415 159 1 +32 160 1 +96 160 1 +128 160 1 +144 160 1 +152 160 1 +156 160 1 +158 160 1 +159 160 1 +160 160 941 +161 160 1 +162 160 1 +164 160 1 +168 160 1 +176 160 1 +192 160 1 +224 160 1 +288 160 1 +416 160 1 +33 161 1 +97 161 1 +129 161 1 +145 161 1 +153 161 1 +157 161 1 +159 161 1 +160 161 1 +161 161 947 +162 161 1 +163 161 1 +165 161 1 +169 161 1 +177 161 1 +193 161 1 +225 161 1 +289 161 1 +417 161 1 +34 162 1 +98 162 1 +130 162 1 +146 162 1 +154 162 1 +158 162 1 +160 162 1 +161 162 1 +162 162 953 +163 162 1 +164 162 1 +166 162 1 +170 162 1 +178 162 1 +194 162 1 +226 162 1 +290 162 1 +418 162 1 +35 163 1 +99 163 1 +131 163 1 +147 163 1 +155 163 1 +159 163 1 +161 163 1 +162 163 1 +163 163 967 +164 163 1 +165 163 1 +167 163 1 +171 163 1 +179 163 1 +195 163 1 +227 163 1 +291 163 1 +419 163 1 +36 164 1 +100 164 1 +132 164 1 +148 164 1 +156 164 1 +160 164 1 +162 164 1 +163 164 1 +164 164 971 +165 164 1 +166 164 1 +168 164 1 +172 164 1 +180 164 1 +196 164 1 +228 164 1 +292 164 1 +420 164 1 +37 165 1 +101 165 1 +133 165 1 +149 165 1 +157 165 1 +161 165 1 +163 165 1 +164 165 1 +165 165 977 +166 165 1 +167 165 1 +169 165 1 +173 165 1 +181 165 1 +197 165 1 +229 165 1 +293 165 1 +421 165 1 +38 166 1 +102 166 1 +134 166 1 +150 166 1 +158 166 1 +162 166 1 +164 166 1 +165 166 1 +166 166 983 +167 166 1 +168 166 1 +170 166 1 +174 166 1 +182 166 1 +198 166 1 +230 166 1 +294 166 1 +422 166 1 +39 167 1 +103 167 1 +135 167 1 +151 167 1 +159 167 1 +163 167 1 +165 167 1 +166 167 1 +167 167 991 +168 167 1 +169 167 1 +171 167 1 +175 167 1 +183 167 1 +199 167 1 +231 167 1 +295 167 1 +423 167 1 +40 168 1 +104 168 1 +136 168 1 +152 168 1 +160 168 1 +164 168 1 +166 168 1 +167 168 1 +168 168 997 +169 168 1 +170 168 1 +172 168 1 +176 168 1 +184 168 1 +200 168 1 +232 168 1 +296 168 1 +424 168 1 +41 169 1 +105 169 1 +137 169 1 +153 169 1 +161 169 1 +165 169 1 +167 169 1 +168 169 1 +169 169 1009 +170 169 1 +171 169 1 +173 169 1 +177 169 1 +185 169 1 +201 169 1 +233 169 1 +297 169 1 +425 169 1 +42 170 1 +106 170 1 +138 170 1 +154 170 1 +162 170 1 +166 170 1 +168 170 1 +169 170 1 +170 170 1013 +171 170 1 +172 170 1 +174 170 1 +178 170 1 +186 170 1 +202 170 1 +234 170 1 +298 170 1 +426 170 1 +43 171 1 +107 171 1 +139 171 1 +155 171 1 +163 171 1 +167 171 1 +169 171 1 +170 171 1 +171 171 1019 +172 171 1 +173 171 1 +175 171 1 +179 171 1 +187 171 1 +203 171 1 +235 171 1 +299 171 1 +427 171 1 +44 172 1 +108 172 1 +140 172 1 +156 172 1 +164 172 1 +168 172 1 +170 172 1 +171 172 1 +172 172 1021 +173 172 1 +174 172 1 +176 172 1 +180 172 1 +188 172 1 +204 172 1 +236 172 1 +300 172 1 +428 172 1 +45 173 1 +109 173 1 +141 173 1 +157 173 1 +165 173 1 +169 173 1 +171 173 1 +172 173 1 +173 173 1031 +174 173 1 +175 173 1 +177 173 1 +181 173 1 +189 173 1 +205 173 1 +237 173 1 +301 173 1 +429 173 1 +46 174 1 +110 174 1 +142 174 1 +158 174 1 +166 174 1 +170 174 1 +172 174 1 +173 174 1 +174 174 1033 +175 174 1 +176 174 1 +178 174 1 +182 174 1 +190 174 1 +206 174 1 +238 174 1 +302 174 1 +430 174 1 +47 175 1 +111 175 1 +143 175 1 +159 175 1 +167 175 1 +171 175 1 +173 175 1 +174 175 1 +175 175 1039 +176 175 1 +177 175 1 +179 175 1 +183 175 1 +191 175 1 +207 175 1 +239 175 1 +303 175 1 +431 175 1 +48 176 1 +112 176 1 +144 176 1 +160 176 1 +168 176 1 +172 176 1 +174 176 1 +175 176 1 +176 176 1049 +177 176 1 +178 176 1 +180 176 1 +184 176 1 +192 176 1 +208 176 1 +240 176 1 +304 176 1 +432 176 1 +49 177 1 +113 177 1 +145 177 1 +161 177 1 +169 177 1 +173 177 1 +175 177 1 +176 177 1 +177 177 1051 +178 177 1 +179 177 1 +181 177 1 +185 177 1 +193 177 1 +209 177 1 +241 177 1 +305 177 1 +433 177 1 +50 178 1 +114 178 1 +146 178 1 +162 178 1 +170 178 1 +174 178 1 +176 178 1 +177 178 1 +178 178 1061 +179 178 1 +180 178 1 +182 178 1 +186 178 1 +194 178 1 +210 178 1 +242 178 1 +306 178 1 +434 178 1 +51 179 1 +115 179 1 +147 179 1 +163 179 1 +171 179 1 +175 179 1 +177 179 1 +178 179 1 +179 179 1063 +180 179 1 +181 179 1 +183 179 1 +187 179 1 +195 179 1 +211 179 1 +243 179 1 +307 179 1 +435 179 1 +52 180 1 +116 180 1 +148 180 1 +164 180 1 +172 180 1 +176 180 1 +178 180 1 +179 180 1 +180 180 1069 +181 180 1 +182 180 1 +184 180 1 +188 180 1 +196 180 1 +212 180 1 +244 180 1 +308 180 1 +436 180 1 +53 181 1 +117 181 1 +149 181 1 +165 181 1 +173 181 1 +177 181 1 +179 181 1 +180 181 1 +181 181 1087 +182 181 1 +183 181 1 +185 181 1 +189 181 1 +197 181 1 +213 181 1 +245 181 1 +309 181 1 +437 181 1 +54 182 1 +118 182 1 +150 182 1 +166 182 1 +174 182 1 +178 182 1 +180 182 1 +181 182 1 +182 182 1091 +183 182 1 +184 182 1 +186 182 1 +190 182 1 +198 182 1 +214 182 1 +246 182 1 +310 182 1 +438 182 1 +55 183 1 +119 183 1 +151 183 1 +167 183 1 +175 183 1 +179 183 1 +181 183 1 +182 183 1 +183 183 1093 +184 183 1 +185 183 1 +187 183 1 +191 183 1 +199 183 1 +215 183 1 +247 183 1 +311 183 1 +439 183 1 +56 184 1 +120 184 1 +152 184 1 +168 184 1 +176 184 1 +180 184 1 +182 184 1 +183 184 1 +184 184 1097 +185 184 1 +186 184 1 +188 184 1 +192 184 1 +200 184 1 +216 184 1 +248 184 1 +312 184 1 +440 184 1 +57 185 1 +121 185 1 +153 185 1 +169 185 1 +177 185 1 +181 185 1 +183 185 1 +184 185 1 +185 185 1103 +186 185 1 +187 185 1 +189 185 1 +193 185 1 +201 185 1 +217 185 1 +249 185 1 +313 185 1 +441 185 1 +58 186 1 +122 186 1 +154 186 1 +170 186 1 +178 186 1 +182 186 1 +184 186 1 +185 186 1 +186 186 1109 +187 186 1 +188 186 1 +190 186 1 +194 186 1 +202 186 1 +218 186 1 +250 186 1 +314 186 1 +442 186 1 +59 187 1 +123 187 1 +155 187 1 +171 187 1 +179 187 1 +183 187 1 +185 187 1 +186 187 1 +187 187 1117 +188 187 1 +189 187 1 +191 187 1 +195 187 1 +203 187 1 +219 187 1 +251 187 1 +315 187 1 +443 187 1 +60 188 1 +124 188 1 +156 188 1 +172 188 1 +180 188 1 +184 188 1 +186 188 1 +187 188 1 +188 188 1123 +189 188 1 +190 188 1 +192 188 1 +196 188 1 +204 188 1 +220 188 1 +252 188 1 +316 188 1 +444 188 1 +61 189 1 +125 189 1 +157 189 1 +173 189 1 +181 189 1 +185 189 1 +187 189 1 +188 189 1 +189 189 1129 +190 189 1 +191 189 1 +193 189 1 +197 189 1 +205 189 1 +221 189 1 +253 189 1 +317 189 1 +445 189 1 +62 190 1 +126 190 1 +158 190 1 +174 190 1 +182 190 1 +186 190 1 +188 190 1 +189 190 1 +190 190 1151 +191 190 1 +192 190 1 +194 190 1 +198 190 1 +206 190 1 +222 190 1 +254 190 1 +318 190 1 +446 190 1 +63 191 1 +127 191 1 +159 191 1 +175 191 1 +183 191 1 +187 191 1 +189 191 1 +190 191 1 +191 191 1153 +192 191 1 +193 191 1 +195 191 1 +199 191 1 +207 191 1 +223 191 1 +255 191 1 +319 191 1 +447 191 1 +64 192 1 +128 192 1 +160 192 1 +176 192 1 +184 192 1 +188 192 1 +190 192 1 +191 192 1 +192 192 1163 +193 192 1 +194 192 1 +196 192 1 +200 192 1 +208 192 1 +224 192 1 +256 192 1 +320 192 1 +448 192 1 +65 193 1 +129 193 1 +161 193 1 +177 193 1 +185 193 1 +189 193 1 +191 193 1 +192 193 1 +193 193 1171 +194 193 1 +195 193 1 +197 193 1 +201 193 1 +209 193 1 +225 193 1 +257 193 1 +321 193 1 +449 193 1 +66 194 1 +130 194 1 +162 194 1 +178 194 1 +186 194 1 +190 194 1 +192 194 1 +193 194 1 +194 194 1181 +195 194 1 +196 194 1 +198 194 1 +202 194 1 +210 194 1 +226 194 1 +258 194 1 +322 194 1 +450 194 1 +67 195 1 +131 195 1 +163 195 1 +179 195 1 +187 195 1 +191 195 1 +193 195 1 +194 195 1 +195 195 1187 +196 195 1 +197 195 1 +199 195 1 +203 195 1 +211 195 1 +227 195 1 +259 195 1 +323 195 1 +451 195 1 +68 196 1 +132 196 1 +164 196 1 +180 196 1 +188 196 1 +192 196 1 +194 196 1 +195 196 1 +196 196 1193 +197 196 1 +198 196 1 +200 196 1 +204 196 1 +212 196 1 +228 196 1 +260 196 1 +324 196 1 +452 196 1 +69 197 1 +133 197 1 +165 197 1 +181 197 1 +189 197 1 +193 197 1 +195 197 1 +196 197 1 +197 197 1201 +198 197 1 +199 197 1 +201 197 1 +205 197 1 +213 197 1 +229 197 1 +261 197 1 +325 197 1 +453 197 1 +70 198 1 +134 198 1 +166 198 1 +182 198 1 +190 198 1 +194 198 1 +196 198 1 +197 198 1 +198 198 1213 +199 198 1 +200 198 1 +202 198 1 +206 198 1 +214 198 1 +230 198 1 +262 198 1 +326 198 1 +454 198 1 +71 199 1 +135 199 1 +167 199 1 +183 199 1 +191 199 1 +195 199 1 +197 199 1 +198 199 1 +199 199 1217 +200 199 1 +201 199 1 +203 199 1 +207 199 1 +215 199 1 +231 199 1 +263 199 1 +327 199 1 +455 199 1 +72 200 1 +136 200 1 +168 200 1 +184 200 1 +192 200 1 +196 200 1 +198 200 1 +199 200 1 +200 200 1223 +201 200 1 +202 200 1 +204 200 1 +208 200 1 +216 200 1 +232 200 1 +264 200 1 +328 200 1 +456 200 1 +73 201 1 +137 201 1 +169 201 1 +185 201 1 +193 201 1 +197 201 1 +199 201 1 +200 201 1 +201 201 1229 +202 201 1 +203 201 1 +205 201 1 +209 201 1 +217 201 1 +233 201 1 +265 201 1 +329 201 1 +457 201 1 +74 202 1 +138 202 1 +170 202 1 +186 202 1 +194 202 1 +198 202 1 +200 202 1 +201 202 1 +202 202 1231 +203 202 1 +204 202 1 +206 202 1 +210 202 1 +218 202 1 +234 202 1 +266 202 1 +330 202 1 +458 202 1 +75 203 1 +139 203 1 +171 203 1 +187 203 1 +195 203 1 +199 203 1 +201 203 1 +202 203 1 +203 203 1237 +204 203 1 +205 203 1 +207 203 1 +211 203 1 +219 203 1 +235 203 1 +267 203 1 +331 203 1 +459 203 1 +76 204 1 +140 204 1 +172 204 1 +188 204 1 +196 204 1 +200 204 1 +202 204 1 +203 204 1 +204 204 1249 +205 204 1 +206 204 1 +208 204 1 +212 204 1 +220 204 1 +236 204 1 +268 204 1 +332 204 1 +460 204 1 +77 205 1 +141 205 1 +173 205 1 +189 205 1 +197 205 1 +201 205 1 +203 205 1 +204 205 1 +205 205 1259 +206 205 1 +207 205 1 +209 205 1 +213 205 1 +221 205 1 +237 205 1 +269 205 1 +333 205 1 +461 205 1 +78 206 1 +142 206 1 +174 206 1 +190 206 1 +198 206 1 +202 206 1 +204 206 1 +205 206 1 +206 206 1277 +207 206 1 +208 206 1 +210 206 1 +214 206 1 +222 206 1 +238 206 1 +270 206 1 +334 206 1 +462 206 1 +79 207 1 +143 207 1 +175 207 1 +191 207 1 +199 207 1 +203 207 1 +205 207 1 +206 207 1 +207 207 1279 +208 207 1 +209 207 1 +211 207 1 +215 207 1 +223 207 1 +239 207 1 +271 207 1 +335 207 1 +463 207 1 +80 208 1 +144 208 1 +176 208 1 +192 208 1 +200 208 1 +204 208 1 +206 208 1 +207 208 1 +208 208 1283 +209 208 1 +210 208 1 +212 208 1 +216 208 1 +224 208 1 +240 208 1 +272 208 1 +336 208 1 +464 208 1 +81 209 1 +145 209 1 +177 209 1 +193 209 1 +201 209 1 +205 209 1 +207 209 1 +208 209 1 +209 209 1289 +210 209 1 +211 209 1 +213 209 1 +217 209 1 +225 209 1 +241 209 1 +273 209 1 +337 209 1 +465 209 1 +82 210 1 +146 210 1 +178 210 1 +194 210 1 +202 210 1 +206 210 1 +208 210 1 +209 210 1 +210 210 1291 +211 210 1 +212 210 1 +214 210 1 +218 210 1 +226 210 1 +242 210 1 +274 210 1 +338 210 1 +466 210 1 +83 211 1 +147 211 1 +179 211 1 +195 211 1 +203 211 1 +207 211 1 +209 211 1 +210 211 1 +211 211 1297 +212 211 1 +213 211 1 +215 211 1 +219 211 1 +227 211 1 +243 211 1 +275 211 1 +339 211 1 +467 211 1 +84 212 1 +148 212 1 +180 212 1 +196 212 1 +204 212 1 +208 212 1 +210 212 1 +211 212 1 +212 212 1301 +213 212 1 +214 212 1 +216 212 1 +220 212 1 +228 212 1 +244 212 1 +276 212 1 +340 212 1 +468 212 1 +85 213 1 +149 213 1 +181 213 1 +197 213 1 +205 213 1 +209 213 1 +211 213 1 +212 213 1 +213 213 1303 +214 213 1 +215 213 1 +217 213 1 +221 213 1 +229 213 1 +245 213 1 +277 213 1 +341 213 1 +469 213 1 +86 214 1 +150 214 1 +182 214 1 +198 214 1 +206 214 1 +210 214 1 +212 214 1 +213 214 1 +214 214 1307 +215 214 1 +216 214 1 +218 214 1 +222 214 1 +230 214 1 +246 214 1 +278 214 1 +342 214 1 +470 214 1 +87 215 1 +151 215 1 +183 215 1 +199 215 1 +207 215 1 +211 215 1 +213 215 1 +214 215 1 +215 215 1319 +216 215 1 +217 215 1 +219 215 1 +223 215 1 +231 215 1 +247 215 1 +279 215 1 +343 215 1 +471 215 1 +88 216 1 +152 216 1 +184 216 1 +200 216 1 +208 216 1 +212 216 1 +214 216 1 +215 216 1 +216 216 1321 +217 216 1 +218 216 1 +220 216 1 +224 216 1 +232 216 1 +248 216 1 +280 216 1 +344 216 1 +472 216 1 +89 217 1 +153 217 1 +185 217 1 +201 217 1 +209 217 1 +213 217 1 +215 217 1 +216 217 1 +217 217 1327 +218 217 1 +219 217 1 +221 217 1 +225 217 1 +233 217 1 +249 217 1 +281 217 1 +345 217 1 +473 217 1 +90 218 1 +154 218 1 +186 218 1 +202 218 1 +210 218 1 +214 218 1 +216 218 1 +217 218 1 +218 218 1361 +219 218 1 +220 218 1 +222 218 1 +226 218 1 +234 218 1 +250 218 1 +282 218 1 +346 218 1 +474 218 1 +91 219 1 +155 219 1 +187 219 1 +203 219 1 +211 219 1 +215 219 1 +217 219 1 +218 219 1 +219 219 1367 +220 219 1 +221 219 1 +223 219 1 +227 219 1 +235 219 1 +251 219 1 +283 219 1 +347 219 1 +475 219 1 +92 220 1 +156 220 1 +188 220 1 +204 220 1 +212 220 1 +216 220 1 +218 220 1 +219 220 1 +220 220 1373 +221 220 1 +222 220 1 +224 220 1 +228 220 1 +236 220 1 +252 220 1 +284 220 1 +348 220 1 +476 220 1 +93 221 1 +157 221 1 +189 221 1 +205 221 1 +213 221 1 +217 221 1 +219 221 1 +220 221 1 +221 221 1381 +222 221 1 +223 221 1 +225 221 1 +229 221 1 +237 221 1 +253 221 1 +285 221 1 +349 221 1 +477 221 1 +94 222 1 +158 222 1 +190 222 1 +206 222 1 +214 222 1 +218 222 1 +220 222 1 +221 222 1 +222 222 1399 +223 222 1 +224 222 1 +226 222 1 +230 222 1 +238 222 1 +254 222 1 +286 222 1 +350 222 1 +478 222 1 +95 223 1 +159 223 1 +191 223 1 +207 223 1 +215 223 1 +219 223 1 +221 223 1 +222 223 1 +223 223 1409 +224 223 1 +225 223 1 +227 223 1 +231 223 1 +239 223 1 +255 223 1 +287 223 1 +351 223 1 +479 223 1 +96 224 1 +160 224 1 +192 224 1 +208 224 1 +216 224 1 +220 224 1 +222 224 1 +223 224 1 +224 224 1423 +225 224 1 +226 224 1 +228 224 1 +232 224 1 +240 224 1 +256 224 1 +288 224 1 +352 224 1 +480 224 1 +97 225 1 +161 225 1 +193 225 1 +209 225 1 +217 225 1 +221 225 1 +223 225 1 +224 225 1 +225 225 1427 +226 225 1 +227 225 1 +229 225 1 +233 225 1 +241 225 1 +257 225 1 +289 225 1 +353 225 1 +481 225 1 +98 226 1 +162 226 1 +194 226 1 +210 226 1 +218 226 1 +222 226 1 +224 226 1 +225 226 1 +226 226 1429 +227 226 1 +228 226 1 +230 226 1 +234 226 1 +242 226 1 +258 226 1 +290 226 1 +354 226 1 +482 226 1 +99 227 1 +163 227 1 +195 227 1 +211 227 1 +219 227 1 +223 227 1 +225 227 1 +226 227 1 +227 227 1433 +228 227 1 +229 227 1 +231 227 1 +235 227 1 +243 227 1 +259 227 1 +291 227 1 +355 227 1 +483 227 1 +100 228 1 +164 228 1 +196 228 1 +212 228 1 +220 228 1 +224 228 1 +226 228 1 +227 228 1 +228 228 1439 +229 228 1 +230 228 1 +232 228 1 +236 228 1 +244 228 1 +260 228 1 +292 228 1 +356 228 1 +484 228 1 +101 229 1 +165 229 1 +197 229 1 +213 229 1 +221 229 1 +225 229 1 +227 229 1 +228 229 1 +229 229 1447 +230 229 1 +231 229 1 +233 229 1 +237 229 1 +245 229 1 +261 229 1 +293 229 1 +357 229 1 +485 229 1 +102 230 1 +166 230 1 +198 230 1 +214 230 1 +222 230 1 +226 230 1 +228 230 1 +229 230 1 +230 230 1451 +231 230 1 +232 230 1 +234 230 1 +238 230 1 +246 230 1 +262 230 1 +294 230 1 +358 230 1 +486 230 1 +103 231 1 +167 231 1 +199 231 1 +215 231 1 +223 231 1 +227 231 1 +229 231 1 +230 231 1 +231 231 1453 +232 231 1 +233 231 1 +235 231 1 +239 231 1 +247 231 1 +263 231 1 +295 231 1 +359 231 1 +487 231 1 +104 232 1 +168 232 1 +200 232 1 +216 232 1 +224 232 1 +228 232 1 +230 232 1 +231 232 1 +232 232 1459 +233 232 1 +234 232 1 +236 232 1 +240 232 1 +248 232 1 +264 232 1 +296 232 1 +360 232 1 +488 232 1 +105 233 1 +169 233 1 +201 233 1 +217 233 1 +225 233 1 +229 233 1 +231 233 1 +232 233 1 +233 233 1471 +234 233 1 +235 233 1 +237 233 1 +241 233 1 +249 233 1 +265 233 1 +297 233 1 +361 233 1 +489 233 1 +106 234 1 +170 234 1 +202 234 1 +218 234 1 +226 234 1 +230 234 1 +232 234 1 +233 234 1 +234 234 1481 +235 234 1 +236 234 1 +238 234 1 +242 234 1 +250 234 1 +266 234 1 +298 234 1 +362 234 1 +490 234 1 +107 235 1 +171 235 1 +203 235 1 +219 235 1 +227 235 1 +231 235 1 +233 235 1 +234 235 1 +235 235 1483 +236 235 1 +237 235 1 +239 235 1 +243 235 1 +251 235 1 +267 235 1 +299 235 1 +363 235 1 +491 235 1 +108 236 1 +172 236 1 +204 236 1 +220 236 1 +228 236 1 +232 236 1 +234 236 1 +235 236 1 +236 236 1487 +237 236 1 +238 236 1 +240 236 1 +244 236 1 +252 236 1 +268 236 1 +300 236 1 +364 236 1 +492 236 1 +109 237 1 +173 237 1 +205 237 1 +221 237 1 +229 237 1 +233 237 1 +235 237 1 +236 237 1 +237 237 1489 +238 237 1 +239 237 1 +241 237 1 +245 237 1 +253 237 1 +269 237 1 +301 237 1 +365 237 1 +493 237 1 +110 238 1 +174 238 1 +206 238 1 +222 238 1 +230 238 1 +234 238 1 +236 238 1 +237 238 1 +238 238 1493 +239 238 1 +240 238 1 +242 238 1 +246 238 1 +254 238 1 +270 238 1 +302 238 1 +366 238 1 +494 238 1 +111 239 1 +175 239 1 +207 239 1 +223 239 1 +231 239 1 +235 239 1 +237 239 1 +238 239 1 +239 239 1499 +240 239 1 +241 239 1 +243 239 1 +247 239 1 +255 239 1 +271 239 1 +303 239 1 +367 239 1 +495 239 1 +112 240 1 +176 240 1 +208 240 1 +224 240 1 +232 240 1 +236 240 1 +238 240 1 +239 240 1 +240 240 1511 +241 240 1 +242 240 1 +244 240 1 +248 240 1 +256 240 1 +272 240 1 +304 240 1 +368 240 1 +496 240 1 +113 241 1 +177 241 1 +209 241 1 +225 241 1 +233 241 1 +237 241 1 +239 241 1 +240 241 1 +241 241 1523 +242 241 1 +243 241 1 +245 241 1 +249 241 1 +257 241 1 +273 241 1 +305 241 1 +369 241 1 +497 241 1 +114 242 1 +178 242 1 +210 242 1 +226 242 1 +234 242 1 +238 242 1 +240 242 1 +241 242 1 +242 242 1531 +243 242 1 +244 242 1 +246 242 1 +250 242 1 +258 242 1 +274 242 1 +306 242 1 +370 242 1 +498 242 1 +115 243 1 +179 243 1 +211 243 1 +227 243 1 +235 243 1 +239 243 1 +241 243 1 +242 243 1 +243 243 1543 +244 243 1 +245 243 1 +247 243 1 +251 243 1 +259 243 1 +275 243 1 +307 243 1 +371 243 1 +499 243 1 +116 244 1 +180 244 1 +212 244 1 +228 244 1 +236 244 1 +240 244 1 +242 244 1 +243 244 1 +244 244 1549 +245 244 1 +246 244 1 +248 244 1 +252 244 1 +260 244 1 +276 244 1 +308 244 1 +372 244 1 +500 244 1 +117 245 1 +181 245 1 +213 245 1 +229 245 1 +237 245 1 +241 245 1 +243 245 1 +244 245 1 +245 245 1553 +246 245 1 +247 245 1 +249 245 1 +253 245 1 +261 245 1 +277 245 1 +309 245 1 +373 245 1 +118 246 1 +182 246 1 +214 246 1 +230 246 1 +238 246 1 +242 246 1 +244 246 1 +245 246 1 +246 246 1559 +247 246 1 +248 246 1 +250 246 1 +254 246 1 +262 246 1 +278 246 1 +310 246 1 +374 246 1 +119 247 1 +183 247 1 +215 247 1 +231 247 1 +239 247 1 +243 247 1 +245 247 1 +246 247 1 +247 247 1567 +248 247 1 +249 247 1 +251 247 1 +255 247 1 +263 247 1 +279 247 1 +311 247 1 +375 247 1 +120 248 1 +184 248 1 +216 248 1 +232 248 1 +240 248 1 +244 248 1 +246 248 1 +247 248 1 +248 248 1571 +249 248 1 +250 248 1 +252 248 1 +256 248 1 +264 248 1 +280 248 1 +312 248 1 +376 248 1 +121 249 1 +185 249 1 +217 249 1 +233 249 1 +241 249 1 +245 249 1 +247 249 1 +248 249 1 +249 249 1579 +250 249 1 +251 249 1 +253 249 1 +257 249 1 +265 249 1 +281 249 1 +313 249 1 +377 249 1 +122 250 1 +186 250 1 +218 250 1 +234 250 1 +242 250 1 +246 250 1 +248 250 1 +249 250 1 +250 250 1583 +251 250 1 +252 250 1 +254 250 1 +258 250 1 +266 250 1 +282 250 1 +314 250 1 +378 250 1 +123 251 1 +187 251 1 +219 251 1 +235 251 1 +243 251 1 +247 251 1 +249 251 1 +250 251 1 +251 251 1597 +252 251 1 +253 251 1 +255 251 1 +259 251 1 +267 251 1 +283 251 1 +315 251 1 +379 251 1 +124 252 1 +188 252 1 +220 252 1 +236 252 1 +244 252 1 +248 252 1 +250 252 1 +251 252 1 +252 252 1601 +253 252 1 +254 252 1 +256 252 1 +260 252 1 +268 252 1 +284 252 1 +316 252 1 +380 252 1 +125 253 1 +189 253 1 +221 253 1 +237 253 1 +245 253 1 +249 253 1 +251 253 1 +252 253 1 +253 253 1607 +254 253 1 +255 253 1 +257 253 1 +261 253 1 +269 253 1 +285 253 1 +317 253 1 +381 253 1 +126 254 1 +190 254 1 +222 254 1 +238 254 1 +246 254 1 +250 254 1 +252 254 1 +253 254 1 +254 254 1609 +255 254 1 +256 254 1 +258 254 1 +262 254 1 +270 254 1 +286 254 1 +318 254 1 +382 254 1 +127 255 1 +191 255 1 +223 255 1 +239 255 1 +247 255 1 +251 255 1 +253 255 1 +254 255 1 +255 255 1613 +256 255 1 +257 255 1 +259 255 1 +263 255 1 +271 255 1 +287 255 1 +319 255 1 +383 255 1 +128 256 1 +192 256 1 +224 256 1 +240 256 1 +248 256 1 +252 256 1 +254 256 1 +255 256 1 +256 256 1619 +257 256 1 +258 256 1 +260 256 1 +264 256 1 +272 256 1 +288 256 1 +320 256 1 +384 256 1 +1 257 1 +129 257 1 +193 257 1 +225 257 1 +241 257 1 +249 257 1 +253 257 1 +255 257 1 +256 257 1 +257 257 1621 +258 257 1 +259 257 1 +261 257 1 +265 257 1 +273 257 1 +289 257 1 +321 257 1 +385 257 1 +2 258 1 +130 258 1 +194 258 1 +226 258 1 +242 258 1 +250 258 1 +254 258 1 +256 258 1 +257 258 1 +258 258 1627 +259 258 1 +260 258 1 +262 258 1 +266 258 1 +274 258 1 +290 258 1 +322 258 1 +386 258 1 +3 259 1 +131 259 1 +195 259 1 +227 259 1 +243 259 1 +251 259 1 +255 259 1 +257 259 1 +258 259 1 +259 259 1637 +260 259 1 +261 259 1 +263 259 1 +267 259 1 +275 259 1 +291 259 1 +323 259 1 +387 259 1 +4 260 1 +132 260 1 +196 260 1 +228 260 1 +244 260 1 +252 260 1 +256 260 1 +258 260 1 +259 260 1 +260 260 1657 +261 260 1 +262 260 1 +264 260 1 +268 260 1 +276 260 1 +292 260 1 +324 260 1 +388 260 1 +5 261 1 +133 261 1 +197 261 1 +229 261 1 +245 261 1 +253 261 1 +257 261 1 +259 261 1 +260 261 1 +261 261 1663 +262 261 1 +263 261 1 +265 261 1 +269 261 1 +277 261 1 +293 261 1 +325 261 1 +389 261 1 +6 262 1 +134 262 1 +198 262 1 +230 262 1 +246 262 1 +254 262 1 +258 262 1 +260 262 1 +261 262 1 +262 262 1667 +263 262 1 +264 262 1 +266 262 1 +270 262 1 +278 262 1 +294 262 1 +326 262 1 +390 262 1 +7 263 1 +135 263 1 +199 263 1 +231 263 1 +247 263 1 +255 263 1 +259 263 1 +261 263 1 +262 263 1 +263 263 1669 +264 263 1 +265 263 1 +267 263 1 +271 263 1 +279 263 1 +295 263 1 +327 263 1 +391 263 1 +8 264 1 +136 264 1 +200 264 1 +232 264 1 +248 264 1 +256 264 1 +260 264 1 +262 264 1 +263 264 1 +264 264 1693 +265 264 1 +266 264 1 +268 264 1 +272 264 1 +280 264 1 +296 264 1 +328 264 1 +392 264 1 +9 265 1 +137 265 1 +201 265 1 +233 265 1 +249 265 1 +257 265 1 +261 265 1 +263 265 1 +264 265 1 +265 265 1697 +266 265 1 +267 265 1 +269 265 1 +273 265 1 +281 265 1 +297 265 1 +329 265 1 +393 265 1 +10 266 1 +138 266 1 +202 266 1 +234 266 1 +250 266 1 +258 266 1 +262 266 1 +264 266 1 +265 266 1 +266 266 1699 +267 266 1 +268 266 1 +270 266 1 +274 266 1 +282 266 1 +298 266 1 +330 266 1 +394 266 1 +11 267 1 +139 267 1 +203 267 1 +235 267 1 +251 267 1 +259 267 1 +263 267 1 +265 267 1 +266 267 1 +267 267 1709 +268 267 1 +269 267 1 +271 267 1 +275 267 1 +283 267 1 +299 267 1 +331 267 1 +395 267 1 +12 268 1 +140 268 1 +204 268 1 +236 268 1 +252 268 1 +260 268 1 +264 268 1 +266 268 1 +267 268 1 +268 268 1721 +269 268 1 +270 268 1 +272 268 1 +276 268 1 +284 268 1 +300 268 1 +332 268 1 +396 268 1 +13 269 1 +141 269 1 +205 269 1 +237 269 1 +253 269 1 +261 269 1 +265 269 1 +267 269 1 +268 269 1 +269 269 1723 +270 269 1 +271 269 1 +273 269 1 +277 269 1 +285 269 1 +301 269 1 +333 269 1 +397 269 1 +14 270 1 +142 270 1 +206 270 1 +238 270 1 +254 270 1 +262 270 1 +266 270 1 +268 270 1 +269 270 1 +270 270 1733 +271 270 1 +272 270 1 +274 270 1 +278 270 1 +286 270 1 +302 270 1 +334 270 1 +398 270 1 +15 271 1 +143 271 1 +207 271 1 +239 271 1 +255 271 1 +263 271 1 +267 271 1 +269 271 1 +270 271 1 +271 271 1741 +272 271 1 +273 271 1 +275 271 1 +279 271 1 +287 271 1 +303 271 1 +335 271 1 +399 271 1 +16 272 1 +144 272 1 +208 272 1 +240 272 1 +256 272 1 +264 272 1 +268 272 1 +270 272 1 +271 272 1 +272 272 1747 +273 272 1 +274 272 1 +276 272 1 +280 272 1 +288 272 1 +304 272 1 +336 272 1 +400 272 1 +17 273 1 +145 273 1 +209 273 1 +241 273 1 +257 273 1 +265 273 1 +269 273 1 +271 273 1 +272 273 1 +273 273 1753 +274 273 1 +275 273 1 +277 273 1 +281 273 1 +289 273 1 +305 273 1 +337 273 1 +401 273 1 +18 274 1 +146 274 1 +210 274 1 +242 274 1 +258 274 1 +266 274 1 +270 274 1 +272 274 1 +273 274 1 +274 274 1759 +275 274 1 +276 274 1 +278 274 1 +282 274 1 +290 274 1 +306 274 1 +338 274 1 +402 274 1 +19 275 1 +147 275 1 +211 275 1 +243 275 1 +259 275 1 +267 275 1 +271 275 1 +273 275 1 +274 275 1 +275 275 1777 +276 275 1 +277 275 1 +279 275 1 +283 275 1 +291 275 1 +307 275 1 +339 275 1 +403 275 1 +20 276 1 +148 276 1 +212 276 1 +244 276 1 +260 276 1 +268 276 1 +272 276 1 +274 276 1 +275 276 1 +276 276 1783 +277 276 1 +278 276 1 +280 276 1 +284 276 1 +292 276 1 +308 276 1 +340 276 1 +404 276 1 +21 277 1 +149 277 1 +213 277 1 +245 277 1 +261 277 1 +269 277 1 +273 277 1 +275 277 1 +276 277 1 +277 277 1787 +278 277 1 +279 277 1 +281 277 1 +285 277 1 +293 277 1 +309 277 1 +341 277 1 +405 277 1 +22 278 1 +150 278 1 +214 278 1 +246 278 1 +262 278 1 +270 278 1 +274 278 1 +276 278 1 +277 278 1 +278 278 1789 +279 278 1 +280 278 1 +282 278 1 +286 278 1 +294 278 1 +310 278 1 +342 278 1 +406 278 1 +23 279 1 +151 279 1 +215 279 1 +247 279 1 +263 279 1 +271 279 1 +275 279 1 +277 279 1 +278 279 1 +279 279 1801 +280 279 1 +281 279 1 +283 279 1 +287 279 1 +295 279 1 +311 279 1 +343 279 1 +407 279 1 +24 280 1 +152 280 1 +216 280 1 +248 280 1 +264 280 1 +272 280 1 +276 280 1 +278 280 1 +279 280 1 +280 280 1811 +281 280 1 +282 280 1 +284 280 1 +288 280 1 +296 280 1 +312 280 1 +344 280 1 +408 280 1 +25 281 1 +153 281 1 +217 281 1 +249 281 1 +265 281 1 +273 281 1 +277 281 1 +279 281 1 +280 281 1 +281 281 1823 +282 281 1 +283 281 1 +285 281 1 +289 281 1 +297 281 1 +313 281 1 +345 281 1 +409 281 1 +26 282 1 +154 282 1 +218 282 1 +250 282 1 +266 282 1 +274 282 1 +278 282 1 +280 282 1 +281 282 1 +282 282 1831 +283 282 1 +284 282 1 +286 282 1 +290 282 1 +298 282 1 +314 282 1 +346 282 1 +410 282 1 +27 283 1 +155 283 1 +219 283 1 +251 283 1 +267 283 1 +275 283 1 +279 283 1 +281 283 1 +282 283 1 +283 283 1847 +284 283 1 +285 283 1 +287 283 1 +291 283 1 +299 283 1 +315 283 1 +347 283 1 +411 283 1 +28 284 1 +156 284 1 +220 284 1 +252 284 1 +268 284 1 +276 284 1 +280 284 1 +282 284 1 +283 284 1 +284 284 1861 +285 284 1 +286 284 1 +288 284 1 +292 284 1 +300 284 1 +316 284 1 +348 284 1 +412 284 1 +29 285 1 +157 285 1 +221 285 1 +253 285 1 +269 285 1 +277 285 1 +281 285 1 +283 285 1 +284 285 1 +285 285 1867 +286 285 1 +287 285 1 +289 285 1 +293 285 1 +301 285 1 +317 285 1 +349 285 1 +413 285 1 +30 286 1 +158 286 1 +222 286 1 +254 286 1 +270 286 1 +278 286 1 +282 286 1 +284 286 1 +285 286 1 +286 286 1871 +287 286 1 +288 286 1 +290 286 1 +294 286 1 +302 286 1 +318 286 1 +350 286 1 +414 286 1 +31 287 1 +159 287 1 +223 287 1 +255 287 1 +271 287 1 +279 287 1 +283 287 1 +285 287 1 +286 287 1 +287 287 1873 +288 287 1 +289 287 1 +291 287 1 +295 287 1 +303 287 1 +319 287 1 +351 287 1 +415 287 1 +32 288 1 +160 288 1 +224 288 1 +256 288 1 +272 288 1 +280 288 1 +284 288 1 +286 288 1 +287 288 1 +288 288 1877 +289 288 1 +290 288 1 +292 288 1 +296 288 1 +304 288 1 +320 288 1 +352 288 1 +416 288 1 +33 289 1 +161 289 1 +225 289 1 +257 289 1 +273 289 1 +281 289 1 +285 289 1 +287 289 1 +288 289 1 +289 289 1879 +290 289 1 +291 289 1 +293 289 1 +297 289 1 +305 289 1 +321 289 1 +353 289 1 +417 289 1 +34 290 1 +162 290 1 +226 290 1 +258 290 1 +274 290 1 +282 290 1 +286 290 1 +288 290 1 +289 290 1 +290 290 1889 +291 290 1 +292 290 1 +294 290 1 +298 290 1 +306 290 1 +322 290 1 +354 290 1 +418 290 1 +35 291 1 +163 291 1 +227 291 1 +259 291 1 +275 291 1 +283 291 1 +287 291 1 +289 291 1 +290 291 1 +291 291 1901 +292 291 1 +293 291 1 +295 291 1 +299 291 1 +307 291 1 +323 291 1 +355 291 1 +419 291 1 +36 292 1 +164 292 1 +228 292 1 +260 292 1 +276 292 1 +284 292 1 +288 292 1 +290 292 1 +291 292 1 +292 292 1907 +293 292 1 +294 292 1 +296 292 1 +300 292 1 +308 292 1 +324 292 1 +356 292 1 +420 292 1 +37 293 1 +165 293 1 +229 293 1 +261 293 1 +277 293 1 +285 293 1 +289 293 1 +291 293 1 +292 293 1 +293 293 1913 +294 293 1 +295 293 1 +297 293 1 +301 293 1 +309 293 1 +325 293 1 +357 293 1 +421 293 1 +38 294 1 +166 294 1 +230 294 1 +262 294 1 +278 294 1 +286 294 1 +290 294 1 +292 294 1 +293 294 1 +294 294 1931 +295 294 1 +296 294 1 +298 294 1 +302 294 1 +310 294 1 +326 294 1 +358 294 1 +422 294 1 +39 295 1 +167 295 1 +231 295 1 +263 295 1 +279 295 1 +287 295 1 +291 295 1 +293 295 1 +294 295 1 +295 295 1933 +296 295 1 +297 295 1 +299 295 1 +303 295 1 +311 295 1 +327 295 1 +359 295 1 +423 295 1 +40 296 1 +168 296 1 +232 296 1 +264 296 1 +280 296 1 +288 296 1 +292 296 1 +294 296 1 +295 296 1 +296 296 1949 +297 296 1 +298 296 1 +300 296 1 +304 296 1 +312 296 1 +328 296 1 +360 296 1 +424 296 1 +41 297 1 +169 297 1 +233 297 1 +265 297 1 +281 297 1 +289 297 1 +293 297 1 +295 297 1 +296 297 1 +297 297 1951 +298 297 1 +299 297 1 +301 297 1 +305 297 1 +313 297 1 +329 297 1 +361 297 1 +425 297 1 +42 298 1 +170 298 1 +234 298 1 +266 298 1 +282 298 1 +290 298 1 +294 298 1 +296 298 1 +297 298 1 +298 298 1973 +299 298 1 +300 298 1 +302 298 1 +306 298 1 +314 298 1 +330 298 1 +362 298 1 +426 298 1 +43 299 1 +171 299 1 +235 299 1 +267 299 1 +283 299 1 +291 299 1 +295 299 1 +297 299 1 +298 299 1 +299 299 1979 +300 299 1 +301 299 1 +303 299 1 +307 299 1 +315 299 1 +331 299 1 +363 299 1 +427 299 1 +44 300 1 +172 300 1 +236 300 1 +268 300 1 +284 300 1 +292 300 1 +296 300 1 +298 300 1 +299 300 1 +300 300 1987 +301 300 1 +302 300 1 +304 300 1 +308 300 1 +316 300 1 +332 300 1 +364 300 1 +428 300 1 +45 301 1 +173 301 1 +237 301 1 +269 301 1 +285 301 1 +293 301 1 +297 301 1 +299 301 1 +300 301 1 +301 301 1993 +302 301 1 +303 301 1 +305 301 1 +309 301 1 +317 301 1 +333 301 1 +365 301 1 +429 301 1 +46 302 1 +174 302 1 +238 302 1 +270 302 1 +286 302 1 +294 302 1 +298 302 1 +300 302 1 +301 302 1 +302 302 1997 +303 302 1 +304 302 1 +306 302 1 +310 302 1 +318 302 1 +334 302 1 +366 302 1 +430 302 1 +47 303 1 +175 303 1 +239 303 1 +271 303 1 +287 303 1 +295 303 1 +299 303 1 +301 303 1 +302 303 1 +303 303 1999 +304 303 1 +305 303 1 +307 303 1 +311 303 1 +319 303 1 +335 303 1 +367 303 1 +431 303 1 +48 304 1 +176 304 1 +240 304 1 +272 304 1 +288 304 1 +296 304 1 +300 304 1 +302 304 1 +303 304 1 +304 304 2003 +305 304 1 +306 304 1 +308 304 1 +312 304 1 +320 304 1 +336 304 1 +368 304 1 +432 304 1 +49 305 1 +177 305 1 +241 305 1 +273 305 1 +289 305 1 +297 305 1 +301 305 1 +303 305 1 +304 305 1 +305 305 2011 +306 305 1 +307 305 1 +309 305 1 +313 305 1 +321 305 1 +337 305 1 +369 305 1 +433 305 1 +50 306 1 +178 306 1 +242 306 1 +274 306 1 +290 306 1 +298 306 1 +302 306 1 +304 306 1 +305 306 1 +306 306 2017 +307 306 1 +308 306 1 +310 306 1 +314 306 1 +322 306 1 +338 306 1 +370 306 1 +434 306 1 +51 307 1 +179 307 1 +243 307 1 +275 307 1 +291 307 1 +299 307 1 +303 307 1 +305 307 1 +306 307 1 +307 307 2027 +308 307 1 +309 307 1 +311 307 1 +315 307 1 +323 307 1 +339 307 1 +371 307 1 +435 307 1 +52 308 1 +180 308 1 +244 308 1 +276 308 1 +292 308 1 +300 308 1 +304 308 1 +306 308 1 +307 308 1 +308 308 2029 +309 308 1 +310 308 1 +312 308 1 +316 308 1 +324 308 1 +340 308 1 +372 308 1 +436 308 1 +53 309 1 +181 309 1 +245 309 1 +277 309 1 +293 309 1 +301 309 1 +305 309 1 +307 309 1 +308 309 1 +309 309 2039 +310 309 1 +311 309 1 +313 309 1 +317 309 1 +325 309 1 +341 309 1 +373 309 1 +437 309 1 +54 310 1 +182 310 1 +246 310 1 +278 310 1 +294 310 1 +302 310 1 +306 310 1 +308 310 1 +309 310 1 +310 310 2053 +311 310 1 +312 310 1 +314 310 1 +318 310 1 +326 310 1 +342 310 1 +374 310 1 +438 310 1 +55 311 1 +183 311 1 +247 311 1 +279 311 1 +295 311 1 +303 311 1 +307 311 1 +309 311 1 +310 311 1 +311 311 2063 +312 311 1 +313 311 1 +315 311 1 +319 311 1 +327 311 1 +343 311 1 +375 311 1 +439 311 1 +56 312 1 +184 312 1 +248 312 1 +280 312 1 +296 312 1 +304 312 1 +308 312 1 +310 312 1 +311 312 1 +312 312 2069 +313 312 1 +314 312 1 +316 312 1 +320 312 1 +328 312 1 +344 312 1 +376 312 1 +440 312 1 +57 313 1 +185 313 1 +249 313 1 +281 313 1 +297 313 1 +305 313 1 +309 313 1 +311 313 1 +312 313 1 +313 313 2081 +314 313 1 +315 313 1 +317 313 1 +321 313 1 +329 313 1 +345 313 1 +377 313 1 +441 313 1 +58 314 1 +186 314 1 +250 314 1 +282 314 1 +298 314 1 +306 314 1 +310 314 1 +312 314 1 +313 314 1 +314 314 2083 +315 314 1 +316 314 1 +318 314 1 +322 314 1 +330 314 1 +346 314 1 +378 314 1 +442 314 1 +59 315 1 +187 315 1 +251 315 1 +283 315 1 +299 315 1 +307 315 1 +311 315 1 +313 315 1 +314 315 1 +315 315 2087 +316 315 1 +317 315 1 +319 315 1 +323 315 1 +331 315 1 +347 315 1 +379 315 1 +443 315 1 +60 316 1 +188 316 1 +252 316 1 +284 316 1 +300 316 1 +308 316 1 +312 316 1 +314 316 1 +315 316 1 +316 316 2089 +317 316 1 +318 316 1 +320 316 1 +324 316 1 +332 316 1 +348 316 1 +380 316 1 +444 316 1 +61 317 1 +189 317 1 +253 317 1 +285 317 1 +301 317 1 +309 317 1 +313 317 1 +315 317 1 +316 317 1 +317 317 2099 +318 317 1 +319 317 1 +321 317 1 +325 317 1 +333 317 1 +349 317 1 +381 317 1 +445 317 1 +62 318 1 +190 318 1 +254 318 1 +286 318 1 +302 318 1 +310 318 1 +314 318 1 +316 318 1 +317 318 1 +318 318 2111 +319 318 1 +320 318 1 +322 318 1 +326 318 1 +334 318 1 +350 318 1 +382 318 1 +446 318 1 +63 319 1 +191 319 1 +255 319 1 +287 319 1 +303 319 1 +311 319 1 +315 319 1 +317 319 1 +318 319 1 +319 319 2113 +320 319 1 +321 319 1 +323 319 1 +327 319 1 +335 319 1 +351 319 1 +383 319 1 +447 319 1 +64 320 1 +192 320 1 +256 320 1 +288 320 1 +304 320 1 +312 320 1 +316 320 1 +318 320 1 +319 320 1 +320 320 2129 +321 320 1 +322 320 1 +324 320 1 +328 320 1 +336 320 1 +352 320 1 +384 320 1 +448 320 1 +65 321 1 +193 321 1 +257 321 1 +289 321 1 +305 321 1 +313 321 1 +317 321 1 +319 321 1 +320 321 1 +321 321 2131 +322 321 1 +323 321 1 +325 321 1 +329 321 1 +337 321 1 +353 321 1 +385 321 1 +449 321 1 +66 322 1 +194 322 1 +258 322 1 +290 322 1 +306 322 1 +314 322 1 +318 322 1 +320 322 1 +321 322 1 +322 322 2137 +323 322 1 +324 322 1 +326 322 1 +330 322 1 +338 322 1 +354 322 1 +386 322 1 +450 322 1 +67 323 1 +195 323 1 +259 323 1 +291 323 1 +307 323 1 +315 323 1 +319 323 1 +321 323 1 +322 323 1 +323 323 2141 +324 323 1 +325 323 1 +327 323 1 +331 323 1 +339 323 1 +355 323 1 +387 323 1 +451 323 1 +68 324 1 +196 324 1 +260 324 1 +292 324 1 +308 324 1 +316 324 1 +320 324 1 +322 324 1 +323 324 1 +324 324 2143 +325 324 1 +326 324 1 +328 324 1 +332 324 1 +340 324 1 +356 324 1 +388 324 1 +452 324 1 +69 325 1 +197 325 1 +261 325 1 +293 325 1 +309 325 1 +317 325 1 +321 325 1 +323 325 1 +324 325 1 +325 325 2153 +326 325 1 +327 325 1 +329 325 1 +333 325 1 +341 325 1 +357 325 1 +389 325 1 +453 325 1 +70 326 1 +198 326 1 +262 326 1 +294 326 1 +310 326 1 +318 326 1 +322 326 1 +324 326 1 +325 326 1 +326 326 2161 +327 326 1 +328 326 1 +330 326 1 +334 326 1 +342 326 1 +358 326 1 +390 326 1 +454 326 1 +71 327 1 +199 327 1 +263 327 1 +295 327 1 +311 327 1 +319 327 1 +323 327 1 +325 327 1 +326 327 1 +327 327 2179 +328 327 1 +329 327 1 +331 327 1 +335 327 1 +343 327 1 +359 327 1 +391 327 1 +455 327 1 +72 328 1 +200 328 1 +264 328 1 +296 328 1 +312 328 1 +320 328 1 +324 328 1 +326 328 1 +327 328 1 +328 328 2203 +329 328 1 +330 328 1 +332 328 1 +336 328 1 +344 328 1 +360 328 1 +392 328 1 +456 328 1 +73 329 1 +201 329 1 +265 329 1 +297 329 1 +313 329 1 +321 329 1 +325 329 1 +327 329 1 +328 329 1 +329 329 2207 +330 329 1 +331 329 1 +333 329 1 +337 329 1 +345 329 1 +361 329 1 +393 329 1 +457 329 1 +74 330 1 +202 330 1 +266 330 1 +298 330 1 +314 330 1 +322 330 1 +326 330 1 +328 330 1 +329 330 1 +330 330 2213 +331 330 1 +332 330 1 +334 330 1 +338 330 1 +346 330 1 +362 330 1 +394 330 1 +458 330 1 +75 331 1 +203 331 1 +267 331 1 +299 331 1 +315 331 1 +323 331 1 +327 331 1 +329 331 1 +330 331 1 +331 331 2221 +332 331 1 +333 331 1 +335 331 1 +339 331 1 +347 331 1 +363 331 1 +395 331 1 +459 331 1 +76 332 1 +204 332 1 +268 332 1 +300 332 1 +316 332 1 +324 332 1 +328 332 1 +330 332 1 +331 332 1 +332 332 2237 +333 332 1 +334 332 1 +336 332 1 +340 332 1 +348 332 1 +364 332 1 +396 332 1 +460 332 1 +77 333 1 +205 333 1 +269 333 1 +301 333 1 +317 333 1 +325 333 1 +329 333 1 +331 333 1 +332 333 1 +333 333 2239 +334 333 1 +335 333 1 +337 333 1 +341 333 1 +349 333 1 +365 333 1 +397 333 1 +461 333 1 +78 334 1 +206 334 1 +270 334 1 +302 334 1 +318 334 1 +326 334 1 +330 334 1 +332 334 1 +333 334 1 +334 334 2243 +335 334 1 +336 334 1 +338 334 1 +342 334 1 +350 334 1 +366 334 1 +398 334 1 +462 334 1 +79 335 1 +207 335 1 +271 335 1 +303 335 1 +319 335 1 +327 335 1 +331 335 1 +333 335 1 +334 335 1 +335 335 2251 +336 335 1 +337 335 1 +339 335 1 +343 335 1 +351 335 1 +367 335 1 +399 335 1 +463 335 1 +80 336 1 +208 336 1 +272 336 1 +304 336 1 +320 336 1 +328 336 1 +332 336 1 +334 336 1 +335 336 1 +336 336 2267 +337 336 1 +338 336 1 +340 336 1 +344 336 1 +352 336 1 +368 336 1 +400 336 1 +464 336 1 +81 337 1 +209 337 1 +273 337 1 +305 337 1 +321 337 1 +329 337 1 +333 337 1 +335 337 1 +336 337 1 +337 337 2269 +338 337 1 +339 337 1 +341 337 1 +345 337 1 +353 337 1 +369 337 1 +401 337 1 +465 337 1 +82 338 1 +210 338 1 +274 338 1 +306 338 1 +322 338 1 +330 338 1 +334 338 1 +336 338 1 +337 338 1 +338 338 2273 +339 338 1 +340 338 1 +342 338 1 +346 338 1 +354 338 1 +370 338 1 +402 338 1 +466 338 1 +83 339 1 +211 339 1 +275 339 1 +307 339 1 +323 339 1 +331 339 1 +335 339 1 +337 339 1 +338 339 1 +339 339 2281 +340 339 1 +341 339 1 +343 339 1 +347 339 1 +355 339 1 +371 339 1 +403 339 1 +467 339 1 +84 340 1 +212 340 1 +276 340 1 +308 340 1 +324 340 1 +332 340 1 +336 340 1 +338 340 1 +339 340 1 +340 340 2287 +341 340 1 +342 340 1 +344 340 1 +348 340 1 +356 340 1 +372 340 1 +404 340 1 +468 340 1 +85 341 1 +213 341 1 +277 341 1 +309 341 1 +325 341 1 +333 341 1 +337 341 1 +339 341 1 +340 341 1 +341 341 2293 +342 341 1 +343 341 1 +345 341 1 +349 341 1 +357 341 1 +373 341 1 +405 341 1 +469 341 1 +86 342 1 +214 342 1 +278 342 1 +310 342 1 +326 342 1 +334 342 1 +338 342 1 +340 342 1 +341 342 1 +342 342 2297 +343 342 1 +344 342 1 +346 342 1 +350 342 1 +358 342 1 +374 342 1 +406 342 1 +470 342 1 +87 343 1 +215 343 1 +279 343 1 +311 343 1 +327 343 1 +335 343 1 +339 343 1 +341 343 1 +342 343 1 +343 343 2309 +344 343 1 +345 343 1 +347 343 1 +351 343 1 +359 343 1 +375 343 1 +407 343 1 +471 343 1 +88 344 1 +216 344 1 +280 344 1 +312 344 1 +328 344 1 +336 344 1 +340 344 1 +342 344 1 +343 344 1 +344 344 2311 +345 344 1 +346 344 1 +348 344 1 +352 344 1 +360 344 1 +376 344 1 +408 344 1 +472 344 1 +89 345 1 +217 345 1 +281 345 1 +313 345 1 +329 345 1 +337 345 1 +341 345 1 +343 345 1 +344 345 1 +345 345 2333 +346 345 1 +347 345 1 +349 345 1 +353 345 1 +361 345 1 +377 345 1 +409 345 1 +473 345 1 +90 346 1 +218 346 1 +282 346 1 +314 346 1 +330 346 1 +338 346 1 +342 346 1 +344 346 1 +345 346 1 +346 346 2339 +347 346 1 +348 346 1 +350 346 1 +354 346 1 +362 346 1 +378 346 1 +410 346 1 +474 346 1 +91 347 1 +219 347 1 +283 347 1 +315 347 1 +331 347 1 +339 347 1 +343 347 1 +345 347 1 +346 347 1 +347 347 2341 +348 347 1 +349 347 1 +351 347 1 +355 347 1 +363 347 1 +379 347 1 +411 347 1 +475 347 1 +92 348 1 +220 348 1 +284 348 1 +316 348 1 +332 348 1 +340 348 1 +344 348 1 +346 348 1 +347 348 1 +348 348 2347 +349 348 1 +350 348 1 +352 348 1 +356 348 1 +364 348 1 +380 348 1 +412 348 1 +476 348 1 +93 349 1 +221 349 1 +285 349 1 +317 349 1 +333 349 1 +341 349 1 +345 349 1 +347 349 1 +348 349 1 +349 349 2351 +350 349 1 +351 349 1 +353 349 1 +357 349 1 +365 349 1 +381 349 1 +413 349 1 +477 349 1 +94 350 1 +222 350 1 +286 350 1 +318 350 1 +334 350 1 +342 350 1 +346 350 1 +348 350 1 +349 350 1 +350 350 2357 +351 350 1 +352 350 1 +354 350 1 +358 350 1 +366 350 1 +382 350 1 +414 350 1 +478 350 1 +95 351 1 +223 351 1 +287 351 1 +319 351 1 +335 351 1 +343 351 1 +347 351 1 +349 351 1 +350 351 1 +351 351 2371 +352 351 1 +353 351 1 +355 351 1 +359 351 1 +367 351 1 +383 351 1 +415 351 1 +479 351 1 +96 352 1 +224 352 1 +288 352 1 +320 352 1 +336 352 1 +344 352 1 +348 352 1 +350 352 1 +351 352 1 +352 352 2377 +353 352 1 +354 352 1 +356 352 1 +360 352 1 +368 352 1 +384 352 1 +416 352 1 +480 352 1 +97 353 1 +225 353 1 +289 353 1 +321 353 1 +337 353 1 +345 353 1 +349 353 1 +351 353 1 +352 353 1 +353 353 2381 +354 353 1 +355 353 1 +357 353 1 +361 353 1 +369 353 1 +385 353 1 +417 353 1 +481 353 1 +98 354 1 +226 354 1 +290 354 1 +322 354 1 +338 354 1 +346 354 1 +350 354 1 +352 354 1 +353 354 1 +354 354 2383 +355 354 1 +356 354 1 +358 354 1 +362 354 1 +370 354 1 +386 354 1 +418 354 1 +482 354 1 +99 355 1 +227 355 1 +291 355 1 +323 355 1 +339 355 1 +347 355 1 +351 355 1 +353 355 1 +354 355 1 +355 355 2389 +356 355 1 +357 355 1 +359 355 1 +363 355 1 +371 355 1 +387 355 1 +419 355 1 +483 355 1 +100 356 1 +228 356 1 +292 356 1 +324 356 1 +340 356 1 +348 356 1 +352 356 1 +354 356 1 +355 356 1 +356 356 2393 +357 356 1 +358 356 1 +360 356 1 +364 356 1 +372 356 1 +388 356 1 +420 356 1 +484 356 1 +101 357 1 +229 357 1 +293 357 1 +325 357 1 +341 357 1 +349 357 1 +353 357 1 +355 357 1 +356 357 1 +357 357 2399 +358 357 1 +359 357 1 +361 357 1 +365 357 1 +373 357 1 +389 357 1 +421 357 1 +485 357 1 +102 358 1 +230 358 1 +294 358 1 +326 358 1 +342 358 1 +350 358 1 +354 358 1 +356 358 1 +357 358 1 +358 358 2411 +359 358 1 +360 358 1 +362 358 1 +366 358 1 +374 358 1 +390 358 1 +422 358 1 +486 358 1 +103 359 1 +231 359 1 +295 359 1 +327 359 1 +343 359 1 +351 359 1 +355 359 1 +357 359 1 +358 359 1 +359 359 2417 +360 359 1 +361 359 1 +363 359 1 +367 359 1 +375 359 1 +391 359 1 +423 359 1 +487 359 1 +104 360 1 +232 360 1 +296 360 1 +328 360 1 +344 360 1 +352 360 1 +356 360 1 +358 360 1 +359 360 1 +360 360 2423 +361 360 1 +362 360 1 +364 360 1 +368 360 1 +376 360 1 +392 360 1 +424 360 1 +488 360 1 +105 361 1 +233 361 1 +297 361 1 +329 361 1 +345 361 1 +353 361 1 +357 361 1 +359 361 1 +360 361 1 +361 361 2437 +362 361 1 +363 361 1 +365 361 1 +369 361 1 +377 361 1 +393 361 1 +425 361 1 +489 361 1 +106 362 1 +234 362 1 +298 362 1 +330 362 1 +346 362 1 +354 362 1 +358 362 1 +360 362 1 +361 362 1 +362 362 2441 +363 362 1 +364 362 1 +366 362 1 +370 362 1 +378 362 1 +394 362 1 +426 362 1 +490 362 1 +107 363 1 +235 363 1 +299 363 1 +331 363 1 +347 363 1 +355 363 1 +359 363 1 +361 363 1 +362 363 1 +363 363 2447 +364 363 1 +365 363 1 +367 363 1 +371 363 1 +379 363 1 +395 363 1 +427 363 1 +491 363 1 +108 364 1 +236 364 1 +300 364 1 +332 364 1 +348 364 1 +356 364 1 +360 364 1 +362 364 1 +363 364 1 +364 364 2459 +365 364 1 +366 364 1 +368 364 1 +372 364 1 +380 364 1 +396 364 1 +428 364 1 +492 364 1 +109 365 1 +237 365 1 +301 365 1 +333 365 1 +349 365 1 +357 365 1 +361 365 1 +363 365 1 +364 365 1 +365 365 2467 +366 365 1 +367 365 1 +369 365 1 +373 365 1 +381 365 1 +397 365 1 +429 365 1 +493 365 1 +110 366 1 +238 366 1 +302 366 1 +334 366 1 +350 366 1 +358 366 1 +362 366 1 +364 366 1 +365 366 1 +366 366 2473 +367 366 1 +368 366 1 +370 366 1 +374 366 1 +382 366 1 +398 366 1 +430 366 1 +494 366 1 +111 367 1 +239 367 1 +303 367 1 +335 367 1 +351 367 1 +359 367 1 +363 367 1 +365 367 1 +366 367 1 +367 367 2477 +368 367 1 +369 367 1 +371 367 1 +375 367 1 +383 367 1 +399 367 1 +431 367 1 +495 367 1 +112 368 1 +240 368 1 +304 368 1 +336 368 1 +352 368 1 +360 368 1 +364 368 1 +366 368 1 +367 368 1 +368 368 2503 +369 368 1 +370 368 1 +372 368 1 +376 368 1 +384 368 1 +400 368 1 +432 368 1 +496 368 1 +113 369 1 +241 369 1 +305 369 1 +337 369 1 +353 369 1 +361 369 1 +365 369 1 +367 369 1 +368 369 1 +369 369 2521 +370 369 1 +371 369 1 +373 369 1 +377 369 1 +385 369 1 +401 369 1 +433 369 1 +497 369 1 +114 370 1 +242 370 1 +306 370 1 +338 370 1 +354 370 1 +362 370 1 +366 370 1 +368 370 1 +369 370 1 +370 370 2531 +371 370 1 +372 370 1 +374 370 1 +378 370 1 +386 370 1 +402 370 1 +434 370 1 +498 370 1 +115 371 1 +243 371 1 +307 371 1 +339 371 1 +355 371 1 +363 371 1 +367 371 1 +369 371 1 +370 371 1 +371 371 2539 +372 371 1 +373 371 1 +375 371 1 +379 371 1 +387 371 1 +403 371 1 +435 371 1 +499 371 1 +116 372 1 +244 372 1 +308 372 1 +340 372 1 +356 372 1 +364 372 1 +368 372 1 +370 372 1 +371 372 1 +372 372 2543 +373 372 1 +374 372 1 +376 372 1 +380 372 1 +388 372 1 +404 372 1 +436 372 1 +500 372 1 +117 373 1 +245 373 1 +309 373 1 +341 373 1 +357 373 1 +365 373 1 +369 373 1 +371 373 1 +372 373 1 +373 373 2549 +374 373 1 +375 373 1 +377 373 1 +381 373 1 +389 373 1 +405 373 1 +437 373 1 +118 374 1 +246 374 1 +310 374 1 +342 374 1 +358 374 1 +366 374 1 +370 374 1 +372 374 1 +373 374 1 +374 374 2551 +375 374 1 +376 374 1 +378 374 1 +382 374 1 +390 374 1 +406 374 1 +438 374 1 +119 375 1 +247 375 1 +311 375 1 +343 375 1 +359 375 1 +367 375 1 +371 375 1 +373 375 1 +374 375 1 +375 375 2557 +376 375 1 +377 375 1 +379 375 1 +383 375 1 +391 375 1 +407 375 1 +439 375 1 +120 376 1 +248 376 1 +312 376 1 +344 376 1 +360 376 1 +368 376 1 +372 376 1 +374 376 1 +375 376 1 +376 376 2579 +377 376 1 +378 376 1 +380 376 1 +384 376 1 +392 376 1 +408 376 1 +440 376 1 +121 377 1 +249 377 1 +313 377 1 +345 377 1 +361 377 1 +369 377 1 +373 377 1 +375 377 1 +376 377 1 +377 377 2591 +378 377 1 +379 377 1 +381 377 1 +385 377 1 +393 377 1 +409 377 1 +441 377 1 +122 378 1 +250 378 1 +314 378 1 +346 378 1 +362 378 1 +370 378 1 +374 378 1 +376 378 1 +377 378 1 +378 378 2593 +379 378 1 +380 378 1 +382 378 1 +386 378 1 +394 378 1 +410 378 1 +442 378 1 +123 379 1 +251 379 1 +315 379 1 +347 379 1 +363 379 1 +371 379 1 +375 379 1 +377 379 1 +378 379 1 +379 379 2609 +380 379 1 +381 379 1 +383 379 1 +387 379 1 +395 379 1 +411 379 1 +443 379 1 +124 380 1 +252 380 1 +316 380 1 +348 380 1 +364 380 1 +372 380 1 +376 380 1 +378 380 1 +379 380 1 +380 380 2617 +381 380 1 +382 380 1 +384 380 1 +388 380 1 +396 380 1 +412 380 1 +444 380 1 +125 381 1 +253 381 1 +317 381 1 +349 381 1 +365 381 1 +373 381 1 +377 381 1 +379 381 1 +380 381 1 +381 381 2621 +382 381 1 +383 381 1 +385 381 1 +389 381 1 +397 381 1 +413 381 1 +445 381 1 +126 382 1 +254 382 1 +318 382 1 +350 382 1 +366 382 1 +374 382 1 +378 382 1 +380 382 1 +381 382 1 +382 382 2633 +383 382 1 +384 382 1 +386 382 1 +390 382 1 +398 382 1 +414 382 1 +446 382 1 +127 383 1 +255 383 1 +319 383 1 +351 383 1 +367 383 1 +375 383 1 +379 383 1 +381 383 1 +382 383 1 +383 383 2647 +384 383 1 +385 383 1 +387 383 1 +391 383 1 +399 383 1 +415 383 1 +447 383 1 +128 384 1 +256 384 1 +320 384 1 +352 384 1 +368 384 1 +376 384 1 +380 384 1 +382 384 1 +383 384 1 +384 384 2657 +385 384 1 +386 384 1 +388 384 1 +392 384 1 +400 384 1 +416 384 1 +448 384 1 +129 385 1 +257 385 1 +321 385 1 +353 385 1 +369 385 1 +377 385 1 +381 385 1 +383 385 1 +384 385 1 +385 385 2659 +386 385 1 +387 385 1 +389 385 1 +393 385 1 +401 385 1 +417 385 1 +449 385 1 +130 386 1 +258 386 1 +322 386 1 +354 386 1 +370 386 1 +378 386 1 +382 386 1 +384 386 1 +385 386 1 +386 386 2663 +387 386 1 +388 386 1 +390 386 1 +394 386 1 +402 386 1 +418 386 1 +450 386 1 +131 387 1 +259 387 1 +323 387 1 +355 387 1 +371 387 1 +379 387 1 +383 387 1 +385 387 1 +386 387 1 +387 387 2671 +388 387 1 +389 387 1 +391 387 1 +395 387 1 +403 387 1 +419 387 1 +451 387 1 +132 388 1 +260 388 1 +324 388 1 +356 388 1 +372 388 1 +380 388 1 +384 388 1 +386 388 1 +387 388 1 +388 388 2677 +389 388 1 +390 388 1 +392 388 1 +396 388 1 +404 388 1 +420 388 1 +452 388 1 +133 389 1 +261 389 1 +325 389 1 +357 389 1 +373 389 1 +381 389 1 +385 389 1 +387 389 1 +388 389 1 +389 389 2683 +390 389 1 +391 389 1 +393 389 1 +397 389 1 +405 389 1 +421 389 1 +453 389 1 +134 390 1 +262 390 1 +326 390 1 +358 390 1 +374 390 1 +382 390 1 +386 390 1 +388 390 1 +389 390 1 +390 390 2687 +391 390 1 +392 390 1 +394 390 1 +398 390 1 +406 390 1 +422 390 1 +454 390 1 +135 391 1 +263 391 1 +327 391 1 +359 391 1 +375 391 1 +383 391 1 +387 391 1 +389 391 1 +390 391 1 +391 391 2689 +392 391 1 +393 391 1 +395 391 1 +399 391 1 +407 391 1 +423 391 1 +455 391 1 +136 392 1 +264 392 1 +328 392 1 +360 392 1 +376 392 1 +384 392 1 +388 392 1 +390 392 1 +391 392 1 +392 392 2693 +393 392 1 +394 392 1 +396 392 1 +400 392 1 +408 392 1 +424 392 1 +456 392 1 +137 393 1 +265 393 1 +329 393 1 +361 393 1 +377 393 1 +385 393 1 +389 393 1 +391 393 1 +392 393 1 +393 393 2699 +394 393 1 +395 393 1 +397 393 1 +401 393 1 +409 393 1 +425 393 1 +457 393 1 +138 394 1 +266 394 1 +330 394 1 +362 394 1 +378 394 1 +386 394 1 +390 394 1 +392 394 1 +393 394 1 +394 394 2707 +395 394 1 +396 394 1 +398 394 1 +402 394 1 +410 394 1 +426 394 1 +458 394 1 +139 395 1 +267 395 1 +331 395 1 +363 395 1 +379 395 1 +387 395 1 +391 395 1 +393 395 1 +394 395 1 +395 395 2711 +396 395 1 +397 395 1 +399 395 1 +403 395 1 +411 395 1 +427 395 1 +459 395 1 +140 396 1 +268 396 1 +332 396 1 +364 396 1 +380 396 1 +388 396 1 +392 396 1 +394 396 1 +395 396 1 +396 396 2713 +397 396 1 +398 396 1 +400 396 1 +404 396 1 +412 396 1 +428 396 1 +460 396 1 +141 397 1 +269 397 1 +333 397 1 +365 397 1 +381 397 1 +389 397 1 +393 397 1 +395 397 1 +396 397 1 +397 397 2719 +398 397 1 +399 397 1 +401 397 1 +405 397 1 +413 397 1 +429 397 1 +461 397 1 +142 398 1 +270 398 1 +334 398 1 +366 398 1 +382 398 1 +390 398 1 +394 398 1 +396 398 1 +397 398 1 +398 398 2729 +399 398 1 +400 398 1 +402 398 1 +406 398 1 +414 398 1 +430 398 1 +462 398 1 +143 399 1 +271 399 1 +335 399 1 +367 399 1 +383 399 1 +391 399 1 +395 399 1 +397 399 1 +398 399 1 +399 399 2731 +400 399 1 +401 399 1 +403 399 1 +407 399 1 +415 399 1 +431 399 1 +463 399 1 +144 400 1 +272 400 1 +336 400 1 +368 400 1 +384 400 1 +392 400 1 +396 400 1 +398 400 1 +399 400 1 +400 400 2741 +401 400 1 +402 400 1 +404 400 1 +408 400 1 +416 400 1 +432 400 1 +464 400 1 +145 401 1 +273 401 1 +337 401 1 +369 401 1 +385 401 1 +393 401 1 +397 401 1 +399 401 1 +400 401 1 +401 401 2749 +402 401 1 +403 401 1 +405 401 1 +409 401 1 +417 401 1 +433 401 1 +465 401 1 +146 402 1 +274 402 1 +338 402 1 +370 402 1 +386 402 1 +394 402 1 +398 402 1 +400 402 1 +401 402 1 +402 402 2753 +403 402 1 +404 402 1 +406 402 1 +410 402 1 +418 402 1 +434 402 1 +466 402 1 +147 403 1 +275 403 1 +339 403 1 +371 403 1 +387 403 1 +395 403 1 +399 403 1 +401 403 1 +402 403 1 +403 403 2767 +404 403 1 +405 403 1 +407 403 1 +411 403 1 +419 403 1 +435 403 1 +467 403 1 +148 404 1 +276 404 1 +340 404 1 +372 404 1 +388 404 1 +396 404 1 +400 404 1 +402 404 1 +403 404 1 +404 404 2777 +405 404 1 +406 404 1 +408 404 1 +412 404 1 +420 404 1 +436 404 1 +468 404 1 +149 405 1 +277 405 1 +341 405 1 +373 405 1 +389 405 1 +397 405 1 +401 405 1 +403 405 1 +404 405 1 +405 405 2789 +406 405 1 +407 405 1 +409 405 1 +413 405 1 +421 405 1 +437 405 1 +469 405 1 +150 406 1 +278 406 1 +342 406 1 +374 406 1 +390 406 1 +398 406 1 +402 406 1 +404 406 1 +405 406 1 +406 406 2791 +407 406 1 +408 406 1 +410 406 1 +414 406 1 +422 406 1 +438 406 1 +470 406 1 +151 407 1 +279 407 1 +343 407 1 +375 407 1 +391 407 1 +399 407 1 +403 407 1 +405 407 1 +406 407 1 +407 407 2797 +408 407 1 +409 407 1 +411 407 1 +415 407 1 +423 407 1 +439 407 1 +471 407 1 +152 408 1 +280 408 1 +344 408 1 +376 408 1 +392 408 1 +400 408 1 +404 408 1 +406 408 1 +407 408 1 +408 408 2801 +409 408 1 +410 408 1 +412 408 1 +416 408 1 +424 408 1 +440 408 1 +472 408 1 +153 409 1 +281 409 1 +345 409 1 +377 409 1 +393 409 1 +401 409 1 +405 409 1 +407 409 1 +408 409 1 +409 409 2803 +410 409 1 +411 409 1 +413 409 1 +417 409 1 +425 409 1 +441 409 1 +473 409 1 +154 410 1 +282 410 1 +346 410 1 +378 410 1 +394 410 1 +402 410 1 +406 410 1 +408 410 1 +409 410 1 +410 410 2819 +411 410 1 +412 410 1 +414 410 1 +418 410 1 +426 410 1 +442 410 1 +474 410 1 +155 411 1 +283 411 1 +347 411 1 +379 411 1 +395 411 1 +403 411 1 +407 411 1 +409 411 1 +410 411 1 +411 411 2833 +412 411 1 +413 411 1 +415 411 1 +419 411 1 +427 411 1 +443 411 1 +475 411 1 +156 412 1 +284 412 1 +348 412 1 +380 412 1 +396 412 1 +404 412 1 +408 412 1 +410 412 1 +411 412 1 +412 412 2837 +413 412 1 +414 412 1 +416 412 1 +420 412 1 +428 412 1 +444 412 1 +476 412 1 +157 413 1 +285 413 1 +349 413 1 +381 413 1 +397 413 1 +405 413 1 +409 413 1 +411 413 1 +412 413 1 +413 413 2843 +414 413 1 +415 413 1 +417 413 1 +421 413 1 +429 413 1 +445 413 1 +477 413 1 +158 414 1 +286 414 1 +350 414 1 +382 414 1 +398 414 1 +406 414 1 +410 414 1 +412 414 1 +413 414 1 +414 414 2851 +415 414 1 +416 414 1 +418 414 1 +422 414 1 +430 414 1 +446 414 1 +478 414 1 +159 415 1 +287 415 1 +351 415 1 +383 415 1 +399 415 1 +407 415 1 +411 415 1 +413 415 1 +414 415 1 +415 415 2857 +416 415 1 +417 415 1 +419 415 1 +423 415 1 +431 415 1 +447 415 1 +479 415 1 +160 416 1 +288 416 1 +352 416 1 +384 416 1 +400 416 1 +408 416 1 +412 416 1 +414 416 1 +415 416 1 +416 416 2861 +417 416 1 +418 416 1 +420 416 1 +424 416 1 +432 416 1 +448 416 1 +480 416 1 +161 417 1 +289 417 1 +353 417 1 +385 417 1 +401 417 1 +409 417 1 +413 417 1 +415 417 1 +416 417 1 +417 417 2879 +418 417 1 +419 417 1 +421 417 1 +425 417 1 +433 417 1 +449 417 1 +481 417 1 +162 418 1 +290 418 1 +354 418 1 +386 418 1 +402 418 1 +410 418 1 +414 418 1 +416 418 1 +417 418 1 +418 418 2887 +419 418 1 +420 418 1 +422 418 1 +426 418 1 +434 418 1 +450 418 1 +482 418 1 +163 419 1 +291 419 1 +355 419 1 +387 419 1 +403 419 1 +411 419 1 +415 419 1 +417 419 1 +418 419 1 +419 419 2897 +420 419 1 +421 419 1 +423 419 1 +427 419 1 +435 419 1 +451 419 1 +483 419 1 +164 420 1 +292 420 1 +356 420 1 +388 420 1 +404 420 1 +412 420 1 +416 420 1 +418 420 1 +419 420 1 +420 420 2903 +421 420 1 +422 420 1 +424 420 1 +428 420 1 +436 420 1 +452 420 1 +484 420 1 +165 421 1 +293 421 1 +357 421 1 +389 421 1 +405 421 1 +413 421 1 +417 421 1 +419 421 1 +420 421 1 +421 421 2909 +422 421 1 +423 421 1 +425 421 1 +429 421 1 +437 421 1 +453 421 1 +485 421 1 +166 422 1 +294 422 1 +358 422 1 +390 422 1 +406 422 1 +414 422 1 +418 422 1 +420 422 1 +421 422 1 +422 422 2917 +423 422 1 +424 422 1 +426 422 1 +430 422 1 +438 422 1 +454 422 1 +486 422 1 +167 423 1 +295 423 1 +359 423 1 +391 423 1 +407 423 1 +415 423 1 +419 423 1 +421 423 1 +422 423 1 +423 423 2927 +424 423 1 +425 423 1 +427 423 1 +431 423 1 +439 423 1 +455 423 1 +487 423 1 +168 424 1 +296 424 1 +360 424 1 +392 424 1 +408 424 1 +416 424 1 +420 424 1 +422 424 1 +423 424 1 +424 424 2939 +425 424 1 +426 424 1 +428 424 1 +432 424 1 +440 424 1 +456 424 1 +488 424 1 +169 425 1 +297 425 1 +361 425 1 +393 425 1 +409 425 1 +417 425 1 +421 425 1 +423 425 1 +424 425 1 +425 425 2953 +426 425 1 +427 425 1 +429 425 1 +433 425 1 +441 425 1 +457 425 1 +489 425 1 +170 426 1 +298 426 1 +362 426 1 +394 426 1 +410 426 1 +418 426 1 +422 426 1 +424 426 1 +425 426 1 +426 426 2957 +427 426 1 +428 426 1 +430 426 1 +434 426 1 +442 426 1 +458 426 1 +490 426 1 +171 427 1 +299 427 1 +363 427 1 +395 427 1 +411 427 1 +419 427 1 +423 427 1 +425 427 1 +426 427 1 +427 427 2963 +428 427 1 +429 427 1 +431 427 1 +435 427 1 +443 427 1 +459 427 1 +491 427 1 +172 428 1 +300 428 1 +364 428 1 +396 428 1 +412 428 1 +420 428 1 +424 428 1 +426 428 1 +427 428 1 +428 428 2969 +429 428 1 +430 428 1 +432 428 1 +436 428 1 +444 428 1 +460 428 1 +492 428 1 +173 429 1 +301 429 1 +365 429 1 +397 429 1 +413 429 1 +421 429 1 +425 429 1 +427 429 1 +428 429 1 +429 429 2971 +430 429 1 +431 429 1 +433 429 1 +437 429 1 +445 429 1 +461 429 1 +493 429 1 +174 430 1 +302 430 1 +366 430 1 +398 430 1 +414 430 1 +422 430 1 +426 430 1 +428 430 1 +429 430 1 +430 430 2999 +431 430 1 +432 430 1 +434 430 1 +438 430 1 +446 430 1 +462 430 1 +494 430 1 +175 431 1 +303 431 1 +367 431 1 +399 431 1 +415 431 1 +423 431 1 +427 431 1 +429 431 1 +430 431 1 +431 431 3001 +432 431 1 +433 431 1 +435 431 1 +439 431 1 +447 431 1 +463 431 1 +495 431 1 +176 432 1 +304 432 1 +368 432 1 +400 432 1 +416 432 1 +424 432 1 +428 432 1 +430 432 1 +431 432 1 +432 432 3011 +433 432 1 +434 432 1 +436 432 1 +440 432 1 +448 432 1 +464 432 1 +496 432 1 +177 433 1 +305 433 1 +369 433 1 +401 433 1 +417 433 1 +425 433 1 +429 433 1 +431 433 1 +432 433 1 +433 433 3019 +434 433 1 +435 433 1 +437 433 1 +441 433 1 +449 433 1 +465 433 1 +497 433 1 +178 434 1 +306 434 1 +370 434 1 +402 434 1 +418 434 1 +426 434 1 +430 434 1 +432 434 1 +433 434 1 +434 434 3023 +435 434 1 +436 434 1 +438 434 1 +442 434 1 +450 434 1 +466 434 1 +498 434 1 +179 435 1 +307 435 1 +371 435 1 +403 435 1 +419 435 1 +427 435 1 +431 435 1 +433 435 1 +434 435 1 +435 435 3037 +436 435 1 +437 435 1 +439 435 1 +443 435 1 +451 435 1 +467 435 1 +499 435 1 +180 436 1 +308 436 1 +372 436 1 +404 436 1 +420 436 1 +428 436 1 +432 436 1 +434 436 1 +435 436 1 +436 436 3041 +437 436 1 +438 436 1 +440 436 1 +444 436 1 +452 436 1 +468 436 1 +500 436 1 +181 437 1 +309 437 1 +373 437 1 +405 437 1 +421 437 1 +429 437 1 +433 437 1 +435 437 1 +436 437 1 +437 437 3049 +438 437 1 +439 437 1 +441 437 1 +445 437 1 +453 437 1 +469 437 1 +182 438 1 +310 438 1 +374 438 1 +406 438 1 +422 438 1 +430 438 1 +434 438 1 +436 438 1 +437 438 1 +438 438 3061 +439 438 1 +440 438 1 +442 438 1 +446 438 1 +454 438 1 +470 438 1 +183 439 1 +311 439 1 +375 439 1 +407 439 1 +423 439 1 +431 439 1 +435 439 1 +437 439 1 +438 439 1 +439 439 3067 +440 439 1 +441 439 1 +443 439 1 +447 439 1 +455 439 1 +471 439 1 +184 440 1 +312 440 1 +376 440 1 +408 440 1 +424 440 1 +432 440 1 +436 440 1 +438 440 1 +439 440 1 +440 440 3079 +441 440 1 +442 440 1 +444 440 1 +448 440 1 +456 440 1 +472 440 1 +185 441 1 +313 441 1 +377 441 1 +409 441 1 +425 441 1 +433 441 1 +437 441 1 +439 441 1 +440 441 1 +441 441 3083 +442 441 1 +443 441 1 +445 441 1 +449 441 1 +457 441 1 +473 441 1 +186 442 1 +314 442 1 +378 442 1 +410 442 1 +426 442 1 +434 442 1 +438 442 1 +440 442 1 +441 442 1 +442 442 3089 +443 442 1 +444 442 1 +446 442 1 +450 442 1 +458 442 1 +474 442 1 +187 443 1 +315 443 1 +379 443 1 +411 443 1 +427 443 1 +435 443 1 +439 443 1 +441 443 1 +442 443 1 +443 443 3109 +444 443 1 +445 443 1 +447 443 1 +451 443 1 +459 443 1 +475 443 1 +188 444 1 +316 444 1 +380 444 1 +412 444 1 +428 444 1 +436 444 1 +440 444 1 +442 444 1 +443 444 1 +444 444 3119 +445 444 1 +446 444 1 +448 444 1 +452 444 1 +460 444 1 +476 444 1 +189 445 1 +317 445 1 +381 445 1 +413 445 1 +429 445 1 +437 445 1 +441 445 1 +443 445 1 +444 445 1 +445 445 3121 +446 445 1 +447 445 1 +449 445 1 +453 445 1 +461 445 1 +477 445 1 +190 446 1 +318 446 1 +382 446 1 +414 446 1 +430 446 1 +438 446 1 +442 446 1 +444 446 1 +445 446 1 +446 446 3137 +447 446 1 +448 446 1 +450 446 1 +454 446 1 +462 446 1 +478 446 1 +191 447 1 +319 447 1 +383 447 1 +415 447 1 +431 447 1 +439 447 1 +443 447 1 +445 447 1 +446 447 1 +447 447 3163 +448 447 1 +449 447 1 +451 447 1 +455 447 1 +463 447 1 +479 447 1 +192 448 1 +320 448 1 +384 448 1 +416 448 1 +432 448 1 +440 448 1 +444 448 1 +446 448 1 +447 448 1 +448 448 3167 +449 448 1 +450 448 1 +452 448 1 +456 448 1 +464 448 1 +480 448 1 +193 449 1 +321 449 1 +385 449 1 +417 449 1 +433 449 1 +441 449 1 +445 449 1 +447 449 1 +448 449 1 +449 449 3169 +450 449 1 +451 449 1 +453 449 1 +457 449 1 +465 449 1 +481 449 1 +194 450 1 +322 450 1 +386 450 1 +418 450 1 +434 450 1 +442 450 1 +446 450 1 +448 450 1 +449 450 1 +450 450 3181 +451 450 1 +452 450 1 +454 450 1 +458 450 1 +466 450 1 +482 450 1 +195 451 1 +323 451 1 +387 451 1 +419 451 1 +435 451 1 +443 451 1 +447 451 1 +449 451 1 +450 451 1 +451 451 3187 +452 451 1 +453 451 1 +455 451 1 +459 451 1 +467 451 1 +483 451 1 +196 452 1 +324 452 1 +388 452 1 +420 452 1 +436 452 1 +444 452 1 +448 452 1 +450 452 1 +451 452 1 +452 452 3191 +453 452 1 +454 452 1 +456 452 1 +460 452 1 +468 452 1 +484 452 1 +197 453 1 +325 453 1 +389 453 1 +421 453 1 +437 453 1 +445 453 1 +449 453 1 +451 453 1 +452 453 1 +453 453 3203 +454 453 1 +455 453 1 +457 453 1 +461 453 1 +469 453 1 +485 453 1 +198 454 1 +326 454 1 +390 454 1 +422 454 1 +438 454 1 +446 454 1 +450 454 1 +452 454 1 +453 454 1 +454 454 3209 +455 454 1 +456 454 1 +458 454 1 +462 454 1 +470 454 1 +486 454 1 +199 455 1 +327 455 1 +391 455 1 +423 455 1 +439 455 1 +447 455 1 +451 455 1 +453 455 1 +454 455 1 +455 455 3217 +456 455 1 +457 455 1 +459 455 1 +463 455 1 +471 455 1 +487 455 1 +200 456 1 +328 456 1 +392 456 1 +424 456 1 +440 456 1 +448 456 1 +452 456 1 +454 456 1 +455 456 1 +456 456 3221 +457 456 1 +458 456 1 +460 456 1 +464 456 1 +472 456 1 +488 456 1 +201 457 1 +329 457 1 +393 457 1 +425 457 1 +441 457 1 +449 457 1 +453 457 1 +455 457 1 +456 457 1 +457 457 3229 +458 457 1 +459 457 1 +461 457 1 +465 457 1 +473 457 1 +489 457 1 +202 458 1 +330 458 1 +394 458 1 +426 458 1 +442 458 1 +450 458 1 +454 458 1 +456 458 1 +457 458 1 +458 458 3251 +459 458 1 +460 458 1 +462 458 1 +466 458 1 +474 458 1 +490 458 1 +203 459 1 +331 459 1 +395 459 1 +427 459 1 +443 459 1 +451 459 1 +455 459 1 +457 459 1 +458 459 1 +459 459 3253 +460 459 1 +461 459 1 +463 459 1 +467 459 1 +475 459 1 +491 459 1 +204 460 1 +332 460 1 +396 460 1 +428 460 1 +444 460 1 +452 460 1 +456 460 1 +458 460 1 +459 460 1 +460 460 3257 +461 460 1 +462 460 1 +464 460 1 +468 460 1 +476 460 1 +492 460 1 +205 461 1 +333 461 1 +397 461 1 +429 461 1 +445 461 1 +453 461 1 +457 461 1 +459 461 1 +460 461 1 +461 461 3259 +462 461 1 +463 461 1 +465 461 1 +469 461 1 +477 461 1 +493 461 1 +206 462 1 +334 462 1 +398 462 1 +430 462 1 +446 462 1 +454 462 1 +458 462 1 +460 462 1 +461 462 1 +462 462 3271 +463 462 1 +464 462 1 +466 462 1 +470 462 1 +478 462 1 +494 462 1 +207 463 1 +335 463 1 +399 463 1 +431 463 1 +447 463 1 +455 463 1 +459 463 1 +461 463 1 +462 463 1 +463 463 3299 +464 463 1 +465 463 1 +467 463 1 +471 463 1 +479 463 1 +495 463 1 +208 464 1 +336 464 1 +400 464 1 +432 464 1 +448 464 1 +456 464 1 +460 464 1 +462 464 1 +463 464 1 +464 464 3301 +465 464 1 +466 464 1 +468 464 1 +472 464 1 +480 464 1 +496 464 1 +209 465 1 +337 465 1 +401 465 1 +433 465 1 +449 465 1 +457 465 1 +461 465 1 +463 465 1 +464 465 1 +465 465 3307 +466 465 1 +467 465 1 +469 465 1 +473 465 1 +481 465 1 +497 465 1 +210 466 1 +338 466 1 +402 466 1 +434 466 1 +450 466 1 +458 466 1 +462 466 1 +464 466 1 +465 466 1 +466 466 3313 +467 466 1 +468 466 1 +470 466 1 +474 466 1 +482 466 1 +498 466 1 +211 467 1 +339 467 1 +403 467 1 +435 467 1 +451 467 1 +459 467 1 +463 467 1 +465 467 1 +466 467 1 +467 467 3319 +468 467 1 +469 467 1 +471 467 1 +475 467 1 +483 467 1 +499 467 1 +212 468 1 +340 468 1 +404 468 1 +436 468 1 +452 468 1 +460 468 1 +464 468 1 +466 468 1 +467 468 1 +468 468 3323 +469 468 1 +470 468 1 +472 468 1 +476 468 1 +484 468 1 +500 468 1 +213 469 1 +341 469 1 +405 469 1 +437 469 1 +453 469 1 +461 469 1 +465 469 1 +467 469 1 +468 469 1 +469 469 3329 +470 469 1 +471 469 1 +473 469 1 +477 469 1 +485 469 1 +214 470 1 +342 470 1 +406 470 1 +438 470 1 +454 470 1 +462 470 1 +466 470 1 +468 470 1 +469 470 1 +470 470 3331 +471 470 1 +472 470 1 +474 470 1 +478 470 1 +486 470 1 +215 471 1 +343 471 1 +407 471 1 +439 471 1 +455 471 1 +463 471 1 +467 471 1 +469 471 1 +470 471 1 +471 471 3343 +472 471 1 +473 471 1 +475 471 1 +479 471 1 +487 471 1 +216 472 1 +344 472 1 +408 472 1 +440 472 1 +456 472 1 +464 472 1 +468 472 1 +470 472 1 +471 472 1 +472 472 3347 +473 472 1 +474 472 1 +476 472 1 +480 472 1 +488 472 1 +217 473 1 +345 473 1 +409 473 1 +441 473 1 +457 473 1 +465 473 1 +469 473 1 +471 473 1 +472 473 1 +473 473 3359 +474 473 1 +475 473 1 +477 473 1 +481 473 1 +489 473 1 +218 474 1 +346 474 1 +410 474 1 +442 474 1 +458 474 1 +466 474 1 +470 474 1 +472 474 1 +473 474 1 +474 474 3361 +475 474 1 +476 474 1 +478 474 1 +482 474 1 +490 474 1 +219 475 1 +347 475 1 +411 475 1 +443 475 1 +459 475 1 +467 475 1 +471 475 1 +473 475 1 +474 475 1 +475 475 3371 +476 475 1 +477 475 1 +479 475 1 +483 475 1 +491 475 1 +220 476 1 +348 476 1 +412 476 1 +444 476 1 +460 476 1 +468 476 1 +472 476 1 +474 476 1 +475 476 1 +476 476 3373 +477 476 1 +478 476 1 +480 476 1 +484 476 1 +492 476 1 +221 477 1 +349 477 1 +413 477 1 +445 477 1 +461 477 1 +469 477 1 +473 477 1 +475 477 1 +476 477 1 +477 477 3389 +478 477 1 +479 477 1 +481 477 1 +485 477 1 +493 477 1 +222 478 1 +350 478 1 +414 478 1 +446 478 1 +462 478 1 +470 478 1 +474 478 1 +476 478 1 +477 478 1 +478 478 3391 +479 478 1 +480 478 1 +482 478 1 +486 478 1 +494 478 1 +223 479 1 +351 479 1 +415 479 1 +447 479 1 +463 479 1 +471 479 1 +475 479 1 +477 479 1 +478 479 1 +479 479 3407 +480 479 1 +481 479 1 +483 479 1 +487 479 1 +495 479 1 +224 480 1 +352 480 1 +416 480 1 +448 480 1 +464 480 1 +472 480 1 +476 480 1 +478 480 1 +479 480 1 +480 480 3413 +481 480 1 +482 480 1 +484 480 1 +488 480 1 +496 480 1 +225 481 1 +353 481 1 +417 481 1 +449 481 1 +465 481 1 +473 481 1 +477 481 1 +479 481 1 +480 481 1 +481 481 3433 +482 481 1 +483 481 1 +485 481 1 +489 481 1 +497 481 1 +226 482 1 +354 482 1 +418 482 1 +450 482 1 +466 482 1 +474 482 1 +478 482 1 +480 482 1 +481 482 1 +482 482 3449 +483 482 1 +484 482 1 +486 482 1 +490 482 1 +498 482 1 +227 483 1 +355 483 1 +419 483 1 +451 483 1 +467 483 1 +475 483 1 +479 483 1 +481 483 1 +482 483 1 +483 483 3457 +484 483 1 +485 483 1 +487 483 1 +491 483 1 +499 483 1 +228 484 1 +356 484 1 +420 484 1 +452 484 1 +468 484 1 +476 484 1 +480 484 1 +482 484 1 +483 484 1 +484 484 3461 +485 484 1 +486 484 1 +488 484 1 +492 484 1 +500 484 1 +229 485 1 +357 485 1 +421 485 1 +453 485 1 +469 485 1 +477 485 1 +481 485 1 +483 485 1 +484 485 1 +485 485 3463 +486 485 1 +487 485 1 +489 485 1 +493 485 1 +230 486 1 +358 486 1 +422 486 1 +454 486 1 +470 486 1 +478 486 1 +482 486 1 +484 486 1 +485 486 1 +486 486 3467 +487 486 1 +488 486 1 +490 486 1 +494 486 1 +231 487 1 +359 487 1 +423 487 1 +455 487 1 +471 487 1 +479 487 1 +483 487 1 +485 487 1 +486 487 1 +487 487 3469 +488 487 1 +489 487 1 +491 487 1 +495 487 1 +232 488 1 +360 488 1 +424 488 1 +456 488 1 +472 488 1 +480 488 1 +484 488 1 +486 488 1 +487 488 1 +488 488 3491 +489 488 1 +490 488 1 +492 488 1 +496 488 1 +233 489 1 +361 489 1 +425 489 1 +457 489 1 +473 489 1 +481 489 1 +485 489 1 +487 489 1 +488 489 1 +489 489 3499 +490 489 1 +491 489 1 +493 489 1 +497 489 1 +234 490 1 +362 490 1 +426 490 1 +458 490 1 +474 490 1 +482 490 1 +486 490 1 +488 490 1 +489 490 1 +490 490 3511 +491 490 1 +492 490 1 +494 490 1 +498 490 1 +235 491 1 +363 491 1 +427 491 1 +459 491 1 +475 491 1 +483 491 1 +487 491 1 +489 491 1 +490 491 1 +491 491 3517 +492 491 1 +493 491 1 +495 491 1 +499 491 1 +236 492 1 +364 492 1 +428 492 1 +460 492 1 +476 492 1 +484 492 1 +488 492 1 +490 492 1 +491 492 1 +492 492 3527 +493 492 1 +494 492 1 +496 492 1 +500 492 1 +237 493 1 +365 493 1 +429 493 1 +461 493 1 +477 493 1 +485 493 1 +489 493 1 +491 493 1 +492 493 1 +493 493 3529 +494 493 1 +495 493 1 +497 493 1 +238 494 1 +366 494 1 +430 494 1 +462 494 1 +478 494 1 +486 494 1 +490 494 1 +492 494 1 +493 494 1 +494 494 3533 +495 494 1 +496 494 1 +498 494 1 +239 495 1 +367 495 1 +431 495 1 +463 495 1 +479 495 1 +487 495 1 +491 495 1 +493 495 1 +494 495 1 +495 495 3539 +496 495 1 +497 495 1 +499 495 1 +240 496 1 +368 496 1 +432 496 1 +464 496 1 +480 496 1 +488 496 1 +492 496 1 +494 496 1 +495 496 1 +496 496 3541 +497 496 1 +498 496 1 +500 496 1 +241 497 1 +369 497 1 +433 497 1 +465 497 1 +481 497 1 +489 497 1 +493 497 1 +495 497 1 +496 497 1 +497 497 3547 +498 497 1 +499 497 1 +242 498 1 +370 498 1 +434 498 1 +466 498 1 +482 498 1 +490 498 1 +494 498 1 +496 498 1 +497 498 1 +498 498 3557 +499 498 1 +500 498 1 +243 499 1 +371 499 1 +435 499 1 +467 499 1 +483 499 1 +491 499 1 +495 499 1 +497 499 1 +498 499 1 +499 499 3559 +500 499 1 +244 500 1 +372 500 1 +436 500 1 +468 500 1 +484 500 1 +492 500 1 +496 500 1 +498 500 1 +499 500 1 +500 500 3571 diff --git a/SPEX/ExampleMats/Trefethen_500.rhs.txt b/SPEX/ExampleMats/Trefethen_500.rhs.txt new file mode 100644 index 0000000000..d776bc42cb --- /dev/null +++ b/SPEX/ExampleMats/Trefethen_500.rhs.txt @@ -0,0 +1,501 @@ +500 1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/SPEX/ExampleMats/example.mat.txt b/SPEX/ExampleMats/example.mat.txt new file mode 100644 index 0000000000..ec5a50dca9 --- /dev/null +++ b/SPEX/ExampleMats/example.mat.txt @@ -0,0 +1,9 @@ +4 4 8 +1 1 2 +4 1 -3 +2 2 5 +1 2 -1 +2 3 -1 +3 3 2 +1 4 -3 +4 4 5 diff --git a/SPEX/ExampleMats/example.rhs.txt b/SPEX/ExampleMats/example.rhs.txt new file mode 100644 index 0000000000..208faa80da --- /dev/null +++ b/SPEX/ExampleMats/example.rhs.txt @@ -0,0 +1,9 @@ +8 1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/SPEX/ExampleMats/mesh1e1.mat.txt b/SPEX/ExampleMats/mesh1e1.mat.txt new file mode 100644 index 0000000000..9fa0f0b2ec --- /dev/null +++ b/SPEX/ExampleMats/mesh1e1.mat.txt @@ -0,0 +1,307 @@ +48 48 306 +1 1 2.977568 +2 1 -0.405002 +8 1 0.156027 +45 1 0.210025 +48 1 1.206514 +1 2 -0.405002 +2 2 4.058510 +3 2 0.216812 +42 2 0.182615 +43 2 0.638841 +46 2 0.334952 +48 2 1.280289 +2 3 0.216812 +3 3 2.124108 +4 3 -0.080115 +46 3 0.827181 +3 4 -0.080115 +4 4 3.031396 +5 4 0.225935 +37 4 0.586120 +44 4 0.508613 +46 4 0.630613 +4 5 0.225935 +5 5 2.107705 +6 5 -0.076779 +44 5 0.804992 +5 6 -0.076779 +6 6 3.078530 +7 6 0.205580 +41 6 0.712866 +44 6 0.564706 +47 6 0.518599 +6 7 0.205580 +7 7 2.094885 +8 7 -0.068234 +47 7 0.821071 +1 8 0.156027 +7 8 -0.068234 +8 8 3.126347 +35 8 0.648631 +45 8 0.785688 +47 8 0.467767 +9 9 3.713649 +10 9 0.080448 +15 9 0.031980 +18 9 0.576484 +23 9 0.745579 +30 9 0.652559 +31 9 0.626599 +9 10 0.080448 +10 10 3.000242 +11 10 0.277821 +21 10 1.210132 +23 10 0.431840 +10 11 0.277821 +11 11 4.943567 +12 11 -0.342455 +21 11 0.309926 +24 11 0.729180 +25 11 1.175784 +27 11 1.108401 +11 12 -0.342455 +12 12 5.015323 +13 12 0.382281 +27 12 0.830750 +34 12 0.126147 +36 12 1.103006 +38 12 1.230685 +12 13 0.382281 +13 13 2.840558 +14 13 0.139618 +19 13 0.405272 +34 13 0.913387 +13 14 0.139618 +14 14 4.112784 +15 14 0.564372 +16 14 0.231253 +17 14 0.686969 +19 14 1.490573 +9 15 0.031980 +14 15 0.564372 +15 15 3.090884 +16 15 1.033551 +18 15 0.460981 +14 16 0.231253 +15 16 1.033551 +16 16 5.176547 +17 16 1.431193 +18 16 0.931275 +20 16 0.549274 +14 17 0.686969 +16 17 1.431193 +17 17 5.374872 +19 17 0.680945 +20 17 0.538425 +22 17 1.037339 +9 18 0.576484 +15 18 0.460981 +16 18 0.931275 +18 18 4.713440 +20 18 0.473941 +31 18 0.694966 +40 18 0.575795 +13 19 0.405272 +14 19 1.490573 +17 19 0.680945 +19 19 5.539172 +22 19 0.776290 +34 19 1.186091 +16 20 0.549274 +17 20 0.538425 +18 20 0.473941 +20 20 5.005990 +22 20 0.434392 +40 20 1.030750 +42 20 0.197977 +43 20 0.781231 +10 21 1.210132 +11 21 0.309926 +21 21 4.962782 +23 21 0.575195 +24 21 1.128118 +28 21 0.739411 +17 22 1.037339 +19 22 0.776290 +20 22 0.434392 +22 22 5.319452 +34 22 0.340036 +37 22 0.579572 +43 22 0.462808 +46 22 0.689014 +9 23 0.745579 +10 23 0.431840 +21 23 0.575195 +23 23 4.774714 +28 23 0.928992 +30 23 0.725312 +33 23 0.367796 +11 24 0.729180 +21 24 1.128118 +24 24 5.100276 +25 24 0.727205 +26 24 0.958298 +28 24 0.557475 +11 25 1.175784 +24 25 0.727205 +25 25 5.381007 +26 25 0.822331 +27 25 0.541164 +29 25 1.114524 +24 26 0.958298 +25 26 0.822331 +26 26 5.383416 +28 26 0.746836 +29 26 0.232295 +35 26 0.301369 +41 26 0.586612 +47 26 0.735675 +11 27 1.108401 +12 27 0.830750 +25 27 0.541164 +27 27 5.419806 +29 27 1.068270 +38 27 0.871223 +21 28 0.739411 +23 28 0.928992 +24 28 0.557475 +26 28 0.746836 +28 28 5.210912 +33 28 0.469623 +35 28 0.768575 +25 29 1.114524 +26 29 0.232295 +27 29 1.068270 +29 29 5.401751 +38 29 0.587584 +39 29 0.468280 +41 29 0.930797 +9 30 0.652559 +23 30 0.725312 +30 30 4.836357 +31 30 1.060914 +32 30 0.492282 +33 30 0.905290 +9 31 0.626599 +18 31 0.694966 +30 31 1.060914 +31 31 4.778445 +32 31 0.506239 +40 31 0.889729 +30 32 0.492282 +31 32 0.506239 +32 32 5.173274 +33 32 0.988156 +40 32 0.911091 +42 32 0.667618 +45 32 0.607887 +23 33 0.367796 +28 33 0.469623 +30 33 0.905290 +32 33 0.988156 +33 33 5.162946 +35 33 1.048019 +45 33 0.384062 +12 34 0.126147 +13 34 0.913387 +19 34 1.186091 +22 34 0.340036 +34 34 5.312636 +36 34 1.009800 +37 34 0.737174 +8 35 0.648631 +26 35 0.301369 +28 35 0.768575 +33 35 1.048019 +35 35 5.257402 +45 35 0.587907 +47 35 0.902901 +12 36 1.103006 +34 36 1.009800 +36 36 5.427940 +37 36 0.751991 +38 36 0.351124 +39 36 1.212018 +4 37 0.586120 +22 37 0.579572 +34 37 0.737174 +36 37 0.751991 +37 37 5.210871 +39 37 0.292738 +44 37 0.699639 +46 37 0.563635 +12 38 1.230685 +27 38 0.871223 +29 38 0.587584 +36 38 0.351124 +38 38 5.131964 +39 38 1.091347 +29 39 0.468280 +36 39 1.212018 +37 39 0.292738 +38 39 1.091347 +39 39 5.533580 +41 39 0.587688 +44 39 0.881508 +18 40 0.575795 +20 40 1.030750 +31 40 0.889729 +32 40 0.911091 +40 40 5.095706 +42 40 0.688341 +6 41 0.712866 +26 41 0.586612 +29 41 0.930797 +39 41 0.587688 +41 41 5.133159 +44 41 0.659520 +47 41 0.655675 +2 42 0.182615 +20 42 0.197977 +32 42 0.667618 +40 42 0.688341 +42 42 5.211102 +43 42 1.175215 +45 42 0.168889 +48 42 1.130447 +2 43 0.638841 +20 43 0.781231 +22 43 0.462808 +42 43 1.175215 +43 43 5.243415 +46 43 1.185322 +4 44 0.508613 +5 44 0.804992 +6 44 0.564706 +37 44 0.699639 +39 44 0.881508 +41 44 0.659520 +44 44 5.118978 +1 45 0.210025 +8 45 0.785688 +32 45 0.607887 +33 45 0.384062 +35 45 0.587907 +42 45 0.168889 +45 45 5.095647 +48 45 1.351190 +2 46 0.334952 +3 46 0.827181 +4 46 0.630613 +22 46 0.689014 +37 46 0.563635 +43 46 1.185322 +46 46 5.230717 +6 47 0.518599 +7 47 0.821071 +8 47 0.467767 +26 47 0.735675 +35 47 0.902901 +41 47 0.655675 +47 47 5.101689 +1 48 1.206514 +2 48 1.280289 +42 48 1.130447 +45 48 1.351190 +48 48 5.968440 \ No newline at end of file diff --git a/SPEX/ExampleMats/mesh1e1.rhs.txt b/SPEX/ExampleMats/mesh1e1.rhs.txt new file mode 100644 index 0000000000..e31e55a135 --- /dev/null +++ b/SPEX/ExampleMats/mesh1e1.rhs.txt @@ -0,0 +1,49 @@ +48 1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/SPEX/SPEX_Left_LU/ExampleMats/test_mat.txt b/SPEX/ExampleMats/test.mat.txt similarity index 100% rename from SPEX/SPEX_Left_LU/ExampleMats/test_mat.txt rename to SPEX/ExampleMats/test.mat.txt diff --git a/SPEX/SPEX_Left_LU/ExampleMats/test_rhs.txt b/SPEX/ExampleMats/test.rhs.txt similarity index 100% rename from SPEX/SPEX_Left_LU/ExampleMats/test_rhs.txt rename to SPEX/ExampleMats/test.rhs.txt diff --git a/SPEX/ExampleMats/test1.mat.txt b/SPEX/ExampleMats/test1.mat.txt new file mode 100644 index 0000000000..75ca102575 --- /dev/null +++ b/SPEX/ExampleMats/test1.mat.txt @@ -0,0 +1,2 @@ +2 2 1 +1 2 3.14159 diff --git a/SPEX/ExampleMats/test2.mat.txt b/SPEX/ExampleMats/test2.mat.txt new file mode 100644 index 0000000000..dbb85ea23a --- /dev/null +++ b/SPEX/ExampleMats/test2.mat.txt @@ -0,0 +1,4 @@ +3 3 3 +2 1 1 +1 3 1 +3 2 1 diff --git a/SPEX/ExampleMats/test3.mat.txt b/SPEX/ExampleMats/test3.mat.txt new file mode 100644 index 0000000000..e4a20685cd --- /dev/null +++ b/SPEX/ExampleMats/test3.mat.txt @@ -0,0 +1,3 @@ +2 2 2 +1 2 3.14158 +2 1 3 diff --git a/SPEX/ExampleMats/test4.mat.txt b/SPEX/ExampleMats/test4.mat.txt new file mode 100644 index 0000000000..4715271504 --- /dev/null +++ b/SPEX/ExampleMats/test4.mat.txt @@ -0,0 +1,3 @@ +2 2 2 +1 2 1 +2 1 1 diff --git a/SPEX/ExampleMats/test5.mat.txt b/SPEX/ExampleMats/test5.mat.txt new file mode 100644 index 0000000000..4bec2e4e9d --- /dev/null +++ b/SPEX/ExampleMats/test5.mat.txt @@ -0,0 +1,2 @@ +2 1 1 +1 1 3.14159 diff --git a/SPEX/ExampleMats/tomography.mat b/SPEX/ExampleMats/tomography.mat new file mode 100644 index 0000000000..a69d1d3abb --- /dev/null +++ b/SPEX/ExampleMats/tomography.mat @@ -0,0 +1,28727 @@ +500 500 28726 +1 1 1.252630 +319 1 0.147929 +320 1 0.065746 +322 1 0.147929 +323 1 0.147929 +324 1 0.065746 +333 1 0.065746 +337 1 0.147929 +338 1 0.065746 +342 1 0.147929 +377 1 -4.451226 +402 1 -12.176466 +406 1 -18.602982 +427 1 -12.190485 +431 1 -24.917577 +452 1 -12.213604 +456 1 -25.187298 +477 1 -12.245813 +481 1 -25.487253 +2 2 0.940335 +319 2 0.065746 +321 2 0.065746 +322 2 0.065746 +329 2 0.065746 +332 2 0.065746 +333 2 0.147929 +335 2 0.147929 +336 2 0.065746 +361 2 -8.324114 +362 2 -0.784650 +377 2 -10.336360 +386 2 -10.985199 +402 2 -28.458070 +406 2 -9.167910 +410 2 -5.057559 +411 2 -6.366862 +426 2 -25.500777 +427 2 -3.257855 +431 2 -12.443869 +435 2 -11.902031 +451 2 -29.080771 +455 2 -9.113298 +456 2 -3.655776 +459 2 -5.672320 +460 2 -6.748318 +476 2 -29.424106 +480 2 -13.114869 +484 2 -12.982873 +500 2 -4.747824 +3 3 5.115220 +319 3 0.065746 +320 3 0.147929 +321 3 0.065746 +322 3 0.591716 +323 3 0.591716 +324 3 0.591716 +327 3 0.591716 +330 3 0.591716 +332 3 0.591716 +333 3 0.147929 +337 3 0.591716 +338 3 0.147929 +342 3 0.147929 +361 3 -4.407671 +362 3 -3.223390 +377 3 -10.106363 +386 3 -8.958698 +402 3 -27.539594 +406 3 -8.104303 +411 3 -9.049106 +427 3 -27.415523 +431 3 -10.779999 +436 3 -9.154717 +452 3 -27.312571 +456 3 -10.810839 +461 3 -9.276005 +477 3 -27.230770 +481 3 -10.853813 +486 3 -9.413512 +4 4 1.712853 +319 4 0.065746 +320 4 0.147929 +322 4 0.147929 +323 4 0.147929 +329 4 0.147929 +330 4 0.147929 +332 4 0.147929 +333 4 0.147929 +335 4 0.147929 +336 4 0.065746 +338 4 0.147929 +377 4 -10.242783 +402 4 -28.170308 +406 4 -8.737519 +426 4 -18.027776 +427 4 -10.396084 +431 4 -11.799299 +451 4 -28.698650 +455 4 -1.645017 +456 4 -10.392946 +476 4 -28.994403 +480 4 -12.293683 +5 5 3.619494 +319 5 0.065746 +321 5 0.147929 +322 5 0.065746 +323 5 0.147929 +324 5 0.065746 +327 5 0.591716 +333 5 0.065746 +334 5 0.147929 +336 5 0.591716 +337 5 0.147929 +338 5 0.591716 +339 5 0.147929 +342 5 0.591716 +361 5 -25.168329 +362 5 -1.271566 +377 5 -4.620854 +385 5 -14.866842 +386 5 -17.866260 +401 5 -0.023504 +402 5 -12.706425 +406 5 -10.797896 +409 5 -8.074397 +410 5 -26.954536 +426 5 -12.875755 +430 5 -7.485991 +431 5 -7.378833 +433 5 -4.776742 +434 5 -32.785398 +451 5 -13.031269 +454 5 -1.536498 +455 5 -13.961056 +457 5 -5.044059 +458 5 -35.305093 +476 5 -13.196266 +479 5 -16.166555 +481 5 -9.004540 +482 5 -34.397955 +500 5 -6.580751 +6 6 0.956772 +321 6 0.147929 +322 6 0.065746 +324 6 0.065746 +329 6 0.065746 +337 6 0.147929 +338 6 0.147929 +342 6 0.065746 +354 6 -4.130753 +355 6 -81.469571 +356 6 -32.918233 +357 6 -32.919603 +358 6 -32.921175 +359 6 -32.922987 +360 6 -32.925089 +361 6 -32.927542 +362 6 -0.956586 +379 6 -26.396467 +380 6 -79.295276 +381 6 -12.251710 +403 6 -4.496474 +404 6 -22.570360 +405 6 -21.205188 +406 6 -58.798166 +407 6 -8.386655 +428 6 -21.277207 +429 6 -6.495940 +431 6 -62.350037 +432 6 -18.115157 +433 6 -4.967501 +452 6 -9.221660 +453 6 -19.292844 +456 6 -37.130185 +457 6 -30.586221 +458 6 -14.793105 +459 6 -0.162442 +476 6 -0.876754 +477 6 -18.374785 +478 6 -10.037946 +481 6 -9.366111 +482 6 -51.471789 +483 6 -5.099449 +484 6 -14.165294 +7 7 2.238823 +321 7 0.591716 +322 7 0.147929 +324 7 0.147929 +329 7 0.591716 +336 7 0.065746 +337 7 0.147929 +338 7 0.147929 +342 7 0.147929 +357 7 -41.208517 +358 7 -132.578704 +359 7 -132.656444 +360 7 -132.746754 +361 7 -132.852373 +362 7 -3.861121 +380 7 -77.742411 +381 7 -253.881930 +382 7 -91.302873 +405 7 -158.762222 +406 7 -95.275320 +407 7 -31.016068 +429 7 -92.967984 +430 7 -75.560732 +431 7 -32.959927 +432 7 -63.879431 +433 7 -20.299512 +453 7 -13.726877 +454 7 -148.635861 +455 7 -11.306722 +457 7 -80.047474 +458 7 -24.189262 +459 7 -8.951231 +477 7 -0.479330 +478 7 -130.760401 +479 7 -36.433050 +480 7 -11.407530 +482 7 -52.354808 +483 7 -25.768197 +484 7 -31.404320 +8 8 5.049474 +319 8 0.147929 +321 8 0.147929 +322 8 0.591716 +323 8 0.591716 +324 8 0.065746 +327 8 0.591716 +330 8 0.591716 +333 8 0.147929 +334 8 0.591716 +337 8 0.591716 +338 8 0.591716 +339 8 0.147929 +361 8 -14.474784 +362 8 -3.353131 +377 8 -10.014716 +386 8 -21.112615 +402 8 -27.388614 +406 8 -18.575118 +411 8 -21.527227 +427 8 -27.409980 +431 8 -24.872344 +436 8 -21.985096 +452 8 -27.451829 +456 8 -25.132492 +460 8 -6.424869 +461 8 -16.063496 +477 8 -27.514143 +481 8 -25.422662 +485 8 -23.039351 +9 9 0.792406 +321 9 0.065746 +323 9 0.065746 +324 9 0.065746 +332 9 0.147929 +337 9 0.065746 +338 9 0.065746 +342 9 0.065746 +361 9 -4.864458 +362 9 -2.793026 +386 9 -8.999830 +411 9 -9.101684 +436 9 -9.219110 +461 9 -9.352637 +486 9 -9.502861 +10 10 1.614234 +320 10 0.147929 +322 10 0.591716 +323 10 0.065746 +324 10 0.065746 +327 10 0.065746 +329 10 0.065746 +333 10 0.065746 +337 10 0.147929 +338 10 0.147929 +377 10 -4.461743 +402 10 -12.224284 +427 10 -12.266240 +452 10 -12.317314 +476 10 -5.943525 +477 10 -6.433955 +11 11 1.433432 +322 11 0.147929 +323 11 0.591716 +324 11 0.147929 +337 11 0.147929 +342 11 0.147929 +12 12 2.370316 +322 12 0.591716 +323 12 0.065746 +324 12 0.147929 +327 12 0.147929 +333 12 0.065746 +334 12 0.591716 +335 12 0.147929 +336 12 0.147929 +337 12 0.147929 +342 12 0.065746 +377 12 -4.577713 +402 12 -12.598368 +426 12 -10.201625 +427 12 -2.522512 +451 12 -12.859438 +476 12 -13.004119 +13 13 1.121137 +319 13 0.147929 +322 13 0.147929 +323 13 0.065746 +324 13 0.147929 +327 13 0.065746 +334 13 0.147929 +342 13 0.147929 +406 13 -18.530332 +431 13 -24.799023 +456 13 -25.043083 +481 13 -25.316823 +14 14 4.539941 +319 14 0.147929 +320 14 0.591716 +322 14 0.147929 +323 14 0.147929 +324 14 0.147929 +327 14 0.591716 +330 14 0.591716 +332 14 0.591716 +333 14 0.147929 +337 14 0.591716 +342 14 0.591716 +377 14 -10.014792 +402 14 -27.385346 +406 14 -18.546347 +427 14 -27.401624 +431 14 -24.825336 +452 14 -27.438391 +456 14 -25.075256 +477 14 -27.495631 +481 14 -25.354980 +15 15 3.866042 +319 15 0.147929 +320 15 0.591716 +323 15 0.591716 +324 15 0.147929 +327 15 0.147929 +328 15 0.065746 +330 15 0.591716 +333 15 0.147929 +337 15 0.591716 +342 15 0.591716 +377 15 -10.014809 +402 15 -27.385097 +406 15 -18.545704 +427 15 -27.400943 +431 15 -24.824281 +452 15 -27.437278 +456 15 -25.073969 +460 15 -6.936143 +477 15 -27.494088 +481 15 -25.353454 +485 15 -10.250668 +16 16 2.534681 +319 16 0.147929 +321 16 0.147929 +322 16 0.591716 +323 16 0.147929 +324 16 0.147929 +330 16 0.147929 +334 16 0.147929 +335 16 0.591716 +337 16 0.065746 +342 16 0.147929 +361 16 -15.128925 +362 16 -2.951903 +386 16 -21.462625 +406 16 -18.797762 +411 16 -21.939985 +431 16 -25.227961 +436 16 -22.464168 +456 16 -25.557973 +460 16 -16.943933 +461 16 -6.093737 +481 16 -25.919695 +485 16 -23.663163 +17 17 2.600427 +319 17 0.147929 +320 17 0.147929 +321 17 0.147929 +323 17 0.065746 +324 17 0.591716 +328 17 0.147929 +333 17 0.065746 +336 17 0.147929 +337 17 0.591716 +338 17 0.147929 +342 17 0.147929 +361 17 -20.443097 +362 17 -1.546924 +377 17 -4.620256 +386 17 -26.719061 +402 17 -12.728116 +406 17 -21.553636 +410 17 -23.747794 +411 17 -4.266741 +426 17 -12.867891 +427 17 -0.005789 +430 17 -0.660260 +431 17 -28.715079 +434 17 -4.571338 +435 17 -24.855356 +451 17 -13.028927 +455 17 -30.282510 +459 17 -30.963781 +460 17 -21.525191 +476 17 -13.193657 +479 17 -4.542362 +480 17 -26.701773 +483 17 -21.647505 +484 17 -27.348116 +485 17 -16.452989 +500 17 -6.489718 +18 18 2.386752 +320 18 0.147929 +321 18 0.147929 +322 18 0.147929 +323 18 0.147929 +329 18 0.591716 +330 18 0.147929 +332 18 0.147929 +333 18 0.147929 +336 18 0.065746 +337 18 0.147929 +338 18 0.147929 +342 18 0.147929 +361 18 -20.622716 +362 18 -1.529765 +377 18 -16.270124 +386 18 -26.936927 +402 18 -11.873459 +403 18 -31.108445 +410 18 -24.907327 +411 18 -3.359047 +428 18 -11.150583 +429 18 -29.696707 +434 18 -6.416043 +435 18 -23.300048 +454 18 -13.325335 +455 18 -25.492342 +459 18 -31.294592 +480 18 -18.448030 +481 18 -18.453074 +483 18 -24.520030 +484 18 -8.490021 +19 19 1.696417 +319 19 0.147929 +321 19 0.065746 +322 19 0.065746 +323 19 0.591716 +327 19 0.147929 +330 19 0.147929 +333 19 0.147929 +337 19 0.065746 +338 19 0.065746 +361 19 -6.819240 +362 19 -1.259830 +377 19 -10.062830 +386 19 -9.598189 +402 19 -27.590889 +406 19 -18.936740 +411 19 -9.820563 +427 19 -27.715929 +431 19 -25.445191 +436 19 -10.064365 +451 19 -4.938707 +452 19 -22.922856 +456 19 -25.813406 +460 19 -9.048967 +461 19 -1.281799 +476 19 -28.027701 +480 19 -5.102938 +481 19 -21.111450 +485 19 -10.621010 +20 20 1.137574 +320 20 0.065746 +321 20 0.065746 +323 20 0.065746 +324 20 0.147929 +328 20 0.065746 +330 20 0.065746 +334 20 0.065746 +336 20 0.065746 +338 20 0.065746 +339 20 0.147929 +342 20 0.065746 +361 20 -10.640544 +362 20 -0.586045 +385 20 -4.697569 +386 20 -9.136824 +409 20 -0.296058 +410 20 -14.433768 +434 20 -15.714433 +458 20 -14.179447 +459 20 -2.615057 +460 20 -12.182791 +482 20 -13.934504 +483 20 -4.040770 +484 20 -16.385829 +485 20 -2.610146 +21 21 3.405819 +319 21 0.147929 +320 21 0.591716 +321 21 0.065746 +322 21 0.147929 +323 21 0.147929 +324 21 0.591716 +328 21 0.065746 +333 21 0.065746 +337 21 0.591716 +338 21 0.591716 +342 21 0.147929 +361 21 -6.232026 +362 21 -1.629572 +377 21 -4.451239 +386 21 -9.296669 +402 21 -12.169701 +406 21 -18.504980 +411 21 -9.464494 +427 21 -12.173765 +431 21 -24.757126 +436 21 -9.650686 +452 21 -12.186939 +456 21 -24.991629 +460 21 -6.887534 +461 21 -9.856108 +477 21 -12.209219 +481 21 -25.255620 +485 21 -19.906323 +486 21 -0.345037 +22 22 3.126397 +319 22 0.147929 +321 22 0.147929 +322 22 0.147929 +323 22 0.147929 +324 22 0.147929 +327 22 0.591716 +328 22 0.147929 +329 22 0.147929 +330 22 0.147929 +332 22 0.065746 +333 22 0.147929 +334 22 0.147929 +338 22 0.591716 +342 22 0.147929 +361 22 -14.792665 +362 22 -3.150153 +377 22 -10.018871 +386 22 -21.272193 +402 22 -27.420235 +406 22 -18.674362 +411 22 -21.715905 +427 22 -27.471265 +431 22 -25.032363 +436 22 -22.204484 +452 22 -27.542767 +456 22 -25.325364 +460 22 -27.370905 +461 22 -11.200097 +477 22 -27.634705 +481 22 -25.649140 +485 22 -46.762196 +23 23 4.293393 +320 23 0.147929 +321 23 0.147929 +322 23 0.147929 +323 23 0.591716 +324 23 0.147929 +327 23 0.065746 +328 23 0.065746 +329 23 0.591716 +330 23 0.591716 +333 23 0.065746 +334 23 0.591716 +335 23 0.147929 +341 23 0.591716 +342 23 0.147929 +361 23 -15.879580 +362 23 -2.572260 +377 23 -4.493346 +386 23 -21.969840 +402 23 -12.333145 +411 23 -22.532709 +427 23 -12.408069 +435 23 -4.899363 +436 23 -18.248440 +451 23 -10.810604 +452 23 -1.681615 +460 23 -31.148411 +476 23 -12.585534 +485 23 -35.448594 +24 24 1.630671 +320 24 0.147929 +321 24 0.147929 +322 24 0.147929 +323 24 0.147929 +324 24 0.147929 +329 24 0.147929 +330 24 0.147929 +332 24 0.065746 +336 24 0.147929 +341 24 0.065746 +342 24 0.065746 +361 24 -6.527524 +362 24 -10.545096 +386 24 -19.996850 +411 24 -20.148642 +436 24 -20.333237 +461 24 -20.551460 +486 24 -20.804282 +25 25 5.542571 +319 25 0.147929 +320 25 0.591716 +321 25 0.065746 +322 25 0.591716 +323 25 0.147929 +324 25 0.591716 +327 25 0.591716 +329 25 0.591716 +330 25 0.591716 +332 25 0.065746 +334 25 0.065746 +338 25 0.591716 +339 25 0.065746 +342 25 0.591716 +361 25 -6.366946 +362 25 -1.534821 +386 25 -9.353025 +406 25 -18.535979 +411 25 -9.531627 +431 25 -24.808314 +436 25 -9.729152 +456 25 -25.054454 +460 25 -1.793941 +461 25 -8.152579 +481 25 -25.330318 +485 25 -10.184732 +26 26 1.630671 +319 26 0.065746 +322 26 0.147929 +323 26 0.147929 +324 26 0.147929 +330 26 0.065746 +333 26 0.065746 +335 26 0.147929 +342 26 0.591716 +377 26 -4.456632 +402 26 -12.204115 +406 26 -8.336205 +427 26 -12.236984 +431 26 -11.183481 +452 26 -12.278957 +456 26 -11.324818 +477 26 -12.330014 +481 26 -11.480109 +27 27 5.723373 +319 27 0.591716 +322 27 0.147929 +323 27 0.147929 +324 27 0.591716 +328 27 0.147929 +329 27 0.147929 +330 27 0.591716 +332 27 0.591716 +333 27 0.591716 +336 27 0.591716 +339 27 0.591716 +341 27 0.147929 +342 27 0.591716 +377 27 -61.152282 +402 27 -56.332726 +403 27 -105.783558 +406 27 -40.913384 +407 27 -47.742027 +428 27 -71.178365 +429 27 -83.705917 +432 27 -114.369260 +454 27 -97.256782 +455 27 -50.732475 +457 27 -74.233878 +458 27 -36.523970 +460 27 -14.746031 +480 27 -135.118354 +481 27 -6.336597 +483 27 -107.389832 +485 27 -5.601739 +486 27 -15.550997 +28 28 1.236193 +319 28 0.147929 +322 28 0.065746 +323 28 0.065746 +324 28 0.147929 +328 28 0.065746 +329 28 0.065746 +332 28 0.147929 +337 28 0.065746 +339 28 0.065746 +342 28 0.147929 +406 28 -18.561522 +431 28 -24.850170 +456 28 -25.105531 +460 28 -7.939394 +481 28 -25.390810 +485 28 -11.901131 +29 29 0.660914 +323 29 0.065746 +324 29 0.065746 +330 29 0.147929 +341 29 0.065746 +342 29 0.065746 +30 30 1.482742 +319 30 0.065746 +323 30 0.147929 +324 30 0.147929 +329 30 0.065746 +330 30 0.147929 +335 30 0.065746 +336 30 0.147929 +337 30 0.147929 +341 30 0.147929 +342 30 0.147929 +406 30 -10.340295 +430 30 -5.220300 +431 30 -8.964578 +455 30 -14.730485 +479 30 -12.645940 +480 30 -2.661649 +31 31 1.778600 +321 31 0.147929 +324 31 0.147929 +326 31 0.065746 +327 31 0.147929 +329 31 0.065746 +332 31 0.147929 +333 31 0.147929 +335 31 0.065746 +336 31 0.147929 +337 31 0.147929 +338 31 0.147929 +339 31 0.147929 +361 31 -16.148300 +362 31 -2.456990 +377 31 -10.351824 +386 31 -22.178191 +402 31 -28.114022 +411 31 -22.774947 +427 31 -27.849393 +435 31 -8.632562 +436 31 -14.793666 +452 31 -27.607448 +460 31 -24.135238 +477 31 -3.960713 +478 31 -23.427575 +485 31 -24.905360 +32 32 2.008711 +319 32 0.065746 +320 32 0.591716 +321 32 0.147929 +324 32 0.147929 +326 32 0.147929 +327 32 0.065746 +328 32 0.147929 +332 32 0.147929 +334 32 0.147929 +342 32 0.147929 +361 32 -9.411513 +362 32 -7.736438 +386 32 -20.122125 +406 32 -8.100875 +411 32 -20.315179 +431 32 -10.769090 +436 32 -20.542130 +456 32 -10.792652 +460 32 -14.747022 +461 32 -20.803997 +481 32 -10.828309 +485 32 -21.604097 +486 32 -21.101946 +33 33 1.400559 +320 33 0.147929 +321 33 0.065746 +322 33 0.147929 +323 33 0.065746 +324 33 0.065746 +326 33 0.147929 +329 33 0.147929 +332 33 0.147929 +333 33 0.065746 +342 33 0.147929 +361 33 -4.013758 +362 33 -3.601260 +377 33 -4.505587 +386 33 -8.933010 +402 33 -12.270600 +411 33 -9.015698 +427 33 -12.205057 +436 33 -9.113361 +452 33 -12.148988 +461 33 -9.226439 +477 33 -12.102409 +486 33 -9.355433 +34 34 1.400559 +319 34 0.065746 +321 34 0.065746 +322 34 0.065746 +324 34 0.147929 +327 34 0.065746 +328 34 0.147929 +329 34 0.147929 +337 34 0.147929 +338 34 0.147929 +342 34 0.147929 +361 34 -5.043728 +362 34 -2.627440 +386 34 -9.020703 +406 34 -8.099589 +411 34 -9.128025 +431 34 -10.751085 +436 34 -9.251108 +456 34 -10.756038 +460 34 -14.869824 +461 34 -9.390506 +481 34 -10.773038 +485 34 -21.819119 +486 34 -9.546845 +35 35 2.074458 +320 35 0.147929 +323 35 0.147929 +324 35 0.591716 +326 35 0.591716 +329 35 0.065746 +330 35 0.065746 +337 35 0.065746 +341 35 0.147929 +481 35 -67.791057 +36 36 1.778600 +320 36 0.065746 +321 36 0.147929 +322 36 0.065746 +324 36 0.147929 +328 36 0.147929 +336 36 0.147929 +337 36 0.591716 +339 36 0.147929 +341 36 0.065746 +356 36 -17.195725 +357 36 -33.051273 +358 36 -33.062455 +359 36 -33.075362 +360 36 -33.090347 +361 36 -33.107859 +362 36 -0.962075 +380 36 -49.510780 +381 36 -226.463786 +382 36 -21.608644 +404 36 -3.255058 +405 36 -47.290752 +406 36 -174.872860 +407 36 -22.762807 +408 36 -36.230486 +409 36 -4.453979 +429 36 -14.833117 +430 36 -36.420267 +431 36 -50.489970 +432 36 -127.818852 +434 36 -32.080403 +435 36 -17.333106 +453 36 -10.314909 +454 36 -5.050658 +455 36 -36.660328 +456 36 -36.025557 +457 36 -137.656732 +460 36 -14.288346 +477 36 -3.944144 +478 36 -11.978916 +480 36 -36.939436 +481 36 -31.189397 +482 36 -36.281011 +483 36 -101.912482 +37 37 5.345332 +319 37 0.147929 +320 37 0.591716 +321 37 0.147929 +322 37 0.591716 +323 37 0.591716 +324 37 0.591716 +326 37 0.147929 +328 37 0.147929 +329 37 0.591716 +332 37 0.147929 +333 37 0.065746 +337 37 0.591716 +339 37 0.147929 +341 37 0.591716 +361 37 -8.066180 +362 37 -9.038622 +377 37 -4.503474 +386 37 -20.051608 +402 37 -12.265852 +406 37 -18.223794 +411 37 -20.222362 +427 37 -12.201807 +431 37 -24.216354 +436 37 -20.426396 +452 37 -12.147222 +456 37 -24.258069 +460 37 -14.685008 +461 37 -20.664620 +477 37 -12.102114 +481 37 -24.326953 +485 37 -21.493667 +486 37 -20.938095 +38 38 1.696417 +319 38 0.147929 +320 38 0.147929 +321 38 0.147929 +326 38 0.065746 +328 38 0.147929 +330 38 0.065746 +332 38 0.147929 +333 38 0.065746 +334 38 0.147929 +337 38 0.065746 +341 38 0.147929 +342 38 0.147929 +361 38 -19.731781 +362 38 -1.624135 +377 38 -4.514441 +386 38 -25.869457 +402 38 -12.401189 +406 38 -20.699218 +410 38 -18.932009 +411 38 -8.101620 +426 38 -3.024245 +427 38 -9.467112 +431 38 -28.105110 +435 38 -28.301048 +451 38 -12.590825 +455 38 -21.440253 +456 38 -7.410322 +459 38 -26.571090 +460 38 -23.792087 +476 38 -12.699513 +480 38 -29.642978 +483 38 -9.830409 +484 38 -34.176393 +485 38 -18.588203 +39 39 1.499178 +321 39 0.591716 +322 39 0.147929 +333 39 0.147929 +337 39 0.147929 +341 39 0.065746 +342 39 0.147929 +361 39 -110.279685 +362 39 -4.817527 +377 39 -20.734382 +385 39 -90.337375 +386 39 -53.407407 +402 39 -4.576064 +403 39 -37.753811 +404 39 -11.639795 +409 39 -85.540701 +410 39 -69.764831 +429 39 -26.441754 +430 39 -23.702301 +433 39 -96.479364 +434 39 -71.670516 +455 39 -14.761797 +456 39 -31.803827 +457 39 -123.999913 +458 39 -58.360781 +481 39 -50.680972 +482 39 -84.947374 +40 40 5.641190 +320 40 0.065746 +321 40 0.147929 +322 40 0.147929 +323 40 0.147929 +326 40 0.591716 +327 40 0.591716 +328 40 0.147929 +329 40 0.147929 +330 40 0.591716 +332 40 0.591716 +333 40 0.591716 +335 40 0.147929 +338 40 0.591716 +339 40 0.147929 +341 40 0.591716 +342 40 0.147929 +362 40 -18.482491 +377 40 -63.421393 +387 40 -21.049684 +402 40 -51.040100 +403 40 -116.749562 +412 40 -20.581967 +428 40 -55.323594 +429 40 -104.487007 +437 40 -20.159220 +454 40 -70.987705 +455 40 -81.227147 +460 40 -10.019620 +461 40 -6.124387 +462 40 -7.670096 +463 40 -12.109049 +480 40 -98.364707 +481 40 -46.666176 +486 40 -22.859938 +488 40 -19.439670 +41 41 2.304569 +319 41 0.147929 +322 41 0.147929 +323 41 0.591716 +324 41 0.065746 +333 41 0.065746 +336 41 0.147929 +337 41 0.591716 +341 41 0.147929 +342 41 0.147929 +377 41 -4.505089 +402 41 -12.269479 +406 41 -19.159891 +427 41 -12.204287 +431 41 -25.789474 +452 41 -12.148565 +456 41 -26.213901 +477 41 -12.102331 +480 41 -15.536908 +481 41 -11.135896 +42 42 5.427515 +319 42 0.147929 +320 42 0.591716 +321 42 0.147929 +322 42 0.591716 +323 42 0.591716 +327 42 0.591716 +328 42 0.147929 +329 42 0.591716 +330 42 0.591716 +337 42 0.591716 +341 42 0.591716 +361 42 -14.519357 +362 42 -3.323787 +386 42 -21.133828 +406 42 -18.588927 +411 42 -21.552363 +431 42 -24.894795 +436 42 -22.014367 +456 42 -25.159726 +460 42 -22.839353 +461 42 -15.381330 +481 42 -25.454783 +485 42 -46.295135 +43 43 6.084977 +319 43 0.065746 +320 43 0.591716 +321 43 0.147929 +322 43 0.591716 +323 43 0.591716 +324 43 0.591716 +328 43 0.591716 +329 43 0.147929 +330 43 0.591716 +337 43 0.591716 +339 43 0.591716 +341 43 0.591716 +342 43 0.147929 +361 43 -10.201485 +362 43 -6.982595 +386 43 -20.179427 +406 43 -8.106022 +411 43 -20.389275 +431 43 -10.784684 +436 43 -20.633530 +456 43 -10.818276 +460 43 -59.215500 +461 43 -20.913289 +481 43 -10.864019 +485 43 -86.816621 +486 43 -21.229800 +44 44 6.019231 +319 44 0.591716 +320 44 0.147929 +321 44 0.147929 +322 44 0.591716 +323 44 0.591716 +324 44 0.147929 +327 44 0.591716 +328 44 0.147929 +329 44 0.591716 +330 44 0.591716 +335 44 0.147929 +337 44 0.147929 +339 44 0.591716 +341 44 0.591716 +342 44 0.147929 +361 44 -15.770933 +362 44 -2.621876 +386 44 -21.889499 +406 44 -76.494962 +411 44 -22.439137 +431 44 -102.935979 +435 44 -3.356098 +436 44 -19.684029 +456 44 -104.598601 +460 44 -40.112588 +480 44 -56.184500 +481 44 -50.213511 +485 44 -48.812055 +45 45 1.647107 +320 45 0.065746 +322 45 0.147929 +324 45 0.147929 +329 45 0.147929 +336 45 0.147929 +337 45 0.147929 +338 45 0.147929 +339 45 0.147929 +341 45 0.147929 +342 45 0.147929 +379 45 -98.773841 +403 45 -12.720175 +404 45 -189.623080 +405 45 -89.127183 +428 45 -61.255581 +429 45 -63.678114 +430 45 -123.270081 +431 45 -38.599475 +452 45 -22.981646 +453 45 -40.893243 +454 45 -52.134496 +455 45 -85.950130 +456 45 -51.073977 +457 45 -29.610458 +476 45 -3.902438 +477 45 -48.199866 +478 45 -13.459352 +479 45 -52.300952 +480 45 -11.535572 +481 45 -100.756870 +482 45 -27.072676 +483 45 -21.760883 +46 46 1.071828 +320 46 0.065746 +321 46 0.065746 +322 46 0.065746 +324 46 0.147929 +329 46 0.065746 +337 46 0.147929 +338 46 0.065746 +339 46 0.065746 +341 46 0.065746 +342 46 0.065746 +360 46 -5.300417 +361 46 -15.703519 +362 46 -0.457851 +383 46 -2.733954 +384 46 -15.521635 +385 46 -10.304363 +406 46 -4.957611 +407 46 -15.390490 +408 46 -12.717033 +429 46 -19.816396 +430 46 -15.293127 +431 46 -10.380728 +453 46 -14.792027 +454 46 -137.433488 +455 46 -17.287376 +477 46 -2.746153 +478 46 -27.426484 +479 46 -33.357521 +480 46 -93.817949 +481 46 -8.368114 +47 47 4.819362 +320 47 0.147929 +321 47 0.591716 +322 47 0.591716 +323 47 0.591716 +324 47 0.147929 +329 47 0.591716 +330 47 0.591716 +333 47 0.065746 +336 47 0.065746 +337 47 0.591716 +342 47 0.591716 +361 47 -79.634950 +362 47 -6.413653 +377 47 -6.846513 +386 47 -104.314764 +402 47 -6.133039 +403 47 -12.009546 +410 47 -80.665512 +411 47 -28.434643 +428 47 -7.532416 +429 47 -9.789751 +435 47 -114.311458 +454 47 -10.181533 +455 47 -6.358668 +459 47 -115.429887 +460 47 -4.548613 +480 47 -14.136051 +481 47 -1.663387 +483 47 -51.365148 +484 47 -74.765363 +48 48 1.121137 +320 48 0.147929 +322 48 0.065746 +324 48 0.147929 +329 48 0.147929 +337 48 0.065746 +341 48 0.147929 +342 48 0.147929 +431 48 -46.733912 +455 48 -35.415755 +456 48 -117.551111 +457 48 -26.048194 +479 48 -21.940921 +480 48 -31.275797 +481 48 -55.921830 +482 48 -53.332503 +483 48 -15.707034 +49 49 1.055391 +319 49 0.147929 +320 49 0.147929 +322 49 0.065746 +324 49 0.147929 +326 49 0.147929 +337 49 0.147929 +406 49 -19.034662 +431 49 -25.596835 +456 49 -25.990362 +480 49 -10.070856 +481 49 -16.346546 +50 50 2.156640 +319 50 0.147929 +320 50 0.147929 +324 50 0.147929 +326 50 0.065746 +328 50 0.065746 +332 50 0.591716 +334 50 0.147929 +335 50 0.147929 +336 50 0.147929 +337 50 0.147929 +339 50 0.147929 +406 50 -20.799257 +431 50 -28.254075 +455 50 -22.705328 +456 50 -6.313395 +460 50 -9.495067 +480 50 -29.831163 +484 50 -6.980270 +485 50 -7.485079 +51 51 1.055391 +319 51 0.065746 +321 51 0.147929 +325 51 0.147929 +326 51 0.147929 +340 51 0.147929 +341 51 0.147929 +361 51 -20.228518 +362 51 -1.568580 +386 51 -26.460454 +406 51 -9.276369 +410 51 -22.334460 +411 51 -5.381311 +431 51 -12.605374 +434 51 -2.320426 +435 51 -26.763167 +444 51 -25.951377 +455 51 -15.960022 +456 51 -8.534256 +459 51 -30.571842 +469 51 -27.896355 +470 51 -7.601628 +480 51 -43.460308 +483 51 -18.160139 +484 51 -14.028071 +495 51 -35.061679 +52 52 1.860782 +319 52 0.147929 +320 52 0.147929 +321 52 0.147929 +324 52 0.065746 +326 52 0.147929 +328 52 0.147929 +330 52 0.147929 +333 52 0.147929 +335 52 0.147929 +337 52 0.147929 +339 52 0.065746 +341 52 0.147929 +361 52 -20.145268 +362 52 -1.577341 +377 52 -10.124081 +386 52 -26.360636 +402 52 -27.795374 +406 52 -20.793876 +410 52 -21.777414 +411 52 -5.823086 +427 52 -27.974791 +431 52 -28.246065 +434 52 -1.432575 +435 52 -27.518702 +451 52 -28.077937 +452 52 -0.097080 +455 52 -22.638554 +456 52 -6.371129 +459 52 -30.420765 +460 52 -21.331865 +476 52 -28.395900 +480 52 -29.821048 +483 52 -16.789944 +484 52 -30.800801 +485 52 -16.919676 +53 53 3.685240 +319 53 0.147929 +320 53 0.591716 +321 53 0.147929 +322 53 0.065746 +323 53 0.147929 +324 53 0.147929 +326 53 0.147929 +327 53 0.065746 +329 53 0.065746 +330 53 0.065746 +332 53 0.065746 +333 53 0.147929 +337 53 0.591716 +338 53 0.147929 +339 53 0.147929 +341 53 0.147929 +342 53 0.591716 +361 53 -14.313914 +362 53 -3.461349 +377 53 -10.014786 +386 53 -21.039114 +402 53 -27.385437 +406 53 -18.547622 +411 53 -21.439990 +427 53 -27.401874 +431 53 -24.827427 +436 53 -21.883390 +452 53 -27.438798 +456 53 -25.077809 +460 53 -3.849293 +461 53 -18.522090 +477 53 -27.496196 +481 53 -25.358003 +485 53 -22.906210 +54 54 5.706936 +319 54 0.591716 +320 54 0.591716 +321 54 0.147929 +322 54 0.065746 +323 54 0.147929 +324 54 0.147929 +326 54 0.147929 +327 54 0.147929 +328 54 0.065746 +329 54 0.591716 +330 54 0.591716 +332 54 0.147929 +333 54 0.147929 +338 54 0.591716 +339 54 0.147929 +341 54 0.591716 +342 54 0.591716 +361 54 -14.320749 +362 54 -3.456679 +377 54 -10.014750 +386 54 -21.042140 +402 54 -27.386135 +406 54 -74.201620 +411 54 -21.443587 +427 54 -27.403736 +431 54 -99.327946 +436 54 -21.887587 +452 54 -27.441824 +456 54 -100.333489 +460 54 -10.897401 +461 54 -18.417792 +477 54 -27.500383 +481 54 -101.458367 +485 54 -33.167098 +55 55 2.781229 +319 55 0.065746 +320 55 0.147929 +321 55 0.065746 +322 55 0.065746 +323 55 0.065746 +324 55 0.591716 +326 55 0.591716 +329 55 0.065746 +332 55 0.065746 +333 55 0.065746 +336 55 0.147929 +338 55 0.591716 +361 55 -6.254351 +362 55 -1.613529 +377 55 -8.199372 +386 55 -9.305509 +402 55 -3.531790 +403 55 -17.541360 +404 55 -0.428142 +406 55 -4.513915 +407 55 -5.371182 +411 55 -9.475048 +429 55 -17.325341 +430 55 -2.879626 +432 55 -12.748149 +436 55 -9.663040 +455 55 -15.124218 +456 55 -3.857234 +457 55 -7.931850 +458 55 -4.409279 +460 55 -0.006368 +461 55 -9.863991 +481 55 -14.444965 +482 55 -3.391800 +483 55 -11.961533 +485 55 -10.097953 +56 56 1.860782 +320 56 0.147929 +322 56 0.147929 +323 56 0.147929 +324 56 0.147929 +326 56 0.147929 +327 56 0.147929 +329 56 0.147929 +332 56 0.147929 +336 56 0.065746 +337 56 0.147929 +341 56 0.065746 +342 56 0.147929 +430 56 -205.426508 +431 56 -5.726831 +454 56 -70.905286 +455 56 -165.919726 +456 56 -83.641404 +457 56 -2.763457 +478 56 -28.820964 +479 56 -71.170527 +480 56 -99.558918 +481 56 -78.678543 +482 56 -43.564410 +57 57 5.641190 +319 57 0.147929 +320 57 0.591716 +322 57 0.065746 +323 57 0.147929 +324 57 0.147929 +326 57 0.147929 +327 57 0.591716 +329 57 0.591716 +330 57 0.591716 +332 57 0.147929 +333 57 0.147929 +337 57 0.591716 +338 57 0.591716 +339 57 0.147929 +341 57 0.591716 +342 57 0.147929 +377 57 -10.014828 +402 57 -27.384852 +406 57 -18.545059 +427 57 -27.400265 +431 57 -24.823224 +452 57 -27.436168 +456 57 -25.072678 +477 57 -27.492546 +481 57 -25.351925 +58 58 2.518245 +319 58 0.147929 +320 58 0.065746 +322 58 0.065746 +324 58 0.147929 +326 58 0.591716 +328 58 0.591716 +329 58 0.147929 +338 58 0.147929 +339 58 0.147929 +341 58 0.065746 +342 58 0.147929 +376 58 -222.657604 +377 58 -106.117424 +378 58 -32.984077 +379 58 -12.016942 +400 58 -8.070001 +401 58 -270.024618 +402 58 -138.475361 +403 58 -133.752017 +404 58 -154.843657 +405 58 -167.002305 +406 58 -122.370814 +425 58 -13.910080 +426 58 -160.645139 +427 58 -106.206667 +428 58 -63.089901 +429 58 -3.079225 +431 58 -38.836316 +432 58 -134.342669 +433 58 -134.548526 +434 58 -133.487308 +449 58 -1.282085 +450 58 -12.856128 +451 58 -40.824591 +452 58 -143.159985 +453 58 -76.000687 +454 58 -56.840889 +455 58 -7.272287 +459 58 -1.299752 +460 58 -115.826749 +474 58 -14.374296 +475 58 -8.780397 +476 58 -29.199747 +477 58 -131.320148 +478 58 -50.669460 +479 58 -40.611079 +480 58 -46.824378 +481 58 -8.241846 +499 58 -14.617538 +500 58 -28.466389 +59 59 1.729290 +319 59 0.147929 +320 59 0.147929 +323 59 0.147929 +324 59 0.147929 +335 59 0.147929 +337 59 0.147929 +338 59 0.147929 +339 59 0.147929 +341 59 0.147929 +342 59 0.147929 +406 59 -19.284057 +431 59 -25.979335 +456 59 -26.433110 +480 59 -20.211682 +481 59 -6.710637 +60 60 3.833169 +319 60 0.147929 +320 60 0.147929 +321 60 0.065746 +322 60 0.147929 +323 60 0.591716 +324 60 0.065746 +326 60 0.147929 +327 60 0.591716 +328 60 0.147929 +329 60 0.147929 +333 60 0.065746 +334 60 0.591716 +335 60 0.065746 +337 60 0.147929 +338 60 0.147929 +339 60 0.147929 +341 60 0.147929 +342 60 0.065746 +361 60 -7.266940 +362 60 -1.056421 +377 60 -4.531172 +386 60 -9.930565 +402 60 -12.454076 +406 60 -19.471928 +411 60 -10.207594 +426 60 -5.583511 +427 60 -6.971240 +431 60 -26.264939 +435 60 -5.048813 +436 60 -5.460870 +451 60 -12.664788 +456 60 -26.761233 +460 60 -27.683659 +476 60 -12.784088 +480 60 -26.248698 +481 60 -1.045727 +485 60 -36.302550 +61 61 4.687870 +320 61 0.591716 +322 61 0.591716 +323 61 0.147929 +324 61 0.591716 +326 61 0.591716 +328 61 0.591716 +329 61 0.147929 +337 61 0.147929 +338 61 0.147929 +339 61 0.147929 +341 61 0.591716 +342 61 0.147929 +460 61 -59.195636 +485 61 -86.781814 +62 62 1.910092 +319 62 0.147929 +322 62 0.147929 +323 62 0.147929 +324 62 0.065746 +326 62 0.065746 +328 62 0.065746 +329 62 0.147929 +332 62 0.147929 +334 62 0.147929 +335 62 0.147929 +336 62 0.147929 +337 62 0.065746 +339 62 0.065746 +342 62 0.147929 +406 62 -18.356880 +431 62 -24.257259 +456 62 -9.858349 +457 62 -14.286437 +460 62 -6.578521 +482 62 -24.060070 +485 62 -9.644576 +63 63 3.257890 +319 63 0.147929 +320 63 0.591716 +322 63 0.147929 +323 63 0.147929 +324 63 0.065746 +327 63 0.147929 +328 63 0.065746 +330 63 0.147929 +334 63 0.147929 +335 63 0.065746 +337 63 0.591716 +338 63 0.591716 +341 63 0.147929 +406 63 -18.883705 +431 63 -25.362607 +456 63 -25.716598 +460 63 -7.153144 +480 63 -2.088591 +481 63 -24.014362 +485 63 -10.610042 +64 64 1.466305 +319 64 0.147929 +320 64 0.065746 +324 64 0.147929 +327 64 0.147929 +332 64 0.065746 +334 64 0.065746 +335 64 0.065746 +336 64 0.147929 +337 64 0.065746 +338 64 0.147929 +339 64 0.147929 +406 64 -18.297963 +431 64 -24.393933 +456 64 -24.526376 +481 64 -24.686684 +65 65 6.084977 +319 65 0.065746 +320 65 0.591716 +322 65 0.591716 +323 65 0.591716 +324 65 0.591716 +325 65 0.147929 +327 65 0.591716 +329 65 0.147929 +332 65 0.591716 +333 65 0.147929 +334 65 0.147929 +337 65 0.591716 +338 65 0.147929 +339 65 0.147929 +341 65 0.591716 +342 65 0.147929 +377 65 -10.103789 +402 65 -27.533988 +406 65 -8.104770 +427 65 -27.412003 +431 65 -10.781306 +444 65 -24.345457 +452 65 -27.311119 +456 65 -10.812932 +469 65 -33.409349 +477 65 -27.231371 +481 65 -10.856697 +494 65 -15.284216 +495 65 -17.847314 +66 66 2.896285 +319 66 0.065746 +320 66 0.147929 +321 66 0.065746 +323 66 0.147929 +324 66 0.147929 +327 66 0.147929 +329 66 0.147929 +339 66 0.591716 +341 66 0.591716 +342 66 0.591716 +361 66 -6.086518 +362 66 -1.737442 +386 66 -9.243464 +406 66 -8.194424 +411 66 -9.400764 +431 66 -10.952775 +436 66 -9.575913 +456 66 -11.044782 +461 66 -9.769719 +481 66 -11.149664 +485 66 -7.379346 +486 66 -2.603719 +67 67 1.630671 +319 67 0.147929 +320 67 0.147929 +321 67 0.065746 +322 67 0.147929 +324 67 0.147929 +327 67 0.147929 +328 67 0.065746 +329 67 0.065746 +339 67 0.147929 +341 67 0.147929 +342 67 0.147929 +361 67 -6.105527 +362 67 -1.723038 +386 67 -9.249996 +406 67 -18.442142 +411 67 -9.408609 +431 67 -24.651715 +436 67 -9.585134 +456 67 -24.860753 +460 67 -6.842637 +461 67 -9.780387 +481 67 -25.098796 +485 67 -17.777734 +486 67 -2.312124 +68 68 1.252630 +320 68 0.065746 +321 68 0.065746 +322 68 0.147929 +323 68 0.147929 +324 68 0.065746 +327 68 0.147929 +330 68 0.065746 +333 68 0.147929 +341 68 0.147929 +361 68 -11.062230 +362 68 -0.569468 +377 68 -10.298574 +385 68 -6.185843 +386 68 -8.199440 +402 68 -28.342398 +409 68 -2.861670 +410 68 -12.515057 +426 68 -22.857023 +427 68 -5.767723 +433 68 -1.073923 +434 68 -15.395892 +451 68 -28.928535 +457 68 -0.845954 +458 68 -16.825666 +476 68 -29.253428 +481 68 -2.227964 +482 68 -16.759690 +69 69 1.482742 +319 69 0.065746 +320 69 0.147929 +321 69 0.147929 +323 69 0.147929 +324 69 0.065746 +333 69 0.065746 +336 69 0.147929 +339 69 0.147929 +341 69 0.147929 +342 69 0.147929 +361 69 -28.104345 +362 69 -1.192626 +377 69 -4.547179 +385 69 -24.213197 +386 69 -12.445225 +402 69 -12.504086 +406 69 -11.510742 +409 69 -24.196563 +410 69 -15.492393 +426 69 -7.481691 +427 69 -5.132259 +430 69 -10.496468 +431 69 -5.430674 +433 69 -28.234771 +434 69 -14.826366 +451 69 -12.733235 +454 69 -7.054273 +455 69 -9.645606 +457 69 -36.569625 +458 69 -10.226924 +476 69 -12.861824 +478 69 -4.908989 +479 69 -12.607878 +480 69 -11.881770 +481 69 -37.600215 +482 69 -1.424479 +70 70 1.696417 +319 70 0.147929 +320 70 0.147929 +321 70 0.065746 +322 70 0.147929 +323 70 0.147929 +324 70 0.065746 +327 70 0.147929 +336 70 0.147929 +338 70 0.065746 +339 70 0.147929 +341 70 0.065746 +342 70 0.147929 +361 70 -12.561094 +362 70 -0.528588 +385 70 -10.973466 +386 70 -5.414406 +406 70 -26.123297 +409 70 -11.120106 +410 70 -6.633377 +430 70 -24.486476 +431 70 -11.684420 +433 70 -13.085441 +434 70 -6.188294 +454 70 -17.453589 +455 70 -20.501083 +456 70 -0.122685 +457 70 -16.858210 +458 70 -3.977437 +478 70 -13.346608 +479 70 -26.494032 +480 70 -6.249131 +481 70 -16.563038 +71 71 1.236193 +320 71 0.065746 +324 71 0.147929 +328 71 0.065746 +333 71 0.065746 +336 71 0.065746 +337 71 0.065746 +338 71 0.147929 +339 71 0.065746 +341 71 0.147929 +342 71 0.147929 +377 71 -4.663173 +401 71 -1.810557 +402 71 -11.047210 +426 71 -13.021485 +451 71 -13.195041 +460 71 -11.579610 +476 71 -13.378176 +484 71 -14.447269 +485 71 -3.519299 +500 71 -12.295657 +72 72 4.293393 +319 72 0.065746 +320 72 0.147929 +322 72 0.065746 +324 72 0.147929 +327 72 0.591716 +329 72 0.147929 +330 72 0.591716 +332 72 0.591716 +333 72 0.065746 +334 72 0.591716 +337 72 0.147929 +338 72 0.147929 +341 72 0.147929 +342 72 0.591716 +377 72 -4.451576 +402 72 -12.168821 +406 72 -8.226189 +427 72 -12.170251 +431 72 -11.006074 +452 72 -12.180796 +456 72 -11.110969 +477 72 -12.200451 +481 72 -11.228983 +73 73 1.482742 +319 73 0.147929 +320 73 0.147929 +322 73 0.065746 +324 73 0.065746 +327 73 0.147929 +337 73 0.147929 +338 73 0.147929 +339 73 0.147929 +341 73 0.065746 +342 73 0.147929 +406 73 -25.890662 +430 73 -23.583745 +431 73 -12.239619 +454 73 -15.811472 +455 73 -21.748841 +478 73 -10.957009 +479 73 -28.439723 +74 74 0.611604 +322 74 0.065746 +324 74 0.147929 +330 74 0.147929 +75 75 7.350592 +319 75 0.147929 +320 75 0.591716 +322 75 0.591716 +323 75 0.591716 +324 75 0.591716 +325 75 0.591716 +327 75 0.591716 +329 75 0.591716 +330 75 0.591716 +334 75 0.591716 +337 75 0.591716 +338 75 0.147929 +339 75 0.147929 +341 75 0.591716 +342 75 0.147929 +406 75 -18.532036 +431 75 -24.801828 +444 75 -94.696177 +456 75 -25.046517 +469 75 -130.179284 +481 75 -25.320900 +494 75 -129.372245 +76 76 0.907462 +323 76 0.065746 +334 76 0.591716 +77 77 1.532051 +319 77 0.065746 +321 77 0.065746 +322 77 0.065746 +323 77 0.065746 +324 77 0.065746 +327 77 0.147929 +333 77 0.065746 +337 77 0.147929 +338 77 0.147929 +339 77 0.147929 +341 77 0.147929 +342 77 0.147929 +361 77 -6.713366 +362 77 -1.317953 +377 77 -4.459245 +386 77 -9.532609 +402 77 -12.214667 +406 77 -8.354574 +411 77 -9.743665 +427 77 -12.252534 +431 77 -11.212447 +436 77 -9.975465 +452 77 -12.299513 +456 77 -11.359123 +460 77 -7.360903 +461 77 -2.868210 +476 77 -2.777152 +477 77 -9.578427 +481 77 -11.519892 +485 77 -10.505790 +78 78 2.731920 +319 78 0.065746 +320 78 0.147929 +322 78 0.147929 +323 78 0.065746 +324 78 0.147929 +327 78 0.147929 +329 78 0.147929 +330 78 0.147929 +332 78 0.065746 +333 78 0.065746 +337 78 0.147929 +339 78 0.591716 +341 78 0.591716 +377 78 -4.453740 +402 78 -12.168661 +406 78 -8.194165 +427 78 -12.161205 +431 78 -10.952333 +452 78 -12.162885 +456 78 -11.044228 +477 78 -12.173700 +481 78 -11.148995 +79 79 1.564924 +320 79 0.065746 +321 79 0.147929 +324 79 0.065746 +330 79 0.147929 +333 79 0.147929 +335 79 0.147929 +337 79 0.147929 +338 79 0.147929 +339 79 0.147929 +341 79 0.147929 +361 79 -20.177721 +362 79 -1.573901 +377 79 -10.126945 +386 79 -26.399513 +402 79 -27.804652 +410 79 -21.995163 +411 79 -5.650229 +426 79 -0.586813 +427 79 -27.399384 +434 79 -1.779679 +435 79 -27.223124 +451 79 -28.188562 +459 79 -30.479592 +476 79 -28.411591 +483 79 -17.325258 +484 79 -14.758132 +80 80 1.926529 +319 80 0.065746 +320 80 0.147929 +321 80 0.147929 +323 80 0.147929 +327 80 0.147929 +329 80 0.147929 +330 80 0.147929 +332 80 0.147929 +337 80 0.065746 +338 80 0.065746 +339 80 0.147929 +341 80 0.147929 +342 80 0.147929 +361 80 -10.485294 +362 80 -6.714544 +386 80 -20.204042 +406 80 -8.099141 +411 80 -20.420808 +431 80 -10.760771 +436 80 -20.672201 +456 80 -10.777455 +461 80 -20.959350 +481 80 -10.806209 +486 80 -21.283539 +81 81 3.915352 +320 81 0.591716 +321 81 0.065746 +323 81 0.591716 +326 81 0.591716 +327 81 0.147929 +329 81 0.065746 +330 81 0.147929 +332 81 0.147929 +334 81 0.147929 +335 81 0.147929 +337 81 0.147929 +338 81 0.147929 +339 81 0.065746 +341 81 0.591716 +342 81 0.065746 +361 81 -11.786325 +362 81 -0.546902 +385 81 -8.576971 +386 81 -6.767877 +409 81 -6.984844 +410 81 -9.525732 +433 81 -7.045641 +434 81 -10.756186 +457 81 -8.826667 +458 81 -10.400333 +481 81 -12.416688 +482 81 -8.375015 +82 82 6.594510 +320 82 0.147929 +321 82 0.591716 +323 82 0.065746 +324 82 0.147929 +326 82 0.147929 +327 82 0.147929 +330 82 0.591716 +331 82 0.591716 +332 82 0.147929 +333 82 0.065746 +335 82 0.591716 +336 82 0.147929 +337 82 0.591716 +338 82 0.591716 +339 82 0.591716 +341 82 0.591716 +342 82 0.591716 +361 82 -105.589094 +362 82 -4.935439 +377 82 -4.864080 +385 82 -75.634190 +386 82 -61.818108 +401 82 -6.564811 +402 82 -6.891763 +409 82 -60.175500 +410 82 -87.647191 +426 82 -13.693394 +433 82 -59.501985 +434 82 -99.803727 +450 82 -0.442688 +451 82 -13.498040 +457 82 -74.190929 +458 82 -97.785142 +475 82 -14.197990 +481 82 -105.015906 +482 82 -80.868478 +483 82 -2.491844 +500 82 -14.464465 +83 83 1.614234 +321 83 0.591716 +323 83 0.147929 +324 83 0.065746 +330 83 0.065746 +331 83 0.065746 +337 83 0.147929 +338 83 0.065746 +339 83 0.065746 +342 83 0.147929 +360 83 -63.067907 +361 83 -140.023035 +362 83 -4.080440 +383 83 -63.781125 +384 83 -138.622540 +385 83 -76.195679 +406 83 -114.298733 +407 83 -137.608559 +408 83 -74.295615 +428 83 -85.529550 +429 83 -136.547532 +430 83 -136.853521 +431 83 -22.905643 +453 83 -187.765065 +454 83 -30.730196 +455 83 -15.057012 +456 83 -3.306633 +478 83 -50.259639 +479 83 -102.283702 +480 83 -16.631856 +481 83 -11.778975 +482 83 -15.118480 +483 83 -13.699633 +84 84 2.403189 +319 84 0.147929 +320 84 0.147929 +321 84 0.147929 +322 84 0.147929 +324 84 0.065746 +326 84 0.065746 +329 84 0.065746 +330 84 0.147929 +331 84 0.147929 +332 84 0.147929 +333 84 0.065746 +335 84 0.591716 +337 84 0.065746 +338 84 0.065746 +339 84 0.065746 +342 84 0.065746 +361 84 -16.328849 +362 84 -2.385289 +377 84 -4.527996 +386 84 -22.325610 +402 84 -12.444092 +406 84 -19.452418 +411 84 -22.946025 +426 84 -5.150994 +427 84 -7.391859 +431 84 -26.235361 +435 84 -11.069962 +436 84 -12.552659 +451 84 -12.650964 +456 84 -26.727328 +460 84 -24.358748 +476 84 -12.768330 +480 84 -25.669579 +481 84 -1.586463 +483 84 -0.301054 +485 84 -25.157934 +85 85 2.370316 +320 85 0.147929 +321 85 0.147929 +322 85 0.147929 +324 85 0.147929 +326 85 0.147929 +327 85 0.065746 +329 85 0.147929 +331 85 0.065746 +332 85 0.147929 +335 85 0.147929 +336 85 0.147929 +337 85 0.147929 +338 85 0.147929 +339 85 0.147929 +341 85 0.147929 +342 85 0.065746 +360 85 -22.404288 +361 85 -34.576637 +362 85 -1.006945 +383 85 -33.084470 +384 85 -34.302102 +385 85 -12.023690 +405 85 -25.555455 +406 85 -34.022353 +407 85 -34.102262 +408 85 -1.110175 +429 85 -283.788842 +430 85 -69.941616 +431 85 -0.894851 +453 85 -39.083258 +454 85 -155.618295 +455 85 -174.511192 +456 85 -25.083768 +457 85 -9.221498 +477 85 -11.380801 +478 85 -67.864269 +479 85 -79.406139 +480 85 -154.406313 +481 85 -54.330830 +482 85 -15.262597 +483 85 -14.912926 +86 86 4.819362 +319 86 0.065746 +320 86 0.591716 +322 86 0.591716 +323 86 0.591716 +327 86 0.591716 +329 86 0.591716 +331 86 0.591716 +337 86 0.591716 +339 86 0.147929 +341 86 0.147929 +342 86 0.065746 +406 86 -8.251877 +431 86 -11.048294 +456 86 -11.162606 +481 86 -11.290233 +483 86 -1.114169 +87 87 2.370316 +319 87 0.065746 +320 87 0.591716 +321 87 0.065746 +322 87 0.147929 +327 87 0.147929 +331 87 0.147929 +332 87 0.065746 +335 87 0.147929 +337 87 0.147929 +338 87 0.147929 +339 87 0.147929 +341 87 0.147929 +342 87 0.147929 +361 87 -7.267212 +362 87 -1.056317 +386 87 -9.930792 +406 87 -8.652119 +411 87 -10.207857 +431 87 -11.670166 +435 87 -5.052427 +436 87 -5.457558 +456 87 -11.890283 +460 87 -10.838673 +480 87 -11.604996 +481 87 -0.521786 +483 87 -0.301397 +485 87 -11.195498 +88 88 0.743097 +324 88 0.065746 +332 88 0.147929 +337 88 0.065746 +338 88 0.147929 +342 88 0.065746 +89 89 3.948225 +319 89 0.147929 +320 89 0.591716 +321 89 0.147929 +322 89 0.147929 +324 89 0.591716 +326 89 0.591716 +327 89 0.147929 +332 89 0.147929 +337 89 0.147929 +338 89 0.591716 +339 89 0.147929 +341 89 0.147929 +342 89 0.147929 +361 89 -12.053246 +362 89 -5.275103 +386 89 -20.398930 +406 89 -18.312098 +411 89 -20.665816 +431 89 -24.421019 +436 89 -20.969100 +456 89 -24.563042 +461 89 -21.310155 +481 89 -24.733045 +486 89 -21.690513 +90 90 2.534681 +319 90 0.147929 +320 90 0.147929 +321 90 0.147929 +322 90 0.147929 +323 90 0.147929 +324 90 0.147929 +325 90 0.147929 +326 90 0.147929 +327 90 0.065746 +329 90 0.147929 +335 90 0.147929 +336 90 0.147929 +337 90 0.147929 +339 90 0.147929 +340 90 0.147929 +342 90 0.147929 +360 90 -11.928220 +361 90 -35.332702 +362 90 -1.030157 +383 90 -6.157187 +384 90 -34.923503 +385 90 -23.182341 +405 90 -20.179128 +406 90 -40.319393 +407 90 -34.628453 +408 90 -28.607372 +428 90 -21.803225 +429 90 -63.698519 +430 90 -49.646208 +431 90 -23.346266 +444 90 -26.291328 +445 90 -33.224205 +446 90 -33.233208 +447 90 -33.243457 +448 90 -29.070125 +451 90 -57.457501 +452 90 -72.130662 +453 90 -80.610646 +454 90 -38.934588 +455 90 -33.059122 +456 90 -3.289917 +473 90 -4.184959 +474 90 -33.268244 +475 90 -330.188720 +476 90 -117.167831 +477 90 -33.178349 +499 90 -29.741488 +500 90 -173.244201 +91 91 1.416995 +319 91 0.147929 +320 91 0.147929 +321 91 0.065746 +322 91 0.147929 +324 91 0.147929 +326 91 0.147929 +327 91 0.065746 +332 91 0.147929 +342 91 0.147929 +361 91 -6.259095 +362 91 -1.610138 +386 91 -9.307412 +406 91 -18.495422 +411 91 -9.477318 +431 91 -24.741245 +436 91 -9.665697 +456 91 -24.972050 +460 91 -0.081185 +461 91 -9.792238 +481 91 -25.232269 +485 91 -10.101446 +92 92 2.140204 +321 92 0.065746 +322 92 0.065746 +323 92 0.147929 +324 92 0.147929 +325 92 0.147929 +326 92 0.147929 +327 92 0.065746 +329 92 0.147929 +332 92 0.147929 +335 92 0.147929 +336 92 0.147929 +337 92 0.147929 +339 92 0.065746 +341 92 0.147929 +342 92 0.147929 +359 92 -3.232121 +360 92 -15.025366 +361 92 -15.063457 +362 92 -0.438230 +381 92 -6.952400 +382 92 -14.941191 +383 92 -14.965166 +384 92 -11.760831 +401 92 -1.881657 +402 92 -33.325654 +403 92 -33.347538 +404 92 -33.372370 +405 92 -130.204014 +406 92 -186.463857 +421 92 -31.557225 +422 92 -33.248935 +423 92 -33.260749 +424 92 -33.274121 +425 92 -33.289240 +426 92 -31.424671 +429 92 -4.437851 +430 92 -132.552892 +431 92 -148.595331 +432 92 -31.766655 +444 92 -26.295328 +445 92 -33.229372 +446 92 -1.681295 +454 92 -51.060901 +455 92 -110.836573 +456 92 -77.679153 +457 92 -54.569660 +458 92 -21.120072 +478 92 -26.464970 +479 92 -36.382168 +480 92 -101.779294 +481 92 -46.263531 +482 92 -68.610553 +483 92 -24.294658 +484 92 -9.939892 +93 93 7.712196 +319 93 0.147929 +320 93 0.147929 +322 93 0.591716 +323 93 0.591716 +324 93 0.147929 +325 93 0.591716 +327 93 0.591716 +329 93 0.591716 +330 93 0.147929 +332 93 0.591716 +333 93 0.065746 +334 93 0.147929 +337 93 0.591716 +338 93 0.591716 +339 93 0.591716 +340 93 0.147929 +341 93 0.591716 +342 93 0.591716 +377 93 -4.519639 +402 93 -12.302592 +406 93 -18.222762 +427 93 -12.227692 +431 93 -24.195086 +444 93 -98.650379 +452 93 -12.162353 +456 93 -33.893291 +469 93 -135.281367 +477 93 -12.106598 +481 93 -49.029173 +494 93 -35.074263 +495 93 -98.964117 +94 94 4.441321 +319 94 0.147929 +320 94 0.591716 +322 94 0.147929 +323 94 0.591716 +324 94 0.147929 +326 94 0.147929 +327 94 0.591716 +330 94 0.591716 +332 94 0.147929 +333 94 0.065746 +334 94 0.147929 +335 94 0.065746 +337 94 0.147929 +338 94 0.147929 +339 94 0.147929 +340 94 0.147929 +341 94 0.147929 +342 94 0.065746 +377 94 -4.471931 +402 94 -12.261090 +406 94 -18.954366 +427 94 -12.316179 +431 94 -25.472563 +451 94 -1.930619 +452 94 -10.449801 +456 94 -36.034300 +476 94 -12.453772 +480 94 -31.965161 +481 94 -20.623106 +95 95 2.830539 +320 95 0.147929 +321 95 0.591716 +322 95 0.147929 +323 95 0.147929 +325 95 0.147929 +327 95 0.147929 +329 95 0.147929 +332 95 0.147929 +335 95 0.065746 +336 95 0.147929 +338 95 0.147929 +341 95 0.591716 +360 95 -53.421193 +361 95 -140.811938 +362 95 -4.104676 +383 95 -39.143528 +384 95 -139.269511 +385 95 -86.553776 +406 95 -70.372840 +407 95 -138.155538 +408 95 -99.526073 +423 95 -10.748523 +424 95 -32.957510 +425 95 -32.959869 +426 95 -32.962533 +427 95 -32.965541 +428 95 -32.968943 +429 95 -40.925332 +430 95 -275.827678 +431 95 -67.339298 +444 95 -26.079432 +445 95 -32.950509 +446 95 -32.951942 +447 95 -32.953572 +448 95 -22.206897 +454 95 -92.958537 +455 95 -250.441858 +478 95 -42.221314 +479 95 -92.622103 +480 95 -183.066746 +481 95 -27.870242 +96 96 3.044214 +321 96 0.591716 +324 96 0.147929 +325 96 0.591716 +326 96 0.147929 +332 96 0.147929 +335 96 0.065746 +336 96 0.147929 +337 96 0.147929 +338 96 0.147929 +341 96 0.591716 +342 96 0.065746 +360 96 -43.153435 +361 96 -141.776352 +362 96 -4.134335 +383 96 -13.068223 +384 96 -140.057874 +385 96 -97.689660 +406 96 -24.268532 +407 96 -138.820523 +408 96 -126.322907 +425 96 -120.807368 +426 96 -131.734316 +427 96 -131.740949 +428 96 -131.748448 +429 96 -131.756940 +430 96 -227.359359 +431 96 -114.060353 +444 96 -104.244744 +445 96 -131.707797 +446 96 -131.710958 +447 96 -131.714554 +448 96 -131.718630 +449 96 -131.723238 +450 96 -10.921074 +455 96 -292.810901 +456 96 -10.617923 +479 96 -25.281350 +480 96 -198.998426 +481 96 -68.210616 +482 96 -6.716299 +97 97 3.109961 +320 97 0.147929 +321 97 0.065746 +322 97 0.147929 +324 97 0.591716 +325 97 0.147929 +326 97 0.591716 +327 97 0.147929 +332 97 0.591716 +337 97 0.065746 +338 97 0.147929 +341 97 0.065746 +342 97 0.147929 +361 97 -8.476947 +362 97 -0.760826 +386 97 -11.157861 +410 97 -6.261445 +411 97 -5.361901 +435 97 -12.129668 +444 97 -32.518999 +445 97 -5.167278 +459 97 -7.856989 +460 97 -4.822646 +470 97 -36.172943 +471 97 -14.555938 +484 97 -13.276053 +496 97 -27.113529 +497 97 -21.955064 +98 98 1.729290 +320 98 0.147929 +321 98 0.591716 +326 98 0.147929 +328 98 0.147929 +332 98 0.147929 +335 98 0.147929 +341 98 0.147929 +360 98 -59.137274 +361 98 -140.331983 +362 98 -4.089929 +383 98 -53.725544 +384 98 -138.876129 +385 98 -80.405035 +406 98 -96.328763 +407 98 -137.823089 +408 98 -84.583654 +430 98 -210.374305 +431 98 -74.151345 +432 98 -33.088664 +433 98 -33.102598 +434 98 -4.682540 +455 98 -130.148369 +459 98 -28.436145 +460 98 -28.420668 +480 98 -122.653711 +481 98 -6.578216 +99 99 3.044214 +319 99 0.147929 +320 99 0.147929 +322 99 0.147929 +323 99 0.591716 +324 99 0.147929 +326 99 0.147929 +327 99 0.147929 +329 99 0.147929 +331 99 0.065746 +332 99 0.147929 +334 99 0.147929 +335 99 0.147929 +337 99 0.065746 +338 99 0.147929 +340 99 0.147929 +341 99 0.147929 +342 99 0.147929 +406 99 -19.108783 +431 99 -25.711011 +455 99 -0.529976 +456 99 -35.883730 +480 99 -40.037364 +481 99 -13.159236 +483 99 -0.130433 +100 100 4.359139 +320 100 0.147929 +321 100 0.065746 +322 100 0.591716 +324 100 0.147929 +325 100 0.065746 +326 100 0.147929 +327 100 0.147929 +328 100 0.065746 +329 100 0.591716 +332 100 0.147929 +334 100 0.065746 +335 100 0.147929 +337 100 0.147929 +338 100 0.147929 +339 100 0.147929 +340 100 0.591716 +341 100 0.591716 +342 100 0.147929 +361 100 -7.174775 +362 100 -1.092917 +386 100 -9.855176 +411 100 -10.120111 +435 100 -3.805990 +436 100 -6.603269 +444 100 -10.162595 +455 100 -5.944152 +456 100 -35.745603 +460 100 -18.140293 +469 100 -14.016751 +480 100 -108.004609 +485 100 -22.108970 +494 100 -13.984932 +101 101 2.419625 +319 101 0.147929 +320 101 0.065746 +321 101 0.065746 +322 101 0.065746 +324 101 0.147929 +325 101 0.147929 +326 101 0.147929 +327 101 0.147929 +328 101 0.065746 +332 101 0.147929 +335 101 0.147929 +336 101 0.147929 +337 101 0.065746 +338 101 0.147929 +339 101 0.147929 +340 101 0.147929 +341 101 0.147929 +342 101 0.065746 +361 101 -13.992050 +362 101 -0.504729 +385 101 -15.128502 +386 101 -3.223544 +406 101 -27.403435 +408 101 -1.579275 +409 101 -16.726444 +410 101 -1.818414 +430 101 -29.199821 +431 101 -8.887809 +432 101 -7.151022 +433 101 -14.963797 +444 101 -27.428456 +445 101 -34.695541 +446 101 -8.715563 +454 101 -25.980944 +455 101 -30.596440 +456 101 -18.844015 +457 101 -9.237813 +459 101 -11.435994 +460 101 -13.038565 +471 101 -26.033028 +472 101 -34.809230 +473 101 -30.827601 +478 101 -25.779904 +479 101 -59.659007 +480 101 -37.171710 +481 101 -8.938682 +482 101 -15.082077 +483 101 -15.117140 +484 101 -3.721880 +498 101 -4.050738 +499 101 -34.956970 +500 101 -35.046396 +102 102 1.942965 +320 102 0.147929 +321 102 0.147929 +322 102 0.147929 +324 102 0.591716 +328 102 0.147929 +329 102 0.065746 +337 102 0.147929 +339 102 0.147929 +342 102 0.147929 +361 102 -8.615201 +362 102 -8.505016 +386 102 -20.077115 +411 102 -20.256176 +436 102 -20.468739 +460 102 -14.704658 +461 102 -20.715754 +485 102 -21.528825 +486 102 -20.998322 +103 103 1.614234 +320 103 0.147929 +321 103 0.147929 +324 103 0.147929 +327 103 0.065746 +328 103 0.065746 +329 103 0.147929 +335 103 0.065746 +336 103 0.147929 +337 103 0.065746 +339 103 0.147929 +341 103 0.147929 +342 103 0.065746 +360 103 -13.146001 +361 103 -35.221367 +362 103 -1.026734 +383 103 -9.252961 +384 103 -34.832430 +385 103 -21.864303 +406 103 -16.647193 +407 103 -34.551595 +408 103 -25.428223 +429 103 -0.788458 +430 103 -147.823276 +431 103 -32.480901 +432 103 -14.692807 +433 103 -14.349499 +454 103 -42.658560 +455 103 -161.761600 +456 103 -19.732245 +458 103 -0.348524 +459 103 -14.704044 +460 103 -12.617186 +478 103 -12.746831 +479 103 -42.258308 +480 103 -85.523979 +481 103 -70.178803 +482 103 -11.782938 +104 104 1.170447 +320 104 0.065746 +321 104 0.065746 +324 104 0.065746 +327 104 0.065746 +329 104 0.065746 +336 104 0.147929 +339 104 0.147929 +341 104 0.147929 +342 104 0.147929 +360 104 -6.148771 +361 104 -15.627409 +362 104 -0.455511 +383 104 -4.892270 +384 104 -15.459349 +385 104 -9.387456 +406 104 -8.784202 +407 104 -15.337909 +408 104 -10.501686 +429 104 -1.103903 +430 104 -104.065284 +431 104 -6.505356 +454 104 -25.418606 +455 104 -114.433477 +456 104 -31.918344 +478 104 -6.225577 +479 104 -32.558510 +480 104 -55.704473 +481 104 -47.262110 +482 104 -27.595647 +105 105 2.518245 +319 105 0.147929 +323 105 0.147929 +324 105 0.147929 +326 105 0.065746 +327 105 0.591716 +329 105 0.147929 +332 105 0.065746 +334 105 0.147929 +335 105 0.147929 +338 105 0.065746 +342 105 0.591716 +406 105 -19.173624 +431 105 -25.810524 +456 105 -26.238255 +480 105 -16.086648 +481 105 -10.613920 +106 106 2.978468 +319 106 0.147929 +320 106 0.147929 +321 106 0.147929 +322 106 0.065746 +323 106 0.147929 +324 106 0.147929 +326 106 0.147929 +328 106 0.147929 +329 106 0.147929 +332 106 0.147929 +334 106 0.147929 +337 106 0.147929 +338 106 0.147929 +339 106 0.147929 +341 106 0.591716 +342 106 0.147929 +361 106 -10.916201 +362 106 -6.311126 +386 106 -20.246528 +406 106 -18.260069 +411 106 -20.474874 +431 106 -24.316468 +436 106 -20.738229 +456 106 -24.417693 +460 106 -14.870580 +461 106 -21.037778 +481 106 -24.546460 +485 106 -21.820431 +486 106 -21.374862 +107 107 2.600427 +320 107 0.147929 +321 107 0.591716 +323 107 0.065746 +324 107 0.147929 +326 107 0.147929 +328 107 0.147929 +329 107 0.147929 +332 107 0.147929 +336 107 0.147929 +337 107 0.147929 +338 107 0.147929 +339 107 0.147929 +341 107 0.147929 +342 107 0.065746 +360 107 -54.583739 +361 107 -140.711236 +362 107 -4.101582 +383 107 -42.105342 +384 107 -139.187031 +385 107 -85.300486 +406 107 -75.634908 +407 107 -138.085868 +408 107 -96.488713 +429 107 -1.928475 +430 107 -290.353375 +431 107 -95.072261 +432 107 -33.070658 +433 107 -33.083266 +434 107 -1.560574 +454 107 -32.350824 +455 107 -251.007456 +456 107 -28.432548 +459 107 -31.537246 +460 107 -28.401363 +478 107 -13.594778 +479 107 -37.164455 +480 107 -123.037922 +481 107 -121.755376 +482 107 -12.182699 +108 108 2.731920 +319 108 0.147929 +320 108 0.065746 +321 108 0.147929 +322 108 0.065746 +323 108 0.147929 +324 108 0.147929 +326 108 0.147929 +327 108 0.065746 +328 108 0.147929 +329 108 0.147929 +332 108 0.591716 +337 108 0.147929 +338 108 0.065746 +339 108 0.147929 +341 108 0.147929 +342 108 0.147929 +361 108 -10.850546 +362 108 -6.372285 +386 108 -20.239614 +406 108 -18.258378 +411 108 -20.466105 +431 108 -24.312747 +436 108 -20.727542 +456 108 -24.412278 +460 108 -14.864124 +461 108 -21.025102 +481 108 -24.539337 +485 108 -21.809222 +486 108 -21.360116 +109 109 2.748356 +319 109 0.147929 +320 109 0.147929 +321 109 0.591716 +323 109 0.147929 +324 109 0.147929 +326 109 0.147929 +328 109 0.147929 +329 109 0.147929 +332 109 0.147929 +334 109 0.065746 +337 109 0.147929 +338 109 0.147929 +339 109 0.147929 +341 109 0.147929 +342 109 0.065746 +361 109 -43.639901 +362 109 -25.267681 +386 109 -80.983459 +406 109 -18.259669 +411 109 -81.896136 +431 109 -24.315590 +436 109 -82.948822 +456 109 -24.416418 +460 109 -14.869853 +461 109 -84.146257 +481 109 -24.544784 +485 109 -21.819169 +486 109 -85.493798 +110 110 2.501808 +320 110 0.147929 +321 110 0.591716 +323 110 0.147929 +324 110 0.147929 +326 110 0.147929 +328 110 0.065746 +329 110 0.065746 +332 110 0.147929 +335 110 0.065746 +336 110 0.147929 +337 110 0.065746 +338 110 0.147929 +339 110 0.147929 +341 110 0.065746 +342 110 0.147929 +360 110 -56.583492 +361 110 -140.541756 +362 110 -4.096374 +383 110 -47.204744 +384 110 -139.048149 +385 110 -83.147971 +406 110 -84.706601 +407 110 -137.968516 +408 110 -91.262083 +429 110 -1.821787 +430 110 -287.033244 +431 110 -67.527954 +432 110 -14.701052 +433 110 -14.706875 +434 110 -1.235865 +454 110 -14.345885 +455 110 -257.775982 +456 110 -37.440272 +459 110 -13.477733 +460 110 -12.626025 +478 110 -6.758754 +479 110 -45.375155 +480 110 -119.855031 +481 110 -105.314430 +482 110 -27.090474 +111 111 5.723373 +319 111 0.147929 +320 111 0.591716 +322 111 0.147929 +323 111 0.591716 +324 111 0.591716 +326 111 0.591716 +327 111 0.147929 +329 111 0.591716 +332 111 0.147929 +337 111 0.591716 +338 111 0.591716 +341 111 0.591716 +342 111 0.147929 +406 111 -18.608251 +431 111 -24.926101 +456 111 -25.197600 +481 111 -25.499371 +112 112 2.962032 +320 112 0.065746 +321 112 0.591716 +323 112 0.147929 +324 112 0.147929 +326 112 0.065746 +327 112 0.147929 +328 112 0.147929 +329 112 0.591716 +332 112 0.147929 +335 112 0.065746 +337 112 0.147929 +338 112 0.147929 +339 112 0.147929 +342 112 0.147929 +360 112 -51.814392 +361 112 -140.953826 +362 112 -4.109038 +383 112 -35.053119 +384 112 -139.385673 +385 112 -88.288404 +406 112 -63.114064 +407 112 -138.253626 +408 112 -103.722858 +430 112 -322.263917 +431 112 -107.741585 +432 112 -33.062985 +433 112 -33.075028 +434 112 -0.071338 +454 112 -144.358273 +455 112 -212.266451 +456 112 -48.916755 +459 112 -33.017592 +460 112 -28.393138 +478 112 -44.456501 +479 112 -128.626094 +480 112 -68.005167 +481 112 -135.078315 +482 112 -28.248128 +113 113 1.416995 +320 113 0.147929 +322 113 0.065746 +324 113 0.147929 +326 113 0.147929 +327 113 0.147929 +328 113 0.065746 +332 113 0.147929 +337 113 0.147929 +338 113 0.147929 +460 113 -6.710316 +485 113 -9.871530 +114 114 4.161900 +320 114 0.591716 +322 114 0.147929 +323 114 0.591716 +324 114 0.147929 +327 114 0.147929 +329 114 0.147929 +332 114 0.147929 +334 114 0.065746 +337 114 0.591716 +338 114 0.591716 +341 114 0.591716 +342 114 0.147929 +115 115 1.416995 +320 115 0.065746 +321 115 0.065746 +324 115 0.147929 +326 115 0.147929 +335 115 0.147929 +336 115 0.147929 +337 115 0.147929 +338 115 0.147929 +342 115 0.147929 +361 115 -11.815759 +362 115 -0.546110 +385 115 -8.670667 +386 115 -6.713515 +409 115 -7.146451 +410 115 -9.410798 +433 115 -7.280746 +434 115 -10.576131 +457 115 -9.142565 +458 115 -10.148951 +481 115 -12.822203 +482 115 -8.044566 +116 116 3.340072 +319 116 0.147929 +320 116 0.147929 +321 116 0.147929 +322 116 0.147929 +324 116 0.591716 +328 116 0.065746 +329 116 0.147929 +332 116 0.147929 +333 116 0.591716 +335 116 0.591716 +336 116 0.147929 +339 116 0.147929 +342 116 0.065746 +360 116 -24.915028 +361 116 -34.448139 +362 116 -1.003008 +376 116 -28.573144 +377 116 -49.918981 +382 116 -5.546531 +383 116 -34.096916 +384 116 -34.195809 +385 116 -9.396534 +400 116 -99.997629 +401 116 -124.087524 +404 116 -17.237002 +405 116 -67.837901 +406 116 -61.823416 +407 116 -28.465306 +423 116 -35.844346 +424 116 -150.654118 +425 116 -51.589203 +426 116 -50.493393 +427 116 -67.527293 +428 116 -67.617738 +429 116 -50.483589 +447 116 -202.708924 +448 116 -195.888136 +449 116 -81.945418 +450 116 -82.007938 +451 116 -31.585316 +452 116 -14.631589 +453 116 -14.632105 +454 116 -14.632691 +455 116 -14.633355 +456 116 -14.634111 +457 116 -14.634975 +458 116 -14.635967 +459 116 -14.637111 +460 116 -12.555299 +471 116 -22.763848 +472 116 -509.420199 +473 116 -63.363767 +474 116 -34.178023 +475 116 -7.116825 +496 116 -30.974488 +497 116 -202.461642 +498 116 -229.662502 +499 116 -39.255919 +500 116 -33.097775 +117 117 6.150723 +319 117 0.147929 +320 117 0.591716 +321 117 0.065746 +322 117 0.591716 +323 117 0.591716 +324 117 0.591716 +326 117 0.147929 +328 117 0.147929 +329 117 0.065746 +330 117 0.147929 +332 117 0.147929 +334 117 0.591716 +335 117 0.147929 +338 117 0.147929 +339 117 0.591716 +341 117 0.591716 +342 117 0.591716 +361 117 -6.962447 +362 117 -1.187431 +386 117 -9.694996 +406 117 -19.071312 +411 117 -9.933693 +431 117 -25.653350 +435 117 -0.818295 +436 117 -9.376554 +456 117 -26.056074 +460 117 -26.825364 +480 117 -11.762163 +481 117 -14.730431 +485 117 -35.075960 +118 118 2.321006 +320 118 0.147929 +321 118 0.147929 +324 118 0.147929 +326 118 0.147929 +328 118 0.147929 +331 118 0.147929 +332 118 0.591716 +335 118 0.147929 +338 118 0.147929 +339 118 0.147929 +342 118 0.147929 +360 118 -12.068987 +361 118 -35.319439 +362 118 -1.029749 +383 118 -6.514607 +384 118 -34.912661 +385 118 -23.029635 +406 118 -11.796667 +407 118 -34.619309 +408 118 -28.240030 +429 118 -29.413706 +430 118 -34.401495 +431 118 -22.705977 +454 118 -392.323491 +455 118 -73.300638 +456 118 -55.749545 +457 118 -32.912484 +458 118 -32.913540 +459 118 -32.914757 +460 118 -28.232103 +479 118 -247.097298 +480 118 -79.305219 +481 118 -18.693237 +482 118 -34.448445 +483 118 -31.244931 +119 119 6.463018 +319 119 0.147929 +320 119 0.591716 +321 119 0.591716 +322 119 0.147929 +323 119 0.591716 +324 119 0.147929 +326 119 0.591716 +327 119 0.147929 +328 119 0.591716 +329 119 0.591716 +331 119 0.147929 +332 119 0.147929 +333 119 0.147929 +334 119 0.591716 +338 119 0.147929 +339 119 0.147929 +341 119 0.591716 +342 119 0.147929 +361 119 -37.739875 +362 119 -30.855665 +377 119 -10.102085 +386 119 -80.494495 +402 119 -27.530287 +406 119 -18.233076 +411 119 -81.268521 +427 119 -27.409698 +431 119 -24.250380 +436 119 -82.178192 +452 119 -27.310200 +456 119 -24.316919 +460 119 -59.017420 +461 119 -83.227584 +477 119 -27.231826 +481 119 -24.410745 +483 119 -0.263809 +485 119 -86.468238 +486 119 -84.421375 +120 120 1.384122 +319 120 0.147929 +321 120 0.065746 +322 120 0.065746 +323 120 0.065746 +324 120 0.065746 +326 120 0.147929 +327 120 0.065746 +328 120 0.065746 +331 120 0.147929 +339 120 0.147929 +341 120 0.147929 +361 120 -4.245638 +362 120 -3.378223 +386 120 -8.947251 +406 120 -18.233727 +411 120 -9.034281 +431 120 -24.252273 +436 120 -9.136413 +456 120 -24.319991 +460 120 -6.560504 +461 120 -9.254105 +481 120 -24.415002 +483 120 -0.263896 +485 120 -9.612901 +486 120 -9.387882 +121 121 5.624753 +320 121 0.591716 +321 121 0.065746 +322 121 0.591716 +323 121 0.591716 +324 121 0.591716 +326 121 0.065746 +327 121 0.591716 +329 121 0.147929 +331 121 0.591716 +332 121 0.147929 +334 121 0.147929 +338 121 0.591716 +341 121 0.591716 +342 121 0.065746 +361 121 -5.814899 +362 121 -1.952331 +386 121 -9.162315 +411 121 -9.302732 +436 121 -9.460223 +461 121 -9.635507 +483 121 -1.084877 +485 121 -3.199042 +486 121 -6.630337 +122 122 3.997535 +319 122 0.147929 +320 122 0.591716 +321 122 0.147929 +322 122 0.147929 +323 122 0.065746 +324 122 0.591716 +327 122 0.065746 +329 122 0.147929 +332 122 0.591716 +333 122 0.147929 +335 122 0.147929 +338 122 0.591716 +339 122 0.065746 +341 122 0.147929 +342 122 0.147929 +361 122 -15.014271 +362 122 -3.017555 +377 122 -10.028460 +386 122 -21.395146 +402 122 -27.463558 +406 122 -18.761968 +411 122 -21.860702 +427 122 -27.539659 +431 122 -25.171533 +436 122 -22.372383 +452 122 -27.636248 +456 122 -25.491160 +460 122 -15.105622 +461 122 -7.826996 +477 122 -27.753277 +481 122 -25.842227 +485 122 -23.544010 +123 123 2.764793 +320 123 0.147929 +321 123 0.591716 +324 123 0.591716 +329 123 0.147929 +332 123 0.591716 +338 123 0.147929 +339 123 0.147929 +341 123 0.147929 +360 123 -56.740716 +361 123 -140.528628 +362 123 -4.095970 +383 123 -47.605918 +384 123 -139.037387 +385 123 -82.978912 +406 123 -85.420915 +407 123 -137.959420 +408 123 -90.851049 +429 123 -3.331775 +430 123 -307.609215 +431 123 -52.109215 +454 123 -32.303745 +455 123 -335.580835 +478 123 -14.637544 +479 123 -18.743788 +480 123 -133.087214 +481 123 -195.668268 +124 124 4.753616 +319 124 0.147929 +320 124 0.147929 +321 124 0.147929 +322 124 0.147929 +323 124 0.591716 +324 124 0.147929 +326 124 0.591716 +327 124 0.591716 +331 124 0.147929 +332 124 0.147929 +333 124 0.065746 +334 124 0.591716 +335 124 0.147929 +339 124 0.147929 +340 124 0.147929 +342 124 0.591716 +361 124 -15.669176 +362 124 -2.669956 +377 124 -4.482619 +386 124 -21.816342 +402 124 -12.297606 +406 124 -19.066783 +411 124 -22.353844 +427 124 -12.363407 +431 124 -25.646373 +435 124 -1.894197 +436 124 -21.047710 +451 124 -7.178413 +452 124 -5.259982 +455 124 -0.298955 +456 124 -36.012643 +460 124 -23.583377 +476 124 -12.522521 +480 124 -38.108061 +481 124 -14.925726 +483 124 -0.291761 +485 124 -24.281280 +125 125 2.403189 +319 125 0.065746 +320 125 0.147929 +321 125 0.065746 +322 125 0.147929 +323 125 0.147929 +324 125 0.147929 +326 125 0.147929 +327 125 0.591716 +329 125 0.065746 +331 125 0.065746 +332 125 0.147929 +333 125 0.147929 +338 125 0.065746 +339 125 0.065746 +340 125 0.065746 +341 125 0.065746 +361 125 -6.637592 +362 125 -1.361945 +377 125 -10.020722 +386 125 -9.488802 +402 125 -27.429514 +406 125 -8.315003 +411 125 -9.692159 +427 125 -27.486728 +431 125 -11.149867 +436 125 -9.915809 +452 125 -27.564413 +456 125 -15.739567 +460 125 -6.144375 +461 125 -4.016436 +477 125 -27.662535 +480 125 -10.283870 +481 125 -12.642856 +483 125 -0.125767 +485 125 -10.428302 +126 126 1.877219 +319 126 0.147929 +320 126 0.591716 +321 126 0.147929 +323 126 0.147929 +326 126 0.147929 +332 126 0.147929 +333 126 0.147929 +335 126 0.147929 +361 126 -26.196649 +362 126 -1.239487 +377 126 -11.008015 +385 126 -18.263456 +386 126 -15.832163 +401 126 -15.758813 +402 126 -14.707389 +406 126 -26.062998 +409 126 -13.931320 +410 126 -22.707398 +426 126 -31.020298 +430 126 -24.254058 +431 126 -11.826735 +433 126 -13.259031 +434 126 -26.194010 +450 126 -4.230330 +451 126 -27.367921 +454 126 -17.031090 +455 126 -20.821313 +457 126 -16.379131 +458 126 -26.177770 +475 126 -32.198627 +478 126 -12.731636 +479 126 -26.993859 +481 126 -23.474551 +482 126 -22.488435 +499 126 -0.648692 +500 126 -32.170967 +127 127 1.778600 +319 127 0.147929 +320 127 0.147929 +322 127 0.147929 +323 127 0.065746 +324 127 0.147929 +326 127 0.147929 +335 127 0.147929 +336 127 0.065746 +338 127 0.147929 +339 127 0.065746 +341 127 0.147929 +342 127 0.147929 +406 127 -20.671065 +431 127 -28.063172 +455 127 -21.074883 +456 127 -7.728339 +480 127 -29.589968 +128 128 1.269066 +320 128 0.591716 +322 128 0.065746 +324 128 0.147929 +329 128 0.065746 +338 128 0.147929 +353 128 -44.010555 +354 128 -78.103469 +378 128 -26.069634 +379 128 -171.807944 +402 128 -7.977695 +403 128 -18.596553 +404 128 -133.522879 +405 128 -35.113590 +427 128 -17.229942 +428 128 -9.875790 +429 128 -106.989705 +430 128 -58.680074 +451 128 -9.426390 +452 128 -18.236829 +454 128 -92.249552 +455 128 -48.200839 +456 128 -22.456902 +476 128 -15.058625 +477 128 -13.186892 +480 128 -104.629081 +481 128 -55.718449 +500 128 -13.800869 +129 129 5.641190 +319 129 0.147929 +320 129 0.591716 +321 129 0.147929 +322 129 0.147929 +323 129 0.147929 +324 129 0.591716 +326 129 0.147929 +327 129 0.591716 +329 129 0.147929 +330 129 0.591716 +331 129 0.591716 +334 129 0.065746 +338 129 0.147929 +339 129 0.591716 +341 129 0.591716 +342 129 0.147929 +361 129 -12.831573 +362 129 -4.601784 +386 129 -20.553090 +406 129 -18.354936 +411 129 -20.855465 +431 129 -24.499850 +436 129 -21.195671 +456 129 -24.667185 +461 129 -21.575259 +481 129 -24.862844 +483 129 -1.081069 +485 129 -3.536868 +486 129 -18.459075 +130 130 0.792406 +319 130 0.065746 +322 130 0.065746 +324 130 0.065746 +326 130 0.065746 +329 130 0.065746 +332 130 0.147929 +342 130 0.065746 +406 130 -8.388668 +431 130 -11.265885 +456 130 -11.422099 +480 130 -0.683851 +481 130 -10.908815 +131 131 1.992275 +319 131 0.065746 +320 131 0.065746 +321 131 0.147929 +322 131 0.147929 +323 131 0.147929 +324 131 0.147929 +326 131 0.065746 +329 131 0.147929 +332 131 0.065746 +335 131 0.147929 +338 131 0.147929 +339 131 0.147929 +341 131 0.147929 +342 131 0.147929 +361 131 -15.360405 +362 131 -2.825561 +386 131 -21.606970 +406 131 -8.386909 +411 131 -22.109196 +431 131 -11.263137 +436 131 -22.659754 +456 131 -11.418869 +460 131 -20.631474 +461 131 -2.629810 +480 131 -0.577539 +481 131 -11.011402 +485 131 -23.916601 +132 132 4.671433 +319 132 0.065746 +320 132 0.147929 +321 132 0.591716 +322 132 0.147929 +324 132 0.147929 +325 132 0.065746 +326 132 0.147929 +327 132 0.147929 +332 132 0.147929 +334 132 0.147929 +335 132 0.147929 +337 132 0.591716 +338 132 0.591716 +339 132 0.591716 +341 132 0.591716 +342 132 0.147929 +361 132 -62.511822 +362 132 -10.759524 +386 132 -87.149156 +406 132 -8.464343 +411 132 -89.279780 +431 132 -11.383305 +435 132 -5.190608 +436 132 -86.420793 +444 132 -10.221224 +456 132 -11.559339 +460 132 -94.155289 +469 132 -14.086615 +480 132 -4.686963 +481 132 -7.063340 +485 132 -96.923428 +494 132 -14.041663 +133 133 3.323636 +320 133 0.591716 +322 133 0.065746 +325 133 0.065746 +327 133 0.147929 +328 133 0.147929 +329 133 0.147929 +331 133 0.591716 +332 133 0.147929 +336 133 0.065746 +337 133 0.147929 +338 133 0.147929 +339 133 0.591716 +341 133 0.147929 +342 133 0.065746 +444 133 -11.624988 +445 133 -14.688747 +446 133 -14.690593 +447 133 -14.692694 +448 133 -14.695075 +449 133 -14.697770 +450 133 -12.292172 +456 133 -25.709945 +457 133 -33.057434 +458 133 -33.069070 +459 133 -33.082500 +460 133 -28.387189 +475 133 -2.408641 +476 133 -14.704251 +477 133 -17.033846 +478 133 -433.373629 +479 133 -208.424191 +480 133 -165.127459 +481 133 -139.457705 +482 133 -132.156169 +483 133 -119.504415 +134 134 2.534681 +321 134 0.147929 +324 134 0.147929 +325 134 0.147929 +328 134 0.591716 +329 134 0.147929 +335 134 0.065746 +338 134 0.147929 +339 134 0.591716 +341 134 0.147929 +342 134 0.147929 +360 134 -14.417279 +361 134 -35.112921 +362 134 -1.023402 +383 134 -12.493894 +384 134 -34.743576 +385 134 -20.495284 +406 134 -22.410533 +407 134 -34.476524 +408 134 -22.105897 +423 134 -23.183010 +424 134 -32.969827 +425 134 -32.972676 +426 134 -32.975892 +427 134 -32.979525 +428 134 -32.983632 +429 134 -36.111509 +430 134 -293.795204 +431 134 -144.278404 +432 134 -132.368165 +433 134 -132.424898 +434 134 -20.870304 +444 134 -26.087847 +445 134 -32.961376 +446 134 -32.963106 +447 134 -32.965074 +448 134 -9.784294 +454 134 -32.310706 +455 134 -216.039291 +456 134 -33.852644 +459 134 -111.620097 +460 134 -113.697163 +478 134 -14.482645 +479 134 -18.906985 +480 134 -45.447923 +481 134 -168.481867 +482 134 -29.366413 +135 135 4.753616 +319 135 0.147929 +321 135 0.591716 +322 135 0.147929 +324 135 0.591716 +325 135 0.147929 +326 135 0.147929 +327 135 0.591716 +328 135 0.591716 +329 135 0.147929 +335 135 0.591716 +336 135 0.065746 +339 135 0.147929 +342 135 0.591716 +361 135 -49.321790 +362 135 -20.124430 +386 135 -81.792231 +406 135 -18.344573 +411 135 -82.906296 +431 135 -24.246772 +436 135 -84.167763 +444 135 -34.123158 +445 135 -0.850407 +456 135 -13.559641 +457 135 -10.581264 +460 135 -59.764766 +461 135 -85.582361 +470 135 -42.605447 +471 135 -4.628685 +482 135 -24.062723 +485 135 -87.769855 +486 135 -87.156457 +496 135 -39.273899 +497 135 -6.617766 +136 136 2.222387 +319 136 0.147929 +320 136 0.147929 +321 136 0.147929 +325 136 0.147929 +326 136 0.147929 +332 136 0.147929 +333 136 0.065746 +335 136 0.065746 +336 136 0.065746 +338 136 0.147929 +339 136 0.147929 +341 136 0.591716 +361 136 -20.240205 +362 136 -1.567366 +377 136 -4.506690 +386 136 -26.474491 +402 136 -12.376404 +406 136 -20.885809 +410 136 -22.412265 +411 136 -5.319718 +426 136 -1.544303 +427 136 -10.916983 +431 136 -28.382891 +434 136 -2.444406 +435 136 -26.657800 +444 136 -25.918611 +451 136 -12.555441 +455 136 -23.760726 +456 136 -5.403338 +459 136 -30.593096 +469 136 -28.157955 +470 136 -7.297292 +476 136 -12.658796 +480 136 -29.993776 +483 136 -18.351716 +484 136 -13.860647 +495 136 -35.022046 +137 137 1.926529 +319 137 0.065746 +321 137 0.147929 +322 137 0.147929 +324 137 0.147929 +325 137 0.147929 +327 137 0.147929 +328 137 0.147929 +332 137 0.147929 +335 137 0.065746 +336 137 0.065746 +338 137 0.147929 +339 137 0.147929 +341 137 0.147929 +361 137 -33.455593 +362 137 -1.112009 +384 137 -2.062011 +385 137 -37.465753 +386 137 -4.522131 +406 137 -13.981223 +408 137 -13.671586 +409 137 -34.981150 +429 137 -1.047397 +430 137 -17.796699 +431 137 -0.805626 +432 137 -30.832536 +433 137 -23.018401 +444 137 -29.254558 +445 137 -20.025958 +453 137 -4.443458 +454 137 -16.518136 +455 137 -17.972335 +456 137 -36.137659 +457 137 -5.559205 +459 137 -27.235697 +460 137 -29.280798 +470 137 -17.041858 +471 137 -37.204349 +472 137 -11.186745 +477 137 -9.423991 +478 137 -25.338804 +479 137 -35.731263 +480 137 -17.947256 +481 137 -22.056239 +482 137 -33.883454 +483 137 -33.958265 +484 137 -6.809445 +497 137 -26.174758 +498 137 -35.942145 +138 138 2.436062 +320 138 0.591716 +321 138 0.147929 +322 138 0.147929 +324 138 0.147929 +325 138 0.147929 +326 138 0.065746 +327 138 0.065746 +328 138 0.147929 +331 138 0.147929 +332 138 0.147929 +333 138 0.065746 +334 138 0.147929 +338 138 0.147929 +342 138 0.065746 +361 138 -25.598859 +362 138 -1.257433 +377 138 -4.527006 +385 138 -16.308504 +386 138 -16.993297 +402 138 -12.319598 +409 138 -10.560135 +410 138 -25.139716 +427 138 -12.240140 +433 138 -8.371026 +434 138 -29.978078 +444 138 -28.138827 +445 138 -30.879114 +452 138 -12.170289 +457 138 -9.837939 +458 138 -31.428842 +459 138 -3.976926 +460 138 -31.078569 +470 138 -4.737842 +471 138 -35.700555 +472 138 -35.796367 +473 138 -1.233446 +477 138 -12.110069 +481 138 -15.112248 +482 138 -29.353292 +483 138 -24.858508 +484 138 -31.984341 +498 138 -34.672444 +499 138 -36.030936 +500 138 -1.668796 +139 139 2.222387 +320 139 0.147929 +322 139 0.147929 +324 139 0.147929 +325 139 0.147929 +326 139 0.147929 +328 139 0.065746 +332 139 0.591716 +335 139 0.065746 +338 139 0.147929 +339 139 0.147929 +341 139 0.065746 +342 139 0.147929 +444 139 -29.094472 +445 139 -21.234640 +459 139 -1.117761 +460 139 -13.917346 +470 139 -15.624725 +471 139 -36.987921 +472 139 -14.130518 +483 139 -8.992867 +484 139 -14.975642 +497 139 -23.005282 +498 139 -37.305557 +499 139 -2.941873 +140 140 2.501808 +320 140 0.065746 +321 140 0.147929 +323 140 0.147929 +324 140 0.147929 +328 140 0.591716 +330 140 0.065746 +331 140 0.591716 +332 140 0.065746 +334 140 0.065746 +335 140 0.065746 +341 140 0.147929 +342 140 0.147929 +361 140 -27.442755 +362 140 -1.207322 +385 140 -22.192822 +386 140 -13.571995 +409 140 -20.709556 +410 140 -17.912490 +433 140 -23.132456 +434 140 -18.662900 +457 140 -29.665948 +458 140 -15.639301 +459 140 -9.429725 +460 140 -125.363753 +480 140 -2.704457 +481 140 -37.852783 +482 140 -8.606555 +483 140 -81.910622 +484 140 -135.524557 +141 141 2.436062 +319 141 0.147929 +320 141 0.147929 +321 141 0.147929 +322 141 0.065746 +323 141 0.147929 +324 141 0.591716 +325 141 0.065746 +326 141 0.147929 +327 141 0.065746 +329 141 0.147929 +331 141 0.065746 +332 141 0.147929 +339 141 0.147929 +341 141 0.147929 +361 141 -11.018799 +362 141 -6.215797 +386 141 -20.257677 +406 141 -18.263055 +411 141 -20.488993 +431 141 -24.322957 +436 141 -20.755418 +444 141 -10.688108 +456 141 -24.427082 +461 141 -21.058153 +469 141 -14.677975 +481 141 -24.558776 +483 141 -0.118151 +486 141 -21.398551 +494 141 -10.377315 +495 141 -4.191539 +142 142 1.614234 +323 142 0.065746 +325 142 0.147929 +326 142 0.065746 +328 142 0.147929 +332 142 0.065746 +336 142 0.147929 +339 142 0.591716 +341 142 0.065746 +342 142 0.065746 +444 142 -25.727823 +460 142 -25.523333 +469 142 -29.761171 +470 142 -5.445293 +484 142 -30.761709 +485 142 -8.761813 +495 142 -34.791388 +143 143 2.271696 +321 143 0.147929 +322 143 0.147929 +325 143 0.147929 +326 143 0.147929 +328 143 0.065746 +329 143 0.065746 +330 143 0.065746 +332 143 0.591716 +333 143 0.065746 +334 143 0.147929 +335 143 0.147929 +336 143 0.065746 +339 143 0.065746 +342 143 0.147929 +361 143 -4.872717 +362 143 -12.176920 +377 143 -4.899497 +386 143 -19.956011 +402 143 -13.235814 +411 143 -20.092392 +427 143 -6.030894 +428 143 -6.977509 +436 143 -20.261226 +444 143 -31.935527 +453 143 -12.793241 +460 143 -6.455462 +461 143 -20.463267 +469 143 -4.978916 +470 143 -38.319533 +478 143 -12.590500 +485 143 -9.421332 +486 143 -20.699412 +495 143 -8.845403 +496 143 -33.437974 +144 144 2.156640 +320 144 0.591716 +322 144 0.147929 +324 144 0.147929 +325 144 0.591716 +326 144 0.147929 +331 144 0.065746 +332 144 0.147929 +342 144 0.065746 +444 144 -93.770742 +469 144 -129.000379 +483 144 -0.125800 +494 144 -128.312744 +145 145 2.797666 +320 145 0.147929 +321 145 0.147929 +323 145 0.147929 +324 145 0.147929 +326 145 0.065746 +327 145 0.147929 +329 145 0.065746 +331 145 0.591716 +332 145 0.591716 +335 145 0.065746 +336 145 0.065746 +339 145 0.147929 +341 145 0.147929 +342 145 0.065746 +353 145 -30.196345 +354 145 -497.489896 +355 145 -34.015438 +356 145 -32.898931 +357 145 -32.899000 +358 145 -32.899079 +359 145 -32.899170 +360 145 -32.899276 +361 145 -32.899399 +362 145 -0.955730 +378 145 -40.275963 +379 145 -292.425666 +380 145 -173.072035 +381 145 -1.015134 +403 145 -72.952052 +404 145 -125.429209 +405 145 -150.841873 +406 145 -144.324131 +427 145 -2.572125 +428 145 -76.497090 +429 145 -76.063745 +430 145 -168.260459 +431 145 -50.734863 +432 145 -107.143126 +452 145 -30.473500 +453 145 -49.316214 +454 145 -43.679604 +455 145 -155.147806 +456 145 -42.008423 +457 145 -93.688419 +458 145 -55.644298 +477 145 -42.150461 +478 145 -38.430513 +479 145 -37.657709 +480 145 -61.681714 +481 145 -137.673691 +483 145 -133.623081 +484 145 -6.944770 +146 146 2.353879 +320 146 0.065746 +321 146 0.591716 +322 146 0.065746 +324 146 0.147929 +327 146 0.065746 +328 146 0.591716 +329 146 0.065746 +330 146 0.065746 +332 146 0.147929 +338 146 0.147929 +341 146 0.147929 +360 146 -55.788466 +361 146 -140.608576 +362 146 -4.098427 +383 146 -45.176711 +384 146 -139.102915 +385 146 -84.003231 +406 146 -81.096986 +407 146 -138.014798 +408 146 -93.340290 +430 146 -249.068382 +431 146 -188.951543 +432 146 -132.526560 +433 146 -132.594996 +434 146 -42.290785 +454 146 -31.311557 +455 146 -113.610868 +456 146 -30.140585 +459 146 -90.383251 +460 146 -113.867119 +478 146 -12.656017 +479 146 -31.790216 +480 146 -47.958567 +481 146 -82.211560 +147 147 2.156640 +320 147 0.065746 +322 147 0.147929 +323 147 0.591716 +324 147 0.147929 +330 147 0.065746 +334 147 0.147929 +335 147 0.591716 +341 147 0.147929 +148 148 4.161900 +319 148 0.147929 +320 148 0.147929 +321 148 0.147929 +322 148 0.147929 +323 148 0.591716 +324 148 0.147929 +326 148 0.147929 +327 148 0.147929 +329 148 0.147929 +331 148 0.065746 +332 148 0.147929 +333 148 0.147929 +334 148 0.147929 +335 148 0.147929 +337 148 0.147929 +338 148 0.147929 +339 148 0.591716 +341 148 0.591716 +361 148 -15.800475 +362 148 -2.608210 +377 148 -10.099426 +386 148 -21.911118 +402 148 -27.714686 +406 148 -19.129899 +411 148 -22.464326 +427 148 -27.874590 +431 148 -25.743452 +435 148 -3.777566 +436 148 -19.291554 +451 148 -21.052884 +452 148 -7.002329 +456 148 -26.160610 +460 148 -23.728441 +476 148 -28.256432 +480 148 -14.304694 +481 148 -12.307318 +483 148 -0.130415 +485 148 -24.445405 +149 149 4.013971 +319 149 0.147929 +320 149 0.147929 +322 149 0.591716 +323 149 0.147929 +324 149 0.591716 +326 149 0.591716 +327 149 0.147929 +329 149 0.147929 +332 149 0.591716 +334 149 0.147929 +335 149 0.147929 +337 149 0.147929 +338 149 0.147929 +341 149 0.065746 +406 149 -18.507288 +431 149 -24.760953 +456 149 -24.996342 +481 149 -25.261235 +150 150 3.060651 +319 150 0.147929 +320 150 0.147929 +321 150 0.147929 +322 150 0.147929 +323 150 0.147929 +324 150 0.147929 +326 150 0.591716 +327 150 0.147929 +330 150 0.147929 +332 150 0.147929 +334 150 0.147929 +335 150 0.147929 +337 150 0.147929 +338 150 0.147929 +339 150 0.147929 +341 150 0.147929 +361 150 -15.687744 +362 150 -2.661066 +386 150 -21.829540 +406 150 -19.069193 +411 150 -22.369237 +431 150 -25.650086 +435 150 -2.162108 +436 150 -20.797530 +456 150 -26.052283 +460 150 -23.603602 +480 150 -11.666624 +481 150 -14.821634 +485 150 -24.304167 +151 151 3.340072 +319 151 0.065746 +320 151 0.147929 +322 151 0.591716 +324 151 0.147929 +326 151 0.147929 +327 151 0.147929 +332 151 0.591716 +334 151 0.147929 +335 151 0.147929 +337 151 0.147929 +338 151 0.065746 +339 151 0.591716 +341 151 0.147929 +406 151 -8.226389 +431 151 -11.006405 +456 151 -11.111377 +481 151 -11.229469 +152 152 1.910092 +319 152 0.147929 +320 152 0.147929 +321 152 0.065746 +322 152 0.065746 +323 152 0.147929 +324 152 0.147929 +326 152 0.147929 +327 152 0.065746 +328 152 0.147929 +332 152 0.065746 +335 152 0.147929 +337 152 0.147929 +338 152 0.147929 +339 152 0.065746 +361 152 -6.898881 +362 152 -1.218689 +386 152 -9.650883 +406 152 -18.977980 +411 152 -9.882193 +431 152 -25.509180 +436 152 -10.135490 +456 152 -25.888194 +460 152 -26.556988 +461 152 -0.106483 +480 152 -7.281580 +481 152 -19.018710 +485 152 -34.844256 +153 153 4.227646 +319 153 0.065746 +320 153 0.147929 +322 153 0.591716 +323 153 0.147929 +324 153 0.591716 +326 153 0.591716 +327 153 0.147929 +328 153 0.065746 +329 153 0.147929 +331 153 0.147929 +332 153 0.591716 +334 153 0.147929 +335 153 0.147929 +338 153 0.147929 +341 153 0.147929 +342 153 0.147929 +406 153 -8.232314 +431 153 -11.016202 +456 153 -11.123412 +460 153 -6.862536 +481 153 -11.243788 +483 153 -0.275554 +485 153 -10.127899 +154 154 2.074458 +320 154 0.147929 +321 154 0.147929 +322 154 0.065746 +323 154 0.147929 +324 154 0.147929 +326 154 0.147929 +327 154 0.147929 +328 154 0.147929 +331 154 0.147929 +335 154 0.065746 +336 154 0.065746 +337 154 0.147929 +338 154 0.147929 +339 154 0.147929 +360 154 -6.769186 +361 154 -35.901065 +362 154 -1.047659 +384 154 -28.517347 +385 154 -28.851785 +407 154 -23.366239 +408 154 -35.187240 +409 154 -6.868757 +430 154 -28.191167 +431 154 -34.871474 +432 154 -11.651220 +453 154 -6.006920 +454 154 -242.347168 +455 154 -73.263187 +456 154 -36.521500 +457 154 -32.900137 +458 154 -32.900298 +459 154 -32.900484 +460 154 -28.218916 +478 154 -45.317134 +479 154 -188.984705 +480 154 -49.732630 +481 154 -30.247406 +482 154 -33.937412 +483 154 -30.747171 +155 155 3.192143 +320 155 0.147929 +321 155 0.147929 +322 155 0.065746 +323 155 0.147929 +324 155 0.147929 +327 155 0.591716 +328 155 0.591716 +329 155 0.147929 +335 155 0.147929 +336 155 0.147929 +337 155 0.147929 +338 155 0.147929 +339 155 0.065746 +341 155 0.147929 +342 155 0.147929 +360 155 -19.966522 +361 155 -34.717550 +362 155 -1.011265 +383 155 -26.756500 +384 155 -34.418437 +385 155 -14.588984 +405 155 -1.590496 +406 155 -191.305280 +407 155 -34.201090 +408 155 -7.545027 +430 155 -182.463437 +431 155 -267.637555 +432 155 -141.300714 +433 155 -134.583516 +434 155 -134.250054 +454 155 -23.249928 +455 155 -215.922603 +456 155 -130.414554 +457 155 -52.554446 +458 155 -0.211963 +459 155 -0.574920 +460 155 -115.861980 +478 155 -5.187860 +479 155 -116.560714 +480 155 -135.704366 +481 155 -62.686237 +482 155 -68.872267 +483 155 -34.400065 +156 156 2.748356 +320 156 0.147929 +321 156 0.147929 +322 156 0.147929 +323 156 0.147929 +324 156 0.147929 +326 156 0.147929 +327 156 0.147929 +328 156 0.147929 +329 156 0.147929 +330 156 0.065746 +331 156 0.147929 +335 156 0.147929 +336 156 0.147929 +337 156 0.065746 +338 156 0.147929 +339 156 0.147929 +341 156 0.147929 +342 156 0.147929 +353 156 -62.655499 +354 156 -424.926759 +355 156 -66.770476 +356 156 -32.898732 +357 156 -32.898787 +358 156 -32.898851 +359 156 -32.898925 +360 156 -32.899010 +361 156 -32.899109 +362 156 -0.955721 +378 156 -86.131021 +379 156 -262.453495 +380 156 -96.717255 +381 156 -38.170417 +382 156 -21.419569 +402 156 -19.908188 +403 156 -97.541069 +404 156 -142.051201 +405 156 -106.035316 +406 156 -71.218159 +407 156 -14.545566 +408 156 -36.221890 +409 156 -4.357923 +427 156 -36.928717 +428 156 -105.006552 +429 156 -116.846569 +430 156 -85.093083 +431 156 -28.263065 +432 156 -58.687722 +434 156 -32.166959 +435 156 -17.307800 +451 156 -22.838253 +452 156 -55.545552 +453 156 -65.383414 +454 156 -71.601323 +455 156 -64.552204 +456 156 -73.680736 +457 156 -33.773559 +458 156 -38.215304 +460 156 -14.304633 +476 156 -33.856212 +477 156 -58.658612 +478 156 -53.212283 +479 156 -63.653194 +480 156 -51.936790 +481 156 -82.098061 +482 156 -12.941768 +483 156 -48.586212 +484 156 -15.735326 +500 156 -32.385821 +157 157 1.795036 +321 157 0.147929 +322 157 0.147929 +323 157 0.147929 +324 157 0.147929 +327 157 0.065746 +328 157 0.147929 +329 157 0.147929 +331 157 0.147929 +336 157 0.147929 +341 157 0.147929 +342 157 0.147929 +353 157 -25.885883 +354 157 -256.317245 +355 157 -63.984932 +356 157 -32.897909 +357 157 -32.897909 +358 157 -32.897909 +359 157 -32.897909 +360 157 -32.897909 +361 157 -32.897909 +362 157 -0.955684 +378 157 -70.916761 +379 157 -103.217647 +380 157 -91.037075 +381 157 -37.779189 +382 157 -19.877240 +402 157 -12.611396 +403 157 -59.626654 +404 157 -78.640309 +405 157 -35.047625 +406 157 -70.783058 +407 157 -16.024907 +408 157 -36.152900 +409 157 -3.574929 +427 157 -32.285847 +428 157 -49.187287 +429 157 -70.909723 +430 157 -25.844474 +431 157 -16.736086 +432 157 -58.391757 +434 157 -32.873731 +435 157 -17.102274 +451 157 -16.759505 +452 157 -47.041717 +453 157 -64.188615 +454 157 -26.039820 +456 157 -28.260238 +457 157 -30.247103 +458 157 -37.938071 +460 157 -14.437821 +476 157 -33.953290 +477 157 -42.681471 +478 157 -53.140149 +479 157 -26.041091 +481 157 -27.547830 +483 157 -48.861887 +484 157 -15.475564 +500 157 -27.402382 +158 158 2.304569 +320 158 0.147929 +322 158 0.065746 +323 158 0.147929 +324 158 0.147929 +326 158 0.147929 +327 158 0.147929 +329 158 0.065746 +332 158 0.147929 +336 158 0.147929 +338 158 0.591716 +341 158 0.147929 +342 158 0.147929 +431 158 -19.535649 +455 158 -40.770595 +456 158 -340.393980 +457 158 -7.653971 +479 158 -15.853835 +480 158 -88.488242 +481 158 -242.818413 +482 158 -37.279813 +483 158 -1.231453 +159 159 4.145464 +319 159 0.147929 +320 159 0.147929 +321 159 0.147929 +322 159 0.147929 +323 159 0.591716 +324 159 0.147929 +326 159 0.147929 +328 159 0.065746 +329 159 0.065746 +331 159 0.147929 +333 159 0.065746 +334 159 0.591716 +335 159 0.147929 +338 159 0.591716 +341 159 0.591716 +342 159 0.147929 +361 159 -15.669481 +362 159 -2.669810 +377 159 -4.482901 +386 159 -21.816559 +402 159 -12.298553 +406 159 -19.068369 +411 159 -22.354096 +427 159 -12.364611 +431 159 -25.648816 +435 159 -1.898604 +436 159 -21.043594 +451 159 -7.290365 +452 159 -5.149492 +456 159 -26.050807 +460 159 -30.849608 +476 159 -12.524242 +480 159 -11.629367 +481 159 -14.857204 +483 159 -0.291777 +485 159 -35.077490 +160 160 5.559007 +320 160 0.591716 +321 160 0.147929 +323 160 0.591716 +324 160 0.591716 +326 160 0.591716 +327 160 0.065746 +328 160 0.147929 +329 160 0.147929 +331 160 0.147929 +332 160 0.591716 +333 160 0.065746 +337 160 0.147929 +338 160 0.147929 +339 160 0.591716 +340 160 0.147929 +341 160 0.591716 +361 160 -8.477152 +362 160 -8.638941 +377 160 -4.503935 +386 160 -20.070329 +402 160 -12.266888 +411 160 -20.247209 +427 160 -12.202514 +436 160 -20.457531 +452 160 -12.147601 +456 160 -9.684839 +460 160 -14.701254 +461 160 -20.702236 +477 160 -12.102170 +481 160 -24.802035 +483 160 -0.262891 +485 160 -21.522746 +486 160 -20.982414 +161 161 3.635930 +320 161 0.591716 +321 161 0.147929 +322 161 0.591716 +323 161 0.147929 +324 161 0.147929 +326 161 0.147929 +327 161 0.147929 +328 161 0.591716 +329 161 0.147929 +332 161 0.065746 +333 161 0.065746 +335 161 0.147929 +336 161 0.147929 +338 161 0.147929 +341 161 0.147929 +361 161 -30.411228 +362 161 -1.151026 +377 161 -8.187104 +385 161 -30.995333 +386 161 -8.815437 +402 161 -3.551467 +403 161 -17.553113 +404 161 -0.366502 +409 161 -35.917113 +410 161 -7.564412 +429 161 -17.399826 +430 161 -2.779564 +432 161 -7.932809 +433 161 -37.562594 +434 161 -2.097479 +455 161 -15.238459 +456 161 -57.779269 +457 161 -161.630990 +458 161 -132.438042 +459 161 -132.504588 +460 161 -113.710292 +480 161 -132.349274 +481 161 -417.141728 +162 162 2.896285 +320 162 0.147929 +321 162 0.147929 +322 162 0.147929 +323 162 0.147929 +324 162 0.147929 +326 162 0.147929 +329 162 0.147929 +331 162 0.591716 +332 162 0.147929 +335 162 0.065746 +336 162 0.147929 +337 162 0.147929 +338 162 0.065746 +339 162 0.147929 +341 162 0.147929 +342 162 0.147929 +353 162 -30.173738 +354 162 -499.269171 +355 162 -40.602761 +356 162 -32.898401 +357 162 -32.898435 +358 162 -32.898473 +359 162 -32.898517 +360 162 -32.898568 +361 162 -32.898627 +362 162 -0.955706 +378 162 -58.697747 +379 162 -245.733338 +380 162 -226.994318 +381 162 -4.322659 +402 162 -15.149652 +403 162 -44.706144 +404 162 -148.945790 +405 162 -138.977601 +406 162 -173.596643 +407 162 -0.848221 +427 162 -32.265118 +428 162 -47.012030 +429 162 -116.956151 +430 162 -101.430421 +431 162 -80.740041 +432 162 -131.369038 +451 162 -18.877039 +452 162 -43.332486 +453 162 -53.049139 +454 162 -37.601197 +455 162 -92.389469 +456 162 -74.802447 +457 162 -104.207733 +458 162 -74.129125 +476 162 -33.919102 +477 162 -29.770788 +478 162 -53.152471 +479 162 -37.590904 +480 162 -52.682208 +481 162 -92.494848 +482 162 -29.019123 +483 162 -140.783753 +484 162 -17.215236 +500 162 -29.140105 +163 163 5.246713 +319 163 0.147929 +320 163 0.591716 +321 163 0.147929 +322 163 0.147929 +323 163 0.591716 +324 163 0.147929 +325 163 0.065746 +326 163 0.147929 +327 163 0.147929 +329 163 0.065746 +330 163 0.591716 +332 163 0.591716 +333 163 0.147929 +334 163 0.591716 +335 163 0.065746 +337 163 0.147929 +338 163 0.147929 +339 163 0.147929 +340 163 0.147929 +341 163 0.147929 +342 163 0.065746 +361 163 -15.473049 +362 163 -2.767089 +377 163 -10.064452 +386 163 -21.681134 +402 163 -27.596530 +406 163 -18.968424 +411 163 -22.195954 +427 163 -27.723341 +431 163 -25.494369 +436 163 -22.759890 +444 163 -10.250301 +451 163 -5.892227 +452 163 -21.978525 +456 163 -36.069106 +460 163 -22.410503 +461 163 -0.965153 +469 163 -14.122150 +476 163 -28.038671 +480 163 -32.827540 +481 163 -19.816666 +485 163 -24.046141 +494 163 -14.071707 +164 164 3.192143 +320 164 0.591716 +321 164 0.147929 +322 164 0.147929 +323 164 0.147929 +324 164 0.147929 +325 164 0.147929 +326 164 0.147929 +327 164 0.147929 +328 164 0.065746 +329 164 0.147929 +331 164 0.065746 +332 164 0.147929 +337 164 0.147929 +338 164 0.147929 +339 164 0.147929 +340 164 0.147929 +341 164 0.147929 +342 164 0.147929 +361 164 -14.220324 +362 164 -3.525934 +386 164 -20.998505 +411 164 -21.391690 +436 164 -21.826997 +444 164 -23.579761 +456 164 -9.915848 +460 164 -9.279849 +461 164 -19.948178 +469 164 -32.424422 +480 164 -20.269629 +481 164 -5.275353 +483 164 -0.123267 +485 164 -33.058670 +494 164 -32.234492 +165 165 2.600427 +320 165 0.591716 +322 165 0.147929 +323 165 0.065746 +324 165 0.147929 +326 165 0.147929 +327 165 0.147929 +332 165 0.147929 +335 165 0.065746 +337 165 0.591716 +338 165 0.147929 +342 165 0.147929 +166 166 2.485371 +319 166 0.147929 +320 166 0.147929 +321 166 0.065746 +322 166 0.147929 +323 166 0.065746 +324 166 0.065746 +325 166 0.065746 +326 166 0.065746 +327 166 0.147929 +328 166 0.065746 +329 166 0.147929 +331 166 0.147929 +332 166 0.147929 +333 166 0.147929 +334 166 0.065746 +337 166 0.147929 +338 166 0.147929 +340 166 0.147929 +342 166 0.147929 +361 166 -6.615280 +362 166 -1.375276 +377 166 -10.018176 +386 166 -9.476397 +402 166 -27.416509 +406 166 -18.682772 +411 166 -9.677551 +427 166 -27.464867 +431 166 -25.045798 +436 166 -9.898871 +444 166 -10.472564 +452 166 -27.533695 +456 166 -35.346715 +460 166 -12.841648 +461 166 -4.356045 +469 166 -14.401511 +477 166 -27.622962 +480 166 -22.745956 +481 166 -28.729499 +483 166 -0.282385 +485 166 -20.856285 +494 166 -14.318037 +167 167 2.994905 +319 167 0.147929 +320 167 0.065746 +321 167 0.147929 +322 167 0.065746 +323 167 0.147929 +326 167 0.147929 +327 167 0.065746 +328 167 0.147929 +331 167 0.591716 +332 167 0.065746 +335 167 0.065746 +336 167 0.065746 +337 167 0.147929 +338 167 0.065746 +339 167 0.147929 +340 167 0.591716 +342 167 0.065746 +361 167 -28.144177 +362 167 -1.191786 +385 167 -24.333584 +386 167 -12.378795 +406 167 -25.940604 +409 167 -24.404391 +410 167 -15.349100 +430 167 -23.778941 +431 167 -12.119012 +433 167 -28.539358 +434 167 -14.598472 +454 167 -16.166794 +455 167 -71.943440 +456 167 -16.176955 +457 167 -36.982530 +458 167 -9.904513 +459 167 -8.388852 +460 167 -30.501458 +478 167 -11.473934 +479 167 -95.396713 +480 167 -123.199989 +481 167 -37.585664 +482 167 -1.914852 +483 167 -38.467805 +484 167 -26.960342 +168 168 3.553748 +319 168 0.065746 +321 168 0.147929 +322 168 0.147929 +323 168 0.147929 +326 168 0.147929 +327 168 0.065746 +328 168 0.147929 +331 168 0.591716 +332 168 0.147929 +335 168 0.065746 +336 168 0.147929 +337 168 0.147929 +339 168 0.591716 +340 168 0.591716 +342 168 0.147929 +361 168 -27.945913 +362 168 -1.196013 +385 168 -23.733002 +386 168 -12.710982 +406 168 -11.411567 +409 168 -23.367643 +410 168 -16.064958 +430 168 -10.104757 +431 168 -5.674321 +433 168 -27.020471 +434 168 -15.736160 +454 168 -6.340509 +455 168 -59.512572 +456 168 -16.308483 +457 168 -34.924367 +458 168 -11.513040 +459 168 -7.936738 +460 168 -30.552656 +478 168 -3.871003 +479 168 -75.561890 +480 168 -122.854039 +481 168 -37.658804 +482 168 -3.134275 +483 168 -38.104034 +484 168 -27.466873 +169 169 3.455128 +319 169 0.147929 +320 169 0.147929 +321 169 0.065746 +322 169 0.591716 +323 169 0.591716 +324 169 0.147929 +326 169 0.147929 +327 169 0.147929 +328 169 0.147929 +329 169 0.065746 +331 169 0.065746 +332 169 0.147929 +333 169 0.065746 +334 169 0.147929 +335 169 0.065746 +337 169 0.147929 +340 169 0.147929 +341 169 0.065746 +342 169 0.147929 +361 169 -6.679475 +362 169 -1.337384 +377 169 -4.459661 +386 169 -9.512694 +402 169 -12.216295 +406 169 -18.787991 +411 169 -9.720265 +427 169 -12.254881 +431 169 -25.212580 +436 169 -9.948374 +452 169 -12.302581 +456 169 -35.617832 +460 169 -22.774828 +461 169 -3.380689 +476 169 -3.355050 +477 169 -9.004318 +480 169 -24.205738 +481 169 -27.711479 +483 169 -0.126400 +485 169 -34.116712 +170 170 1.663544 +320 170 0.591716 +322 170 0.065746 +323 170 0.065746 +324 170 0.147929 +328 170 0.065746 +332 170 0.065746 +335 170 0.065746 +336 170 0.065746 +337 170 0.147929 +338 170 0.065746 +341 170 0.065746 +458 170 -1.862591 +459 170 -14.989121 +460 170 -12.881515 +481 170 -75.342715 +482 170 -14.937910 +483 170 -13.099039 +171 171 2.649737 +320 171 0.147929 +322 171 0.147929 +323 171 0.065746 +324 171 0.147929 +325 171 0.147929 +326 171 0.147929 +327 171 0.065746 +329 171 0.147929 +332 171 0.591716 +335 171 0.065746 +336 171 0.147929 +337 171 0.065746 +338 171 0.147929 +339 171 0.065746 +341 171 0.147929 +342 171 0.147929 +423 171 -9.956765 +424 171 -32.956830 +425 171 -32.959163 +426 171 -32.961796 +427 171 -32.964770 +428 171 -32.968133 +429 171 -35.875105 +430 171 -228.828920 +444 171 -26.078967 +445 171 -32.949910 +446 171 -32.951326 +447 171 -32.952938 +448 171 -22.998000 +454 171 -77.318229 +455 171 -326.191936 +456 171 -37.665332 +478 171 -38.133598 +479 171 -56.893662 +480 171 -187.077873 +481 171 -127.990523 +482 171 -27.030699 +172 172 1.597798 +320 172 0.147929 +321 172 0.065746 +322 172 0.147929 +323 172 0.065746 +325 172 0.065746 +326 172 0.147929 +327 172 0.147929 +329 172 0.147929 +332 172 0.065746 +336 172 0.147929 +339 172 0.065746 +340 172 0.065746 +342 172 0.065746 +361 172 -7.438858 +362 172 -0.995088 +386 172 -10.079897 +411 172 -10.380524 +435 172 -7.273732 +436 172 -3.434198 +444 172 -10.107556 +455 172 -1.256096 +456 172 -3.488899 +460 172 -11.063762 +469 172 -13.957224 +480 172 -12.318488 +484 172 -2.298902 +485 172 -9.150843 +494 172 -13.944742 +173 173 3.405819 +319 173 0.147929 +320 173 0.147929 +321 173 0.591716 +323 173 0.147929 +324 173 0.147929 +326 173 0.065746 +327 173 0.147929 +331 173 0.147929 +332 173 0.147929 +335 173 0.147929 +336 173 0.147929 +337 173 0.147929 +338 173 0.147929 +339 173 0.147929 +340 173 0.591716 +341 173 0.065746 +342 173 0.065746 +361 173 -113.029461 +362 173 -4.757713 +385 173 -98.699809 +386 173 -48.763388 +406 173 -26.056128 +409 173 -99.974975 +410 173 -59.773284 +430 173 -24.227510 +431 173 -11.843019 +433 173 -117.613559 +434 173 -55.810714 +454 173 -16.982817 +455 173 -71.889333 +456 173 -17.000079 +457 173 -151.731949 +458 173 -35.961307 +478 173 -12.661379 +479 173 -97.021443 +480 173 -165.574377 +481 173 -149.293556 +483 173 -0.837887 +174 174 1.663544 +320 174 0.065746 +321 174 0.147929 +322 174 0.065746 +323 174 0.147929 +324 174 0.065746 +325 174 0.065746 +326 174 0.147929 +327 174 0.065746 +332 174 0.147929 +336 174 0.065746 +337 174 0.065746 +338 174 0.147929 +341 174 0.147929 +342 174 0.065746 +360 174 -10.285883 +361 174 -35.495541 +362 174 -1.035167 +383 174 -1.995285 +384 174 -35.056438 +385 174 -24.971152 +406 174 -3.830251 +407 174 -34.740478 +408 174 -32.890877 +424 174 -1.811931 +425 174 -14.637737 +426 174 -14.638443 +427 174 -14.639241 +428 174 -14.640142 +429 174 -14.641163 +430 174 -104.530798 +431 174 -30.784734 +444 174 -11.583567 +445 174 -14.635255 +446 174 -14.635635 +447 174 -14.636068 +448 174 -14.636558 +449 174 -12.825180 +454 174 -19.956124 +455 174 -193.760606 +456 174 -16.675798 +478 174 -8.508257 +479 174 -24.969552 +480 174 -121.295930 +481 174 -63.449926 +482 174 -9.997076 +175 175 2.271696 +319 175 0.147929 +320 175 0.065746 +321 175 0.147929 +323 175 0.147929 +325 175 0.065746 +326 175 0.065746 +330 175 0.065746 +332 175 0.147929 +335 175 0.147929 +336 175 0.147929 +338 175 0.065746 +339 175 0.147929 +340 175 0.591716 +342 175 0.065746 +361 175 -28.128883 +362 175 -1.192108 +385 175 -24.287376 +386 175 -12.404284 +406 175 -25.904054 +409 175 -24.324620 +410 175 -15.404088 +430 175 -23.636164 +431 175 -12.207200 +433 175 -28.422441 +434 175 -14.685935 +444 175 -13.773527 +445 175 -4.698308 +454 175 -15.906907 +455 175 -72.013985 +456 175 -16.191204 +457 175 -36.824025 +458 175 -10.028262 +470 175 -12.783648 +471 175 -11.966067 +478 175 -11.095840 +479 175 -95.120215 +480 175 -123.251741 +481 175 -37.591243 +482 175 -1.160199 +496 175 -5.618848 +497 175 -17.704271 +498 175 -0.467063 +176 176 1.466305 +321 176 0.147929 +322 176 0.065746 +323 176 0.065746 +324 176 0.147929 +325 176 0.147929 +326 176 0.147929 +327 176 0.147929 +329 176 0.065746 +332 176 0.147929 +338 176 0.065746 +342 176 0.065746 +360 176 -11.200418 +361 176 -35.402985 +362 176 -1.032319 +383 176 -4.311007 +384 176 -34.980918 +385 176 -23.973387 +406 176 -7.906202 +407 176 -34.676861 +408 176 -30.506087 +424 176 -15.790012 +425 176 -32.940528 +426 176 -32.942358 +427 176 -32.944426 +428 176 -32.946763 +429 176 -32.949410 +430 176 -102.410099 +431 176 -26.649811 +444 176 -26.066719 +445 176 -32.934094 +446 176 -32.935079 +447 176 -32.936200 +448 176 -32.937470 +449 176 -17.148894 +454 176 -48.114559 +455 176 -124.342246 +456 176 -11.444095 +478 176 -14.548901 +479 176 -52.096958 +480 176 -62.590279 +481 176 -43.976367 +482 176 -9.707151 +177 177 3.866042 +319 177 0.147929 +320 177 0.147929 +322 177 0.591716 +323 177 0.147929 +324 177 0.147929 +325 177 0.147929 +326 177 0.591716 +327 177 0.147929 +329 177 0.147929 +330 177 0.147929 +331 177 0.147929 +332 177 0.591716 +337 177 0.147929 +339 177 0.147929 +340 177 0.065746 +341 177 0.147929 +406 177 -18.497856 +431 177 -24.745293 +444 177 -23.721568 +456 177 -29.369083 +469 177 -32.605634 +480 177 -8.443088 +481 177 -28.103824 +483 177 -0.275948 +494 177 -32.398058 +178 178 3.077087 +319 178 0.147929 +321 178 0.147929 +322 178 0.065746 +324 178 0.147929 +325 178 0.147929 +326 178 0.591716 +331 178 0.065746 +332 178 0.065746 +333 178 0.065746 +335 178 0.591716 +336 178 0.591716 +339 178 0.065746 +340 178 0.065746 +341 178 0.065746 +362 178 -16.998817 +377 178 -5.525106 +386 178 -15.455634 +387 178 -4.399097 +402 178 -11.212420 +403 178 -3.602932 +406 178 -17.544736 +407 178 -1.753651 +411 178 -19.945201 +428 178 -14.400069 +432 178 -25.260375 +436 178 -20.067275 +444 178 -30.889452 +445 178 -10.996936 +453 178 -7.856485 +454 178 -6.146518 +456 178 -4.684414 +457 178 -24.872290 +461 178 -20.221499 +470 178 -28.205288 +471 178 -27.895137 +479 178 -13.624835 +481 178 -11.817540 +482 178 -24.518468 +483 178 -0.115999 +486 178 -20.408557 +496 178 -11.532764 +497 178 -39.689408 +498 178 -2.675062 +179 179 5.328895 +319 179 0.065746 +321 179 0.147929 +322 179 0.147929 +323 179 0.591716 +324 179 0.147929 +325 179 0.147929 +326 179 0.065746 +327 179 0.147929 +330 179 0.591716 +331 179 0.591716 +335 179 0.147929 +336 179 0.147929 +337 179 0.591716 +338 179 0.591716 +339 179 0.591716 +340 179 0.065746 +341 179 0.147929 +342 179 0.147929 +361 179 -24.643333 +362 179 -1.290361 +385 179 -13.065321 +386 179 -18.977929 +406 179 -10.595182 +409 179 -4.968479 +410 179 -29.248487 +430 179 -6.524408 +431 179 -8.039049 +433 179 -0.297751 +434 179 -36.314108 +444 179 -29.787700 +455 179 -19.399921 +456 179 -2.016943 +458 179 -39.243388 +469 179 -10.333722 +470 179 -30.170131 +479 179 -16.362342 +480 179 -15.978150 +481 179 -1.443525 +482 179 -39.769974 +483 179 -3.128442 +495 179 -21.303851 +496 179 -18.400188 +180 180 2.271696 +320 180 0.147929 +321 180 0.147929 +322 180 0.065746 +323 180 0.065746 +324 180 0.147929 +325 180 0.147929 +327 180 0.147929 +331 180 0.147929 +332 180 0.147929 +335 180 0.065746 +336 180 0.147929 +337 180 0.065746 +338 180 0.065746 +339 180 0.147929 +340 180 0.147929 +341 180 0.147929 +342 180 0.065746 +361 180 -28.334028 +362 180 -1.187853 +385 180 -24.905558 +386 180 -12.064232 +409 180 -25.391901 +410 180 -14.669654 +433 180 -29.987362 +434 180 -13.516771 +444 180 -31.155205 +445 180 -9.898932 +455 180 -12.876500 +456 180 -5.059893 +457 180 -37.902806 +458 180 -8.372798 +470 180 -29.651228 +471 180 -25.388758 +479 180 -18.033723 +480 180 -42.209231 +481 180 -36.473427 +483 180 -0.841401 +496 180 -14.402935 +497 180 -38.546470 +181 181 1.893655 +319 181 0.147929 +320 181 0.065746 +324 181 0.065746 +326 181 0.065746 +330 181 0.147929 +332 181 0.065746 +336 181 0.065746 +337 181 0.147929 +338 181 0.591716 +340 181 0.147929 +341 181 0.065746 +342 181 0.065746 +406 181 -20.627782 +431 181 -27.998680 +455 181 -25.547101 +456 181 -14.543581 +480 181 -59.140008 +182 182 2.321006 +319 182 0.065746 +320 182 0.065746 +321 182 0.147929 +323 182 0.065746 +325 182 0.065746 +326 182 0.065746 +331 182 0.591716 +336 182 0.065746 +337 182 0.065746 +338 182 0.065746 +339 182 0.065746 +340 182 0.591716 +342 182 0.147929 +361 182 -27.928142 +362 182 -1.196398 +385 182 -23.679003 +386 182 -12.740946 +406 182 -11.436428 +409 182 -23.274433 +410 182 -16.129446 +430 182 -10.203635 +431 182 -5.612550 +433 182 -26.883981 +434 182 -15.838549 +444 182 -13.831121 +445 182 -4.462328 +454 182 -6.520800 +455 182 -59.472052 +456 182 -16.296932 +457 182 -34.739523 +458 182 -11.657678 +470 182 -13.095041 +471 182 -11.427321 +478 182 -4.133123 +479 182 -75.799325 +480 182 -122.401003 +481 182 -37.665449 +482 182 -3.326438 +483 182 -3.241410 +496 182 -6.236453 +497 182 -17.350442 +183 183 4.441321 +319 183 0.147929 +320 183 0.591716 +321 183 0.065746 +322 183 0.147929 +323 183 0.591716 +324 183 0.591716 +325 183 0.147929 +327 183 0.591716 +331 183 0.065746 +332 183 0.147929 +337 183 0.147929 +338 183 0.591716 +339 183 0.147929 +340 183 0.147929 +342 183 0.065746 +361 183 -6.875801 +362 183 -1.230384 +386 183 -9.635316 +406 183 -18.969356 +411 183 -9.864000 +431 183 -25.495814 +436 183 -10.114505 +444 183 -23.058078 +456 183 -36.071471 +460 183 -9.942751 +461 183 -0.445285 +469 183 -31.768573 +480 183 -32.884864 +481 183 -19.763214 +483 183 -0.128572 +485 183 -10.685878 +494 183 -31.656001 +184 184 5.131657 +320 184 0.147929 +322 184 0.147929 +323 184 0.591716 +324 184 0.147929 +325 184 0.147929 +326 184 0.591716 +327 184 0.147929 +331 184 0.147929 +332 184 0.147929 +335 184 0.147929 +337 184 0.591716 +338 184 0.591716 +339 184 0.591716 +340 184 0.147929 +342 184 0.591716 +444 184 -22.974929 +455 184 -0.299228 +456 184 -9.964432 +469 184 -31.667236 +480 184 -26.550552 +483 184 -0.291717 +494 184 -31.570685 +185 185 6.084977 +319 185 0.147929 +321 185 0.147929 +322 185 0.147929 +323 185 0.591716 +325 185 0.147929 +326 185 0.591716 +327 185 0.591716 +329 185 0.147929 +330 185 0.147929 +331 185 0.591716 +332 185 0.591716 +337 185 0.591716 +338 185 0.591716 +339 185 0.065746 +340 185 0.147929 +341 185 0.591716 +361 185 -14.993966 +362 185 -3.029393 +386 185 -21.383472 +406 185 -18.733148 +411 185 -21.846973 +431 185 -25.125929 +436 185 -22.356479 +444 185 -23.437582 +456 185 -35.476682 +460 185 -14.779471 +461 185 -8.134936 +469 185 -32.243624 +480 185 -23.480583 +481 185 -28.206263 +483 185 -1.134445 +485 185 -23.523349 +494 185 -32.072408 +186 186 3.241453 +319 186 0.147929 +320 186 0.065746 +321 186 0.147929 +325 186 0.147929 +329 186 0.147929 +330 186 0.591716 +331 186 0.147929 +332 186 0.065746 +333 186 0.065746 +335 186 0.065746 +336 186 0.065746 +337 186 0.147929 +338 186 0.591716 +340 186 0.591716 +361 186 -19.855896 +362 186 -1.609488 +377 186 -4.492621 +386 186 -26.016054 +402 186 -12.330770 +406 186 -20.612571 +410 186 -19.800478 +411 186 -7.402281 +427 186 -12.405115 +431 186 -27.976011 +435 186 -28.494970 +444 186 -25.975225 +451 186 -10.599234 +452 186 -1.889449 +455 186 -40.360808 +456 186 -33.740789 +459 186 -28.178901 +460 186 -1.721167 +469 186 -27.708322 +470 186 -7.820767 +476 186 -12.581415 +480 186 -147.882189 +483 186 -12.318989 +484 186 -19.477852 +495 186 -35.090527 +187 187 1.975838 +319 187 0.147929 +321 187 0.065746 +322 187 0.591716 +323 187 0.147929 +327 187 0.147929 +329 187 0.147929 +331 187 0.147929 +332 187 0.065746 +333 187 0.065746 +337 187 0.065746 +338 187 0.065746 +341 187 0.065746 +361 187 -6.056819 +362 187 -1.760127 +377 187 -4.451030 +386 187 -9.233498 +402 187 -12.171097 +406 187 -18.479934 +411 187 -9.388782 +427 187 -12.178040 +431 187 -24.715405 +436 187 -9.561820 +452 187 -12.194089 +456 187 -24.940093 +461 187 -9.753409 +477 187 -12.219238 +481 187 -25.194077 +483 187 -0.274252 +485 187 -6.907424 +486 187 -3.056995 +188 188 3.323636 +319 188 0.065746 +320 188 0.591716 +321 188 0.147929 +323 188 0.147929 +324 188 0.147929 +325 188 0.065746 +326 188 0.147929 +327 188 0.147929 +329 188 0.147929 +332 188 0.147929 +335 188 0.591716 +336 188 0.065746 +337 188 0.147929 +338 188 0.147929 +340 188 0.065746 +341 188 0.147929 +342 188 0.147929 +361 188 -12.113669 +362 188 -5.221569 +386 188 -20.409156 +406 188 -4.311207 +407 188 -5.821023 +411 188 -20.678490 +432 188 -13.037946 +436 188 -20.984316 +444 188 -11.870484 +445 188 -15.006041 +446 188 -15.016925 +447 188 -2.041939 +456 188 -6.950007 +457 188 -5.880152 +458 188 -6.709643 +461 188 -21.328020 +472 188 -12.987394 +473 188 -15.043433 +474 188 -15.059422 +475 188 -11.764092 +481 188 -9.840208 +482 188 -7.221465 +483 188 -12.171883 +486 188 -21.711146 +500 188 -3.313445 +189 189 2.436062 +319 189 0.147929 +320 189 0.147929 +322 189 0.065746 +324 189 0.147929 +325 189 0.147929 +327 189 0.591716 +332 189 0.065746 +333 189 0.147929 +335 189 0.065746 +337 189 0.147929 +338 189 0.147929 +339 189 0.065746 +340 189 0.147929 +342 189 0.147929 +377 189 -10.065138 +402 189 -27.598912 +406 189 -18.986406 +427 189 -27.726465 +431 189 -25.522230 +444 189 -23.082399 +451 189 -6.286503 +452 189 -21.588116 +456 189 -36.113148 +469 189 -31.798491 +476 189 -28.043283 +480 189 -33.899766 +481 189 -18.814687 +494 189 -31.681555 +190 190 2.567554 +319 190 0.065746 +320 190 0.591716 +321 190 0.147929 +322 190 0.147929 +324 190 0.147929 +325 190 0.065746 +327 190 0.065746 +330 190 0.147929 +331 190 0.147929 +332 190 0.065746 +337 190 0.147929 +338 190 0.065746 +339 190 0.147929 +340 190 0.147929 +341 190 0.147929 +342 190 0.065746 +361 190 -9.777062 +362 190 -7.386346 +386 190 -20.146802 +406 190 -8.102647 +411 190 -20.347215 +431 190 -10.775101 +436 190 -20.581745 +444 190 -10.883892 +456 190 -20.494566 +461 190 -20.851443 +469 190 -14.931073 +481 190 -35.675040 +483 190 -0.263878 +486 190 -21.157512 +494 190 -5.392037 +495 190 -9.408876 +191 191 1.400559 +321 191 0.065746 +328 191 0.065746 +332 191 0.147929 +336 191 0.147929 +339 191 0.591716 +340 191 0.065746 +342 191 0.065746 +362 191 -7.546078 +387 191 -8.779243 +412 191 -8.781986 +437 191 -8.798433 +456 191 -4.556974 +460 191 -6.386667 +461 191 -6.263009 +462 191 -2.565649 +481 191 -11.526292 +485 191 -9.260638 +486 191 -8.872796 +192 192 6.315089 +321 192 0.147929 +322 192 0.591716 +324 192 0.591716 +325 192 0.147929 +327 192 0.147929 +329 192 0.591716 +330 192 0.591716 +332 192 0.591716 +333 192 0.147929 +335 192 0.591716 +336 192 0.147929 +337 192 0.591716 +341 192 0.591716 +342 192 0.591716 +361 192 -19.648767 +362 192 -1.634240 +377 192 -12.671234 +386 192 -25.771831 +402 192 -23.710530 +403 192 -10.230277 +410 192 -18.343829 +411 192 -8.577192 +428 192 -32.936114 +435 192 -28.171970 +444 192 -27.275733 +445 192 -34.497676 +446 192 -12.882125 +453 192 -12.794925 +454 192 -19.180243 +459 192 -25.484436 +460 192 -4.047331 +471 192 -21.662342 +472 192 -34.597923 +473 192 -34.658806 +474 192 -5.235777 +479 192 -31.059767 +483 192 -8.400291 +484 192 -22.607117 +499 192 -29.492252 +500 192 -34.806691 +193 193 2.666174 +320 193 0.147929 +321 193 0.147929 +322 193 0.147929 +324 193 0.147929 +325 193 0.147929 +328 193 0.065746 +329 193 0.065746 +330 193 0.147929 +331 193 0.147929 +332 193 0.147929 +333 193 0.065746 +334 193 0.147929 +335 193 0.147929 +337 193 0.147929 +338 193 0.147929 +339 193 0.147929 +340 193 0.147929 +342 193 0.147929 +361 193 -15.631605 +362 193 -2.688106 +377 193 -4.480890 +386 193 -21.789848 +402 193 -12.291791 +411 193 -22.322931 +427 193 -12.355992 +435 193 -1.350568 +436 193 -21.555723 +444 193 -22.991199 +451 193 -6.468600 +452 193 -5.960775 +455 193 -0.191729 +456 193 -10.059884 +460 193 -30.797422 +469 193 -31.686931 +476 193 -12.511890 +480 193 -26.516227 +483 193 -0.291289 +485 193 -35.012657 +494 193 -31.587090 +194 194 2.748356 +319 194 0.147929 +320 194 0.147929 +321 194 0.147929 +323 194 0.147929 +324 194 0.147929 +325 194 0.147929 +328 194 0.147929 +331 194 0.147929 +332 194 0.147929 +333 194 0.147929 +335 194 0.147929 +336 194 0.147929 +337 194 0.147929 +338 194 0.065746 +339 194 0.065746 +340 194 0.147929 +341 194 0.147929 +342 194 0.147929 +361 194 -25.952218 +362 194 -1.246604 +377 194 -11.057138 +385 194 -17.470249 +386 194 -16.300214 +401 194 -16.471481 +402 194 -14.139957 +406 194 -25.964583 +409 194 -12.563420 +410 194 -23.690394 +426 194 -31.181685 +430 194 -23.872385 +431 194 -12.061384 +433 194 -11.273821 +434 194 -27.726264 +444 194 -24.977458 +450 194 -6.567345 +451 194 -25.208599 +454 194 -16.336845 +455 194 -32.846764 +456 194 -4.185427 +457 194 -13.719504 +458 194 -28.307643 +460 194 -30.904257 +469 194 -34.229349 +475 194 -32.392681 +478 194 -11.721353 +479 194 -39.430807 +480 194 -30.147194 +481 194 -20.070568 +482 194 -25.277128 +483 194 -11.302285 +484 194 -36.954998 +485 194 -1.117197 +494 194 -3.639276 +495 194 -30.247713 +499 194 -4.369629 +500 194 -28.660383 +195 195 7.777942 +319 195 0.147929 +320 195 0.591716 +321 195 0.065746 +322 195 0.147929 +323 195 0.591716 +324 195 0.591716 +326 195 0.065746 +327 195 0.591716 +328 195 0.147929 +329 195 0.591716 +330 195 0.591716 +331 195 0.591716 +332 195 0.591716 +333 195 0.147929 +337 195 0.591716 +338 195 0.591716 +339 195 0.147929 +341 195 0.591716 +342 195 0.147929 +361 195 -6.302385 +362 195 -1.579494 +377 195 -10.015071 +386 195 -9.325172 +402 195 -27.382868 +406 195 -18.524839 +411 195 -9.498491 +427 195 -27.394406 +431 195 -24.789971 +436 195 -9.690457 +452 195 -27.426438 +456 195 -25.031989 +460 195 -16.322124 +461 195 -9.135872 +477 195 -27.478953 +481 195 -25.303647 +483 195 -1.107584 +485 195 -33.114241 +196 196 2.041584 +319 196 0.065746 +320 196 0.147929 +321 196 0.065746 +322 196 0.147929 +323 196 0.147929 +324 196 0.065746 +325 196 0.147929 +327 196 0.147929 +331 196 0.065746 +333 196 0.065746 +335 196 0.147929 +336 196 0.147929 +339 196 0.147929 +340 196 0.147929 +341 196 0.065746 +342 196 0.065746 +362 196 -7.630802 +377 196 -6.578050 +387 196 -8.818201 +402 196 -6.822316 +403 196 -10.647542 +406 196 -4.724066 +407 196 -4.953089 +412 196 -8.757410 +428 196 -9.578516 +429 196 -7.157330 +432 196 -12.504333 +437 196 -8.710806 +444 196 -28.841879 +445 196 -23.329349 +454 196 -13.587853 +455 196 -2.447378 +456 196 -12.434062 +457 196 -9.979604 +458 196 -2.152468 +462 196 -8.678173 +470 196 -13.201302 +471 196 -36.646884 +472 196 -19.188510 +480 196 -15.370233 +481 196 -30.988883 +483 196 -11.913310 +487 196 -8.659360 +497 196 -17.591945 +498 196 -36.933613 +499 196 -10.704232 +197 197 2.863412 +319 197 0.065746 +322 197 0.147929 +325 197 0.065746 +327 197 0.065746 +328 197 0.065746 +329 197 0.147929 +332 197 0.591716 +333 197 0.065746 +335 197 0.591716 +337 197 0.591716 +339 197 0.147929 +340 197 0.065746 +377 197 -4.903187 +402 197 -13.245077 +406 197 -8.221907 +427 197 -5.925675 +428 197 -7.090803 +431 197 -6.972126 +432 197 -3.868412 +444 197 -14.189898 +453 197 -12.800156 +456 197 -4.385309 +457 197 -10.762978 +460 197 -6.451495 +469 197 -2.220876 +470 197 -17.018112 +478 197 -12.596288 +481 197 -11.146222 +482 197 -10.698144 +485 197 -9.413688 +495 197 -3.949898 +496 197 -14.838326 +198 198 1.630671 +320 198 0.147929 +322 198 0.147929 +323 198 0.147929 +324 198 0.147929 +325 198 0.065746 +328 198 0.147929 +329 198 0.147929 +335 198 0.065746 +338 198 0.065746 +341 198 0.147929 +342 198 0.147929 +444 198 -11.670203 +445 198 -14.747152 +446 198 -14.750618 +447 198 -14.754563 +448 198 -14.759038 +449 198 -2.850105 +459 198 -16.404406 +460 198 -29.810110 +474 198 -11.913997 +475 198 -14.769826 +476 198 -14.776294 +477 198 -14.783608 +478 198 -14.791888 +479 198 -12.257399 +482 198 -23.965650 +483 198 -34.479334 +484 198 -18.207771 +199 199 2.501808 +319 199 0.065746 +321 199 0.065746 +323 199 0.147929 +325 199 0.065746 +326 199 0.591716 +327 199 0.147929 +330 199 0.147929 +332 199 0.147929 +335 199 0.591716 +336 199 0.147929 +339 199 0.065746 +341 199 0.065746 +362 199 -8.131908 +387 199 -9.275233 +406 199 -3.908519 +407 199 -6.926304 +412 199 -9.083542 +432 199 -13.860607 +437 199 -8.910924 +444 199 -12.723687 +445 199 -11.251220 +457 199 -1.410199 +458 199 -11.884810 +462 199 -6.953640 +463 199 -1.802820 +470 199 -4.861174 +471 199 -16.159532 +472 199 -10.638581 +483 199 -11.443251 +484 199 -1.325345 +488 199 -8.619327 +497 199 -5.575077 +498 199 -16.275661 +499 199 -7.975875 +200 200 1.548488 +322 200 0.147929 +323 200 0.065746 +324 200 0.147929 +327 200 0.591716 +329 200 0.147929 +332 200 0.065746 +333 200 0.065746 +341 200 0.065746 +377 200 -4.523869 +402 200 -12.312339 +427 200 -12.234797 +452 200 -12.166842 +477 200 -12.108498 +201 201 3.077087 +319 201 0.147929 +320 201 0.147929 +321 201 0.147929 +323 201 0.065746 +324 201 0.147929 +326 201 0.147929 +327 201 0.065746 +328 201 0.065746 +329 201 0.591716 +330 201 0.147929 +331 201 0.147929 +332 201 0.147929 +335 201 0.065746 +336 201 0.147929 +337 201 0.065746 +338 201 0.147929 +339 201 0.147929 +340 201 0.065746 +341 201 0.147929 +342 201 0.065746 +360 201 -17.127859 +361 201 -34.905313 +362 201 -1.017026 +383 201 -19.436537 +384 201 -34.573081 +385 201 -17.597355 +405 201 -29.446783 +406 201 -62.792401 +407 201 -34.332236 +408 201 -15.006935 +427 201 -10.531149 +428 201 -65.784402 +429 201 -68.703808 +430 201 -39.438831 +450 201 -173.003373 +451 201 -149.686028 +452 201 -120.233645 +453 201 -32.022137 +454 201 -29.249476 +455 201 -29.249877 +456 201 -16.082386 +457 201 -14.627822 +458 201 -14.628295 +459 201 -14.628840 +460 201 -12.547656 +475 201 -238.116776 +476 201 -228.943175 +477 201 -52.887351 +478 201 -37.898732 +479 201 -33.133533 +480 201 -33.147403 +481 201 -33.163215 +482 201 -33.181307 +483 201 -30.013713 +500 201 -169.306615 +202 202 3.241453 +319 202 0.147929 +320 202 0.147929 +321 202 0.147929 +323 202 0.065746 +324 202 0.147929 +325 202 0.147929 +328 202 0.147929 +330 202 0.147929 +332 202 0.065746 +335 202 0.065746 +336 202 0.147929 +337 202 0.591716 +338 202 0.147929 +339 202 0.065746 +340 202 0.591716 +341 202 0.147929 +342 202 0.065746 +361 202 -25.258473 +362 202 -1.268516 +385 202 -15.171218 +386 202 -17.680741 +406 202 -25.008320 +409 202 -8.599189 +410 202 -26.569848 +430 202 -19.991356 +431 202 -14.515924 +433 202 -5.534864 +434 202 -32.191482 +444 202 -26.258241 +454 202 -9.247317 +455 202 -69.277789 +456 202 -17.301063 +457 202 -6.054058 +458 202 -34.486422 +460 202 -29.869548 +469 202 -25.616198 +470 202 -10.282129 +478 202 -1.421954 +479 202 -65.534425 +480 202 -129.394190 +481 202 -10.289852 +482 202 -33.334147 +483 202 -7.227588 +484 202 -37.285444 +485 202 -2.467110 +495 202 -35.433068 +203 203 2.863412 +320 203 0.591716 +321 203 0.065746 +322 203 0.065746 +323 203 0.065746 +324 203 0.147929 +325 203 0.147929 +326 203 0.065746 +327 203 0.147929 +328 203 0.147929 +331 203 0.147929 +332 203 0.147929 +335 203 0.147929 +336 203 0.147929 +337 203 0.147929 +338 203 0.147929 +339 203 0.065746 +341 203 0.065746 +342 203 0.147929 +357 203 -2.526895 +358 203 -14.737150 +359 203 -14.746281 +360 203 -14.756889 +361 203 -14.769298 +362 203 -0.429255 +377 203 -11.324749 +378 203 -172.714663 +379 203 -102.732824 +380 203 -18.772268 +381 203 -14.722364 +382 203 -12.202349 +399 203 -24.925051 +400 203 -33.901634 +401 203 -33.946738 +402 203 -22.673133 +403 203 -126.646328 +404 203 -306.602168 +405 203 -71.900787 +406 203 -34.043741 +407 203 -30.760694 +420 203 -21.367282 +421 203 -33.768405 +422 203 -33.795683 +423 203 -33.826676 +424 203 -8.936769 +427 203 -10.131458 +428 203 -87.034684 +429 203 -227.029717 +430 203 -91.403795 +431 203 -48.556454 +432 203 -3.364559 +433 203 -34.219503 +434 203 -34.329150 +435 203 -7.570422 +444 203 -26.693810 +445 203 -12.377196 +452 203 -18.624694 +453 203 -63.140545 +454 203 -167.932564 +455 203 -109.085035 +456 203 -46.795154 +457 203 -48.378220 +460 203 -21.975213 +476 203 -14.355894 +477 203 -29.866197 +478 203 -38.538210 +479 203 -155.758802 +480 203 -85.307117 +481 203 -44.887469 +482 203 -34.307071 +483 203 -41.177786 +500 203 -5.311735 +204 204 4.753616 +319 204 0.147929 +320 204 0.147929 +321 204 0.147929 +322 204 0.591716 +323 204 0.591716 +324 204 0.147929 +327 204 0.147929 +328 204 0.147929 +329 204 0.065746 +331 204 0.147929 +334 204 0.147929 +337 204 0.147929 +338 204 0.147929 +339 204 0.591716 +340 204 0.591716 +341 204 0.591716 +361 204 -16.651092 +362 204 -2.268117 +386 204 -22.602665 +406 204 -19.658966 +411 204 -23.266973 +431 204 -26.547743 +435 204 -15.272454 +436 204 -8.718180 +455 204 -14.606765 +456 204 -55.095876 +460 204 -41.867037 +480 204 -138.281843 +483 204 -0.306060 +484 204 -3.378760 +485 204 -47.760450 +205 205 2.814103 +319 205 0.147929 +321 205 0.147929 +322 205 0.065746 +323 205 0.591716 +327 205 0.147929 +328 205 0.065746 +331 205 0.065746 +332 205 0.591716 +335 205 0.591716 +341 205 0.147929 +362 205 -18.248030 +387 205 -20.822116 +406 205 -8.829422 +407 205 -15.470811 +412 205 -20.400615 +432 205 -31.095052 +437 205 -20.021496 +457 205 -3.596850 +458 205 -26.238771 +460 205 -4.556026 +461 205 -2.576765 +462 205 -18.139283 +463 205 -1.543471 +483 205 -26.668236 +484 205 -2.140555 +486 205 -10.106896 +488 205 -19.382595 +206 206 2.337442 +319 206 0.147929 +320 206 0.065746 +321 206 0.065746 +322 206 0.065746 +324 206 0.147929 +325 206 0.147929 +327 206 0.147929 +328 206 0.065746 +331 206 0.147929 +332 206 0.147929 +334 206 0.065746 +336 206 0.147929 +337 206 0.065746 +338 206 0.147929 +339 206 0.065746 +340 206 0.147929 +341 206 0.147929 +342 206 0.147929 +361 206 -9.534104 +362 206 -0.649070 +385 206 -0.253352 +386 206 -12.171982 +406 206 -20.522991 +410 206 -13.087746 +431 206 -27.842462 +434 206 -6.453976 +435 206 -7.357436 +444 206 -33.438036 +445 206 -2.573196 +455 206 -24.102658 +456 206 -15.803889 +458 206 -1.115856 +459 206 -13.484842 +460 206 -10.692101 +470 206 -39.977721 +471 206 -8.595491 +480 206 -58.921014 +483 206 -15.889956 +484 206 -11.462287 +485 206 -5.003207 +496 206 -34.350017 +497 206 -12.762101 +207 207 1.038955 +320 207 0.065746 +321 207 0.147929 +323 207 0.065746 +332 207 0.147929 +335 207 0.147929 +336 207 0.147929 +341 207 0.065746 +362 207 -18.244548 +387 207 -20.818753 +412 207 -20.397955 +437 207 -20.019503 +462 207 -18.325244 +463 207 -1.356151 +488 207 -19.381840 +208 208 3.849606 +319 208 0.147929 +320 208 0.591716 +321 208 0.147929 +322 208 0.065746 +323 208 0.147929 +327 208 0.147929 +328 208 0.065746 +329 208 0.065746 +331 208 0.147929 +332 208 0.591716 +335 208 0.591716 +336 208 0.591716 +339 208 0.147929 +341 208 0.147929 +362 208 -18.248913 +387 208 -20.822970 +406 208 -8.840398 +407 208 -15.435861 +412 208 -20.401290 +432 208 -31.067024 +437 208 -20.022002 +457 208 -3.728128 +458 208 -26.083502 +460 208 -4.562002 +461 208 -2.568442 +462 208 -18.092260 +463 208 -1.590840 +483 208 -27.090311 +484 208 -1.879696 +486 208 -10.103955 +488 208 -19.382788 +209 209 0.743097 +321 209 0.147929 +322 209 0.065746 +325 209 0.065746 +329 209 0.065746 +335 209 0.147929 +352 209 -8.217393 +353 209 -51.684967 +354 209 -32.904776 +355 209 -32.905176 +356 209 -32.905631 +357 209 -32.906151 +358 209 -32.906748 +359 209 -32.907436 +360 209 -32.908234 +361 209 -32.909165 +362 209 -0.956027 +375 209 -12.197711 +376 209 -15.629348 +377 209 -7.961272 +378 209 -52.111372 +397 209 -4.302801 +398 209 -15.508394 +399 209 -15.543640 +400 209 -3.386017 +402 209 -13.951385 +403 209 -39.014250 +419 209 -0.019589 +420 209 -15.426463 +421 209 -15.450239 +422 209 -11.174617 +426 209 -0.165961 +427 209 -24.854092 +428 209 -28.351373 +444 209 -12.175638 +451 209 -14.622039 +452 209 -12.895086 +453 209 -10.301726 +454 209 -16.006333 +475 209 -2.837448 +476 209 -12.139043 +477 209 -13.088161 +479 209 -26.261093 +500 209 -15.342116 +210 210 2.830539 +324 210 0.147929 +326 210 0.591716 +327 210 0.065746 +329 210 0.591716 +330 210 0.147929 +332 210 0.147929 +334 210 0.147929 +337 210 0.147929 +342 210 0.591716 +211 211 1.679980 +320 211 0.147929 +321 211 0.147929 +322 211 0.147929 +324 211 0.065746 +325 211 0.065746 +327 211 0.065746 +328 211 0.147929 +329 211 0.147929 +332 211 0.147929 +335 211 0.065746 +337 211 0.065746 +339 211 0.065746 +341 211 0.147929 +357 211 -14.252876 +358 211 -33.133721 +359 211 -33.152283 +360 211 -33.173845 +361 211 -33.199059 +362 211 -0.964853 +377 211 -1.477177 +378 211 -15.103848 +379 211 -150.102115 +380 211 -68.556355 +381 211 -37.074515 +382 211 -18.864771 +399 211 -8.767050 +400 211 -15.039715 +401 211 -15.058463 +402 211 -13.602539 +403 211 -11.191981 +404 211 -137.687923 +405 211 -57.728153 +406 211 -30.482148 +407 211 -34.565797 +408 211 -13.229371 +420 211 -8.922973 +421 211 -14.984309 +422 211 -14.995657 +423 211 -15.008548 +424 211 -6.256112 +428 211 -61.026042 +429 211 -51.063171 +430 211 -86.493554 +431 211 -7.600657 +433 211 -21.467216 +434 211 -34.849250 +435 211 -11.075792 +444 211 -11.845983 +445 211 -6.051382 +452 211 -21.671134 +453 211 -55.027848 +454 211 -37.229940 +455 211 -63.455410 +456 211 -28.636978 +460 211 -18.956281 +476 211 -2.770129 +477 211 -46.570327 +478 211 -29.290608 +479 211 -37.259814 +480 211 -30.103702 +481 211 -49.156653 +482 211 -10.965956 +212 212 3.027778 +320 212 0.591716 +321 212 0.147929 +322 212 0.147929 +323 212 0.065746 +324 212 0.147929 +325 212 0.147929 +327 212 0.147929 +328 212 0.147929 +329 212 0.065746 +332 212 0.147929 +335 212 0.591716 +336 212 0.065746 +337 212 0.065746 +339 212 0.147929 +341 212 0.147929 +356 212 -16.986900 +357 212 -33.051556 +358 212 -33.062759 +359 212 -33.075690 +360 212 -33.090703 +361 212 -33.108248 +362 212 -0.962087 +377 212 -30.170222 +378 212 -46.478778 +379 212 -372.068729 +380 212 -67.377967 +381 212 -19.288447 +398 212 -3.036386 +399 212 -34.023372 +400 212 -34.070207 +401 212 -34.123301 +402 212 -4.013326 +403 212 -71.142945 +404 212 -349.202937 +405 212 -19.497370 +406 212 -31.208220 +407 212 -34.553683 +408 212 -12.862376 +420 212 -24.364007 +421 212 -33.913592 +422 212 -33.945632 +423 212 -30.945667 +427 212 -14.790475 +428 212 -58.845964 +429 212 -268.684623 +430 212 -93.089757 +431 212 -1.421591 +433 212 -21.821072 +434 212 -34.834902 +435 212 -10.996415 +444 212 -26.802830 +445 212 -9.521492 +452 212 -36.892373 +453 212 -48.037554 +454 212 -233.500490 +455 212 -99.815151 +456 212 -16.069167 +460 212 -19.022213 +476 212 -25.579510 +477 212 -37.639442 +478 212 -37.221232 +479 212 -130.087387 +480 212 -133.291827 +481 212 -62.770258 +482 212 -5.696139 +500 212 -6.270051 +213 213 1.910092 +319 213 0.147929 +320 213 0.065746 +321 213 0.147929 +323 213 0.147929 +324 213 0.065746 +326 213 0.147929 +327 213 0.065746 +328 213 0.065746 +331 213 0.147929 +332 213 0.147929 +333 213 0.147929 +335 213 0.147929 +336 213 0.065746 +341 213 0.147929 +361 213 -24.257999 +362 213 -1.305384 +377 213 -10.811077 +385 213 -11.708847 +386 213 -19.830761 +402 213 -29.247655 +406 213 -20.252745 +409 213 -2.630050 +410 213 -30.995406 +427 213 -20.858367 +428 213 -7.948102 +431 213 -27.438973 +434 213 -35.921052 +453 213 -28.391196 +455 213 -15.063190 +456 213 -13.034239 +458 213 -35.375702 +459 213 -3.659495 +460 213 -14.010260 +478 213 -28.002119 +480 213 -28.799069 +482 213 -35.830900 +483 213 -13.644293 +484 213 -15.597376 +214 214 2.452498 +319 214 0.147929 +320 214 0.065746 +321 214 0.065746 +323 214 0.147929 +324 214 0.065746 +327 214 0.147929 +328 214 0.147929 +329 214 0.065746 +330 214 0.065746 +331 214 0.065746 +332 214 0.591716 +333 214 0.147929 +335 214 0.147929 +336 214 0.065746 +339 214 0.065746 +340 214 0.065746 +341 214 0.065746 +342 214 0.065746 +361 214 -11.491066 +362 214 -0.555343 +377 214 -11.720944 +385 214 -7.623161 +386 214 -7.328492 +401 214 -23.661057 +402 214 -8.905852 +406 214 -26.768499 +409 214 -5.339918 +410 214 -10.704949 +426 214 -33.345011 +430 214 -26.910902 +431 214 -10.225105 +433 214 -4.657042 +434 214 -12.596443 +450 214 -30.088058 +451 214 -4.060952 +454 214 -21.849379 +455 214 -22.497549 +456 214 -1.834952 +457 214 -5.624414 +458 214 -12.960956 +460 214 -29.839779 +474 214 -6.857175 +475 214 -28.118555 +478 214 -19.750981 +479 214 -27.365546 +480 214 -12.974802 +481 214 -8.315352 +482 214 -11.730813 +483 214 -7.378220 +484 214 -37.295592 +485 214 -2.506573 +499 214 -35.821302 +215 215 4.145464 +319 215 0.147929 +321 215 0.147929 +322 215 0.147929 +323 215 0.591716 +324 215 0.591716 +327 215 0.147929 +328 215 0.065746 +329 215 0.065746 +331 215 0.147929 +332 215 0.147929 +333 215 0.065746 +334 215 0.591716 +335 215 0.147929 +339 215 0.591716 +340 215 0.147929 +342 215 0.147929 +361 215 -15.673740 +362 215 -2.667766 +377 215 -4.482458 +386 215 -21.819580 +402 215 -12.297065 +406 215 -19.066989 +411 215 -22.357621 +427 215 -12.362718 +431 215 -25.646690 +435 215 -1.960099 +436 215 -20.986159 +451 215 -7.114015 +452 215 -5.323543 +455 215 -0.299744 +456 215 -36.012312 +460 215 -30.855502 +476 215 -12.521536 +480 215 -38.117645 +481 215 -14.916820 +483 215 -0.291802 +485 215 -35.084808 +216 216 4.079717 +320 216 0.591716 +321 216 0.065746 +322 216 0.147929 +323 216 0.591716 +327 216 0.147929 +329 216 0.147929 +331 216 0.147929 +332 216 0.147929 +333 216 0.065746 +335 216 0.147929 +337 216 0.147929 +338 216 0.591716 +339 216 0.147929 +340 216 0.147929 +341 216 0.591716 +362 216 -8.523449 +377 216 -7.117774 +387 216 -9.659085 +402 216 -5.516266 +403 216 -13.304107 +412 216 -9.394566 +428 216 -5.679960 +429 216 -12.230076 +437 216 -4.281804 +438 216 -4.871875 +454 216 -7.116158 +455 216 -9.927669 +456 216 -13.822449 +463 216 -8.935004 +480 216 -9.855923 +481 216 -34.239677 +482 216 -6.340307 +483 216 -0.332543 +488 216 -8.737248 +217 217 2.156640 +319 217 0.147929 +320 217 0.147929 +321 217 0.065746 +322 217 0.147929 +323 217 0.147929 +324 217 0.147929 +327 217 0.147929 +328 217 0.147929 +329 217 0.147929 +331 217 0.147929 +339 217 0.147929 +340 217 0.065746 +341 217 0.147929 +342 217 0.147929 +361 217 -6.607830 +362 217 -1.379765 +386 217 -9.472304 +406 217 -18.715121 +411 217 -9.672730 +431 217 -25.097317 +436 217 -9.893279 +456 217 -29.860105 +460 217 -21.535762 +461 217 -4.469567 +480 217 -10.335175 +481 217 -26.904673 +483 217 -0.282635 +485 217 -33.901067 +218 218 3.553748 +321 218 0.065746 +322 218 0.147929 +323 218 0.591716 +324 218 0.065746 +326 218 0.147929 +327 218 0.147929 +329 218 0.591716 +330 218 0.147929 +331 218 0.065746 +332 218 0.591716 +333 218 0.147929 +341 218 0.591716 +361 218 -6.591341 +362 218 -1.389768 +377 218 -10.017737 +386 218 -9.463335 +402 218 -27.414059 +411 218 -9.662158 +427 218 -27.460587 +436 218 -9.881014 +452 218 -27.527585 +460 218 -5.399914 +461 218 -4.721022 +477 218 -27.615023 +483 218 -0.125303 +485 218 -10.383035 +219 219 3.570184 +319 219 0.147929 +320 219 0.591716 +322 219 0.147929 +323 219 0.065746 +324 219 0.147929 +331 219 0.147929 +332 219 0.591716 +337 219 0.591716 +338 219 0.591716 +339 219 0.147929 +341 219 0.147929 +406 219 -18.605470 +431 219 -24.921604 +456 219 -25.192166 +481 219 -25.492980 +483 219 -0.279994 +220 220 5.493261 +319 220 0.147929 +320 220 0.147929 +322 220 0.147929 +323 220 0.591716 +324 220 0.147929 +326 220 0.591716 +327 220 0.065746 +328 220 0.147929 +329 220 0.147929 +330 220 0.591716 +331 220 0.591716 +332 220 0.591716 +333 220 0.147929 +334 220 0.147929 +337 220 0.147929 +338 220 0.147929 +339 220 0.147929 +341 220 0.591716 +377 220 -10.015775 +402 220 -27.401450 +406 220 -18.630564 +427 220 -27.437368 +431 220 -24.962105 +452 220 -27.493757 +456 220 -25.241019 +460 220 -15.780598 +477 220 -27.570594 +481 220 -25.550375 +483 220 -1.122766 +485 220 -23.353430 +221 221 5.575444 +319 221 0.147929 +320 221 0.591716 +322 221 0.147929 +323 221 0.147929 +324 221 0.147929 +326 221 0.591716 +327 221 0.147929 +328 221 0.147929 +329 221 0.147929 +330 221 0.591716 +331 221 0.147929 +332 221 0.147929 +333 221 0.147929 +334 221 0.147929 +337 221 0.591716 +338 221 0.591716 +339 221 0.147929 +341 221 0.591716 +377 221 -10.016153 +402 221 -27.404218 +406 221 -18.639575 +427 221 -27.442675 +431 221 -24.976602 +452 221 -27.501603 +456 221 -25.258463 +460 221 -15.795159 +477 221 -27.580976 +481 221 -25.570835 +483 221 -0.280960 +485 221 -23.377566 +222 222 5.854865 +319 222 0.147929 +320 222 0.591716 +322 222 0.591716 +323 222 0.591716 +324 222 0.147929 +327 222 0.147929 +328 222 0.147929 +329 222 0.591716 +331 222 0.591716 +333 222 0.147929 +337 222 0.591716 +338 222 0.591716 +339 222 0.065746 +340 222 0.065746 +341 222 0.591716 +377 222 -10.016369 +402 222 -27.405699 +406 222 -18.644586 +427 222 -27.445458 +431 222 -24.984655 +452 222 -27.505688 +456 222 -29.703642 +460 222 -15.803861 +477 222 -27.586362 +480 222 -9.839629 +481 222 -27.179606 +483 222 -1.124467 +485 222 -23.391986 +223 223 4.589250 +319 223 0.591716 +321 223 0.065746 +322 223 0.147929 +323 223 0.591716 +327 223 0.147929 +328 223 0.147929 +329 223 0.591716 +331 223 0.147929 +332 223 0.591716 +337 223 0.065746 +338 223 0.065746 +339 223 0.591716 +341 223 0.591716 +361 223 -6.511205 +362 223 -1.439684 +386 223 -9.421456 +406 223 -74.476209 +411 223 -9.612721 +431 223 -99.774197 +436 223 -9.823595 +456 223 -100.874635 +460 223 -19.868655 +461 223 -5.945891 +481 223 -102.096496 +483 223 -0.280318 +485 223 -33.626621 +224 224 4.293393 +319 224 0.147929 +320 224 0.591716 +321 224 0.065746 +322 224 0.147929 +323 224 0.147929 +324 224 0.147929 +326 224 0.147929 +327 224 0.147929 +328 224 0.147929 +329 224 0.065746 +331 224 0.147929 +332 224 0.147929 +333 224 0.065746 +337 224 0.591716 +338 224 0.591716 +339 224 0.147929 +341 224 0.591716 +361 224 -6.543806 +362 224 -1.419118 +377 224 -4.451716 +386 224 -9.438153 +402 224 -12.180282 +406 224 -18.641999 +411 224 -9.632448 +427 224 -12.197929 +431 224 -24.980498 +436 224 -9.846519 +452 224 -12.224673 +456 224 -25.263147 +460 224 -20.429595 +461 224 -5.447143 +477 224 -12.260504 +481 224 -25.576326 +483 224 -0.280988 +485 224 -33.716005 +225 225 0.381492 +333 225 0.065746 +337 225 0.065746 +377 225 -4.451447 +402 225 -12.178354 +427 225 -12.194254 +452 225 -12.219252 +477 225 -12.253338 +226 226 0.759533 +322 226 0.147929 +331 226 0.147929 +341 226 0.065746 +342 226 0.147929 +483 226 -0.281270 +227 227 5.115220 +319 227 0.147929 +320 227 0.591716 +321 227 0.065746 +322 227 0.147929 +323 227 0.147929 +324 227 0.147929 +327 227 0.591716 +328 227 0.065746 +329 227 0.591716 +331 227 0.591716 +337 227 0.591716 +341 227 0.591716 +342 227 0.591716 +361 227 -6.335723 +362 227 -1.556270 +386 227 -9.339348 +406 227 -18.538195 +411 227 -9.515365 +431 227 -24.811957 +436 227 -9.710170 +456 227 -25.058910 +460 227 -8.223048 +461 227 -8.628683 +481 227 -25.335604 +483 227 -1.109574 +485 227 -20.395399 +228 228 4.161900 +319 228 0.147929 +320 228 0.147929 +321 228 0.147929 +323 228 0.591716 +324 228 0.147929 +327 228 0.147929 +328 228 0.147929 +330 228 0.147929 +331 228 0.147929 +335 228 0.591716 +337 228 0.147929 +339 228 0.065746 +340 228 0.147929 +341 228 0.591716 +342 228 0.591716 +361 228 -26.205243 +362 228 -1.239242 +385 228 -18.291200 +386 228 -15.815866 +406 228 -25.508661 +409 228 -13.979167 +410 228 -22.673111 +430 228 -22.063601 +431 228 -13.189592 +433 228 -13.328516 +434 228 -26.140492 +454 228 -13.039558 +455 228 -35.200407 +456 228 -4.210445 +457 228 -16.472295 +458 228 -26.103290 +459 228 -0.505696 +460 228 -31.681825 +478 228 -6.927093 +479 228 -42.532732 +480 228 -30.555349 +481 228 -23.593884 +482 228 -22.390812 +483 228 -15.564130 +484 228 -36.092262 +229 229 7.350592 +319 229 0.147929 +320 229 0.591716 +322 229 0.147929 +323 229 0.591716 +324 229 0.147929 +326 229 0.147929 +327 229 0.591716 +328 229 0.591716 +329 229 0.591716 +330 229 0.591716 +331 229 0.591716 +332 229 0.147929 +337 229 0.591716 +338 229 0.591716 +339 229 0.147929 +340 229 0.147929 +341 229 0.591716 +342 229 0.147929 +406 229 -18.637928 +431 229 -24.973954 +456 229 -35.230862 +460 229 -63.144609 +480 229 -22.030419 +481 229 -29.257509 +483 229 -1.123343 +485 229 -93.450551 +230 230 5.854865 +319 230 0.147929 +320 230 0.591716 +321 230 0.065746 +322 230 0.147929 +323 230 0.147929 +324 230 0.147929 +326 230 0.591716 +327 230 0.147929 +328 230 0.065746 +329 230 0.147929 +331 230 0.591716 +332 230 0.591716 +337 230 0.591716 +338 230 0.591716 +339 230 0.147929 +340 230 0.147929 +341 230 0.147929 +342 230 0.591716 +361 230 -6.340072 +362 230 -1.553264 +386 230 -9.341229 +406 230 -18.546388 +411 230 -9.517604 +431 230 -24.825404 +436 230 -9.712784 +456 230 -34.990318 +460 230 -8.294403 +461 230 -8.562422 +480 230 -20.239871 +481 230 -30.657612 +483 230 -1.110167 +485 230 -20.402296 +231 231 2.600427 +319 231 0.147929 +320 231 0.147929 +321 231 0.147929 +323 231 0.147929 +324 231 0.147929 +327 231 0.147929 +328 231 0.147929 +330 231 0.147929 +331 231 0.147929 +332 231 0.147929 +333 231 0.065746 +337 231 0.147929 +338 231 0.147929 +339 231 0.147929 +340 231 0.065746 +341 231 0.147929 +342 231 0.147929 +361 231 -14.938298 +362 231 -3.062172 +377 231 -4.452715 +386 231 -21.351890 +402 231 -12.186154 +406 231 -18.694558 +411 231 -21.809813 +427 231 -12.208399 +431 231 -25.064596 +436 231 -22.313417 +452 231 -12.239741 +456 231 -29.814102 +460 231 -29.789474 +461 231 -8.980484 +477 231 -12.280167 +480 231 -10.185618 +481 231 -26.988463 +483 231 -0.282846 +485 231 -47.026598 +232 232 3.915352 +320 232 0.591716 +321 232 0.147929 +322 232 0.147929 +324 232 0.147929 +326 232 0.065746 +328 232 0.065746 +330 232 0.147929 +331 232 0.147929 +332 232 0.147929 +334 232 0.065746 +337 232 0.591716 +338 232 0.591716 +339 232 0.147929 +341 232 0.591716 +342 232 0.065746 +361 232 -14.940585 +362 232 -3.060816 +386 232 -21.353175 +411 232 -21.811326 +436 232 -22.315170 +460 232 -20.990759 +461 232 -8.945715 +483 232 -0.282869 +485 232 -33.941329 +233 233 2.583991 +319 233 0.147929 +320 233 0.591716 +324 233 0.591716 +326 233 0.065746 +329 233 0.065746 +332 233 0.147929 +333 233 0.065746 +337 233 0.147929 +338 233 0.147929 +339 233 0.147929 +341 233 0.147929 +342 233 0.065746 +377 233 -4.451023 +402 233 -12.173922 +406 233 -18.587043 +427 233 -12.185026 +431 233 -24.891736 +452 233 -12.205232 +456 233 -25.156019 +477 233 -12.234532 +481 233 -25.450414 +234 234 4.013971 +319 234 0.147929 +321 234 0.147929 +322 234 0.147929 +325 234 0.591716 +326 234 0.147929 +327 234 0.147929 +332 234 0.591716 +335 234 0.591716 +337 234 0.591716 +338 234 0.591716 +340 234 0.065746 +361 234 -8.758491 +362 234 -8.366201 +386 234 -20.084449 +406 234 -18.368674 +411 234 -20.265845 +431 234 -24.267542 +436 234 -20.480807 +444 234 -124.725118 +456 234 -11.317790 +457 234 -17.177802 +461 234 -20.730297 +469 234 -26.789011 +470 234 -142.483421 +481 234 -11.066680 +482 234 -24.058295 +486 234 -21.015426 +495 234 -51.335606 +496 234 -114.184482 +235 235 8.665516 +319 235 0.147929 +320 235 0.591716 +321 235 0.065746 +322 235 0.591716 +323 235 0.591716 +324 235 0.591716 +326 235 0.591716 +327 235 0.591716 +328 235 0.147929 +330 235 0.591716 +332 235 0.591716 +333 235 0.591716 +334 235 0.147929 +337 235 0.591716 +338 235 0.591716 +339 235 0.147929 +340 235 0.065746 +341 235 0.591716 +342 235 0.591716 +361 235 -6.525440 +362 235 -1.430661 +377 235 -40.066280 +386 235 -9.428689 +402 235 -109.628086 +406 235 -18.638524 +411 235 -9.621270 +427 235 -109.791658 +431 235 -24.974913 +436 235 -9.833531 +452 235 -110.037112 +456 235 -29.690353 +460 235 -20.114195 +461 235 -5.728073 +477 235 -110.364338 +480 235 -9.799697 +481 235 -27.201196 +485 235 -33.666638 +236 236 1.712853 +320 236 0.147929 +323 236 0.065746 +337 236 0.591716 +338 236 0.591716 +341 236 0.065746 +237 237 1.236193 +321 237 0.147929 +322 237 0.065746 +324 237 0.147929 +325 237 0.065746 +327 237 0.065746 +329 237 0.065746 +333 237 0.065746 +337 237 0.065746 +341 237 0.147929 +342 237 0.147929 +360 237 -8.218552 +361 237 -35.723726 +362 237 -1.042194 +377 237 -10.173730 +378 237 -7.663248 +384 237 -32.019071 +385 237 -27.243414 +403 237 -7.435919 +404 237 -15.126351 +405 237 -15.157385 +406 237 -6.023210 +407 237 -29.589403 +408 237 -35.055885 +409 237 -3.223111 +422 237 -0.775205 +423 237 -14.658555 +424 237 -14.659911 +425 237 -14.661441 +426 237 -14.663170 +427 237 -14.665122 +428 237 -14.667330 +429 237 -14.669830 +430 237 -14.672670 +431 237 -107.029130 +432 237 -44.640496 +444 237 -11.599144 +445 237 -14.655370 +446 237 -14.656299 +447 237 -13.882151 +455 237 -23.443598 +456 237 -45.656960 +457 237 -58.853086 +458 237 -15.726848 +479 237 -14.683324 +480 237 -31.622710 +481 237 -24.878485 +482 237 -33.252302 +483 237 -33.531038 +484 237 -4.876676 +238 238 2.600427 +319 238 0.147929 +320 238 0.147929 +322 238 0.147929 +323 238 0.147929 +324 238 0.591716 +328 238 0.065746 +330 238 0.147929 +333 238 0.147929 +335 238 0.147929 +337 238 0.147929 +338 238 0.147929 +339 238 0.147929 +341 238 0.147929 +342 238 0.065746 +377 238 -10.232123 +402 238 -28.137206 +406 238 -19.622551 +426 238 -16.936314 +427 238 -11.448622 +431 238 -26.492785 +451 238 -28.653865 +455 238 -2.826354 +456 238 -24.195536 +460 238 -7.584859 +476 238 -28.943731 +480 238 -27.589081 +485 238 -11.319741 +239 239 1.597798 +319 239 0.147929 +320 239 0.065746 +321 239 0.147929 +323 239 0.147929 +325 239 0.147929 +326 239 0.065746 +328 239 0.065746 +329 239 0.065746 +332 239 0.065746 +333 239 0.065746 +335 239 0.065746 +339 239 0.147929 +341 239 0.147929 +362 239 -18.254076 +377 239 -7.258185 +387 239 -20.827958 +402 239 -5.221509 +403 239 -13.948863 +406 239 -8.821424 +407 239 -15.496383 +412 239 -20.405235 +428 239 -4.787048 +429 239 -13.425391 +432 239 -31.115596 +437 239 -20.024960 +444 239 -28.622397 +445 239 -25.373296 +454 239 -5.644504 +455 239 -11.657290 +457 239 -3.500976 +458 239 -26.352228 +460 239 -4.546437 +461 239 -2.590146 +462 239 -17.818981 +463 239 -1.866140 +470 239 -10.871922 +471 239 -36.351001 +472 239 -24.074964 +480 239 -7.814269 +481 239 -8.627802 +483 239 -26.347167 +484 239 -2.330983 +486 239 -10.111648 +488 239 -19.383915 +497 239 -12.397498 +498 239 -36.611598 +499 239 -18.155779 +240 240 5.115220 +320 240 0.147929 +321 240 0.065746 +323 240 0.591716 +324 240 0.147929 +327 240 0.591716 +328 240 0.065746 +329 240 0.591716 +335 240 0.147929 +337 240 0.147929 +339 240 0.591716 +340 240 0.591716 +341 240 0.591716 +342 240 0.591716 +361 240 -7.185802 +362 240 -1.088411 +386 240 -9.864016 +411 240 -10.130376 +435 240 -3.956479 +436 240 -6.464569 +455 240 -6.202927 +456 240 -35.527686 +460 240 -18.162060 +480 240 -108.120171 +485 240 -22.137847 +241 241 2.288133 +319 241 0.147929 +320 241 0.147929 +321 241 0.147929 +322 241 0.147929 +323 241 0.147929 +324 241 0.065746 +325 241 0.147929 +326 241 0.065746 +332 241 0.147929 +333 241 0.147929 +335 241 0.147929 +337 241 0.065746 +339 241 0.147929 +340 241 0.147929 +341 241 0.065746 +342 241 0.147929 +361 241 -22.499515 +362 241 -1.390975 +377 241 -10.014716 +385 241 -5.045863 +386 241 -24.228727 +402 241 -27.388673 +406 241 -21.246049 +410 241 -30.978222 +427 241 -27.410123 +431 241 -28.918505 +434 241 -23.992439 +435 241 -8.851800 +444 241 -33.206706 +445 241 -3.192256 +452 241 -27.452055 +455 241 -34.167593 +456 241 -7.566357 +458 241 -15.423586 +459 241 -19.460642 +470 241 -39.053574 +471 241 -10.019279 +477 241 -27.514452 +480 241 -61.991282 +482 241 -10.202861 +483 241 -26.905704 +496 241 -32.604207 +497 241 -14.962299 +242 242 3.372945 +319 242 0.147929 +320 242 0.065746 +321 242 0.147929 +322 242 0.147929 +323 242 0.591716 +324 242 0.065746 +325 242 0.147929 +326 242 0.147929 +327 242 0.147929 +329 242 0.147929 +332 242 0.147929 +333 242 0.065746 +335 242 0.065746 +336 242 0.147929 +337 242 0.065746 +339 242 0.591716 +340 242 0.065746 +341 242 0.147929 +342 242 0.065746 +361 242 -16.628786 +362 242 -2.275802 +377 242 -4.544371 +386 242 -22.582937 +402 242 -12.495347 +406 242 -19.612373 +411 242 -23.244140 +426 242 -7.178318 +427 242 -5.425332 +431 242 -26.477415 +435 242 -14.987720 +436 242 -8.976748 +444 242 -22.761510 +451 242 -12.721363 +455 242 -3.730084 +456 242 -27.995963 +460 242 -24.747532 +469 242 -31.422513 +476 242 -12.848372 +480 242 -39.822274 +484 242 -2.912622 +485 242 -22.684491 +494 242 -31.384867 +243 243 0.545858 +324 243 0.147929 +341 243 0.147929 +244 244 1.679980 +319 244 0.147929 +320 244 0.147929 +321 244 0.147929 +324 244 0.065746 +325 244 0.147929 +326 244 0.147929 +330 244 0.065746 +332 244 0.147929 +335 244 0.147929 +338 244 0.065746 +339 244 0.065746 +340 244 0.065746 +342 244 0.065746 +361 244 -20.338013 +362 244 -1.557366 +386 244 -26.592184 +406 244 -21.133605 +410 244 -23.059613 +411 244 -4.808321 +431 244 -28.751401 +434 244 -3.475644 +435 244 -25.782664 +444 244 -25.003070 +455 244 -29.213797 +456 244 -5.576772 +459 244 -30.771391 +469 244 -34.262652 +480 244 -44.080175 +483 244 -19.947499 +484 244 -12.467510 +494 244 -3.265720 +495 244 -30.652038 +245 245 1.121137 +319 245 0.065746 +320 245 0.065746 +321 245 0.147929 +330 245 0.591716 +361 245 -20.377238 +362 245 -1.553433 +386 245 -26.639492 +406 245 -9.402967 +410 245 -23.317364 +411 245 -4.605227 +431 245 -12.793641 +434 245 -3.886098 +435 245 -25.434983 +455 245 -11.937226 +456 245 -1.226435 +459 245 -30.843105 +480 245 -13.556306 +483 245 -20.583792 +484 245 -11.912744 +246 246 1.055391 +323 246 0.065746 +325 246 0.147929 +326 246 0.147929 +332 246 0.147929 +335 246 0.147929 +336 246 0.147929 +444 246 -23.029021 +469 246 -31.732979 +494 246 -31.625796 +247 247 1.252630 +319 247 0.147929 +321 247 0.065746 +323 247 0.065746 +325 247 0.147929 +331 247 0.065746 +332 247 0.147929 +335 247 0.065746 +337 247 0.147929 +339 247 0.147929 +361 247 -9.457191 +362 247 -0.654970 +386 247 -12.329888 +406 247 -20.844626 +410 247 -12.880223 +411 247 -0.096891 +431 247 -28.321606 +434 247 -5.724482 +435 247 -7.959424 +444 247 -31.593402 +455 247 -23.262883 +456 247 -5.832040 +458 247 -0.123988 +459 247 -14.330514 +469 247 -5.740521 +470 247 -37.113396 +480 247 -29.916425 +483 247 -15.479420 +495 247 -10.612178 +496 247 -31.261786 +248 248 1.926529 +320 248 0.065746 +321 248 0.147929 +323 248 0.147929 +324 248 0.147929 +325 248 0.065746 +326 248 0.147929 +331 248 0.147929 +335 248 0.065746 +336 248 0.147929 +337 248 0.147929 +338 248 0.147929 +341 248 0.147929 +342 248 0.147929 +361 248 -22.103746 +362 248 -1.415196 +385 248 -3.409779 +386 248 -25.363867 +410 248 -30.395473 +434 248 -20.501223 +435 248 -11.668869 +444 248 -12.407125 +445 248 -15.139286 +458 248 -10.656892 +459 248 -23.451516 +470 248 -0.561949 +471 248 -15.734017 +472 248 -15.771557 +473 248 -3.963092 +482 248 -4.120394 +483 248 -32.594103 +498 248 -11.851336 +499 248 -15.863321 +500 248 -5.778708 +249 249 0.397929 +338 249 0.147929 +250 250 2.666174 +319 250 0.147929 +321 250 0.147929 +325 250 0.147929 +327 250 0.591716 +328 250 0.147929 +329 250 0.147929 +330 250 0.591716 +331 250 0.147929 +332 250 0.065746 +339 250 0.147929 +340 250 0.065746 +342 250 0.065746 +361 250 -14.847766 +362 250 -3.116488 +386 250 -21.301852 +406 250 -18.676164 +411 250 -21.750876 +431 250 -25.035243 +436 250 -22.245068 +444 250 -23.552415 +456 250 -29.773728 +460 250 -28.285474 +461 250 -10.359193 +469 250 -32.389572 +480 250 -10.066405 +481 250 -27.051319 +483 250 -0.282092 +485 250 -46.859966 +494 250 -32.203153 +251 251 1.975838 +319 251 0.065746 +321 251 0.147929 +322 251 0.147929 +324 251 0.147929 +327 251 0.591716 +328 251 0.147929 +329 251 0.147929 +337 251 0.065746 +338 251 0.065746 +339 251 0.065746 +340 251 0.065746 +341 251 0.065746 +355 251 -31.740294 +356 251 -32.997430 +357 251 -33.004162 +358 251 -33.011892 +359 251 -33.020811 +360 251 -33.031161 +361 251 -33.043252 +362 251 -0.960108 +369 251 -150.689183 +370 251 -68.126067 +371 251 -47.587695 +372 251 -47.589762 +373 251 -47.592105 +374 251 -47.245191 +375 251 -32.971093 +376 251 -32.974241 +377 251 -32.977796 +378 251 -32.981816 +379 251 -32.986370 +380 251 -1.251247 +394 251 -288.479340 +395 251 -89.893967 +396 251 -63.291247 +397 251 -47.945210 +398 251 -47.959585 +399 251 -45.847839 +400 251 -47.719094 +401 251 -47.727740 +402 251 -47.737510 +403 251 -38.831762 +404 251 -14.627770 +405 251 -14.628147 +406 251 -11.988084 +419 251 -169.658110 +420 251 -83.317518 +421 251 -57.993145 +422 251 -29.089986 +423 251 -15.812605 +424 251 -3.639379 +425 251 -14.901820 +426 251 -14.914209 +427 251 -14.928234 +428 251 -23.237705 +429 251 -33.133320 +430 251 -33.147178 +431 251 -33.162975 +432 251 -33.181051 +433 251 -33.201827 +434 251 -15.571398 +444 251 -95.527129 +445 251 -92.311585 +446 251 -51.946603 +447 251 -48.910816 +448 251 -20.841932 +449 251 -21.053150 +450 251 -15.917074 +451 251 -1.914922 +453 251 -0.623230 +454 251 -14.962200 +455 251 -14.982785 +456 251 -1.492022 +459 251 -17.654432 +460 251 -28.519850 +469 251 -31.454989 +470 251 -131.175656 +471 251 -37.873822 +472 251 -33.079098 +473 251 -43.483248 +474 251 -18.123949 +475 251 -14.560368 +476 251 -14.065681 +477 251 -15.884693 +494 251 -31.390962 +495 251 -130.112415 +496 251 -9.167953 +497 251 -42.624923 +498 251 -16.725730 +499 251 -39.893546 +500 251 -12.473217 +252 252 3.668803 +319 252 0.147929 +320 252 0.147929 +321 252 0.065746 +322 252 0.065746 +324 252 0.147929 +325 252 0.591716 +326 252 0.147929 +328 252 0.147929 +331 252 0.147929 +332 252 0.147929 +335 252 0.065746 +336 252 0.065746 +337 252 0.147929 +338 252 0.591716 +339 252 0.065746 +340 252 0.065746 +341 252 0.065746 +342 252 0.591716 +361 252 -9.080641 +362 252 -0.688030 +386 252 -11.868874 +406 252 -20.022150 +410 252 -10.520812 +411 252 -1.922853 +431 252 -27.093788 +434 252 -1.977964 +435 252 -11.092251 +444 252 -136.643170 +455 252 -12.857986 +456 252 -19.710776 +459 252 -13.752178 +460 252 -22.247784 +469 252 -2.311271 +470 252 -177.082228 +471 252 -5.340000 +480 252 -41.008288 +483 252 -9.929534 +484 252 -24.158492 +485 252 -14.814235 +496 252 -173.726831 +497 252 -5.998548 +253 253 3.750986 +319 253 0.147929 +321 253 0.147929 +322 253 0.147929 +323 253 0.591716 +324 253 0.591716 +325 253 0.147929 +326 253 0.591716 +327 253 0.147929 +328 253 0.065746 +329 253 0.147929 +331 253 0.065746 +332 253 0.147929 +337 253 0.065746 +338 253 0.065746 +339 253 0.065746 +340 253 0.147929 +341 253 0.065746 +342 253 0.147929 +361 253 -12.828356 +362 253 -4.604485 +386 253 -20.552340 +406 253 -18.371361 +411 253 -20.854549 +431 253 -24.529151 +436 253 -21.194582 +444 253 -23.675888 +456 253 -34.503372 +460 253 -6.737413 +461 253 -21.573989 +469 253 -32.547179 +480 253 -14.072997 +481 253 -36.026362 +483 253 -0.120240 +485 253 -13.408485 +486 253 -18.503492 +494 253 -32.345192 +254 254 3.997535 +320 254 0.147929 +321 254 0.147929 +322 254 0.065746 +323 254 0.591716 +324 254 0.147929 +326 254 0.147929 +327 254 0.065746 +328 254 0.147929 +330 254 0.147929 +331 254 0.065746 +332 254 0.147929 +335 254 0.591716 +336 254 0.591716 +341 254 0.591716 +342 254 0.147929 +362 254 -17.182336 +387 254 -19.850813 +412 254 -19.708437 +437 254 -19.598084 +460 254 -14.723361 +462 254 -19.519242 +483 254 -0.128650 +485 254 -6.265401 +486 254 -14.861728 +487 254 -19.471548 +255 255 0.693787 +321 255 0.147929 +328 255 0.147929 +342 255 0.147929 +361 255 -16.119020 +362 255 -2.469046 +386 255 -22.154837 +411 255 -22.747822 +435 255 -8.231816 +436 255 -15.163256 +460 255 -40.765255 +485 255 -49.677418 +256 256 1.285503 +320 256 0.065746 +321 256 0.065746 +322 256 0.065746 +323 256 0.065746 +324 256 0.147929 +325 256 0.065746 +329 256 0.065746 +332 256 0.147929 +337 256 0.065746 +338 256 0.147929 +341 256 0.065746 +342 256 0.065746 +360 256 -2.371717 +361 256 -16.040947 +362 256 -0.468246 +384 256 -11.145665 +385 256 -13.535851 +407 256 -7.677250 +408 256 -15.701435 +409 256 -4.650220 +424 256 -11.228781 +425 256 -14.642663 +426 256 -14.643581 +427 256 -14.644618 +428 256 -14.645790 +429 256 -14.647118 +430 256 -14.648625 +431 256 -104.776668 +432 256 -8.259327 +444 256 -11.586805 +445 256 -14.639436 +446 256 -14.639930 +447 256 -14.640492 +448 256 -14.641129 +449 256 -3.413068 +455 256 -23.975891 +456 256 -109.793507 +457 256 -39.815235 +479 256 -15.874843 +480 256 -17.020968 +481 256 -34.959214 +482 256 -91.449174 +483 256 -12.949253 +257 257 6.660256 +319 257 0.147929 +320 257 0.591716 +321 257 0.065746 +322 257 0.591716 +323 257 0.591716 +324 257 0.591716 +325 257 0.147929 +326 257 0.147929 +328 257 0.065746 +329 257 0.591716 +331 257 0.591716 +332 257 0.147929 +337 257 0.591716 +338 257 0.591716 +339 257 0.147929 +340 257 0.065746 +341 257 0.591716 +342 257 0.147929 +361 257 -6.506019 +362 257 -1.442988 +386 257 -9.418843 +406 257 -18.622248 +411 257 -9.609632 +431 257 -24.948705 +436 257 -9.820003 +444 257 -23.599609 +456 257 -29.653846 +460 257 -11.027653 +461 257 -6.025260 +469 257 -32.449738 +480 257 -9.670315 +481 257 -27.279047 +483 257 -1.121172 +485 257 -20.663539 +494 257 -32.257283 +258 258 2.041584 +319 258 0.147929 +320 258 0.065746 +321 258 0.147929 +322 258 0.147929 +323 258 0.065746 +324 258 0.147929 +325 258 0.065746 +327 258 0.147929 +328 258 0.147929 +329 258 0.065746 +332 258 0.065746 +337 258 0.147929 +338 258 0.147929 +339 258 0.147929 +340 258 0.065746 +342 258 0.065746 +361 258 -6.460086 +362 258 -10.611405 +386 258 -19.994884 +406 258 -18.223978 +411 258 -20.145962 +431 258 -24.190201 +436 258 -20.329826 +444 258 -11.033644 +456 258 -28.503358 +460 258 -14.626479 +461 258 -20.547298 +469 258 -15.125385 +481 258 -35.245466 +485 258 -21.387812 +486 258 -20.799345 +494 258 -2.657070 +495 258 -12.322878 +259 259 1.449869 +319 259 0.065746 +320 259 0.065746 +321 259 0.147929 +322 259 0.065746 +323 259 0.147929 +327 259 0.147929 +328 259 0.147929 +329 259 0.065746 +337 259 0.065746 +338 259 0.065746 +339 259 0.147929 +341 259 0.065746 +361 259 -6.300585 +362 259 -10.768313 +386 259 -19.990352 +406 259 -8.099752 +411 259 -20.139774 +431 259 -10.750686 +436 259 -20.321943 +456 259 -10.754937 +460 259 -14.622006 +461 259 -20.537673 +481 259 -10.771234 +485 259 -21.379641 +486 259 -20.787924 +260 260 0.397929 +326 260 0.147929 +261 261 3.471565 +319 261 0.065746 +320 261 0.591716 +321 261 0.591716 +322 261 0.065746 +323 261 0.147929 +327 261 0.065746 +328 261 0.147929 +329 261 0.065746 +337 261 0.147929 +338 261 0.591716 +339 261 0.591716 +341 261 0.147929 +361 261 -45.316380 +362 261 -23.717758 +386 261 -81.176664 +406 261 -8.124182 +411 261 -82.140074 +431 261 -10.825392 +436 261 -83.245241 +456 261 -10.878034 +460 261 -14.917712 +461 261 -84.497151 +481 261 -10.942991 +485 261 -21.901992 +486 261 -85.901412 +262 262 3.159270 +319 262 0.065746 +321 262 0.591716 +322 262 0.147929 +323 262 0.065746 +324 262 0.591716 +325 262 0.147929 +326 262 0.147929 +327 262 0.147929 +328 262 0.065746 +329 262 0.065746 +332 262 0.591716 +339 262 0.147929 +340 262 0.065746 +341 262 0.065746 +362 262 -70.302862 +387 262 -80.750291 +406 262 -3.496322 +407 262 -8.637194 +412 262 -79.673921 +432 262 -11.035207 +433 262 -4.335844 +437 262 -78.739611 +444 262 -26.956371 +445 262 -34.084176 +446 262 -24.489465 +456 262 -7.929980 +458 262 -14.580496 +460 262 -4.429956 +461 262 -2.755236 +462 262 -77.942812 +471 262 -9.628763 +472 262 -34.157086 +473 262 -34.201285 +474 262 -30.675241 +481 262 -7.742676 +482 262 -11.546698 +483 262 -1.360179 +484 262 -12.489367 +486 262 -10.172622 +487 262 -77.279634 +499 262 -3.576222 +500 262 -34.308385 +263 263 2.173077 +319 263 0.147929 +320 263 0.147929 +321 263 0.065746 +322 263 0.065746 +323 263 0.147929 +325 263 0.065746 +326 263 0.065746 +327 263 0.065746 +328 263 0.065746 +329 263 0.147929 +331 263 0.147929 +332 263 0.147929 +337 263 0.147929 +338 263 0.147929 +339 263 0.065746 +340 263 0.065746 +341 263 0.147929 +342 263 0.065746 +361 263 -6.204815 +362 263 -1.649314 +386 263 -9.286145 +406 263 -18.511853 +411 263 -9.451917 +431 263 -24.768515 +436 263 -9.635953 +444 263 -10.461289 +456 263 -29.402662 +460 263 -6.878698 +461 263 -9.839106 +469 263 -14.387150 +480 263 -8.643612 +481 263 -27.952242 +483 263 -0.275844 +485 263 -19.445449 +486 263 -0.771763 +494 263 -14.305133 +264 264 2.058021 +319 264 0.147929 +320 264 0.147929 +323 264 0.065746 +324 264 0.147929 +325 264 0.147929 +327 264 0.147929 +331 264 0.065746 +332 264 0.147929 +335 264 0.147929 +336 264 0.147929 +337 264 0.065746 +338 264 0.065746 +340 264 0.147929 +341 264 0.065746 +342 264 0.147929 +406 264 -19.994049 +431 264 -27.051654 +444 264 -29.425887 +445 264 -18.819621 +455 264 -14.509953 +456 264 -24.099074 +470 264 -18.471391 +471 264 -37.436227 +472 264 -8.228815 +480 264 -56.792581 +483 264 -0.209114 +497 264 -29.374675 +498 264 -31.613784 +265 265 6.742439 +319 265 0.147929 +320 265 0.065746 +321 265 0.147929 +322 265 0.591716 +323 265 0.591716 +324 265 0.147929 +325 265 0.147929 +327 265 0.591716 +328 265 0.065746 +331 265 0.147929 +332 265 0.147929 +335 265 0.147929 +337 265 0.591716 +338 265 0.591716 +339 265 0.591716 +340 265 0.591716 +341 265 0.591716 +342 265 0.591716 +361 265 -15.671613 +362 265 -2.668787 +386 265 -21.818070 +406 265 -19.067681 +411 265 -22.355860 +431 265 -25.647756 +435 265 -1.929382 +436 265 -21.014847 +444 265 -22.979141 +455 265 -1.216507 +456 265 -65.889938 +460 265 -30.852557 +469 265 -31.672327 +480 265 -117.806802 +481 265 -14.886915 +483 265 -0.291790 +485 265 -35.081151 +494 265 -31.574916 +266 266 7.416338 +319 266 0.147929 +320 266 0.591716 +321 266 0.147929 +322 266 0.591716 +323 266 0.147929 +324 266 0.147929 +325 266 0.591716 +327 266 0.591716 +328 266 0.065746 +329 266 0.591716 +331 266 0.591716 +332 266 0.591716 +337 266 0.591716 +338 266 0.591716 +341 266 0.591716 +342 266 0.591716 +361 266 -14.216848 +362 266 -3.528355 +386 266 -20.997027 +406 266 -18.529734 +411 266 -21.389930 +431 266 -24.798038 +436 266 -21.824941 +444 266 -94.778176 +456 266 -25.041876 +460 266 -9.223135 +461 266 -20.001064 +469 266 -130.284174 +481 266 -25.315390 +483 266 -1.108464 +485 266 -33.053539 +494 266 -129.467054 +267 267 3.307199 +319 267 0.147929 +320 267 0.147929 +321 267 0.147929 +322 267 0.065746 +323 267 0.591716 +324 267 0.065746 +325 267 0.065746 +327 267 0.591716 +328 267 0.147929 +329 267 0.147929 +331 267 0.147929 +335 267 0.065746 +337 267 0.147929 +338 267 0.147929 +339 267 0.147929 +340 267 0.147929 +341 267 0.065746 +342 267 0.065746 +361 267 -16.063149 +362 267 -2.492388 +386 267 -22.110710 +406 267 -19.291731 +411 267 -22.696552 +431 267 -25.991038 +435 267 -7.462954 +436 267 -15.873216 +444 267 -10.149880 +455 267 -1.422958 +456 267 -35.436285 +460 267 -40.658584 +469 267 -14.002131 +480 267 -47.454010 +481 267 -6.457090 +483 267 -0.297161 +485 267 -49.536550 +494 267 -13.973775 +268 268 2.863412 +319 268 0.147929 +320 268 0.147929 +321 268 0.065746 +322 268 0.147929 +323 268 0.065746 +324 268 0.065746 +325 268 0.147929 +326 268 0.147929 +327 268 0.147929 +329 268 0.591716 +332 268 0.147929 +335 268 0.065746 +336 268 0.147929 +337 268 0.147929 +338 268 0.065746 +339 268 0.147929 +340 268 0.065746 +341 268 0.147929 +346 268 -21.644266 +347 268 -503.505592 +348 268 -104.139686 +349 268 -52.241573 +350 268 -48.024509 +351 268 -38.975399 +352 268 -14.621303 +353 268 -14.621304 +354 268 -14.621305 +355 268 -14.621305 +356 268 -14.621306 +357 268 -14.621307 +358 268 -14.621308 +359 268 -14.621309 +360 268 -14.621311 +361 268 -14.621313 +362 268 -0.424749 +370 268 -5.184834 +371 268 -33.198576 +372 268 -323.163421 +373 268 -143.916151 +374 268 -78.624139 +375 268 -15.784458 +376 268 -15.583011 +377 268 -33.450490 +378 268 -33.478929 +379 268 -33.511219 +380 268 -30.929773 +395 268 -39.119927 +396 268 -12.719789 +397 268 -124.397016 +398 268 -234.878441 +399 268 -63.032502 +400 268 -77.314441 +401 268 -20.189071 +402 268 -15.904993 +403 268 -5.705533 +405 268 -2.618208 +406 268 -27.523618 +419 268 -30.546915 +420 268 -9.290342 +421 268 -30.552973 +422 268 -60.580129 +423 268 -215.097633 +424 268 -77.544901 +425 268 -36.854219 +426 268 -69.781336 +427 268 -21.980013 +428 268 -10.273050 +429 268 -16.063157 +430 268 -1.864978 +444 268 -11.138219 +446 268 -30.659402 +447 268 -45.984819 +448 268 -180.942478 +449 268 -89.431488 +450 268 -36.389134 +451 268 -27.475803 +452 268 -59.621362 +453 268 -31.376740 +455 268 -14.295820 +456 268 -1.613915 +471 268 -30.776261 +472 268 -30.014863 +473 268 -91.722725 +474 268 -152.763400 +475 268 -60.912201 +476 268 -20.900137 +477 268 -18.459623 +478 268 -51.352768 +479 268 -34.853875 +496 268 -30.903204 +497 268 -26.890160 +498 268 -40.210303 +499 268 -174.846976 +500 268 -61.839990 +269 269 2.551118 +319 269 0.147929 +320 269 0.147929 +321 269 0.147929 +322 269 0.065746 +323 269 0.065746 +324 269 0.065746 +325 269 0.147929 +326 269 0.147929 +327 269 0.065746 +328 269 0.147929 +329 269 0.147929 +332 269 0.147929 +335 269 0.065746 +336 269 0.147929 +337 269 0.147929 +338 269 0.065746 +339 269 0.147929 +340 269 0.065746 +341 269 0.065746 +342 269 0.147929 +346 269 -14.642524 +347 269 -394.775476 +348 269 -157.304509 +349 269 -100.287895 +350 269 -84.942951 +351 269 -43.667779 +352 269 -32.898420 +353 269 -32.898445 +354 269 -32.898474 +355 269 -32.898507 +356 269 -32.898545 +357 269 -32.898588 +358 269 -32.898637 +359 269 -32.898694 +360 269 -32.898760 +361 269 -32.898837 +362 269 -0.955712 +370 269 -0.637631 +371 269 -38.402329 +372 269 -184.876022 +373 269 -168.649330 +374 269 -105.976971 +375 269 -30.607666 +376 269 -60.210690 +377 269 -67.035944 +378 269 -67.100063 +379 269 -46.692806 +380 269 -28.706800 +395 269 -39.833008 +397 269 -81.875539 +398 269 -147.516590 +399 269 -72.594748 +400 269 -109.202168 +401 269 -32.070734 +402 269 -15.836238 +403 269 -4.270030 +404 269 -20.480093 +405 269 -38.549071 +406 269 -61.300335 +407 269 -18.931630 +419 269 -29.118527 +420 269 -11.485343 +421 269 -13.295850 +422 269 -44.061159 +423 269 -107.061582 +424 269 -74.943001 +425 269 -40.033927 +426 269 -96.080792 +427 269 -43.331491 +428 269 -11.635372 +429 269 -15.984823 +430 269 -1.365822 +432 269 -14.982110 +433 269 -33.990962 +434 269 -34.080659 +435 269 -5.204100 +444 269 -11.359115 +446 269 -13.626012 +447 269 -26.710695 +448 269 -82.511903 +449 269 -82.240297 +450 269 -36.669012 +451 269 -27.321293 +452 269 -77.208159 +453 269 -60.176875 +455 269 -14.710604 +456 269 -1.605150 +460 269 -24.109787 +471 269 -13.679620 +472 269 -13.334917 +473 269 -65.607098 +474 269 -71.186204 +475 269 -61.579545 +476 269 -21.043155 +477 269 -15.659078 +478 269 -61.886120 +479 269 -69.651792 +480 269 -0.948834 +496 269 -13.737725 +497 269 -9.524906 +498 269 -41.041342 +499 269 -67.862442 +500 269 -59.994051 +270 270 1.154011 +319 270 0.065746 +320 270 0.065746 +321 270 0.147929 +322 270 0.065746 +324 270 0.065746 +327 270 0.065746 +328 270 0.065746 +329 270 0.147929 +338 270 0.065746 +341 270 0.147929 +347 270 -175.197476 +348 270 -62.620339 +349 270 -62.638190 +350 270 -57.934315 +351 270 -39.657769 +352 270 -32.898011 +353 270 -32.898016 +354 270 -32.898022 +355 270 -32.898028 +356 270 -32.898036 +357 270 -32.898045 +358 270 -32.898055 +359 270 -32.898066 +360 270 -32.898079 +361 270 -32.898095 +362 270 -0.955690 +371 270 -2.124525 +372 270 -102.864523 +373 270 -42.377369 +375 270 -4.724072 +376 270 -23.023463 +377 270 -29.809083 +378 270 -29.838393 +379 270 -21.875156 +380 270 -13.079281 +396 270 -13.542107 +397 270 -35.167764 +398 270 -62.606192 +399 270 -33.609564 +404 270 -7.996535 +405 270 -16.830345 +406 270 -27.261777 +407 270 -8.941742 +421 270 -13.582325 +422 270 -13.455590 +423 270 -69.214644 +424 270 -17.165304 +425 270 -29.107423 +432 270 -6.139308 +433 270 -15.116031 +434 270 -15.156669 +435 270 -2.417457 +446 270 -13.627279 +447 270 -13.406534 +448 270 -53.552177 +449 270 -24.693723 +450 270 -12.316914 +451 270 -22.586090 +460 270 -10.619985 +471 270 -13.676840 +472 270 -13.362921 +473 270 -14.705420 +474 270 -50.879146 +475 270 -11.602055 +476 270 -19.766796 +477 270 -13.919152 +496 270 -13.730860 +497 270 -13.324858 +499 270 -61.727969 +500 270 -14.436067 +271 271 7.334155 +319 271 0.147929 +320 271 0.065746 +321 271 0.065746 +322 271 0.591716 +323 271 0.591716 +324 271 0.147929 +325 271 0.591716 +326 271 0.591716 +327 271 0.147929 +328 271 0.147929 +329 271 0.591716 +331 271 0.591716 +332 271 0.591716 +337 271 0.591716 +338 271 0.147929 +339 271 0.591716 +340 271 0.147929 +341 271 0.591716 +342 271 0.147929 +361 271 -5.930967 +362 271 -1.858547 +386 271 -9.194349 +406 271 -18.413037 +411 271 -9.341567 +431 271 -24.601926 +436 271 -9.506163 +444 271 -94.859309 +456 271 -34.623941 +460 271 -15.282600 +461 271 -9.688892 +469 271 -130.388016 +480 271 -16.103067 +481 271 -34.194756 +483 271 -1.089789 +485 271 -27.469368 +486 271 -4.943849 +494 271 -129.560987 +272 272 6.232906 +319 272 0.147929 +320 272 0.591716 +321 272 0.065746 +322 272 0.591716 +323 272 0.591716 +324 272 0.591716 +326 272 0.147929 +327 272 0.147929 +328 272 0.147929 +329 272 0.147929 +331 272 0.591716 +332 272 0.147929 +337 272 0.147929 +338 272 0.591716 +339 272 0.591716 +341 272 0.591716 +342 272 0.147929 +361 272 -5.919850 +362 272 -1.867410 +386 272 -9.191119 +406 272 -18.410703 +411 272 -9.337660 +431 272 -24.597900 +436 272 -9.501548 +456 272 -24.792970 +460 272 -15.275931 +461 272 -9.683535 +481 272 -25.016801 +483 272 -1.089373 +485 272 -27.288152 +486 272 -5.107704 +273 273 4.211210 +319 273 0.065746 +320 273 0.591716 +322 273 0.147929 +323 273 0.147929 +324 273 0.147929 +325 273 0.065746 +326 273 0.591716 +327 273 0.065746 +329 273 0.147929 +331 273 0.147929 +332 273 0.591716 +335 273 0.147929 +337 273 0.147929 +338 273 0.147929 +339 273 0.147929 +340 273 0.065746 +342 273 0.591716 +406 273 -8.377635 +431 273 -11.248636 +444 273 -10.271509 +456 273 -15.899579 +469 273 -14.148300 +480 273 -11.076118 +481 273 -12.110663 +483 273 -0.285704 +494 273 -14.094121 +274 274 3.685240 +319 274 0.147929 +320 274 0.147929 +321 274 0.147929 +322 274 0.147929 +324 274 0.065746 +325 274 0.591716 +326 274 0.147929 +327 274 0.065746 +328 274 0.591716 +329 274 0.065746 +331 274 0.147929 +332 274 0.147929 +334 274 0.147929 +335 274 0.147929 +336 274 0.065746 +337 274 0.147929 +339 274 0.147929 +340 274 0.147929 +341 274 0.147929 +342 274 0.065746 +346 274 -82.400919 +347 274 -606.579193 +348 274 -338.914351 +349 274 -241.588712 +350 274 -201.017777 +351 274 -105.933614 +352 274 -32.898321 +353 274 -32.898342 +354 274 -32.898365 +355 274 -32.898392 +356 274 -32.898422 +357 274 -32.898457 +358 274 -32.898496 +359 274 -32.898542 +360 274 -32.898595 +361 274 -32.898657 +362 274 -0.955707 +370 274 -18.036465 +371 274 -135.872251 +372 274 -178.463280 +373 274 -143.663269 +374 274 -121.958169 +375 274 -79.106603 +376 274 -148.377902 +377 274 -168.463052 +378 274 -168.670019 +379 274 -145.603045 +380 274 -32.305181 +395 274 -156.886875 +397 274 -92.423583 +398 274 -156.195102 +399 274 -46.608843 +400 274 -88.884698 +401 274 -46.180060 +402 274 -71.302666 +403 274 -51.074955 +404 274 -23.303126 +405 274 -136.868391 +406 274 -163.402632 +407 274 -103.855117 +419 274 -121.327779 +420 274 -38.458817 +421 274 -26.905108 +422 274 -60.704181 +423 274 -94.249252 +424 274 -86.015515 +425 274 -17.288943 +426 274 -69.898656 +427 274 -47.376742 +428 274 -20.541886 +429 274 -71.976844 +430 274 -34.891840 +432 274 -32.273296 +433 274 -136.475253 +434 274 -136.878476 +435 274 -26.418077 +444 274 -44.678937 +446 274 -30.658376 +447 274 -43.633693 +448 274 -65.115739 +449 274 -84.692859 +450 274 -45.100095 +451 274 -12.500929 +452 274 -51.949607 +453 274 -56.376405 +454 274 -2.751777 +455 274 -37.502223 +456 274 -39.722955 +457 274 -16.801658 +460 274 -91.355649 +471 274 -30.779911 +472 274 -43.588355 +473 274 -32.810327 +474 274 -82.820765 +475 274 -60.140597 +476 274 -21.216713 +477 274 -7.015387 +478 274 -44.292513 +479 274 -56.063319 +480 274 -4.777030 +482 274 -19.520487 +483 274 -33.084600 +496 274 -30.911571 +497 274 -32.480346 +498 274 -24.421197 +499 274 -74.654632 +500 274 -60.579567 +275 275 1.910092 +319 275 0.065746 +320 275 0.065746 +321 275 0.147929 +322 275 0.147929 +324 275 0.147929 +325 275 0.147929 +328 275 0.147929 +331 275 0.147929 +335 275 0.147929 +337 275 0.065746 +338 275 0.147929 +339 275 0.065746 +340 275 0.147929 +342 275 0.065746 +361 275 -19.113197 +362 275 -1.705990 +386 275 -25.150959 +406 275 -8.857600 +410 275 -14.395244 +411 275 -11.810027 +431 275 -11.979979 +435 275 -27.352130 +444 275 -27.406111 +455 275 -7.723220 +456 275 -15.374146 +459 275 -18.237990 +460 275 -30.348597 +469 275 -19.036504 +470 275 -18.360266 +480 275 -40.740009 +483 275 -0.351667 +484 275 -39.618031 +485 275 -20.602288 +495 275 -36.823929 +276 276 1.729290 +322 276 0.591716 +323 276 0.591716 +327 276 0.147929 +341 276 0.147929 +277 277 2.123767 +319 277 0.065746 +320 277 0.065746 +321 277 0.147929 +322 277 0.065746 +323 277 0.147929 +324 277 0.147929 +325 277 0.147929 +326 277 0.147929 +327 277 0.065746 +328 277 0.065746 +329 277 0.147929 +332 277 0.147929 +334 277 0.065746 +336 277 0.147929 +341 277 0.147929 +342 277 0.147929 +361 277 -14.007868 +362 277 -3.676791 +386 277 -20.911962 +406 277 -7.710082 +407 277 -0.878983 +411 277 -21.288490 +432 277 -11.240431 +436 277 -21.706288 +444 277 -27.889460 +445 277 -34.479223 +457 277 -11.065363 +460 277 -6.775376 +461 277 -22.167296 +470 277 -0.814079 +471 277 -35.365904 +472 277 -35.449035 +473 277 -9.911027 +482 277 -10.905614 +485 277 -31.656003 +486 277 -0.999234 +498 277 -25.632933 +499 277 -35.652207 +500 277 -14.463080 +278 278 6.315089 +319 278 0.147929 +320 278 0.591716 +322 278 0.591716 +323 278 0.147929 +324 278 0.591716 +326 278 0.591716 +327 278 0.147929 +328 278 0.147929 +329 278 0.147929 +331 278 0.591716 +332 278 0.591716 +334 278 0.147929 +337 278 0.591716 +339 278 0.591716 +340 278 0.147929 +341 278 0.147929 +342 278 0.147929 +406 278 -18.629187 +431 278 -24.959887 +456 278 -35.207846 +460 278 -15.778111 +480 278 -21.872635 +481 278 -29.377611 +483 278 -1.122589 +485 278 -23.349307 +279 279 1.844346 +319 279 0.147929 +321 279 0.147929 +323 279 0.147929 +325 279 0.147929 +328 279 0.147929 +331 279 0.147929 +332 279 0.147929 +334 279 0.147929 +336 279 0.065746 +337 279 0.147929 +339 279 0.065746 +341 279 0.065746 +342 279 0.065746 +361 279 -25.711040 +362 279 -1.253923 +385 279 -16.679327 +386 279 -16.771078 +406 279 -25.622690 +409 279 -11.199553 +410 279 -24.675844 +430 279 -22.522584 +431 279 -12.900746 +433 279 -9.296965 +434 279 -29.258311 +444 279 -25.422050 +454 279 -13.877381 +455 279 -23.229338 +457 279 -11.075130 +458 279 -30.432340 +460 279 -30.551856 +469 279 -32.662933 +470 279 -2.145051 +478 279 -8.144640 +479 279 -30.741836 +481 279 -16.691392 +482 279 -28.053263 +483 279 -10.116187 +484 279 -37.062875 +485 279 -1.572407 +495 279 -34.422210 +280 280 2.962032 +320 280 0.065746 +321 280 0.147929 +322 280 0.147929 +323 280 0.591716 +324 280 0.147929 +325 280 0.147929 +326 280 0.147929 +327 280 0.147929 +329 280 0.065746 +337 280 0.147929 +338 280 0.147929 +339 280 0.147929 +341 280 0.591716 +342 280 0.065746 +361 280 -8.297826 +362 280 -8.813166 +386 280 -20.061898 +411 280 -20.236040 +436 280 -20.443550 +444 280 -24.608831 +461 280 -20.685357 +469 280 -33.750588 +486 280 -20.962536 +494 280 -9.761564 +495 280 -23.683772 +281 281 3.027778 +319 281 0.147929 +320 281 0.065746 +321 281 0.147929 +322 281 0.591716 +324 281 0.147929 +326 281 0.147929 +327 281 0.065746 +328 281 0.147929 +331 281 0.591716 +332 281 0.147929 +334 281 0.065746 +337 281 0.147929 +338 281 0.147929 +339 281 0.147929 +342 281 0.065746 +361 281 -26.654078 +362 281 -1.226923 +385 281 -19.726869 +386 281 -14.979293 +406 281 -22.944307 +409 281 -16.455308 +410 281 -20.907413 +430 281 -9.972680 +431 281 -21.466286 +433 281 -16.928560 +434 281 -23.377913 +455 281 -32.606126 +457 281 -21.305887 +458 281 -22.250668 +459 281 -7.167887 +460 281 -30.643527 +479 281 -24.550334 +480 281 -9.290604 +481 281 -29.794000 +482 281 -17.331545 +483 281 -36.026780 +484 281 -28.332251 +282 282 5.082347 +319 282 0.147929 +320 282 0.065746 +321 282 0.147929 +322 282 0.065746 +323 282 0.591716 +324 282 0.591716 +325 282 0.065746 +327 282 0.591716 +328 282 0.147929 +329 282 0.065746 +331 282 0.065746 +332 282 0.147929 +335 282 0.591716 +337 282 0.147929 +338 282 0.591716 +339 282 0.147929 +341 282 0.591716 +342 282 0.065746 +361 282 -15.723082 +362 282 -2.644290 +386 282 -21.854844 +406 282 -19.098370 +411 282 -22.398744 +431 282 -25.694999 +435 282 -2.670578 +436 282 -20.323042 +444 282 -10.200322 +456 282 -26.104429 +460 282 -40.026821 +469 282 -14.061370 +480 282 -12.959816 +481 282 -13.588046 +483 282 -0.129995 +485 282 -48.698200 +494 282 -14.020708 +283 283 2.879849 +319 283 0.065746 +320 283 0.147929 +321 283 0.147929 +325 283 0.147929 +326 283 0.147929 +328 283 0.065746 +331 283 0.065746 +332 283 0.147929 +335 283 0.065746 +336 283 0.147929 +337 283 0.591716 +338 283 0.591716 +341 283 0.147929 +342 283 0.147929 +361 283 -21.645950 +362 283 -1.446182 +385 283 -1.436455 +386 283 -26.762595 +406 283 -9.845316 +410 283 -29.728180 +430 283 -2.252883 +431 283 -11.197473 +434 283 -16.335106 +435 283 -15.064376 +444 283 -24.878345 +455 283 -13.903231 +458 283 -4.978867 +459 283 -28.244228 +460 283 -10.416139 +469 283 -34.100517 +479 283 -6.181867 +480 283 -8.200898 +483 283 -35.396999 +484 283 -10.488068 +485 283 -5.513894 +494 283 -5.141353 +495 283 -28.626662 +284 284 5.772682 +319 284 0.147929 +320 284 0.591716 +321 284 0.065746 +322 284 0.147929 +323 284 0.591716 +324 284 0.591716 +325 284 0.065746 +326 284 0.147929 +327 284 0.147929 +328 284 0.147929 +329 284 0.591716 +331 284 0.147929 +332 284 0.147929 +334 284 0.065746 +335 284 0.147929 +337 284 0.147929 +338 284 0.147929 +339 284 0.591716 +340 284 0.147929 +341 284 0.591716 +342 284 0.147929 +361 284 -7.074984 +362 284 -1.135475 +386 284 -9.777483 +406 284 -19.187190 +411 284 -10.029795 +431 284 -25.831305 +435 284 -2.422491 +436 284 -7.882970 +444 284 -10.186085 +455 284 -0.941084 +456 284 -35.664405 +460 284 -27.126943 +469 284 -14.044361 +480 284 -43.397822 +481 284 -10.106803 +483 284 -0.294978 +485 284 -35.507238 +494 284 -14.006839 +285 285 8.090237 +319 285 0.147929 +322 285 0.591716 +323 285 0.591716 +324 285 0.591716 +325 285 0.147929 +326 285 0.591716 +327 285 0.591716 +328 285 0.591716 +331 285 0.147929 +332 285 0.147929 +334 285 0.591716 +337 285 0.591716 +338 285 0.591716 +339 285 0.591716 +340 285 0.147929 +341 285 0.591716 +342 285 0.591716 +406 285 -18.238361 +431 285 -24.265042 +444 285 -24.323662 +456 285 -34.039123 +460 285 -59.202654 +469 285 -33.381150 +481 285 -49.303301 +483 285 -0.264421 +485 285 -86.794114 +494 285 -15.799203 +495 285 -17.306442 +286 286 0.611604 +324 286 0.065746 +328 286 0.147929 +339 286 0.147929 +460 286 -20.785870 +484 286 -13.274229 +485 286 -18.314620 +287 287 4.375575 +319 287 0.065746 +320 287 0.591716 +322 287 0.147929 +323 287 0.147929 +324 287 0.147929 +326 287 0.147929 +327 287 0.147929 +328 287 0.147929 +329 287 0.591716 +331 287 0.065746 +332 287 0.147929 +334 287 0.147929 +337 287 0.147929 +338 287 0.147929 +339 287 0.591716 +341 287 0.591716 +342 287 0.147929 +406 287 -8.223891 +431 287 -11.002262 +456 287 -11.106277 +460 287 -15.492301 +481 287 -11.223392 +483 287 -0.122632 +485 287 -22.873972 +288 288 0.463675 +321 288 0.065746 +328 288 0.147929 +361 288 -6.336169 +362 288 -1.555962 +386 288 -9.339540 +411 288 -9.515594 +436 288 -9.710437 +460 288 -16.888048 +461 288 -8.621894 +485 288 -33.188649 +289 289 3.044214 +319 289 0.147929 +321 289 0.147929 +322 289 0.065746 +323 289 0.065746 +324 289 0.147929 +326 289 0.147929 +327 289 0.147929 +328 289 0.147929 +331 289 0.147929 +332 289 0.591716 +334 289 0.591716 +339 289 0.147929 +341 289 0.147929 +342 289 0.147929 +361 289 -14.871210 +362 289 -3.102303 +386 289 -21.314653 +406 289 -18.691350 +411 289 -21.765961 +431 289 -25.059483 +436 289 -22.262568 +456 289 -25.357798 +460 289 -28.675632 +461 289 -10.001786 +481 289 -25.687016 +483 289 -0.282400 +485 289 -46.903748 +290 290 4.375575 +319 290 0.147929 +320 290 0.591716 +321 290 0.147929 +322 290 0.065746 +323 290 0.147929 +324 290 0.147929 +326 290 0.065746 +327 290 0.147929 +328 290 0.147929 +329 290 0.147929 +331 290 0.147929 +332 290 0.147929 +337 290 0.591716 +338 290 0.591716 +339 290 0.147929 +341 290 0.591716 +342 290 0.147929 +361 290 -14.830562 +362 290 -3.126950 +386 290 -21.292527 +406 290 -18.680294 +411 290 -21.739884 +431 290 -25.041841 +436 290 -22.232314 +456 290 -25.336707 +460 290 -28.000208 +461 290 -10.621618 +481 290 -25.662392 +483 290 -0.282036 +485 290 -46.829755 +291 291 1.647107 +324 291 0.147929 +325 291 0.147929 +327 291 0.147929 +331 291 0.065746 +332 291 0.147929 +337 291 0.591716 +342 291 0.147929 +444 291 -24.505319 +469 291 -33.616377 +483 291 -0.116627 +494 291 -11.791595 +495 291 -21.530202 +292 292 3.981098 +319 292 0.065746 +320 292 0.065746 +321 292 0.147929 +322 292 0.147929 +325 292 0.591716 +326 292 0.065746 +327 292 0.147929 +328 292 0.147929 +331 292 0.065746 +332 292 0.591716 +334 292 0.147929 +335 292 0.147929 +337 292 0.591716 +339 292 0.065746 +341 292 0.147929 +342 292 0.591716 +361 292 -20.276883 +362 292 -1.563584 +386 292 -26.518579 +406 292 -8.850210 +410 292 -22.655801 +411 292 -5.127105 +431 292 -11.968885 +434 292 -2.832425 +435 292 -26.328246 +444 292 -137.298235 +455 292 -4.044847 +456 292 -8.186263 +459 292 -30.659867 +460 292 -22.011297 +469 292 -1.135003 +470 292 -176.391714 +471 292 -8.054180 +480 292 -12.511294 +483 292 -19.123574 +484 292 -31.626217 +485 292 -15.333645 +496 292 -170.279454 +497 292 -10.221126 +293 293 3.635930 +319 293 0.147929 +320 293 0.591716 +321 293 0.147929 +323 293 0.147929 +324 293 0.147929 +325 293 0.065746 +326 293 0.147929 +327 293 0.147929 +328 293 0.147929 +329 293 0.147929 +331 293 0.147929 +332 293 0.065746 +334 293 0.147929 +337 293 0.147929 +338 293 0.591716 +339 293 0.147929 +341 293 0.147929 +342 293 0.147929 +361 293 -12.360321 +362 293 -5.005067 +386 293 -20.453704 +406 293 -18.314680 +411 293 -20.733537 +431 293 -24.425897 +436 293 -21.050272 +444 293 -10.665273 +456 293 -24.569589 +460 293 -15.061926 +461 293 -21.405349 +469 293 -14.648554 +481 293 -24.741283 +483 293 -0.268643 +485 293 -22.149196 +486 293 -21.800365 +494 293 -11.120902 +495 293 -3.421095 +294 294 3.635930 +319 294 0.147929 +320 294 0.591716 +321 294 0.147929 +323 294 0.147929 +324 294 0.147929 +325 294 0.147929 +326 294 0.065746 +327 294 0.147929 +328 294 0.147929 +329 294 0.591716 +331 294 0.147929 +332 294 0.147929 +334 294 0.147929 +337 294 0.065746 +338 294 0.147929 +339 294 0.147929 +341 294 0.147929 +342 294 0.147929 +361 294 -12.394734 +362 294 -4.975135 +386 294 -20.460299 +406 294 -18.317926 +411 294 -20.741663 +431 294 -24.432003 +436 294 -21.059991 +444 294 -23.976641 +456 294 -24.577763 +460 294 -15.068383 +461 294 -21.416730 +469 294 -32.933204 +481 294 -24.751552 +483 294 -0.268764 +485 294 -22.160196 +486 294 -21.813485 +494 294 -25.709028 +495 294 -6.986711 +295 295 1.827909 +320 295 0.065746 +323 295 0.147929 +325 295 0.147929 +326 295 0.065746 +327 295 0.065746 +329 295 0.147929 +332 295 0.065746 +334 295 0.147929 +335 295 0.065746 +337 295 0.147929 +338 295 0.065746 +339 295 0.147929 +341 295 0.147929 +342 295 0.147929 +356 295 -9.210141 +357 295 -34.050566 +358 295 -103.650835 +359 295 -151.194403 +378 295 -13.213366 +379 295 -33.849886 +380 295 -33.907873 +381 295 -24.764109 +382 295 -3.453508 +383 295 -140.183265 +384 295 -82.891660 +385 295 -16.327151 +399 295 -4.010399 +400 295 -33.680130 +401 295 -33.714919 +402 295 -33.754329 +403 295 -20.585677 +407 295 -39.770240 +408 295 -112.349420 +409 295 -63.255599 +410 295 -28.694098 +420 295 -16.147473 +421 295 -33.577188 +422 295 -33.598286 +423 295 -33.622245 +424 295 -29.638997 +431 295 -21.696862 +432 295 -52.561205 +433 295 -81.693301 +434 295 -52.438108 +435 295 -13.093591 +436 295 -24.328443 +444 295 -26.550118 +445 295 -17.411199 +455 295 -10.858252 +456 295 -28.146748 +457 295 -44.268571 +458 295 -76.822699 +459 295 -39.447237 +460 295 -22.469339 +461 295 -26.065857 +479 295 -3.044941 +480 295 -34.182279 +481 295 -42.567563 +482 295 -25.986529 +483 295 -58.778914 +484 295 -30.567963 +485 295 -30.821732 +486 295 -0.277585 +487 295 -24.638552 +296 296 3.109961 +319 296 0.147929 +320 296 0.147929 +321 296 0.147929 +323 296 0.147929 +324 296 0.147929 +325 296 0.065746 +326 296 0.591716 +327 296 0.065746 +328 296 0.147929 +329 296 0.147929 +332 296 0.065746 +337 296 0.147929 +338 296 0.147929 +339 296 0.147929 +341 296 0.591716 +361 296 -11.006256 +362 296 -6.227435 +386 296 -20.256291 +406 296 -18.262576 +411 296 -20.487239 +431 296 -24.321924 +436 296 -20.753284 +444 296 -10.689890 +456 296 -24.425592 +460 296 -14.879728 +461 296 -21.055624 +469 296 -14.680273 +481 296 -24.556824 +485 296 -21.836296 +486 296 -21.395611 +494 296 -10.321116 +495 296 -4.249836 +297 297 2.814103 +320 297 0.147929 +321 297 0.147929 +323 297 0.065746 +324 297 0.147929 +325 297 0.147929 +326 297 0.147929 +327 297 0.147929 +328 297 0.147929 +329 297 0.065746 +332 297 0.147929 +334 297 0.591716 +335 297 0.147929 +337 297 0.147929 +338 297 0.065746 +339 297 0.147929 +341 297 0.147929 +355 297 -12.521241 +356 297 -33.012000 +357 297 -33.019723 +358 297 -33.028592 +359 297 -33.038826 +360 297 -33.050704 +361 297 -33.064581 +362 297 -0.960757 +377 297 -24.763562 +378 297 -34.191743 +379 297 -286.720433 +380 297 -176.245514 +381 297 -30.883805 +399 297 -33.593898 +400 297 -34.018412 +401 297 -34.069039 +402 297 -9.362910 +404 297 -215.377749 +405 297 -176.627547 +406 297 -10.469577 +407 297 -35.120745 +408 297 -26.834863 +420 297 -23.510137 +421 297 -33.869014 +422 297 -33.899585 +423 297 -33.934332 +424 297 -0.379847 +428 297 -21.175998 +429 297 -187.274166 +430 297 -134.288950 +431 297 -54.431840 +433 297 -8.464801 +434 297 -35.509398 +435 297 -14.090017 +444 297 -26.769364 +445 297 -10.332068 +453 297 -155.877628 +454 297 -39.731606 +455 297 -80.307997 +456 297 -107.300813 +457 297 -13.232175 +460 297 -16.562230 +477 297 -4.369451 +478 297 -157.084700 +479 297 -45.877215 +480 297 -68.033042 +481 297 -88.534260 +482 297 -32.325863 +298 298 3.652367 +319 298 0.591716 +320 298 0.147929 +321 298 0.147929 +322 298 0.591716 +325 298 0.147929 +328 298 0.147929 +329 298 0.147929 +331 298 0.147929 +337 298 0.591716 +339 298 0.591716 +342 298 0.147929 +359 298 -13.309785 +360 298 -33.690235 +361 298 -33.764501 +362 298 -0.982099 +381 298 -32.164039 +382 298 -33.525861 +383 298 -33.572715 +384 298 -20.317197 +401 298 -17.073792 +402 298 -265.291279 +403 298 -170.035795 +404 298 -165.722420 +405 298 -165.795301 +406 298 -109.813589 +420 298 -2.333197 +421 298 -33.288909 +422 298 -33.300892 +423 298 -33.314489 +424 298 -33.329880 +425 298 -33.347285 +426 298 -135.540120 +427 298 -361.218234 +428 298 -177.955999 +429 298 -65.135342 +430 298 -33.117562 +431 298 -33.131463 +432 298 -33.147365 +433 298 -33.165639 +434 298 -12.327302 +444 298 -26.333261 +445 298 -30.945188 +451 298 -158.826227 +452 298 -29.253568 +453 298 -269.374787 +454 298 -105.543401 +455 298 -34.817862 +456 298 -34.949561 +457 298 -2.179332 +459 298 -20.859445 +460 298 -28.483663 +475 298 -113.219681 +476 298 -48.761741 +477 298 -12.626959 +478 298 -16.176317 +479 298 -288.466534 +480 298 -65.529022 +482 298 -32.922545 +483 298 -31.883842 +499 298 -4.197998 +500 298 -132.124922 +299 299 2.353879 +319 299 0.065746 +323 299 0.065746 +325 299 0.147929 +327 299 0.591716 +328 299 0.065746 +329 299 0.147929 +331 299 0.591716 +339 299 0.147929 +340 299 0.065746 +341 299 0.065746 +342 299 0.147929 +406 299 -8.103049 +431 299 -10.776337 +444 299 -24.553857 +456 299 -15.112589 +460 299 -6.572154 +469 299 -33.679296 +481 299 -21.883263 +483 299 -1.056244 +485 299 -9.633407 +494 299 -10.819309 +495 299 -22.560386 +300 300 1.104701 +319 300 0.065746 +321 300 0.147929 +326 300 0.147929 +331 300 0.065746 +337 300 0.147929 +338 300 0.147929 +340 300 0.065746 +342 300 0.065746 +361 300 -29.376481 +362 300 -1.168062 +385 300 -27.996993 +386 300 -10.393048 +406 300 -13.453460 +409 300 -30.732091 +410 300 -11.034579 +430 300 -17.208010 +431 300 -1.640548 +433 300 -37.838766 +434 300 -7.698845 +453 300 -1.235945 +454 300 -17.873356 +455 300 -7.796256 +456 300 -13.801599 +457 300 -37.519499 +458 300 -0.095897 +477 300 -4.880475 +478 300 -16.415025 +479 300 -13.074732 +480 300 -39.313470 +481 300 -25.057727 +483 300 -0.328750 +301 301 1.499178 +325 301 0.591716 +326 301 0.147929 +332 301 0.147929 +337 301 0.065746 +338 301 0.147929 +342 301 0.147929 +444 301 -101.880331 +469 301 -128.704845 +470 301 -10.777381 +495 301 -137.920621 +302 302 1.449869 +319 302 0.147929 +321 302 0.065746 +323 302 0.147929 +324 302 0.065746 +325 302 0.065746 +327 302 0.065746 +329 302 0.147929 +331 302 0.065746 +334 302 0.065746 +339 302 0.147929 +340 302 0.065746 +342 302 0.147929 +361 302 -6.206450 +362 302 -1.648122 +386 302 -9.286769 +406 302 -18.475032 +411 302 -9.452664 +431 302 -24.707197 +436 302 -9.636828 +444 302 -10.587732 +456 302 -29.314807 +461 302 -9.840116 +469 302 -14.548846 +480 302 -8.128347 +481 302 -28.340811 +483 302 -0.122381 +485 302 -9.317276 +486 302 -0.746180 +494 302 -14.032214 +495 302 -0.419015 +303 303 0.381492 +324 303 0.065746 +332 303 0.065746 +304 304 4.063281 +319 304 0.147929 +321 304 0.147929 +322 304 0.147929 +323 304 0.147929 +324 304 0.147929 +325 304 0.591716 +327 304 0.147929 +328 304 0.147929 +331 304 0.591716 +332 304 0.591716 +334 304 0.065746 +336 304 0.147929 +337 304 0.065746 +339 304 0.591716 +340 304 0.065746 +342 304 0.065746 +361 304 -20.118425 +362 304 -1.580211 +386 304 -26.328514 +406 304 -19.342743 +410 304 -21.596720 +411 304 -5.966691 +431 304 -26.068745 +434 304 -1.144497 +435 304 -27.764213 +444 304 -124.866672 +445 304 -38.619583 +455 304 -0.629022 +456 304 -30.534321 +459 304 -30.372171 +460 304 -22.068640 +470 304 -119.903098 +471 304 -99.325267 +480 304 -34.202297 +481 304 -4.823615 +483 304 -17.879526 +484 304 -34.127840 +485 304 -15.206282 +496 304 -60.178440 +497 304 -150.785070 +305 305 1.400559 +319 305 0.147929 +320 305 0.065746 +321 305 0.065746 +325 305 0.147929 +327 305 0.147929 +334 305 0.065746 +335 305 0.147929 +336 305 0.147929 +340 305 0.065746 +341 305 0.147929 +361 305 -8.939816 +362 305 -0.702499 +386 305 -11.699521 +406 305 -19.335293 +410 305 -9.587038 +411 305 -2.661011 +431 305 -26.057406 +434 305 -0.490322 +435 305 -12.355289 +444 305 -31.186911 +445 305 -9.772601 +455 305 -0.611870 +456 305 -30.535814 +459 305 -13.495656 +470 305 -29.819089 +471 305 -25.100204 +480 305 -33.946988 +481 305 -5.056712 +483 305 -7.236640 +484 305 -6.964901 +496 305 -14.734937 +497 305 -38.106419 +306 306 4.671433 +319 306 0.147929 +321 306 0.147929 +322 306 0.065746 +323 306 0.591716 +324 306 0.591716 +325 306 0.065746 +327 306 0.147929 +328 306 0.147929 +332 306 0.591716 +337 306 0.147929 +339 306 0.591716 +341 306 0.591716 +342 306 0.591716 +361 306 -13.013008 +362 306 -4.450737 +386 306 -20.597127 +406 306 -18.367935 +411 306 -20.909154 +431 306 -24.523075 +436 306 -21.259426 +444 306 -10.607093 +456 306 -24.697295 +460 306 -15.196468 +461 306 -21.649545 +469 306 -14.573710 +481 306 -24.899942 +485 306 -28.537247 +486 306 -15.921451 +494 306 -13.241447 +495 306 -1.232377 +307 307 2.370316 +319 307 0.065746 +321 307 0.065746 +322 307 0.147929 +323 307 0.147929 +325 307 0.147929 +327 307 0.147929 +328 307 0.065746 +329 307 0.591716 +332 307 0.147929 +337 307 0.147929 +339 307 0.147929 +341 307 0.147929 +342 307 0.147929 +361 307 -6.062402 +362 307 -1.755846 +386 307 -9.235349 +406 307 -8.209937 +411 307 -9.391009 +431 307 -10.978983 +436 307 -9.564440 +444 307 -23.506619 +456 307 -11.077488 +460 307 -6.832005 +461 307 -9.756442 +469 307 -32.331285 +481 307 -11.188988 +485 307 -17.072663 +486 307 -2.972012 +494 307 -32.150835 +308 308 2.912722 +319 308 0.147929 +320 308 0.147929 +321 308 0.147929 +322 308 0.147929 +324 308 0.147929 +325 308 0.591716 +327 308 0.147929 +328 308 0.147929 +335 308 0.147929 +336 308 0.147929 +337 308 0.147929 +339 308 0.147929 +340 308 0.147929 +341 308 0.147929 +342 308 0.147929 +360 308 -6.715741 +361 308 -35.907901 +362 308 -1.047870 +384 308 -28.388649 +385 308 -28.911355 +405 308 -12.395799 +406 308 -30.017667 +407 308 -23.137921 +408 308 -35.192294 +409 308 -7.002995 +428 308 -1.037446 +429 308 -36.174533 +430 308 -51.842021 +431 308 -34.875772 +432 308 -11.884183 +444 308 -106.879151 +445 308 -135.112313 +446 308 -135.211970 +447 308 -15.200862 +452 308 -41.212812 +453 308 -69.487663 +454 308 -51.705289 +455 308 -40.383715 +456 308 -3.332774 +457 308 -32.168504 +458 308 -33.135265 +459 308 -33.153951 +460 308 -28.453304 +472 308 -120.124734 +473 308 -135.454715 +474 308 -135.601142 +475 308 -190.636210 +476 308 -136.476802 +477 308 -95.513847 +478 308 -66.486793 +479 308 -49.458756 +480 308 -33.092691 +481 308 -33.105002 +482 308 -0.950581 +499 308 -18.406507 +500 308 -242.050488 +309 309 2.978468 +319 309 0.147929 +320 309 0.065746 +321 309 0.147929 +322 309 0.147929 +324 309 0.147929 +327 309 0.147929 +328 309 0.147929 +335 309 0.147929 +336 309 0.147929 +337 309 0.147929 +339 309 0.147929 +341 309 0.591716 +342 309 0.591716 +360 309 -6.799763 +361 309 -35.897164 +362 309 -1.047539 +384 309 -28.590992 +385 309 -28.817713 +405 309 -12.561416 +406 309 -29.994653 +407 309 -23.496901 +408 309 -35.184356 +409 309 -6.791950 +428 309 -1.479113 +429 309 -36.150334 +430 309 -52.200793 +431 309 -34.869021 +432 309 -11.517906 +452 309 -42.735784 +453 309 -69.017868 +454 309 -34.633244 +455 309 -6.351361 +457 309 -32.476949 +458 309 -33.134267 +459 309 -33.152873 +460 309 -28.452307 +475 309 -159.887679 +476 309 -103.084195 +477 309 -60.574527 +478 309 -33.071646 +479 309 -33.081116 +480 309 -33.091874 +481 309 -33.104133 +482 309 -0.641207 +499 309 -20.191387 +500 309 -377.327094 +310 310 4.161900 +319 310 0.591716 +320 310 0.065746 +321 310 0.147929 +322 310 0.147929 +323 310 0.147929 +324 310 0.591716 +325 310 0.147929 +327 310 0.147929 +328 310 0.147929 +332 310 0.591716 +334 310 0.147929 +336 310 0.147929 +337 310 0.147929 +340 310 0.591716 +341 310 0.147929 +361 310 -21.524946 +362 310 -1.454965 +385 310 -0.898821 +386 310 -27.149296 +406 310 -78.964649 +410 310 -29.553091 +431 310 -106.686559 +434 310 -15.208562 +435 310 -15.988953 +444 310 -29.627558 +445 310 -17.500626 +455 310 -34.466907 +456 310 -117.364309 +458 310 -3.445495 +459 310 -29.545836 +460 310 -24.909524 +470 310 -20.053252 +471 310 -37.709507 +472 310 -4.970407 +480 310 -222.768531 +483 310 -34.943798 +484 310 -28.710477 +485 310 -9.774016 +497 310 -32.918503 +498 310 -26.843607 +311 311 3.767423 +319 311 0.147929 +320 311 0.147929 +321 311 0.147929 +322 311 0.065746 +323 311 0.147929 +324 311 0.147929 +325 311 0.147929 +327 311 0.065746 +328 311 0.065746 +332 311 0.591716 +334 311 0.065746 +335 311 0.147929 +336 311 0.591716 +337 311 0.591716 +339 311 0.147929 +340 311 0.147929 +341 311 0.147929 +361 311 -20.061351 +362 311 -1.586387 +386 311 -26.260321 +406 311 -19.354853 +410 311 -21.210744 +411 311 -6.273937 +431 311 -26.087171 +434 311 -0.529014 +435 311 -28.289349 +444 311 -31.451081 +445 311 -8.755310 +455 311 -1.481548 +456 311 -35.497395 +459 311 -30.269047 +460 311 -9.753308 +470 311 -31.182557 +471 311 -22.775225 +480 311 -49.613880 +481 311 -4.448511 +483 311 -15.398623 +484 311 -24.459212 +485 311 -6.880977 +496 311 -17.422295 +497 311 -34.557034 +312 312 1.564924 +319 312 0.147929 +320 312 0.065746 +321 312 0.065746 +322 312 0.065746 +324 312 0.065746 +327 312 0.065746 +328 312 0.065746 +329 312 0.065746 +331 312 0.065746 +332 312 0.147929 +334 312 0.065746 +335 312 0.147929 +337 312 0.065746 +339 312 0.147929 +341 312 0.065746 +361 312 -7.077980 +362 312 -1.134150 +386 312 -9.779754 +406 312 -19.169950 +411 312 -10.032437 +431 312 -25.804894 +435 312 -2.464575 +436 312 -7.843926 +456 312 -26.231743 +460 312 -17.954275 +480 312 -15.940440 +481 312 -10.752705 +483 312 -0.131071 +485 312 -21.862147 +313 313 2.994905 +319 313 0.065746 +320 313 0.065746 +321 313 0.065746 +322 313 0.147929 +323 313 0.591716 +324 313 0.147929 +327 313 0.065746 +328 313 0.065746 +331 313 0.147929 +334 313 0.065746 +335 313 0.065746 +336 313 0.591716 +337 313 0.591716 +340 313 0.065746 +361 313 -9.175145 +362 313 -0.679013 +386 313 -11.983518 +406 313 -8.674851 +410 313 -11.130603 +411 313 -1.445585 +431 313 -11.704601 +434 313 -2.948056 +435 313 -10.274449 +455 313 -1.073973 +456 313 -15.543854 +459 313 -13.926264 +460 313 -10.241165 +480 313 -24.329772 +483 313 -11.452063 +484 313 -13.498014 +485 313 -5.853516 +314 314 4.539941 +319 314 0.147929 +320 314 0.147929 +321 314 0.147929 +322 314 0.591716 +323 314 0.591716 +327 314 0.591716 +328 314 0.147929 +329 314 0.147929 +331 314 0.591716 +334 314 0.147929 +337 314 0.147929 +339 314 0.147929 +340 314 0.147929 +341 314 0.591716 +361 314 -8.005351 +362 314 -9.097895 +386 314 -20.049011 +406 314 -18.222995 +411 314 -20.218903 +431 314 -24.211188 +436 314 -20.422051 +456 314 -33.930890 +460 314 -14.680859 +461 314 -20.659363 +481 314 -49.103542 +483 314 -1.050309 +485 314 -21.486221 +486 314 -20.931896 +315 315 4.079717 +319 315 0.147929 +320 315 0.591716 +321 315 0.147929 +323 315 0.147929 +324 315 0.147929 +325 315 0.065746 +327 315 0.065746 +329 315 0.147929 +331 315 0.147929 +332 315 0.591716 +334 315 0.147929 +337 315 0.591716 +339 315 0.147929 +340 315 0.147929 +341 315 0.591716 +361 315 -14.199111 +362 315 -3.540734 +386 315 -20.989516 +406 315 -18.531977 +411 315 -21.380988 +431 315 -24.801731 +436 315 -21.814493 +444 315 -10.514433 +456 315 -34.951643 +460 315 -2.021233 +461 315 -20.270817 +469 315 -14.454949 +480 315 -19.896840 +481 315 -30.937450 +483 315 -0.277069 +485 315 -22.815847 +494 315 -14.366190 +316 316 2.863412 +319 316 0.147929 +320 316 0.065746 +321 316 0.147929 +323 316 0.065746 +325 316 0.065746 +327 316 0.147929 +328 316 0.065746 +329 316 0.147929 +331 316 0.065746 +332 316 0.147929 +337 316 0.591716 +338 316 0.591716 +339 316 0.065746 +340 316 0.147929 +341 316 0.147929 +361 316 -14.179176 +362 316 -3.554697 +386 316 -20.981140 +406 316 -18.525668 +411 316 -21.371013 +431 316 -24.791338 +436 316 -21.802836 +444 316 -10.524183 +456 316 -34.934524 +460 316 -8.618487 +461 316 -20.573772 +469 316 -14.467416 +480 316 -19.735930 +481 316 -31.070207 +483 316 -0.123067 +485 316 -33.013740 +494 316 -14.377451 +317 317 1.252630 +319 317 0.147929 +321 317 0.065746 +323 317 0.147929 +324 317 0.065746 +325 317 0.065746 +329 317 0.147929 +332 317 0.065746 +339 317 0.147929 +340 317 0.147929 +361 317 -6.285408 +362 317 -1.591447 +386 317 -9.318121 +406 317 -18.518498 +411 317 -9.490090 +431 317 -24.779504 +436 317 -9.680635 +444 317 -10.528216 +456 317 -34.915187 +460 317 -0.497042 +461 317 -9.393602 +469 317 -14.472574 +480 317 -19.554272 +481 317 -31.220269 +485 317 -10.121079 +494 317 -14.382113 +318 318 4.079717 +319 318 0.147929 +320 318 0.147929 +321 318 0.591716 +324 318 0.591716 +325 318 0.065746 +327 318 0.147929 +329 318 0.065746 +331 318 0.147929 +337 318 0.591716 +338 318 0.591716 +339 318 0.147929 +341 318 0.591716 +361 318 -50.970807 +362 318 -18.706724 +386 318 -82.131047 +406 318 -18.365360 +411 318 -83.322463 +431 318 -24.518494 +436 318 -84.664438 +444 318 -10.520691 +456 318 -24.691374 +461 318 -86.163088 +469 318 -14.462950 +481 318 -24.892660 +483 318 -0.270264 +485 318 -9.110637 +486 318 -78.714539 +494 318 -14.373415 +1 319 0.147929 +2 319 0.065746 +3 319 0.065746 +4 319 0.065746 +5 319 0.065746 +8 319 0.147929 +13 319 0.147929 +14 319 0.147929 +15 319 0.147929 +16 319 0.147929 +17 319 0.147929 +19 319 0.147929 +21 319 0.147929 +22 319 0.147929 +25 319 0.147929 +26 319 0.065746 +27 319 0.591716 +28 319 0.147929 +30 319 0.065746 +32 319 0.065746 +34 319 0.065746 +37 319 0.147929 +38 319 0.147929 +41 319 0.147929 +42 319 0.147929 +43 319 0.065746 +44 319 0.591716 +49 319 0.147929 +50 319 0.147929 +51 319 0.065746 +52 319 0.147929 +53 319 0.147929 +54 319 0.591716 +55 319 0.065746 +57 319 0.147929 +58 319 0.147929 +59 319 0.147929 +60 319 0.147929 +62 319 0.147929 +63 319 0.147929 +64 319 0.147929 +65 319 0.065746 +66 319 0.065746 +67 319 0.147929 +69 319 0.065746 +70 319 0.147929 +72 319 0.065746 +73 319 0.147929 +75 319 0.147929 +77 319 0.065746 +78 319 0.065746 +80 319 0.065746 +84 319 0.147929 +86 319 0.065746 +87 319 0.065746 +89 319 0.147929 +90 319 0.147929 +91 319 0.147929 +93 319 0.147929 +94 319 0.147929 +99 319 0.147929 +101 319 0.147929 +105 319 0.147929 +106 319 0.147929 +108 319 0.147929 +109 319 0.147929 +111 319 0.147929 +116 319 0.147929 +117 319 0.147929 +119 319 0.147929 +120 319 0.147929 +122 319 0.147929 +124 319 0.147929 +125 319 0.065746 +126 319 0.147929 +127 319 0.147929 +129 319 0.147929 +130 319 0.065746 +131 319 0.065746 +132 319 0.065746 +135 319 0.147929 +136 319 0.147929 +137 319 0.065746 +141 319 0.147929 +148 319 0.147929 +149 319 0.147929 +150 319 0.147929 +151 319 0.065746 +152 319 0.147929 +153 319 0.065746 +159 319 0.147929 +163 319 0.147929 +166 319 0.147929 +167 319 0.147929 +168 319 0.065746 +169 319 0.147929 +173 319 0.147929 +175 319 0.147929 +177 319 0.147929 +178 319 0.147929 +179 319 0.065746 +181 319 0.147929 +182 319 0.065746 +183 319 0.147929 +185 319 0.147929 +186 319 0.147929 +187 319 0.147929 +188 319 0.065746 +189 319 0.147929 +190 319 0.065746 +194 319 0.147929 +195 319 0.147929 +196 319 0.065746 +197 319 0.065746 +199 319 0.065746 +201 319 0.147929 +202 319 0.147929 +204 319 0.147929 +205 319 0.147929 +206 319 0.147929 +208 319 0.147929 +213 319 0.147929 +214 319 0.147929 +215 319 0.147929 +217 319 0.147929 +219 319 0.147929 +220 319 0.147929 +221 319 0.147929 +222 319 0.147929 +223 319 0.591716 +224 319 0.147929 +227 319 0.147929 +228 319 0.147929 +229 319 0.147929 +230 319 0.147929 +231 319 0.147929 +233 319 0.147929 +234 319 0.147929 +235 319 0.147929 +238 319 0.147929 +239 319 0.147929 +241 319 0.147929 +242 319 0.147929 +244 319 0.147929 +245 319 0.065746 +247 319 0.147929 +250 319 0.147929 +251 319 0.065746 +252 319 0.147929 +253 319 0.147929 +257 319 0.147929 +258 319 0.147929 +259 319 0.065746 +261 319 0.065746 +262 319 0.065746 +263 319 0.147929 +264 319 0.147929 +265 319 0.147929 +266 319 0.147929 +267 319 0.147929 +268 319 0.147929 +269 319 0.147929 +270 319 0.065746 +271 319 0.147929 +272 319 0.147929 +273 319 0.065746 +274 319 0.147929 +275 319 0.065746 +277 319 0.065746 +278 319 0.147929 +279 319 0.147929 +281 319 0.147929 +282 319 0.147929 +283 319 0.065746 +284 319 0.147929 +285 319 0.147929 +287 319 0.065746 +289 319 0.147929 +290 319 0.147929 +292 319 0.065746 +293 319 0.147929 +294 319 0.147929 +296 319 0.147929 +298 319 0.591716 +299 319 0.065746 +300 319 0.065746 +302 319 0.147929 +304 319 0.147929 +305 319 0.147929 +306 319 0.147929 +307 319 0.065746 +308 319 0.147929 +309 319 0.147929 +310 319 0.591716 +311 319 0.147929 +312 319 0.147929 +313 319 0.065746 +314 319 0.147929 +315 319 0.147929 +316 319 0.147929 +317 319 0.147929 +318 319 0.147929 +319 319 38.731835 +347 319 -87.985741 +348 319 -114.894237 +349 319 -114.952710 +350 319 -115.018841 +351 319 -74.499424 +369 319 -13.894450 +370 319 -14.625846 +371 319 -14.625970 +372 319 -14.626111 +373 319 -14.626270 +374 319 -14.276887 +376 319 -65.326734 +377 319 -148.158171 +378 319 -148.258157 +379 319 -127.399854 +380 319 -105.021035 +399 319 -0.349563 +400 319 -14.626654 +401 319 -14.626884 +402 319 -129.672980 +403 319 -146.894426 +404 319 -181.343887 +405 319 -298.399108 +406 319 -3784.740859 +407 319 -128.486509 +426 319 -28.144742 +427 319 -44.332523 +428 319 -92.697089 +429 319 -163.720149 +430 319 -455.388093 +431 319 -4032.726734 +432 319 -311.202393 +433 319 -4.335844 +447 319 -29.370147 +448 319 -33.661787 +449 319 -33.690472 +450 319 -42.133909 +451 319 -72.281853 +452 319 -124.151407 +453 319 -88.429463 +454 319 -255.527665 +455 319 -764.033403 +456 319 -3425.023372 +457 319 -199.007771 +458 319 -154.935167 +472 319 -2.921319 +475 319 -70.683139 +476 319 -73.930756 +477 319 -20.686548 +478 319 -188.266183 +479 319 -448.706576 +480 319 -1204.092240 +481 319 -2650.430019 +482 319 -118.303314 +483 319 -235.744882 +484 319 -20.165946 +1 320 0.065746 +3 320 0.147929 +4 320 0.147929 +10 320 0.147929 +14 320 0.591716 +15 320 0.591716 +17 320 0.147929 +18 320 0.147929 +20 320 0.065746 +21 320 0.591716 +23 320 0.147929 +24 320 0.147929 +25 320 0.591716 +32 320 0.591716 +33 320 0.147929 +35 320 0.147929 +36 320 0.065746 +37 320 0.591716 +38 320 0.147929 +40 320 0.065746 +42 320 0.591716 +43 320 0.591716 +44 320 0.147929 +45 320 0.065746 +46 320 0.065746 +47 320 0.147929 +48 320 0.147929 +49 320 0.147929 +50 320 0.147929 +52 320 0.147929 +53 320 0.591716 +54 320 0.591716 +55 320 0.147929 +56 320 0.147929 +57 320 0.591716 +58 320 0.065746 +59 320 0.147929 +60 320 0.147929 +61 320 0.591716 +63 320 0.591716 +64 320 0.065746 +65 320 0.591716 +66 320 0.147929 +67 320 0.147929 +68 320 0.065746 +69 320 0.147929 +70 320 0.147929 +71 320 0.065746 +72 320 0.147929 +73 320 0.147929 +75 320 0.591716 +78 320 0.147929 +79 320 0.065746 +80 320 0.147929 +81 320 0.591716 +82 320 0.147929 +84 320 0.147929 +85 320 0.147929 +86 320 0.591716 +87 320 0.591716 +89 320 0.591716 +90 320 0.147929 +91 320 0.147929 +93 320 0.147929 +94 320 0.591716 +95 320 0.147929 +97 320 0.147929 +98 320 0.147929 +99 320 0.147929 +100 320 0.147929 +101 320 0.065746 +102 320 0.147929 +103 320 0.147929 +104 320 0.065746 +106 320 0.147929 +107 320 0.147929 +108 320 0.065746 +109 320 0.147929 +110 320 0.147929 +111 320 0.591716 +112 320 0.065746 +113 320 0.147929 +114 320 0.591716 +115 320 0.065746 +116 320 0.147929 +117 320 0.591716 +118 320 0.147929 +119 320 0.591716 +121 320 0.591716 +122 320 0.591716 +123 320 0.147929 +124 320 0.147929 +125 320 0.147929 +126 320 0.591716 +127 320 0.147929 +128 320 0.591716 +129 320 0.591716 +131 320 0.065746 +132 320 0.147929 +133 320 0.591716 +136 320 0.147929 +138 320 0.591716 +139 320 0.147929 +140 320 0.065746 +141 320 0.147929 +144 320 0.591716 +145 320 0.147929 +146 320 0.065746 +147 320 0.065746 +148 320 0.147929 +149 320 0.147929 +150 320 0.147929 +151 320 0.147929 +152 320 0.147929 +153 320 0.147929 +154 320 0.147929 +155 320 0.147929 +156 320 0.147929 +158 320 0.147929 +159 320 0.147929 +160 320 0.591716 +161 320 0.591716 +162 320 0.147929 +163 320 0.591716 +164 320 0.591716 +165 320 0.591716 +166 320 0.147929 +167 320 0.065746 +169 320 0.147929 +170 320 0.591716 +171 320 0.147929 +172 320 0.147929 +173 320 0.147929 +174 320 0.065746 +175 320 0.065746 +177 320 0.147929 +180 320 0.147929 +181 320 0.065746 +182 320 0.065746 +183 320 0.591716 +184 320 0.147929 +186 320 0.065746 +188 320 0.591716 +189 320 0.147929 +190 320 0.591716 +193 320 0.147929 +194 320 0.147929 +195 320 0.591716 +196 320 0.147929 +198 320 0.147929 +201 320 0.147929 +202 320 0.147929 +203 320 0.591716 +204 320 0.147929 +206 320 0.065746 +207 320 0.065746 +208 320 0.591716 +211 320 0.147929 +212 320 0.591716 +213 320 0.065746 +214 320 0.065746 +216 320 0.591716 +217 320 0.147929 +219 320 0.591716 +220 320 0.147929 +221 320 0.591716 +222 320 0.591716 +224 320 0.591716 +227 320 0.591716 +228 320 0.147929 +229 320 0.591716 +230 320 0.591716 +231 320 0.147929 +232 320 0.591716 +233 320 0.591716 +235 320 0.591716 +236 320 0.147929 +238 320 0.147929 +239 320 0.065746 +240 320 0.147929 +241 320 0.147929 +242 320 0.065746 +244 320 0.147929 +245 320 0.065746 +248 320 0.065746 +252 320 0.147929 +254 320 0.147929 +256 320 0.065746 +257 320 0.591716 +258 320 0.065746 +259 320 0.065746 +261 320 0.591716 +263 320 0.147929 +264 320 0.147929 +265 320 0.065746 +266 320 0.591716 +267 320 0.147929 +268 320 0.147929 +269 320 0.147929 +270 320 0.065746 +271 320 0.065746 +272 320 0.591716 +273 320 0.591716 +274 320 0.147929 +275 320 0.065746 +277 320 0.065746 +278 320 0.591716 +280 320 0.065746 +281 320 0.065746 +282 320 0.065746 +283 320 0.147929 +284 320 0.591716 +287 320 0.591716 +290 320 0.591716 +292 320 0.065746 +293 320 0.591716 +294 320 0.591716 +295 320 0.065746 +296 320 0.147929 +297 320 0.147929 +298 320 0.147929 +305 320 0.065746 +308 320 0.147929 +309 320 0.065746 +310 320 0.065746 +311 320 0.147929 +312 320 0.065746 +313 320 0.065746 +314 320 0.147929 +315 320 0.591716 +316 320 0.065746 +318 320 0.147929 +320 320 72.252772 +347 320 -107.006608 +353 320 -21.975654 +354 320 -123.657317 +359 320 -8.964040 +372 320 -48.336388 +373 320 -74.493979 +376 320 -3.738565 +378 320 -43.928541 +379 320 -302.626422 +380 320 -13.003624 +381 320 -10.279640 +384 320 -9.930397 +398 320 -118.428482 +399 320 -2.016299 +401 320 -13.692473 +402 320 -3.901208 +403 320 -7.265735 +404 320 -438.154622 +405 320 -26.720991 +406 320 -15.590913 +409 320 -9.911904 +423 320 -16.794290 +424 320 -101.296685 +426 320 -8.440456 +427 320 -34.747147 +429 320 -428.778681 +430 320 -196.938105 +431 320 -49.551644 +434 320 -9.906493 +449 320 -110.063739 +450 320 -15.310282 +452 320 -42.487619 +454 320 -364.556570 +455 320 -429.576182 +456 320 -96.484007 +459 320 -9.914146 +472 320 -37.099611 +474 320 -6.227886 +475 320 -144.869867 +476 320 -23.790392 +477 320 -25.648447 +478 320 -91.692890 +479 320 -171.916469 +480 320 -626.098008 +481 320 -220.026597 +484 320 -9.934887 +497 320 -15.195577 +498 320 -21.856718 +500 320 -171.564225 +2 321 0.065746 +3 321 0.065746 +5 321 0.147929 +6 321 0.147929 +7 321 0.591716 +8 321 0.147929 +9 321 0.065746 +16 321 0.147929 +17 321 0.147929 +18 321 0.147929 +19 321 0.065746 +20 321 0.065746 +21 321 0.065746 +22 321 0.147929 +23 321 0.147929 +24 321 0.147929 +25 321 0.065746 +31 321 0.147929 +32 321 0.147929 +33 321 0.065746 +34 321 0.065746 +36 321 0.147929 +37 321 0.147929 +38 321 0.147929 +39 321 0.591716 +40 321 0.147929 +42 321 0.147929 +43 321 0.147929 +44 321 0.147929 +46 321 0.065746 +47 321 0.591716 +51 321 0.147929 +52 321 0.147929 +53 321 0.147929 +54 321 0.147929 +55 321 0.065746 +60 321 0.065746 +66 321 0.065746 +67 321 0.065746 +68 321 0.065746 +69 321 0.147929 +70 321 0.065746 +77 321 0.065746 +79 321 0.147929 +80 321 0.147929 +81 321 0.065746 +82 321 0.591716 +83 321 0.591716 +84 321 0.147929 +85 321 0.147929 +87 321 0.065746 +89 321 0.147929 +90 321 0.147929 +91 321 0.065746 +92 321 0.065746 +95 321 0.591716 +96 321 0.591716 +97 321 0.065746 +98 321 0.591716 +100 321 0.065746 +101 321 0.065746 +102 321 0.147929 +103 321 0.147929 +104 321 0.065746 +106 321 0.147929 +107 321 0.591716 +108 321 0.147929 +109 321 0.591716 +110 321 0.591716 +112 321 0.591716 +115 321 0.065746 +116 321 0.147929 +117 321 0.065746 +118 321 0.147929 +119 321 0.591716 +120 321 0.065746 +121 321 0.065746 +122 321 0.147929 +123 321 0.591716 +124 321 0.147929 +125 321 0.065746 +126 321 0.147929 +129 321 0.147929 +131 321 0.147929 +132 321 0.591716 +134 321 0.147929 +135 321 0.591716 +136 321 0.147929 +137 321 0.147929 +138 321 0.147929 +140 321 0.147929 +141 321 0.147929 +143 321 0.147929 +145 321 0.147929 +146 321 0.591716 +148 321 0.147929 +150 321 0.147929 +152 321 0.065746 +154 321 0.147929 +155 321 0.147929 +156 321 0.147929 +157 321 0.147929 +159 321 0.147929 +160 321 0.147929 +161 321 0.147929 +162 321 0.147929 +163 321 0.147929 +164 321 0.147929 +166 321 0.065746 +167 321 0.147929 +168 321 0.147929 +169 321 0.065746 +172 321 0.065746 +173 321 0.591716 +174 321 0.147929 +175 321 0.147929 +176 321 0.147929 +178 321 0.147929 +179 321 0.147929 +180 321 0.147929 +182 321 0.147929 +183 321 0.065746 +185 321 0.147929 +186 321 0.147929 +187 321 0.065746 +188 321 0.147929 +190 321 0.147929 +191 321 0.065746 +192 321 0.147929 +193 321 0.147929 +194 321 0.147929 +195 321 0.065746 +196 321 0.065746 +199 321 0.065746 +201 321 0.147929 +202 321 0.147929 +203 321 0.065746 +204 321 0.147929 +205 321 0.147929 +206 321 0.065746 +207 321 0.147929 +208 321 0.147929 +209 321 0.147929 +211 321 0.147929 +212 321 0.147929 +213 321 0.147929 +214 321 0.065746 +215 321 0.147929 +216 321 0.065746 +217 321 0.065746 +218 321 0.065746 +223 321 0.065746 +224 321 0.065746 +227 321 0.065746 +228 321 0.147929 +230 321 0.065746 +231 321 0.147929 +232 321 0.147929 +234 321 0.147929 +235 321 0.065746 +237 321 0.147929 +239 321 0.147929 +240 321 0.065746 +241 321 0.147929 +242 321 0.147929 +244 321 0.147929 +245 321 0.147929 +247 321 0.065746 +248 321 0.147929 +250 321 0.147929 +251 321 0.147929 +252 321 0.065746 +253 321 0.147929 +254 321 0.147929 +255 321 0.147929 +256 321 0.065746 +257 321 0.065746 +258 321 0.147929 +259 321 0.147929 +261 321 0.591716 +262 321 0.591716 +263 321 0.065746 +265 321 0.147929 +266 321 0.147929 +267 321 0.147929 +268 321 0.065746 +269 321 0.147929 +270 321 0.147929 +271 321 0.065746 +272 321 0.065746 +274 321 0.147929 +275 321 0.147929 +277 321 0.147929 +279 321 0.147929 +280 321 0.147929 +281 321 0.147929 +282 321 0.147929 +283 321 0.147929 +284 321 0.065746 +288 321 0.065746 +289 321 0.147929 +290 321 0.147929 +292 321 0.147929 +293 321 0.147929 +294 321 0.147929 +296 321 0.147929 +297 321 0.147929 +298 321 0.147929 +300 321 0.147929 +302 321 0.065746 +304 321 0.147929 +305 321 0.065746 +306 321 0.147929 +307 321 0.065746 +308 321 0.147929 +309 321 0.147929 +310 321 0.147929 +311 321 0.147929 +312 321 0.065746 +313 321 0.065746 +314 321 0.147929 +315 321 0.147929 +316 321 0.147929 +317 321 0.065746 +318 321 0.591716 +321 321 48.108868 +347 321 -88.368077 +348 321 -113.315899 +349 321 -113.315931 +350 321 -113.315968 +351 321 -113.316008 +352 321 -113.316055 +353 321 -123.516496 +354 321 -265.642271 +355 321 -350.714688 +356 321 -410.926201 +357 321 -500.851283 +358 321 -623.354003 +359 321 -640.049159 +360 321 -1366.476080 +361 321 -5330.838312 +362 321 -875.271933 +369 321 -31.310650 +370 321 -32.960033 +371 321 -32.961726 +372 321 -32.963652 +373 321 -32.965835 +374 321 -32.968304 +375 321 -32.971093 +376 321 -32.974241 +377 321 -32.977796 +378 321 -34.820362 +379 321 -89.163000 +380 321 -102.741453 +381 321 -236.728718 +382 321 -176.383577 +383 321 -597.127721 +384 321 -1793.308912 +385 321 -1865.664033 +386 321 -3384.385132 +387 321 -245.873444 +402 321 -29.030803 +403 321 -33.391322 +404 321 -37.215117 +405 321 -93.480666 +406 321 -925.219725 +407 321 -1719.480166 +408 321 -1246.624657 +409 321 -694.964178 +410 321 -1255.742803 +411 321 -2387.823106 +412 321 -237.586924 +426 321 -22.348651 +427 321 -33.725919 +428 321 -150.554386 +429 321 -279.388461 +430 321 -1259.234681 +431 321 -811.695388 +432 321 -94.220585 +433 321 -695.409377 +434 321 -840.525198 +435 321 -768.783217 +436 321 -2164.547833 +437 321 -229.286843 +438 321 -4.871875 +447 321 -29.186351 +448 321 -33.598353 +449 321 -33.624578 +450 321 -41.955586 +451 321 -70.412636 +452 321 -86.858025 +453 321 -133.003337 +454 321 -105.375127 +455 321 -37.785833 +456 321 -88.316592 +457 321 -820.284528 +458 321 -682.894277 +459 321 -740.043030 +460 321 -884.979556 +461 321 -1496.473510 +462 321 -195.705379 +463 321 -29.203476 +472 321 -3.046259 +475 321 -68.505294 +476 321 -77.717536 +477 321 -50.189813 +478 321 -12.413093 +479 321 -45.210493 +480 321 -199.010695 +481 321 -749.370226 +482 321 -489.779890 +483 321 -487.616538 +484 321 -365.682981 +485 321 -1344.869053 +486 321 -1047.785536 +487 321 -105.410542 +488 321 -114.327382 +1 322 0.147929 +2 322 0.065746 +3 322 0.591716 +4 322 0.147929 +5 322 0.065746 +6 322 0.065746 +7 322 0.147929 +8 322 0.591716 +10 322 0.591716 +11 322 0.147929 +12 322 0.591716 +13 322 0.147929 +14 322 0.147929 +16 322 0.591716 +18 322 0.147929 +19 322 0.065746 +21 322 0.147929 +22 322 0.147929 +23 322 0.147929 +24 322 0.147929 +25 322 0.591716 +26 322 0.147929 +27 322 0.147929 +28 322 0.065746 +33 322 0.147929 +34 322 0.065746 +36 322 0.065746 +37 322 0.591716 +39 322 0.147929 +40 322 0.147929 +41 322 0.147929 +42 322 0.591716 +43 322 0.591716 +44 322 0.591716 +45 322 0.147929 +46 322 0.065746 +47 322 0.591716 +48 322 0.065746 +49 322 0.065746 +53 322 0.065746 +54 322 0.065746 +55 322 0.065746 +56 322 0.147929 +57 322 0.065746 +58 322 0.065746 +60 322 0.147929 +61 322 0.591716 +62 322 0.147929 +63 322 0.147929 +65 322 0.591716 +67 322 0.147929 +68 322 0.147929 +70 322 0.147929 +72 322 0.065746 +73 322 0.065746 +74 322 0.065746 +75 322 0.591716 +77 322 0.065746 +78 322 0.147929 +84 322 0.147929 +85 322 0.147929 +86 322 0.591716 +87 322 0.147929 +89 322 0.147929 +90 322 0.147929 +91 322 0.147929 +92 322 0.065746 +93 322 0.591716 +94 322 0.147929 +95 322 0.147929 +97 322 0.147929 +99 322 0.147929 +100 322 0.591716 +101 322 0.065746 +102 322 0.147929 +106 322 0.065746 +108 322 0.065746 +111 322 0.147929 +113 322 0.065746 +114 322 0.147929 +116 322 0.147929 +117 322 0.591716 +119 322 0.147929 +120 322 0.065746 +121 322 0.591716 +122 322 0.147929 +124 322 0.147929 +125 322 0.147929 +127 322 0.147929 +128 322 0.065746 +129 322 0.147929 +130 322 0.065746 +131 322 0.147929 +132 322 0.147929 +133 322 0.065746 +135 322 0.147929 +137 322 0.147929 +138 322 0.147929 +139 322 0.147929 +141 322 0.065746 +143 322 0.147929 +144 322 0.147929 +146 322 0.065746 +147 322 0.147929 +148 322 0.147929 +149 322 0.591716 +150 322 0.147929 +151 322 0.591716 +152 322 0.065746 +153 322 0.591716 +154 322 0.065746 +155 322 0.065746 +156 322 0.147929 +157 322 0.147929 +158 322 0.065746 +159 322 0.147929 +161 322 0.591716 +162 322 0.147929 +163 322 0.147929 +164 322 0.147929 +165 322 0.147929 +166 322 0.147929 +167 322 0.065746 +168 322 0.147929 +169 322 0.591716 +170 322 0.065746 +171 322 0.147929 +172 322 0.147929 +174 322 0.065746 +176 322 0.065746 +177 322 0.591716 +178 322 0.065746 +179 322 0.147929 +180 322 0.065746 +183 322 0.147929 +184 322 0.147929 +185 322 0.147929 +187 322 0.591716 +189 322 0.065746 +190 322 0.147929 +192 322 0.591716 +193 322 0.147929 +195 322 0.147929 +196 322 0.147929 +197 322 0.147929 +198 322 0.147929 +200 322 0.147929 +203 322 0.065746 +204 322 0.591716 +205 322 0.065746 +206 322 0.065746 +208 322 0.065746 +209 322 0.065746 +211 322 0.147929 +212 322 0.147929 +215 322 0.147929 +216 322 0.147929 +217 322 0.147929 +218 322 0.147929 +219 322 0.147929 +220 322 0.147929 +221 322 0.147929 +222 322 0.591716 +223 322 0.147929 +224 322 0.147929 +226 322 0.147929 +227 322 0.147929 +229 322 0.147929 +230 322 0.147929 +232 322 0.147929 +234 322 0.147929 +235 322 0.591716 +237 322 0.065746 +238 322 0.147929 +241 322 0.147929 +242 322 0.147929 +251 322 0.147929 +252 322 0.065746 +253 322 0.147929 +254 322 0.065746 +256 322 0.065746 +257 322 0.591716 +258 322 0.147929 +259 322 0.065746 +261 322 0.065746 +262 322 0.147929 +263 322 0.065746 +265 322 0.591716 +266 322 0.591716 +267 322 0.065746 +268 322 0.147929 +269 322 0.065746 +270 322 0.065746 +271 322 0.591716 +272 322 0.591716 +273 322 0.147929 +274 322 0.147929 +275 322 0.147929 +276 322 0.591716 +277 322 0.065746 +278 322 0.591716 +280 322 0.147929 +281 322 0.591716 +282 322 0.065746 +284 322 0.147929 +285 322 0.591716 +287 322 0.147929 +289 322 0.065746 +290 322 0.065746 +292 322 0.147929 +298 322 0.591716 +304 322 0.147929 +306 322 0.065746 +307 322 0.147929 +308 322 0.147929 +309 322 0.147929 +310 322 0.147929 +311 322 0.065746 +312 322 0.065746 +313 322 0.147929 +314 322 0.591716 +322 322 58.720859 +347 322 -76.853129 +353 322 -75.191261 +354 322 -25.594544 +355 322 -3.543964 +369 322 -5.236796 +371 322 -2.124525 +372 322 -85.606377 +376 322 -3.659999 +377 322 -0.497323 +378 322 -135.200273 +379 322 -53.861713 +380 322 -30.502196 +381 322 -6.018712 +394 322 -31.686759 +396 322 -26.261897 +397 322 -61.717469 +400 322 -8.070001 +401 322 -5.620560 +402 322 -85.989744 +403 322 -126.938908 +404 322 -52.746200 +405 322 -56.146069 +406 322 -2.225865 +419 322 -31.603158 +421 322 -84.336256 +422 322 -3.923426 +425 322 -13.910080 +426 322 -109.159672 +427 322 -168.778178 +428 322 -102.289106 +429 322 -85.700248 +430 322 -97.342948 +431 322 -25.602835 +444 322 -31.525807 +446 322 -88.571069 +449 322 -1.282085 +450 322 -12.856128 +451 322 -212.953874 +452 322 -148.153459 +453 322 -92.530879 +454 322 -217.014861 +455 322 -60.086601 +456 322 -15.562266 +469 322 -31.454989 +471 322 -111.676479 +472 322 -7.435874 +474 322 -14.374296 +475 322 -148.584846 +476 322 -196.523653 +477 322 -108.203545 +478 322 -232.559483 +479 322 -102.636588 +480 322 -128.180106 +481 322 -85.727728 +494 322 -31.390962 +496 322 -120.257848 +499 322 -87.154919 +500 322 -294.311257 +1 323 0.147929 +3 323 0.591716 +4 323 0.147929 +5 323 0.147929 +8 323 0.591716 +9 323 0.065746 +10 323 0.065746 +11 323 0.591716 +12 323 0.065746 +13 323 0.065746 +14 323 0.147929 +15 323 0.591716 +16 323 0.147929 +17 323 0.065746 +18 323 0.147929 +19 323 0.591716 +20 323 0.065746 +21 323 0.147929 +22 323 0.147929 +23 323 0.591716 +24 323 0.147929 +25 323 0.147929 +26 323 0.147929 +27 323 0.147929 +28 323 0.065746 +29 323 0.065746 +30 323 0.147929 +33 323 0.065746 +35 323 0.147929 +37 323 0.591716 +40 323 0.147929 +41 323 0.591716 +42 323 0.591716 +43 323 0.591716 +44 323 0.591716 +47 323 0.591716 +53 323 0.147929 +54 323 0.147929 +55 323 0.065746 +56 323 0.147929 +57 323 0.147929 +59 323 0.147929 +60 323 0.591716 +61 323 0.147929 +62 323 0.147929 +63 323 0.147929 +65 323 0.591716 +66 323 0.147929 +68 323 0.147929 +69 323 0.147929 +70 323 0.147929 +75 323 0.591716 +76 323 0.065746 +77 323 0.065746 +78 323 0.065746 +80 323 0.147929 +81 323 0.591716 +82 323 0.065746 +83 323 0.147929 +86 323 0.591716 +90 323 0.147929 +92 323 0.147929 +93 323 0.591716 +94 323 0.591716 +95 323 0.147929 +99 323 0.591716 +105 323 0.147929 +106 323 0.147929 +107 323 0.065746 +108 323 0.147929 +109 323 0.147929 +110 323 0.147929 +111 323 0.591716 +112 323 0.147929 +114 323 0.591716 +117 323 0.591716 +119 323 0.591716 +120 323 0.065746 +121 323 0.591716 +122 323 0.065746 +124 323 0.591716 +125 323 0.147929 +126 323 0.147929 +127 323 0.065746 +129 323 0.147929 +131 323 0.147929 +140 323 0.147929 +141 323 0.147929 +142 323 0.065746 +145 323 0.147929 +147 323 0.591716 +148 323 0.591716 +149 323 0.147929 +150 323 0.147929 +152 323 0.147929 +153 323 0.147929 +154 323 0.147929 +155 323 0.147929 +156 323 0.147929 +157 323 0.147929 +158 323 0.147929 +159 323 0.591716 +160 323 0.591716 +161 323 0.147929 +162 323 0.147929 +163 323 0.591716 +164 323 0.147929 +165 323 0.065746 +166 323 0.065746 +167 323 0.147929 +168 323 0.147929 +169 323 0.591716 +170 323 0.065746 +171 323 0.065746 +172 323 0.065746 +173 323 0.147929 +174 323 0.147929 +175 323 0.147929 +176 323 0.065746 +177 323 0.147929 +179 323 0.591716 +180 323 0.065746 +182 323 0.065746 +183 323 0.591716 +184 323 0.591716 +185 323 0.591716 +187 323 0.147929 +188 323 0.147929 +194 323 0.147929 +195 323 0.591716 +196 323 0.147929 +198 323 0.147929 +199 323 0.147929 +200 323 0.065746 +201 323 0.065746 +202 323 0.065746 +203 323 0.065746 +204 323 0.591716 +205 323 0.591716 +207 323 0.065746 +208 323 0.147929 +212 323 0.065746 +213 323 0.147929 +214 323 0.147929 +215 323 0.591716 +216 323 0.591716 +217 323 0.147929 +218 323 0.591716 +219 323 0.065746 +220 323 0.591716 +221 323 0.147929 +222 323 0.591716 +223 323 0.591716 +224 323 0.147929 +227 323 0.147929 +228 323 0.591716 +229 323 0.591716 +230 323 0.147929 +231 323 0.147929 +235 323 0.591716 +236 323 0.065746 +238 323 0.147929 +239 323 0.147929 +240 323 0.591716 +241 323 0.147929 +242 323 0.591716 +246 323 0.065746 +247 323 0.065746 +248 323 0.147929 +253 323 0.591716 +254 323 0.591716 +256 323 0.065746 +257 323 0.591716 +258 323 0.065746 +259 323 0.147929 +261 323 0.147929 +262 323 0.065746 +263 323 0.147929 +264 323 0.065746 +265 323 0.591716 +266 323 0.147929 +267 323 0.591716 +268 323 0.065746 +269 323 0.065746 +271 323 0.591716 +272 323 0.591716 +273 323 0.147929 +276 323 0.591716 +277 323 0.147929 +278 323 0.147929 +279 323 0.147929 +280 323 0.591716 +282 323 0.591716 +284 323 0.591716 +285 323 0.591716 +287 323 0.147929 +289 323 0.065746 +290 323 0.147929 +293 323 0.147929 +294 323 0.147929 +295 323 0.147929 +296 323 0.147929 +297 323 0.065746 +299 323 0.065746 +302 323 0.147929 +304 323 0.147929 +306 323 0.591716 +307 323 0.147929 +310 323 0.147929 +311 323 0.147929 +313 323 0.591716 +314 323 0.591716 +315 323 0.147929 +316 323 0.065746 +317 323 0.147929 +323 323 70.758354 +347 323 -23.064047 +354 323 -96.474867 +358 323 -11.070681 +359 323 -9.913490 +372 323 -28.134525 +378 323 -4.630047 +379 323 -124.037147 +383 323 -23.650922 +397 323 -18.650741 +398 323 -9.215161 +403 323 -44.516406 +404 323 -95.517961 +405 323 -18.732557 +406 323 -7.395374 +408 323 -24.039115 +423 323 -27.607258 +428 323 -73.466922 +429 323 -66.976666 +430 323 -122.179510 +431 323 -16.905398 +433 323 -24.464944 +448 323 -27.359408 +450 323 -3.806789 +453 323 -147.186790 +454 323 -34.196916 +455 323 -215.252510 +456 323 -36.840872 +457 323 -6.068628 +458 323 -18.860941 +473 323 -27.123078 +475 323 -33.814565 +478 323 -156.873800 +479 323 -113.782966 +480 323 -165.581045 +481 323 -45.735096 +482 323 -25.434182 +498 323 -14.542406 +499 323 -12.356503 +500 323 -41.282014 +1 324 0.065746 +3 324 0.591716 +5 324 0.065746 +6 324 0.065746 +7 324 0.147929 +8 324 0.065746 +9 324 0.065746 +10 324 0.065746 +11 324 0.147929 +12 324 0.147929 +13 324 0.147929 +14 324 0.147929 +15 324 0.147929 +16 324 0.147929 +17 324 0.591716 +20 324 0.147929 +21 324 0.591716 +22 324 0.147929 +23 324 0.147929 +24 324 0.147929 +25 324 0.591716 +26 324 0.147929 +27 324 0.591716 +28 324 0.147929 +29 324 0.065746 +30 324 0.147929 +31 324 0.147929 +32 324 0.147929 +33 324 0.065746 +34 324 0.147929 +35 324 0.591716 +36 324 0.147929 +37 324 0.591716 +41 324 0.065746 +43 324 0.591716 +44 324 0.147929 +45 324 0.147929 +46 324 0.147929 +47 324 0.147929 +48 324 0.147929 +49 324 0.147929 +50 324 0.147929 +52 324 0.065746 +53 324 0.147929 +54 324 0.147929 +55 324 0.591716 +56 324 0.147929 +57 324 0.147929 +58 324 0.147929 +59 324 0.147929 +60 324 0.065746 +61 324 0.591716 +62 324 0.065746 +63 324 0.065746 +64 324 0.147929 +65 324 0.591716 +66 324 0.147929 +67 324 0.147929 +68 324 0.065746 +69 324 0.065746 +70 324 0.065746 +71 324 0.147929 +72 324 0.147929 +73 324 0.065746 +74 324 0.147929 +75 324 0.591716 +77 324 0.065746 +78 324 0.147929 +79 324 0.065746 +82 324 0.147929 +83 324 0.065746 +84 324 0.065746 +85 324 0.147929 +88 324 0.065746 +89 324 0.591716 +90 324 0.147929 +91 324 0.147929 +92 324 0.147929 +93 324 0.147929 +94 324 0.147929 +96 324 0.147929 +97 324 0.591716 +99 324 0.147929 +100 324 0.147929 +101 324 0.147929 +102 324 0.591716 +103 324 0.147929 +104 324 0.065746 +105 324 0.147929 +106 324 0.147929 +107 324 0.147929 +108 324 0.147929 +109 324 0.147929 +110 324 0.147929 +111 324 0.591716 +112 324 0.147929 +113 324 0.147929 +114 324 0.147929 +115 324 0.147929 +116 324 0.591716 +117 324 0.591716 +118 324 0.147929 +119 324 0.147929 +120 324 0.065746 +121 324 0.591716 +122 324 0.591716 +123 324 0.591716 +124 324 0.147929 +125 324 0.147929 +127 324 0.147929 +128 324 0.147929 +129 324 0.591716 +130 324 0.065746 +131 324 0.147929 +132 324 0.147929 +134 324 0.147929 +135 324 0.591716 +137 324 0.147929 +138 324 0.147929 +139 324 0.147929 +140 324 0.147929 +141 324 0.591716 +144 324 0.147929 +145 324 0.147929 +146 324 0.147929 +147 324 0.147929 +148 324 0.147929 +149 324 0.591716 +150 324 0.147929 +151 324 0.147929 +152 324 0.147929 +153 324 0.591716 +154 324 0.147929 +155 324 0.147929 +156 324 0.147929 +157 324 0.147929 +158 324 0.147929 +159 324 0.147929 +160 324 0.591716 +161 324 0.147929 +162 324 0.147929 +163 324 0.147929 +164 324 0.147929 +165 324 0.147929 +166 324 0.065746 +169 324 0.147929 +170 324 0.147929 +171 324 0.147929 +173 324 0.147929 +174 324 0.065746 +176 324 0.147929 +177 324 0.147929 +178 324 0.147929 +179 324 0.147929 +180 324 0.147929 +181 324 0.065746 +183 324 0.591716 +184 324 0.147929 +188 324 0.147929 +189 324 0.147929 +190 324 0.147929 +192 324 0.591716 +193 324 0.147929 +194 324 0.147929 +195 324 0.591716 +196 324 0.065746 +198 324 0.147929 +200 324 0.147929 +201 324 0.147929 +202 324 0.147929 +203 324 0.147929 +204 324 0.147929 +206 324 0.147929 +210 324 0.147929 +211 324 0.065746 +212 324 0.147929 +213 324 0.065746 +214 324 0.065746 +215 324 0.591716 +217 324 0.147929 +218 324 0.065746 +219 324 0.147929 +220 324 0.147929 +221 324 0.147929 +222 324 0.147929 +224 324 0.147929 +227 324 0.147929 +228 324 0.147929 +229 324 0.147929 +230 324 0.147929 +231 324 0.147929 +232 324 0.147929 +233 324 0.591716 +235 324 0.591716 +237 324 0.147929 +238 324 0.591716 +240 324 0.147929 +241 324 0.065746 +242 324 0.065746 +243 324 0.147929 +244 324 0.065746 +248 324 0.147929 +251 324 0.147929 +252 324 0.147929 +253 324 0.591716 +254 324 0.147929 +256 324 0.147929 +257 324 0.591716 +258 324 0.147929 +262 324 0.591716 +264 324 0.147929 +265 324 0.147929 +266 324 0.147929 +267 324 0.065746 +268 324 0.065746 +269 324 0.065746 +270 324 0.065746 +271 324 0.147929 +272 324 0.591716 +273 324 0.147929 +274 324 0.065746 +275 324 0.147929 +277 324 0.147929 +278 324 0.591716 +280 324 0.147929 +281 324 0.147929 +282 324 0.591716 +284 324 0.591716 +285 324 0.591716 +286 324 0.065746 +287 324 0.147929 +289 324 0.147929 +290 324 0.147929 +291 324 0.147929 +293 324 0.147929 +294 324 0.147929 +296 324 0.147929 +297 324 0.147929 +302 324 0.065746 +303 324 0.065746 +304 324 0.147929 +306 324 0.591716 +308 324 0.147929 +309 324 0.147929 +310 324 0.591716 +311 324 0.147929 +312 324 0.065746 +313 324 0.147929 +315 324 0.147929 +317 324 0.065746 +318 324 0.591716 +324 324 66.873141 +347 324 -60.365060 +348 324 -5.215303 +353 324 -3.133489 +354 324 -132.551223 +355 324 -6.344363 +369 324 -8.319198 +372 324 -2.733429 +373 324 -70.172666 +374 324 -2.222642 +376 324 -9.997203 +378 324 -7.093856 +379 324 -181.652656 +380 324 -60.620459 +381 324 -47.665074 +394 324 -31.742597 +395 324 -17.888636 +398 324 -6.495439 +399 324 -66.287764 +401 324 -28.005756 +402 324 -8.282058 +404 324 -87.950912 +405 324 -202.372894 +406 324 -92.654477 +420 324 -24.607922 +421 324 -23.604922 +424 324 -14.836421 +425 324 -55.616527 +427 324 -35.152249 +429 324 -41.679613 +430 324 -466.328086 +431 324 -156.949707 +432 324 -37.489993 +446 324 -19.283187 +447 324 -27.442303 +450 324 -41.136869 +451 324 -38.677891 +452 324 -8.721523 +453 324 -39.238532 +454 324 -80.601995 +455 324 -528.518112 +456 324 -331.362070 +457 324 -102.216528 +472 324 -181.192651 +473 324 -46.332007 +475 324 -37.612808 +476 324 -88.120256 +477 324 -17.383428 +478 324 -35.072555 +479 324 -70.612651 +480 324 -120.901471 +481 324 -714.940414 +482 324 -192.095603 +498 324 -171.754795 +499 324 -51.668591 +500 324 -56.120640 +51 325 0.147929 +65 325 0.147929 +75 325 0.591716 +90 325 0.147929 +92 325 0.147929 +93 325 0.591716 +95 325 0.147929 +96 325 0.591716 +97 325 0.147929 +100 325 0.065746 +101 325 0.147929 +132 325 0.065746 +133 325 0.065746 +134 325 0.147929 +135 325 0.147929 +136 325 0.147929 +137 325 0.147929 +138 325 0.147929 +139 325 0.147929 +141 325 0.065746 +142 325 0.147929 +143 325 0.147929 +144 325 0.591716 +163 325 0.065746 +164 325 0.147929 +166 325 0.065746 +171 325 0.147929 +172 325 0.065746 +174 325 0.065746 +175 325 0.065746 +176 325 0.147929 +177 325 0.147929 +178 325 0.147929 +179 325 0.147929 +180 325 0.147929 +182 325 0.065746 +183 325 0.147929 +184 325 0.147929 +185 325 0.147929 +186 325 0.147929 +188 325 0.065746 +189 325 0.147929 +190 325 0.065746 +192 325 0.147929 +193 325 0.147929 +194 325 0.147929 +196 325 0.147929 +197 325 0.065746 +198 325 0.065746 +199 325 0.065746 +202 325 0.147929 +203 325 0.147929 +206 325 0.147929 +209 325 0.065746 +211 325 0.065746 +212 325 0.147929 +234 325 0.591716 +237 325 0.065746 +239 325 0.147929 +241 325 0.147929 +242 325 0.147929 +244 325 0.147929 +246 325 0.147929 +247 325 0.147929 +248 325 0.065746 +250 325 0.147929 +252 325 0.591716 +253 325 0.147929 +256 325 0.065746 +257 325 0.147929 +258 325 0.065746 +262 325 0.147929 +263 325 0.065746 +264 325 0.147929 +265 325 0.147929 +266 325 0.591716 +267 325 0.065746 +268 325 0.147929 +269 325 0.147929 +271 325 0.591716 +273 325 0.065746 +274 325 0.591716 +275 325 0.147929 +277 325 0.147929 +279 325 0.147929 +280 325 0.147929 +282 325 0.065746 +283 325 0.147929 +284 325 0.065746 +285 325 0.147929 +291 325 0.147929 +292 325 0.591716 +293 325 0.065746 +294 325 0.147929 +295 325 0.147929 +296 325 0.065746 +297 325 0.147929 +298 325 0.147929 +299 325 0.147929 +301 325 0.591716 +302 325 0.065746 +304 325 0.591716 +305 325 0.147929 +306 325 0.065746 +307 325 0.147929 +308 325 0.591716 +310 325 0.147929 +311 325 0.147929 +315 325 0.065746 +316 325 0.065746 +317 325 0.065746 +318 325 0.065746 +325 325 27.479113 +346 325 -118.687710 +347 325 -88.678847 +352 325 -8.217393 +353 325 -10.854273 +356 325 -9.210141 +357 325 -34.050566 +358 325 -34.138765 +359 325 -2.735319 +370 325 -23.858931 +371 325 -207.473156 +375 325 -12.197711 +376 325 -15.629348 +377 325 -75.199659 +378 325 -126.556522 +379 325 -81.109827 +380 325 -33.907873 +381 325 -24.764109 +395 325 -235.839810 +397 325 -4.302801 +398 325 -18.544780 +399 325 -120.863410 +400 325 -154.096115 +401 325 -169.867909 +402 325 -121.071144 +403 325 -53.933215 +404 325 -33.372370 +405 325 -33.400622 +406 325 -0.501224 +419 325 -181.012810 +420 325 -171.306034 +421 325 -230.408880 +422 325 -228.734492 +423 325 -272.459559 +424 325 -254.190528 +425 325 -363.217969 +426 325 -355.239930 +427 325 -307.544191 +428 325 -307.569180 +429 325 -307.597483 +430 325 -89.527963 +431 325 -20.018056 +444 325 -3444.749699 +445 325 -1060.376963 +446 325 -568.116037 +447 325 -386.614564 +448 325 -307.447216 +449 325 -182.658255 +450 325 -23.213246 +469 325 -2082.561077 +470 325 -1216.997472 +471 325 -657.691581 +472 325 -416.111867 +473 325 -269.478363 +474 325 -231.753823 +475 325 -84.309998 +476 325 -29.480545 +477 325 -29.491743 +478 325 -20.455665 +479 325 -12.257399 +494 325 -1365.143816 +495 325 -814.263377 +496 325 -819.597366 +497 325 -556.293756 +498 325 -300.875539 +499 325 -195.349667 +500 325 -129.385503 +31 326 0.065746 +32 326 0.147929 +33 326 0.147929 +35 326 0.591716 +37 326 0.147929 +38 326 0.065746 +40 326 0.591716 +49 326 0.147929 +50 326 0.065746 +51 326 0.147929 +52 326 0.147929 +53 326 0.147929 +54 326 0.147929 +55 326 0.591716 +56 326 0.147929 +57 326 0.147929 +58 326 0.591716 +60 326 0.147929 +61 326 0.591716 +62 326 0.065746 +81 326 0.591716 +82 326 0.147929 +84 326 0.065746 +85 326 0.147929 +89 326 0.591716 +90 326 0.147929 +91 326 0.147929 +92 326 0.147929 +94 326 0.147929 +96 326 0.147929 +97 326 0.591716 +98 326 0.147929 +99 326 0.147929 +100 326 0.147929 +101 326 0.147929 +105 326 0.065746 +106 326 0.147929 +107 326 0.147929 +108 326 0.147929 +109 326 0.147929 +110 326 0.147929 +111 326 0.591716 +112 326 0.065746 +113 326 0.147929 +115 326 0.147929 +117 326 0.147929 +118 326 0.147929 +119 326 0.591716 +120 326 0.147929 +121 326 0.065746 +124 326 0.591716 +125 326 0.147929 +126 326 0.147929 +127 326 0.147929 +129 326 0.147929 +130 326 0.065746 +131 326 0.065746 +132 326 0.147929 +135 326 0.147929 +136 326 0.147929 +138 326 0.065746 +139 326 0.147929 +141 326 0.147929 +142 326 0.065746 +143 326 0.147929 +144 326 0.147929 +145 326 0.065746 +148 326 0.147929 +149 326 0.591716 +150 326 0.591716 +151 326 0.147929 +152 326 0.147929 +153 326 0.591716 +154 326 0.147929 +156 326 0.147929 +158 326 0.147929 +159 326 0.147929 +160 326 0.591716 +161 326 0.147929 +162 326 0.147929 +163 326 0.147929 +164 326 0.147929 +165 326 0.147929 +166 326 0.065746 +167 326 0.147929 +168 326 0.147929 +169 326 0.147929 +171 326 0.147929 +172 326 0.147929 +173 326 0.065746 +174 326 0.147929 +175 326 0.065746 +176 326 0.147929 +177 326 0.591716 +178 326 0.591716 +179 326 0.065746 +181 326 0.065746 +182 326 0.065746 +184 326 0.591716 +185 326 0.591716 +188 326 0.147929 +195 326 0.065746 +199 326 0.591716 +201 326 0.147929 +203 326 0.065746 +210 326 0.591716 +213 326 0.147929 +218 326 0.147929 +220 326 0.591716 +221 326 0.591716 +224 326 0.147929 +229 326 0.147929 +230 326 0.591716 +232 326 0.065746 +233 326 0.065746 +234 326 0.147929 +235 326 0.591716 +239 326 0.065746 +241 326 0.065746 +242 326 0.147929 +244 326 0.147929 +246 326 0.147929 +248 326 0.147929 +252 326 0.147929 +253 326 0.591716 +254 326 0.147929 +257 326 0.147929 +260 326 0.147929 +262 326 0.147929 +263 326 0.065746 +268 326 0.147929 +269 326 0.147929 +271 326 0.591716 +272 326 0.147929 +273 326 0.591716 +274 326 0.147929 +277 326 0.147929 +278 326 0.591716 +280 326 0.147929 +281 326 0.147929 +283 326 0.147929 +284 326 0.147929 +285 326 0.591716 +287 326 0.147929 +289 326 0.147929 +290 326 0.065746 +292 326 0.065746 +293 326 0.147929 +294 326 0.065746 +295 326 0.065746 +296 326 0.591716 +297 326 0.147929 +300 326 0.147929 +301 326 0.147929 +326 326 46.011105 +347 326 -89.670052 +354 326 -62.992106 +359 326 -9.006622 +372 326 -60.652994 +373 326 -41.663151 +376 326 -32.855001 +378 326 -4.847621 +379 326 -78.388559 +380 326 -12.398140 +384 326 -9.951426 +398 326 -100.663414 +401 326 -120.511329 +403 326 -1.227490 +404 326 -76.371472 +405 326 -26.226646 +406 326 -21.779047 +409 326 -9.905555 +423 326 -67.966912 +424 326 -31.073813 +426 326 -111.359594 +427 326 -7.371119 +429 326 -97.026642 +430 326 -132.052261 +431 326 -26.359435 +434 326 -9.872983 +449 326 -97.455265 +450 326 -9.235812 +452 326 -117.041863 +454 326 -85.455525 +455 326 -302.339183 +456 326 -49.866680 +459 326 -9.853608 +474 326 -90.850528 +475 326 -39.325856 +476 326 -19.046689 +477 326 -115.447107 +479 326 -65.317964 +480 326 -330.802842 +481 326 -92.915377 +484 326 -9.847370 +499 326 -5.904328 +500 326 -114.191025 +3 327 0.591716 +5 327 0.591716 +8 327 0.591716 +10 327 0.065746 +12 327 0.147929 +13 327 0.065746 +14 327 0.591716 +15 327 0.147929 +19 327 0.147929 +22 327 0.591716 +23 327 0.065746 +25 327 0.591716 +31 327 0.147929 +32 327 0.065746 +34 327 0.065746 +40 327 0.591716 +42 327 0.591716 +44 327 0.591716 +53 327 0.065746 +54 327 0.147929 +56 327 0.147929 +57 327 0.591716 +60 327 0.591716 +63 327 0.147929 +64 327 0.147929 +65 327 0.591716 +66 327 0.147929 +67 327 0.147929 +68 327 0.147929 +70 327 0.147929 +72 327 0.591716 +73 327 0.147929 +75 327 0.591716 +77 327 0.147929 +78 327 0.147929 +80 327 0.147929 +81 327 0.147929 +82 327 0.147929 +85 327 0.065746 +86 327 0.591716 +87 327 0.147929 +89 327 0.147929 +90 327 0.065746 +91 327 0.065746 +92 327 0.065746 +93 327 0.591716 +94 327 0.591716 +95 327 0.147929 +97 327 0.147929 +99 327 0.147929 +100 327 0.147929 +101 327 0.147929 +103 327 0.065746 +104 327 0.065746 +105 327 0.591716 +108 327 0.065746 +111 327 0.147929 +112 327 0.147929 +113 327 0.147929 +114 327 0.147929 +119 327 0.147929 +120 327 0.065746 +121 327 0.591716 +122 327 0.065746 +124 327 0.591716 +125 327 0.591716 +129 327 0.591716 +132 327 0.147929 +133 327 0.147929 +135 327 0.591716 +137 327 0.147929 +138 327 0.065746 +141 327 0.065746 +145 327 0.147929 +146 327 0.065746 +148 327 0.147929 +149 327 0.147929 +150 327 0.147929 +151 327 0.147929 +152 327 0.065746 +153 327 0.147929 +154 327 0.147929 +155 327 0.591716 +156 327 0.147929 +157 327 0.065746 +158 327 0.147929 +160 327 0.065746 +161 327 0.147929 +163 327 0.147929 +164 327 0.147929 +165 327 0.147929 +166 327 0.147929 +167 327 0.065746 +168 327 0.065746 +169 327 0.147929 +171 327 0.065746 +172 327 0.147929 +173 327 0.147929 +174 327 0.065746 +176 327 0.147929 +177 327 0.147929 +179 327 0.147929 +180 327 0.147929 +183 327 0.591716 +184 327 0.147929 +185 327 0.591716 +187 327 0.147929 +188 327 0.147929 +189 327 0.591716 +190 327 0.065746 +192 327 0.147929 +195 327 0.591716 +196 327 0.147929 +197 327 0.065746 +199 327 0.147929 +200 327 0.591716 +201 327 0.065746 +203 327 0.147929 +204 327 0.147929 +205 327 0.147929 +206 327 0.147929 +208 327 0.147929 +210 327 0.065746 +211 327 0.065746 +212 327 0.147929 +213 327 0.065746 +214 327 0.147929 +215 327 0.147929 +216 327 0.147929 +217 327 0.147929 +218 327 0.147929 +220 327 0.065746 +221 327 0.147929 +222 327 0.147929 +223 327 0.147929 +224 327 0.147929 +227 327 0.591716 +228 327 0.147929 +229 327 0.591716 +230 327 0.147929 +231 327 0.147929 +234 327 0.147929 +235 327 0.591716 +237 327 0.065746 +240 327 0.591716 +242 327 0.147929 +250 327 0.591716 +251 327 0.591716 +253 327 0.147929 +254 327 0.065746 +258 327 0.147929 +259 327 0.147929 +261 327 0.065746 +262 327 0.147929 +263 327 0.065746 +264 327 0.147929 +265 327 0.591716 +266 327 0.591716 +267 327 0.591716 +268 327 0.147929 +269 327 0.065746 +270 327 0.065746 +271 327 0.147929 +272 327 0.147929 +273 327 0.065746 +274 327 0.065746 +276 327 0.147929 +277 327 0.065746 +278 327 0.147929 +280 327 0.147929 +281 327 0.065746 +282 327 0.591716 +284 327 0.147929 +285 327 0.591716 +287 327 0.147929 +289 327 0.147929 +290 327 0.147929 +291 327 0.147929 +292 327 0.147929 +293 327 0.147929 +294 327 0.147929 +295 327 0.065746 +296 327 0.065746 +297 327 0.147929 +299 327 0.591716 +302 327 0.065746 +304 327 0.147929 +305 327 0.147929 +306 327 0.147929 +307 327 0.147929 +308 327 0.147929 +309 327 0.147929 +310 327 0.147929 +311 327 0.065746 +312 327 0.065746 +313 327 0.065746 +314 327 0.591716 +315 327 0.065746 +316 327 0.147929 +318 327 0.147929 +327 327 58.409534 +347 327 -61.189850 +353 327 -40.843715 +354 327 -21.107407 +358 327 -7.979659 +359 327 -2.394141 +369 327 -22.287056 +372 327 -71.068704 +378 327 -78.028399 +379 327 -52.208857 +383 327 -11.856786 +394 327 -134.435502 +397 327 -70.767550 +403 327 -122.513746 +404 327 -41.027230 +405 327 -10.058470 +406 327 -20.030003 +407 327 -3.792852 +408 327 -8.437103 +419 327 -133.342423 +422 327 -70.494023 +428 327 -129.188632 +429 327 -46.957399 +430 327 -209.797665 +431 327 -16.956080 +432 327 -12.630400 +444 327 -64.001322 +445 327 -68.252693 +447 327 -70.248830 +450 327 -3.828471 +452 327 -40.883181 +453 327 -126.281570 +454 327 -153.605633 +455 327 -203.107617 +456 327 -27.938387 +457 327 -9.543281 +470 327 -131.175656 +472 327 -70.032586 +475 327 -29.477206 +477 327 -115.199437 +478 327 -116.095174 +479 327 -269.557201 +480 327 -103.379529 +481 327 -29.458433 +495 327 -130.112415 +497 327 -51.893861 +498 327 -17.951957 +500 327 -83.825070 +15 328 0.065746 +17 328 0.147929 +20 328 0.065746 +21 328 0.065746 +22 328 0.147929 +23 328 0.065746 +27 328 0.147929 +28 328 0.065746 +32 328 0.147929 +34 328 0.147929 +36 328 0.147929 +37 328 0.147929 +38 328 0.147929 +40 328 0.147929 +42 328 0.147929 +43 328 0.591716 +44 328 0.147929 +50 328 0.065746 +52 328 0.147929 +54 328 0.065746 +58 328 0.591716 +60 328 0.147929 +61 328 0.591716 +62 328 0.065746 +63 328 0.065746 +67 328 0.065746 +71 328 0.065746 +98 328 0.147929 +100 328 0.065746 +101 328 0.065746 +102 328 0.147929 +103 328 0.065746 +106 328 0.147929 +107 328 0.147929 +108 328 0.147929 +109 328 0.147929 +110 328 0.065746 +112 328 0.147929 +113 328 0.065746 +116 328 0.065746 +117 328 0.147929 +118 328 0.147929 +119 328 0.591716 +120 328 0.065746 +133 328 0.147929 +134 328 0.591716 +135 328 0.591716 +137 328 0.147929 +138 328 0.147929 +139 328 0.065746 +140 328 0.591716 +142 328 0.147929 +143 328 0.065746 +146 328 0.591716 +152 328 0.147929 +153 328 0.065746 +154 328 0.147929 +155 328 0.591716 +156 328 0.147929 +157 328 0.147929 +159 328 0.065746 +160 328 0.147929 +161 328 0.591716 +164 328 0.065746 +166 328 0.065746 +167 328 0.147929 +168 328 0.147929 +169 328 0.147929 +170 328 0.065746 +191 328 0.065746 +193 328 0.065746 +194 328 0.147929 +195 328 0.147929 +197 328 0.065746 +198 328 0.147929 +201 328 0.065746 +202 328 0.147929 +203 328 0.147929 +204 328 0.147929 +205 328 0.065746 +206 328 0.065746 +208 328 0.065746 +211 328 0.147929 +212 328 0.147929 +213 328 0.065746 +214 328 0.147929 +215 328 0.065746 +217 328 0.147929 +220 328 0.147929 +221 328 0.147929 +222 328 0.147929 +223 328 0.147929 +224 328 0.147929 +227 328 0.065746 +228 328 0.147929 +229 328 0.591716 +230 328 0.065746 +231 328 0.147929 +232 328 0.065746 +235 328 0.147929 +238 328 0.065746 +239 328 0.065746 +240 328 0.065746 +250 328 0.147929 +251 328 0.147929 +252 328 0.147929 +253 328 0.065746 +254 328 0.147929 +255 328 0.147929 +257 328 0.065746 +258 328 0.147929 +259 328 0.147929 +261 328 0.147929 +262 328 0.065746 +263 328 0.065746 +265 328 0.065746 +266 328 0.065746 +267 328 0.147929 +269 328 0.147929 +270 328 0.065746 +271 328 0.147929 +272 328 0.147929 +274 328 0.591716 +275 328 0.147929 +277 328 0.065746 +278 328 0.147929 +279 328 0.147929 +281 328 0.147929 +282 328 0.147929 +283 328 0.065746 +284 328 0.147929 +285 328 0.591716 +286 328 0.147929 +287 328 0.147929 +288 328 0.147929 +289 328 0.147929 +290 328 0.147929 +292 328 0.147929 +293 328 0.147929 +294 328 0.147929 +296 328 0.147929 +297 328 0.147929 +298 328 0.147929 +299 328 0.065746 +304 328 0.147929 +306 328 0.147929 +307 328 0.065746 +308 328 0.147929 +309 328 0.147929 +310 328 0.147929 +311 328 0.065746 +312 328 0.065746 +313 328 0.065746 +314 328 0.147929 +316 328 0.065746 +328 328 37.047333 +347 328 -134.079378 +348 328 -182.891903 +349 328 -183.033438 +350 328 -163.584743 +351 328 -40.419129 +354 328 -63.678722 +355 328 -59.989778 +369 328 -31.406085 +370 328 -20.540189 +375 328 -19.608900 +376 328 -243.128916 +377 328 -256.717822 +378 328 -188.048239 +379 328 -209.275931 +380 328 -118.838704 +381 328 -145.274762 +382 328 -62.905452 +395 328 -12.522715 +396 328 -33.067422 +397 328 -33.072564 +398 328 -33.078394 +399 328 -33.084989 +400 328 -33.092440 +401 328 -33.100856 +402 328 -122.403960 +403 328 -162.333825 +404 328 -185.650735 +405 328 -348.305432 +406 328 -467.671338 +407 328 -311.664220 +408 328 -161.531887 +409 328 -12.386831 +428 328 -37.633950 +429 328 -66.238687 +430 328 -325.378021 +431 328 -533.483427 +432 328 -785.316395 +433 328 -1000.391507 +434 328 -789.107063 +435 328 -129.515460 +447 328 -6.149619 +448 328 -14.630050 +449 328 -14.630368 +450 328 -18.214062 +451 328 -29.257120 +452 328 -29.257795 +453 328 -29.258558 +454 328 -86.185547 +455 328 -95.071036 +456 328 -151.921862 +457 328 -325.158712 +458 328 -329.065858 +459 328 -799.722625 +460 328 -3324.816669 +461 328 -16.614976 +472 328 -7.894966 +475 328 -46.931798 +476 328 -66.112469 +477 328 -66.127276 +478 328 -86.454423 +479 328 -99.193671 +480 328 -99.223008 +481 328 -177.213541 +482 328 -90.380178 +483 328 -368.910566 +484 328 -755.093492 +485 328 -2135.740783 +486 328 -93.767783 +2 329 0.065746 +4 329 0.147929 +6 329 0.065746 +7 329 0.591716 +10 329 0.065746 +18 329 0.591716 +22 329 0.147929 +23 329 0.591716 +24 329 0.147929 +25 329 0.591716 +27 329 0.147929 +28 329 0.065746 +30 329 0.065746 +31 329 0.065746 +33 329 0.147929 +34 329 0.147929 +35 329 0.065746 +37 329 0.591716 +40 329 0.147929 +42 329 0.591716 +43 329 0.147929 +44 329 0.591716 +45 329 0.147929 +46 329 0.065746 +47 329 0.591716 +48 329 0.147929 +53 329 0.065746 +54 329 0.591716 +55 329 0.065746 +56 329 0.147929 +57 329 0.591716 +58 329 0.147929 +60 329 0.147929 +61 329 0.147929 +62 329 0.147929 +65 329 0.147929 +66 329 0.147929 +67 329 0.065746 +72 329 0.147929 +75 329 0.591716 +78 329 0.147929 +80 329 0.147929 +81 329 0.065746 +84 329 0.065746 +85 329 0.147929 +86 329 0.591716 +90 329 0.147929 +92 329 0.147929 +93 329 0.591716 +95 329 0.147929 +99 329 0.147929 +100 329 0.591716 +102 329 0.065746 +103 329 0.147929 +104 329 0.065746 +105 329 0.147929 +106 329 0.147929 +107 329 0.147929 +108 329 0.147929 +109 329 0.147929 +110 329 0.065746 +111 329 0.591716 +112 329 0.591716 +114 329 0.147929 +116 329 0.147929 +117 329 0.065746 +119 329 0.591716 +121 329 0.147929 +122 329 0.147929 +123 329 0.147929 +125 329 0.065746 +128 329 0.065746 +129 329 0.147929 +130 329 0.065746 +131 329 0.147929 +133 329 0.147929 +134 329 0.147929 +135 329 0.147929 +141 329 0.147929 +143 329 0.065746 +145 329 0.065746 +146 329 0.065746 +148 329 0.147929 +149 329 0.147929 +153 329 0.147929 +155 329 0.147929 +156 329 0.147929 +157 329 0.147929 +158 329 0.065746 +159 329 0.065746 +160 329 0.147929 +161 329 0.147929 +162 329 0.147929 +163 329 0.065746 +164 329 0.147929 +166 329 0.147929 +169 329 0.065746 +171 329 0.147929 +172 329 0.147929 +176 329 0.065746 +177 329 0.147929 +185 329 0.147929 +186 329 0.147929 +187 329 0.147929 +188 329 0.147929 +192 329 0.591716 +193 329 0.065746 +195 329 0.591716 +197 329 0.147929 +198 329 0.147929 +200 329 0.147929 +201 329 0.591716 +204 329 0.065746 +208 329 0.065746 +209 329 0.065746 +210 329 0.591716 +211 329 0.147929 +212 329 0.065746 +214 329 0.065746 +215 329 0.065746 +216 329 0.147929 +217 329 0.147929 +218 329 0.591716 +220 329 0.147929 +221 329 0.147929 +222 329 0.591716 +223 329 0.591716 +224 329 0.065746 +227 329 0.591716 +229 329 0.591716 +230 329 0.147929 +233 329 0.065746 +237 329 0.065746 +239 329 0.065746 +240 329 0.591716 +242 329 0.147929 +250 329 0.147929 +251 329 0.147929 +253 329 0.147929 +256 329 0.065746 +257 329 0.591716 +258 329 0.065746 +259 329 0.065746 +261 329 0.065746 +262 329 0.065746 +263 329 0.147929 +266 329 0.591716 +267 329 0.147929 +268 329 0.591716 +269 329 0.147929 +270 329 0.147929 +271 329 0.591716 +272 329 0.147929 +273 329 0.147929 +274 329 0.065746 +277 329 0.147929 +278 329 0.147929 +280 329 0.065746 +282 329 0.065746 +284 329 0.591716 +287 329 0.591716 +290 329 0.147929 +293 329 0.147929 +294 329 0.591716 +295 329 0.147929 +296 329 0.147929 +297 329 0.065746 +298 329 0.147929 +299 329 0.147929 +302 329 0.147929 +307 329 0.591716 +312 329 0.065746 +314 329 0.147929 +315 329 0.147929 +316 329 0.147929 +317 329 0.147929 +318 329 0.065746 +329 329 50.426442 +347 329 -180.062264 +353 329 -63.555126 +354 329 -39.255263 +355 329 -4.639244 +358 329 -22.571358 +359 329 -4.110451 +369 329 -6.905089 +372 329 -208.137968 +373 329 -0.051787 +376 329 -7.580381 +378 329 -122.557935 +379 329 -57.727976 +380 329 -60.269751 +381 329 -27.647658 +382 329 -3.453508 +383 329 -27.453056 +394 329 -40.693879 +395 329 -0.702882 +397 329 -54.333839 +398 329 -151.455675 +401 329 -28.106033 +402 329 -3.645195 +403 329 -135.508713 +404 329 -83.559398 +405 329 -146.427475 +406 329 -5.459721 +407 329 -32.330003 +420 329 -40.595791 +423 329 -203.458996 +426 329 -38.421560 +427 329 -38.823476 +428 329 -183.610940 +429 329 -121.811166 +430 329 -323.493086 +431 329 -51.460741 +432 329 -12.160039 +445 329 -9.611020 +446 329 -30.156641 +448 329 -201.206330 +450 329 -34.029723 +451 329 -56.644778 +452 329 -127.880036 +453 329 -117.961441 +454 329 -597.701485 +455 329 -104.386250 +456 329 -48.265519 +471 329 -21.746836 +472 329 -53.483548 +473 329 -61.813303 +474 329 -137.225425 +475 329 -143.287158 +476 329 -48.217277 +477 329 -182.029609 +478 329 -378.317597 +479 329 -402.992712 +480 329 -109.788941 +481 329 -15.715001 +497 329 -54.116658 +498 329 -20.260299 +499 329 -196.962547 +500 329 -170.725665 +3 330 0.591716 +4 330 0.147929 +8 330 0.591716 +14 330 0.591716 +15 330 0.591716 +16 330 0.147929 +18 330 0.147929 +19 330 0.147929 +20 330 0.065746 +22 330 0.147929 +23 330 0.591716 +24 330 0.147929 +25 330 0.591716 +26 330 0.065746 +27 330 0.591716 +29 330 0.147929 +30 330 0.147929 +35 330 0.065746 +38 330 0.065746 +40 330 0.591716 +42 330 0.591716 +43 330 0.591716 +44 330 0.591716 +47 330 0.591716 +52 330 0.147929 +53 330 0.065746 +54 330 0.591716 +57 330 0.591716 +63 330 0.147929 +68 330 0.065746 +72 330 0.591716 +74 330 0.147929 +75 330 0.591716 +78 330 0.147929 +79 330 0.147929 +80 330 0.147929 +81 330 0.147929 +82 330 0.591716 +83 330 0.065746 +84 330 0.147929 +93 330 0.147929 +94 330 0.591716 +117 330 0.147929 +129 330 0.591716 +140 330 0.065746 +143 330 0.065746 +146 330 0.065746 +147 330 0.065746 +150 330 0.147929 +156 330 0.065746 +163 330 0.591716 +175 330 0.065746 +177 330 0.147929 +179 330 0.591716 +181 330 0.147929 +185 330 0.147929 +186 330 0.591716 +190 330 0.147929 +192 330 0.591716 +193 330 0.147929 +195 330 0.591716 +199 330 0.147929 +201 330 0.147929 +202 330 0.147929 +210 330 0.147929 +214 330 0.065746 +218 330 0.147929 +220 330 0.591716 +221 330 0.591716 +228 330 0.147929 +229 330 0.591716 +231 330 0.147929 +232 330 0.147929 +235 330 0.591716 +238 330 0.147929 +244 330 0.065746 +245 330 0.591716 +250 330 0.591716 +254 330 0.147929 +330 330 40.378628 +354 330 -11.100961 +379 330 -11.688014 +404 330 -11.637788 +429 330 -11.598217 +430 330 -7.120960 +450 330 -9.140216 +453 330 -11.273417 +454 330 -11.569278 +455 330 -11.233220 +475 330 -12.890637 +476 330 -17.301952 +478 330 -11.986767 +479 330 -11.550956 +480 330 -11.266506 +481 330 -2.278227 +82 331 0.591716 +83 331 0.065746 +84 331 0.147929 +85 331 0.065746 +86 331 0.591716 +87 331 0.147929 +99 331 0.065746 +118 331 0.147929 +119 331 0.147929 +120 331 0.147929 +121 331 0.591716 +124 331 0.147929 +125 331 0.065746 +129 331 0.591716 +133 331 0.591716 +138 331 0.147929 +140 331 0.591716 +141 331 0.065746 +144 331 0.065746 +145 331 0.591716 +148 331 0.065746 +153 331 0.147929 +154 331 0.147929 +156 331 0.147929 +157 331 0.147929 +159 331 0.147929 +160 331 0.147929 +162 331 0.591716 +164 331 0.065746 +166 331 0.147929 +167 331 0.591716 +168 331 0.591716 +169 331 0.065746 +173 331 0.147929 +177 331 0.147929 +178 331 0.065746 +179 331 0.591716 +180 331 0.147929 +182 331 0.591716 +183 331 0.065746 +184 331 0.147929 +185 331 0.591716 +186 331 0.147929 +187 331 0.147929 +190 331 0.147929 +193 331 0.147929 +194 331 0.147929 +195 331 0.591716 +196 331 0.065746 +201 331 0.147929 +203 331 0.147929 +204 331 0.147929 +205 331 0.065746 +206 331 0.147929 +208 331 0.147929 +213 331 0.147929 +214 331 0.065746 +215 331 0.147929 +216 331 0.147929 +217 331 0.147929 +218 331 0.065746 +219 331 0.147929 +220 331 0.591716 +221 331 0.147929 +222 331 0.591716 +223 331 0.147929 +224 331 0.147929 +226 331 0.147929 +227 331 0.591716 +228 331 0.147929 +229 331 0.591716 +230 331 0.591716 +231 331 0.147929 +232 331 0.147929 +247 331 0.065746 +248 331 0.147929 +250 331 0.147929 +252 331 0.147929 +253 331 0.065746 +254 331 0.065746 +257 331 0.591716 +263 331 0.147929 +264 331 0.065746 +265 331 0.147929 +266 331 0.591716 +267 331 0.147929 +271 331 0.591716 +272 331 0.591716 +273 331 0.147929 +274 331 0.147929 +275 331 0.147929 +278 331 0.591716 +279 331 0.147929 +281 331 0.591716 +282 331 0.065746 +283 331 0.065746 +284 331 0.147929 +285 331 0.147929 +287 331 0.065746 +289 331 0.147929 +290 331 0.147929 +291 331 0.065746 +292 331 0.065746 +293 331 0.147929 +294 331 0.147929 +298 331 0.147929 +299 331 0.591716 +300 331 0.065746 +302 331 0.065746 +304 331 0.591716 +312 331 0.065746 +313 331 0.147929 +314 331 0.591716 +315 331 0.147929 +316 331 0.065746 +318 331 0.147929 +331 331 40.041315 +347 331 -24.959251 +348 331 -34.971064 +349 331 -24.149350 +354 331 -379.332322 +355 331 -3.018751 +374 331 -10.904373 +375 331 -35.147762 +376 331 -33.737637 +378 331 -4.759394 +379 331 -23.163171 +380 331 -382.323556 +401 331 -1.517178 +402 331 -47.204942 +403 331 -35.516375 +404 331 -22.613011 +405 331 -73.469902 +406 331 -322.997943 +427 331 -18.205389 +428 331 -34.603474 +429 331 -72.681721 +430 331 -57.981373 +431 331 -153.948023 +432 331 -231.820054 +450 331 -8.108427 +451 331 -33.101039 +452 331 -33.110557 +453 331 -12.397377 +454 331 -76.497719 +455 331 -124.051986 +456 331 -121.658469 +457 331 -288.400637 +458 331 -110.686050 +478 331 -114.314349 +479 331 -165.195044 +480 331 -165.236419 +481 331 -218.816052 +482 331 -311.120655 +483 331 -718.740851 +2 332 0.065746 +3 332 0.591716 +4 332 0.147929 +9 332 0.147929 +14 332 0.591716 +18 332 0.147929 +22 332 0.065746 +24 332 0.065746 +25 332 0.065746 +27 332 0.591716 +28 332 0.147929 +31 332 0.147929 +32 332 0.147929 +33 332 0.147929 +37 332 0.147929 +38 332 0.147929 +40 332 0.591716 +50 332 0.591716 +53 332 0.065746 +54 332 0.147929 +55 332 0.065746 +56 332 0.147929 +57 332 0.147929 +62 332 0.147929 +64 332 0.065746 +65 332 0.591716 +72 332 0.591716 +78 332 0.065746 +80 332 0.147929 +81 332 0.147929 +82 332 0.147929 +84 332 0.147929 +85 332 0.147929 +87 332 0.065746 +88 332 0.147929 +89 332 0.147929 +91 332 0.147929 +92 332 0.147929 +93 332 0.591716 +94 332 0.147929 +95 332 0.147929 +96 332 0.147929 +97 332 0.591716 +98 332 0.147929 +99 332 0.147929 +100 332 0.147929 +101 332 0.147929 +105 332 0.065746 +106 332 0.147929 +107 332 0.147929 +108 332 0.591716 +109 332 0.147929 +110 332 0.147929 +111 332 0.147929 +112 332 0.147929 +113 332 0.147929 +114 332 0.147929 +116 332 0.147929 +117 332 0.147929 +118 332 0.591716 +119 332 0.147929 +121 332 0.147929 +122 332 0.591716 +123 332 0.591716 +124 332 0.147929 +125 332 0.147929 +126 332 0.147929 +130 332 0.147929 +131 332 0.065746 +132 332 0.147929 +133 332 0.147929 +136 332 0.147929 +137 332 0.147929 +138 332 0.147929 +139 332 0.591716 +140 332 0.065746 +141 332 0.147929 +142 332 0.065746 +143 332 0.591716 +144 332 0.147929 +145 332 0.591716 +146 332 0.147929 +148 332 0.147929 +149 332 0.591716 +150 332 0.147929 +151 332 0.591716 +152 332 0.065746 +153 332 0.591716 +158 332 0.147929 +160 332 0.591716 +161 332 0.065746 +162 332 0.147929 +163 332 0.591716 +164 332 0.147929 +165 332 0.147929 +166 332 0.147929 +167 332 0.065746 +168 332 0.147929 +169 332 0.147929 +170 332 0.065746 +171 332 0.591716 +172 332 0.065746 +173 332 0.147929 +174 332 0.147929 +175 332 0.147929 +176 332 0.147929 +177 332 0.591716 +178 332 0.065746 +180 332 0.147929 +181 332 0.065746 +183 332 0.147929 +184 332 0.147929 +185 332 0.591716 +186 332 0.065746 +187 332 0.065746 +188 332 0.147929 +189 332 0.065746 +190 332 0.065746 +191 332 0.147929 +192 332 0.591716 +193 332 0.147929 +194 332 0.147929 +195 332 0.591716 +197 332 0.591716 +199 332 0.147929 +200 332 0.065746 +201 332 0.147929 +202 332 0.065746 +203 332 0.147929 +205 332 0.591716 +206 332 0.147929 +207 332 0.147929 +208 332 0.591716 +210 332 0.147929 +211 332 0.147929 +212 332 0.147929 +213 332 0.147929 +214 332 0.591716 +215 332 0.147929 +216 332 0.147929 +218 332 0.591716 +219 332 0.591716 +220 332 0.591716 +221 332 0.147929 +223 332 0.591716 +224 332 0.147929 +229 332 0.147929 +230 332 0.591716 +231 332 0.147929 +232 332 0.147929 +233 332 0.147929 +234 332 0.591716 +235 332 0.591716 +239 332 0.065746 +241 332 0.147929 +242 332 0.147929 +244 332 0.147929 +246 332 0.147929 +247 332 0.147929 +250 332 0.065746 +252 332 0.147929 +253 332 0.147929 +254 332 0.147929 +256 332 0.147929 +257 332 0.147929 +258 332 0.065746 +262 332 0.591716 +263 332 0.147929 +264 332 0.147929 +265 332 0.147929 +266 332 0.591716 +268 332 0.147929 +269 332 0.147929 +271 332 0.591716 +272 332 0.147929 +273 332 0.591716 +274 332 0.147929 +277 332 0.147929 +278 332 0.591716 +279 332 0.147929 +281 332 0.147929 +282 332 0.147929 +283 332 0.147929 +284 332 0.147929 +285 332 0.147929 +287 332 0.147929 +289 332 0.591716 +290 332 0.147929 +291 332 0.147929 +292 332 0.591716 +293 332 0.065746 +294 332 0.147929 +295 332 0.065746 +296 332 0.065746 +297 332 0.147929 +301 332 0.147929 +303 332 0.065746 +304 332 0.591716 +306 332 0.591716 +307 332 0.147929 +310 332 0.591716 +311 332 0.591716 +312 332 0.147929 +315 332 0.591716 +316 332 0.147929 +317 332 0.065746 +332 332 61.696995 +347 332 -99.824847 +354 332 -140.964905 +359 332 -9.393991 +372 332 -18.342383 +373 332 -94.823125 +378 332 -8.560557 +379 332 -193.797057 +380 332 -19.120333 +384 332 -10.275957 +398 332 -66.426720 +399 332 -44.084333 +404 332 -113.404007 +405 332 -143.454449 +406 332 -23.207795 +409 332 -10.121617 +424 332 -107.492203 +425 332 -0.390681 +429 332 -59.915431 +430 332 -470.914364 +431 332 -41.347828 +434 332 -9.983298 +449 332 -14.788659 +450 332 -100.771053 +454 332 -125.027340 +455 332 -727.324369 +456 332 -108.841232 +459 332 -9.860529 +472 332 -38.640342 +475 332 -85.973280 +476 332 -50.471033 +478 332 -20.279488 +479 332 -114.742795 +480 332 -408.097099 +481 332 -397.583271 +482 332 -39.049628 +484 332 -1.039554 +485 332 -8.713328 +497 332 -10.339664 +498 332 -28.154017 +1 333 0.065746 +2 333 0.147929 +3 333 0.147929 +4 333 0.147929 +5 333 0.065746 +8 333 0.147929 +10 333 0.065746 +12 333 0.065746 +14 333 0.147929 +15 333 0.147929 +17 333 0.065746 +18 333 0.147929 +19 333 0.147929 +21 333 0.065746 +22 333 0.147929 +23 333 0.065746 +26 333 0.065746 +27 333 0.591716 +31 333 0.147929 +33 333 0.065746 +37 333 0.065746 +38 333 0.065746 +39 333 0.147929 +40 333 0.591716 +41 333 0.065746 +47 333 0.065746 +52 333 0.147929 +53 333 0.147929 +54 333 0.147929 +55 333 0.065746 +57 333 0.147929 +60 333 0.065746 +65 333 0.147929 +68 333 0.147929 +69 333 0.065746 +71 333 0.065746 +72 333 0.065746 +77 333 0.065746 +78 333 0.065746 +79 333 0.147929 +82 333 0.065746 +84 333 0.065746 +93 333 0.065746 +94 333 0.065746 +116 333 0.591716 +119 333 0.147929 +122 333 0.147929 +124 333 0.065746 +125 333 0.147929 +126 333 0.147929 +136 333 0.065746 +138 333 0.065746 +143 333 0.065746 +148 333 0.147929 +159 333 0.065746 +160 333 0.065746 +161 333 0.065746 +163 333 0.147929 +166 333 0.147929 +169 333 0.065746 +178 333 0.065746 +186 333 0.065746 +187 333 0.065746 +189 333 0.147929 +192 333 0.147929 +193 333 0.065746 +194 333 0.147929 +195 333 0.147929 +196 333 0.065746 +197 333 0.065746 +200 333 0.065746 +213 333 0.147929 +214 333 0.147929 +215 333 0.065746 +216 333 0.065746 +218 333 0.147929 +220 333 0.147929 +221 333 0.147929 +222 333 0.147929 +224 333 0.065746 +225 333 0.065746 +231 333 0.065746 +233 333 0.065746 +235 333 0.591716 +237 333 0.065746 +238 333 0.147929 +239 333 0.065746 +241 333 0.147929 +242 333 0.065746 +333 333 20.397077 +376 333 -28.573144 +377 333 -852.504148 +378 333 -7.663248 +400 333 -99.997629 +401 333 -188.377746 +402 333 -1682.197959 +403 333 -397.669035 +404 333 -27.560790 +405 333 -15.157385 +406 333 -6.023210 +423 333 -35.844346 +424 333 -150.654118 +425 333 -51.589203 +426 333 -272.078909 +427 333 -1267.545018 +428 333 -234.583078 +429 333 -321.659101 +430 333 -29.361490 +431 333 -6.356137 +447 333 -138.002807 +448 333 -113.997945 +450 333 -41.328419 +451 333 -459.357293 +452 333 -1012.827987 +453 333 -74.636003 +454 333 -243.426630 +455 333 -232.967444 +456 333 -39.382723 +472 333 -5.179271 +474 333 -6.857175 +475 333 -106.907854 +476 333 -514.959024 +477 333 -869.189705 +478 333 -76.616482 +479 333 -44.684602 +480 333 -299.107568 +481 333 -110.759048 +482 333 -3.391800 +499 333 -40.839623 +500 333 -105.409765 +5 334 0.147929 +8 334 0.591716 +12 334 0.591716 +13 334 0.147929 +16 334 0.147929 +20 334 0.065746 +22 334 0.147929 +23 334 0.591716 +25 334 0.065746 +32 334 0.147929 +38 334 0.147929 +50 334 0.147929 +60 334 0.591716 +62 334 0.147929 +63 334 0.147929 +64 334 0.065746 +65 334 0.147929 +72 334 0.591716 +75 334 0.591716 +76 334 0.591716 +81 334 0.147929 +93 334 0.147929 +94 334 0.147929 +99 334 0.147929 +100 334 0.065746 +105 334 0.147929 +106 334 0.147929 +109 334 0.065746 +114 334 0.065746 +117 334 0.591716 +119 334 0.591716 +121 334 0.147929 +124 334 0.591716 +129 334 0.065746 +132 334 0.147929 +138 334 0.147929 +140 334 0.065746 +143 334 0.147929 +147 334 0.147929 +148 334 0.147929 +149 334 0.147929 +150 334 0.147929 +151 334 0.147929 +153 334 0.147929 +159 334 0.591716 +163 334 0.591716 +166 334 0.065746 +169 334 0.147929 +193 334 0.147929 +204 334 0.147929 +206 334 0.065746 +210 334 0.147929 +215 334 0.591716 +220 334 0.147929 +221 334 0.147929 +232 334 0.065746 +235 334 0.147929 +274 334 0.147929 +277 334 0.065746 +278 334 0.147929 +279 334 0.147929 +281 334 0.065746 +284 334 0.065746 +285 334 0.591716 +287 334 0.147929 +289 334 0.591716 +292 334 0.147929 +293 334 0.147929 +294 334 0.147929 +295 334 0.147929 +297 334 0.591716 +302 334 0.065746 +304 334 0.065746 +305 334 0.065746 +310 334 0.147929 +311 334 0.065746 +312 334 0.065746 +313 334 0.065746 +314 334 0.147929 +315 334 0.147929 +334 334 30.003165 +347 334 -29.097068 +358 334 -17.248609 +359 334 -5.695328 +372 334 -30.152306 +379 334 -101.967913 +383 334 -26.174047 +397 334 -30.163829 +404 334 -112.061162 +407 334 -3.647385 +408 334 -23.296495 +422 334 -30.187076 +428 334 -13.563478 +429 334 -100.517382 +432 334 -27.770766 +447 334 -30.221986 +453 334 -116.226597 +457 334 -28.656662 +472 334 -30.268471 +478 334 -118.497482 +481 334 -29.050937 +482 334 -0.552347 +497 334 -30.326409 +2 335 0.147929 +4 335 0.147929 +12 335 0.147929 +16 335 0.591716 +23 335 0.147929 +26 335 0.147929 +30 335 0.065746 +31 335 0.065746 +40 335 0.147929 +44 335 0.147929 +50 335 0.147929 +52 335 0.147929 +59 335 0.147929 +60 335 0.065746 +62 335 0.147929 +63 335 0.065746 +64 335 0.065746 +79 335 0.147929 +81 335 0.147929 +82 335 0.591716 +84 335 0.591716 +85 335 0.147929 +87 335 0.147929 +90 335 0.147929 +92 335 0.147929 +94 335 0.065746 +95 335 0.065746 +96 335 0.065746 +98 335 0.147929 +99 335 0.147929 +100 335 0.147929 +101 335 0.147929 +103 335 0.065746 +105 335 0.147929 +110 335 0.065746 +112 335 0.065746 +115 335 0.147929 +116 335 0.591716 +117 335 0.147929 +118 335 0.147929 +122 335 0.147929 +124 335 0.147929 +126 335 0.147929 +127 335 0.147929 +131 335 0.147929 +132 335 0.147929 +134 335 0.065746 +135 335 0.591716 +136 335 0.065746 +137 335 0.065746 +139 335 0.065746 +140 335 0.065746 +143 335 0.147929 +145 335 0.065746 +147 335 0.591716 +148 335 0.147929 +149 335 0.147929 +150 335 0.147929 +151 335 0.147929 +152 335 0.147929 +153 335 0.147929 +154 335 0.065746 +155 335 0.147929 +156 335 0.147929 +159 335 0.147929 +161 335 0.147929 +162 335 0.065746 +163 335 0.065746 +165 335 0.065746 +167 335 0.065746 +168 335 0.065746 +169 335 0.065746 +170 335 0.065746 +171 335 0.065746 +173 335 0.147929 +175 335 0.147929 +178 335 0.591716 +179 335 0.147929 +180 335 0.065746 +184 335 0.147929 +186 335 0.065746 +188 335 0.591716 +189 335 0.065746 +192 335 0.591716 +193 335 0.147929 +194 335 0.147929 +196 335 0.147929 +197 335 0.591716 +198 335 0.065746 +199 335 0.591716 +201 335 0.065746 +202 335 0.065746 +203 335 0.147929 +205 335 0.591716 +207 335 0.147929 +208 335 0.591716 +209 335 0.147929 +211 335 0.065746 +212 335 0.591716 +213 335 0.147929 +214 335 0.147929 +215 335 0.147929 +216 335 0.147929 +228 335 0.591716 +234 335 0.591716 +238 335 0.147929 +239 335 0.065746 +240 335 0.147929 +241 335 0.147929 +242 335 0.065746 +244 335 0.147929 +246 335 0.147929 +247 335 0.065746 +248 335 0.065746 +252 335 0.065746 +254 335 0.591716 +264 335 0.147929 +265 335 0.147929 +267 335 0.065746 +268 335 0.065746 +269 335 0.065746 +273 335 0.147929 +274 335 0.147929 +275 335 0.147929 +282 335 0.591716 +283 335 0.065746 +284 335 0.147929 +292 335 0.147929 +295 335 0.065746 +297 335 0.147929 +305 335 0.147929 +308 335 0.147929 +309 335 0.147929 +311 335 0.147929 +312 335 0.147929 +313 335 0.065746 +335 335 38.609110 +347 335 -54.332416 +353 335 -15.618088 +354 335 -46.976406 +359 335 -8.982542 +372 335 -60.220158 +378 335 -37.055956 +379 335 -156.547212 +383 335 -5.067916 +384 335 -4.956515 +397 335 -17.697790 +398 335 -41.895102 +403 335 -52.894421 +404 335 -191.152002 +406 335 -25.676682 +408 335 -10.083503 +423 335 -58.986849 +428 335 -33.547728 +429 335 -221.256331 +430 335 -65.575535 +431 335 -47.169648 +433 335 -10.156110 +448 335 -58.404000 +450 335 -3.858493 +453 335 -10.301726 +454 335 -265.122661 +455 335 -154.815158 +456 335 -24.822192 +458 335 -10.242463 +472 335 -126.871093 +473 335 -42.422751 +474 335 -15.423345 +475 335 -41.562377 +479 335 -289.136344 +480 335 -157.584660 +481 335 -39.757753 +483 335 -10.342808 +497 335 -128.101067 +499 335 -57.314684 +500 335 -89.103866 +2 336 0.065746 +4 336 0.065746 +5 336 0.591716 +7 336 0.065746 +12 336 0.147929 +17 336 0.147929 +18 336 0.065746 +20 336 0.065746 +24 336 0.147929 +27 336 0.591716 +30 336 0.147929 +31 336 0.147929 +36 336 0.147929 +41 336 0.147929 +45 336 0.147929 +47 336 0.065746 +50 336 0.147929 +55 336 0.147929 +56 336 0.065746 +62 336 0.147929 +64 336 0.147929 +69 336 0.147929 +70 336 0.147929 +71 336 0.065746 +82 336 0.147929 +85 336 0.147929 +90 336 0.147929 +92 336 0.147929 +95 336 0.147929 +96 336 0.147929 +101 336 0.147929 +103 336 0.147929 +104 336 0.147929 +107 336 0.147929 +110 336 0.147929 +115 336 0.147929 +116 336 0.147929 +127 336 0.065746 +133 336 0.065746 +135 336 0.065746 +136 336 0.065746 +137 336 0.065746 +142 336 0.147929 +143 336 0.065746 +145 336 0.065746 +154 336 0.065746 +155 336 0.147929 +156 336 0.147929 +157 336 0.147929 +158 336 0.147929 +161 336 0.147929 +162 336 0.147929 +167 336 0.065746 +168 336 0.147929 +170 336 0.065746 +171 336 0.147929 +172 336 0.147929 +173 336 0.147929 +174 336 0.065746 +175 336 0.147929 +178 336 0.591716 +179 336 0.147929 +180 336 0.147929 +181 336 0.065746 +182 336 0.065746 +186 336 0.065746 +188 336 0.065746 +191 336 0.147929 +192 336 0.147929 +194 336 0.147929 +196 336 0.147929 +199 336 0.147929 +201 336 0.147929 +202 336 0.147929 +203 336 0.147929 +206 336 0.147929 +207 336 0.147929 +208 336 0.591716 +212 336 0.065746 +213 336 0.065746 +214 336 0.065746 +242 336 0.147929 +246 336 0.147929 +248 336 0.147929 +252 336 0.065746 +254 336 0.591716 +264 336 0.147929 +268 336 0.147929 +269 336 0.147929 +274 336 0.065746 +277 336 0.147929 +279 336 0.065746 +283 336 0.147929 +304 336 0.147929 +305 336 0.147929 +308 336 0.147929 +309 336 0.147929 +310 336 0.147929 +311 336 0.591716 +313 336 0.591716 +336 336 28.878374 +347 336 -63.390320 +354 336 -82.557170 +372 336 -75.026054 +378 336 -10.807747 +379 336 -107.199898 +380 336 -23.511504 +381 336 -8.313473 +397 336 -74.596888 +403 336 -56.038495 +404 336 -98.645507 +405 336 -49.155833 +406 336 -13.095442 +422 336 -74.196535 +428 336 -81.726737 +429 336 -94.728942 +430 336 -172.247831 +431 336 -14.688851 +447 336 -29.264925 +448 336 -44.561143 +450 336 -8.506959 +453 336 -123.066650 +454 336 -65.590512 +455 336 -290.960195 +456 336 -25.226461 +472 336 -30.186014 +473 336 -73.486438 +475 336 -56.479740 +478 336 -138.117946 +479 336 -154.385997 +480 336 -220.080473 +481 336 -35.321062 +497 336 -30.642240 +498 336 -73.178479 +500 336 -114.073893 +1 337 0.147929 +3 337 0.591716 +5 337 0.147929 +6 337 0.147929 +7 337 0.147929 +8 337 0.591716 +9 337 0.065746 +10 337 0.147929 +11 337 0.147929 +12 337 0.147929 +14 337 0.591716 +15 337 0.591716 +16 337 0.065746 +17 337 0.591716 +18 337 0.147929 +19 337 0.065746 +21 337 0.591716 +28 337 0.065746 +30 337 0.147929 +31 337 0.147929 +34 337 0.147929 +35 337 0.065746 +36 337 0.591716 +37 337 0.591716 +38 337 0.065746 +39 337 0.147929 +41 337 0.591716 +42 337 0.591716 +43 337 0.591716 +44 337 0.147929 +45 337 0.147929 +46 337 0.147929 +47 337 0.591716 +48 337 0.065746 +49 337 0.147929 +50 337 0.147929 +52 337 0.147929 +53 337 0.591716 +56 337 0.147929 +57 337 0.591716 +59 337 0.147929 +60 337 0.147929 +61 337 0.147929 +62 337 0.065746 +63 337 0.591716 +64 337 0.065746 +65 337 0.591716 +71 337 0.065746 +72 337 0.147929 +73 337 0.147929 +75 337 0.591716 +77 337 0.147929 +78 337 0.147929 +79 337 0.147929 +80 337 0.065746 +81 337 0.147929 +82 337 0.591716 +83 337 0.147929 +84 337 0.065746 +85 337 0.147929 +86 337 0.591716 +87 337 0.147929 +88 337 0.065746 +89 337 0.147929 +90 337 0.147929 +92 337 0.147929 +93 337 0.591716 +94 337 0.147929 +96 337 0.147929 +97 337 0.065746 +99 337 0.065746 +100 337 0.147929 +101 337 0.065746 +102 337 0.147929 +103 337 0.065746 +106 337 0.147929 +107 337 0.147929 +108 337 0.147929 +109 337 0.147929 +110 337 0.065746 +111 337 0.591716 +112 337 0.147929 +113 337 0.147929 +114 337 0.591716 +115 337 0.147929 +132 337 0.591716 +133 337 0.147929 +148 337 0.147929 +149 337 0.147929 +150 337 0.147929 +151 337 0.147929 +152 337 0.147929 +154 337 0.147929 +155 337 0.147929 +156 337 0.065746 +160 337 0.147929 +162 337 0.147929 +163 337 0.147929 +164 337 0.147929 +165 337 0.591716 +166 337 0.147929 +167 337 0.147929 +168 337 0.147929 +169 337 0.147929 +170 337 0.147929 +171 337 0.065746 +173 337 0.147929 +174 337 0.065746 +177 337 0.147929 +179 337 0.591716 +180 337 0.065746 +181 337 0.147929 +182 337 0.065746 +183 337 0.147929 +184 337 0.591716 +185 337 0.591716 +186 337 0.147929 +187 337 0.065746 +188 337 0.147929 +189 337 0.147929 +190 337 0.147929 +192 337 0.591716 +193 337 0.147929 +194 337 0.147929 +195 337 0.591716 +197 337 0.591716 +201 337 0.065746 +202 337 0.591716 +203 337 0.147929 +204 337 0.147929 +206 337 0.065746 +210 337 0.147929 +211 337 0.065746 +212 337 0.065746 +216 337 0.147929 +219 337 0.591716 +220 337 0.147929 +221 337 0.591716 +222 337 0.591716 +223 337 0.065746 +224 337 0.591716 +225 337 0.065746 +227 337 0.591716 +228 337 0.147929 +229 337 0.591716 +230 337 0.591716 +231 337 0.147929 +232 337 0.591716 +233 337 0.147929 +234 337 0.591716 +235 337 0.591716 +236 337 0.591716 +237 337 0.065746 +238 337 0.147929 +240 337 0.147929 +241 337 0.065746 +242 337 0.065746 +247 337 0.147929 +248 337 0.147929 +251 337 0.065746 +252 337 0.147929 +253 337 0.065746 +256 337 0.065746 +257 337 0.591716 +258 337 0.147929 +259 337 0.065746 +261 337 0.147929 +263 337 0.147929 +264 337 0.065746 +265 337 0.591716 +266 337 0.591716 +267 337 0.147929 +268 337 0.147929 +269 337 0.147929 +271 337 0.591716 +272 337 0.147929 +273 337 0.147929 +274 337 0.147929 +275 337 0.065746 +278 337 0.591716 +279 337 0.147929 +280 337 0.147929 +281 337 0.147929 +282 337 0.147929 +283 337 0.591716 +284 337 0.147929 +285 337 0.591716 +287 337 0.147929 +290 337 0.591716 +291 337 0.591716 +292 337 0.591716 +293 337 0.147929 +294 337 0.065746 +295 337 0.147929 +296 337 0.147929 +297 337 0.147929 +298 337 0.591716 +300 337 0.147929 +301 337 0.065746 +304 337 0.065746 +306 337 0.147929 +307 337 0.147929 +308 337 0.147929 +309 337 0.147929 +310 337 0.147929 +311 337 0.591716 +312 337 0.065746 +313 337 0.591716 +314 337 0.147929 +315 337 0.591716 +316 337 0.591716 +318 337 0.591716 +337 337 68.576471 +347 337 -89.114206 +348 337 -49.377687 +354 337 -46.849063 +355 337 -15.580589 +359 337 -21.860640 +369 337 -4.956959 +373 337 -70.231378 +374 337 -83.746947 +378 337 -5.875789 +379 337 -61.531343 +380 337 -89.523300 +381 337 -138.860731 +384 337 -23.791469 +394 337 -10.743282 +395 337 -16.581383 +396 337 -1.989292 +399 337 -36.891196 +400 337 -108.691885 +401 337 -1.339059 +402 337 -22.554280 +404 337 -54.167484 +405 337 -114.185971 +406 337 -210.698444 +407 337 -10.844830 +409 337 -23.309325 +421 337 -14.656930 +422 337 -13.320179 +425 337 -13.140798 +426 337 -119.022391 +427 337 -134.022735 +428 337 -42.694200 +429 337 -20.400115 +430 337 -188.260984 +431 337 -185.169929 +432 337 -159.623180 +434 337 -12.769462 +435 337 -10.099687 +447 337 -3.400729 +448 337 -16.806779 +449 337 -6.353532 +450 337 -4.286250 +451 337 -5.420455 +452 337 -117.084333 +453 337 -180.153692 +454 337 -83.441214 +455 337 -165.997937 +456 337 -231.126967 +457 337 -265.519907 +460 337 -22.469339 +474 337 -10.551945 +475 337 -51.190082 +476 337 -31.886100 +477 337 -6.970607 +478 337 -139.647438 +479 337 -215.789430 +480 337 -64.379932 +481 337 -277.985590 +482 337 -251.474006 +483 337 -138.728255 +485 337 -22.108403 +500 337 -42.410931 +1 338 0.065746 +3 338 0.147929 +4 338 0.147929 +5 338 0.591716 +6 338 0.147929 +7 338 0.147929 +8 338 0.591716 +9 338 0.065746 +10 338 0.147929 +17 338 0.147929 +18 338 0.147929 +19 338 0.065746 +20 338 0.065746 +21 338 0.591716 +22 338 0.591716 +25 338 0.591716 +31 338 0.147929 +34 338 0.147929 +40 338 0.591716 +45 338 0.147929 +46 338 0.065746 +53 338 0.147929 +54 338 0.591716 +55 338 0.591716 +57 338 0.591716 +58 338 0.147929 +59 338 0.147929 +60 338 0.147929 +61 338 0.147929 +63 338 0.591716 +64 338 0.147929 +65 338 0.147929 +70 338 0.065746 +71 338 0.147929 +72 338 0.147929 +73 338 0.147929 +75 338 0.147929 +77 338 0.147929 +79 338 0.147929 +80 338 0.065746 +81 338 0.147929 +82 338 0.591716 +83 338 0.065746 +84 338 0.065746 +85 338 0.147929 +87 338 0.147929 +88 338 0.147929 +89 338 0.591716 +93 338 0.591716 +94 338 0.147929 +95 338 0.147929 +96 338 0.147929 +97 338 0.147929 +99 338 0.147929 +100 338 0.147929 +101 338 0.147929 +105 338 0.065746 +106 338 0.147929 +107 338 0.147929 +108 338 0.065746 +109 338 0.147929 +110 338 0.147929 +111 338 0.591716 +112 338 0.147929 +113 338 0.147929 +114 338 0.591716 +115 338 0.147929 +117 338 0.147929 +118 338 0.147929 +119 338 0.147929 +121 338 0.591716 +122 338 0.591716 +123 338 0.147929 +125 338 0.065746 +127 338 0.147929 +128 338 0.147929 +129 338 0.147929 +131 338 0.147929 +132 338 0.591716 +133 338 0.147929 +134 338 0.147929 +136 338 0.147929 +137 338 0.147929 +138 338 0.147929 +139 338 0.147929 +146 338 0.147929 +148 338 0.147929 +149 338 0.147929 +150 338 0.147929 +151 338 0.065746 +152 338 0.147929 +153 338 0.147929 +154 338 0.147929 +155 338 0.147929 +156 338 0.147929 +158 338 0.591716 +159 338 0.591716 +160 338 0.147929 +161 338 0.147929 +162 338 0.065746 +163 338 0.147929 +164 338 0.147929 +165 338 0.147929 +166 338 0.147929 +167 338 0.065746 +170 338 0.065746 +171 338 0.147929 +173 338 0.147929 +174 338 0.147929 +175 338 0.065746 +176 338 0.065746 +179 338 0.591716 +180 338 0.065746 +181 338 0.591716 +182 338 0.065746 +183 338 0.591716 +184 338 0.591716 +185 338 0.591716 +186 338 0.591716 +187 338 0.065746 +188 338 0.147929 +189 338 0.147929 +190 338 0.065746 +193 338 0.147929 +194 338 0.065746 +195 338 0.591716 +198 338 0.065746 +201 338 0.147929 +202 338 0.147929 +203 338 0.147929 +204 338 0.147929 +206 338 0.147929 +216 338 0.591716 +219 338 0.591716 +220 338 0.147929 +221 338 0.591716 +222 338 0.591716 +223 338 0.065746 +224 338 0.591716 +229 338 0.591716 +230 338 0.591716 +231 338 0.147929 +232 338 0.591716 +233 338 0.147929 +234 338 0.591716 +235 338 0.591716 +236 338 0.591716 +238 338 0.147929 +244 338 0.065746 +248 338 0.147929 +249 338 0.147929 +251 338 0.065746 +252 338 0.591716 +253 338 0.065746 +256 338 0.147929 +257 338 0.591716 +258 338 0.147929 +259 338 0.065746 +261 338 0.591716 +263 338 0.147929 +264 338 0.065746 +265 338 0.591716 +266 338 0.591716 +267 338 0.147929 +268 338 0.065746 +269 338 0.065746 +270 338 0.065746 +271 338 0.147929 +272 338 0.591716 +273 338 0.147929 +275 338 0.147929 +280 338 0.147929 +281 338 0.147929 +282 338 0.591716 +283 338 0.591716 +284 338 0.147929 +285 338 0.591716 +287 338 0.147929 +290 338 0.591716 +293 338 0.591716 +294 338 0.147929 +295 338 0.065746 +296 338 0.147929 +297 338 0.065746 +300 338 0.147929 +301 338 0.147929 +316 338 0.591716 +318 338 0.591716 +338 338 62.592662 +347 338 -46.165647 +348 338 -3.247400 +353 338 -3.234992 +354 338 -58.079799 +355 338 -13.932613 +359 338 -9.222662 +369 338 -4.096707 +372 338 -0.479126 +373 338 -55.252110 +374 338 -3.442977 +376 338 -10.228367 +378 338 -7.208931 +379 338 -88.959055 +380 338 -42.189429 +381 338 -20.645491 +384 338 -10.123259 +394 338 -12.730287 +395 338 -11.640237 +398 338 -0.234909 +399 338 -55.184571 +400 338 -1.714872 +401 338 -26.649573 +402 338 -10.436519 +404 338 -65.598997 +405 338 -97.501342 +406 338 -43.683182 +409 338 -10.007197 +420 338 -6.171684 +421 338 -17.368378 +424 338 -0.969600 +425 338 -54.136506 +427 338 -35.861230 +429 338 -42.544957 +430 338 -272.287855 +431 338 -100.270217 +432 338 -5.528328 +434 338 -9.905873 +446 338 -0.561882 +447 338 -18.067783 +448 338 -4.035154 +450 338 -15.761673 +451 338 -49.810300 +452 338 -4.162548 +453 338 -44.697953 +454 338 -63.636283 +455 338 -402.197118 +456 338 -252.701850 +457 338 -30.771190 +459 338 -9.818955 +473 338 -14.192381 +474 338 -7.572003 +476 338 -54.002645 +477 338 -37.669812 +478 338 -50.030818 +479 338 -73.632099 +480 338 -131.759800 +481 338 -505.541249 +482 338 -84.259622 +484 338 -9.746152 +499 338 -10.841358 +500 338 -10.014547 +5 339 0.147929 +8 339 0.147929 +20 339 0.147929 +25 339 0.065746 +27 339 0.591716 +28 339 0.065746 +31 339 0.147929 +36 339 0.147929 +37 339 0.147929 +40 339 0.147929 +43 339 0.591716 +44 339 0.591716 +45 339 0.147929 +46 339 0.065746 +50 339 0.147929 +52 339 0.065746 +53 339 0.147929 +54 339 0.147929 +57 339 0.147929 +58 339 0.147929 +59 339 0.147929 +60 339 0.147929 +61 339 0.147929 +62 339 0.065746 +64 339 0.147929 +65 339 0.147929 +66 339 0.591716 +67 339 0.147929 +69 339 0.147929 +70 339 0.147929 +71 339 0.065746 +73 339 0.147929 +75 339 0.147929 +77 339 0.147929 +78 339 0.591716 +79 339 0.147929 +80 339 0.147929 +81 339 0.065746 +82 339 0.591716 +83 339 0.065746 +84 339 0.065746 +85 339 0.147929 +86 339 0.147929 +87 339 0.147929 +89 339 0.147929 +90 339 0.147929 +92 339 0.065746 +93 339 0.591716 +94 339 0.147929 +100 339 0.147929 +101 339 0.147929 +102 339 0.147929 +103 339 0.147929 +104 339 0.147929 +106 339 0.147929 +107 339 0.147929 +108 339 0.147929 +109 339 0.147929 +110 339 0.147929 +112 339 0.147929 +116 339 0.147929 +117 339 0.591716 +118 339 0.147929 +119 339 0.147929 +120 339 0.147929 +122 339 0.065746 +123 339 0.147929 +124 339 0.147929 +125 339 0.065746 +127 339 0.065746 +129 339 0.591716 +131 339 0.147929 +132 339 0.591716 +133 339 0.591716 +134 339 0.591716 +135 339 0.147929 +136 339 0.147929 +137 339 0.147929 +139 339 0.147929 +141 339 0.147929 +142 339 0.591716 +143 339 0.065746 +145 339 0.147929 +148 339 0.591716 +150 339 0.147929 +151 339 0.591716 +152 339 0.065746 +154 339 0.147929 +155 339 0.065746 +156 339 0.147929 +160 339 0.591716 +162 339 0.147929 +163 339 0.147929 +164 339 0.147929 +167 339 0.147929 +168 339 0.591716 +171 339 0.065746 +172 339 0.065746 +173 339 0.147929 +175 339 0.147929 +177 339 0.147929 +178 339 0.065746 +179 339 0.591716 +180 339 0.147929 +182 339 0.065746 +183 339 0.147929 +184 339 0.591716 +185 339 0.065746 +189 339 0.065746 +190 339 0.147929 +191 339 0.591716 +193 339 0.147929 +194 339 0.065746 +195 339 0.147929 +196 339 0.147929 +197 339 0.147929 +199 339 0.065746 +201 339 0.147929 +202 339 0.065746 +203 339 0.065746 +204 339 0.591716 +206 339 0.065746 +208 339 0.147929 +211 339 0.065746 +212 339 0.147929 +214 339 0.065746 +215 339 0.591716 +216 339 0.147929 +217 339 0.147929 +219 339 0.147929 +220 339 0.147929 +221 339 0.147929 +222 339 0.065746 +223 339 0.591716 +224 339 0.147929 +228 339 0.065746 +229 339 0.147929 +230 339 0.147929 +231 339 0.147929 +232 339 0.147929 +233 339 0.147929 +235 339 0.147929 +238 339 0.147929 +239 339 0.147929 +240 339 0.591716 +241 339 0.147929 +242 339 0.591716 +244 339 0.065746 +247 339 0.147929 +250 339 0.147929 +251 339 0.065746 +252 339 0.065746 +253 339 0.065746 +257 339 0.147929 +258 339 0.147929 +259 339 0.147929 +261 339 0.591716 +262 339 0.147929 +263 339 0.065746 +265 339 0.591716 +267 339 0.147929 +268 339 0.147929 +269 339 0.147929 +271 339 0.591716 +272 339 0.591716 +273 339 0.147929 +274 339 0.147929 +275 339 0.065746 +278 339 0.591716 +279 339 0.065746 +280 339 0.147929 +281 339 0.147929 +282 339 0.147929 +284 339 0.591716 +285 339 0.591716 +286 339 0.147929 +287 339 0.591716 +289 339 0.147929 +290 339 0.147929 +292 339 0.065746 +293 339 0.147929 +294 339 0.147929 +295 339 0.147929 +296 339 0.147929 +297 339 0.147929 +298 339 0.591716 +299 339 0.147929 +302 339 0.147929 +304 339 0.591716 +306 339 0.591716 +307 339 0.147929 +308 339 0.147929 +309 339 0.147929 +311 339 0.147929 +312 339 0.147929 +314 339 0.147929 +315 339 0.147929 +316 339 0.065746 +317 339 0.147929 +318 339 0.147929 +339 339 56.038038 +347 339 -86.472615 +348 339 -62.321285 +354 339 -86.346895 +358 339 -4.288843 +359 339 -16.162752 +369 339 -6.411341 +373 339 -53.599965 +374 339 -107.639207 +375 339 -3.469342 +376 339 -12.154092 +378 339 -3.033832 +379 339 -138.166457 +380 339 -21.788028 +381 339 -24.006102 +383 339 -22.923309 +394 339 -8.476864 +395 339 -15.699603 +396 339 -13.369414 +399 339 -9.087698 +400 339 -114.187779 +401 339 -52.405421 +402 339 -47.473568 +404 339 -66.771328 +405 339 -136.542207 +406 339 -37.795346 +408 339 -23.164157 +421 339 -2.362916 +422 339 -15.769807 +423 339 -15.812605 +424 339 -1.161796 +426 339 -85.761229 +427 339 -203.373853 +428 339 -74.030344 +429 339 -26.234936 +430 339 -366.707604 +431 339 -49.679436 +433 339 -23.437757 +449 339 -14.699619 +450 339 -24.742540 +451 339 -13.765386 +452 339 -57.854765 +453 339 -237.130774 +454 339 -138.641021 +455 339 -449.917671 +456 339 -125.800355 +458 339 -23.744883 +472 339 -32.726211 +473 339 -34.130715 +474 339 -34.178023 +475 339 -52.072917 +476 339 -73.503080 +477 339 -55.265050 +478 339 -139.700383 +479 339 -322.699625 +480 339 -158.888532 +481 339 -503.814240 +482 339 -4.476395 +483 339 -24.086375 +500 339 -51.331401 +51 340 0.147929 +90 340 0.147929 +93 340 0.147929 +94 340 0.147929 +99 340 0.147929 +100 340 0.591716 +101 340 0.147929 +124 340 0.147929 +125 340 0.065746 +160 340 0.147929 +163 340 0.147929 +164 340 0.147929 +166 340 0.147929 +167 340 0.591716 +168 340 0.591716 +169 340 0.147929 +172 340 0.065746 +173 340 0.591716 +175 340 0.591716 +177 340 0.065746 +178 340 0.065746 +179 340 0.065746 +180 340 0.147929 +181 340 0.147929 +182 340 0.591716 +183 340 0.147929 +184 340 0.147929 +185 340 0.147929 +186 340 0.591716 +188 340 0.065746 +189 340 0.147929 +190 340 0.147929 +191 340 0.065746 +193 340 0.147929 +194 340 0.147929 +196 340 0.147929 +197 340 0.065746 +201 340 0.065746 +202 340 0.591716 +204 340 0.591716 +206 340 0.147929 +214 340 0.065746 +215 340 0.147929 +216 340 0.147929 +217 340 0.065746 +222 340 0.065746 +228 340 0.147929 +229 340 0.147929 +230 340 0.147929 +231 340 0.065746 +234 340 0.065746 +235 340 0.065746 +240 340 0.591716 +241 340 0.147929 +242 340 0.065746 +244 340 0.065746 +250 340 0.065746 +251 340 0.065746 +252 340 0.065746 +253 340 0.147929 +257 340 0.065746 +258 340 0.065746 +262 340 0.065746 +263 340 0.065746 +264 340 0.147929 +265 340 0.591716 +267 340 0.147929 +268 340 0.065746 +269 340 0.065746 +271 340 0.147929 +273 340 0.065746 +274 340 0.147929 +275 340 0.147929 +278 340 0.147929 +284 340 0.147929 +285 340 0.147929 +299 340 0.065746 +300 340 0.065746 +302 340 0.065746 +304 340 0.065746 +305 340 0.065746 +308 340 0.147929 +310 340 0.591716 +311 340 0.147929 +313 340 0.065746 +314 340 0.147929 +315 340 0.147929 +316 340 0.147929 +317 340 0.147929 +340 340 30.715046 +347 340 -49.264000 +348 340 -66.747692 +349 340 -21.304941 +369 340 -13.050554 +374 340 -45.629525 +375 340 -67.147255 +376 340 -29.907399 +394 340 -1.059671 +395 340 -14.858510 +396 340 -14.865119 +397 340 -14.872646 +398 340 -14.881191 +399 340 -12.413287 +401 340 -37.482483 +402 340 -67.667024 +403 340 -25.534143 +424 340 -2.477583 +425 340 -14.901820 +426 340 -14.914209 +427 340 -14.928234 +428 340 -56.771212 +429 340 -68.349342 +430 340 -8.376367 +450 340 -3.582514 +451 340 -14.622545 +452 340 -17.566707 +453 340 -48.288232 +454 340 -79.701300 +455 340 -618.413108 +456 340 -800.621098 +475 340 -42.332726 +476 340 -66.396207 +477 340 -63.480495 +478 340 -33.414415 +479 340 -468.448348 +480 340 -2430.188271 +481 340 -351.666614 +482 340 -25.108470 +23 341 0.591716 +24 341 0.065746 +27 341 0.147929 +29 341 0.065746 +30 341 0.147929 +35 341 0.147929 +36 341 0.065746 +37 341 0.591716 +38 341 0.147929 +39 341 0.065746 +40 341 0.591716 +41 341 0.147929 +42 341 0.591716 +43 341 0.591716 +44 341 0.591716 +45 341 0.147929 +46 341 0.065746 +48 341 0.147929 +51 341 0.147929 +52 341 0.147929 +53 341 0.147929 +54 341 0.591716 +56 341 0.065746 +57 341 0.591716 +58 341 0.065746 +59 341 0.147929 +60 341 0.147929 +61 341 0.591716 +63 341 0.147929 +65 341 0.591716 +66 341 0.591716 +67 341 0.147929 +68 341 0.147929 +69 341 0.147929 +70 341 0.065746 +71 341 0.147929 +72 341 0.147929 +73 341 0.065746 +75 341 0.591716 +77 341 0.147929 +78 341 0.591716 +79 341 0.147929 +80 341 0.147929 +81 341 0.591716 +82 341 0.591716 +85 341 0.147929 +86 341 0.147929 +87 341 0.147929 +89 341 0.147929 +92 341 0.147929 +93 341 0.591716 +94 341 0.147929 +95 341 0.591716 +96 341 0.591716 +97 341 0.065746 +98 341 0.147929 +99 341 0.147929 +100 341 0.591716 +101 341 0.147929 +103 341 0.147929 +104 341 0.147929 +106 341 0.591716 +107 341 0.147929 +108 341 0.147929 +109 341 0.147929 +110 341 0.065746 +111 341 0.591716 +114 341 0.591716 +117 341 0.591716 +119 341 0.591716 +120 341 0.147929 +121 341 0.591716 +122 341 0.147929 +123 341 0.147929 +125 341 0.065746 +127 341 0.147929 +129 341 0.591716 +131 341 0.147929 +132 341 0.591716 +133 341 0.147929 +134 341 0.147929 +136 341 0.591716 +137 341 0.147929 +139 341 0.065746 +140 341 0.147929 +141 341 0.147929 +142 341 0.065746 +145 341 0.147929 +146 341 0.147929 +147 341 0.147929 +148 341 0.591716 +149 341 0.065746 +150 341 0.147929 +151 341 0.147929 +153 341 0.147929 +155 341 0.147929 +156 341 0.147929 +157 341 0.147929 +158 341 0.147929 +159 341 0.591716 +160 341 0.591716 +161 341 0.147929 +162 341 0.147929 +163 341 0.147929 +164 341 0.147929 +169 341 0.065746 +170 341 0.065746 +171 341 0.147929 +173 341 0.065746 +174 341 0.147929 +177 341 0.147929 +178 341 0.065746 +179 341 0.147929 +180 341 0.147929 +181 341 0.065746 +185 341 0.591716 +187 341 0.065746 +188 341 0.147929 +190 341 0.147929 +192 341 0.591716 +194 341 0.147929 +195 341 0.591716 +196 341 0.065746 +198 341 0.147929 +199 341 0.065746 +200 341 0.065746 +201 341 0.147929 +202 341 0.147929 +203 341 0.065746 +204 341 0.591716 +205 341 0.147929 +206 341 0.147929 +207 341 0.065746 +208 341 0.147929 +211 341 0.147929 +212 341 0.147929 +213 341 0.147929 +214 341 0.065746 +216 341 0.591716 +217 341 0.147929 +218 341 0.591716 +219 341 0.147929 +220 341 0.591716 +221 341 0.591716 +222 341 0.591716 +223 341 0.591716 +224 341 0.591716 +226 341 0.065746 +227 341 0.591716 +228 341 0.591716 +229 341 0.591716 +230 341 0.147929 +231 341 0.147929 +232 341 0.591716 +233 341 0.147929 +235 341 0.591716 +236 341 0.065746 +237 341 0.147929 +238 341 0.147929 +239 341 0.147929 +240 341 0.591716 +241 341 0.065746 +242 341 0.147929 +243 341 0.147929 +248 341 0.147929 +251 341 0.065746 +252 341 0.065746 +253 341 0.065746 +254 341 0.591716 +256 341 0.065746 +257 341 0.591716 +259 341 0.065746 +261 341 0.147929 +262 341 0.065746 +263 341 0.147929 +264 341 0.065746 +265 341 0.591716 +266 341 0.591716 +267 341 0.065746 +268 341 0.147929 +269 341 0.065746 +270 341 0.147929 +271 341 0.591716 +272 341 0.591716 +274 341 0.147929 +276 341 0.147929 +277 341 0.147929 +278 341 0.147929 +279 341 0.065746 +280 341 0.591716 +282 341 0.591716 +283 341 0.147929 +284 341 0.591716 +285 341 0.591716 +287 341 0.591716 +289 341 0.147929 +290 341 0.591716 +292 341 0.147929 +293 341 0.147929 +294 341 0.147929 +295 341 0.147929 +296 341 0.591716 +297 341 0.147929 +299 341 0.065746 +305 341 0.147929 +306 341 0.591716 +307 341 0.147929 +308 341 0.147929 +309 341 0.591716 +310 341 0.147929 +311 341 0.147929 +312 341 0.065746 +314 341 0.591716 +315 341 0.591716 +316 341 0.147929 +318 341 0.591716 +341 341 72.906674 +347 341 -99.888744 +354 341 -96.813638 +358 341 -6.352920 +359 341 -14.193372 +369 341 -2.814297 +372 341 -100.476834 +373 341 -13.384674 +376 341 -3.472612 +378 341 -4.644757 +379 341 -171.115923 +380 341 -10.385121 +383 341 -23.057229 +394 341 -16.910501 +397 341 -5.935796 +398 341 -106.381423 +401 341 -12.787142 +403 341 -11.730710 +404 341 -208.040270 +405 341 -23.926459 +406 341 -12.891954 +408 341 -23.329048 +419 341 -4.712528 +420 341 -11.942121 +423 341 -110.808805 +426 341 -12.676769 +428 341 -9.152054 +429 341 -232.081541 +430 341 -251.180612 +431 341 -58.794905 +433 341 -23.634489 +445 341 -14.447872 +446 341 -1.944893 +448 341 -50.591417 +449 341 -58.750704 +450 341 -8.826225 +451 341 -12.575392 +454 341 -256.704247 +455 341 -514.954415 +456 341 -87.041929 +458 341 -23.974411 +471 341 -16.126986 +474 341 -107.922332 +475 341 -40.445867 +476 341 -17.213149 +477 341 -2.851554 +478 341 -17.911424 +479 341 -256.818274 +480 341 -519.077160 +481 341 -125.975271 +483 341 -24.349731 +496 341 -9.167953 +497 341 -6.691360 +499 341 -106.553955 +500 341 -149.417225 +1 342 0.147929 +3 342 0.147929 +5 342 0.591716 +6 342 0.065746 +7 342 0.147929 +9 342 0.065746 +11 342 0.147929 +12 342 0.065746 +13 342 0.147929 +14 342 0.591716 +15 342 0.591716 +16 342 0.147929 +17 342 0.147929 +18 342 0.147929 +20 342 0.065746 +21 342 0.147929 +22 342 0.147929 +23 342 0.147929 +24 342 0.065746 +25 342 0.591716 +26 342 0.591716 +27 342 0.591716 +28 342 0.147929 +29 342 0.065746 +30 342 0.147929 +32 342 0.147929 +33 342 0.147929 +34 342 0.147929 +38 342 0.147929 +39 342 0.147929 +40 342 0.147929 +41 342 0.147929 +43 342 0.147929 +44 342 0.147929 +45 342 0.147929 +46 342 0.065746 +47 342 0.591716 +48 342 0.147929 +53 342 0.591716 +54 342 0.591716 +56 342 0.147929 +57 342 0.147929 +58 342 0.147929 +59 342 0.147929 +60 342 0.065746 +61 342 0.147929 +62 342 0.147929 +65 342 0.147929 +66 342 0.591716 +67 342 0.147929 +69 342 0.147929 +70 342 0.147929 +71 342 0.147929 +72 342 0.591716 +73 342 0.147929 +75 342 0.147929 +77 342 0.147929 +80 342 0.147929 +81 342 0.065746 +82 342 0.591716 +83 342 0.147929 +84 342 0.065746 +85 342 0.065746 +86 342 0.065746 +87 342 0.147929 +88 342 0.065746 +89 342 0.147929 +90 342 0.147929 +91 342 0.147929 +92 342 0.147929 +93 342 0.591716 +94 342 0.065746 +96 342 0.065746 +97 342 0.147929 +99 342 0.147929 +100 342 0.147929 +101 342 0.065746 +102 342 0.147929 +103 342 0.065746 +104 342 0.147929 +105 342 0.591716 +106 342 0.147929 +107 342 0.065746 +108 342 0.147929 +109 342 0.065746 +110 342 0.147929 +111 342 0.147929 +112 342 0.147929 +114 342 0.147929 +115 342 0.147929 +116 342 0.065746 +117 342 0.591716 +118 342 0.147929 +119 342 0.147929 +121 342 0.065746 +122 342 0.147929 +124 342 0.591716 +127 342 0.147929 +129 342 0.147929 +130 342 0.065746 +131 342 0.147929 +132 342 0.147929 +133 342 0.065746 +134 342 0.147929 +135 342 0.591716 +138 342 0.065746 +139 342 0.147929 +140 342 0.147929 +142 342 0.065746 +143 342 0.147929 +144 342 0.065746 +145 342 0.065746 +153 342 0.147929 +155 342 0.147929 +156 342 0.147929 +157 342 0.147929 +158 342 0.147929 +159 342 0.147929 +162 342 0.147929 +163 342 0.065746 +164 342 0.147929 +165 342 0.147929 +166 342 0.147929 +167 342 0.065746 +168 342 0.147929 +169 342 0.147929 +171 342 0.147929 +172 342 0.065746 +173 342 0.065746 +174 342 0.065746 +175 342 0.065746 +176 342 0.065746 +179 342 0.147929 +180 342 0.065746 +181 342 0.065746 +182 342 0.147929 +183 342 0.065746 +184 342 0.591716 +188 342 0.147929 +189 342 0.147929 +190 342 0.065746 +191 342 0.065746 +192 342 0.591716 +193 342 0.147929 +194 342 0.147929 +195 342 0.147929 +196 342 0.065746 +198 342 0.147929 +201 342 0.065746 +202 342 0.065746 +203 342 0.147929 +206 342 0.147929 +210 342 0.591716 +214 342 0.065746 +215 342 0.147929 +217 342 0.147929 +226 342 0.147929 +227 342 0.591716 +228 342 0.591716 +229 342 0.147929 +230 342 0.591716 +231 342 0.147929 +232 342 0.065746 +233 342 0.065746 +235 342 0.591716 +237 342 0.147929 +238 342 0.065746 +240 342 0.591716 +241 342 0.147929 +242 342 0.065746 +244 342 0.065746 +248 342 0.147929 +250 342 0.065746 +252 342 0.591716 +253 342 0.147929 +254 342 0.147929 +255 342 0.147929 +256 342 0.065746 +257 342 0.147929 +258 342 0.065746 +263 342 0.065746 +264 342 0.147929 +265 342 0.591716 +266 342 0.591716 +267 342 0.065746 +269 342 0.147929 +271 342 0.147929 +272 342 0.147929 +273 342 0.591716 +274 342 0.065746 +275 342 0.065746 +277 342 0.147929 +278 342 0.147929 +279 342 0.065746 +280 342 0.065746 +281 342 0.065746 +282 342 0.065746 +283 342 0.147929 +284 342 0.147929 +285 342 0.591716 +287 342 0.147929 +289 342 0.147929 +290 342 0.147929 +291 342 0.147929 +292 342 0.591716 +293 342 0.147929 +294 342 0.147929 +295 342 0.147929 +298 342 0.147929 +299 342 0.147929 +300 342 0.065746 +301 342 0.147929 +302 342 0.147929 +304 342 0.065746 +306 342 0.591716 +307 342 0.147929 +308 342 0.147929 +309 342 0.591716 +342 342 52.796441 +347 342 -40.225568 +348 342 -29.996415 +354 342 -126.483354 +355 342 -19.562132 +359 342 -28.559055 +373 342 -24.933285 +374 342 -52.973609 +375 342 -4.849538 +376 342 -14.065765 +378 342 -5.041277 +379 342 -27.379938 +380 342 -139.356901 +381 342 -49.530034 +384 342 -13.862639 +385 342 -16.327151 +399 342 -2.293795 +400 342 -50.806770 +401 342 -40.347476 +402 342 -41.544826 +404 342 -33.490178 +405 342 -51.710872 +406 342 -190.578003 +407 342 -37.804583 +410 342 -28.694098 +426 342 -30.977164 +427 342 -74.835546 +428 342 -61.000732 +429 342 -9.794640 +430 342 -211.278723 +431 342 -125.841508 +432 342 -209.284664 +433 342 -25.267013 +435 342 -2.993904 +436 342 -24.328443 +450 342 -4.167685 +451 342 -3.178658 +452 342 -13.840030 +453 342 -104.149386 +454 342 -127.096124 +455 342 -98.726624 +456 342 -346.688520 +457 342 -184.980368 +458 342 -171.281996 +459 342 -9.113673 +461 342 -26.065857 +472 342 -15.822139 +473 342 -12.191913 +475 342 -58.170901 +476 342 -32.803774 +477 342 -9.623444 +478 342 -15.196588 +479 342 -100.255529 +480 342 -129.940234 +481 342 -115.626794 +482 342 -368.665038 +483 342 -200.322340 +484 342 -115.757078 +486 342 -0.277585 +487 342 -24.638552 +498 342 -4.362402 +499 342 -16.639516 +500 342 -106.221698 +343 343 11111111.111111 +344 344 11111111.111111 +345 345 11111111.111111 +268 346 -21.644266 +269 346 -14.642524 +274 346 -82.400919 +325 346 -118.687710 +346 346 11127202.315343 +347 346 11878.900649 +370 346 3333.449292 +371 346 27579.890508 +395 346 31514.333089 +419 346 24247.541585 +420 346 7851.858409 +444 346 8975.935129 +268 347 -503.505592 +269 347 -394.775476 +270 347 -175.197476 +274 347 -606.579193 +319 347 -87.985741 +320 347 -107.006608 +321 347 -88.368077 +322 347 -76.853129 +323 347 -23.064047 +324 347 -60.365060 +325 347 -88.678847 +326 347 -89.670052 +327 347 -61.189850 +328 347 -134.079378 +329 347 -180.062264 +331 347 -24.959251 +332 347 -99.824847 +334 347 -29.097068 +335 347 -54.332416 +336 347 -63.390320 +337 347 -89.114206 +338 347 -46.165647 +339 347 -86.472615 +340 347 -49.264000 +341 347 -99.888744 +342 347 -40.225568 +346 347 11878.900649 +347 347 11427399.467594 +348 347 117104.074863 +349 347 77761.788996 +350 347 66559.878454 +351 347 38954.713460 +352 347 19652.336447 +353 347 19652.345106 +354 347 19652.354912 +355 347 19652.366041 +356 347 19652.378710 +357 347 19652.393185 +358 347 19652.409792 +359 347 19652.428941 +360 347 19652.451143 +361 347 19652.477052 +362 347 570.904889 +370 347 2397.246523 +371 347 21064.065670 +372 347 149002.060732 +373 347 107474.154164 +374 347 58906.636316 +375 347 22752.190201 +376 347 42035.743358 +377 347 50448.869110 +378 347 50504.101740 +379 347 41740.483433 +380 347 18114.265452 +395 347 23560.881455 +396 347 4540.925992 +397 347 60558.530147 +398 347 121005.486056 +399 347 48451.105254 +400 347 54061.910795 +401 347 18244.232994 +402 347 17898.327045 +403 347 10478.684429 +404 347 8826.532926 +405 347 32524.143935 +406 347 47113.851125 +407 347 21830.683226 +419 347 18087.458419 +420 347 5911.657567 +421 347 15110.119806 +422 347 32202.394729 +423 347 93259.499465 +424 347 55835.084854 +425 347 28162.718563 +426 347 46516.254022 +427 347 21627.513161 +428 347 7499.092666 +429 347 18068.894526 +430 347 6490.279687 +432 347 8986.446256 +433 347 30893.414601 +434 347 30982.081160 +435 347 5647.069526 +444 347 6710.991363 +446 347 15928.275120 +447 347 23400.066083 +448 347 71733.746145 +449 347 57515.987827 +450 347 29875.421598 +451 347 20722.682497 +452 347 37481.452239 +453 347 28490.525079 +454 347 503.710981 +455 347 11684.063815 +456 347 7297.349259 +457 347 2834.851844 +460 347 21008.275276 +471 347 15989.771164 +472 347 18368.214919 +473 347 37280.344493 +474 347 69783.788180 +475 347 41944.062672 +476 347 19283.328141 +477 347 12769.184731 +478 347 31403.941174 +479 347 30969.608703 +480 347 1055.251111 +482 347 3293.585090 +483 347 5582.183675 +496 347 16056.512879 +497 347 14995.050188 +498 347 18728.585602 +499 347 72487.522243 +500 347 40650.760407 +268 348 -104.139686 +269 348 -157.304509 +270 348 -62.620339 +274 348 -338.914351 +319 348 -114.894237 +321 348 -113.315899 +324 348 -5.215303 +328 348 -182.891903 +331 348 -34.971064 +337 348 -49.377687 +338 348 -3.247400 +339 348 -62.321285 +340 348 -66.747692 +342 348 -29.996415 +347 348 117104.074863 +348 348 11248296.382276 +349 348 103491.471901 +350 348 88290.554069 +351 348 51191.063334 +352 348 25200.537617 +353 348 25200.549217 +354 348 25200.562353 +355 348 25200.577261 +356 348 25200.594233 +357 348 25200.613624 +358 348 25200.635872 +359 348 25200.661524 +360 348 25200.691267 +361 348 25200.725975 +362 348 732.081667 +373 348 19567.493271 +374 348 46459.551050 +375 348 30435.494447 +376 348 56728.828000 +377 348 67659.793125 +378 348 67734.318448 +379 348 56067.823449 +380 348 23682.446231 +398 348 9.986832 +399 348 7148.354902 +400 348 35255.555222 +401 348 18410.115394 +402 348 24527.577271 +403 348 14498.835054 +404 348 11751.394811 +405 348 44233.098972 +406 348 63316.409415 +407 348 29916.863683 +424 348 92.525602 +425 348 3285.479965 +426 348 28979.499535 +427 348 16511.383217 +428 348 10137.557470 +429 348 24761.182140 +430 348 9034.146098 +432 348 12121.813595 +433 348 42142.923738 +434 348 42264.091542 +435 348 7730.544229 +450 348 420.515863 +451 348 1995.285247 +452 348 22203.953713 +453 348 21106.098017 +454 348 568.547623 +455 348 15871.462310 +456 348 10168.692399 +457 348 3971.985666 +460 348 28631.445191 +476 348 957.290519 +477 348 1181.828653 +478 348 18116.242567 +479 348 22475.224723 +480 348 1092.259172 +482 348 4614.728911 +483 348 7821.344733 +268 349 -52.241573 +269 349 -100.287895 +270 349 -62.638190 +274 349 -241.588712 +319 349 -114.952710 +321 349 -113.315931 +328 349 -183.033438 +331 349 -24.149350 +340 349 -21.304941 +347 349 77761.788996 +348 349 103491.471901 +349 349 11241103.050587 +350 349 88332.776550 +351 349 51207.224444 +352 349 25200.544749 +353 349 25200.556350 +354 349 25200.569486 +355 349 25200.584394 +356 349 25200.601366 +357 349 25200.620757 +358 349 25200.643005 +359 349 25200.668656 +360 349 25200.698400 +361 349 25200.733108 +362 349 732.081874 +374 349 4760.359961 +375 349 15315.476119 +376 349 49762.478516 +377 349 67705.275486 +378 349 67779.852927 +379 349 56104.587702 +380 349 23694.548750 +401 349 2773.085406 +402 349 10944.343367 +403 349 7940.581592 +404 349 11760.161038 +405 349 44266.657691 +406 349 63359.750696 +407 349 29940.142546 +428 349 3051.366693 +429 349 11046.476417 +430 349 5562.883849 +432 349 12131.069556 +433 349 42175.539407 +434 349 42296.801181 +435 349 7736.551992 +455 349 5546.794657 +456 349 6413.950660 +457 349 2742.863963 +460 349 28653.579408 +482 349 3186.711810 +483 349 5401.047843 +268 350 -48.024509 +269 350 -84.942951 +270 350 -57.934315 +274 350 -201.017777 +319 350 -115.018841 +321 350 -113.315968 +328 350 -163.584743 +347 350 66559.878454 +348 350 88290.554069 +349 350 88332.776550 +350 350 11354135.268571 +351 350 51225.509987 +352 350 25200.552803 +353 350 25200.564404 +354 350 25200.577539 +355 350 25200.592448 +356 350 25200.609420 +357 350 25200.628810 +358 350 25200.651058 +359 350 25200.676710 +360 350 25200.706453 +361 350 25200.741162 +362 350 732.082108 +375 350 2615.604406 +376 350 37209.109923 +377 350 63295.283241 +378 350 63364.689246 +379 350 54308.865461 +380 350 23708.236296 +404 350 9134.700837 +405 350 39825.229155 +406 350 58921.634467 +407 350 27419.072369 +432 350 10192.896218 +433 350 37706.103654 +434 350 37815.526449 +435 350 7046.006394 +460 350 25489.592643 +268 351 -38.975399 +269 351 -43.667779 +270 351 -39.657769 +274 351 -105.933614 +319 351 -74.499424 +321 351 -113.316008 +328 351 -40.419129 +347 351 38954.713460 +348 351 51191.063334 +349 351 51207.224444 +350 351 51225.509987 +351 351 11437235.463215 +352 351 25200.561893 +353 351 25200.573494 +354 351 25200.586629 +355 351 25200.601538 +356 351 25200.618510 +357 351 25200.637900 +358 351 25200.660148 +359 351 25200.685800 +360 351 25200.715543 +361 351 25200.750252 +362 351 732.082372 +376 351 10604.751148 +377 351 26069.053270 +378 351 26095.591972 +379 351 24534.005887 +380 351 15649.547123 +404 351 1591.738527 +405 351 10510.553182 +406 351 23143.389961 +407 351 7094.169324 +432 351 2204.534858 +433 351 9322.396291 +434 351 9349.939738 +435 351 1804.574674 +460 351 6240.351580 +209 352 -8.217393 +268 352 -14.621303 +269 352 -32.898420 +270 352 -32.898011 +274 352 -32.898321 +321 352 -113.316055 +325 352 -8.217393 +347 352 19652.336447 +348 352 25200.537617 +349 352 25200.544749 +350 352 25200.552803 +351 352 25200.561893 +352 352 11658045.411917 +353 352 26557.221809 +354 352 25200.596892 +355 352 25200.611801 +356 352 25200.628773 +357 352 25200.648164 +358 352 25200.670412 +359 352 25200.696063 +360 352 25200.725807 +361 352 25200.760515 +362 352 732.082670 +375 352 1524.549779 +376 352 1953.458242 +377 352 932.893214 +397 352 537.792215 +398 352 1938.340609 +399 352 1942.745941 +400 352 423.206580 +419 352 2.448309 +420 352 1928.100319 +421 352 1931.072010 +422 352 1396.676809 +444 352 1521.790943 +128 353 -44.010555 +145 353 -30.196345 +156 353 -62.655499 +157 353 -25.885883 +162 353 -30.173738 +209 353 -51.684967 +268 353 -14.621304 +269 353 -32.898445 +270 353 -32.898016 +274 353 -32.898342 +320 353 -21.975654 +321 353 -123.516496 +322 353 -75.191261 +324 353 -3.133489 +325 353 -10.854273 +327 353 -40.843715 +329 353 -63.555126 +335 353 -15.618088 +338 353 -3.234992 +347 353 19652.345106 +348 353 25200.549217 +349 353 25200.556350 +350 353 25200.564404 +351 353 25200.573494 +352 353 26557.221809 +353 353 11963360.796713 +354 353 37695.265974 +355 353 27469.587674 +356 353 27469.636037 +357 353 27469.691295 +358 353 27469.754697 +359 353 27469.827802 +360 353 27469.912571 +361 353 27470.011494 +362 353 798.005479 +375 353 2013.762634 +376 353 2580.303556 +377 353 1291.535397 +378 353 37953.917241 +379 353 5412.406570 +397 353 710.364387 +398 353 2560.334825 +399 353 2566.153784 +400 353 559.009360 +402 353 9234.452575 +403 353 29405.372808 +404 353 4566.650951 +405 353 754.712537 +419 353 3.233947 +420 353 2546.808528 +421 353 2550.733805 +422 353 1844.856502 +426 353 19.784231 +427 353 18879.066976 +428 353 20405.854690 +429 353 3973.475082 +430 353 1263.006350 +444 353 2010.118516 +451 353 10898.256345 +452 353 22853.299844 +453 353 4565.353583 +454 353 5115.963728 +455 353 1250.571547 +456 353 481.124745 +475 353 338.253261 +476 353 16881.981174 +477 353 20751.970622 +479 353 2772.600959 +480 353 3885.804227 +481 353 1199.288556 +500 353 15555.543489 +6 354 -4.130753 +128 354 -78.103469 +145 354 -497.489896 +156 354 -424.926759 +157 354 -256.317245 +162 354 -499.269171 +209 354 -32.904776 +268 354 -14.621305 +269 354 -32.898474 +270 354 -32.898022 +274 354 -32.898365 +320 354 -123.657317 +321 354 -265.642271 +322 354 -25.594544 +323 354 -96.474867 +324 354 -132.551223 +326 354 -62.992106 +327 354 -21.107407 +328 354 -63.678722 +329 354 -39.255263 +330 354 -11.100961 +331 354 -379.332322 +332 354 -140.964905 +335 354 -46.976406 +336 354 -82.557170 +337 354 -46.849063 +338 354 -58.079799 +339 354 -86.346895 +341 354 -96.813638 +342 354 -126.483354 +347 354 19652.354912 +348 354 25200.562353 +349 354 25200.569486 +350 354 25200.577539 +351 354 25200.586629 +352 354 25200.596892 +353 354 37695.265974 +354 354 12476183.256581 +355 354 75676.550935 +356 354 59078.639416 +357 354 59078.807342 +358 354 59079.000020 +359 354 59079.222186 +360 354 59079.479797 +361 354 59079.780426 +362 354 1716.272621 +378 354 15887.441874 +379 354 178636.592249 +380 354 146079.816534 +381 354 17809.527853 +382 354 8905.282472 +402 354 2281.648728 +403 354 24524.935298 +404 354 95624.016095 +405 354 91591.711010 +406 354 116671.995172 +407 354 6767.510149 +408 354 15578.273087 +409 354 1715.950065 +427 354 5236.439107 +428 354 31378.310891 +429 354 72004.479537 +430 354 80061.788024 +431 354 42998.679313 +432 354 90142.915432 +434 354 13991.273642 +435 354 7408.459581 +451 354 2862.077939 +452 354 11793.938602 +453 354 34965.607670 +454 354 36872.091864 +455 354 62490.778936 +456 354 46013.980206 +457 354 66449.554388 +458 354 52003.842914 +460 354 6184.904789 +476 354 5252.070456 +477 354 12484.558458 +478 354 32373.742738 +479 354 27269.498466 +480 354 37602.611544 +481 354 72043.828309 +482 354 9200.253287 +483 354 94896.253792 +484 354 13735.494826 +500 354 4446.405571 +6 355 -81.469571 +145 355 -34.015438 +156 355 -66.770476 +157 355 -63.984932 +162 355 -40.602761 +209 355 -32.905176 +251 355 -31.740294 +268 355 -14.621305 +269 355 -32.898507 +270 355 -32.898028 +274 355 -32.898392 +297 355 -12.521241 +321 355 -350.714688 +322 355 -3.543964 +324 355 -6.344363 +328 355 -59.989778 +329 355 -4.639244 +331 355 -3.018751 +337 355 -15.580589 +338 355 -13.932613 +342 355 -19.562132 +347 355 19652.366041 +348 355 25200.577261 +349 355 25200.584394 +350 355 25200.592448 +351 355 25200.601538 +352 355 25200.611801 +353 355 27469.587674 +354 355 75676.550935 +355 355 12081725.342889 +356 355 78032.861539 +357 355 78035.395178 +358 355 78038.303869 +359 355 78041.659840 +360 355 78045.554085 +361 355 78050.102519 +362 355 2267.431160 +369 355 6718.150442 +370 355 7072.049112 +371 355 7072.412392 +372 355 7072.825683 +373 355 7073.294150 +374 355 7073.823906 +375 355 7074.422200 +376 355 7075.097644 +377 355 7075.860507 +378 355 7076.723080 +379 355 8990.360479 +380 355 15910.002411 +381 355 16302.246946 +382 355 8386.230710 +403 355 242.376561 +404 355 1431.514639 +405 355 2085.557621 +406 355 9706.517988 +407 355 7334.730030 +408 355 14675.673350 +409 355 1614.937995 +428 355 1258.289480 +429 355 458.372393 +431 355 6426.624604 +432 355 5326.200328 +433 355 664.201606 +434 355 13182.200957 +435 355 6978.861722 +452 355 497.081580 +453 355 1264.499235 +456 355 3520.931116 +457 355 4146.468177 +458 355 4240.581099 +459 355 21.720069 +460 355 5826.882936 +476 355 47.260267 +477 355 1052.999924 +478 355 708.306629 +481 355 882.142167 +482 355 5128.882271 +483 355 2377.329526 +484 355 3081.776801 +6 356 -32.918233 +36 356 -17.195725 +145 356 -32.898931 +156 356 -32.898732 +157 356 -32.897909 +162 356 -32.898401 +209 356 -32.905631 +212 356 -16.986900 +251 356 -32.997430 +268 356 -14.621306 +269 356 -32.898545 +270 356 -32.898036 +274 356 -32.898422 +295 356 -9.210141 +297 356 -33.012000 +321 356 -410.926201 +325 356 -9.210141 +347 356 19652.378710 +348 356 25200.594233 +349 356 25200.601366 +350 356 25200.609420 +351 356 25200.618510 +352 356 25200.628773 +353 356 27469.636037 +354 356 59078.639416 +355 356 78032.861539 +356 356 11968630.144597 +357 356 93599.707529 +358 356 93612.033506 +359 356 91664.724589 +360 356 91503.576294 +361 356 91514.271040 +362 356 2658.667559 +369 356 6984.235896 +370 356 7352.151414 +371 356 7352.529082 +372 356 7352.958743 +373 356 7353.445764 +374 356 7353.996502 +375 356 7354.618493 +376 356 7355.320689 +377 356 7356.113767 +378 356 8179.681990 +379 356 13273.916642 +380 356 10773.918940 +381 356 5227.400794 +399 356 249.689656 +400 356 2096.943592 +401 356 2099.109613 +402 356 2101.563317 +403 356 1281.675691 +420 356 1005.350663 +421 356 2090.534380 +422 356 2091.847992 +423 356 2093.339697 +424 356 1845.340402 +444 356 1653.025137 +445 356 1084.030914 +6 357 -32.919603 +7 357 -41.208517 +36 357 -33.051273 +145 357 -32.899000 +156 357 -32.898787 +157 357 -32.897909 +162 357 -32.898435 +203 357 -2.526895 +209 357 -32.906151 +211 357 -14.252876 +212 357 -33.051556 +251 357 -33.004162 +268 357 -14.621307 +269 357 -32.898588 +270 357 -32.898045 +274 357 -32.898457 +295 357 -34.050566 +297 357 -33.019723 +321 357 -500.851283 +325 357 -34.050566 +347 357 19652.393185 +348 357 25200.613624 +349 357 25200.620757 +350 357 25200.628810 +351 357 25200.637900 +352 357 25200.648164 +353 357 27469.691295 +354 357 59078.807342 +355 357 78035.395178 +356 357 93599.707529 +357 357 12062935.854687 +358 357 119474.551233 +359 357 112264.277815 +360 357 111655.823481 +361 357 111680.563732 +362 357 3244.732257 +369 357 6985.660885 +370 357 7353.651468 +371 357 7354.029214 +372 357 7354.458962 +373 357 7354.946082 +374 357 7355.496933 +375 357 7356.119050 +376 357 7356.821390 +377 357 7357.614630 +378 357 10470.650968 +379 357 23529.964790 +380 357 23827.866755 +381 357 24792.936916 +382 357 8645.146788 +399 357 923.120910 +400 357 7752.553726 +401 357 7760.561662 +402 357 7769.633186 +403 357 4738.448706 +420 357 3716.854884 +421 357 7728.858398 +422 357 7733.714920 +423 357 7739.229862 +424 357 6822.358343 +444 357 6111.354752 +445 357 4007.741520 +6 358 -32.921175 +7 358 -132.578704 +36 358 -33.062455 +145 358 -32.899079 +156 358 -32.898851 +157 358 -32.897909 +162 358 -32.898473 +203 358 -14.737150 +209 358 -32.906748 +211 358 -33.133721 +212 358 -33.062759 +251 358 -33.011892 +268 358 -14.621308 +269 358 -32.898637 +270 358 -32.898055 +274 358 -32.898496 +295 358 -103.650835 +297 358 -33.028592 +321 358 -623.354003 +323 358 -11.070681 +325 358 -34.138765 +327 358 -7.979659 +329 358 -22.571358 +334 358 -17.248609 +339 358 -4.288843 +341 358 -6.352920 +347 358 19652.409792 +348 358 25200.635872 +349 358 25200.643005 +350 358 25200.651058 +351 358 25200.660148 +352 358 25200.670412 +353 358 27469.754697 +354 358 59079.000020 +355 358 78038.303869 +356 358 93612.033506 +357 358 119474.551233 +358 358 12240373.904509 +359 358 143131.304390 +360 358 139138.002398 +361 358 139184.578783 +362 358 4044.087580 +369 358 6987.296932 +370 358 7355.373699 +371 358 7355.751533 +372 358 7356.181381 +373 358 7356.668616 +374 358 7357.219596 +375 358 7357.841859 +376 358 7358.544363 +377 358 7359.337788 +378 358 10821.703515 +379 358 27743.020597 +380 358 30808.590109 +381 358 49972.861833 +382 358 27944.672270 +383 358 12104.626193 +399 358 925.512024 +400 358 7772.634784 +401 358 7780.663462 +402 358 7789.758483 +403 358 4750.722476 +407 358 5818.616827 +408 358 7212.907936 +420 358 3726.482469 +421 358 7748.878078 +422 358 7753.747180 +423 358 7759.276408 +424 358 6840.029962 +431 358 3310.558848 +432 358 6626.455055 +433 358 3525.424294 +444 358 6127.184692 +445 358 4018.122575 +455 358 1656.777939 +456 358 4184.964888 +457 358 4953.820588 +458 358 3129.535618 +479 358 464.604407 +480 358 5215.613465 +481 358 5027.877765 +482 358 1967.842261 +483 358 1744.043391 +6 359 -32.922987 +7 359 -132.656444 +36 359 -33.075362 +92 359 -3.232121 +145 359 -32.899170 +156 359 -32.898925 +157 359 -32.897909 +162 359 -32.898517 +203 359 -14.746281 +209 359 -32.907436 +211 359 -33.152283 +212 359 -33.075690 +251 359 -33.020811 +268 359 -14.621309 +269 359 -32.898694 +270 359 -32.898066 +274 359 -32.898542 +295 359 -151.194403 +297 359 -33.038826 +298 359 -13.309785 +320 359 -8.964040 +321 359 -640.049159 +323 359 -9.913490 +325 359 -2.735319 +326 359 -9.006622 +327 359 -2.394141 +329 359 -4.110451 +332 359 -9.393991 +334 359 -5.695328 +335 359 -8.982542 +337 359 -21.860640 +338 359 -9.222662 +339 359 -16.162752 +341 359 -14.193372 +342 359 -28.559055 +347 359 19652.428941 +348 359 25200.661524 +349 359 25200.668656 +350 359 25200.676710 +351 359 25200.685800 +352 359 25200.696063 +353 359 27469.827802 +354 359 59079.222186 +355 359 78041.659840 +356 359 91664.724589 +357 359 112264.277815 +358 359 143131.304390 +359 359 12249813.045111 +360 359 142942.246948 +361 359 142997.401534 +362 359 4154.993389 +369 359 6989.184714 +370 359 7357.360926 +371 359 7357.738862 +372 359 7358.168826 +373 359 7358.656193 +374 359 7359.207321 +375 359 7359.829752 +376 359 7360.532447 +377 359 7361.326086 +378 359 8018.917719 +379 359 20565.150616 +380 359 23620.970049 +381 359 47975.944417 +382 359 31280.724575 +383 359 12952.930053 +384 359 14881.042883 +385 359 3152.106861 +399 359 74.155307 +400 359 622.771077 +401 359 623.414363 +402 359 3236.164790 +403 359 3385.000438 +404 359 3006.812619 +405 359 3009.608538 +406 359 499.584747 +407 359 1176.884532 +408 359 8962.076920 +409 359 9002.971503 +410 359 5539.659993 +420 359 298.578997 +421 359 620.867605 +422 359 621.257735 +423 359 621.700756 +424 359 548.047469 +431 359 602.883083 +432 359 1867.007319 +433 359 7855.572978 +434 359 7406.235634 +435 359 2070.511559 +436 359 4696.830079 +444 359 490.931777 +445 359 321.946237 +455 359 301.714435 +456 359 812.438535 +457 359 1857.501144 +458 359 7557.988798 +459 359 5487.846034 +460 359 3320.472361 +461 359 5032.253778 +479 359 84.608717 +480 359 949.810975 +481 359 1610.679491 +482 359 1725.742180 +483 359 6381.051104 +484 359 4219.243102 +485 359 4512.117059 +486 359 53.590324 +487 359 4756.699400 +6 360 -32.925089 +7 360 -132.746754 +36 360 -33.090347 +46 360 -5.300417 +83 360 -63.067907 +85 360 -22.404288 +90 360 -11.928220 +92 360 -15.025366 +95 360 -53.421193 +96 360 -43.153435 +98 360 -59.137274 +103 360 -13.146001 +104 360 -6.148771 +107 360 -54.583739 +110 360 -56.583492 +112 360 -51.814392 +116 360 -24.915028 +118 360 -12.068987 +123 360 -56.740716 +134 360 -14.417279 +145 360 -32.899276 +146 360 -55.788466 +154 360 -6.769186 +155 360 -19.966522 +156 360 -32.899010 +157 360 -32.897909 +162 360 -32.898568 +174 360 -10.285883 +176 360 -11.200418 +201 360 -17.127859 +203 360 -14.756889 +209 360 -32.908234 +211 360 -33.173845 +212 360 -33.090703 +237 360 -8.218552 +251 360 -33.031161 +256 360 -2.371717 +268 360 -14.621311 +269 360 -32.898760 +270 360 -32.898079 +274 360 -32.898595 +297 360 -33.050704 +298 360 -33.690235 +308 360 -6.715741 +309 360 -6.799763 +321 360 -1366.476080 +347 360 19652.451143 +348 360 25200.691267 +349 360 25200.698400 +350 360 25200.706453 +351 360 25200.715543 +352 360 25200.725807 +353 360 27469.912571 +354 360 59079.479797 +355 360 78045.554085 +356 360 91503.576294 +357 360 111655.823481 +358 360 139138.002398 +359 360 142942.246948 +360 360 11928929.856330 +361 360 315299.251688 +362 360 9176.756817 +369 360 6991.375493 +370 360 7359.667110 +371 360 7360.045165 +372 360 7360.475264 +373 360 7360.962783 +374 360 7361.514085 +375 360 7362.136711 +376 360 7362.839626 +377 360 7363.633514 +378 360 7777.196961 +379 360 19948.565923 +380 360 23006.287222 +381 360 53224.852046 +382 360 39436.593979 +383 360 68839.038799 +384 360 169167.987863 +385 360 96842.106861 +402 360 6611.648934 +403 360 7604.739703 +404 360 8250.384471 +405 360 17263.387009 +406 360 95103.715824 +407 360 158752.389050 +408 360 104685.233779 +409 360 1291.257421 +426 360 3764.084744 +427 360 5680.307724 +428 360 18422.651105 +429 360 30677.673539 +430 360 112459.709568 +431 360 66057.273577 +432 360 2183.531676 +447 360 4915.728419 +448 360 5658.822455 +449 360 5663.239434 +450 360 6629.402220 +451 360 7865.137766 +452 360 7543.288658 +453 360 9105.743649 +454 360 5105.234449 +455 360 905.476599 +472 360 513.067955 +475 360 3820.519028 +476 360 3863.246938 +477 360 2292.565918 +2 361 -8.324114 +3 361 -4.407671 +5 361 -25.168329 +6 361 -32.927542 +7 361 -132.852373 +8 361 -14.474784 +9 361 -4.864458 +16 361 -15.128925 +17 361 -20.443097 +18 361 -20.622716 +19 361 -6.819240 +20 361 -10.640544 +21 361 -6.232026 +22 361 -14.792665 +23 361 -15.879580 +24 361 -6.527524 +25 361 -6.366946 +31 361 -16.148300 +32 361 -9.411513 +33 361 -4.013758 +34 361 -5.043728 +36 361 -33.107859 +37 361 -8.066180 +38 361 -19.731781 +39 361 -110.279685 +42 361 -14.519357 +43 361 -10.201485 +44 361 -15.770933 +46 361 -15.703519 +47 361 -79.634950 +51 361 -20.228518 +52 361 -20.145268 +53 361 -14.313914 +54 361 -14.320749 +55 361 -6.254351 +60 361 -7.266940 +66 361 -6.086518 +67 361 -6.105527 +68 361 -11.062230 +69 361 -28.104345 +70 361 -12.561094 +77 361 -6.713366 +79 361 -20.177721 +80 361 -10.485294 +81 361 -11.786325 +82 361 -105.589094 +83 361 -140.023035 +84 361 -16.328849 +85 361 -34.576637 +87 361 -7.267212 +89 361 -12.053246 +90 361 -35.332702 +91 361 -6.259095 +92 361 -15.063457 +95 361 -140.811938 +96 361 -141.776352 +97 361 -8.476947 +98 361 -140.331983 +100 361 -7.174775 +101 361 -13.992050 +102 361 -8.615201 +103 361 -35.221367 +104 361 -15.627409 +106 361 -10.916201 +107 361 -140.711236 +108 361 -10.850546 +109 361 -43.639901 +110 361 -140.541756 +112 361 -140.953826 +115 361 -11.815759 +116 361 -34.448139 +117 361 -6.962447 +118 361 -35.319439 +119 361 -37.739875 +120 361 -4.245638 +121 361 -5.814899 +122 361 -15.014271 +123 361 -140.528628 +124 361 -15.669176 +125 361 -6.637592 +126 361 -26.196649 +129 361 -12.831573 +131 361 -15.360405 +132 361 -62.511822 +134 361 -35.112921 +135 361 -49.321790 +136 361 -20.240205 +137 361 -33.455593 +138 361 -25.598859 +140 361 -27.442755 +141 361 -11.018799 +143 361 -4.872717 +145 361 -32.899399 +146 361 -140.608576 +148 361 -15.800475 +150 361 -15.687744 +152 361 -6.898881 +154 361 -35.901065 +155 361 -34.717550 +156 361 -32.899109 +157 361 -32.897909 +159 361 -15.669481 +160 361 -8.477152 +161 361 -30.411228 +162 361 -32.898627 +163 361 -15.473049 +164 361 -14.220324 +166 361 -6.615280 +167 361 -28.144177 +168 361 -27.945913 +169 361 -6.679475 +172 361 -7.438858 +173 361 -113.029461 +174 361 -35.495541 +175 361 -28.128883 +176 361 -35.402985 +179 361 -24.643333 +180 361 -28.334028 +182 361 -27.928142 +183 361 -6.875801 +185 361 -14.993966 +186 361 -19.855896 +187 361 -6.056819 +188 361 -12.113669 +190 361 -9.777062 +192 361 -19.648767 +193 361 -15.631605 +194 361 -25.952218 +195 361 -6.302385 +201 361 -34.905313 +202 361 -25.258473 +203 361 -14.769298 +204 361 -16.651092 +206 361 -9.534104 +209 361 -32.909165 +211 361 -33.199059 +212 361 -33.108248 +213 361 -24.257999 +214 361 -11.491066 +215 361 -15.673740 +217 361 -6.607830 +218 361 -6.591341 +223 361 -6.511205 +224 361 -6.543806 +227 361 -6.335723 +228 361 -26.205243 +230 361 -6.340072 +231 361 -14.938298 +232 361 -14.940585 +234 361 -8.758491 +235 361 -6.525440 +237 361 -35.723726 +240 361 -7.185802 +241 361 -22.499515 +242 361 -16.628786 +244 361 -20.338013 +245 361 -20.377238 +247 361 -9.457191 +248 361 -22.103746 +250 361 -14.847766 +251 361 -33.043252 +252 361 -9.080641 +253 361 -12.828356 +255 361 -16.119020 +256 361 -16.040947 +257 361 -6.506019 +258 361 -6.460086 +259 361 -6.300585 +261 361 -45.316380 +263 361 -6.204815 +265 361 -15.671613 +266 361 -14.216848 +267 361 -16.063149 +268 361 -14.621313 +269 361 -32.898837 +270 361 -32.898095 +271 361 -5.930967 +272 361 -5.919850 +274 361 -32.898657 +275 361 -19.113197 +277 361 -14.007868 +279 361 -25.711040 +280 361 -8.297826 +281 361 -26.654078 +282 361 -15.723082 +283 361 -21.645950 +284 361 -7.074984 +288 361 -6.336169 +289 361 -14.871210 +290 361 -14.830562 +292 361 -20.276883 +293 361 -12.360321 +294 361 -12.394734 +296 361 -11.006256 +297 361 -33.064581 +298 361 -33.764501 +300 361 -29.376481 +302 361 -6.206450 +304 361 -20.118425 +305 361 -8.939816 +306 361 -13.013008 +307 361 -6.062402 +308 361 -35.907901 +309 361 -35.897164 +310 361 -21.524946 +311 361 -20.061351 +312 361 -7.077980 +313 361 -9.175145 +314 361 -8.005351 +315 361 -14.199111 +316 361 -14.179176 +317 361 -6.285408 +318 361 -50.970807 +321 361 -5330.838312 +347 361 19652.477052 +348 361 25200.725975 +349 361 25200.733108 +350 361 25200.741162 +351 361 25200.750252 +352 361 25200.760515 +353 361 27470.011494 +354 361 59079.780426 +355 361 78050.102519 +356 361 91514.271040 +357 361 111680.563732 +358 361 139184.578783 +359 361 142997.401534 +360 361 315299.251688 +361 361 12306897.557838 +362 361 69311.149936 +369 361 6993.934582 +370 361 7362.361006 +371 361 7362.739199 +372 361 7363.169456 +373 361 7363.657154 +374 361 7364.208657 +375 361 7364.831511 +376 361 7365.534683 +377 361 7366.328862 +378 361 7780.239630 +379 361 19959.466302 +380 361 23020.666339 +381 361 53278.271004 +382 361 39841.337288 +383 361 141048.716618 +384 361 426442.915706 +385 361 405347.244761 +386 361 378044.598420 +402 361 6626.223546 +403 361 7621.503469 +404 361 8511.822168 +405 361 21638.261274 +406 361 219338.057586 +407 361 409128.478766 +408 361 297198.718193 +409 361 133154.114537 +410 361 201746.306724 +411 361 216423.329800 +426 361 5204.317422 +427 361 7853.735093 +428 361 35478.512603 +429 361 66095.550722 +430 361 299897.997832 +431 361 193918.486772 +432 361 21852.932130 +433 361 131781.203616 +434 361 146239.979013 +435 361 101510.927212 +436 361 187846.368305 +447 361 6796.608681 +448 361 7824.029025 +449 361 7830.136050 +450 361 9795.828248 +451 361 16652.214181 +452 361 20719.933771 +453 361 31966.354338 +454 361 25542.537776 +455 361 8873.333131 +456 361 18895.075979 +457 361 154081.284867 +458 361 120214.052683 +459 361 102076.764165 +460 361 94242.981988 +461 361 116668.463988 +472 361 709.380548 +475 361 16550.148583 +476 361 18827.646096 +477 361 12181.152542 +478 361 2807.342782 +479 361 10098.336742 +480 361 39138.419670 +481 361 138881.478621 +482 361 85055.137795 +483 361 68580.129034 +484 361 48999.412225 +485 361 137556.624236 +486 361 72689.823776 +2 362 -0.784650 +3 362 -3.223390 +5 362 -1.271566 +6 362 -0.956586 +7 362 -3.861121 +8 362 -3.353131 +9 362 -2.793026 +16 362 -2.951903 +17 362 -1.546924 +18 362 -1.529765 +19 362 -1.259830 +20 362 -0.586045 +21 362 -1.629572 +22 362 -3.150153 +23 362 -2.572260 +24 362 -10.545096 +25 362 -1.534821 +31 362 -2.456990 +32 362 -7.736438 +33 362 -3.601260 +34 362 -2.627440 +36 362 -0.962075 +37 362 -9.038622 +38 362 -1.624135 +39 362 -4.817527 +40 362 -18.482491 +42 362 -3.323787 +43 362 -6.982595 +44 362 -2.621876 +46 362 -0.457851 +47 362 -6.413653 +51 362 -1.568580 +52 362 -1.577341 +53 362 -3.461349 +54 362 -3.456679 +55 362 -1.613529 +60 362 -1.056421 +66 362 -1.737442 +67 362 -1.723038 +68 362 -0.569468 +69 362 -1.192626 +70 362 -0.528588 +77 362 -1.317953 +79 362 -1.573901 +80 362 -6.714544 +81 362 -0.546902 +82 362 -4.935439 +83 362 -4.080440 +84 362 -2.385289 +85 362 -1.006945 +87 362 -1.056317 +89 362 -5.275103 +90 362 -1.030157 +91 362 -1.610138 +92 362 -0.438230 +95 362 -4.104676 +96 362 -4.134335 +97 362 -0.760826 +98 362 -4.089929 +100 362 -1.092917 +101 362 -0.504729 +102 362 -8.505016 +103 362 -1.026734 +104 362 -0.455511 +106 362 -6.311126 +107 362 -4.101582 +108 362 -6.372285 +109 362 -25.267681 +110 362 -4.096374 +112 362 -4.109038 +115 362 -0.546110 +116 362 -1.003008 +117 362 -1.187431 +118 362 -1.029749 +119 362 -30.855665 +120 362 -3.378223 +121 362 -1.952331 +122 362 -3.017555 +123 362 -4.095970 +124 362 -2.669956 +125 362 -1.361945 +126 362 -1.239487 +129 362 -4.601784 +131 362 -2.825561 +132 362 -10.759524 +134 362 -1.023402 +135 362 -20.124430 +136 362 -1.567366 +137 362 -1.112009 +138 362 -1.257433 +140 362 -1.207322 +141 362 -6.215797 +143 362 -12.176920 +145 362 -0.955730 +146 362 -4.098427 +148 362 -2.608210 +150 362 -2.661066 +152 362 -1.218689 +154 362 -1.047659 +155 362 -1.011265 +156 362 -0.955721 +157 362 -0.955684 +159 362 -2.669810 +160 362 -8.638941 +161 362 -1.151026 +162 362 -0.955706 +163 362 -2.767089 +164 362 -3.525934 +166 362 -1.375276 +167 362 -1.191786 +168 362 -1.196013 +169 362 -1.337384 +172 362 -0.995088 +173 362 -4.757713 +174 362 -1.035167 +175 362 -1.192108 +176 362 -1.032319 +178 362 -16.998817 +179 362 -1.290361 +180 362 -1.187853 +182 362 -1.196398 +183 362 -1.230384 +185 362 -3.029393 +186 362 -1.609488 +187 362 -1.760127 +188 362 -5.221569 +190 362 -7.386346 +191 362 -7.546078 +192 362 -1.634240 +193 362 -2.688106 +194 362 -1.246604 +195 362 -1.579494 +196 362 -7.630802 +199 362 -8.131908 +201 362 -1.017026 +202 362 -1.268516 +203 362 -0.429255 +204 362 -2.268117 +205 362 -18.248030 +206 362 -0.649070 +207 362 -18.244548 +208 362 -18.248913 +209 362 -0.956027 +211 362 -0.964853 +212 362 -0.962087 +213 362 -1.305384 +214 362 -0.555343 +215 362 -2.667766 +216 362 -8.523449 +217 362 -1.379765 +218 362 -1.389768 +223 362 -1.439684 +224 362 -1.419118 +227 362 -1.556270 +228 362 -1.239242 +230 362 -1.553264 +231 362 -3.062172 +232 362 -3.060816 +234 362 -8.366201 +235 362 -1.430661 +237 362 -1.042194 +239 362 -18.254076 +240 362 -1.088411 +241 362 -1.390975 +242 362 -2.275802 +244 362 -1.557366 +245 362 -1.553433 +247 362 -0.654970 +248 362 -1.415196 +250 362 -3.116488 +251 362 -0.960108 +252 362 -0.688030 +253 362 -4.604485 +254 362 -17.182336 +255 362 -2.469046 +256 362 -0.468246 +257 362 -1.442988 +258 362 -10.611405 +259 362 -10.768313 +261 362 -23.717758 +262 362 -70.302862 +263 362 -1.649314 +265 362 -2.668787 +266 362 -3.528355 +267 362 -2.492388 +268 362 -0.424749 +269 362 -0.955712 +270 362 -0.955690 +271 362 -1.858547 +272 362 -1.867410 +274 362 -0.955707 +275 362 -1.705990 +277 362 -3.676791 +279 362 -1.253923 +280 362 -8.813166 +281 362 -1.226923 +282 362 -2.644290 +283 362 -1.446182 +284 362 -1.135475 +288 362 -1.555962 +289 362 -3.102303 +290 362 -3.126950 +292 362 -1.563584 +293 362 -5.005067 +294 362 -4.975135 +296 362 -6.227435 +297 362 -0.960757 +298 362 -0.982099 +300 362 -1.168062 +302 362 -1.648122 +304 362 -1.580211 +305 362 -0.702499 +306 362 -4.450737 +307 362 -1.755846 +308 362 -1.047870 +309 362 -1.047539 +310 362 -1.454965 +311 362 -1.586387 +312 362 -1.134150 +313 362 -0.679013 +314 362 -9.097895 +315 362 -3.540734 +316 362 -3.554697 +317 362 -1.591447 +318 362 -18.706724 +321 362 -875.271933 +347 362 570.904889 +348 362 732.081667 +349 362 732.081874 +350 362 732.082108 +351 362 732.082372 +352 362 732.082670 +353 362 798.005479 +354 362 1716.272621 +355 362 2267.431160 +356 362 2658.667559 +357 362 3244.732257 +358 362 4044.087580 +359 362 4154.993389 +360 362 9176.756817 +361 362 69311.149936 +362 362 11265049.901535 +369 362 203.216384 +370 362 213.921415 +371 362 213.932404 +372 362 213.944905 +373 362 213.959076 +374 362 213.975101 +375 362 213.993198 +376 362 214.013630 +377 362 214.036705 +378 362 226.066598 +379 362 580.003974 +380 362 668.989780 +381 362 1548.624466 +382 362 1158.265888 +383 362 4109.978105 +384 362 12432.372181 +385 362 13902.961445 +386 362 81728.396002 +387 362 29740.954580 +402 362 192.735244 +403 362 221.684693 +404 362 247.607444 +405 362 629.839472 +406 362 6392.420540 +407 362 11926.078064 +408 362 8679.543417 +409 362 5605.654139 +410 362 11718.329630 +411 362 73444.835313 +412 362 28759.766406 +426 362 151.531344 +427 362 228.673029 +428 362 1033.658993 +429 362 1926.083585 +430 362 8742.449521 +431 362 5653.971036 +432 362 690.623261 +433 362 5630.693757 +434 362 7213.092770 +435 362 8946.835746 +436 362 70988.989418 +437 362 27708.266461 +438 362 631.597997 +447 362 197.893242 +448 362 227.808094 +449 362 227.985909 +450 362 285.259586 +451 362 485.252761 +452 362 604.072882 +453 362 932.338021 +454 362 745.328385 +455 362 275.428661 +456 362 678.000057 +457 362 6664.348964 +458 362 5772.076831 +459 362 7797.573915 +460 362 16051.945576 +461 362 59462.567758 +462 362 23576.265573 +463 362 3678.440670 +472 362 20.654656 +475 362 482.842245 +476 362 549.371176 +477 362 355.469411 +478 362 93.311451 +479 362 341.369659 +480 362 1582.374732 +481 362 6130.170183 +482 362 4165.882281 +483 362 5019.511656 +484 362 4013.825833 +485 362 27295.842362 +486 362 49427.106693 +487 362 12448.450365 +488 362 14192.064001 +363 363 11156313.758077 +364 364 11111111.111111 +365 365 11111111.111111 +366 366 11111111.111111 +367 367 11111111.111111 +368 368 11141713.231778 +251 369 -150.689183 +319 369 -13.894450 +321 369 -31.310650 +322 369 -5.236796 +324 369 -8.319198 +327 369 -22.287056 +328 369 -31.406085 +329 369 -6.905089 +337 369 -4.956959 +338 369 -4.096707 +339 369 -6.411341 +340 369 -13.050554 +341 369 -2.814297 +355 369 6718.150442 +356 369 6984.235896 +357 369 6985.660885 +358 369 6987.296932 +359 369 6989.184714 +360 369 6991.375493 +361 369 6993.934582 +362 369 203.216384 +369 369 11162809.459959 +370 369 14428.055069 +371 369 10067.652034 +372 369 10068.089493 +373 369 10068.585348 +374 369 9995.271230 +375 369 6978.661342 +376 369 6979.327643 +377 369 6980.080180 +378 369 6980.931076 +379 369 6981.894921 +380 369 264.838922 +394 369 13233.991520 +395 369 10153.304940 +396 369 11424.815460 +397 369 9973.679404 +398 369 9976.613282 +399 369 9562.011986 +400 369 10116.813004 +401 369 10118.648346 +402 369 10120.722236 +403 369 8229.985846 +404 369 3091.353744 +405 369 3091.433478 +406 369 2533.496860 +419 369 6342.856013 +420 369 4174.592766 +421 369 3745.215498 +422 369 2542.095984 +423 369 1541.989937 +424 369 605.091752 +425 369 2957.995258 +426 369 2960.454394 +427 369 2963.238347 +428 369 4735.766643 +429 369 7034.374097 +430 369 7037.316191 +431 369 7040.669956 +432 369 7044.507534 +433 369 7048.918358 +434 369 3305.887742 +444 369 3526.654571 +445 369 3637.821069 +446 369 2610.370812 +447 369 2925.513448 +448 369 1518.587029 +449 369 1912.482112 +450 369 1552.177354 +451 369 186.736510 +453 369 123.710579 +454 369 2969.980598 +455 369 2974.066531 +456 369 296.164713 +459 369 3748.126588 +460 369 6054.910649 +469 369 1113.529831 +470 369 4940.747373 +471 369 1705.430662 +472 369 1696.117839 +473 369 2531.593559 +474 369 1267.386059 +475 369 1097.784021 +476 369 1371.636032 +477 369 1549.019715 +494 369 1111.263250 +495 369 4900.700264 +496 369 392.438502 +497 369 1963.748046 +498 369 920.243020 +499 369 2309.365415 +500 369 809.387924 +251 370 -68.126067 +268 370 -5.184834 +269 370 -0.637631 +274 370 -18.036465 +319 370 -14.625846 +321 370 -32.960033 +325 370 -23.858931 +328 370 -20.540189 +346 370 3333.449292 +347 370 2397.246523 +355 370 7072.049112 +356 370 7352.151414 +357 370 7353.651468 +358 370 7355.373699 +359 370 7357.360926 +360 370 7359.667110 +361 370 7362.361006 +362 370 213.921415 +369 370 14428.055069 +370 370 11151321.930600 +371 370 16068.605447 +372 370 10598.336950 +373 370 10598.858924 +374 370 10521.685615 +375 370 7346.283203 +376 370 7346.984604 +377 370 7347.776782 +378 370 7348.672503 +379 370 7349.687121 +380 370 278.790104 +395 370 8063.795919 +396 370 4591.466896 +397 370 4592.180837 +398 370 4592.990342 +399 370 4671.669644 +400 370 7848.773291 +401 370 7849.993014 +402 370 7851.371254 +403 370 6614.817741 +404 370 3254.080763 +405 370 3254.164694 +406 370 2666.858625 +419 370 4894.433689 +420 370 1547.415245 +428 370 1238.112735 +429 370 4600.616983 +430 370 4602.541170 +431 370 4604.734597 +432 370 4607.244447 +433 370 4610.129211 +434 370 2162.114651 +444 370 1801.237627 +459 370 2451.347426 +460 370 3960.028907 +251 371 -47.587695 +268 371 -33.198576 +269 371 -38.402329 +270 371 -2.124525 +274 371 -135.872251 +319 371 -14.625970 +321 371 -32.961726 +322 371 -2.124525 +325 371 -207.473156 +346 371 27579.890508 +347 371 21064.065670 +355 371 7072.412392 +356 371 7352.529082 +357 371 7354.029214 +358 371 7355.751533 +359 371 7357.738862 +360 371 7360.045165 +361 371 7362.739199 +362 371 213.932404 +369 371 10067.652034 +370 371 16068.605447 +371 371 11192766.354409 +372 371 10966.546837 +373 371 10599.263773 +374 371 10522.089834 +375 371 7346.660570 +376 371 7347.362007 +377 371 7348.154226 +378 371 7349.049992 +379 371 7350.064663 +380 371 278.804425 +395 371 55145.033918 +396 371 437.599904 +399 371 77.764224 +400 371 3253.860134 +401 371 3253.911296 +402 371 3253.969064 +403 371 3254.034364 +404 371 3254.108308 +405 371 3254.192240 +406 371 2666.881199 +419 371 42274.356081 +420 371 13897.624078 +421 371 438.899508 +444 371 15707.849745 +446 371 440.352154 +471 371 441.953656 +496 371 443.699272 +251 372 -47.589762 +268 372 -323.163421 +269 372 -184.876022 +270 372 -102.864523 +274 372 -178.463280 +319 372 -14.626111 +320 372 -48.336388 +321 372 -32.963652 +322 372 -85.606377 +323 372 -28.134525 +324 372 -2.733429 +326 372 -60.652994 +327 372 -71.068704 +329 372 -208.137968 +332 372 -18.342383 +334 372 -30.152306 +335 372 -60.220158 +336 372 -75.026054 +338 372 -0.479126 +341 372 -100.476834 +347 372 149002.060732 +355 372 7072.825683 +356 372 7352.958743 +357 372 7354.458962 +358 372 7356.181381 +359 372 7358.168826 +360 372 7360.475264 +361 372 7363.169456 +362 372 213.944905 +369 372 10068.089493 +370 372 10598.336950 +371 372 10966.546837 +372 372 11289939.579732 +373 372 29118.726168 +374 372 10522.549696 +375 372 7347.089887 +376 372 7347.791365 +377 372 7348.583631 +378 372 7349.479450 +379 372 7350.494179 +380 372 278.820718 +396 372 4956.066967 +397 372 69883.206553 +398 372 93207.833135 +399 372 2422.615860 +400 372 3253.891464 +401 372 3253.942626 +402 372 3254.000395 +403 372 3254.065696 +404 372 3254.139640 +405 372 3254.223573 +406 372 2666.906877 +421 372 16874.789976 +422 372 36867.052695 +423 372 96550.381031 +424 372 17820.751016 +425 372 624.335320 +446 372 17742.430270 +447 372 26698.138708 +448 372 82140.740260 +449 372 36008.038757 +450 372 4123.880250 +451 372 433.951036 +471 372 17810.947537 +472 372 20589.072845 +473 372 43703.616293 +474 372 67990.779487 +475 372 14167.584351 +476 372 1173.718955 +477 372 191.822403 +496 372 17885.308094 +497 372 16871.192123 +498 372 21985.933050 +499 372 79954.618517 +500 372 22398.783938 +251 373 -47.592105 +268 373 -143.916151 +269 373 -168.649330 +270 373 -42.377369 +274 373 -143.663269 +319 373 -14.626270 +320 373 -74.493979 +321 373 -32.965835 +324 373 -70.172666 +326 373 -41.663151 +329 373 -0.051787 +332 373 -94.823125 +337 373 -70.231378 +338 373 -55.252110 +339 373 -53.599965 +341 373 -13.384674 +342 373 -24.933285 +347 373 107474.154164 +348 373 19567.493271 +355 373 7073.294150 +356 373 7353.445764 +357 373 7354.946082 +358 373 7356.668616 +359 373 7358.656193 +360 373 7360.962783 +361 373 7363.657154 +362 373 213.959076 +369 373 10068.585348 +370 373 10598.858924 +371 373 10599.263773 +372 373 29118.726168 +373 373 11221444.457899 +374 373 43570.913619 +375 373 7864.153062 +376 373 7348.278044 +377 373 7349.070362 +378 373 7349.966240 +379 373 7350.981037 +380 373 278.839185 +398 373 45259.769092 +399 373 51442.673117 +400 373 40692.767321 +401 373 9594.021387 +402 373 3254.035903 +403 373 3254.101205 +404 373 3254.175150 +405 373 3254.259084 +406 373 2666.935979 +423 373 10997.497619 +424 373 45680.139711 +425 373 32515.736814 +426 373 33456.494015 +427 373 12821.638863 +448 373 803.833308 +449 373 29892.838106 +450 373 30005.919566 +451 373 24360.265115 +452 373 28012.698893 +453 373 17434.576700 +454 373 139.243314 +473 373 1.245072 +474 373 11861.088544 +475 373 33742.891933 +476 373 21570.008508 +477 373 15124.143133 +478 373 23949.553868 +479 373 19352.646034 +480 373 380.309879 +499 373 3229.529917 +500 373 24125.712382 +251 374 -47.245191 +268 374 -78.624139 +269 374 -105.976971 +274 374 -121.958169 +319 374 -14.276887 +321 374 -32.968304 +324 374 -2.222642 +331 374 -10.904373 +337 374 -83.746947 +338 374 -3.442977 +339 374 -107.639207 +340 374 -45.629525 +342 374 -52.973609 +347 374 58906.636316 +348 374 46459.551050 +349 374 4760.359961 +355 374 7073.823906 +356 374 7353.996502 +357 374 7355.496933 +358 374 7357.219596 +359 374 7359.207321 +360 374 7361.514085 +361 374 7364.208657 +362 374 213.975101 +369 374 9995.271230 +370 374 10521.685615 +371 374 10522.089834 +372 374 10522.549696 +373 374 43570.913619 +374 374 11222336.622015 +375 374 23066.620832 +376 374 14383.542375 +377 374 7349.620773 +378 374 7350.516718 +379 374 7351.531591 +380 374 278.860069 +399 374 10710.792126 +400 374 64279.817672 +401 374 24544.482668 +402 374 16824.544576 +403 374 9771.673234 +404 374 3176.505219 +405 374 3176.523431 +406 374 2603.229924 +424 374 19.943347 +425 374 3664.839786 +426 374 50735.707484 +427 374 27624.728046 +428 374 7114.435988 +429 374 13780.334705 +430 374 3493.530401 +450 374 180.842343 +451 374 1747.624062 +452 374 39093.671083 +453 374 35934.097356 +454 374 712.161581 +455 374 10368.414168 +456 374 3779.490560 +457 374 1238.509996 +476 374 504.275205 +477 374 939.103413 +478 374 31654.264353 +479 374 38902.801531 +480 374 1466.940018 +482 374 1438.924600 +483 374 2438.783634 +209 375 -12.197711 +251 375 -32.971093 +268 375 -15.784458 +269 375 -30.607666 +270 375 -4.724072 +274 375 -79.106603 +321 375 -32.971093 +325 375 -12.197711 +328 375 -19.608900 +331 375 -35.147762 +339 375 -3.469342 +340 375 -67.147255 +342 375 -4.849538 +347 375 22752.190201 +348 375 30435.494447 +349 375 15315.476119 +350 375 2615.604406 +352 375 1524.549779 +353 375 2013.762634 +355 375 7074.422200 +356 375 7354.618493 +357 375 7356.119050 +358 375 7357.841859 +359 375 7359.829752 +360 375 7362.136711 +361 375 7364.831511 +362 375 213.993198 +369 375 6978.661342 +370 375 7346.283203 +371 375 7346.660570 +372 375 7347.089887 +373 375 7864.153062 +374 375 23066.620832 +375 375 11330002.920569 +376 375 29914.839112 +377 375 13196.469462 +378 375 11817.830455 +379 375 9189.477561 +380 375 278.883655 +397 375 798.286519 +398 375 2877.228665 +399 375 2883.767839 +400 375 2376.515528 +401 375 10573.573441 +402 375 24666.610346 +403 375 14578.066126 +404 375 2635.517919 +405 375 4479.412806 +406 375 4487.164325 +407 375 2547.420093 +419 375 3.634215 +420 375 2862.028211 +421 375 2866.439322 +422 375 2073.195254 +426 375 994.875340 +427 375 1800.613976 +428 375 10197.980963 +429 375 24901.549640 +430 375 9081.757894 +432 375 1948.649920 +433 375 4506.353762 +434 375 4518.299106 +435 375 697.345912 +444 375 2258.911826 +452 375 427.680392 +453 375 2005.831983 +454 375 202.975152 +455 375 15965.042944 +456 375 10221.604952 +457 375 3992.054877 +460 375 3189.040646 +478 375 248.116995 +479 375 1884.121152 +480 375 352.360828 +482 375 4638.045704 +483 375 7860.863561 +58 376 -222.657604 +116 376 -28.573144 +209 376 -15.629348 +251 376 -32.974241 +268 376 -15.583011 +269 376 -60.210690 +270 376 -23.023463 +274 376 -148.377902 +319 376 -65.326734 +320 376 -3.738565 +321 376 -32.974241 +322 376 -3.659999 +324 376 -9.997203 +325 376 -15.629348 +326 376 -32.855001 +328 376 -243.128916 +329 376 -7.580381 +331 376 -33.737637 +333 376 -28.573144 +338 376 -10.228367 +339 376 -12.154092 +340 376 -29.907399 +341 376 -3.472612 +342 376 -14.065765 +347 376 42035.743358 +348 376 56728.828000 +349 376 49762.478516 +350 376 37209.109923 +351 376 10604.751148 +352 376 1953.458242 +353 376 2580.303556 +355 376 7075.097644 +356 376 7355.320689 +357 376 7356.821390 +358 376 7358.544363 +359 376 7360.532447 +360 376 7362.839626 +361 376 7365.534683 +362 376 214.013630 +369 376 6979.327643 +370 376 7346.984604 +371 376 7347.362007 +372 376 7347.791365 +373 376 7348.278044 +374 376 14383.542375 +375 376 29914.839112 +376 376 11525193.223122 +377 376 71177.348650 +378 376 54660.607131 +379 376 41021.245870 +380 376 8353.076628 +397 376 1022.872065 +398 376 3686.692378 +399 376 3695.071248 +400 376 6082.924400 +401 376 26803.456337 +402 376 32162.399678 +403 376 33608.121377 +404 376 36359.600056 +405 376 62040.011527 +406 376 60980.565473 +407 376 22902.146838 +419 376 4.656645 +420 376 3667.215513 +421 376 3672.867621 +422 376 2656.456623 +423 376 1730.873767 +424 376 7274.878378 +425 376 3265.525522 +426 376 8776.197447 +427 376 7480.311301 +428 376 10116.788587 +429 376 15752.274385 +430 376 7726.586354 +431 376 6574.697062 +432 376 32692.074982 +433 376 55709.902115 +434 376 55624.190841 +435 376 5946.474425 +444 376 2894.421675 +447 376 6663.964103 +448 376 5504.802624 +449 376 71.371874 +450 376 715.682454 +451 376 2111.796750 +452 376 8128.503539 +453 376 5477.651416 +454 376 5151.407082 +455 376 8512.274699 +456 376 8963.185017 +457 376 3831.893956 +459 376 220.038186 +460 376 42075.238170 +472 376 250.099829 +474 376 800.196668 +475 376 449.937154 +476 376 1511.463817 +477 376 7301.258007 +478 376 3458.282162 +479 376 3123.488180 +480 376 4282.036232 +481 376 783.672388 +482 376 4451.967683 +483 376 7545.486346 +499 376 813.737654 +500 376 1458.713849 +1 377 -4.451226 +2 377 -10.336360 +3 377 -10.106363 +4 377 -10.242783 +5 377 -4.620854 +8 377 -10.014716 +10 377 -4.461743 +12 377 -4.577713 +14 377 -10.014792 +15 377 -10.014809 +17 377 -4.620256 +18 377 -16.270124 +19 377 -10.062830 +21 377 -4.451239 +22 377 -10.018871 +23 377 -4.493346 +26 377 -4.456632 +27 377 -61.152282 +31 377 -10.351824 +33 377 -4.505587 +37 377 -4.503474 +38 377 -4.514441 +39 377 -20.734382 +40 377 -63.421393 +41 377 -4.505089 +47 377 -6.846513 +52 377 -10.124081 +53 377 -10.014786 +54 377 -10.014750 +55 377 -8.199372 +57 377 -10.014828 +58 377 -106.117424 +60 377 -4.531172 +65 377 -10.103789 +68 377 -10.298574 +69 377 -4.547179 +71 377 -4.663173 +72 377 -4.451576 +77 377 -4.459245 +78 377 -4.453740 +79 377 -10.126945 +82 377 -4.864080 +84 377 -4.527996 +93 377 -4.519639 +94 377 -4.471931 +116 377 -49.918981 +119 377 -10.102085 +122 377 -10.028460 +124 377 -4.482619 +125 377 -10.020722 +126 377 -11.008015 +136 377 -4.506690 +138 377 -4.527006 +143 377 -4.899497 +148 377 -10.099426 +159 377 -4.482901 +160 377 -4.503935 +161 377 -8.187104 +163 377 -10.064452 +166 377 -10.018176 +169 377 -4.459661 +178 377 -5.525106 +186 377 -4.492621 +187 377 -4.451030 +189 377 -10.065138 +192 377 -12.671234 +193 377 -4.480890 +194 377 -11.057138 +195 377 -10.015071 +196 377 -6.578050 +197 377 -4.903187 +200 377 -4.523869 +203 377 -11.324749 +209 377 -7.961272 +211 377 -1.477177 +212 377 -30.170222 +213 377 -10.811077 +214 377 -11.720944 +215 377 -4.482458 +216 377 -7.117774 +218 377 -10.017737 +220 377 -10.015775 +221 377 -10.016153 +222 377 -10.016369 +224 377 -4.451716 +225 377 -4.451447 +231 377 -4.452715 +233 377 -4.451023 +235 377 -40.066280 +237 377 -10.173730 +238 377 -10.232123 +239 377 -7.258185 +241 377 -10.014716 +242 377 -4.544371 +251 377 -32.977796 +268 377 -33.450490 +269 377 -67.035944 +270 377 -29.809083 +274 377 -168.463052 +297 377 -24.763562 +319 377 -148.158171 +321 377 -32.977796 +322 377 -0.497323 +325 377 -75.199659 +328 377 -256.717822 +333 377 -852.504148 +347 377 50448.869110 +348 377 67659.793125 +349 377 67705.275486 +350 377 63295.283241 +351 377 26069.053270 +352 377 932.893214 +353 377 1291.535397 +355 377 7075.860507 +356 377 7356.113767 +357 377 7357.614630 +358 377 7359.337788 +359 377 7361.326086 +360 377 7363.633514 +361 377 7366.328862 +362 377 214.036705 +369 377 6980.080180 +370 377 7347.776782 +371 377 7348.154226 +372 377 7348.583631 +373 377 7349.070362 +374 377 7349.620773 +375 377 13196.469462 +376 377 71177.348650 +377 377 11836118.007691 +378 377 99277.014221 +379 377 72992.917646 +380 377 24020.165581 +397 377 488.482624 +398 377 2379.889196 +399 377 16432.504871 +400 377 24397.153017 +401 377 30962.587125 +402 377 134092.190127 +403 377 60690.553846 +404 377 37087.761280 +405 377 70661.388324 +406 377 82271.029381 +407 377 30030.097055 +419 377 2.223826 +420 377 12492.266529 +421 377 17262.260560 +422 377 16790.858992 +423 377 17942.815454 +424 377 13597.950484 +425 377 4352.223900 +426 377 19638.257386 +427 377 86557.007010 +428 377 23059.365384 +429 377 35691.491555 +430 377 4027.472026 +431 377 5783.823387 +432 377 28771.900582 +433 377 58932.081724 +434 377 58922.537512 +435 377 7759.767117 +444 377 13639.658682 +445 377 4755.022191 +447 377 11642.341404 +448 377 9617.217398 +450 377 3222.416680 +451 377 32218.914540 +452 377 68817.813244 +453 377 5739.099268 +454 377 25098.207172 +455 377 25874.549319 +456 377 5402.253263 +459 377 160.652323 +460 377 43055.564480 +472 377 436.939267 +474 377 543.318542 +475 377 8117.067982 +476 377 35520.966374 +477 377 58995.312468 +478 377 5563.558283 +479 377 3805.491708 +480 377 31475.667758 +481 377 12431.913829 +482 377 422.999711 +499 377 3213.135305 +500 377 7844.819828 +58 378 -32.984077 +128 378 -26.069634 +145 378 -40.275963 +156 378 -86.131021 +157 378 -70.916761 +162 378 -58.697747 +203 378 -172.714663 +209 378 -52.111372 +211 378 -15.103848 +212 378 -46.478778 +237 378 -7.663248 +251 378 -32.981816 +268 378 -33.478929 +269 378 -67.100063 +270 378 -29.838393 +274 378 -168.670019 +295 378 -13.213366 +297 378 -34.191743 +319 378 -148.258157 +320 378 -43.928541 +321 378 -34.820362 +322 378 -135.200273 +323 378 -4.630047 +324 378 -7.093856 +325 378 -126.556522 +326 378 -4.847621 +327 378 -78.028399 +328 378 -188.048239 +329 378 -122.557935 +331 378 -4.759394 +332 378 -8.560557 +333 378 -7.663248 +335 378 -37.055956 +336 378 -10.807747 +337 378 -5.875789 +338 378 -7.208931 +339 378 -3.033832 +341 378 -4.644757 +342 378 -5.041277 +347 378 50504.101740 +348 378 67734.318448 +349 378 67779.852927 +350 378 63364.689246 +351 378 26095.591972 +353 378 37953.917241 +354 378 15887.441874 +355 378 7076.723080 +356 378 8179.681990 +357 378 10470.650968 +358 378 10821.703515 +359 378 8018.917719 +360 378 7777.196961 +361 378 7780.239630 +362 378 226.066598 +369 378 6980.931076 +370 378 7348.672503 +371 378 7349.049992 +372 378 7349.479450 +373 378 7349.966240 +374 378 7350.516718 +375 378 11817.830455 +376 378 54660.607131 +377 378 99277.014221 +378 378 12097911.761880 +379 378 84891.440782 +380 378 27596.416630 +381 378 2623.688750 +382 378 341.229917 +398 378 703.056052 +399 378 23035.281539 +400 378 29043.476647 +401 378 29083.971146 +402 378 28149.974402 +403 378 66129.661926 +404 378 35190.684922 +405 378 55811.658344 +406 378 71304.939583 +407 378 30949.036258 +420 378 18871.328286 +421 378 28923.923964 +422 378 28948.394384 +423 378 28273.146742 +424 378 5972.459341 +426 378 33.167740 +427 378 31764.397562 +428 378 45055.815076 +429 378 14808.752056 +430 378 3575.680719 +431 378 2331.570309 +432 378 12278.387308 +433 378 43334.894546 +434 378 43459.813106 +435 378 7986.383078 +444 378 22862.895757 +445 378 10031.134742 +451 378 17030.253239 +452 378 43962.764892 +453 378 13155.402409 +454 378 15028.526272 +455 378 5248.964134 +456 378 1664.028285 +457 378 1578.168765 +460 378 29404.649006 +475 378 567.072653 +476 378 29739.420620 +477 378 40610.076450 +478 378 2784.208066 +479 378 16144.443309 +480 378 4373.333785 +481 378 1882.958075 +482 378 1164.000512 +483 378 1333.800061 +500 378 25306.513516 +6 379 -26.396467 +45 379 -98.773841 +58 379 -12.016942 +128 379 -171.807944 +145 379 -292.425666 +156 379 -262.453495 +157 379 -103.217647 +162 379 -245.733338 +203 379 -102.732824 +211 379 -150.102115 +212 379 -372.068729 +251 379 -32.986370 +268 379 -33.511219 +269 379 -46.692806 +270 379 -21.875156 +274 379 -145.603045 +295 379 -33.849886 +297 379 -286.720433 +319 379 -127.399854 +320 379 -302.626422 +321 379 -89.163000 +322 379 -53.861713 +323 379 -124.037147 +324 379 -181.652656 +325 379 -81.109827 +326 379 -78.388559 +327 379 -52.208857 +328 379 -209.275931 +329 379 -57.727976 +330 379 -11.688014 +331 379 -23.163171 +332 379 -193.797057 +334 379 -101.967913 +335 379 -156.547212 +336 379 -107.199898 +337 379 -61.531343 +338 379 -88.959055 +339 379 -138.166457 +341 379 -171.115923 +342 379 -27.379938 +347 379 41740.483433 +348 379 56067.823449 +349 379 56104.587702 +350 379 54308.865461 +351 379 24534.005887 +353 379 5412.406570 +354 379 178636.592249 +355 379 8990.360479 +356 379 13273.916642 +357 379 23529.964790 +358 379 27743.020597 +359 379 20565.150616 +360 379 19948.565923 +361 379 19959.466302 +362 379 580.003974 +369 379 6981.894921 +370 379 7349.687121 +371 379 7350.064663 +372 379 7350.494179 +373 379 7350.981037 +374 379 7351.531591 +375 379 9189.477561 +376 379 41021.245870 +377 379 72992.917646 +378 379 84891.440782 +379 379 12493519.082950 +380 379 70784.253496 +381 379 16068.651781 +382 379 4185.916960 +398 379 133.755620 +399 379 10740.258622 +400 379 18565.259940 +401 379 18588.937864 +402 379 11902.181634 +403 379 26552.004904 +404 379 250562.796154 +405 379 147188.562518 +406 379 72329.290437 +407 379 39438.749921 +408 379 4102.294809 +420 379 11013.557405 +421 379 18495.313602 +422 379 18509.635492 +423 379 18392.152242 +424 379 7804.100003 +427 379 1186.872541 +428 379 46634.525160 +429 379 168409.410790 +430 379 131746.320482 +431 379 17438.290622 +432 379 10036.819856 +433 379 44352.205336 +434 379 48613.909153 +435 379 10741.828346 +444 379 14621.250082 +445 379 7469.193536 +452 379 9242.675073 +453 379 80650.495591 +454 379 93086.111314 +455 379 109818.592607 +456 379 59016.379645 +457 379 10565.089742 +458 379 552.673351 +460 379 31102.019587 +476 379 2844.916855 +477 379 17655.548106 +478 379 72961.815163 +479 379 60243.979466 +480 379 82126.019485 +481 379 103703.636802 +482 379 12164.964666 +483 379 8012.571444 +500 379 503.144875 +6 380 -79.295276 +7 380 -77.742411 +36 380 -49.510780 +145 380 -173.072035 +156 380 -96.717255 +157 380 -91.037075 +162 380 -226.994318 +203 380 -18.772268 +211 380 -68.556355 +212 380 -67.377967 +251 380 -1.251247 +268 380 -30.929773 +269 380 -28.706800 +270 380 -13.079281 +274 380 -32.305181 +295 380 -33.907873 +297 380 -176.245514 +319 380 -105.021035 +320 380 -13.003624 +321 380 -102.741453 +322 380 -30.502196 +324 380 -60.620459 +325 380 -33.907873 +326 380 -12.398140 +328 380 -118.838704 +329 380 -60.269751 +331 380 -382.323556 +332 380 -19.120333 +336 380 -23.511504 +337 380 -89.523300 +338 380 -42.189429 +339 380 -21.788028 +341 380 -10.385121 +342 380 -139.356901 +347 380 18114.265452 +348 380 23682.446231 +349 380 23694.548750 +350 380 23708.236296 +351 380 15649.547123 +354 380 146079.816534 +355 380 15910.002411 +356 380 10773.918940 +357 380 23827.866755 +358 380 30808.590109 +359 380 23620.970049 +360 380 23006.287222 +361 380 23020.666339 +362 380 668.989780 +369 380 264.838922 +370 380 278.790104 +371 380 278.804425 +372 380 278.820718 +373 380 278.839185 +374 380 278.860069 +375 380 278.883655 +376 380 8353.076628 +377 380 24020.165581 +378 380 27596.416630 +379 380 70784.253496 +380 380 12305869.045993 +381 380 39624.201853 +382 380 8510.250475 +399 380 919.252472 +400 380 7720.065819 +401 380 7728.040197 +402 380 7737.073706 +403 380 4718.591729 +404 380 645.084944 +405 380 78422.872840 +406 380 166911.326910 +407 380 27491.514574 +408 380 15128.953681 +409 380 295.914731 +420 380 3701.279005 +421 380 7696.469788 +422 380 7701.305959 +423 380 7706.797791 +424 380 6793.768520 +429 380 12897.023463 +430 380 32293.930572 +431 380 60157.280224 +432 380 95014.054894 +433 380 13533.238559 +434 380 27962.042549 +435 380 9957.563204 +444 380 6085.744465 +445 380 3990.946650 +453 380 3665.553419 +454 380 16481.648481 +455 380 10850.432437 +456 380 32949.330260 +457 380 74909.408486 +458 380 54920.473551 +459 380 17.984223 +460 380 14415.167868 +477 380 838.263588 +478 380 16270.482300 +479 380 3710.920346 +480 380 10179.131148 +481 380 19884.396277 +482 380 22256.163825 +483 380 97392.389199 +484 380 15903.961089 +6 381 -12.251710 +7 381 -253.881930 +36 381 -226.463786 +92 381 -6.952400 +145 381 -1.015134 +156 381 -38.170417 +157 381 -37.779189 +162 381 -4.322659 +203 381 -14.722364 +211 381 -37.074515 +212 381 -19.288447 +295 381 -24.764109 +297 381 -30.883805 +298 381 -32.164039 +320 381 -10.279640 +321 381 -236.728718 +322 381 -6.018712 +324 381 -47.665074 +325 381 -24.764109 +328 381 -145.274762 +329 381 -27.647658 +336 381 -8.313473 +337 381 -138.860731 +338 381 -20.645491 +339 381 -24.006102 +342 381 -49.530034 +354 381 17809.527853 +355 381 16302.246946 +356 381 5227.400794 +357 381 24792.936916 +358 381 49972.861833 +359 381 47975.944417 +360 381 53224.852046 +361 381 53278.271004 +362 381 1548.624466 +378 381 2623.688750 +379 381 16068.651781 +380 381 39624.201853 +381 381 12128993.803658 +382 381 49207.256564 +383 381 8882.185081 +384 381 5661.206734 +399 381 671.362309 +400 381 5638.234724 +401 381 5644.058692 +402 381 11962.791935 +403 381 10706.391657 +404 381 7266.176016 +405 381 14993.487261 +406 381 54121.358893 +407 381 28869.171676 +408 381 32469.838148 +409 381 2991.987475 +420 381 2703.173820 +421 381 5621.001716 +422 381 5624.533740 +423 381 5628.544618 +424 381 4961.727331 +429 381 4162.636417 +430 381 4404.004456 +431 381 13320.195319 +432 381 38957.130388 +433 381 7620.414498 +434 381 32567.523400 +435 381 15976.749947 +444 381 4444.632542 +445 381 2914.728256 +453 381 558.498494 +454 381 6818.206335 +455 381 1429.711488 +456 381 5781.108474 +457 381 38682.784892 +458 381 8989.548204 +459 381 1794.154866 +460 381 14775.479191 +477 381 19.502244 +478 381 5895.150529 +479 381 1702.317610 +480 381 1442.458452 +481 381 4996.712838 +482 381 14198.940470 +483 381 24811.879780 +484 381 9543.008570 +7 382 -91.302873 +36 382 -21.608644 +92 382 -14.941191 +116 382 -5.546531 +156 382 -21.419569 +157 382 -19.877240 +203 382 -12.202349 +211 382 -18.864771 +295 382 -3.453508 +298 382 -33.525861 +321 382 -176.383577 +328 382 -62.905452 +329 382 -3.453508 +354 382 8905.282472 +355 382 8386.230710 +357 382 8645.146788 +358 382 27944.672270 +359 382 31280.724575 +360 382 39436.593979 +361 382 39841.337288 +362 382 1158.265888 +378 382 341.229917 +379 382 4185.916960 +380 382 8510.250475 +381 382 49207.256564 +382 382 12103593.347910 +383 382 12929.022349 +384 382 8559.454407 +385 382 352.318811 +402 382 6579.390903 +403 382 7567.636413 +404 382 7716.172728 +405 382 8850.963585 +406 382 3331.857617 +407 382 8179.736278 +408 382 15395.012989 +409 382 1761.987240 +426 382 837.952599 +427 382 1264.538112 +428 382 1266.156828 +429 382 1125.649631 +431 382 506.528768 +432 382 283.884813 +434 382 13761.030610 +435 382 7336.063574 +447 382 1094.329082 +448 382 1259.755107 +449 382 1260.738406 +450 382 1261.851429 +451 382 425.158593 +455 382 253.493663 +456 382 575.028181 +460 382 6098.431756 +472 382 114.218105 +479 382 71.086336 +480 382 798.009757 +46 383 -2.733954 +83 383 -63.781125 +85 383 -33.084470 +90 383 -6.157187 +92 383 -14.965166 +95 383 -39.143528 +96 383 -13.068223 +98 383 -53.725544 +103 383 -9.252961 +104 383 -4.892270 +107 383 -42.105342 +110 383 -47.204744 +112 383 -35.053119 +116 383 -34.096916 +118 383 -6.514607 +123 383 -47.605918 +134 383 -12.493894 +146 383 -45.176711 +155 383 -26.756500 +174 383 -1.995285 +176 383 -4.311007 +201 383 -19.436537 +295 383 -140.183265 +298 383 -33.572715 +321 383 -597.127721 +323 383 -23.650922 +327 383 -11.856786 +329 383 -27.453056 +334 383 -26.174047 +335 383 -5.067916 +339 383 -22.923309 +341 383 -23.057229 +358 383 12104.626193 +359 383 12952.930053 +360 383 68839.038799 +361 383 141048.716618 +362 383 4109.978105 +381 383 8882.185081 +382 383 12929.022349 +383 383 12265517.706968 +384 383 136302.498053 +385 383 71465.670686 +402 383 6588.585817 +403 383 7578.212433 +404 383 8459.481845 +405 383 21193.805626 +406 383 87899.673815 +407 383 133724.949292 +408 383 89398.328139 +426 383 5151.255707 +427 383 7773.660681 +428 383 21109.573729 +429 383 31377.724378 +430 383 84250.042055 +431 383 44957.923175 +432 383 9448.144277 +433 383 12010.109851 +447 383 6727.312425 +448 383 7744.257488 +449 383 7750.302248 +450 383 8847.863528 +451 383 8116.547949 +452 383 5884.527262 +453 383 4689.605007 +454 383 347.487280 +455 383 2015.103297 +456 383 5205.122458 +457 383 7761.716552 +458 383 11221.372249 +472 383 702.147909 +475 383 822.560731 +476 383 372.642465 +479 383 565.088327 +480 383 6343.638240 +481 383 7577.784324 +482 383 4164.153252 +483 383 8325.033622 +46 384 -15.521635 +83 384 -138.622540 +85 384 -34.302102 +90 384 -34.923503 +92 384 -11.760831 +95 384 -139.269511 +96 384 -140.057874 +98 384 -138.876129 +103 384 -34.832430 +104 384 -15.459349 +107 384 -139.187031 +110 384 -139.048149 +112 384 -139.385673 +116 384 -34.195809 +118 384 -34.912661 +123 384 -139.037387 +134 384 -34.743576 +137 384 -2.062011 +146 384 -139.102915 +154 384 -28.517347 +155 384 -34.418437 +174 384 -35.056438 +176 384 -34.980918 +201 384 -34.573081 +237 384 -32.019071 +256 384 -11.145665 +295 384 -82.891660 +298 384 -20.317197 +308 384 -28.388649 +309 384 -28.590992 +320 384 -9.930397 +321 384 -1793.308912 +326 384 -9.951426 +332 384 -10.275957 +335 384 -4.956515 +337 384 -23.791469 +338 384 -10.123259 +342 384 -13.862639 +359 384 14881.042883 +360 384 169167.987863 +361 384 426442.915706 +362 384 12432.372181 +381 384 5661.206734 +382 384 8559.454407 +383 384 136302.498053 +384 384 12583880.091061 +385 384 256351.330771 +386 384 63.034873 +402 384 3987.213902 +403 384 4586.106154 +404 384 5467.466691 +405 384 18490.998314 +406 384 216575.756629 +407 384 400205.744394 +408 384 284584.411460 +409 384 15822.467522 +410 384 2688.965190 +426 384 5166.196239 +427 384 7796.207150 +428 384 35148.279748 +429 384 65436.857081 +430 384 292639.674966 +431 384 186155.475189 +432 384 9678.060022 +433 384 1086.512833 +434 384 8130.010094 +435 384 1904.898997 +436 384 2279.853385 +447 384 6746.824100 +448 384 7766.718677 +449 384 7772.780968 +450 384 9719.778687 +451 384 16487.107965 +452 384 19611.509077 +453 384 28340.095009 +454 384 20656.547490 +455 384 4067.263671 +456 384 503.729931 +457 384 77.490856 +458 384 772.164844 +459 384 6041.944865 +460 384 3613.751221 +461 384 2442.668910 +472 384 704.184395 +475 384 14053.716102 +476 384 15357.085431 +477 384 9665.573197 +478 384 173.028543 +479 384 498.065089 +480 384 250.170332 +483 384 779.729656 +484 384 4654.229161 +485 384 4917.571536 +486 384 26.012881 +487 384 2308.914107 +5 385 -14.866842 +20 385 -4.697569 +39 385 -90.337375 +46 385 -10.304363 +68 385 -6.185843 +69 385 -24.213197 +70 385 -10.973466 +81 385 -8.576971 +82 385 -75.634190 +83 385 -76.195679 +85 385 -12.023690 +90 385 -23.182341 +95 385 -86.553776 +96 385 -97.689660 +98 385 -80.405035 +101 385 -15.128502 +103 385 -21.864303 +104 385 -9.387456 +107 385 -85.300486 +110 385 -83.147971 +112 385 -88.288404 +115 385 -8.670667 +116 385 -9.396534 +118 385 -23.029635 +123 385 -82.978912 +126 385 -18.263456 +134 385 -20.495284 +137 385 -37.465753 +138 385 -16.308504 +140 385 -22.192822 +146 385 -84.003231 +154 385 -28.851785 +155 385 -14.588984 +161 385 -30.995333 +167 385 -24.333584 +168 385 -23.733002 +173 385 -98.699809 +174 385 -24.971152 +175 385 -24.287376 +176 385 -23.973387 +179 385 -13.065321 +180 385 -24.905558 +182 385 -23.679003 +194 385 -17.470249 +201 385 -17.597355 +202 385 -15.171218 +206 385 -0.253352 +213 385 -11.708847 +214 385 -7.623161 +228 385 -18.291200 +237 385 -27.243414 +241 385 -5.045863 +248 385 -3.409779 +256 385 -13.535851 +279 385 -16.679327 +281 385 -19.726869 +283 385 -1.436455 +295 385 -16.327151 +300 385 -27.996993 +308 385 -28.911355 +309 385 -28.817713 +310 385 -0.898821 +321 385 -1865.664033 +342 385 -16.327151 +359 385 3152.106861 +360 385 96842.106861 +361 385 405347.244761 +362 385 13902.961445 +382 385 352.318811 +383 385 71465.670686 +384 385 256351.330771 +385 385 12051864.582063 +386 385 69427.015494 +404 385 241.155079 +405 385 4300.392862 +406 385 123006.959474 +407 385 247947.122623 +408 385 191094.291989 +409 385 112398.521169 +410 385 93523.495129 +426 385 1419.599076 +427 385 2142.289598 +428 385 16876.856396 +429 385 35060.656613 +430 385 185632.217370 +431 385 126636.351960 +432 385 20568.258267 +433 385 112021.777809 +434 385 93818.363123 +435 385 1173.128553 +436 385 2685.167671 +447 385 1853.933690 +448 385 2134.186575 +449 385 2135.852409 +450 385 3125.247782 +451 385 8697.535857 +452 385 13048.513046 +453 385 22640.406996 +454 385 20240.949287 +455 385 8417.531462 +456 385 20064.650724 +457 385 128482.155784 +458 385 81164.911282 +459 385 2139.592641 +461 385 2876.928679 +472 385 193.500105 +475 385 12607.614855 +476 385 14820.682385 +477 385 9793.500634 +478 385 3143.845359 +479 385 11230.816732 +480 385 36182.618853 +481 385 111698.185878 +482 385 54652.051355 +483 385 3065.352475 +486 385 30.637473 +487 385 2719.394833 +2 386 -10.985199 +3 386 -8.958698 +5 386 -17.866260 +8 386 -21.112615 +9 386 -8.999830 +16 386 -21.462625 +17 386 -26.719061 +18 386 -26.936927 +19 386 -9.598189 +20 386 -9.136824 +21 386 -9.296669 +22 386 -21.272193 +23 386 -21.969840 +24 386 -19.996850 +25 386 -9.353025 +31 386 -22.178191 +32 386 -20.122125 +33 386 -8.933010 +34 386 -9.020703 +37 386 -20.051608 +38 386 -25.869457 +39 386 -53.407407 +42 386 -21.133828 +43 386 -20.179427 +44 386 -21.889499 +47 386 -104.314764 +51 386 -26.460454 +52 386 -26.360636 +53 386 -21.039114 +54 386 -21.042140 +55 386 -9.305509 +60 386 -9.930565 +66 386 -9.243464 +67 386 -9.249996 +68 386 -8.199440 +69 386 -12.445225 +70 386 -5.414406 +77 386 -9.532609 +79 386 -26.399513 +80 386 -20.204042 +81 386 -6.767877 +82 386 -61.818108 +84 386 -22.325610 +87 386 -9.930792 +89 386 -20.398930 +91 386 -9.307412 +97 386 -11.157861 +100 386 -9.855176 +101 386 -3.223544 +102 386 -20.077115 +106 386 -20.246528 +108 386 -20.239614 +109 386 -80.983459 +115 386 -6.713515 +117 386 -9.694996 +119 386 -80.494495 +120 386 -8.947251 +121 386 -9.162315 +122 386 -21.395146 +124 386 -21.816342 +125 386 -9.488802 +126 386 -15.832163 +129 386 -20.553090 +131 386 -21.606970 +132 386 -87.149156 +135 386 -81.792231 +136 386 -26.474491 +137 386 -4.522131 +138 386 -16.993297 +140 386 -13.571995 +141 386 -20.257677 +143 386 -19.956011 +148 386 -21.911118 +150 386 -21.829540 +152 386 -9.650883 +159 386 -21.816559 +160 386 -20.070329 +161 386 -8.815437 +163 386 -21.681134 +164 386 -20.998505 +166 386 -9.476397 +167 386 -12.378795 +168 386 -12.710982 +169 386 -9.512694 +172 386 -10.079897 +173 386 -48.763388 +175 386 -12.404284 +178 386 -15.455634 +179 386 -18.977929 +180 386 -12.064232 +182 386 -12.740946 +183 386 -9.635316 +185 386 -21.383472 +186 386 -26.016054 +187 386 -9.233498 +188 386 -20.409156 +190 386 -20.146802 +192 386 -25.771831 +193 386 -21.789848 +194 386 -16.300214 +195 386 -9.325172 +202 386 -17.680741 +204 386 -22.602665 +206 386 -12.171982 +213 386 -19.830761 +214 386 -7.328492 +215 386 -21.819580 +217 386 -9.472304 +218 386 -9.463335 +223 386 -9.421456 +224 386 -9.438153 +227 386 -9.339348 +228 386 -15.815866 +230 386 -9.341229 +231 386 -21.351890 +232 386 -21.353175 +234 386 -20.084449 +235 386 -9.428689 +240 386 -9.864016 +241 386 -24.228727 +242 386 -22.582937 +244 386 -26.592184 +245 386 -26.639492 +247 386 -12.329888 +248 386 -25.363867 +250 386 -21.301852 +252 386 -11.868874 +253 386 -20.552340 +255 386 -22.154837 +257 386 -9.418843 +258 386 -19.994884 +259 386 -19.990352 +261 386 -81.176664 +263 386 -9.286145 +265 386 -21.818070 +266 386 -20.997027 +267 386 -22.110710 +271 386 -9.194349 +272 386 -9.191119 +275 386 -25.150959 +277 386 -20.911962 +279 386 -16.771078 +280 386 -20.061898 +281 386 -14.979293 +282 386 -21.854844 +283 386 -26.762595 +284 386 -9.777483 +288 386 -9.339540 +289 386 -21.314653 +290 386 -21.292527 +292 386 -26.518579 +293 386 -20.453704 +294 386 -20.460299 +296 386 -20.256291 +300 386 -10.393048 +302 386 -9.286769 +304 386 -26.328514 +305 386 -11.699521 +306 386 -20.597127 +307 386 -9.235349 +310 386 -27.149296 +311 386 -26.260321 +312 386 -9.779754 +313 386 -11.983518 +314 386 -20.049011 +315 386 -20.989516 +316 386 -20.981140 +317 386 -9.318121 +318 386 -82.131047 +321 386 -3384.385132 +361 386 378044.598420 +362 386 81728.396002 +384 386 63.034873 +385 386 69427.015494 +386 386 11881996.330410 +387 386 459.618060 +408 386 495.367036 +409 386 57406.046652 +410 386 172813.829322 +411 386 342686.131332 +432 386 1765.888643 +433 386 59595.437462 +434 386 96650.666088 +435 386 132889.258034 +436 386 305238.636074 +455 386 549.407217 +456 386 4229.791574 +457 386 72378.989168 +458 386 75347.505455 +459 386 131351.647376 +460 386 131287.620665 +461 386 206025.159299 +478 386 379.463369 +479 386 1557.058356 +480 386 14710.358460 +481 386 69327.717216 +482 386 56032.945992 +483 386 86508.162862 +484 386 64245.954383 +485 386 195744.451109 +486 386 141715.704152 +40 387 -21.049684 +178 387 -4.399097 +191 387 -8.779243 +196 387 -8.818201 +199 387 -9.275233 +205 387 -20.822116 +207 387 -20.818753 +208 387 -20.822970 +216 387 -9.659085 +239 387 -20.827958 +254 387 -19.850813 +262 387 -80.750291 +321 387 -245.873444 +362 387 29740.954580 +386 387 459.618060 +387 387 11282842.408475 +411 387 593.128338 +412 387 32942.299730 +436 387 596.758580 +437 387 31746.729422 +438 387 715.749992 +461 387 1437.658768 +462 387 27022.811375 +463 387 4184.877669 +486 387 1791.712242 +487 387 14320.547924 +488 387 16179.323400 +388 388 11169989.842413 +389 389 11111111.111111 +390 390 11111111.111111 +391 391 11111111.111111 +392 392 11111111.111111 +393 393 11265394.735976 +251 394 -288.479340 +322 394 -31.686759 +324 394 -31.742597 +327 394 -134.435502 +329 394 -40.693879 +337 394 -10.743282 +338 394 -12.730287 +339 394 -8.476864 +340 394 -1.059671 +341 394 -16.910501 +369 394 13233.991520 +394 394 11325759.706508 +395 394 11258.938969 +396 394 2288.410729 +397 394 239.711200 +398 394 239.848922 +399 394 200.072258 +419 394 38276.443492 +420 394 20714.514547 +421 394 11127.819753 +422 394 4209.838129 +423 394 2038.768075 +424 394 189.726611 +425 394 240.181416 +426 394 240.381091 +427 394 240.607141 +428 394 230.818446 +444 394 21293.750509 +445 394 21866.758838 +446 394 13042.633981 +447 394 9942.688111 +448 394 3527.634306 +449 394 2933.468121 +450 394 2052.237541 +451 394 246.896835 +453 394 10.044973 +454 394 241.154594 +455 394 241.486361 +456 394 24.047794 +469 394 6737.736846 +470 394 29802.584301 +471 394 10130.352022 +472 394 8137.349444 +473 394 9033.270611 +474 394 3190.393251 +475 394 2379.241576 +476 394 1813.531780 +477 394 2048.062616 +494 394 6724.022239 +495 394 29561.020175 +496 394 2358.077491 +497 394 11606.062411 +498 394 3717.978654 +499 394 8333.203958 +500 394 2340.853153 +251 395 -89.893967 +268 395 -39.119927 +269 395 -39.833008 +274 395 -156.886875 +324 395 -17.888636 +325 395 -235.839810 +328 395 -12.522715 +329 395 -0.702882 +337 395 -16.581383 +338 395 -11.640237 +339 395 -15.699603 +340 395 -14.858510 +346 395 31514.333089 +347 395 23560.881455 +369 395 10153.304940 +370 395 8063.795919 +371 395 55145.033918 +394 395 11258.938969 +395 395 11321410.557562 +396 395 9852.961440 +397 395 6160.897520 +398 395 6163.322163 +399 395 5606.139203 +400 395 2801.392624 +401 395 2802.105060 +402 395 2802.910111 +403 395 2048.982031 +419 395 48087.636216 +420 395 20007.775423 +421 395 10190.275582 +422 395 7125.074473 +423 395 3775.907126 +424 395 837.354958 +425 395 3367.780784 +426 395 3370.580596 +427 395 3373.750224 +428 395 3991.333775 +429 395 2804.853278 +430 395 2806.026395 +431 395 2807.363659 +432 395 2808.893837 +433 395 2810.652588 +434 395 1318.174146 +444 395 17850.312175 +445 395 45.666616 +446 395 2574.630504 +447 395 7375.058882 +448 395 4953.133206 +449 395 5112.514744 +450 395 3800.853295 +451 395 457.266095 +453 395 140.848810 +454 395 3381.426512 +455 395 3386.078489 +456 395 337.193857 +459 395 1494.510386 +460 395 2414.306625 +471 395 103.329763 +472 395 2004.907383 +473 395 6054.794759 +474 395 4001.838666 +475 395 3672.166262 +476 395 3358.757503 +477 395 3793.121110 +497 395 170.737783 +498 395 1774.978719 +499 395 5432.639943 +500 395 2393.139185 +251 396 -63.291247 +268 396 -12.719789 +270 396 -13.542107 +322 396 -26.261897 +328 396 -33.067422 +337 396 -1.989292 +339 396 -13.369414 +340 396 -14.865119 +347 396 4540.925992 +369 396 11424.815460 +370 396 4591.466896 +371 396 437.599904 +372 396 4956.066967 +394 396 2288.410729 +395 396 9852.961440 +396 396 11241049.809766 +397 396 12280.755147 +398 396 10758.818605 +399 396 10202.303525 +400 396 7397.344095 +401 396 7399.225350 +402 396 7401.351164 +403 396 5410.532246 +421 396 6348.719404 +422 396 3609.801631 +423 396 3215.474087 +424 396 796.427416 +425 396 3369.278615 +426 396 3372.079672 +427 396 3375.250710 +428 396 5231.158304 +429 396 7406.482281 +430 396 7409.580008 +431 396 7413.111182 +432 396 7417.151763 +433 396 7421.795912 +434 396 3480.764408 +446 396 5443.157491 +447 396 102.896306 +448 396 508.524945 +449 396 3181.389309 +450 396 3236.717661 +451 396 389.397099 +453 396 140.911453 +454 396 3382.930412 +455 396 3387.584457 +456 396 337.343825 +459 396 3946.397047 +460 396 6375.206638 +471 396 5463.413960 +474 396 319.271619 +475 396 440.555007 +476 396 2860.239237 +477 396 3230.133113 +496 396 5485.456063 +500 396 74.392305 +209 397 -4.302801 +251 397 -47.945210 +268 397 -124.397016 +269 397 -81.875539 +270 397 -35.167764 +274 397 -92.423583 +322 397 -61.717469 +323 397 -18.650741 +325 397 -4.302801 +327 397 -70.767550 +328 397 -33.072564 +329 397 -54.333839 +334 397 -30.163829 +335 397 -17.697790 +336 397 -74.596888 +340 397 -14.872646 +341 397 -5.935796 +347 397 60558.530147 +352 397 537.792215 +353 397 710.364387 +369 397 9973.679404 +370 397 4592.180837 +372 397 69883.206553 +375 397 798.286519 +376 397 1022.872065 +377 397 488.482624 +394 397 239.711200 +395 397 6160.897520 +396 397 12280.755147 +397 397 11252736.680116 +398 397 24568.571062 +399 397 11222.137638 +400 397 7620.094249 +401 397 7400.375878 +402 397 7402.502022 +403 397 5411.373546 +419 397 1.281987 +420 397 1009.594120 +421 397 12949.044175 +422 397 37453.530504 +423 397 20558.755181 +424 397 560.461274 +425 397 3370.984799 +426 397 3373.787275 +427 397 3376.959919 +428 397 5233.107909 +429 397 7407.633937 +430 397 7410.732146 +431 397 7414.263869 +432 397 7418.305078 +433 397 7422.949949 +434 397 3481.305642 +444 397 796.841935 +446 397 12791.120516 +447 397 26604.397385 +448 397 29142.392840 +449 397 388.334707 +453 397 140.982809 +454 397 3384.643510 +455 397 3389.299912 +456 397 337.514654 +459 397 3947.010684 +460 397 6376.197938 +471 397 12841.181633 +472 397 20530.326826 +473 397 25935.809068 +474 397 9353.912805 +496 397 12895.461476 +497 397 16827.937780 +498 397 20834.992905 +499 397 17866.132378 +209 398 -15.508394 +212 398 -3.036386 +251 398 -47.959585 +268 398 -234.878441 +269 398 -147.516590 +270 398 -62.606192 +274 398 -156.195102 +320 398 -118.428482 +323 398 -9.215161 +324 398 -6.495439 +325 398 -18.544780 +326 398 -100.663414 +328 398 -33.078394 +329 398 -151.455675 +332 398 -66.426720 +335 398 -41.895102 +338 398 -0.234909 +340 398 -14.881191 +341 398 -106.381423 +347 398 121005.486056 +348 398 9.986832 +352 398 1938.340609 +353 398 2560.334825 +369 398 9976.613282 +370 398 4592.990342 +372 398 93207.833135 +373 398 45259.769092 +375 398 2877.228665 +376 398 3686.692378 +377 398 2379.889196 +378 398 703.056052 +379 398 133.755620 +394 398 239.848922 +395 398 6163.322163 +396 398 10758.818605 +397 398 24568.571062 +398 398 11272969.414516 +399 398 22877.934877 +400 398 8897.825201 +401 398 8102.094132 +402 398 7486.184318 +403 398 5412.327458 +419 398 4.620607 +420 398 4138.930050 +421 398 4340.552875 +422 398 3332.665444 +423 398 86255.296735 +424 398 47724.347391 +425 398 4691.835944 +426 398 3375.725628 +427 398 3378.900094 +428 398 5235.320570 +429 398 7408.939748 +430 398 7412.038503 +431 398 7415.570849 +432 398 7419.612770 +433 398 7424.258460 +434 398 3481.919324 +444 398 3422.175997 +445 398 195.437824 +448 398 52901.939187 +449 398 62818.759782 +450 398 15414.494247 +451 398 856.718524 +453 398 141.063809 +454 398 3386.588099 +455 398 3391.247177 +456 398 337.708568 +459 398 3947.706459 +460 398 6377.321928 +473 398 17374.923299 +474 398 69423.681129 +475 398 38622.039419 +476 398 4193.925718 +477 398 327.119413 +498 398 1019.056287 +499 398 64323.220081 +500 398 45289.756958 +203 399 -24.925051 +209 399 -15.543640 +211 399 -8.767050 +212 399 -34.023372 +251 399 -45.847839 +268 399 -63.032502 +269 399 -72.594748 +270 399 -33.609564 +274 399 -46.608843 +295 399 -4.010399 +297 399 -33.593898 +319 399 -0.349563 +320 399 -2.016299 +324 399 -66.287764 +325 399 -120.863410 +328 399 -33.084989 +332 399 -44.084333 +337 399 -36.891196 +338 399 -55.184571 +339 399 -9.087698 +340 399 -12.413287 +342 399 -2.293795 +347 399 48451.105254 +348 399 7148.354902 +352 399 1942.745941 +353 399 2566.153784 +356 399 249.689656 +357 399 923.120910 +358 399 925.512024 +359 399 74.155307 +369 399 9562.011986 +370 399 4671.669644 +371 399 77.764224 +372 399 2422.615860 +373 399 51442.673117 +374 399 10710.792126 +375 399 2883.767839 +376 399 3695.071248 +377 399 16432.504871 +378 399 23035.281539 +379 399 10740.258622 +380 399 919.252472 +381 399 671.362309 +394 399 200.072258 +395 399 5606.139203 +396 399 10202.303525 +397 399 11222.137638 +398 399 22877.934877 +399 399 11242400.151541 +400 399 44609.852135 +401 399 32445.673254 +402 399 17081.595544 +403 399 6049.262366 +404 399 77.773796 +405 399 77.775802 +406 399 63.738958 +419 399 4.631109 +420 399 19817.664579 +421 399 27742.408840 +422 399 26752.564574 +423 399 23436.170980 +424 399 18679.582918 +425 399 33609.986649 +426 399 14996.380418 +427 399 4725.882205 +428 399 4698.156877 +429 399 7410.416918 +430 399 7413.516291 +431 399 7417.049341 +432 399 7421.092068 +433 399 7425.738685 +434 399 3482.613537 +444 399 21919.463670 +445 399 7900.713082 +449 399 1549.249777 +450 399 18009.417664 +451 399 23729.270602 +452 399 11520.799913 +453 399 2987.570371 +454 399 2824.954652 +455 399 2828.841066 +456 399 281.702811 +459 399 3948.493540 +460 399 6378.593418 +475 399 8277.586511 +476 399 18271.293507 +477 399 15025.847285 +478 399 10753.152803 +479 399 3210.518630 +480 399 14.712667 +500 399 397.828708 +58 400 -8.070001 +116 400 -99.997629 +203 400 -33.901634 +209 400 -3.386017 +211 400 -15.039715 +212 400 -34.070207 +251 400 -47.719094 +268 400 -77.314441 +269 400 -109.202168 +274 400 -88.884698 +295 400 -33.680130 +297 400 -34.018412 +319 400 -14.626654 +322 400 -8.070001 +325 400 -154.096115 +328 400 -33.092440 +333 400 -99.997629 +337 400 -108.691885 +338 400 -1.714872 +339 400 -114.187779 +342 400 -50.806770 +347 400 54061.910795 +348 400 35255.555222 +352 400 423.206580 +353 400 559.009360 +356 400 2096.943592 +357 400 7752.553726 +358 400 7772.634784 +359 400 622.771077 +369 400 10116.813004 +370 400 7848.773291 +371 400 3253.860134 +372 400 3253.891464 +373 400 40692.767321 +374 400 64279.817672 +375 400 2376.515528 +376 400 6082.924400 +377 400 24397.153017 +378 400 29043.476647 +379 400 18565.259940 +380 400 7720.065819 +381 400 5638.234724 +395 400 2801.392624 +396 400 7397.344095 +397 400 7620.094249 +398 400 8897.825201 +399 400 44609.852135 +400 400 11527479.259050 +401 400 81367.229941 +402 400 29731.396112 +403 400 13355.711504 +404 400 3254.260632 +405 400 3254.344568 +406 400 2667.006035 +419 400 1.008838 +420 400 22426.799190 +421 400 35206.546065 +422 400 35014.406309 +423 400 39829.011306 +424 400 35774.626988 +425 400 13847.058684 +426 400 59006.401358 +427 400 27921.916274 +428 400 1994.731996 +429 400 7412.085863 +430 400 7415.185934 +431 400 7418.719780 +432 400 7422.763417 +433 400 7427.411080 +434 400 3483.397878 +444 400 27828.388104 +445 400 12753.911209 +447 400 23321.921400 +448 400 19265.195931 +449 400 157.369205 +450 400 1584.247907 +451 400 1065.315983 +452 400 46995.599103 +453 400 36962.117794 +454 400 514.220165 +459 400 3949.382804 +460 400 6380.029980 +472 400 875.276106 +474 400 1764.368891 +476 400 85.102000 +477 400 357.794808 +478 400 38947.578528 +479 400 40398.376356 +480 400 1139.753397 +499 400 1794.225669 +5 401 -0.023504 +58 401 -270.024618 +71 401 -1.810557 +82 401 -6.564811 +92 401 -1.881657 +116 401 -124.087524 +126 401 -15.758813 +194 401 -16.471481 +203 401 -33.946738 +211 401 -15.058463 +212 401 -34.123301 +214 401 -23.661057 +251 401 -47.727740 +268 401 -20.189071 +269 401 -32.070734 +274 401 -46.180060 +295 401 -33.714919 +297 401 -34.069039 +298 401 -17.073792 +319 401 -14.626884 +320 401 -13.692473 +322 401 -5.620560 +324 401 -28.005756 +325 401 -169.867909 +326 401 -120.511329 +328 401 -33.100856 +329 401 -28.106033 +331 401 -1.517178 +333 401 -188.377746 +337 401 -1.339059 +338 401 -26.649573 +339 401 -52.405421 +340 401 -37.482483 +341 401 -12.787142 +342 401 -40.347476 +347 401 18244.232994 +348 401 18410.115394 +349 401 2773.085406 +356 401 2099.109613 +357 401 7760.561662 +358 401 7780.663462 +359 401 623.414363 +369 401 10118.648346 +370 401 7849.993014 +371 401 3253.911296 +372 401 3253.942626 +373 401 9594.021387 +374 401 24544.482668 +375 401 10573.573441 +376 401 26803.456337 +377 401 30962.587125 +378 401 29083.971146 +379 401 18588.937864 +380 401 7728.040197 +381 401 5644.058692 +395 401 2802.105060 +396 401 7399.225350 +397 401 7400.375878 +398 401 8102.094132 +399 401 32445.673254 +400 401 81367.229941 +401 401 11773464.998224 +402 401 55912.483747 +403 401 17447.375533 +404 401 3678.817348 +405 401 3679.251781 +406 401 2673.423536 +420 401 21931.258425 +421 401 38700.642413 +422 401 38751.642942 +423 401 45601.721158 +424 401 46189.797868 +425 401 16280.163052 +426 401 58188.574255 +427 401 28739.635157 +428 401 14965.021485 +429 401 17258.009350 +430 401 8801.106464 +431 401 7420.606471 +432 401 7424.651137 +433 401 7429.299982 +434 401 3484.283758 +444 401 30611.700059 +445 401 16764.794110 +446 401 21.386084 +447 401 28940.280916 +448 401 23906.271383 +449 401 109.603823 +450 401 7137.714283 +451 401 15900.840636 +452 401 34749.942796 +453 401 25596.499998 +454 401 6888.269556 +455 401 8949.258552 +456 401 1290.490700 +457 401 172.319910 +459 401 3950.387192 +460 401 6381.652517 +472 401 1086.134198 +474 401 2325.636544 +475 401 14620.395814 +476 401 5964.291407 +477 401 26778.929773 +478 401 12887.901561 +479 401 19543.086407 +480 401 6116.843077 +481 401 847.944845 +482 401 200.204567 +483 401 339.319810 +499 401 7534.857598 +500 401 13812.180901 +1 402 -12.176466 +2 402 -28.458070 +3 402 -27.539594 +4 402 -28.170308 +5 402 -12.706425 +8 402 -27.388614 +10 402 -12.224284 +12 402 -12.598368 +14 402 -27.385346 +15 402 -27.385097 +17 402 -12.728116 +18 402 -11.873459 +19 402 -27.590889 +21 402 -12.169701 +22 402 -27.420235 +23 402 -12.333145 +26 402 -12.204115 +27 402 -56.332726 +31 402 -28.114022 +33 402 -12.270600 +37 402 -12.265852 +38 402 -12.401189 +39 402 -4.576064 +40 402 -51.040100 +41 402 -12.269479 +47 402 -6.133039 +52 402 -27.795374 +53 402 -27.385437 +54 402 -27.386135 +55 402 -3.531790 +57 402 -27.384852 +58 402 -138.475361 +60 402 -12.454076 +65 402 -27.533988 +68 402 -28.342398 +69 402 -12.504086 +71 402 -11.047210 +72 402 -12.168821 +77 402 -12.214667 +78 402 -12.168661 +79 402 -27.804652 +82 402 -6.891763 +84 402 -12.444092 +92 402 -33.325654 +93 402 -12.302592 +94 402 -12.261090 +119 402 -27.530287 +122 402 -27.463558 +124 402 -12.297606 +125 402 -27.429514 +126 402 -14.707389 +128 402 -7.977695 +136 402 -12.376404 +138 402 -12.319598 +143 402 -13.235814 +148 402 -27.714686 +156 402 -19.908188 +157 402 -12.611396 +159 402 -12.298553 +160 402 -12.266888 +161 402 -3.551467 +162 402 -15.149652 +163 402 -27.596530 +166 402 -27.416509 +169 402 -12.216295 +178 402 -11.212420 +186 402 -12.330770 +187 402 -12.171097 +189 402 -27.598912 +192 402 -23.710530 +193 402 -12.291791 +194 402 -14.139957 +195 402 -27.382868 +196 402 -6.822316 +197 402 -13.245077 +200 402 -12.312339 +203 402 -22.673133 +209 402 -13.951385 +211 402 -13.602539 +212 402 -4.013326 +213 402 -29.247655 +214 402 -8.905852 +215 402 -12.297065 +216 402 -5.516266 +218 402 -27.414059 +220 402 -27.401450 +221 402 -27.404218 +222 402 -27.405699 +224 402 -12.180282 +225 402 -12.178354 +231 402 -12.186154 +233 402 -12.173922 +235 402 -109.628086 +238 402 -28.137206 +239 402 -5.221509 +241 402 -27.388673 +242 402 -12.495347 +251 402 -47.737510 +268 402 -15.904993 +269 402 -15.836238 +274 402 -71.302666 +295 402 -33.754329 +297 402 -9.362910 +298 402 -265.291279 +319 402 -129.672980 +320 402 -3.901208 +321 402 -29.030803 +322 402 -85.989744 +324 402 -8.282058 +325 402 -121.071144 +328 402 -122.403960 +329 402 -3.645195 +331 402 -47.204942 +333 402 -1682.197959 +337 402 -22.554280 +338 402 -10.436519 +339 402 -47.473568 +340 402 -67.667024 +342 402 -41.544826 +347 402 17898.327045 +348 402 24527.577271 +349 402 10944.343367 +353 402 9234.452575 +354 402 2281.648728 +356 402 2101.563317 +357 402 7769.633186 +358 402 7789.758483 +359 402 3236.164790 +360 402 6611.648934 +361 402 6626.223546 +362 402 192.735244 +369 402 10120.722236 +370 402 7851.371254 +371 402 3253.969064 +372 402 3254.000395 +373 402 3254.035903 +374 402 16824.544576 +375 402 24666.610346 +376 402 32162.399678 +377 402 134092.190127 +378 402 28149.974402 +379 402 11902.181634 +380 402 7737.073706 +381 402 11962.791935 +382 402 6579.390903 +383 402 6588.585817 +384 402 3987.213902 +395 402 2802.910111 +396 402 7401.351164 +397 402 7402.502022 +398 402 7486.184318 +399 402 17081.595544 +400 402 29731.396112 +401 402 55912.483747 +402 402 12207695.318185 +403 402 120328.200464 +404 402 57147.211420 +405 402 56778.763323 +406 402 33881.422749 +420 402 11023.076703 +421 402 27086.978173 +422 402 27482.587486 +423 402 27419.342246 +424 402 17924.862518 +425 402 8477.634724 +426 402 51225.165239 +427 402 274205.331395 +428 402 65554.192767 +429 402 68033.211314 +430 402 24044.942431 +431 402 17840.999079 +432 402 27614.636063 +433 402 27643.893061 +434 402 19534.416320 +444 402 21718.202287 +445 402 16427.886014 +446 402 378.764612 +450 402 2906.146813 +451 402 95264.625379 +452 402 194559.327239 +453 402 31550.473803 +454 402 40357.676089 +455 402 39170.822538 +456 402 14476.809027 +457 402 4192.331425 +459 402 8143.348882 +460 402 23770.414753 +474 402 412.826333 +475 402 13217.128369 +476 402 113545.783582 +477 402 161590.240814 +478 402 18641.300723 +479 402 23636.093002 +480 402 40028.851705 +481 402 10492.452221 +482 402 7482.894038 +483 402 10461.464868 +499 402 2755.030736 +500 402 31231.000054 +6 403 -4.496474 +18 403 -31.108445 +27 403 -105.783558 +39 403 -37.753811 +40 403 -116.749562 +45 403 -12.720175 +47 403 -12.009546 +55 403 -17.541360 +58 403 -133.752017 +92 403 -33.347538 +128 403 -18.596553 +145 403 -72.952052 +156 403 -97.541069 +157 403 -59.626654 +161 403 -17.553113 +162 403 -44.706144 +178 403 -3.602932 +192 403 -10.230277 +196 403 -10.647542 +203 403 -126.646328 +209 403 -39.014250 +211 403 -11.191981 +212 403 -71.142945 +216 403 -13.304107 +237 403 -7.435919 +239 403 -13.948863 +251 403 -38.831762 +268 403 -5.705533 +269 403 -4.270030 +274 403 -51.074955 +295 403 -20.585677 +298 403 -170.035795 +319 403 -146.894426 +320 403 -7.265735 +321 403 -33.391322 +322 403 -126.938908 +323 403 -44.516406 +325 403 -53.933215 +326 403 -1.227490 +327 403 -122.513746 +328 403 -162.333825 +329 403 -135.508713 +331 403 -35.516375 +333 403 -397.669035 +335 403 -52.894421 +336 403 -56.038495 +340 403 -25.534143 +341 403 -11.730710 +347 403 10478.684429 +348 403 14498.835054 +349 403 7940.581592 +353 403 29405.372808 +354 403 24524.935298 +355 403 242.376561 +356 403 1281.675691 +357 403 4738.448706 +358 403 4750.722476 +359 403 3385.000438 +360 403 7604.739703 +361 403 7621.503469 +362 403 221.684693 +369 403 8229.985846 +370 403 6614.817741 +371 403 3254.034364 +372 403 3254.065696 +373 403 3254.101205 +374 403 9771.673234 +375 403 14578.066126 +376 403 33608.121377 +377 403 60690.553846 +378 403 66129.661926 +379 403 26552.004904 +380 403 4718.591729 +381 403 10706.391657 +382 403 7567.636413 +383 403 7578.212433 +384 403 4586.106154 +395 403 2048.982031 +396 403 5410.532246 +397 403 5411.373546 +398 403 5412.327458 +399 403 6049.262366 +400 403 13355.711504 +401 403 17447.375533 +402 403 120328.200464 +403 403 12190845.685189 +404 403 91518.787541 +405 403 79923.466521 +406 403 49558.990753 +420 403 2247.069077 +421 403 11786.498666 +422 403 12170.795799 +423 403 12176.793246 +424 403 11625.502156 +425 403 7504.371947 +426 403 7084.043289 +427 403 20843.546774 +428 403 122594.031477 +429 403 92764.758236 +430 403 21896.727118 +431 403 15904.063282 +432 403 36776.953330 +433 403 36827.425528 +434 403 33086.190579 +444 403 9622.431454 +445 403 9913.804145 +446 403 379.013343 +451 403 6869.367057 +452 403 51704.175258 +453 403 41703.077185 +454 403 53735.699638 +455 403 55333.514200 +456 403 19428.677823 +457 403 4033.921589 +459 403 3799.705167 +460 403 31690.919230 +476 403 21255.214993 +477 403 56958.062992 +478 403 20570.532411 +479 403 15881.403287 +480 403 56166.844894 +481 403 23605.406865 +482 403 5591.633370 +483 403 7943.304439 +500 403 12985.946839 +6 404 -22.570360 +36 404 -3.255058 +39 404 -11.639795 +45 404 -189.623080 +55 404 -0.428142 +58 404 -154.843657 +92 404 -33.372370 +116 404 -17.237002 +128 404 -133.522879 +145 404 -125.429209 +156 404 -142.051201 +157 404 -78.640309 +161 404 -0.366502 +162 404 -148.945790 +203 404 -306.602168 +211 404 -137.687923 +212 404 -349.202937 +237 404 -15.126351 +251 404 -14.627770 +269 404 -20.480093 +270 404 -7.996535 +274 404 -23.303126 +297 404 -215.377749 +298 404 -165.722420 +319 404 -181.343887 +320 404 -438.154622 +321 404 -37.215117 +322 404 -52.746200 +323 404 -95.517961 +324 404 -87.950912 +325 404 -33.372370 +326 404 -76.371472 +327 404 -41.027230 +328 404 -185.650735 +329 404 -83.559398 +330 404 -11.637788 +331 404 -22.613011 +332 404 -113.404007 +333 404 -27.560790 +334 404 -112.061162 +335 404 -191.152002 +336 404 -98.645507 +337 404 -54.167484 +338 404 -65.598997 +339 404 -66.771328 +341 404 -208.040270 +342 404 -33.490178 +347 404 8826.532926 +348 404 11751.394811 +349 404 11760.161038 +350 404 9134.700837 +351 404 1591.738527 +353 404 4566.650951 +354 404 95624.016095 +355 404 1431.514639 +359 404 3006.812619 +360 404 8250.384471 +361 404 8511.822168 +362 404 247.607444 +369 404 3091.353744 +370 404 3254.080763 +371 404 3254.108308 +372 404 3254.139640 +373 404 3254.175150 +374 404 3176.505219 +375 404 2635.517919 +376 404 36359.600056 +377 404 37087.761280 +378 404 35190.684922 +379 404 250562.796154 +380 404 645.084944 +381 404 7266.176016 +382 404 7716.172728 +383 404 8459.481845 +384 404 5467.466691 +385 404 241.155079 +399 404 77.773796 +400 404 3254.260632 +401 404 3678.817348 +402 404 57147.211420 +403 404 91518.787541 +404 404 12482620.518524 +405 404 131111.845082 +406 404 69394.007632 +407 404 8528.998481 +421 404 7119.222213 +422 404 7500.867256 +423 404 7503.532562 +424 404 7506.549360 +425 404 7509.960027 +426 404 10220.051413 +427 404 3936.671772 +428 404 41180.540359 +429 404 236473.198414 +430 404 75581.331602 +431 404 19992.313407 +432 404 34486.005616 +433 404 42359.641519 +434 404 42152.787756 +435 404 2054.878248 +444 404 5932.152892 +445 404 7496.454103 +446 404 379.295572 +447 404 3417.555279 +448 404 3920.715338 +449 404 3923.994606 +450 404 3927.707179 +451 404 801.177035 +452 404 7359.565347 +453 404 76573.020421 +454 404 136050.243592 +455 404 103694.560041 +456 404 20643.380849 +457 404 8924.517321 +459 404 294.060226 +460 404 34432.270084 +472 404 343.604811 +476 404 1021.154413 +477 404 18731.593046 +478 404 68791.017156 +479 404 96209.726716 +480 404 98865.107712 +481 404 48066.419344 +482 404 8573.983585 +483 404 7288.739541 +6 405 -21.205188 +7 405 -158.762222 +36 405 -47.290752 +45 405 -89.127183 +58 405 -167.002305 +85 405 -25.555455 +90 405 -20.179128 +92 405 -130.204014 +116 405 -67.837901 +128 405 -35.113590 +145 405 -150.841873 +155 405 -1.590496 +156 405 -106.035316 +157 405 -35.047625 +162 405 -138.977601 +201 405 -29.446783 +203 405 -71.900787 +211 405 -57.728153 +212 405 -19.497370 +237 405 -15.157385 +251 405 -14.628147 +268 405 -2.618208 +269 405 -38.549071 +270 405 -16.830345 +274 405 -136.868391 +297 405 -176.627547 +298 405 -165.795301 +308 405 -12.395799 +309 405 -12.561416 +319 405 -298.399108 +320 405 -26.720991 +321 405 -93.480666 +322 405 -56.146069 +323 405 -18.732557 +324 405 -202.372894 +325 405 -33.400622 +326 405 -26.226646 +327 405 -10.058470 +328 405 -348.305432 +329 405 -146.427475 +331 405 -73.469902 +332 405 -143.454449 +333 405 -15.157385 +336 405 -49.155833 +337 405 -114.185971 +338 405 -97.501342 +339 405 -136.542207 +341 405 -23.926459 +342 405 -51.710872 +347 405 32524.143935 +348 405 44233.098972 +349 405 44266.657691 +350 405 39825.229155 +351 405 10510.553182 +353 405 754.712537 +354 405 91591.711010 +355 405 2085.557621 +359 405 3009.608538 +360 405 17263.387009 +361 405 21638.261274 +362 405 629.839472 +369 405 3091.433478 +370 405 3254.164694 +371 405 3254.192240 +372 405 3254.223573 +373 405 3254.259084 +374 405 3176.523431 +375 405 4479.412806 +376 405 62040.011527 +377 405 70661.388324 +378 405 55811.658344 +379 405 147188.562518 +380 405 78422.872840 +381 405 14993.487261 +382 405 8850.963585 +383 405 21193.805626 +384 405 18490.998314 +385 405 4300.392862 +399 405 77.775802 +400 405 3254.344568 +401 405 3679.251781 +402 405 56778.763323 +403 405 79923.466521 +404 405 131111.845082 +405 405 12633688.230835 +406 405 158630.625958 +407 405 48931.817738 +408 405 252.794234 +421 405 7125.249041 +422 405 7507.217168 +423 405 7509.884730 +424 405 7512.904082 +425 405 7516.317636 +426 405 18674.811813 +427 405 17537.019975 +428 405 25550.946165 +429 405 53846.472500 +430 405 171328.051280 +431 405 57529.695830 +432 405 50655.256560 +433 405 79878.136183 +434 405 79782.128743 +435 405 9324.754034 +444 405 5937.174798 +445 405 7502.800278 +446 405 379.616668 +447 405 13426.598560 +448 405 15422.238515 +449 405 15434.829617 +450 405 17122.925919 +451 405 15131.320209 +452 405 15079.682827 +453 405 12419.351371 +454 405 40429.923499 +455 405 70364.341805 +456 405 89263.514302 +457 405 27518.386181 +458 405 3499.803474 +459 405 294.359829 +460 405 59540.173252 +472 405 1368.280655 +475 405 7014.879538 +476 405 6372.510043 +477 405 1306.803415 +478 405 33886.565914 +479 405 13739.533301 +480 405 28746.228695 +481 405 103465.331936 +482 405 29205.672602 +483 405 22343.600872 +1 406 -18.602982 +2 406 -9.167910 +3 406 -8.104303 +4 406 -8.737519 +5 406 -10.797896 +6 406 -58.798166 +7 406 -95.275320 +8 406 -18.575118 +13 406 -18.530332 +14 406 -18.546347 +15 406 -18.545704 +16 406 -18.797762 +17 406 -21.553636 +19 406 -18.936740 +21 406 -18.504980 +22 406 -18.674362 +25 406 -18.535979 +26 406 -8.336205 +27 406 -40.913384 +28 406 -18.561522 +30 406 -10.340295 +32 406 -8.100875 +34 406 -8.099589 +36 406 -174.872860 +37 406 -18.223794 +38 406 -20.699218 +41 406 -19.159891 +42 406 -18.588927 +43 406 -8.106022 +44 406 -76.494962 +46 406 -4.957611 +49 406 -19.034662 +50 406 -20.799257 +51 406 -9.276369 +52 406 -20.793876 +53 406 -18.547622 +54 406 -74.201620 +55 406 -4.513915 +57 406 -18.545059 +58 406 -122.370814 +59 406 -19.284057 +60 406 -19.471928 +62 406 -18.356880 +63 406 -18.883705 +64 406 -18.297963 +65 406 -8.104770 +66 406 -8.194424 +67 406 -18.442142 +69 406 -11.510742 +70 406 -26.123297 +72 406 -8.226189 +73 406 -25.890662 +75 406 -18.532036 +77 406 -8.354574 +78 406 -8.194165 +80 406 -8.099141 +83 406 -114.298733 +84 406 -19.452418 +85 406 -34.022353 +86 406 -8.251877 +87 406 -8.652119 +89 406 -18.312098 +90 406 -40.319393 +91 406 -18.495422 +92 406 -186.463857 +93 406 -18.222762 +94 406 -18.954366 +95 406 -70.372840 +96 406 -24.268532 +98 406 -96.328763 +99 406 -19.108783 +101 406 -27.403435 +103 406 -16.647193 +104 406 -8.784202 +105 406 -19.173624 +106 406 -18.260069 +107 406 -75.634908 +108 406 -18.258378 +109 406 -18.259669 +110 406 -84.706601 +111 406 -18.608251 +112 406 -63.114064 +116 406 -61.823416 +117 406 -19.071312 +118 406 -11.796667 +119 406 -18.233076 +120 406 -18.233727 +122 406 -18.761968 +123 406 -85.420915 +124 406 -19.066783 +125 406 -8.315003 +126 406 -26.062998 +127 406 -20.671065 +129 406 -18.354936 +130 406 -8.388668 +131 406 -8.386909 +132 406 -8.464343 +134 406 -22.410533 +135 406 -18.344573 +136 406 -20.885809 +137 406 -13.981223 +141 406 -18.263055 +145 406 -144.324131 +146 406 -81.096986 +148 406 -19.129899 +149 406 -18.507288 +150 406 -19.069193 +151 406 -8.226389 +152 406 -18.977980 +153 406 -8.232314 +155 406 -191.305280 +156 406 -71.218159 +157 406 -70.783058 +159 406 -19.068369 +162 406 -173.596643 +163 406 -18.968424 +166 406 -18.682772 +167 406 -25.940604 +168 406 -11.411567 +169 406 -18.787991 +173 406 -26.056128 +174 406 -3.830251 +175 406 -25.904054 +176 406 -7.906202 +177 406 -18.497856 +178 406 -17.544736 +179 406 -10.595182 +181 406 -20.627782 +182 406 -11.436428 +183 406 -18.969356 +185 406 -18.733148 +186 406 -20.612571 +187 406 -18.479934 +188 406 -4.311207 +189 406 -18.986406 +190 406 -8.102647 +194 406 -25.964583 +195 406 -18.524839 +196 406 -4.724066 +197 406 -8.221907 +199 406 -3.908519 +201 406 -62.792401 +202 406 -25.008320 +203 406 -34.043741 +204 406 -19.658966 +205 406 -8.829422 +206 406 -20.522991 +208 406 -8.840398 +211 406 -30.482148 +212 406 -31.208220 +213 406 -20.252745 +214 406 -26.768499 +215 406 -19.066989 +217 406 -18.715121 +219 406 -18.605470 +220 406 -18.630564 +221 406 -18.639575 +222 406 -18.644586 +223 406 -74.476209 +224 406 -18.641999 +227 406 -18.538195 +228 406 -25.508661 +229 406 -18.637928 +230 406 -18.546388 +231 406 -18.694558 +233 406 -18.587043 +234 406 -18.368674 +235 406 -18.638524 +237 406 -6.023210 +238 406 -19.622551 +239 406 -8.821424 +241 406 -21.246049 +242 406 -19.612373 +244 406 -21.133605 +245 406 -9.402967 +247 406 -20.844626 +250 406 -18.676164 +251 406 -11.988084 +252 406 -20.022150 +253 406 -18.371361 +257 406 -18.622248 +258 406 -18.223978 +259 406 -8.099752 +261 406 -8.124182 +262 406 -3.496322 +263 406 -18.511853 +264 406 -19.994049 +265 406 -19.067681 +266 406 -18.529734 +267 406 -19.291731 +268 406 -27.523618 +269 406 -61.300335 +270 406 -27.261777 +271 406 -18.413037 +272 406 -18.410703 +273 406 -8.377635 +274 406 -163.402632 +275 406 -8.857600 +277 406 -7.710082 +278 406 -18.629187 +279 406 -25.622690 +281 406 -22.944307 +282 406 -19.098370 +283 406 -9.845316 +284 406 -19.187190 +285 406 -18.238361 +287 406 -8.223891 +289 406 -18.691350 +290 406 -18.680294 +292 406 -8.850210 +293 406 -18.314680 +294 406 -18.317926 +296 406 -18.262576 +297 406 -10.469577 +298 406 -109.813589 +299 406 -8.103049 +300 406 -13.453460 +302 406 -18.475032 +304 406 -19.342743 +305 406 -19.335293 +306 406 -18.367935 +307 406 -8.209937 +308 406 -30.017667 +309 406 -29.994653 +310 406 -78.964649 +311 406 -19.354853 +312 406 -19.169950 +313 406 -8.674851 +314 406 -18.222995 +315 406 -18.531977 +316 406 -18.525668 +317 406 -18.518498 +318 406 -18.365360 +319 406 -3784.740859 +320 406 -15.590913 +321 406 -925.219725 +322 406 -2.225865 +323 406 -7.395374 +324 406 -92.654477 +325 406 -0.501224 +326 406 -21.779047 +327 406 -20.030003 +328 406 -467.671338 +329 406 -5.459721 +331 406 -322.997943 +332 406 -23.207795 +333 406 -6.023210 +335 406 -25.676682 +336 406 -13.095442 +337 406 -210.698444 +338 406 -43.683182 +339 406 -37.795346 +341 406 -12.891954 +342 406 -190.578003 +347 406 47113.851125 +348 406 63316.409415 +349 406 63359.750696 +350 406 58921.634467 +351 406 23143.389961 +354 406 116671.995172 +355 406 9706.517988 +359 406 499.584747 +360 406 95103.715824 +361 406 219338.057586 +362 406 6392.420540 +369 406 2533.496860 +370 406 2666.858625 +371 406 2666.881199 +372 406 2666.906877 +373 406 2666.935979 +374 406 2603.229924 +375 406 4487.164325 +376 406 60980.565473 +377 406 82271.029381 +378 406 71304.939583 +379 406 72329.290437 +380 406 166911.326910 +381 406 54121.358893 +382 406 3331.857617 +383 406 87899.673815 +384 406 216575.756629 +385 406 123006.959474 +399 406 63.738958 +400 406 2667.006035 +401 406 2673.423536 +402 406 33881.422749 +403 406 49558.990753 +404 406 69394.007632 +405 406 158630.625958 +406 406 13420309.521931 +407 406 278082.947545 +408 406 134474.942020 +421 406 106.924449 +422 406 112.656421 +423 406 112.696452 +424 406 112.741762 +425 406 112.792987 +426 406 10539.150670 +427 406 16142.106548 +428 406 49355.937648 +429 406 81250.564896 +430 406 242300.937040 +431 406 697014.249936 +432 406 203955.184667 +433 406 103373.919422 +434 406 107524.197807 +435 406 14541.696368 +444 406 89.095713 +445 406 112.590140 +446 406 5.696686 +447 406 12232.389828 +448 406 14053.592740 +449 406 14065.016522 +450 406 17622.831049 +451 406 26407.258941 +452 406 35186.052933 +453 406 26329.497104 +454 406 47828.776887 +455 406 132485.159651 +456 406 462372.044215 +457 406 133528.942002 +458 406 66728.478117 +459 406 829.005990 +460 406 78203.927986 +472 406 1249.560002 +475 406 15712.635182 +476 406 15656.904164 +477 406 4297.341540 +478 406 34609.416927 +479 406 81143.735385 +480 406 173810.616057 +481 406 348168.709496 +482 406 54419.269753 +483 406 130962.651332 +484 406 21439.487499 +6 407 -8.386655 +7 407 -31.016068 +27 407 -47.742027 +36 407 -22.762807 +46 407 -15.390490 +55 407 -5.371182 +83 407 -137.608559 +85 407 -34.102262 +90 407 -34.628453 +95 407 -138.155538 +96 407 -138.820523 +98 407 -137.823089 +103 407 -34.551595 +104 407 -15.337909 +107 407 -138.085868 +110 407 -137.968516 +112 407 -138.253626 +116 407 -28.465306 +118 407 -34.619309 +123 407 -137.959420 +134 407 -34.476524 +146 407 -138.014798 +154 407 -23.366239 +155 407 -34.201090 +156 407 -14.545566 +157 407 -16.024907 +162 407 -0.848221 +174 407 -34.740478 +176 407 -34.676861 +178 407 -1.753651 +188 407 -5.821023 +196 407 -4.953089 +199 407 -6.926304 +201 407 -34.332236 +203 407 -30.760694 +205 407 -15.470811 +208 407 -15.435861 +211 407 -34.565797 +212 407 -34.553683 +237 407 -29.589403 +239 407 -15.496383 +256 407 -7.677250 +262 407 -8.637194 +269 407 -18.931630 +270 407 -8.941742 +274 407 -103.855117 +277 407 -0.878983 +295 407 -39.770240 +297 407 -35.120745 +308 407 -23.137921 +309 407 -23.496901 +319 407 -128.486509 +321 407 -1719.480166 +327 407 -3.792852 +328 407 -311.664220 +329 407 -32.330003 +334 407 -3.647385 +337 407 -10.844830 +342 407 -37.804583 +347 407 21830.683226 +348 407 29916.863683 +349 407 29940.142546 +350 407 27419.072369 +351 407 7094.169324 +354 407 6767.510149 +355 407 7334.730030 +358 407 5818.616827 +359 407 1176.884532 +360 407 158752.389050 +361 407 409128.478766 +362 407 11926.078064 +375 407 2547.420093 +376 407 22902.146838 +377 407 30030.097055 +378 407 30949.036258 +379 407 39438.749921 +380 407 27491.514574 +381 407 28869.171676 +382 407 8179.736278 +383 407 133724.949292 +384 407 400205.744394 +385 407 247947.122623 +404 407 8528.998481 +405 407 48931.817738 +406 407 278082.947545 +407 407 13007009.515157 +408 407 301040.447209 +409 407 5695.119708 +426 407 4300.449738 +427 407 6489.725795 +428 407 33642.672247 +429 407 63834.446676 +430 407 287500.762496 +431 407 185437.668198 +432 407 52724.947794 +433 407 54721.663741 +434 407 72135.222337 +435 407 20945.171101 +447 407 5616.197409 +448 407 6465.178973 +449 407 6470.225351 +450 407 8402.557628 +451 407 15942.449042 +452 407 18833.828067 +453 407 25805.735718 +454 407 17246.895883 +455 407 5497.684063 +456 407 5585.945285 +457 407 12961.836603 +458 407 22181.464165 +459 407 1749.483494 +460 407 42296.587291 +472 407 586.177810 +475 407 12310.522285 +476 407 12934.836702 +477 407 7910.242071 +479 407 665.474446 +480 407 7470.565124 +481 407 1496.053673 +482 407 554.705246 +483 407 23279.808445 +484 407 10415.367176 +36 408 -36.230486 +46 408 -12.717033 +83 408 -74.295615 +85 408 -1.110175 +90 408 -28.607372 +95 408 -99.526073 +96 408 -126.322907 +98 408 -84.583654 +101 408 -1.579275 +103 408 -25.428223 +104 408 -10.501686 +107 408 -96.488713 +110 408 -91.262083 +112 408 -103.722858 +118 408 -28.240030 +123 408 -90.851049 +134 408 -22.105897 +137 408 -13.671586 +146 408 -93.340290 +154 408 -35.187240 +155 408 -7.545027 +156 408 -36.221890 +157 408 -36.152900 +174 408 -32.890877 +176 408 -30.506087 +201 408 -15.006935 +211 408 -13.229371 +212 408 -12.862376 +237 408 -35.055885 +256 408 -15.701435 +295 408 -112.349420 +297 408 -26.834863 +308 408 -35.192294 +309 408 -35.184356 +321 408 -1246.624657 +323 408 -24.039115 +327 408 -8.437103 +328 408 -161.531887 +334 408 -23.296495 +335 408 -10.083503 +339 408 -23.164157 +341 408 -23.329048 +354 408 15578.273087 +355 408 14675.673350 +358 408 7212.907936 +359 408 8962.076920 +360 408 104685.233779 +361 408 297198.718193 +362 408 8679.543417 +379 408 4102.294809 +380 408 15128.953681 +381 408 32469.838148 +382 408 15395.012989 +383 408 89398.328139 +384 408 284584.411460 +385 408 191094.291989 +386 408 495.367036 +405 408 252.794234 +406 408 134474.942020 +407 408 301040.447209 +408 408 12812241.161262 +409 408 13456.027558 +410 408 43.679709 +428 408 13909.852995 +429 408 33802.489839 +430 408 211026.578369 +431 408 149855.232137 +432 408 20508.570218 +433 408 20770.184851 +434 408 36354.607176 +435 408 17165.494567 +450 408 842.143312 +451 408 8306.232073 +452 408 14507.740192 +453 408 26714.547817 +454 408 24694.529513 +455 408 6374.066291 +456 408 4153.663851 +457 408 7459.507513 +458 408 12134.946964 +460 408 16884.312652 +475 408 15416.364415 +476 408 18088.620140 +477 408 11938.826545 +478 408 1147.217089 +479 408 3529.978963 +480 408 2046.518581 +481 408 6337.506051 +482 408 4220.152875 +483 408 9198.014330 +5 409 -8.074397 +20 409 -0.296058 +36 409 -4.453979 +39 409 -85.540701 +68 409 -2.861670 +69 409 -24.196563 +70 409 -11.120106 +81 409 -6.984844 +82 409 -60.175500 +101 409 -16.726444 +115 409 -7.146451 +126 409 -13.931320 +137 409 -34.981150 +138 409 -10.560135 +140 409 -20.709556 +154 409 -6.868757 +156 409 -4.357923 +157 409 -3.574929 +161 409 -35.917113 +167 409 -24.404391 +168 409 -23.367643 +173 409 -99.974975 +175 409 -24.324620 +179 409 -4.968479 +180 409 -25.391901 +182 409 -23.274433 +194 409 -12.563420 +202 409 -8.599189 +213 409 -2.630050 +214 409 -5.339918 +228 409 -13.979167 +237 409 -3.223111 +256 409 -4.650220 +279 409 -11.199553 +281 409 -16.455308 +295 409 -63.255599 +300 409 -30.732091 +308 409 -7.002995 +309 409 -6.791950 +320 409 -9.911904 +321 409 -694.964178 +326 409 -9.905555 +328 409 -12.386831 +332 409 -10.121617 +337 409 -23.309325 +338 409 -10.007197 +354 409 1715.950065 +355 409 1614.937995 +359 409 9002.971503 +360 409 1291.257421 +361 409 133154.114537 +362 409 5605.654139 +380 409 295.914731 +381 409 2991.987475 +382 409 1761.987240 +384 409 15822.467522 +385 409 112398.521169 +386 409 57406.046652 +407 409 5695.119708 +408 409 13456.027558 +409 409 12552762.248832 +410 409 72856.986832 +430 409 3930.555511 +431 409 5507.040576 +432 409 13346.333393 +433 409 108406.488428 +434 409 84823.383468 +435 409 3036.481446 +452 409 872.413089 +453 409 3221.014588 +454 409 4524.944962 +455 409 5172.931520 +456 409 20816.695270 +457 409 123527.091891 +458 409 61679.767515 +459 409 6058.076985 +460 409 4741.043588 +475 409 2272.000639 +476 409 3206.286778 +477 409 2340.761884 +478 409 2935.356051 +479 409 10861.067125 +480 409 36929.821158 +481 409 103639.421335 +482 409 37033.807912 +483 409 144.188126 +484 409 4624.919105 +485 409 4825.059230 +2 410 -5.057559 +5 410 -26.954536 +17 410 -23.747794 +18 410 -24.907327 +20 410 -14.433768 +38 410 -18.932009 +39 410 -69.764831 +47 410 -80.665512 +51 410 -22.334460 +52 410 -21.777414 +68 410 -12.515057 +69 410 -15.492393 +70 410 -6.633377 +79 410 -21.995163 +81 410 -9.525732 +82 410 -87.647191 +97 410 -6.261445 +101 410 -1.818414 +115 410 -9.410798 +126 410 -22.707398 +136 410 -22.412265 +138 410 -25.139716 +140 410 -17.912490 +161 410 -7.564412 +167 410 -15.349100 +168 410 -16.064958 +173 410 -59.773284 +175 410 -15.404088 +179 410 -29.248487 +180 410 -14.669654 +182 410 -16.129446 +186 410 -19.800478 +192 410 -18.343829 +194 410 -23.690394 +202 410 -26.569848 +206 410 -13.087746 +213 410 -30.995406 +214 410 -10.704949 +228 410 -22.673111 +241 410 -30.978222 +244 410 -23.059613 +245 410 -23.317364 +247 410 -12.880223 +248 410 -30.395473 +252 410 -10.520812 +275 410 -14.395244 +279 410 -24.675844 +281 410 -20.907413 +283 410 -29.728180 +292 410 -22.655801 +295 410 -28.694098 +300 410 -11.034579 +304 410 -21.596720 +305 410 -9.587038 +310 410 -29.553091 +311 410 -21.210744 +313 410 -11.130603 +321 410 -1255.742803 +342 410 -28.694098 +359 410 5539.659993 +361 410 201746.306724 +362 410 11718.329630 +384 410 2688.965190 +385 410 93523.495129 +386 410 172813.829322 +408 410 43.679709 +409 410 72856.986832 +410 410 12201410.585332 +411 410 18674.427652 +432 410 603.431041 +433 410 75264.299594 +434 410 129215.890481 +435 410 94901.040334 +436 410 4719.039225 +456 410 2698.244522 +457 410 93058.358631 +458 410 106448.907548 +459 410 114364.396512 +460 410 3736.648786 +461 410 5056.048988 +479 410 262.177256 +480 410 16623.457065 +481 410 91827.786469 +482 410 81683.667443 +483 410 81929.571942 +484 410 48285.859952 +486 410 53.843728 +487 410 4779.191640 +2 411 -6.366862 +3 411 -9.049106 +8 411 -21.527227 +9 411 -9.101684 +16 411 -21.939985 +17 411 -4.266741 +18 411 -3.359047 +19 411 -9.820563 +21 411 -9.464494 +22 411 -21.715905 +23 411 -22.532709 +24 411 -20.148642 +25 411 -9.531627 +31 411 -22.774947 +32 411 -20.315179 +33 411 -9.015698 +34 411 -9.128025 +37 411 -20.222362 +38 411 -8.101620 +42 411 -21.552363 +43 411 -20.389275 +44 411 -22.439137 +47 411 -28.434643 +51 411 -5.381311 +52 411 -5.823086 +53 411 -21.439990 +54 411 -21.443587 +55 411 -9.475048 +60 411 -10.207594 +66 411 -9.400764 +67 411 -9.408609 +77 411 -9.743665 +79 411 -5.650229 +80 411 -20.420808 +84 411 -22.946025 +87 411 -10.207857 +89 411 -20.665816 +91 411 -9.477318 +97 411 -5.361901 +100 411 -10.120111 +102 411 -20.256176 +106 411 -20.474874 +108 411 -20.466105 +109 411 -81.896136 +117 411 -9.933693 +119 411 -81.268521 +120 411 -9.034281 +121 411 -9.302732 +122 411 -21.860702 +124 411 -22.353844 +125 411 -9.692159 +129 411 -20.855465 +131 411 -22.109196 +132 411 -89.279780 +135 411 -82.906296 +136 411 -5.319718 +141 411 -20.488993 +143 411 -20.092392 +148 411 -22.464326 +150 411 -22.369237 +152 411 -9.882193 +159 411 -22.354096 +160 411 -20.247209 +163 411 -22.195954 +164 411 -21.391690 +166 411 -9.677551 +169 411 -9.720265 +172 411 -10.380524 +178 411 -19.945201 +183 411 -9.864000 +185 411 -21.846973 +186 411 -7.402281 +187 411 -9.388782 +188 411 -20.678490 +190 411 -20.347215 +192 411 -8.577192 +193 411 -22.322931 +195 411 -9.498491 +204 411 -23.266973 +215 411 -22.357621 +217 411 -9.672730 +218 411 -9.662158 +223 411 -9.612721 +224 411 -9.632448 +227 411 -9.515365 +230 411 -9.517604 +231 411 -21.809813 +232 411 -21.811326 +234 411 -20.265845 +235 411 -9.621270 +240 411 -10.130376 +242 411 -23.244140 +244 411 -4.808321 +245 411 -4.605227 +247 411 -0.096891 +250 411 -21.750876 +252 411 -1.922853 +253 411 -20.854549 +255 411 -22.747822 +257 411 -9.609632 +258 411 -20.145962 +259 411 -20.139774 +261 411 -82.140074 +263 411 -9.451917 +265 411 -22.355860 +266 411 -21.389930 +267 411 -22.696552 +271 411 -9.341567 +272 411 -9.337660 +275 411 -11.810027 +277 411 -21.288490 +280 411 -20.236040 +282 411 -22.398744 +284 411 -10.029795 +288 411 -9.515594 +289 411 -21.765961 +290 411 -21.739884 +292 411 -5.127105 +293 411 -20.733537 +294 411 -20.741663 +296 411 -20.487239 +302 411 -9.452664 +304 411 -5.966691 +305 411 -2.661011 +306 411 -20.909154 +307 411 -9.391009 +311 411 -6.273937 +312 411 -10.032437 +313 411 -1.445585 +314 411 -20.218903 +315 411 -21.380988 +316 411 -21.371013 +317 411 -9.490090 +318 411 -83.322463 +321 411 -2387.823106 +361 411 216423.329800 +362 411 73444.835313 +386 411 342686.131332 +387 411 593.128338 +410 411 18674.427652 +411 411 11928130.957006 +434 411 1125.897475 +435 411 45357.386712 +436 411 311095.972338 +458 411 0.182723 +459 411 25521.241436 +460 411 130877.542143 +461 411 209477.923053 +483 411 12011.752062 +484 411 18884.344872 +485 411 200165.196559 +486 411 143929.626163 +40 412 -20.581967 +191 412 -8.781986 +196 412 -8.757410 +199 412 -9.083542 +205 412 -20.400615 +207 412 -20.397955 +208 412 -20.401290 +216 412 -9.394566 +239 412 -20.405235 +254 412 -19.708437 +262 412 -79.673921 +321 412 -237.586924 +362 412 28759.766406 +387 412 32942.299730 +412 412 11411877.093390 +437 412 31241.707682 +438 412 696.148820 +461 412 836.575215 +462 412 26603.493802 +463 412 4087.263795 +486 412 1185.174867 +487 412 14153.223753 +488 412 15836.571704 +413 413 11224946.427183 +414 414 11111111.111111 +415 415 11111111.111111 +416 416 11111111.111111 +417 417 11111111.111111 +418 418 11391147.167632 +209 419 -0.019589 +251 419 -169.658110 +268 419 -30.546915 +269 419 -29.118527 +274 419 -121.327779 +322 419 -31.603158 +325 419 -181.012810 +327 419 -133.342423 +341 419 -4.712528 +346 419 24247.541585 +347 419 18087.458419 +352 419 2.448309 +353 419 3.233947 +369 419 6342.856013 +370 419 4894.433689 +371 419 42274.356081 +375 419 3.634215 +376 419 4.656645 +377 419 2.223826 +394 419 38276.443492 +395 419 48087.636216 +397 419 1.281987 +398 419 4.620607 +399 419 4.631109 +400 419 1.008838 +419 419 11456691.158339 +420 419 12925.544136 +421 419 4.603280 +422 419 3.329392 +444 419 34858.430059 +445 419 16416.243396 +446 419 139.405170 +469 419 6719.960476 +470 419 29560.262889 +471 419 1155.942973 +494 419 6706.282053 +495 419 29320.662893 +496 419 657.136498 +497 419 479.620350 +203 420 -21.367282 +209 420 -15.426463 +211 420 -8.922973 +212 420 -24.364007 +251 420 -83.317518 +268 420 -9.290342 +269 420 -11.485343 +274 420 -38.458817 +295 420 -16.147473 +297 420 -23.510137 +298 420 -2.333197 +324 420 -24.607922 +325 420 -171.306034 +329 420 -40.595791 +338 420 -6.171684 +341 420 -11.942121 +346 420 7851.858409 +347 420 5911.657567 +352 420 1928.100319 +353 420 2546.808528 +356 420 1005.350663 +357 420 3716.854884 +358 420 3726.482469 +359 420 298.578997 +369 420 4174.592766 +370 420 1547.415245 +371 420 13897.624078 +375 420 2862.028211 +376 420 3667.215513 +377 420 12492.266529 +378 420 18871.328286 +379 420 11013.557405 +380 420 3701.279005 +381 420 2703.173820 +394 420 20714.514547 +395 420 20007.775423 +397 420 1009.594120 +398 420 4138.930050 +399 420 19817.664579 +400 420 22426.799190 +401 420 21931.258425 +402 420 11023.076703 +403 420 2247.069077 +419 420 12925.544136 +420 420 11388110.133389 +421 420 31252.074213 +422 420 24709.904519 +423 420 21608.413553 +424 420 5961.284399 +425 420 525.967012 +426 420 256.982532 +444 420 24787.992608 +445 420 13469.806111 +446 420 11889.576882 +447 420 6261.061491 +448 420 378.785149 +471 420 8897.231109 +472 420 7358.874324 +473 420 6204.780197 +474 420 710.793873 +496 420 1665.263933 +497 420 11076.575934 +498 420 3012.674895 +499 420 5850.511000 +500 420 940.078698 +92 421 -31.557225 +203 421 -33.768405 +209 421 -15.450239 +211 421 -14.984309 +212 421 -33.913592 +251 421 -57.993145 +268 421 -30.552973 +269 421 -13.295850 +270 421 -13.582325 +274 421 -26.905108 +295 421 -33.577188 +297 421 -33.869014 +298 421 -33.288909 +322 421 -84.336256 +324 421 -23.604922 +325 421 -230.408880 +337 421 -14.656930 +338 421 -17.368378 +339 421 -2.362916 +347 421 15110.119806 +352 421 1931.072010 +353 421 2550.733805 +356 421 2090.534380 +357 421 7728.858398 +358 421 7748.878078 +359 421 620.867605 +369 421 3745.215498 +371 421 438.899508 +372 421 16874.789976 +375 421 2866.439322 +376 421 3672.867621 +377 421 17262.260560 +378 421 28923.923964 +379 421 18495.313602 +380 421 7696.469788 +381 421 5621.001716 +394 421 11127.819753 +395 421 10190.275582 +396 421 6348.719404 +397 421 12949.044175 +398 421 4340.552875 +399 421 27742.408840 +400 421 35206.546065 +401 421 38700.642413 +402 421 27086.978173 +403 421 11786.498666 +404 421 7119.222213 +405 421 7125.249041 +406 421 106.924449 +419 421 4.603280 +420 421 31252.074213 +421 421 11395423.788094 +422 421 55770.542371 +423 421 48798.490537 +424 421 24920.696700 +425 421 14605.728747 +426 421 10370.226891 +444 421 41490.019604 +445 421 26757.439205 +446 421 21063.346326 +447 421 9910.100308 +448 421 4812.745861 +449 421 1944.708446 +450 421 572.058853 +451 421 68.822209 +471 421 17546.562785 +472 421 2537.891664 +473 421 8423.166540 +474 421 4352.684283 +475 421 3245.970612 +476 421 505.519896 +477 421 570.895097 +496 421 17619.637951 +498 421 2328.806864 +499 421 7499.830676 +500 421 3193.689293 +92 422 -33.248935 +203 422 -33.795683 +209 422 -11.174617 +211 422 -14.995657 +212 422 -33.945632 +237 422 -0.775205 +251 422 -29.089986 +268 422 -60.580129 +269 422 -44.061159 +270 422 -13.455590 +274 422 -60.704181 +295 422 -33.598286 +297 422 -33.899585 +298 422 -33.300892 +322 422 -3.923426 +325 422 -228.734492 +327 422 -70.494023 +334 422 -30.187076 +336 422 -74.196535 +337 422 -13.320179 +339 422 -15.769807 +347 422 32202.394729 +352 422 1396.676809 +353 422 1844.856502 +356 422 2091.847992 +357 422 7733.714920 +358 422 7753.747180 +359 422 621.257735 +369 422 2542.095984 +372 422 36867.052695 +375 422 2073.195254 +376 422 2656.456623 +377 422 16790.858992 +378 422 28948.394384 +379 422 18509.635492 +380 422 7701.305959 +381 422 5624.533740 +394 422 4209.838129 +395 422 7125.074473 +396 422 3609.801631 +397 422 37453.530504 +398 422 3332.665444 +399 422 26752.564574 +400 422 35014.406309 +401 422 38751.642942 +402 422 27482.587486 +403 422 12170.795799 +404 422 7500.867256 +405 422 7507.217168 +406 422 112.656421 +419 422 3.329392 +420 422 24709.904519 +421 422 55770.542371 +422 422 11340882.389612 +423 422 52606.221406 +424 422 25720.716822 +425 422 15161.995688 +426 422 10903.809578 +427 422 172.914619 +428 422 172.940648 +429 422 172.970134 +430 422 173.003620 +431 422 141.026017 +444 422 41159.911505 +445 422 27322.762886 +446 422 1363.836051 +447 422 27373.668951 +448 422 12546.484579 +449 422 4813.057380 +450 422 3817.849590 +451 422 459.310855 +471 422 816.354450 +472 422 20479.584768 +473 422 15078.478762 +474 422 2137.823396 +475 422 2949.929608 +476 422 3373.776876 +477 422 3810.082829 +496 422 819.844641 +497 422 16791.226680 +498 422 18677.324742 +500 422 498.126361 +92 423 -33.260749 +95 423 -10.748523 +116 423 -35.844346 +134 423 -23.183010 +171 423 -9.956765 +203 423 -33.826676 +211 423 -15.008548 +212 423 -30.945667 +237 423 -14.658555 +251 423 -15.812605 +268 423 -215.097633 +269 423 -107.061582 +270 423 -69.214644 +274 423 -94.249252 +295 423 -33.622245 +297 423 -33.934332 +298 423 -33.314489 +320 423 -16.794290 +323 423 -27.607258 +325 423 -272.459559 +326 423 -67.966912 +329 423 -203.458996 +333 423 -35.844346 +335 423 -58.986849 +339 423 -15.812605 +341 423 -110.808805 +347 423 93259.499465 +356 423 2093.339697 +357 423 7739.229862 +358 423 7759.276408 +359 423 621.700756 +369 423 1541.989937 +372 423 96550.381031 +373 423 10997.497619 +376 423 1730.873767 +377 423 17942.815454 +378 423 28273.146742 +379 423 18392.152242 +380 423 7706.797791 +381 423 5628.544618 +394 423 2038.768075 +395 423 3775.907126 +396 423 3215.474087 +397 423 20558.755181 +398 423 86255.296735 +399 423 23436.170980 +400 423 39829.011306 +401 423 45601.721158 +402 423 27419.342246 +403 423 12176.793246 +404 423 7503.532562 +405 423 7509.884730 +406 423 112.696452 +420 423 21608.413553 +421 423 48798.490537 +422 423 52606.221406 +423 423 11328945.670839 +424 423 55187.033120 +425 423 31169.484656 +426 423 23785.705687 +427 423 13052.203772 +428 423 13053.813144 +429 423 13055.636168 +430 423 5862.965223 +431 423 2666.696508 +444 423 48757.939492 +445 423 40016.487085 +446 423 13423.797479 +447 423 21233.492898 +448 423 83631.466663 +449 423 35054.887679 +450 423 3828.210908 +451 423 460.557385 +472 423 313.744437 +473 423 27853.748667 +474 423 70499.216264 +475 423 3947.703787 +476 423 3382.933018 +477 423 3820.423069 +498 423 3053.225532 +499 423 80931.469405 +500 423 17114.606388 +92 424 -33.274121 +95 424 -32.957510 +116 424 -150.654118 +134 424 -32.969827 +171 424 -32.956830 +174 424 -1.811931 +176 424 -15.790012 +203 424 -8.936769 +211 424 -6.256112 +237 424 -14.659911 +251 424 -3.639379 +256 424 -11.228781 +268 424 -77.544901 +269 424 -74.943001 +270 424 -17.165304 +274 424 -86.015515 +295 424 -29.638997 +297 424 -0.379847 +298 424 -33.329880 +320 424 -101.296685 +324 424 -14.836421 +325 424 -254.190528 +326 424 -31.073813 +332 424 -107.492203 +333 424 -150.654118 +338 424 -0.969600 +339 424 -1.161796 +340 424 -2.477583 +347 424 55835.084854 +348 424 92.525602 +356 424 1845.340402 +357 424 6822.358343 +358 424 6840.029962 +359 424 548.047469 +369 424 605.091752 +372 424 17820.751016 +373 424 45680.139711 +374 424 19.943347 +376 424 7274.878378 +377 424 13597.950484 +378 424 5972.459341 +379 424 7804.100003 +380 424 6793.768520 +381 424 4961.727331 +394 424 189.726611 +395 424 837.354958 +396 424 796.427416 +397 424 560.461274 +398 424 47724.347391 +399 424 18679.582918 +400 424 35774.626988 +401 424 46189.797868 +402 424 17924.862518 +403 424 11625.502156 +404 424 7506.549360 +405 424 7512.904082 +406 424 112.741762 +420 424 5961.284399 +421 424 24920.696700 +422 424 25720.716822 +423 424 55187.033120 +424 424 11326651.122949 +425 424 63662.329156 +426 424 43028.574706 +427 424 32292.639457 +428 424 32273.141973 +429 424 31737.311474 +430 424 12661.829104 +431 424 4043.072941 +444 424 45077.609450 +445 424 51000.342888 +446 424 32094.713198 +447 424 66681.573123 +448 424 47696.094314 +449 424 35137.375858 +450 424 25452.008136 +451 424 2202.752189 +453 424 23.485837 +454 424 563.836029 +455 424 564.611723 +456 424 56.225396 +472 424 1318.670758 +474 424 7229.440112 +475 424 41894.159288 +476 424 8341.061684 +477 424 1210.620020 +499 424 290.674519 +500 424 27748.809868 +58 425 -13.910080 +92 425 -33.289240 +95 425 -32.959869 +96 425 -120.807368 +116 425 -51.589203 +134 425 -32.972676 +171 425 -32.959163 +174 425 -14.637737 +176 425 -32.940528 +237 425 -14.661441 +251 425 -14.901820 +256 425 -14.642663 +268 425 -36.854219 +269 425 -40.033927 +270 425 -29.107423 +274 425 -17.288943 +298 425 -33.347285 +322 425 -13.910080 +324 425 -55.616527 +325 425 -363.217969 +332 425 -0.390681 +333 425 -51.589203 +337 425 -13.140798 +338 425 -54.136506 +340 425 -14.901820 +347 425 28162.718563 +348 425 3285.479965 +369 425 2957.995258 +372 425 624.335320 +373 425 32515.736814 +374 425 3664.839786 +376 425 3265.525522 +377 425 4352.223900 +394 425 240.181416 +395 425 3367.780784 +396 425 3369.278615 +397 425 3370.984799 +398 425 4691.835944 +399 425 33609.986649 +400 425 13847.058684 +401 425 16280.163052 +402 425 8477.634724 +403 425 7504.371947 +404 425 7509.960027 +405 425 7516.317636 +406 425 112.792987 +420 425 525.967012 +421 425 14605.728747 +422 425 15161.995688 +423 425 31169.484656 +424 425 63662.329156 +425 425 11615958.720750 +426 425 83655.777419 +427 425 69487.540686 +428 425 69316.029171 +429 425 66076.248420 +430 425 19567.021939 +431 425 4461.735640 +444 425 64123.389692 +445 425 80494.363454 +446 425 66421.319745 +447 425 77904.578143 +448 425 62937.996151 +449 425 34598.676274 +450 425 12336.274616 +451 425 21859.452008 +452 425 3652.112838 +453 425 281.297106 +454 425 3391.282807 +455 425 3395.948343 +456 425 338.176721 +472 425 451.558671 +474 425 3041.203110 +475 425 58.783474 +476 425 13764.935275 +477 425 14239.852625 +478 425 3607.752179 +479 425 160.341161 +499 425 3092.666570 +2 426 -25.500777 +4 426 -18.027776 +5 426 -12.875755 +12 426 -10.201625 +17 426 -12.867891 +38 426 -3.024245 +58 426 -160.645139 +60 426 -5.583511 +68 426 -22.857023 +69 426 -7.481691 +71 426 -13.021485 +79 426 -0.586813 +82 426 -13.693394 +84 426 -5.150994 +92 426 -31.424671 +95 426 -32.962533 +96 426 -131.734316 +116 426 -50.493393 +126 426 -31.020298 +134 426 -32.975892 +136 426 -1.544303 +171 426 -32.961796 +174 426 -14.638443 +176 426 -32.942358 +194 426 -31.181685 +209 426 -0.165961 +214 426 -33.345011 +237 426 -14.663170 +238 426 -16.936314 +242 426 -7.178318 +251 426 -14.914209 +256 426 -14.643581 +268 426 -69.781336 +269 426 -96.080792 +274 426 -69.898656 +298 426 -135.540120 +319 426 -28.144742 +320 426 -8.440456 +321 426 -22.348651 +322 426 -109.159672 +325 426 -355.239930 +326 426 -111.359594 +329 426 -38.421560 +333 426 -272.078909 +337 426 -119.022391 +339 426 -85.761229 +340 426 -14.914209 +341 426 -12.676769 +342 426 -30.977164 +347 426 46516.254022 +348 426 28979.499535 +353 426 19.784231 +360 426 3764.084744 +361 426 5204.317422 +362 426 151.531344 +369 426 2960.454394 +373 426 33456.494015 +374 426 50735.707484 +375 426 994.875340 +376 426 8776.197447 +377 426 19638.257386 +378 426 33.167740 +382 426 837.952599 +383 426 5151.255707 +384 426 5166.196239 +385 426 1419.599076 +394 426 240.381091 +395 426 3370.580596 +396 426 3372.079672 +397 426 3373.787275 +398 426 3375.725628 +399 426 14996.380418 +400 426 59006.401358 +401 426 58188.574255 +402 426 51225.165239 +403 426 7084.043289 +404 426 10220.051413 +405 426 18674.811813 +406 426 10539.150670 +407 426 4300.449738 +420 426 256.982532 +421 426 10370.226891 +422 426 10903.809578 +423 426 23785.705687 +424 426 43028.574706 +425 426 83655.777419 +426 426 12064397.891072 +427 426 117545.166906 +428 426 83296.439060 +429 426 76941.029382 +430 426 19945.421511 +431 426 4462.162590 +444 426 62683.553736 +445 426 78943.221465 +446 426 68835.425049 +447 426 78305.344646 +448 426 66913.552513 +449 426 48250.086445 +450 426 23077.652821 +451 426 83995.187085 +452 426 68778.012240 +453 426 26938.862828 +454 426 3634.993652 +455 426 3398.771573 +456 426 338.457865 +472 426 1016.024922 +474 426 1545.691446 +475 426 45409.433422 +476 426 43524.672245 +477 426 23948.389912 +478 426 38960.522914 +479 426 29414.575986 +480 426 579.957882 +499 426 9904.924926 +500 426 51409.245373 +1 427 -12.190485 +2 427 -3.257855 +3 427 -27.415523 +4 427 -10.396084 +8 427 -27.409980 +10 427 -12.266240 +12 427 -2.522512 +14 427 -27.401624 +15 427 -27.400943 +17 427 -0.005789 +19 427 -27.715929 +21 427 -12.173765 +22 427 -27.471265 +23 427 -12.408069 +26 427 -12.236984 +31 427 -27.849393 +33 427 -12.205057 +37 427 -12.201807 +38 427 -9.467112 +41 427 -12.204287 +52 427 -27.974791 +53 427 -27.401874 +54 427 -27.403736 +57 427 -27.400265 +58 427 -106.206667 +60 427 -6.971240 +65 427 -27.412003 +68 427 -5.767723 +69 427 -5.132259 +72 427 -12.170251 +77 427 -12.252534 +78 427 -12.161205 +79 427 -27.399384 +84 427 -7.391859 +93 427 -12.227692 +94 427 -12.316179 +95 427 -32.965541 +96 427 -131.740949 +116 427 -67.527293 +119 427 -27.409698 +122 427 -27.539659 +124 427 -12.363407 +125 427 -27.486728 +128 427 -17.229942 +134 427 -32.979525 +136 427 -10.916983 +138 427 -12.240140 +143 427 -6.030894 +145 427 -2.572125 +148 427 -27.874590 +156 427 -36.928717 +157 427 -32.285847 +159 427 -12.364611 +160 427 -12.202514 +162 427 -32.265118 +163 427 -27.723341 +166 427 -27.464867 +169 427 -12.254881 +171 427 -32.964770 +174 427 -14.639241 +176 427 -32.944426 +186 427 -12.405115 +187 427 -12.178040 +189 427 -27.726465 +193 427 -12.355992 +195 427 -27.394406 +197 427 -5.925675 +200 427 -12.234797 +201 427 -10.531149 +203 427 -10.131458 +209 427 -24.854092 +212 427 -14.790475 +213 427 -20.858367 +215 427 -12.362718 +218 427 -27.460587 +220 427 -27.437368 +221 427 -27.442675 +222 427 -27.445458 +224 427 -12.197929 +225 427 -12.194254 +231 427 -12.208399 +233 427 -12.185026 +235 427 -109.791658 +237 427 -14.665122 +238 427 -11.448622 +241 427 -27.410123 +242 427 -5.425332 +251 427 -14.928234 +256 427 -14.644618 +268 427 -21.980013 +269 427 -43.331491 +274 427 -47.376742 +298 427 -361.218234 +319 427 -44.332523 +320 427 -34.747147 +321 427 -33.725919 +322 427 -168.778178 +324 427 -35.152249 +325 427 -307.544191 +326 427 -7.371119 +329 427 -38.823476 +331 427 -18.205389 +333 427 -1267.545018 +337 427 -134.022735 +338 427 -35.861230 +339 427 -203.373853 +340 427 -14.928234 +342 427 -74.835546 +347 427 21627.513161 +348 427 16511.383217 +353 427 18879.066976 +354 427 5236.439107 +360 427 5680.307724 +361 427 7853.735093 +362 427 228.673029 +369 427 2963.238347 +373 427 12821.638863 +374 427 27624.728046 +375 427 1800.613976 +376 427 7480.311301 +377 427 86557.007010 +378 427 31764.397562 +379 427 1186.872541 +382 427 1264.538112 +383 427 7773.660681 +384 427 7796.207150 +385 427 2142.289598 +394 427 240.607141 +395 427 3373.750224 +396 427 3375.250710 +397 427 3376.959919 +398 427 3378.900094 +399 427 4725.882205 +400 427 27921.916274 +401 427 28739.635157 +402 427 274205.331395 +403 427 20843.546774 +404 427 3936.671772 +405 427 17537.019975 +406 427 16142.106548 +407 427 6489.725795 +422 427 172.914619 +423 427 13052.203772 +424 427 32292.639457 +425 427 69487.540686 +426 427 117545.166906 +427 427 12371757.219745 +428 427 128359.828829 +429 427 86535.705796 +430 427 20366.196981 +431 427 4462.644810 +444 427 54201.119250 +445 427 68480.842807 +446 427 68483.188542 +447 427 81678.056262 +448 427 70788.299905 +449 427 52126.373806 +450 427 18408.616920 +451 427 74390.613318 +452 427 233460.555794 +453 427 101391.996471 +454 427 28931.690720 +455 427 7903.194250 +456 427 4639.963651 +457 427 268.206912 +472 427 1362.021526 +475 427 4174.634859 +476 427 102765.298120 +477 427 171424.617070 +478 427 34042.825746 +479 427 91713.415045 +480 427 17028.725378 +481 427 245.077665 +482 427 4051.725839 +483 427 3923.894328 +499 427 132.203084 +500 427 31404.865054 +6 428 -21.277207 +18 428 -11.150583 +27 428 -71.178365 +40 428 -55.323594 +45 428 -61.255581 +47 428 -7.532416 +58 428 -63.089901 +83 428 -85.529550 +90 428 -21.803225 +95 428 -32.968943 +96 428 -131.748448 +116 428 -67.617738 +128 428 -9.875790 +134 428 -32.983632 +143 428 -6.977509 +145 428 -76.497090 +156 428 -105.006552 +157 428 -49.187287 +162 428 -47.012030 +171 428 -32.968133 +174 428 -14.640142 +176 428 -32.946763 +178 428 -14.400069 +192 428 -32.936114 +196 428 -9.578516 +197 428 -7.090803 +201 428 -65.784402 +203 428 -87.034684 +209 428 -28.351373 +211 428 -61.026042 +212 428 -58.845964 +213 428 -7.948102 +216 428 -5.679960 +237 428 -14.667330 +239 428 -4.787048 +251 428 -23.237705 +256 428 -14.645790 +268 428 -10.273050 +269 428 -11.635372 +274 428 -20.541886 +297 428 -21.175998 +298 428 -177.955999 +308 428 -1.037446 +309 428 -1.479113 +319 428 -92.697089 +321 428 -150.554386 +322 428 -102.289106 +323 428 -73.466922 +325 428 -307.569180 +327 428 -129.188632 +328 428 -37.633950 +329 428 -183.610940 +331 428 -34.603474 +333 428 -234.583078 +334 428 -13.563478 +335 428 -33.547728 +336 428 -81.726737 +337 428 -42.694200 +339 428 -74.030344 +340 428 -56.771212 +341 428 -9.152054 +342 428 -61.000732 +347 428 7499.092666 +348 428 10137.557470 +349 428 3051.366693 +353 428 20405.854690 +354 428 31378.310891 +355 428 1258.289480 +360 428 18422.651105 +361 428 35478.512603 +362 428 1033.658993 +369 428 4735.766643 +370 428 1238.112735 +374 428 7114.435988 +375 428 10197.980963 +376 428 10116.788587 +377 428 23059.365384 +378 428 45055.815076 +379 428 46634.525160 +382 428 1266.156828 +383 428 21109.573729 +384 428 35148.279748 +385 428 16876.856396 +394 428 230.818446 +395 428 3991.333775 +396 428 5231.158304 +397 428 5233.107909 +398 428 5235.320570 +399 428 4698.156877 +400 428 1994.731996 +401 428 14965.021485 +402 428 65554.192767 +403 428 122594.031477 +404 428 41180.540359 +405 428 25550.946165 +406 428 49355.937648 +407 428 33642.672247 +408 428 13909.852995 +422 428 172.940648 +423 428 13053.813144 +424 428 32273.141973 +425 428 69316.029171 +426 428 83296.439060 +427 428 128359.828829 +428 428 12232841.042772 +429 428 183963.514612 +430 428 60520.515566 +431 428 16204.810669 +432 428 8434.902482 +433 428 8439.702329 +434 428 3331.679686 +444 428 54205.523860 +445 428 68486.407866 +446 428 68488.753814 +447 428 81701.499388 +448 428 70812.819054 +449 428 52149.130302 +450 428 21547.783454 +451 428 23821.121800 +452 428 63959.667712 +453 428 113384.353765 +454 428 61864.908432 +455 428 40971.297586 +456 428 9543.359713 +457 428 509.788130 +459 428 5113.567076 +460 428 7248.581785 +472 428 1363.844120 +475 428 3408.960998 +476 428 6677.755789 +477 428 70396.856945 +478 428 45596.129148 +479 428 44836.474215 +480 428 50536.630822 +481 428 10103.411924 +482 428 7701.224852 +483 428 7458.252041 +500 428 1100.574645 +6 429 -6.495940 +7 429 -92.967984 +18 429 -29.696707 +27 429 -83.705917 +36 429 -14.833117 +39 429 -26.441754 +40 429 -104.487007 +45 429 -63.678114 +46 429 -19.816396 +47 429 -9.789751 +55 429 -17.325341 +58 429 -3.079225 +83 429 -136.547532 +85 429 -283.788842 +90 429 -63.698519 +92 429 -4.437851 +95 429 -40.925332 +96 429 -131.756940 +103 429 -0.788458 +104 429 -1.103903 +107 429 -1.928475 +110 429 -1.821787 +116 429 -50.483589 +118 429 -29.413706 +123 429 -3.331775 +128 429 -106.989705 +134 429 -36.111509 +137 429 -1.047397 +145 429 -76.063745 +156 429 -116.846569 +157 429 -70.909723 +161 429 -17.399826 +162 429 -116.956151 +171 429 -35.875105 +174 429 -14.641163 +176 429 -32.949410 +196 429 -7.157330 +201 429 -68.703808 +203 429 -227.029717 +211 429 -51.063171 +212 429 -268.684623 +216 429 -12.230076 +237 429 -14.669830 +239 429 -13.425391 +251 429 -33.133320 +256 429 -14.647118 +268 429 -16.063157 +269 429 -15.984823 +274 429 -71.976844 +297 429 -187.274166 +298 429 -65.135342 +308 429 -36.174533 +309 429 -36.150334 +319 429 -163.720149 +320 429 -428.778681 +321 429 -279.388461 +322 429 -85.700248 +323 429 -66.976666 +324 429 -41.679613 +325 429 -307.597483 +326 429 -97.026642 +327 429 -46.957399 +328 429 -66.238687 +329 429 -121.811166 +330 429 -11.598217 +331 429 -72.681721 +332 429 -59.915431 +333 429 -321.659101 +334 429 -100.517382 +335 429 -221.256331 +336 429 -94.728942 +337 429 -20.400115 +338 429 -42.544957 +339 429 -26.234936 +340 429 -68.349342 +341 429 -232.081541 +342 429 -9.794640 +347 429 18068.894526 +348 429 24761.182140 +349 429 11046.476417 +353 429 3973.475082 +354 429 72004.479537 +355 429 458.372393 +360 429 30677.673539 +361 429 66095.550722 +362 429 1926.083585 +369 429 7034.374097 +370 429 4600.616983 +374 429 13780.334705 +375 429 24901.549640 +376 429 15752.274385 +377 429 35691.491555 +378 429 14808.752056 +379 429 168409.410790 +380 429 12897.023463 +381 429 4162.636417 +382 429 1125.649631 +383 429 31377.724378 +384 429 65436.857081 +385 429 35060.656613 +395 429 2804.853278 +396 429 7406.482281 +397 429 7407.633937 +398 429 7408.939748 +399 429 7410.416918 +400 429 7412.085863 +401 429 17258.009350 +402 429 68033.211314 +403 429 92764.758236 +404 429 236473.198414 +405 429 53846.472500 +406 429 81250.564896 +407 429 63834.446676 +408 429 33802.489839 +422 429 172.970134 +423 429 13055.636168 +424 429 31737.311474 +425 429 66076.248420 +426 429 76941.029382 +427 429 86535.705796 +428 429 183963.514612 +429 429 12595623.307631 +430 429 146042.386210 +431 429 35313.642277 +432 429 14850.057369 +433 429 14858.800394 +434 429 6246.456078 +444 429 54210.512646 +445 429 68492.711009 +446 429 68495.057200 +447 429 78310.577951 +448 429 66919.968188 +449 429 48251.003768 +450 429 17807.556030 +451 429 31470.543054 +452 429 44281.222636 +453 429 92019.922215 +454 429 228328.432373 +455 429 136140.932989 +456 429 27965.131168 +457 429 5221.833175 +459 429 8622.444283 +460 429 12762.335287 +472 429 1022.311917 +475 429 20954.926432 +476 429 19778.076790 +477 429 6221.327697 +478 429 84463.972295 +479 429 118796.220217 +480 429 151321.869059 +481 429 29861.070427 +482 429 13963.884191 +483 429 16011.206620 +5 430 -7.485991 +7 430 -75.560732 +17 430 -0.660260 +30 430 -5.220300 +36 430 -36.420267 +39 430 -23.702301 +45 430 -123.270081 +46 430 -15.293127 +55 430 -2.879626 +56 430 -205.426508 +69 430 -10.496468 +70 430 -24.486476 +73 430 -23.583745 +83 430 -136.853521 +85 430 -69.941616 +90 430 -49.646208 +92 430 -132.552892 +95 430 -275.827678 +96 430 -227.359359 +98 430 -210.374305 +101 430 -29.199821 +103 430 -147.823276 +104 430 -104.065284 +107 430 -290.353375 +110 430 -287.033244 +112 430 -322.263917 +118 430 -34.401495 +123 430 -307.609215 +126 430 -24.254058 +128 430 -58.680074 +134 430 -293.795204 +137 430 -17.796699 +145 430 -168.260459 +146 430 -249.068382 +154 430 -28.191167 +155 430 -182.463437 +156 430 -85.093083 +157 430 -25.844474 +161 430 -2.779564 +162 430 -101.430421 +167 430 -23.778941 +168 430 -10.104757 +171 430 -228.828920 +173 430 -24.227510 +174 430 -104.530798 +175 430 -23.636164 +176 430 -102.410099 +179 430 -6.524408 +182 430 -10.203635 +194 430 -23.872385 +201 430 -39.438831 +202 430 -19.991356 +203 430 -91.403795 +211 430 -86.493554 +212 430 -93.089757 +214 430 -26.910902 +228 430 -22.063601 +237 430 -14.672670 +251 430 -33.147178 +256 430 -14.648625 +268 430 -1.864978 +269 430 -1.365822 +274 430 -34.891840 +279 430 -22.522584 +281 430 -9.972680 +283 430 -2.252883 +297 430 -134.288950 +298 430 -33.117562 +300 430 -17.208010 +308 430 -51.842021 +309 430 -52.200793 +319 430 -455.388093 +320 430 -196.938105 +321 430 -1259.234681 +322 430 -97.342948 +323 430 -122.179510 +324 430 -466.328086 +325 430 -89.527963 +326 430 -132.052261 +327 430 -209.797665 +328 430 -325.378021 +329 430 -323.493086 +330 430 -7.120960 +331 430 -57.981373 +332 430 -470.914364 +333 430 -29.361490 +335 430 -65.575535 +336 430 -172.247831 +337 430 -188.260984 +338 430 -272.287855 +339 430 -366.707604 +340 430 -8.376367 +341 430 -251.180612 +342 430 -211.278723 +347 430 6490.279687 +348 430 9034.146098 +349 430 5562.883849 +353 430 1263.006350 +354 430 80061.788024 +360 430 112459.709568 +361 430 299897.997832 +362 430 8742.449521 +369 430 7037.316191 +370 430 4602.541170 +374 430 3493.530401 +375 430 9081.757894 +376 430 7726.586354 +377 430 4027.472026 +378 430 3575.680719 +379 430 131746.320482 +380 430 32293.930572 +381 430 4404.004456 +383 430 84250.042055 +384 430 292639.674966 +385 430 185632.217370 +395 430 2806.026395 +396 430 7409.580008 +397 430 7410.732146 +398 430 7412.038503 +399 430 7413.516291 +400 430 7415.185934 +401 430 8801.106464 +402 430 24044.942431 +403 430 21896.727118 +404 430 75581.331602 +405 430 171328.051280 +406 430 242300.937040 +407 430 287500.762496 +408 430 211026.578369 +409 430 3930.555511 +422 430 173.003620 +423 430 5862.965223 +424 430 12661.829104 +425 430 19567.021939 +426 430 19945.421511 +427 430 20366.196981 +428 430 60520.515566 +429 430 146042.386210 +430 430 13352514.936552 +431 430 267783.367094 +432 430 79493.777000 +433 430 72803.320900 +434 430 15787.235377 +444 430 15781.111163 +445 430 19938.851662 +446 430 19939.634624 +447 430 19767.521733 +448 430 14078.569747 +449 430 7280.847536 +450 430 2594.494225 +451 430 18238.615269 +452 430 34309.742243 +453 430 42386.163206 +454 430 163324.734904 +455 430 529785.200187 +456 430 148040.874480 +457 430 12063.202355 +458 430 56.826626 +459 430 57112.216580 +460 430 62561.957185 +475 430 24100.803162 +476 430 26946.284870 +477 430 14409.292359 +478 430 78041.412068 +479 430 166603.272812 +480 430 213954.120235 +481 430 288199.974656 +482 430 51681.269457 +483 430 14863.856187 +1 431 -24.917577 +2 431 -12.443869 +3 431 -10.779999 +4 431 -11.799299 +5 431 -7.378833 +6 431 -62.350037 +7 431 -32.959927 +8 431 -24.872344 +13 431 -24.799023 +14 431 -24.825336 +15 431 -24.824281 +16 431 -25.227961 +17 431 -28.715079 +19 431 -25.445191 +21 431 -24.757126 +22 431 -25.032363 +25 431 -24.808314 +26 431 -11.183481 +28 431 -24.850170 +30 431 -8.964578 +32 431 -10.769090 +34 431 -10.751085 +36 431 -50.489970 +37 431 -24.216354 +38 431 -28.105110 +41 431 -25.789474 +42 431 -24.894795 +43 431 -10.784684 +44 431 -102.935979 +45 431 -38.599475 +46 431 -10.380728 +48 431 -46.733912 +49 431 -25.596835 +50 431 -28.254075 +51 431 -12.605374 +52 431 -28.246065 +53 431 -24.827427 +54 431 -99.327946 +56 431 -5.726831 +57 431 -24.823224 +58 431 -38.836316 +59 431 -25.979335 +60 431 -26.264939 +62 431 -24.257259 +63 431 -25.362607 +64 431 -24.393933 +65 431 -10.781306 +66 431 -10.952775 +67 431 -24.651715 +69 431 -5.430674 +70 431 -11.684420 +72 431 -11.006074 +73 431 -12.239619 +75 431 -24.801828 +77 431 -11.212447 +78 431 -10.952333 +80 431 -10.760771 +83 431 -22.905643 +84 431 -26.235361 +85 431 -0.894851 +86 431 -11.048294 +87 431 -11.670166 +89 431 -24.421019 +90 431 -23.346266 +91 431 -24.741245 +92 431 -148.595331 +93 431 -24.195086 +94 431 -25.472563 +95 431 -67.339298 +96 431 -114.060353 +98 431 -74.151345 +99 431 -25.711011 +101 431 -8.887809 +103 431 -32.480901 +104 431 -6.505356 +105 431 -25.810524 +106 431 -24.316468 +107 431 -95.072261 +108 431 -24.312747 +109 431 -24.315590 +110 431 -67.527954 +111 431 -24.926101 +112 431 -107.741585 +117 431 -25.653350 +118 431 -22.705977 +119 431 -24.250380 +120 431 -24.252273 +122 431 -25.171533 +123 431 -52.109215 +124 431 -25.646373 +125 431 -11.149867 +126 431 -11.826735 +127 431 -28.063172 +129 431 -24.499850 +130 431 -11.265885 +131 431 -11.263137 +132 431 -11.383305 +134 431 -144.278404 +135 431 -24.246772 +136 431 -28.382891 +137 431 -0.805626 +141 431 -24.322957 +145 431 -50.734863 +146 431 -188.951543 +148 431 -25.743452 +149 431 -24.760953 +150 431 -25.650086 +151 431 -11.006405 +152 431 -25.509180 +153 431 -11.016202 +154 431 -34.871474 +155 431 -267.637555 +156 431 -28.263065 +157 431 -16.736086 +158 431 -19.535649 +159 431 -25.648816 +162 431 -80.740041 +163 431 -25.494369 +166 431 -25.045798 +167 431 -12.119012 +168 431 -5.674321 +169 431 -25.212580 +173 431 -11.843019 +174 431 -30.784734 +175 431 -12.207200 +176 431 -26.649811 +177 431 -24.745293 +179 431 -8.039049 +181 431 -27.998680 +182 431 -5.612550 +183 431 -25.495814 +185 431 -25.125929 +186 431 -27.976011 +187 431 -24.715405 +189 431 -25.522230 +190 431 -10.775101 +194 431 -12.061384 +195 431 -24.789971 +197 431 -6.972126 +202 431 -14.515924 +203 431 -48.556454 +204 431 -26.547743 +206 431 -27.842462 +211 431 -7.600657 +212 431 -1.421591 +213 431 -27.438973 +214 431 -10.225105 +215 431 -25.646690 +217 431 -25.097317 +219 431 -24.921604 +220 431 -24.962105 +221 431 -24.976602 +222 431 -24.984655 +223 431 -99.774197 +224 431 -24.980498 +227 431 -24.811957 +228 431 -13.189592 +229 431 -24.973954 +230 431 -24.825404 +231 431 -25.064596 +233 431 -24.891736 +234 431 -24.267542 +235 431 -24.974913 +237 431 -107.029130 +238 431 -26.492785 +241 431 -28.918505 +242 431 -26.477415 +244 431 -28.751401 +245 431 -12.793641 +247 431 -28.321606 +250 431 -25.035243 +251 431 -33.162975 +252 431 -27.093788 +253 431 -24.529151 +256 431 -104.776668 +257 431 -24.948705 +258 431 -24.190201 +259 431 -10.750686 +261 431 -10.825392 +263 431 -24.768515 +264 431 -27.051654 +265 431 -25.647756 +266 431 -24.798038 +267 431 -25.991038 +271 431 -24.601926 +272 431 -24.597900 +273 431 -11.248636 +275 431 -11.979979 +278 431 -24.959887 +279 431 -12.900746 +281 431 -21.466286 +282 431 -25.694999 +283 431 -11.197473 +284 431 -25.831305 +285 431 -24.265042 +287 431 -11.002262 +289 431 -25.059483 +290 431 -25.041841 +292 431 -11.968885 +293 431 -24.425897 +294 431 -24.432003 +295 431 -21.696862 +296 431 -24.321924 +297 431 -54.431840 +298 431 -33.131463 +299 431 -10.776337 +300 431 -1.640548 +302 431 -24.707197 +304 431 -26.068745 +305 431 -26.057406 +306 431 -24.523075 +307 431 -10.978983 +308 431 -34.875772 +309 431 -34.869021 +310 431 -106.686559 +311 431 -26.087171 +312 431 -25.804894 +313 431 -11.704601 +314 431 -24.211188 +315 431 -24.801731 +316 431 -24.791338 +317 431 -24.779504 +318 431 -24.518494 +319 431 -4032.726734 +320 431 -49.551644 +321 431 -811.695388 +322 431 -25.602835 +323 431 -16.905398 +324 431 -156.949707 +325 431 -20.018056 +326 431 -26.359435 +327 431 -16.956080 +328 431 -533.483427 +329 431 -51.460741 +331 431 -153.948023 +332 431 -41.347828 +333 431 -6.356137 +335 431 -47.169648 +336 431 -14.688851 +337 431 -185.169929 +338 431 -100.270217 +339 431 -49.679436 +341 431 -58.794905 +342 431 -125.841508 +354 431 42998.679313 +355 431 6426.624604 +358 431 3310.558848 +359 431 602.883083 +360 431 66057.273577 +361 431 193918.486772 +362 431 5653.971036 +369 431 7040.669956 +370 431 4604.734597 +376 431 6574.697062 +377 431 5783.823387 +378 431 2331.570309 +379 431 17438.290622 +380 431 60157.280224 +381 431 13320.195319 +382 431 506.528768 +383 431 44957.923175 +384 431 186155.475189 +385 431 126636.351960 +395 431 2807.363659 +396 431 7413.111182 +397 431 7414.263869 +398 431 7415.570849 +399 431 7417.049341 +400 431 7418.719780 +401 431 7420.606471 +402 431 17840.999079 +403 431 15904.063282 +404 431 19992.313407 +405 431 57529.695830 +406 431 697014.249936 +407 431 185437.668198 +408 431 149855.232137 +409 431 5507.040576 +422 431 141.026017 +423 431 2666.696508 +424 431 4043.072941 +425 431 4461.735640 +426 431 4462.162590 +427 431 4462.644810 +428 431 16204.810669 +429 431 35313.642277 +430 431 267783.367094 +431 431 14038792.926281 +432 431 160964.942834 +433 431 119636.542808 +434 431 38775.038668 +444 431 3530.132873 +445 431 4460.235684 +446 431 4460.465294 +447 431 4319.700500 +448 431 1794.326111 +449 431 418.284524 +451 431 3971.170823 +452 431 9807.155708 +453 431 22816.500079 +454 431 42426.791181 +455 431 138648.552535 +456 431 690339.223939 +457 431 91804.519775 +458 431 11506.593464 +459 431 81024.557303 +460 431 102830.455109 +475 431 14609.419357 +476 431 17623.350816 +477 431 12068.892920 +478 431 12845.615831 +479 431 48752.206472 +480 431 248321.956052 +481 431 489554.899901 +482 431 97680.710119 +483 431 53920.279582 +484 431 1070.781068 +6 432 -18.115157 +7 432 -63.879431 +27 432 -114.369260 +36 432 -127.818852 +55 432 -12.748149 +58 432 -134.342669 +92 432 -31.766655 +98 432 -33.088664 +101 432 -7.151022 +103 432 -14.692807 +107 432 -33.070658 +110 432 -14.701052 +112 432 -33.062985 +134 432 -132.368165 +137 432 -30.832536 +145 432 -107.143126 +146 432 -132.526560 +154 432 -11.651220 +155 432 -141.300714 +156 432 -58.687722 +157 432 -58.391757 +161 432 -7.932809 +162 432 -131.369038 +178 432 -25.260375 +188 432 -13.037946 +196 432 -12.504333 +197 432 -3.868412 +199 432 -13.860607 +203 432 -3.364559 +205 432 -31.095052 +208 432 -31.067024 +237 432 -44.640496 +239 432 -31.115596 +251 432 -33.181051 +256 432 -8.259327 +262 432 -11.035207 +269 432 -14.982110 +270 432 -6.139308 +274 432 -32.273296 +277 432 -11.240431 +295 432 -52.561205 +298 432 -33.147365 +308 432 -11.884183 +309 432 -11.517906 +319 432 -311.202393 +321 432 -94.220585 +324 432 -37.489993 +327 432 -12.630400 +328 432 -785.316395 +329 432 -12.160039 +331 432 -231.820054 +334 432 -27.770766 +337 432 -159.623180 +338 432 -5.528328 +342 432 -209.284664 +347 432 8986.446256 +348 432 12121.813595 +349 432 12131.069556 +350 432 10192.896218 +351 432 2204.534858 +354 432 90142.915432 +355 432 5326.200328 +358 432 6626.455055 +359 432 1867.007319 +360 432 2183.531676 +361 432 21852.932130 +362 432 690.623261 +369 432 7044.507534 +370 432 4607.244447 +375 432 1948.649920 +376 432 32692.074982 +377 432 28771.900582 +378 432 12278.387308 +379 432 10036.819856 +380 432 95014.054894 +381 432 38957.130388 +382 432 283.884813 +383 432 9448.144277 +384 432 9678.060022 +385 432 20568.258267 +386 432 1765.888643 +395 432 2808.893837 +396 432 7417.151763 +397 432 7418.305078 +398 432 7419.612770 +399 432 7421.092068 +400 432 7422.763417 +401 432 7424.651137 +402 432 27614.636063 +403 432 36776.953330 +404 432 34486.005616 +405 432 50655.256560 +406 432 203955.184667 +407 432 52724.947794 +408 432 20508.570218 +409 432 13346.333393 +410 432 603.431041 +428 432 8434.902482 +429 432 14850.057369 +430 432 79493.777000 +431 432 160964.942834 +432 432 13384794.274094 +433 432 189082.137893 +434 432 96104.203229 +435 432 2365.881950 +452 432 1479.961342 +453 432 5464.209638 +454 432 7676.020347 +455 432 6204.216281 +456 432 13103.363827 +457 432 125512.523051 +458 432 83242.243050 +459 432 82280.521026 +460 432 149936.882843 +475 432 3854.249933 +476 432 5439.224999 +477 432 3970.948970 +478 432 2587.235450 +479 432 8728.721320 +480 432 8306.687391 +481 432 8382.291098 +482 432 17970.425304 +483 432 146667.824554 +484 432 25368.676270 +5 433 -4.776742 +6 433 -4.967501 +7 433 -20.299512 +39 433 -96.479364 +58 433 -134.548526 +68 433 -1.073923 +69 433 -28.234771 +70 433 -13.085441 +81 433 -7.045641 +82 433 -59.501985 +98 433 -33.102598 +101 433 -14.963797 +103 433 -14.349499 +107 433 -33.083266 +110 433 -14.706875 +112 433 -33.075028 +115 433 -7.280746 +126 433 -13.259031 +134 433 -132.424898 +137 433 -23.018401 +138 433 -8.371026 +140 433 -23.132456 +146 433 -132.594996 +155 433 -134.583516 +161 433 -37.562594 +167 433 -28.539358 +168 433 -27.020471 +173 433 -117.613559 +175 433 -28.422441 +179 433 -0.297751 +180 433 -29.987362 +182 433 -26.883981 +194 433 -11.273821 +202 433 -5.534864 +203 433 -34.219503 +211 433 -21.467216 +212 433 -21.821072 +214 433 -4.657042 +228 433 -13.328516 +251 433 -33.201827 +262 433 -4.335844 +269 433 -33.990962 +270 433 -15.116031 +274 433 -136.475253 +279 433 -9.296965 +281 433 -16.928560 +295 433 -81.693301 +297 433 -8.464801 +298 433 -33.165639 +300 433 -37.838766 +319 433 -4.335844 +321 433 -695.409377 +323 433 -24.464944 +328 433 -1000.391507 +335 433 -10.156110 +339 433 -23.437757 +341 433 -23.634489 +342 433 -25.267013 +347 433 30893.414601 +348 433 42142.923738 +349 433 42175.539407 +350 433 37706.103654 +351 433 9322.396291 +355 433 664.201606 +358 433 3525.424294 +359 433 7855.572978 +361 433 131781.203616 +362 433 5630.693757 +369 433 7048.918358 +370 433 4610.129211 +375 433 4506.353762 +376 433 55709.902115 +377 433 58932.081724 +378 433 43334.894546 +379 433 44352.205336 +380 433 13533.238559 +381 433 7620.414498 +383 433 12010.109851 +384 433 1086.512833 +385 433 112021.777809 +386 433 59595.437462 +395 433 2810.652588 +396 433 7421.795912 +397 433 7422.949949 +398 433 7424.258460 +399 433 7425.738685 +400 433 7427.411080 +401 433 7429.299982 +402 433 27643.893061 +403 433 36827.425528 +404 433 42359.641519 +405 433 79878.136183 +406 433 103373.919422 +407 433 54721.663741 +408 433 20770.184851 +409 433 108406.488428 +410 433 75264.299594 +428 433 8439.702329 +429 433 14858.800394 +430 433 72803.320900 +431 433 119636.542808 +432 433 189082.137893 +433 433 13283114.890966 +434 433 221296.597156 +435 433 13631.616862 +455 433 2796.574356 +456 433 18388.786504 +457 433 138842.889372 +458 433 78269.369768 +459 433 82562.723535 +460 433 181716.362847 +478 433 1931.531826 +479 433 7717.408174 +480 433 40299.281786 +481 433 115117.931436 +482 433 36953.214913 +483 433 9395.795813 +484 433 6203.368152 +5 434 -32.785398 +17 434 -4.571338 +18 434 -6.416043 +20 434 -15.714433 +36 434 -32.080403 +39 434 -71.670516 +51 434 -2.320426 +52 434 -1.432575 +58 434 -133.487308 +68 434 -15.395892 +69 434 -14.826366 +70 434 -6.188294 +79 434 -1.779679 +81 434 -10.756186 +82 434 -99.803727 +98 434 -4.682540 +107 434 -1.560574 +110 434 -1.235865 +112 434 -0.071338 +115 434 -10.576131 +126 434 -26.194010 +134 434 -20.870304 +136 434 -2.444406 +138 434 -29.978078 +140 434 -18.662900 +146 434 -42.290785 +155 434 -134.250054 +156 434 -32.166959 +157 434 -32.873731 +161 434 -2.097479 +167 434 -14.598472 +168 434 -15.736160 +173 434 -55.810714 +175 434 -14.685935 +179 434 -36.314108 +180 434 -13.516771 +182 434 -15.838549 +194 434 -27.726264 +202 434 -32.191482 +203 434 -34.329150 +206 434 -6.453976 +211 434 -34.849250 +212 434 -34.834902 +213 434 -35.921052 +214 434 -12.596443 +228 434 -26.140492 +241 434 -23.992439 +244 434 -3.475644 +245 434 -3.886098 +247 434 -5.724482 +248 434 -20.501223 +251 434 -15.571398 +252 434 -1.977964 +269 434 -34.080659 +270 434 -15.156669 +274 434 -136.878476 +279 434 -29.258311 +281 434 -23.377913 +283 434 -16.335106 +292 434 -2.832425 +295 434 -52.438108 +297 434 -35.509398 +298 434 -12.327302 +300 434 -7.698845 +304 434 -1.144497 +305 434 -0.490322 +310 434 -15.208562 +311 434 -0.529014 +313 434 -2.948056 +320 434 -9.906493 +321 434 -840.525198 +326 434 -9.872983 +328 434 -789.107063 +332 434 -9.983298 +337 434 -12.769462 +338 434 -9.905873 +347 434 30982.081160 +348 434 42264.091542 +349 434 42296.801181 +350 434 37815.526449 +351 434 9349.939738 +354 434 13991.273642 +355 434 13182.200957 +359 434 7406.235634 +361 434 146239.979013 +362 434 7213.092770 +369 434 3305.887742 +370 434 2162.114651 +375 434 4518.299106 +376 434 55624.190841 +377 434 58922.537512 +378 434 43459.813106 +379 434 48613.909153 +380 434 27962.042549 +381 434 32567.523400 +382 434 13761.030610 +384 434 8130.010094 +385 434 93818.363123 +386 434 96650.666088 +395 434 1318.174146 +396 434 3480.764408 +397 434 3481.305642 +398 434 3481.919324 +399 434 3482.613537 +400 434 3483.397878 +401 434 3484.283758 +402 434 19534.416320 +403 434 33086.190579 +404 434 42152.787756 +405 434 79782.128743 +406 434 107524.197807 +407 434 72135.222337 +408 434 36354.607176 +409 434 84823.383468 +410 434 129215.890481 +411 434 1125.897475 +428 434 3331.679686 +429 434 6246.456078 +430 434 15787.235377 +431 434 38775.038668 +432 434 96104.203229 +433 434 221296.597156 +434 434 13031997.118178 +435 434 44389.031594 +456 434 1145.691456 +457 434 93969.362812 +458 434 117703.153407 +459 434 45936.016635 +460 434 129904.542815 +480 434 14779.943762 +481 434 96118.661402 +482 434 93914.588143 +483 434 26716.302825 +484 434 7489.061050 +485 434 3231.515682 +2 435 -11.902031 +17 435 -24.855356 +18 435 -23.300048 +23 435 -4.899363 +31 435 -8.632562 +36 435 -17.333106 +38 435 -28.301048 +44 435 -3.356098 +47 435 -114.311458 +51 435 -26.763167 +52 435 -27.518702 +60 435 -5.048813 +79 435 -27.223124 +84 435 -11.069962 +87 435 -5.052427 +97 435 -12.129668 +100 435 -3.805990 +117 435 -0.818295 +124 435 -1.894197 +132 435 -5.190608 +136 435 -26.657800 +148 435 -3.777566 +150 435 -2.162108 +156 435 -17.307800 +157 435 -17.102274 +159 435 -1.898604 +172 435 -7.273732 +186 435 -28.494970 +192 435 -28.171970 +193 435 -1.350568 +203 435 -7.570422 +204 435 -15.272454 +206 435 -7.357436 +211 435 -11.075792 +212 435 -10.996415 +215 435 -1.960099 +240 435 -3.956479 +241 435 -8.851800 +242 435 -14.987720 +244 435 -25.782664 +245 435 -25.434983 +247 435 -7.959424 +248 435 -11.668869 +252 435 -11.092251 +255 435 -8.231816 +265 435 -1.929382 +267 435 -7.462954 +269 435 -5.204100 +270 435 -2.417457 +274 435 -26.418077 +275 435 -27.352130 +282 435 -2.670578 +283 435 -15.064376 +284 435 -2.422491 +292 435 -26.328246 +295 435 -13.093591 +297 435 -14.090017 +304 435 -27.764213 +305 435 -12.355289 +310 435 -15.988953 +311 435 -28.289349 +312 435 -2.464575 +313 435 -10.274449 +321 435 -768.783217 +328 435 -129.515460 +337 435 -10.099687 +342 435 -2.993904 +347 435 5647.069526 +348 435 7730.544229 +349 435 7736.551992 +350 435 7046.006394 +351 435 1804.574674 +354 435 7408.459581 +355 435 6978.861722 +359 435 2070.511559 +361 435 101510.927212 +362 435 8946.835746 +375 435 697.345912 +376 435 5946.474425 +377 435 7759.767117 +378 435 7986.383078 +379 435 10741.828346 +380 435 9957.563204 +381 435 15976.749947 +382 435 7336.063574 +384 435 1904.898997 +385 435 1173.128553 +386 435 132889.258034 +404 435 2054.878248 +405 435 9324.754034 +406 435 14541.696368 +407 435 20945.171101 +408 435 17165.494567 +409 435 3036.481446 +410 435 94901.040334 +411 435 45357.386712 +432 435 2365.881950 +433 435 13631.616862 +434 435 44389.031594 +435 435 12383136.987259 +436 435 12701.481856 +458 435 2782.864594 +459 435 122929.726641 +460 435 44901.729537 +461 435 527.541484 +482 435 935.543614 +483 435 72291.690189 +484 435 66972.030500 +485 435 22180.689468 +486 435 5.617984 +487 435 498.654554 +3 436 -9.154717 +8 436 -21.985096 +9 436 -9.219110 +16 436 -22.464168 +19 436 -10.064365 +21 436 -9.650686 +22 436 -22.204484 +23 436 -18.248440 +24 436 -20.333237 +25 436 -9.729152 +31 436 -14.793666 +32 436 -20.542130 +33 436 -9.113361 +34 436 -9.251108 +37 436 -20.426396 +42 436 -22.014367 +43 436 -20.633530 +44 436 -19.684029 +53 436 -21.883390 +54 436 -21.887587 +55 436 -9.663040 +60 436 -5.460870 +66 436 -9.575913 +67 436 -9.585134 +77 436 -9.975465 +80 436 -20.672201 +84 436 -12.552659 +87 436 -5.457558 +89 436 -20.969100 +91 436 -9.665697 +100 436 -6.603269 +102 436 -20.468739 +106 436 -20.738229 +108 436 -20.727542 +109 436 -82.948822 +117 436 -9.376554 +119 436 -82.178192 +120 436 -9.136413 +121 436 -9.460223 +122 436 -22.372383 +124 436 -21.047710 +125 436 -9.915809 +129 436 -21.195671 +131 436 -22.659754 +132 436 -86.420793 +135 436 -84.167763 +141 436 -20.755418 +143 436 -20.261226 +148 436 -19.291554 +150 436 -20.797530 +152 436 -10.135490 +159 436 -21.043594 +160 436 -20.457531 +163 436 -22.759890 +164 436 -21.826997 +166 436 -9.898871 +169 436 -9.948374 +172 436 -3.434198 +178 436 -20.067275 +183 436 -10.114505 +185 436 -22.356479 +187 436 -9.561820 +188 436 -20.984316 +190 436 -20.581745 +193 436 -21.555723 +195 436 -9.690457 +204 436 -8.718180 +215 436 -20.986159 +217 436 -9.893279 +218 436 -9.881014 +223 436 -9.823595 +224 436 -9.846519 +227 436 -9.710170 +230 436 -9.712784 +231 436 -22.313417 +232 436 -22.315170 +234 436 -20.480807 +235 436 -9.833531 +240 436 -6.464569 +242 436 -8.976748 +250 436 -22.245068 +253 436 -21.194582 +255 436 -15.163256 +257 436 -9.820003 +258 436 -20.329826 +259 436 -20.321943 +261 436 -83.245241 +263 436 -9.635953 +265 436 -21.014847 +266 436 -21.824941 +267 436 -15.873216 +271 436 -9.506163 +272 436 -9.501548 +277 436 -21.706288 +280 436 -20.443550 +282 436 -20.323042 +284 436 -7.882970 +288 436 -9.710437 +289 436 -22.262568 +290 436 -22.232314 +293 436 -21.050272 +294 436 -21.059991 +295 436 -24.328443 +296 436 -20.753284 +302 436 -9.636828 +306 436 -21.259426 +307 436 -9.564440 +312 436 -7.843926 +314 436 -20.422051 +315 436 -21.814493 +316 436 -21.802836 +317 436 -9.680635 +318 436 -84.664438 +321 436 -2164.547833 +342 436 -24.328443 +359 436 4696.830079 +361 436 187846.368305 +362 436 70988.989418 +384 436 2279.853385 +385 436 2685.167671 +386 436 305238.636074 +387 436 596.758580 +410 436 4719.039225 +411 436 311095.972338 +435 436 12701.481856 +436 436 12108308.888945 +460 436 110755.901906 +461 436 216994.316483 +484 436 495.954235 +485 436 184347.992517 +486 436 145829.517715 +487 436 4052.062957 +40 437 -20.159220 +191 437 -8.798433 +196 437 -8.710806 +199 437 -8.910924 +205 437 -20.021496 +207 437 -20.019503 +208 437 -20.022002 +216 437 -4.281804 +239 437 -20.024960 +254 437 -19.598084 +262 437 -78.739611 +321 437 -229.286843 +362 437 27708.266461 +387 437 31746.729422 +412 437 31241.707682 +437 437 11542465.717871 +438 437 317.286887 +461 437 838.141976 +462 437 26234.611173 +463 437 3336.792735 +486 437 1187.394495 +487 437 14010.536760 +488 437 14880.147864 +216 438 -4.871875 +321 438 -4.871875 +362 438 631.597997 +387 438 715.749992 +412 438 696.148820 +437 438 317.286887 +438 438 11280670.605153 +463 438 662.094660 +488 438 647.440705 +439 439 11111111.111111 +440 440 11111111.111111 +441 441 11111111.111111 +442 442 11111111.111111 +443 443 11446854.729258 +51 444 -25.951377 +65 444 -24.345457 +75 444 -94.696177 +90 444 -26.291328 +92 444 -26.295328 +93 444 -98.650379 +95 444 -26.079432 +96 444 -104.244744 +97 444 -32.518999 +100 444 -10.162595 +101 444 -27.428456 +132 444 -10.221224 +133 444 -11.624988 +134 444 -26.087847 +135 444 -34.123158 +136 444 -25.918611 +137 444 -29.254558 +138 444 -28.138827 +139 444 -29.094472 +141 444 -10.688108 +142 444 -25.727823 +143 444 -31.935527 +144 444 -93.770742 +163 444 -10.250301 +164 444 -23.579761 +166 444 -10.472564 +171 444 -26.078967 +172 444 -10.107556 +174 444 -11.583567 +175 444 -13.773527 +176 444 -26.066719 +177 444 -23.721568 +178 444 -30.889452 +179 444 -29.787700 +180 444 -31.155205 +182 444 -13.831121 +183 444 -23.058078 +184 444 -22.974929 +185 444 -23.437582 +186 444 -25.975225 +188 444 -11.870484 +189 444 -23.082399 +190 444 -10.883892 +192 444 -27.275733 +193 444 -22.991199 +194 444 -24.977458 +196 444 -28.841879 +197 444 -14.189898 +198 444 -11.670203 +199 444 -12.723687 +202 444 -26.258241 +203 444 -26.693810 +206 444 -33.438036 +209 444 -12.175638 +211 444 -11.845983 +212 444 -26.802830 +234 444 -124.725118 +237 444 -11.599144 +239 444 -28.622397 +241 444 -33.206706 +242 444 -22.761510 +244 444 -25.003070 +246 444 -23.029021 +247 444 -31.593402 +248 444 -12.407125 +250 444 -23.552415 +251 444 -95.527129 +252 444 -136.643170 +253 444 -23.675888 +256 444 -11.586805 +257 444 -23.599609 +258 444 -11.033644 +262 444 -26.956371 +263 444 -10.461289 +264 444 -29.425887 +265 444 -22.979141 +266 444 -94.778176 +267 444 -10.149880 +268 444 -11.138219 +269 444 -11.359115 +271 444 -94.859309 +273 444 -10.271509 +274 444 -44.678937 +275 444 -27.406111 +277 444 -27.889460 +279 444 -25.422050 +280 444 -24.608831 +282 444 -10.200322 +283 444 -24.878345 +284 444 -10.186085 +285 444 -24.323662 +291 444 -24.505319 +292 444 -137.298235 +293 444 -10.665273 +294 444 -23.976641 +295 444 -26.550118 +296 444 -10.689890 +297 444 -26.769364 +298 444 -26.333261 +299 444 -24.553857 +301 444 -101.880331 +302 444 -10.587732 +304 444 -124.866672 +305 444 -31.186911 +306 444 -10.607093 +307 444 -23.506619 +308 444 -106.879151 +310 444 -29.627558 +311 444 -31.451081 +315 444 -10.514433 +316 444 -10.524183 +317 444 -10.528216 +318 444 -10.520691 +322 444 -31.525807 +325 444 -3444.749699 +327 444 -64.001322 +346 444 8975.935129 +347 444 6710.991363 +352 444 1521.790943 +353 444 2010.118516 +356 444 1653.025137 +357 444 6111.354752 +358 444 6127.184692 +359 444 490.931777 +369 444 3526.654571 +370 444 1801.237627 +371 444 15707.849745 +375 444 2258.911826 +376 444 2894.421675 +377 444 13639.658682 +378 444 22862.895757 +379 444 14621.250082 +380 444 6085.744465 +381 444 4444.632542 +394 444 21293.750509 +395 444 17850.312175 +397 444 796.841935 +398 444 3422.175997 +399 444 21919.463670 +400 444 27828.388104 +401 444 30611.700059 +402 444 21718.202287 +403 444 9622.431454 +404 444 5932.152892 +405 444 5937.174798 +406 444 89.095713 +419 444 34858.430059 +420 444 24787.992608 +421 444 41490.019604 +422 444 41159.911505 +423 444 48757.939492 +424 444 45077.609450 +425 444 64123.389692 +426 444 62683.553736 +427 444 54201.119250 +428 444 54205.523860 +429 444 54210.512646 +430 444 15781.111163 +431 444 3530.132873 +444 444 12099833.790442 +445 444 203519.697603 +446 444 101192.641202 +447 444 68288.428702 +448 444 54247.971149 +449 444 32193.810636 +450 444 4097.458729 +469 444 348497.634587 +470 444 276656.123766 +471 444 132679.302478 +472 444 77651.084720 +473 444 49116.356990 +474 444 41794.754729 +475 444 15131.897326 +476 444 5222.796175 +477 444 5224.781193 +478 444 3627.062951 +479 444 2175.734794 +494 444 224138.941059 +495 444 157073.774073 +496 444 182043.873929 +497 444 116363.127396 +498 444 58616.677012 +499 444 36862.215962 +500 444 23900.775162 +90 445 -33.224205 +92 445 -33.229372 +95 445 -32.950509 +96 445 -131.707797 +97 445 -5.167278 +101 445 -34.695541 +133 445 -14.688747 +134 445 -32.961376 +135 445 -0.850407 +137 445 -20.025958 +138 445 -30.879114 +139 445 -21.234640 +171 445 -32.949910 +174 445 -14.635255 +175 445 -4.698308 +176 445 -32.934094 +178 445 -10.996936 +180 445 -9.898932 +182 445 -4.462328 +188 445 -15.006041 +192 445 -34.497676 +196 445 -23.329349 +198 445 -14.747152 +199 445 -11.251220 +203 445 -12.377196 +206 445 -2.573196 +211 445 -6.051382 +212 445 -9.521492 +237 445 -14.655370 +239 445 -25.373296 +241 445 -3.192256 +248 445 -15.139286 +251 445 -92.311585 +256 445 -14.639436 +262 445 -34.084176 +264 445 -18.819621 +277 445 -34.479223 +295 445 -17.411199 +297 445 -10.332068 +298 445 -30.945188 +304 445 -38.619583 +305 445 -9.772601 +308 445 -135.112313 +310 445 -17.500626 +311 445 -8.755310 +325 445 -1060.376963 +327 445 -68.252693 +329 445 -9.611020 +341 445 -14.447872 +356 445 1084.030914 +357 445 4007.741520 +358 445 4018.122575 +359 445 321.946237 +369 445 3637.821069 +377 445 4755.022191 +378 445 10031.134742 +379 445 7469.193536 +380 445 3990.946650 +381 445 2914.728256 +394 445 21866.758838 +395 445 45.666616 +398 445 195.437824 +399 445 7900.713082 +400 445 12753.911209 +401 445 16764.794110 +402 445 16427.886014 +403 445 9913.804145 +404 445 7496.454103 +405 445 7502.800278 +406 445 112.590140 +419 445 16416.243396 +420 445 13469.806111 +421 445 26757.439205 +422 445 27322.762886 +423 445 40016.487085 +424 445 51000.342888 +425 445 80494.363454 +426 445 78943.221465 +427 445 68480.842807 +428 445 68486.407866 +429 445 68492.711009 +430 445 19938.851662 +431 445 4460.235684 +444 445 203519.697603 +445 445 11726020.685130 +446 445 130270.408653 +447 445 86283.902828 +448 445 68541.839007 +449 445 40675.599509 +450 445 5177.146131 +470 445 51060.842438 +471 445 87794.081973 +472 445 89132.290565 +473 445 61976.504470 +474 445 52833.449249 +475 445 19126.378864 +476 445 6599.547197 +477 445 6602.055507 +478 445 4583.259748 +479 445 2749.385835 +495 445 15008.083371 +496 445 13066.852698 +497 445 47863.661122 +498 445 49569.989459 +499 445 41973.891767 +500 445 30048.197391 +90 446 -33.233208 +92 446 -1.681295 +95 446 -32.951942 +96 446 -131.710958 +101 446 -8.715563 +133 446 -14.690593 +134 446 -32.963106 +171 446 -32.951326 +174 446 -14.635635 +176 446 -32.935079 +188 446 -15.016925 +192 446 -12.882125 +198 446 -14.750618 +237 446 -14.656299 +251 446 -51.946603 +256 446 -14.639930 +262 446 -24.489465 +268 446 -30.659402 +269 446 -13.626012 +270 446 -13.627279 +274 446 -30.658376 +308 446 -135.211970 +322 446 -88.571069 +324 446 -19.283187 +325 446 -568.116037 +329 446 -30.156641 +338 446 -0.561882 +341 446 -1.944893 +347 446 15928.275120 +369 446 2610.370812 +371 446 440.352154 +372 446 17742.430270 +394 446 13042.633981 +395 446 2574.630504 +396 446 5443.157491 +397 446 12791.120516 +401 446 21.386084 +402 446 378.764612 +403 446 379.013343 +404 446 379.295572 +405 446 379.616668 +406 446 5.696686 +419 446 139.405170 +420 446 11889.576882 +421 446 21063.346326 +422 446 1363.836051 +423 446 13423.797479 +424 446 32094.713198 +425 446 66421.319745 +426 446 68835.425049 +427 446 68483.188542 +428 446 68488.753814 +429 446 68495.057200 +430 446 19939.634624 +431 446 4460.465294 +444 446 101192.641202 +445 446 130270.408653 +446 446 11711186.931637 +447 446 90023.983477 +448 446 68580.951490 +449 446 40677.080085 +450 446 5177.549621 +471 446 28352.303235 +472 446 46708.735558 +473 446 49764.665630 +474 446 50171.483451 +475 446 19136.994062 +476 446 6600.738966 +477 446 6603.247771 +478 446 4584.198495 +479 446 2750.031952 +496 446 18775.743661 +497 446 7523.318984 +498 446 2575.597134 +499 446 9099.616415 +500 446 11618.025888 +90 447 -33.243457 +95 447 -32.953572 +96 447 -131.714554 +116 447 -202.708924 +133 447 -14.692694 +134 447 -32.965074 +171 447 -32.952938 +174 447 -14.636068 +176 447 -32.936200 +188 447 -2.041939 +198 447 -14.754563 +237 447 -13.882151 +251 447 -48.910816 +256 447 -14.640492 +268 447 -45.984819 +269 447 -26.710695 +270 447 -13.406534 +274 447 -43.633693 +308 447 -15.200862 +319 447 -29.370147 +321 447 -29.186351 +324 447 -27.442303 +325 447 -386.614564 +327 447 -70.248830 +328 447 -6.149619 +333 447 -138.002807 +334 447 -30.221986 +336 447 -29.264925 +337 447 -3.400729 +338 447 -18.067783 +347 447 23400.066083 +360 447 4915.728419 +361 447 6796.608681 +362 447 197.893242 +369 447 2925.513448 +372 447 26698.138708 +376 447 6663.964103 +377 447 11642.341404 +382 447 1094.329082 +383 447 6727.312425 +384 447 6746.824100 +385 447 1853.933690 +394 447 9942.688111 +395 447 7375.058882 +396 447 102.896306 +397 447 26604.397385 +400 447 23321.921400 +401 447 28940.280916 +404 447 3417.555279 +405 447 13426.598560 +406 447 12232.389828 +407 447 5616.197409 +420 447 6261.061491 +421 447 9910.100308 +422 447 27373.668951 +423 447 21233.492898 +424 447 66681.573123 +425 447 77904.578143 +426 447 78305.344646 +427 447 81678.056262 +428 447 81701.499388 +429 447 78310.577951 +430 447 19767.521733 +431 447 4319.700500 +444 447 68288.428702 +445 447 86283.902828 +446 447 90023.983477 +447 447 11679287.620186 +448 447 114868.222365 +449 447 55698.963922 +450 447 19881.909393 +451 447 4720.565645 +452 447 1368.575908 +453 447 1368.624241 +454 447 1368.678974 +455 447 1368.741104 +456 447 1368.811843 +457 447 1368.892675 +458 447 1368.985436 +459 447 1369.092413 +460 447 1174.368667 +472 447 30004.174137 +473 447 20170.507573 +474 447 16727.837555 +475 447 9175.665003 +476 447 6602.095437 +477 447 6604.604805 +478 447 4585.267043 +479 447 2750.767451 +497 447 16761.154453 +498 447 12281.118312 +499 447 8368.794704 +500 447 2982.191200 +90 448 -29.070125 +95 448 -22.206897 +96 448 -131.718630 +116 448 -195.888136 +133 448 -14.695075 +134 448 -9.784294 +171 448 -22.998000 +174 448 -14.636558 +176 448 -32.937470 +198 448 -14.759038 +251 448 -20.841932 +256 448 -14.641129 +268 448 -180.942478 +269 448 -82.511903 +270 448 -53.552177 +274 448 -65.115739 +319 448 -33.661787 +321 448 -33.598353 +323 448 -27.359408 +325 448 -307.447216 +328 448 -14.630050 +329 448 -201.206330 +333 448 -113.997945 +335 448 -58.404000 +336 448 -44.561143 +337 448 -16.806779 +338 448 -4.035154 +341 448 -50.591417 +347 448 71733.746145 +360 448 5658.822455 +361 448 7824.029025 +362 448 227.808094 +369 448 1518.587029 +372 448 82140.740260 +373 448 803.833308 +376 448 5504.802624 +377 448 9617.217398 +382 448 1259.755107 +383 448 7744.257488 +384 448 7766.718677 +385 448 2134.186575 +394 448 3527.634306 +395 448 4953.133206 +396 448 508.524945 +397 448 29142.392840 +398 448 52901.939187 +400 448 19265.195931 +401 448 23906.271383 +404 448 3920.715338 +405 448 15422.238515 +406 448 14053.592740 +407 448 6465.178973 +420 448 378.785149 +421 448 4812.745861 +422 448 12546.484579 +423 448 83631.466663 +424 448 47696.094314 +425 448 62937.996151 +426 448 66913.552513 +427 448 70788.299905 +428 448 70812.819054 +429 448 66919.968188 +430 448 14078.569747 +431 448 1794.326111 +444 448 54247.971149 +445 448 68541.839007 +446 448 68580.951490 +447 448 114868.222365 +448 448 11625288.307992 +449 448 65933.946831 +450 448 23751.704570 +451 448 7108.888969 +452 448 3255.865984 +453 448 3255.980968 +454 448 3256.111179 +455 448 3256.258987 +456 448 3256.427275 +457 448 3256.619577 +458 448 3256.840258 +459 448 3257.094757 +460 448 2793.843565 +472 448 4111.270400 +473 448 38314.926589 +474 448 55277.976751 +475 448 10322.723209 +476 448 6603.633817 +477 448 6606.143823 +478 448 4586.478973 +479 448 2751.601699 +498 448 12042.054951 +499 448 67378.160080 +500 448 1243.152213 +58 449 -1.282085 +96 449 -131.723238 +116 449 -81.945418 +133 449 -14.697770 +174 449 -12.825180 +176 449 -17.148894 +198 449 -2.850105 +251 449 -21.053150 +256 449 -3.413068 +268 449 -89.431488 +269 449 -82.240297 +270 449 -24.693723 +274 449 -84.692859 +319 449 -33.690472 +320 449 -110.063739 +321 449 -33.624578 +322 449 -1.282085 +325 449 -182.658255 +326 449 -97.455265 +328 449 -14.630368 +332 449 -14.788659 +337 449 -6.353532 +339 449 -14.699619 +341 449 -58.750704 +347 449 57515.987827 +360 449 5663.239434 +361 449 7830.136050 +362 449 227.985909 +369 449 1912.482112 +372 449 36008.038757 +373 449 29892.838106 +376 449 71.371874 +382 449 1260.738406 +383 449 7750.302248 +384 449 7772.780968 +385 449 2135.852409 +394 449 2933.468121 +395 449 5112.514744 +396 449 3181.389309 +397 449 388.334707 +398 449 62818.759782 +399 449 1549.249777 +400 449 157.369205 +401 449 109.603823 +404 449 3923.994606 +405 449 15434.829617 +406 449 14065.016522 +407 449 6470.225351 +421 449 1944.708446 +422 449 4813.057380 +423 449 35054.887679 +424 449 35137.375858 +425 449 34598.676274 +426 449 48250.086445 +427 449 52126.373806 +428 449 52149.130302 +429 449 48251.003768 +430 449 7280.847536 +431 449 418.284524 +444 449 32193.810636 +445 449 40675.599509 +446 449 40677.080085 +447 449 55698.963922 +448 449 65933.946831 +449 449 11579540.240275 +450 449 31394.107168 +451 449 7540.199255 +452 449 3255.936668 +453 449 3256.051655 +454 449 3256.181869 +455 449 3256.329680 +456 449 3256.497972 +457 449 3256.690278 +458 449 3256.910963 +459 449 3257.165468 +460 449 2793.904218 +472 449 3114.594626 +474 449 35622.036624 +475 449 29811.984176 +476 449 7495.539166 +477 449 7480.438423 +478 449 1907.384486 +479 449 531.359407 +499 449 13858.278597 +500 449 43165.539265 +58 450 -12.856128 +82 450 -0.442688 +96 450 -10.921074 +116 450 -82.007938 +126 450 -4.230330 +133 450 -12.292172 +194 450 -6.567345 +201 450 -173.003373 +214 450 -30.088058 +251 450 -15.917074 +268 450 -36.389134 +269 450 -36.669012 +270 450 -12.316914 +274 450 -45.100095 +319 450 -42.133909 +320 450 -15.310282 +321 450 -41.955586 +322 450 -12.856128 +323 450 -3.806789 +324 450 -41.136869 +325 450 -23.213246 +326 450 -9.235812 +327 450 -3.828471 +328 450 -18.214062 +329 450 -34.029723 +330 450 -9.140216 +331 450 -8.108427 +332 450 -100.771053 +333 450 -41.328419 +335 450 -3.858493 +336 450 -8.506959 +337 450 -4.286250 +338 450 -15.761673 +339 450 -24.742540 +340 450 -3.582514 +341 450 -8.826225 +342 450 -4.167685 +347 450 29875.421598 +348 450 420.515863 +360 450 6629.402220 +361 450 9795.828248 +362 450 285.259586 +369 450 1552.177354 +372 450 4123.880250 +373 450 30005.919566 +374 450 180.842343 +376 450 715.682454 +377 450 3222.416680 +382 450 1261.851429 +383 450 8847.863528 +384 450 9719.778687 +385 450 3125.247782 +394 450 2052.237541 +395 450 3800.853295 +396 450 3236.717661 +398 450 15414.494247 +399 450 18009.417664 +400 450 1584.247907 +401 450 7137.714283 +402 450 2906.146813 +404 450 3927.707179 +405 450 17122.925919 +406 450 17622.831049 +407 450 8402.557628 +408 450 842.143312 +421 450 572.058853 +422 450 3817.849590 +423 450 3828.210908 +424 450 25452.008136 +425 450 12336.274616 +426 450 23077.652821 +427 450 18408.616920 +428 450 21547.783454 +429 450 17807.556030 +430 450 2594.494225 +444 450 4097.458729 +445 450 5177.146131 +446 450 5177.549621 +447 450 19881.909393 +448 450 23751.704570 +449 450 31394.107168 +450 450 11844224.513571 +451 450 24084.628822 +452 450 9930.307318 +453 450 5005.696639 +454 450 4850.249369 +455 450 4850.419054 +456 450 4133.090312 +457 450 4054.023366 +458 450 4054.269829 +459 450 4054.554060 +460 450 3477.851670 +472 450 3115.890333 +474 450 4205.491333 +475 450 40306.487406 +476 450 32325.901164 +477 450 12433.678626 +478 450 3159.481826 +479 450 1816.147211 +480 450 1816.907496 +481 450 1817.774163 +482 450 1818.765857 +483 450 1645.140655 +499 450 10356.763302 +500 450 13170.954570 +2 451 -29.080771 +4 451 -28.698650 +5 451 -13.031269 +12 451 -12.859438 +17 451 -13.028927 +19 451 -4.938707 +23 451 -10.810604 +38 451 -12.590825 +52 451 -28.077937 +58 451 -40.824591 +60 451 -12.664788 +68 451 -28.928535 +69 451 -12.733235 +71 451 -13.195041 +79 451 -28.188562 +82 451 -13.498040 +84 451 -12.650964 +90 451 -57.457501 +94 451 -1.930619 +116 451 -31.585316 +124 451 -7.178413 +126 451 -27.367921 +128 451 -9.426390 +136 451 -12.555441 +148 451 -21.052884 +156 451 -22.838253 +157 451 -16.759505 +159 451 -7.290365 +162 451 -18.877039 +163 451 -5.892227 +186 451 -10.599234 +189 451 -6.286503 +193 451 -6.468600 +194 451 -25.208599 +201 451 -149.686028 +209 451 -14.622039 +214 451 -4.060952 +215 451 -7.114015 +238 451 -28.653865 +242 451 -12.721363 +251 451 -1.914922 +268 451 -27.475803 +269 451 -27.321293 +270 451 -22.586090 +274 451 -12.500929 +298 451 -158.826227 +319 451 -72.281853 +321 451 -70.412636 +322 451 -212.953874 +324 451 -38.677891 +328 451 -29.257120 +329 451 -56.644778 +331 451 -33.101039 +333 451 -459.357293 +337 451 -5.420455 +338 451 -49.810300 +339 451 -13.765386 +340 451 -14.622545 +341 451 -12.575392 +342 451 -3.178658 +347 451 20722.682497 +348 451 1995.285247 +353 451 10898.256345 +354 451 2862.077939 +360 451 7865.137766 +361 451 16652.214181 +362 451 485.252761 +369 451 186.736510 +372 451 433.951036 +373 451 24360.265115 +374 451 1747.624062 +376 451 2111.796750 +377 451 32218.914540 +378 451 17030.253239 +382 451 425.158593 +383 451 8116.547949 +384 451 16487.107965 +385 451 8697.535857 +394 451 246.896835 +395 451 457.266095 +396 451 389.397099 +398 451 856.718524 +399 451 23729.270602 +400 451 1065.315983 +401 451 15900.840636 +402 451 95264.625379 +403 451 6869.367057 +404 451 801.177035 +405 451 15131.320209 +406 451 26407.258941 +407 451 15942.449042 +408 451 8306.232073 +421 451 68.822209 +422 451 459.310855 +423 451 460.557385 +424 451 2202.752189 +425 451 21859.452008 +426 451 83995.187085 +427 451 74390.613318 +428 451 23821.121800 +429 451 31470.543054 +430 451 18238.615269 +431 451 3971.170823 +447 451 4720.565645 +448 451 7108.888969 +449 451 7540.199255 +450 451 24084.628822 +451 451 12300043.907087 +452 451 57532.911675 +453 451 19138.545436 +454 451 10763.390061 +455 451 9762.698973 +456 451 6834.299948 +457 451 6510.984212 +458 451 6511.310105 +459 451 6511.685926 +460 451 5585.417656 +472 451 2101.331995 +474 451 188.243414 +475 451 50201.020888 +476 451 125889.940470 +477 451 16680.985063 +478 451 8601.319197 +479 451 7428.009473 +480 451 7417.163137 +481 451 7420.701134 +482 451 7424.749527 +483 451 6715.959207 +499 451 2773.364763 +500 451 71570.859057 +1 452 -12.213604 +3 452 -27.312571 +6 452 -9.221660 +8 452 -27.451829 +10 452 -12.317314 +14 452 -27.438391 +15 452 -27.437278 +19 452 -22.922856 +21 452 -12.186939 +22 452 -27.542767 +23 452 -1.681615 +26 452 -12.278957 +31 452 -27.607448 +33 452 -12.148988 +37 452 -12.147222 +41 452 -12.148565 +45 452 -22.981646 +52 452 -0.097080 +53 452 -27.438798 +54 452 -27.441824 +57 452 -27.436168 +58 452 -143.159985 +65 452 -27.311119 +72 452 -12.180796 +77 452 -12.299513 +78 452 -12.162885 +90 452 -72.130662 +93 452 -12.162353 +94 452 -10.449801 +116 452 -14.631589 +119 452 -27.310200 +122 452 -27.636248 +124 452 -5.259982 +125 452 -27.564413 +128 452 -18.236829 +138 452 -12.170289 +145 452 -30.473500 +148 452 -7.002329 +156 452 -55.545552 +157 452 -47.041717 +159 452 -5.149492 +160 452 -12.147601 +162 452 -43.332486 +163 452 -21.978525 +166 452 -27.533695 +169 452 -12.302581 +186 452 -1.889449 +187 452 -12.194089 +189 452 -21.588116 +193 452 -5.960775 +195 452 -27.426438 +200 452 -12.166842 +201 452 -120.233645 +203 452 -18.624694 +209 452 -12.895086 +211 452 -21.671134 +212 452 -36.892373 +215 452 -5.323543 +218 452 -27.527585 +220 452 -27.493757 +221 452 -27.501603 +222 452 -27.505688 +224 452 -12.224673 +225 452 -12.219252 +231 452 -12.239741 +233 452 -12.205232 +235 452 -110.037112 +241 452 -27.452055 +268 452 -59.621362 +269 452 -77.208159 +274 452 -51.949607 +298 452 -29.253568 +308 452 -41.212812 +309 452 -42.735784 +319 452 -124.151407 +320 452 -42.487619 +321 452 -86.858025 +322 452 -148.153459 +324 452 -8.721523 +326 452 -117.041863 +327 452 -40.883181 +328 452 -29.257795 +329 452 -127.880036 +331 452 -33.110557 +333 452 -1012.827987 +337 452 -117.084333 +338 452 -4.162548 +339 452 -57.854765 +340 452 -17.566707 +342 452 -13.840030 +347 452 37481.452239 +348 452 22203.953713 +353 452 22853.299844 +354 452 11793.938602 +355 452 497.081580 +360 452 7543.288658 +361 452 20719.933771 +362 452 604.072882 +373 452 28012.698893 +374 452 39093.671083 +375 452 427.680392 +376 452 8128.503539 +377 452 68817.813244 +378 452 43962.764892 +379 452 9242.675073 +383 452 5884.527262 +384 452 19611.509077 +385 452 13048.513046 +399 452 11520.799913 +400 452 46995.599103 +401 452 34749.942796 +402 452 194559.327239 +403 452 51704.175258 +404 452 7359.565347 +405 452 15079.682827 +406 452 35186.052933 +407 452 18833.828067 +408 452 14507.740192 +409 452 872.413089 +425 452 3652.112838 +426 452 68778.012240 +427 452 233460.555794 +428 452 63959.667712 +429 452 44281.222636 +430 452 34309.742243 +431 452 9807.155708 +432 452 1479.961342 +447 452 1368.575908 +448 452 3255.865984 +449 452 3255.936668 +450 452 9930.307318 +451 452 57532.911675 +452 452 12575617.868239 +453 452 70291.907598 +454 452 16194.894281 +455 452 11258.416180 +456 452 6899.927883 +457 452 6511.134479 +458 452 6511.460380 +459 452 6511.836212 +460 452 5585.546564 +472 452 1756.996650 +475 452 23947.377499 +476 452 67133.404939 +477 452 241957.469077 +478 452 53103.932404 +479 452 26922.160519 +480 452 7557.706948 +481 452 7422.835047 +482 452 7426.884604 +483 452 6717.890463 +500 452 11775.889629 +6 453 -19.292844 +7 453 -13.726877 +36 453 -10.314909 +45 453 -40.893243 +46 453 -14.792027 +58 453 -76.000687 +83 453 -187.765065 +85 453 -39.083258 +90 453 -80.610646 +116 453 -14.632105 +137 453 -4.443458 +143 453 -12.793241 +145 453 -49.316214 +154 453 -6.006920 +156 453 -65.383414 +157 453 -64.188615 +162 453 -53.049139 +178 453 -7.856485 +192 453 -12.794925 +197 453 -12.800156 +201 453 -32.022137 +203 453 -63.140545 +209 453 -10.301726 +211 453 -55.027848 +212 453 -48.037554 +213 453 -28.391196 +251 453 -0.623230 +268 453 -31.376740 +269 453 -60.176875 +274 453 -56.376405 +297 453 -155.877628 +298 453 -269.374787 +300 453 -1.235945 +308 453 -69.487663 +309 453 -69.017868 +319 453 -88.429463 +321 453 -133.003337 +322 453 -92.530879 +323 453 -147.186790 +324 453 -39.238532 +327 453 -126.281570 +328 453 -29.258558 +329 453 -117.961441 +330 453 -11.273417 +331 453 -12.397377 +333 453 -74.636003 +334 453 -116.226597 +335 453 -10.301726 +336 453 -123.066650 +337 453 -180.153692 +338 453 -44.697953 +339 453 -237.130774 +340 453 -48.288232 +342 453 -104.149386 +347 453 28490.525079 +348 453 21106.098017 +353 453 4565.353583 +354 453 34965.607670 +355 453 1264.499235 +360 453 9105.743649 +361 453 31966.354338 +362 453 932.338021 +369 453 123.710579 +373 453 17434.576700 +374 453 35934.097356 +375 453 2005.831983 +376 453 5477.651416 +377 453 5739.099268 +378 453 13155.402409 +379 453 80650.495591 +380 453 3665.553419 +381 453 558.498494 +383 453 4689.605007 +384 453 28340.095009 +385 453 22640.406996 +394 453 10.044973 +395 453 140.848810 +396 453 140.911453 +397 453 140.982809 +398 453 141.063809 +399 453 2987.570371 +400 453 36962.117794 +401 453 25596.499998 +402 453 31550.473803 +403 453 41703.077185 +404 453 76573.020421 +405 453 12419.351371 +406 453 26329.497104 +407 453 25805.735718 +408 453 26714.547817 +409 453 3221.014588 +424 453 23.485837 +425 453 281.297106 +426 453 26938.862828 +427 453 101391.996471 +428 453 113384.353765 +429 453 92019.922215 +430 453 42386.163206 +431 453 22816.500079 +432 453 5464.209638 +447 453 1368.624241 +448 453 3255.980968 +449 453 3256.051655 +450 453 5005.696639 +451 453 19138.545436 +452 453 70291.907598 +453 453 12567566.126484 +454 453 78161.313394 +455 453 23239.141652 +456 453 8206.502865 +457 453 6511.304342 +458 453 6511.630253 +459 453 6512.006095 +460 453 5585.692284 +472 453 1757.058701 +475 453 33897.579225 +476 453 43066.893520 +477 453 54689.425903 +478 453 145811.926135 +479 453 127727.591561 +480 453 18031.686488 +481 453 2221.657438 +482 453 2850.731659 +483 453 2583.190149 +5 454 -1.536498 +7 454 -148.635861 +18 454 -13.325335 +27 454 -97.256782 +36 454 -5.050658 +40 454 -70.987705 +45 454 -52.134496 +46 454 -137.433488 +47 454 -10.181533 +56 454 -70.905286 +58 454 -56.840889 +69 454 -7.054273 +70 454 -17.453589 +73 454 -15.811472 +83 454 -30.730196 +85 454 -155.618295 +90 454 -38.934588 +92 454 -51.060901 +95 454 -92.958537 +101 454 -25.980944 +103 454 -42.658560 +104 454 -25.418606 +107 454 -32.350824 +110 454 -14.345885 +112 454 -144.358273 +116 454 -14.632691 +118 454 -392.323491 +123 454 -32.303745 +126 454 -17.031090 +128 454 -92.249552 +134 454 -32.310706 +137 454 -16.518136 +145 454 -43.679604 +146 454 -31.311557 +154 454 -242.347168 +155 454 -23.249928 +156 454 -71.601323 +157 454 -26.039820 +162 454 -37.601197 +167 454 -16.166794 +168 454 -6.340509 +171 454 -77.318229 +173 454 -16.982817 +174 454 -19.956124 +175 454 -15.906907 +176 454 -48.114559 +178 454 -6.146518 +182 454 -6.520800 +192 454 -19.180243 +194 454 -16.336845 +196 454 -13.587853 +201 454 -29.249476 +202 454 -9.247317 +203 454 -167.932564 +209 454 -16.006333 +211 454 -37.229940 +212 454 -233.500490 +214 454 -21.849379 +216 454 -7.116158 +228 454 -13.039558 +239 454 -5.644504 +251 454 -14.962200 +274 454 -2.751777 +279 454 -13.877381 +297 454 -39.731606 +298 454 -105.543401 +300 454 -17.873356 +308 454 -51.705289 +309 454 -34.633244 +319 454 -255.527665 +320 454 -364.556570 +321 454 -105.375127 +322 454 -217.014861 +323 454 -34.196916 +324 454 -80.601995 +326 454 -85.455525 +327 454 -153.605633 +328 454 -86.185547 +329 454 -597.701485 +330 454 -11.569278 +331 454 -76.497719 +332 454 -125.027340 +333 454 -243.426630 +335 454 -265.122661 +336 454 -65.590512 +337 454 -83.441214 +338 454 -63.636283 +339 454 -138.641021 +340 454 -79.701300 +341 454 -256.704247 +342 454 -127.096124 +347 454 503.710981 +348 454 568.547623 +353 454 5115.963728 +354 454 36872.091864 +360 454 5105.234449 +361 454 25542.537776 +362 454 745.328385 +369 454 2969.980598 +373 454 139.243314 +374 454 712.161581 +375 454 202.975152 +376 454 5151.407082 +377 454 25098.207172 +378 454 15028.526272 +379 454 93086.111314 +380 454 16481.648481 +381 454 6818.206335 +383 454 347.487280 +384 454 20656.547490 +385 454 20240.949287 +394 454 241.154594 +395 454 3381.426512 +396 454 3382.930412 +397 454 3384.643510 +398 454 3386.588099 +399 454 2824.954652 +400 454 514.220165 +401 454 6888.269556 +402 454 40357.676089 +403 454 53735.699638 +404 454 136050.243592 +405 454 40429.923499 +406 454 47828.776887 +407 454 17246.895883 +408 454 24694.529513 +409 454 4524.944962 +424 454 563.836029 +425 454 3391.282807 +426 454 3634.993652 +427 454 28931.690720 +428 454 61864.908432 +429 454 228328.432373 +430 454 163324.734904 +431 454 42426.791181 +432 454 7676.020347 +447 454 1368.678974 +448 454 3256.111179 +449 454 3256.181869 +450 454 4850.249369 +451 454 10763.390061 +452 454 16194.894281 +453 454 78161.313394 +454 454 13075382.303555 +455 454 144425.496493 +456 454 27890.578394 +457 454 19214.073530 +458 454 19175.260013 +459 454 19175.919682 +460 454 16447.791218 +472 454 1757.128968 +475 454 19152.283052 +476 454 27685.556627 +477 454 27312.987960 +478 454 138730.210461 +479 454 381279.723627 +480 454 151104.956470 +481 454 26002.711946 +482 454 17648.786654 +483 454 16034.861299 +2 455 -9.113298 +4 455 -1.645017 +5 455 -13.961056 +7 455 -11.306722 +17 455 -30.282510 +18 455 -25.492342 +27 455 -50.732475 +30 455 -14.730485 +36 455 -36.660328 +38 455 -21.440253 +39 455 -14.761797 +40 455 -81.227147 +45 455 -85.950130 +46 455 -17.287376 +47 455 -6.358668 +48 455 -35.415755 +50 455 -22.705328 +51 455 -15.960022 +52 455 -22.638554 +55 455 -15.124218 +56 455 -165.919726 +58 455 -7.272287 +69 455 -9.645606 +70 455 -20.501083 +73 455 -21.748841 +83 455 -15.057012 +85 455 -174.511192 +90 455 -33.059122 +92 455 -110.836573 +95 455 -250.441858 +96 455 -292.810901 +98 455 -130.148369 +99 455 -0.529976 +100 455 -5.944152 +101 455 -30.596440 +103 455 -161.761600 +104 455 -114.433477 +107 455 -251.007456 +110 455 -257.775982 +112 455 -212.266451 +116 455 -14.633355 +118 455 -73.300638 +123 455 -335.580835 +124 455 -0.298955 +126 455 -20.821313 +127 455 -21.074883 +128 455 -48.200839 +134 455 -216.039291 +136 455 -23.760726 +137 455 -17.972335 +145 455 -155.147806 +146 455 -113.610868 +154 455 -73.263187 +155 455 -215.922603 +156 455 -64.552204 +158 455 -40.770595 +161 455 -15.238459 +162 455 -92.389469 +167 455 -71.943440 +168 455 -59.512572 +171 455 -326.191936 +172 455 -1.256096 +173 455 -71.889333 +174 455 -193.760606 +175 455 -72.013985 +176 455 -124.342246 +179 455 -19.399921 +180 455 -12.876500 +181 455 -25.547101 +182 455 -59.472052 +184 455 -0.299228 +186 455 -40.360808 +193 455 -0.191729 +194 455 -32.846764 +196 455 -2.447378 +201 455 -29.249877 +202 455 -69.277789 +203 455 -109.085035 +204 455 -14.606765 +206 455 -24.102658 +211 455 -63.455410 +212 455 -99.815151 +213 455 -15.063190 +214 455 -22.497549 +215 455 -0.299744 +216 455 -9.927669 +228 455 -35.200407 +237 455 -23.443598 +238 455 -2.826354 +239 455 -11.657290 +240 455 -6.202927 +241 455 -34.167593 +242 455 -3.730084 +244 455 -29.213797 +245 455 -11.937226 +247 455 -23.262883 +251 455 -14.982785 +252 455 -12.857986 +256 455 -23.975891 +264 455 -14.509953 +265 455 -1.216507 +267 455 -1.422958 +268 455 -14.295820 +269 455 -14.710604 +274 455 -37.502223 +275 455 -7.723220 +279 455 -23.229338 +281 455 -32.606126 +283 455 -13.903231 +284 455 -0.941084 +292 455 -4.044847 +295 455 -10.858252 +297 455 -80.307997 +298 455 -34.817862 +300 455 -7.796256 +304 455 -0.629022 +305 455 -0.611870 +308 455 -40.383715 +309 455 -6.351361 +310 455 -34.466907 +311 455 -1.481548 +313 455 -1.073973 +319 455 -764.033403 +320 455 -429.576182 +321 455 -37.785833 +322 455 -60.086601 +323 455 -215.252510 +324 455 -528.518112 +326 455 -302.339183 +327 455 -203.107617 +328 455 -95.071036 +329 455 -104.386250 +330 455 -11.233220 +331 455 -124.051986 +332 455 -727.324369 +333 455 -232.967444 +335 455 -154.815158 +336 455 -290.960195 +337 455 -165.997937 +338 455 -402.197118 +339 455 -449.917671 +340 455 -618.413108 +341 455 -514.954415 +342 455 -98.726624 +347 455 11684.063815 +348 455 15871.462310 +349 455 5546.794657 +353 455 1250.571547 +354 455 62490.778936 +358 455 1656.777939 +359 455 301.714435 +360 455 905.476599 +361 455 8873.333131 +362 455 275.428661 +369 455 2974.066531 +374 455 10368.414168 +375 455 15965.042944 +376 455 8512.274699 +377 455 25874.549319 +378 455 5248.964134 +379 455 109818.592607 +380 455 10850.432437 +381 455 1429.711488 +382 455 253.493663 +383 455 2015.103297 +384 455 4067.263671 +385 455 8417.531462 +386 455 549.407217 +394 455 241.486361 +395 455 3386.078489 +396 455 3387.584457 +397 455 3389.299912 +398 455 3391.247177 +399 455 2828.841066 +401 455 8949.258552 +402 455 39170.822538 +403 455 55333.514200 +404 455 103694.560041 +405 455 70364.341805 +406 455 132485.159651 +407 455 5497.684063 +408 455 6374.066291 +409 455 5172.931520 +424 455 564.611723 +425 455 3395.948343 +426 455 3398.771573 +427 455 7903.194250 +428 455 40971.297586 +429 455 136140.932989 +430 455 529785.200187 +431 455 138648.552535 +432 455 6204.216281 +433 455 2796.574356 +447 455 1368.741104 +448 455 3256.258987 +449 455 3256.329680 +450 455 4850.419054 +451 455 9762.698973 +452 455 11258.416180 +453 455 23239.141652 +454 455 144425.496493 +455 455 14347245.220977 +456 455 138315.052333 +457 455 23033.878122 +458 455 21151.667410 +459 455 21152.355480 +460 455 18143.006242 +472 455 1757.208731 +475 455 11708.342251 +476 455 18013.979604 +477 455 16600.360524 +478 455 32947.591719 +479 455 198083.646369 +480 455 667957.996721 +481 455 344802.410007 +482 455 41265.171387 +483 455 26271.558819 +1 456 -25.187298 +2 456 -3.655776 +3 456 -10.810839 +4 456 -10.392946 +6 456 -37.130185 +8 456 -25.132492 +13 456 -25.043083 +14 456 -25.075256 +15 456 -25.073969 +16 456 -25.557973 +19 456 -25.813406 +21 456 -24.991629 +22 456 -25.325364 +25 456 -25.054454 +26 456 -11.324818 +28 456 -25.105531 +32 456 -10.792652 +34 456 -10.756038 +36 456 -36.025557 +37 456 -24.258069 +38 456 -7.410322 +39 456 -31.803827 +41 456 -26.213901 +42 456 -25.159726 +43 456 -10.818276 +44 456 -104.598601 +45 456 -51.073977 +48 456 -117.551111 +49 456 -25.990362 +50 456 -6.313395 +51 456 -8.534256 +52 456 -6.371129 +53 456 -25.077809 +54 456 -100.333489 +55 456 -3.857234 +56 456 -83.641404 +57 456 -25.072678 +59 456 -26.433110 +60 456 -26.761233 +62 456 -9.858349 +63 456 -25.716598 +64 456 -24.526376 +65 456 -10.812932 +66 456 -11.044782 +67 456 -24.860753 +70 456 -0.122685 +72 456 -11.110969 +75 456 -25.046517 +77 456 -11.359123 +78 456 -11.044228 +80 456 -10.777455 +83 456 -3.306633 +84 456 -26.727328 +85 456 -25.083768 +86 456 -11.162606 +87 456 -11.890283 +89 456 -24.563042 +90 456 -3.289917 +91 456 -24.972050 +92 456 -77.679153 +93 456 -33.893291 +94 456 -36.034300 +96 456 -10.617923 +99 456 -35.883730 +100 456 -35.745603 +101 456 -18.844015 +103 456 -19.732245 +104 456 -31.918344 +105 456 -26.238255 +106 456 -24.417693 +107 456 -28.432548 +108 456 -24.412278 +109 456 -24.416418 +110 456 -37.440272 +111 456 -25.197600 +112 456 -48.916755 +116 456 -14.634111 +117 456 -26.056074 +118 456 -55.749545 +119 456 -24.316919 +120 456 -24.319991 +122 456 -25.491160 +124 456 -36.012643 +125 456 -15.739567 +127 456 -7.728339 +128 456 -22.456902 +129 456 -24.667185 +130 456 -11.422099 +131 456 -11.418869 +132 456 -11.559339 +133 456 -25.709945 +134 456 -33.852644 +135 456 -13.559641 +136 456 -5.403338 +137 456 -36.137659 +141 456 -24.427082 +145 456 -42.008423 +146 456 -30.140585 +148 456 -26.160610 +149 456 -24.996342 +150 456 -26.052283 +151 456 -11.111377 +152 456 -25.888194 +153 456 -11.123412 +154 456 -36.521500 +155 456 -130.414554 +156 456 -73.680736 +157 456 -28.260238 +158 456 -340.393980 +159 456 -26.050807 +160 456 -9.684839 +161 456 -57.779269 +162 456 -74.802447 +163 456 -36.069106 +164 456 -9.915848 +166 456 -35.346715 +167 456 -16.176955 +168 456 -16.308483 +169 456 -35.617832 +171 456 -37.665332 +172 456 -3.488899 +173 456 -17.000079 +174 456 -16.675798 +175 456 -16.191204 +176 456 -11.444095 +177 456 -29.369083 +178 456 -4.684414 +179 456 -2.016943 +180 456 -5.059893 +181 456 -14.543581 +182 456 -16.296932 +183 456 -36.071471 +184 456 -9.964432 +185 456 -35.476682 +186 456 -33.740789 +187 456 -24.940093 +188 456 -6.950007 +189 456 -36.113148 +190 456 -20.494566 +191 456 -4.556974 +193 456 -10.059884 +194 456 -4.185427 +195 456 -25.031989 +196 456 -12.434062 +197 456 -4.385309 +201 456 -16.082386 +202 456 -17.301063 +203 456 -46.795154 +204 456 -55.095876 +206 456 -15.803889 +211 456 -28.636978 +212 456 -16.069167 +213 456 -13.034239 +214 456 -1.834952 +215 456 -36.012312 +216 456 -13.822449 +217 456 -29.860105 +219 456 -25.192166 +220 456 -25.241019 +221 456 -25.258463 +222 456 -29.703642 +223 456 -100.874635 +224 456 -25.263147 +227 456 -25.058910 +228 456 -4.210445 +229 456 -35.230862 +230 456 -34.990318 +231 456 -29.814102 +233 456 -25.156019 +234 456 -11.317790 +235 456 -29.690353 +237 456 -45.656960 +238 456 -24.195536 +240 456 -35.527686 +241 456 -7.566357 +242 456 -27.995963 +244 456 -5.576772 +245 456 -1.226435 +247 456 -5.832040 +250 456 -29.773728 +251 456 -1.492022 +252 456 -19.710776 +253 456 -34.503372 +256 456 -109.793507 +257 456 -29.653846 +258 456 -28.503358 +259 456 -10.754937 +261 456 -10.878034 +262 456 -7.929980 +263 456 -29.402662 +264 456 -24.099074 +265 456 -65.889938 +266 456 -25.041876 +267 456 -35.436285 +268 456 -1.613915 +269 456 -1.605150 +271 456 -34.623941 +272 456 -24.792970 +273 456 -15.899579 +274 456 -39.722955 +275 456 -15.374146 +278 456 -35.207846 +282 456 -26.104429 +284 456 -35.664405 +285 456 -34.039123 +287 456 -11.106277 +289 456 -25.357798 +290 456 -25.336707 +292 456 -8.186263 +293 456 -24.569589 +294 456 -24.577763 +295 456 -28.146748 +296 456 -24.425592 +297 456 -107.300813 +298 456 -34.949561 +299 456 -15.112589 +300 456 -13.801599 +302 456 -29.314807 +304 456 -30.534321 +305 456 -30.535814 +306 456 -24.697295 +307 456 -11.077488 +308 456 -3.332774 +310 456 -117.364309 +311 456 -35.497395 +312 456 -26.231743 +313 456 -15.543854 +314 456 -33.930890 +315 456 -34.951643 +316 456 -34.934524 +317 456 -34.915187 +318 456 -24.691374 +319 456 -3425.023372 +320 456 -96.484007 +321 456 -88.316592 +322 456 -15.562266 +323 456 -36.840872 +324 456 -331.362070 +326 456 -49.866680 +327 456 -27.938387 +328 456 -151.921862 +329 456 -48.265519 +331 456 -121.658469 +332 456 -108.841232 +333 456 -39.382723 +335 456 -24.822192 +336 456 -25.226461 +337 456 -231.126967 +338 456 -252.701850 +339 456 -125.800355 +340 456 -800.621098 +341 456 -87.041929 +342 456 -346.688520 +347 456 7297.349259 +348 456 10168.692399 +349 456 6413.950660 +353 456 481.124745 +354 456 46013.980206 +355 456 3520.931116 +358 456 4184.964888 +359 456 812.438535 +361 456 18895.075979 +362 456 678.000057 +369 456 296.164713 +374 456 3779.490560 +375 456 10221.604952 +376 456 8963.185017 +377 456 5402.253263 +378 456 1664.028285 +379 456 59016.379645 +380 456 32949.330260 +381 456 5781.108474 +382 456 575.028181 +383 456 5205.122458 +384 456 503.729931 +385 456 20064.650724 +386 456 4229.791574 +394 456 24.047794 +395 456 337.193857 +396 456 337.343825 +397 456 337.514654 +398 456 337.708568 +399 456 281.702811 +401 456 1290.490700 +402 456 14476.809027 +403 456 19428.677823 +404 456 20643.380849 +405 456 89263.514302 +406 456 462372.044215 +407 456 5585.945285 +408 456 4153.663851 +409 456 20816.695270 +410 456 2698.244522 +424 456 56.225396 +425 456 338.176721 +426 456 338.457865 +427 456 4639.963651 +428 456 9543.359713 +429 456 27965.131168 +430 456 148040.874480 +431 456 690339.223939 +432 456 13103.363827 +433 456 18388.786504 +434 456 1145.691456 +447 456 1368.811843 +448 456 3256.427275 +449 456 3256.497972 +450 456 4133.090312 +451 456 6834.299948 +452 456 6899.927883 +453 456 8206.502865 +454 456 27890.578394 +455 456 138315.052333 +456 456 15164504.520632 +457 456 74339.062503 +458 456 33997.162108 +459 456 33875.528931 +460 456 29061.030631 +472 456 1757.299546 +475 456 948.188092 +476 456 1486.307844 +477 456 1421.469331 +478 456 7315.145210 +479 456 34230.676475 +480 456 302059.127857 +481 456 691741.718635 +482 456 151449.387439 +483 456 30504.479334 +5 457 -5.044059 +6 457 -30.586221 +7 457 -80.047474 +27 457 -74.233878 +36 457 -137.656732 +39 457 -123.999913 +45 457 -29.610458 +48 457 -26.048194 +55 457 -7.931850 +56 457 -2.763457 +62 457 -14.286437 +68 457 -0.845954 +69 457 -36.569625 +70 457 -16.858210 +81 457 -8.826667 +82 457 -74.190929 +85 457 -9.221498 +92 457 -54.569660 +101 457 -9.237813 +115 457 -9.142565 +116 457 -14.634975 +118 457 -32.912484 +126 457 -16.379131 +133 457 -33.057434 +135 457 -10.581264 +137 457 -5.559205 +138 457 -9.837939 +140 457 -29.665948 +145 457 -93.688419 +154 457 -32.900137 +155 457 -52.554446 +156 457 -33.773559 +157 457 -30.247103 +158 457 -7.653971 +161 457 -161.630990 +162 457 -104.207733 +167 457 -36.982530 +168 457 -34.924367 +173 457 -151.731949 +175 457 -36.824025 +178 457 -24.872290 +180 457 -37.902806 +182 457 -34.739523 +188 457 -5.880152 +194 457 -13.719504 +196 457 -9.979604 +197 457 -10.762978 +199 457 -1.410199 +201 457 -14.627822 +202 457 -6.054058 +203 457 -48.378220 +205 457 -3.596850 +208 457 -3.728128 +214 457 -5.624414 +228 457 -16.472295 +234 457 -17.177802 +237 457 -58.853086 +239 457 -3.500976 +256 457 -39.815235 +274 457 -16.801658 +277 457 -11.065363 +279 457 -11.075130 +281 457 -21.305887 +295 457 -44.268571 +297 457 -13.232175 +298 457 -2.179332 +300 457 -37.519499 +308 457 -32.168504 +309 457 -32.476949 +319 457 -199.007771 +321 457 -820.284528 +323 457 -6.068628 +324 457 -102.216528 +327 457 -9.543281 +328 457 -325.158712 +331 457 -288.400637 +334 457 -28.656662 +337 457 -265.519907 +338 457 -30.771190 +342 457 -184.980368 +347 457 2834.851844 +348 457 3971.985666 +349 457 2742.863963 +354 457 66449.554388 +355 457 4146.468177 +358 457 4953.820588 +359 457 1857.501144 +361 457 154081.284867 +362 457 6664.348964 +374 457 1238.509996 +375 457 3992.054877 +376 457 3831.893956 +378 457 1578.168765 +379 457 10565.089742 +380 457 74909.408486 +381 457 38682.784892 +383 457 7761.716552 +384 457 77.490856 +385 457 128482.155784 +386 457 72378.989168 +401 457 172.319910 +402 457 4192.331425 +403 457 4033.921589 +404 457 8924.517321 +405 457 27518.386181 +406 457 133528.942002 +407 457 12961.836603 +408 457 7459.507513 +409 457 123527.091891 +410 457 93058.358631 +427 457 268.206912 +428 457 509.788130 +429 457 5221.833175 +430 457 12063.202355 +431 457 91804.519775 +432 457 125512.523051 +433 457 138842.889372 +434 457 93969.362812 +447 457 1368.892675 +448 457 3256.619577 +449 457 3256.690278 +450 457 4054.023366 +451 457 6510.984212 +452 457 6511.134479 +453 457 6511.304342 +454 457 19214.073530 +455 457 23033.878122 +456 457 74339.062503 +457 457 14453591.669091 +458 457 182738.324010 +459 457 72678.676527 +460 457 62361.041364 +472 457 1757.403320 +475 457 10255.707609 +476 457 14445.681808 +477 457 14448.917049 +478 457 19457.792811 +479 457 24512.717692 +480 457 66158.643913 +481 457 182601.431326 +482 457 118661.828001 +483 457 136609.381055 +484 457 4390.647523 +5 458 -35.305093 +6 458 -14.793105 +7 458 -24.189262 +20 458 -14.179447 +27 458 -36.523970 +39 458 -58.360781 +55 458 -4.409279 +68 458 -16.825666 +69 458 -10.226924 +70 458 -3.977437 +81 458 -10.400333 +82 458 -97.785142 +92 458 -21.120072 +103 458 -0.348524 +115 458 -10.148951 +116 458 -14.635967 +118 458 -32.913540 +126 458 -26.177770 +133 458 -33.069070 +138 458 -31.428842 +140 458 -15.639301 +145 458 -55.644298 +154 458 -32.900298 +155 458 -0.211963 +156 458 -38.215304 +157 458 -37.938071 +161 458 -132.438042 +162 458 -74.129125 +167 458 -9.904513 +168 458 -11.513040 +170 458 -1.862591 +173 458 -35.961307 +175 458 -10.028262 +179 458 -39.243388 +180 458 -8.372798 +182 458 -11.657678 +188 458 -6.709643 +194 458 -28.307643 +196 458 -2.152468 +199 458 -11.884810 +201 458 -14.628295 +202 458 -34.486422 +205 458 -26.238771 +206 458 -1.115856 +208 458 -26.083502 +213 458 -35.375702 +214 458 -12.960956 +228 458 -26.103290 +237 458 -15.726848 +239 458 -26.352228 +241 458 -15.423586 +247 458 -0.123988 +248 458 -10.656892 +262 458 -14.580496 +279 458 -30.432340 +281 458 -22.250668 +283 458 -4.978867 +295 458 -76.822699 +300 458 -0.095897 +308 458 -33.135265 +309 458 -33.134267 +310 458 -3.445495 +319 458 -154.935167 +321 458 -682.894277 +323 458 -18.860941 +328 458 -329.065858 +331 458 -110.686050 +335 458 -10.242463 +339 458 -23.744883 +341 458 -23.974411 +342 458 -171.281996 +354 458 52003.842914 +355 458 4240.581099 +358 458 3129.535618 +359 458 7557.988798 +361 458 120214.052683 +362 458 5772.076831 +379 458 552.673351 +380 458 54920.473551 +381 458 8989.548204 +383 458 11221.372249 +384 458 772.164844 +385 458 81164.911282 +386 458 75347.505455 +405 458 3499.803474 +406 458 66728.478117 +407 458 22181.464165 +408 458 12134.946964 +409 458 61679.767515 +410 458 106448.907548 +411 458 0.182723 +430 458 56.826626 +431 458 11506.593464 +432 458 83242.243050 +433 458 78269.369768 +434 458 117703.153407 +435 458 2782.864594 +447 458 1368.985436 +448 458 3256.840258 +449 458 3256.910963 +450 458 4054.269829 +451 458 6511.310105 +452 458 6511.460380 +453 458 6511.630253 +454 458 19175.260013 +455 458 21151.667410 +456 458 33997.162108 +457 458 182738.324010 +458 458 13821867.574487 +459 458 81971.835816 +460 458 63119.057532 +472 458 1757.522408 +475 458 10512.297906 +476 458 14808.599462 +477 458 14811.916015 +478 458 19355.994356 +479 458 22203.822288 +480 458 31127.051638 +481 458 112749.670778 +482 458 97909.671118 +483 458 85832.618283 +484 458 24758.947881 +2 459 -5.672320 +6 459 -0.162442 +7 459 -8.951231 +17 459 -30.963781 +18 459 -31.294592 +20 459 -2.615057 +38 459 -26.571090 +47 459 -115.429887 +51 459 -30.571842 +52 459 -30.420765 +58 459 -1.299752 +79 459 -30.479592 +97 459 -7.856989 +98 459 -28.436145 +101 459 -11.435994 +103 459 -14.704044 +107 459 -31.537246 +110 459 -13.477733 +112 459 -33.017592 +116 459 -14.637111 +118 459 -32.914757 +133 459 -33.082500 +134 459 -111.620097 +136 459 -30.593096 +137 459 -27.235697 +138 459 -3.976926 +139 459 -1.117761 +140 459 -9.429725 +146 459 -90.383251 +154 459 -32.900484 +155 459 -0.574920 +161 459 -132.504588 +167 459 -8.388852 +168 459 -7.936738 +170 459 -14.989121 +186 459 -28.178901 +192 459 -25.484436 +198 459 -16.404406 +201 459 -14.628840 +206 459 -13.484842 +213 459 -3.659495 +228 459 -0.505696 +241 459 -19.460642 +244 459 -30.771391 +245 459 -30.843105 +247 459 -14.330514 +248 459 -23.451516 +251 459 -17.654432 +252 459 -13.752178 +275 459 -18.237990 +281 459 -7.167887 +283 459 -28.244228 +292 459 -30.659867 +295 459 -39.447237 +298 459 -20.859445 +304 459 -30.372171 +305 459 -13.495656 +308 459 -33.153951 +309 459 -33.152873 +310 459 -29.545836 +311 459 -30.269047 +313 459 -13.926264 +320 459 -9.914146 +321 459 -740.043030 +326 459 -9.853608 +328 459 -799.722625 +332 459 -9.860529 +338 459 -9.818955 +342 459 -9.113673 +355 459 21.720069 +359 459 5487.846034 +361 459 102076.764165 +362 459 7797.573915 +369 459 3748.126588 +370 459 2451.347426 +376 459 220.038186 +377 459 160.652323 +380 459 17.984223 +381 459 1794.154866 +384 459 6041.944865 +385 459 2139.592641 +386 459 131351.647376 +395 459 1494.510386 +396 459 3946.397047 +397 459 3947.010684 +398 459 3947.706459 +399 459 3948.493540 +400 459 3949.382804 +401 459 3950.387192 +402 459 8143.348882 +403 459 3799.705167 +404 459 294.060226 +405 459 294.359829 +406 459 829.005990 +407 459 1749.483494 +409 459 6058.076985 +410 459 114364.396512 +411 459 25521.241436 +428 459 5113.567076 +429 459 8622.444283 +430 459 57112.216580 +431 459 81024.557303 +432 459 82280.521026 +433 459 82562.723535 +434 459 45936.016635 +435 459 122929.726641 +447 459 1369.092413 +448 459 3257.094757 +449 459 3257.165468 +450 459 4054.554060 +451 459 6511.685926 +452 459 6511.836212 +453 459 6512.006095 +454 459 19175.919682 +455 459 21152.355480 +456 459 33875.528931 +457 459 72678.676527 +458 459 81971.835816 +459 459 13394345.988582 +460 459 159570.226499 +472 459 1757.659746 +475 459 10518.213083 +476 459 14816.932503 +477 459 14820.250923 +478 459 19366.175364 +479 459 22215.160566 +480 459 22221.731942 +481 459 38463.416846 +482 459 18626.114920 +483 459 116926.166746 +484 459 84461.333761 +485 459 1306.813147 +2 460 -6.748318 +8 460 -6.424869 +15 460 -6.936143 +16 460 -16.943933 +17 460 -21.525191 +19 460 -9.048967 +20 460 -12.182791 +21 460 -6.887534 +22 460 -27.370905 +23 460 -31.148411 +25 460 -1.793941 +27 460 -14.746031 +28 460 -7.939394 +31 460 -24.135238 +32 460 -14.747022 +34 460 -14.869824 +36 460 -14.288346 +37 460 -14.685008 +38 460 -23.792087 +40 460 -10.019620 +42 460 -22.839353 +43 460 -59.215500 +44 460 -40.112588 +47 460 -4.548613 +50 460 -9.495067 +52 460 -21.331865 +53 460 -3.849293 +54 460 -10.897401 +55 460 -0.006368 +58 460 -115.826749 +60 460 -27.683659 +61 460 -59.195636 +62 460 -6.578521 +63 460 -7.153144 +67 460 -6.842637 +71 460 -11.579610 +77 460 -7.360903 +84 460 -24.358748 +87 460 -10.838673 +91 460 -0.081185 +97 460 -4.822646 +98 460 -28.420668 +100 460 -18.140293 +101 460 -13.038565 +102 460 -14.704658 +103 460 -12.617186 +106 460 -14.870580 +107 460 -28.401363 +108 460 -14.864124 +109 460 -14.869853 +110 460 -12.626025 +112 460 -28.393138 +113 460 -6.710316 +116 460 -12.555299 +117 460 -26.825364 +118 460 -28.232103 +119 460 -59.017420 +120 460 -6.560504 +122 460 -15.105622 +124 460 -23.583377 +125 460 -6.144375 +131 460 -20.631474 +132 460 -94.155289 +133 460 -28.387189 +134 460 -113.697163 +135 460 -59.764766 +137 460 -29.280798 +138 460 -31.078569 +139 460 -13.917346 +140 460 -125.363753 +142 460 -25.523333 +143 460 -6.455462 +146 460 -113.867119 +148 460 -23.728441 +150 460 -23.603602 +152 460 -26.556988 +153 460 -6.862536 +154 460 -28.218916 +155 460 -115.861980 +156 460 -14.304633 +157 460 -14.437821 +159 460 -30.849608 +160 460 -14.701254 +161 460 -113.710292 +163 460 -22.410503 +164 460 -9.279849 +166 460 -12.841648 +167 460 -30.501458 +168 460 -30.552656 +169 460 -22.774828 +170 460 -12.881515 +172 460 -11.063762 +183 460 -9.942751 +185 460 -14.779471 +186 460 -1.721167 +191 460 -6.386667 +192 460 -4.047331 +193 460 -30.797422 +194 460 -30.904257 +195 460 -16.322124 +197 460 -6.451495 +198 460 -29.810110 +201 460 -12.547656 +202 460 -29.869548 +203 460 -21.975213 +204 460 -41.867037 +205 460 -4.556026 +206 460 -10.692101 +208 460 -4.562002 +211 460 -18.956281 +212 460 -19.022213 +213 460 -14.010260 +214 460 -29.839779 +215 460 -30.855502 +217 460 -21.535762 +218 460 -5.399914 +220 460 -15.780598 +221 460 -15.795159 +222 460 -15.803861 +223 460 -19.868655 +224 460 -20.429595 +227 460 -8.223048 +228 460 -31.681825 +229 460 -63.144609 +230 460 -8.294403 +231 460 -29.789474 +232 460 -20.990759 +235 460 -20.114195 +238 460 -7.584859 +239 460 -4.546437 +240 460 -18.162060 +242 460 -24.747532 +250 460 -28.285474 +251 460 -28.519850 +252 460 -22.247784 +253 460 -6.737413 +254 460 -14.723361 +255 460 -40.765255 +257 460 -11.027653 +258 460 -14.626479 +259 460 -14.622006 +261 460 -14.917712 +262 460 -4.429956 +263 460 -6.878698 +265 460 -30.852557 +266 460 -9.223135 +267 460 -40.658584 +269 460 -24.109787 +270 460 -10.619985 +271 460 -15.282600 +272 460 -15.275931 +274 460 -91.355649 +275 460 -30.348597 +277 460 -6.775376 +278 460 -15.778111 +279 460 -30.551856 +281 460 -30.643527 +282 460 -40.026821 +283 460 -10.416139 +284 460 -27.126943 +285 460 -59.202654 +286 460 -20.785870 +287 460 -15.492301 +288 460 -16.888048 +289 460 -28.675632 +290 460 -28.000208 +292 460 -22.011297 +293 460 -15.061926 +294 460 -15.068383 +295 460 -22.469339 +296 460 -14.879728 +297 460 -16.562230 +298 460 -28.483663 +299 460 -6.572154 +304 460 -22.068640 +306 460 -15.196468 +307 460 -6.832005 +308 460 -28.453304 +309 460 -28.452307 +310 460 -24.909524 +311 460 -9.753308 +312 460 -17.954275 +313 460 -10.241165 +314 460 -14.680859 +315 460 -2.021233 +316 460 -8.618487 +317 460 -0.497042 +321 460 -884.979556 +328 460 -3324.816669 +337 460 -22.469339 +347 460 21008.275276 +348 460 28631.445191 +349 460 28653.579408 +350 460 25489.592643 +351 460 6240.351580 +354 460 6184.904789 +355 460 5826.882936 +359 460 3320.472361 +361 460 94242.981988 +362 460 16051.945576 +369 460 6054.910649 +370 460 3960.028907 +375 460 3189.040646 +376 460 42075.238170 +377 460 43055.564480 +378 460 29404.649006 +379 460 31102.019587 +380 460 14415.167868 +381 460 14775.479191 +382 460 6098.431756 +384 460 3613.751221 +386 460 131287.620665 +395 460 2414.306625 +396 460 6375.206638 +397 460 6376.197938 +398 460 6377.321928 +399 460 6378.593418 +400 460 6380.029980 +401 460 6381.652517 +402 460 23770.414753 +403 460 31690.919230 +404 460 34432.270084 +405 460 59540.173252 +406 460 78203.927986 +407 460 42296.587291 +408 460 16884.312652 +409 460 4741.043588 +410 460 3736.648786 +411 460 130877.542143 +428 460 7248.581785 +429 460 12762.335287 +430 460 62561.957185 +431 460 102830.455109 +432 460 149936.882843 +433 460 181716.362847 +434 460 129904.542815 +435 460 44901.729537 +436 460 110755.901906 +447 460 1174.368667 +448 460 2793.843565 +449 460 2793.904218 +450 460 3477.851670 +451 460 5585.417656 +452 460 5585.546564 +453 460 5585.692284 +454 460 16447.791218 +455 460 18143.006242 +456 460 29061.030631 +457 460 62361.041364 +458 460 63119.057532 +459 460 159570.226499 +460 460 13220641.291162 +461 460 17582.684397 +472 460 1507.670712 +475 460 9026.903996 +476 460 12716.136264 +477 460 12718.984187 +478 460 16619.718267 +479 460 19064.355229 +480 460 19069.994643 +481 460 34273.428867 +482 460 17949.795574 +483 460 77119.288815 +484 460 151595.671728 +485 460 373724.909752 +486 460 7363.856918 +3 461 -9.276005 +8 461 -16.063496 +9 461 -9.352637 +16 461 -6.093737 +19 461 -1.281799 +21 461 -9.856108 +22 461 -11.200097 +24 461 -20.551460 +25 461 -8.152579 +32 461 -20.803997 +33 461 -9.226439 +34 461 -9.390506 +37 461 -20.664620 +40 461 -6.124387 +42 461 -15.381330 +43 461 -20.913289 +53 461 -18.522090 +54 461 -18.417792 +55 461 -9.863991 +66 461 -9.769719 +67 461 -9.780387 +77 461 -2.868210 +80 461 -20.959350 +89 461 -21.310155 +91 461 -9.792238 +102 461 -20.715754 +106 461 -21.037778 +108 461 -21.025102 +109 461 -84.146257 +119 461 -83.227584 +120 461 -9.254105 +121 461 -9.635507 +122 461 -7.826996 +125 461 -4.016436 +129 461 -21.575259 +131 461 -2.629810 +135 461 -85.582361 +141 461 -21.058153 +143 461 -20.463267 +152 461 -0.106483 +160 461 -20.702236 +163 461 -0.965153 +164 461 -19.948178 +166 461 -4.356045 +169 461 -3.380689 +178 461 -20.221499 +183 461 -0.445285 +185 461 -8.134936 +187 461 -9.753409 +188 461 -21.328020 +190 461 -20.851443 +191 461 -6.263009 +195 461 -9.135872 +205 461 -2.576765 +208 461 -2.568442 +217 461 -4.469567 +218 461 -4.721022 +223 461 -5.945891 +224 461 -5.447143 +227 461 -8.628683 +230 461 -8.562422 +231 461 -8.980484 +232 461 -8.945715 +234 461 -20.730297 +235 461 -5.728073 +239 461 -2.590146 +250 461 -10.359193 +253 461 -21.573989 +257 461 -6.025260 +258 461 -20.547298 +259 461 -20.537673 +261 461 -84.497151 +262 461 -2.755236 +263 461 -9.839106 +266 461 -20.001064 +271 461 -9.688892 +272 461 -9.683535 +277 461 -22.167296 +280 461 -20.685357 +288 461 -8.621894 +289 461 -10.001786 +290 461 -10.621618 +293 461 -21.405349 +294 461 -21.416730 +295 461 -26.065857 +296 461 -21.055624 +302 461 -9.840116 +306 461 -21.649545 +307 461 -9.756442 +314 461 -20.659363 +315 461 -20.270817 +316 461 -20.573772 +317 461 -9.393602 +318 461 -86.163088 +321 461 -1496.473510 +328 461 -16.614976 +342 461 -26.065857 +359 461 5032.253778 +361 461 116668.463988 +362 461 59462.567758 +384 461 2442.668910 +385 461 2876.928679 +386 461 206025.159299 +387 461 1437.658768 +410 461 5056.048988 +411 461 209477.923053 +412 461 836.575215 +435 461 527.541484 +436 461 216994.316483 +437 461 838.141976 +460 461 17582.684397 +461 461 12329496.375615 +462 461 244.404657 +485 461 72468.371834 +486 461 151349.766831 +487 461 4341.440670 +40 462 -7.670096 +191 462 -2.565649 +196 462 -8.678173 +199 462 -6.953640 +205 462 -18.139283 +207 462 -18.325244 +208 462 -18.092260 +239 462 -17.818981 +254 462 -19.519242 +262 462 -77.942812 +321 462 -195.705379 +362 462 23576.265573 +387 462 27022.811375 +412 462 26603.493802 +437 462 26234.611173 +461 462 244.404657 +462 462 11753449.488444 +463 462 1595.142456 +486 462 346.247716 +487 462 13891.796931 +488 462 11402.787000 +40 463 -12.109049 +199 463 -1.802820 +205 463 -1.543471 +207 463 -1.356151 +208 463 -1.590840 +216 463 -8.935004 +239 463 -1.866140 +321 463 -29.203476 +362 463 3678.440670 +387 463 4184.877669 +412 463 4087.263795 +437 463 3336.792735 +438 463 662.094660 +462 463 1595.142456 +463 463 11372272.642069 +488 463 3847.924568 +464 464 11111111.111111 +465 465 11111111.111111 +466 466 11111111.111111 +467 467 11111111.111111 +468 468 11478892.583568 +51 469 -27.896355 +65 469 -33.409349 +75 469 -130.179284 +93 469 -135.281367 +100 469 -14.016751 +132 469 -14.086615 +136 469 -28.157955 +141 469 -14.677975 +142 469 -29.761171 +143 469 -4.978916 +144 469 -129.000379 +163 469 -14.122150 +164 469 -32.424422 +166 469 -14.401511 +172 469 -13.957224 +177 469 -32.605634 +179 469 -10.333722 +183 469 -31.768573 +184 469 -31.667236 +185 469 -32.243624 +186 469 -27.708322 +189 469 -31.798491 +190 469 -14.931073 +193 469 -31.686931 +194 469 -34.229349 +197 469 -2.220876 +202 469 -25.616198 +234 469 -26.789011 +242 469 -31.422513 +244 469 -34.262652 +246 469 -31.732979 +247 469 -5.740521 +250 469 -32.389572 +251 469 -31.454989 +252 469 -2.311271 +253 469 -32.547179 +257 469 -32.449738 +258 469 -15.125385 +263 469 -14.387150 +265 469 -31.672327 +266 469 -130.284174 +267 469 -14.002131 +271 469 -130.388016 +273 469 -14.148300 +275 469 -19.036504 +279 469 -32.662933 +280 469 -33.750588 +282 469 -14.061370 +283 469 -34.100517 +284 469 -14.044361 +285 469 -33.381150 +291 469 -33.616377 +292 469 -1.135003 +293 469 -14.648554 +294 469 -32.933204 +296 469 -14.680273 +299 469 -33.679296 +301 469 -128.704845 +302 469 -14.548846 +306 469 -14.573710 +307 469 -32.331285 +315 469 -14.454949 +316 469 -14.467416 +317 469 -14.472574 +318 469 -14.462950 +322 469 -31.454989 +325 469 -2082.561077 +369 469 1113.529831 +394 469 6737.736846 +419 469 6719.960476 +444 469 348497.634587 +469 469 11972099.781028 +470 469 25237.143590 +471 469 36.307470 +494 469 305755.854356 +495 469 156212.049303 +496 469 10299.905694 +497 469 43.036328 +51 470 -7.601628 +97 470 -36.172943 +135 470 -42.605447 +136 470 -7.297292 +137 470 -17.041858 +138 470 -4.737842 +139 470 -15.624725 +142 470 -5.445293 +143 470 -38.319533 +175 470 -12.783648 +178 470 -28.205288 +179 470 -30.170131 +180 470 -29.651228 +182 470 -13.095041 +186 470 -7.820767 +196 470 -13.201302 +197 470 -17.018112 +199 470 -4.861174 +202 470 -10.282129 +206 470 -39.977721 +234 470 -142.483421 +239 470 -10.871922 +241 470 -39.053574 +247 470 -37.113396 +248 470 -0.561949 +251 470 -131.175656 +252 470 -177.082228 +264 470 -18.471391 +275 470 -18.360266 +277 470 -0.814079 +279 470 -2.145051 +292 470 -176.391714 +301 470 -10.777381 +304 470 -119.903098 +305 470 -29.819089 +310 470 -20.053252 +311 470 -31.182557 +325 470 -1216.997472 +327 470 -131.175656 +369 470 4940.747373 +394 470 29802.584301 +419 470 29560.262889 +444 470 276656.123766 +445 470 51060.842438 +469 470 25237.143590 +470 470 12003880.344911 +471 470 85445.957780 +472 470 10227.281315 +473 470 127.920211 +495 470 68236.437420 +496 470 216435.180172 +497 470 103697.063261 +498 470 24811.222983 +499 470 4675.832378 +500 470 182.432796 +97 471 -14.555938 +101 471 -26.033028 +116 471 -22.763848 +135 471 -4.628685 +137 471 -37.204349 +138 471 -35.700555 +139 471 -36.987921 +175 471 -11.966067 +178 471 -27.895137 +180 471 -25.388758 +182 471 -11.427321 +192 471 -21.662342 +196 471 -36.646884 +199 471 -16.159532 +206 471 -8.595491 +239 471 -36.351001 +241 471 -10.019279 +248 471 -15.734017 +251 471 -37.873822 +252 471 -5.340000 +262 471 -9.628763 +264 471 -37.436227 +268 471 -30.776261 +269 471 -13.679620 +270 471 -13.676840 +274 471 -30.779911 +277 471 -35.365904 +292 471 -8.054180 +304 471 -99.325267 +305 471 -25.100204 +310 471 -37.709507 +311 471 -22.775225 +322 471 -111.676479 +325 471 -657.691581 +329 471 -21.746836 +341 471 -16.126986 +347 471 15989.771164 +369 471 1705.430662 +371 471 441.953656 +372 471 17810.947537 +394 471 10130.352022 +395 471 103.329763 +396 471 5463.413960 +397 471 12841.181633 +419 471 1155.942973 +420 471 8897.231109 +421 471 17546.562785 +422 471 816.354450 +444 471 132679.302478 +445 471 87794.081973 +446 471 28352.303235 +469 471 36.307470 +470 471 85445.957780 +471 471 12029408.303305 +472 471 60953.455478 +473 471 16342.228901 +474 471 2763.378761 +496 471 59615.154464 +497 471 105609.618321 +498 471 74305.029126 +499 471 41527.965924 +500 471 18741.137529 +101 472 -34.809230 +116 472 -509.420199 +137 472 -11.186745 +138 472 -35.796367 +139 472 -14.130518 +188 472 -12.987394 +192 472 -34.597923 +196 472 -19.188510 +199 472 -10.638581 +239 472 -24.074964 +248 472 -15.771557 +251 472 -33.079098 +262 472 -34.157086 +264 472 -8.228815 +268 472 -30.014863 +269 472 -13.334917 +270 472 -13.362921 +274 472 -43.588355 +277 472 -35.449035 +308 472 -120.124734 +310 472 -4.970407 +319 472 -2.921319 +320 472 -37.099611 +321 472 -3.046259 +322 472 -7.435874 +324 472 -181.192651 +325 472 -416.111867 +327 472 -70.032586 +328 472 -7.894966 +329 472 -53.483548 +332 472 -38.640342 +333 472 -5.179271 +334 472 -30.268471 +335 472 -126.871093 +336 472 -30.186014 +339 472 -32.726211 +342 472 -15.822139 +347 472 18368.214919 +360 472 513.067955 +361 472 709.380548 +362 472 20.654656 +369 472 1696.117839 +372 472 20589.072845 +376 472 250.099829 +377 472 436.939267 +382 472 114.218105 +383 472 702.147909 +384 472 704.184395 +385 472 193.500105 +394 472 8137.349444 +395 472 2004.907383 +397 472 20530.326826 +400 472 875.276106 +401 472 1086.134198 +404 472 343.604811 +405 472 1368.280655 +406 472 1249.560002 +407 472 586.177810 +420 472 7358.874324 +421 472 2537.891664 +422 472 20479.584768 +423 472 313.744437 +424 472 1318.670758 +425 472 451.558671 +426 472 1016.024922 +427 472 1362.021526 +428 472 1363.844120 +429 472 1022.311917 +444 472 77651.084720 +445 472 89132.290565 +446 472 46708.735558 +447 472 30004.174137 +448 472 4111.270400 +449 472 3114.594626 +450 472 3115.890333 +451 472 2101.331995 +452 472 1756.996650 +453 472 1757.058701 +454 472 1757.128968 +455 472 1757.208731 +456 472 1757.299546 +457 472 1757.403320 +458 472 1757.522408 +459 472 1757.659746 +460 472 1507.670712 +470 472 10227.281315 +471 472 60953.455478 +472 472 12101410.986836 +473 472 75746.071484 +474 472 46372.009876 +475 472 12301.014910 +496 472 1556.979242 +497 472 77722.345495 +498 472 108344.962367 +499 472 56377.430040 +500 472 37658.173661 +90 473 -4.184959 +101 473 -30.827601 +116 473 -63.363767 +138 473 -1.233446 +188 473 -15.043433 +192 473 -34.658806 +248 473 -3.963092 +251 473 -43.483248 +262 473 -34.201285 +268 473 -91.722725 +269 473 -65.607098 +270 473 -14.705420 +274 473 -32.810327 +277 473 -9.911027 +308 473 -135.454715 +323 473 -27.123078 +324 473 -46.332007 +325 473 -269.478363 +329 473 -61.813303 +335 473 -42.422751 +336 473 -73.486438 +338 473 -14.192381 +339 473 -34.130715 +342 473 -12.191913 +347 473 37280.344493 +369 473 2531.593559 +372 473 43703.616293 +373 473 1.245072 +394 473 9033.270611 +395 473 6054.794759 +397 473 25935.809068 +398 473 17374.923299 +420 473 6204.780197 +421 473 8423.166540 +422 473 15078.478762 +423 473 27853.748667 +444 473 49116.356990 +445 473 61976.504470 +446 473 49764.665630 +447 473 20170.507573 +448 473 38314.926589 +470 473 127.920211 +471 473 16342.228901 +472 473 75746.071484 +473 473 11928538.378628 +474 473 63919.746340 +475 473 14204.219624 +498 473 29661.143270 +499 473 54527.259457 +500 473 35007.293452 +58 474 -14.374296 +90 474 -33.268244 +116 474 -34.178023 +188 474 -15.059422 +192 474 -5.235777 +198 474 -11.913997 +214 474 -6.857175 +251 474 -18.123949 +262 474 -30.675241 +268 474 -152.763400 +269 474 -71.186204 +270 474 -50.879146 +274 474 -82.820765 +308 474 -135.601142 +320 474 -6.227886 +322 474 -14.374296 +325 474 -231.753823 +326 474 -90.850528 +329 474 -137.225425 +333 474 -6.857175 +335 474 -15.423345 +337 474 -10.551945 +338 474 -7.572003 +339 474 -34.178023 +341 474 -107.922332 +347 474 69783.788180 +369 474 1267.386059 +372 474 67990.779487 +373 474 11861.088544 +376 474 800.196668 +377 474 543.318542 +394 474 3190.393251 +395 474 4001.838666 +396 474 319.271619 +397 474 9353.912805 +398 474 69423.681129 +400 474 1764.368891 +401 474 2325.636544 +402 474 412.826333 +420 474 710.793873 +421 474 4352.684283 +422 474 2137.823396 +423 474 70499.216264 +424 474 7229.440112 +425 474 3041.203110 +426 474 1545.691446 +444 474 41794.754729 +445 474 52833.449249 +446 474 50171.483451 +447 474 16727.837555 +448 474 55277.976751 +449 474 35622.036624 +450 474 4205.491333 +451 474 188.243414 +471 474 2763.378761 +472 474 46372.009876 +473 474 63919.746340 +474 474 11974799.662225 +475 474 25396.416877 +476 474 2677.640184 +477 474 2678.965505 +478 474 2680.465910 +479 474 2221.186401 +499 474 63243.699539 +500 474 36337.468045 +58 475 -8.780397 +82 475 -14.197990 +90 475 -330.188720 +116 475 -7.116825 +126 475 -32.198627 +133 475 -2.408641 +188 475 -11.764092 +194 475 -32.392681 +198 475 -14.769826 +201 475 -238.116776 +209 475 -2.837448 +214 475 -28.118555 +251 475 -14.560368 +268 475 -60.912201 +269 475 -61.579545 +270 475 -11.602055 +274 475 -60.140597 +298 475 -113.219681 +308 475 -190.636210 +309 475 -159.887679 +319 475 -70.683139 +320 475 -144.869867 +321 475 -68.505294 +322 475 -148.584846 +323 475 -33.814565 +324 475 -37.612808 +325 475 -84.309998 +326 475 -39.325856 +327 475 -29.477206 +328 475 -46.931798 +329 475 -143.287158 +330 475 -12.890637 +332 475 -85.973280 +333 475 -106.907854 +335 475 -41.562377 +336 475 -56.479740 +337 475 -51.190082 +339 475 -52.072917 +340 475 -42.332726 +341 475 -40.445867 +342 475 -58.170901 +347 475 41944.062672 +353 475 338.253261 +360 475 3820.519028 +361 475 16550.148583 +362 475 482.842245 +369 475 1097.784021 +372 475 14167.584351 +373 475 33742.891933 +376 475 449.937154 +377 475 8117.067982 +378 475 567.072653 +383 475 822.560731 +384 475 14053.716102 +385 475 12607.614855 +394 475 2379.241576 +395 475 3672.166262 +396 475 440.555007 +398 475 38622.039419 +399 475 8277.586511 +401 475 14620.395814 +402 475 13217.128369 +405 475 7014.879538 +406 475 15712.635182 +407 475 12310.522285 +408 475 15416.364415 +409 475 2272.000639 +421 475 3245.970612 +422 475 2949.929608 +423 475 3947.703787 +424 475 41894.159288 +425 475 58.783474 +426 475 45409.433422 +427 475 4174.634859 +428 475 3408.960998 +429 475 20954.926432 +430 475 24100.803162 +431 475 14609.419357 +432 475 3854.249933 +444 475 15131.897326 +445 475 19126.378864 +446 475 19136.994062 +447 475 9175.665003 +448 475 10322.723209 +449 475 29811.984176 +450 475 40306.487406 +451 475 50201.020888 +452 475 23947.377499 +453 475 33897.579225 +454 475 19152.283052 +455 475 11708.342251 +456 475 948.188092 +457 475 10255.707609 +458 475 10512.297906 +459 475 10518.213083 +460 475 9026.903996 +472 475 12301.014910 +473 475 14204.219624 +474 475 25396.416877 +475 475 12343928.899177 +476 475 74722.592692 +477 475 33254.567684 +478 475 19258.412693 +479 475 15815.026142 +480 475 10498.820006 +481 475 10502.717494 +482 475 251.468111 +499 475 14662.254366 +500 475 149189.337566 +2 476 -29.424106 +4 476 -28.994403 +5 476 -13.196266 +6 476 -0.876754 +10 476 -5.943525 +12 476 -13.004119 +17 476 -13.193657 +19 476 -28.027701 +23 476 -12.585534 +38 476 -12.699513 +45 476 -3.902438 +52 476 -28.395900 +58 476 -29.199747 +60 476 -12.784088 +68 476 -29.253428 +69 476 -12.861824 +71 476 -13.378176 +77 476 -2.777152 +79 476 -28.411591 +84 476 -12.768330 +90 476 -117.167831 +94 476 -12.453772 +124 476 -12.522521 +128 476 -15.058625 +133 476 -14.704251 +136 476 -12.658796 +148 476 -28.256432 +156 476 -33.856212 +157 476 -33.953290 +159 476 -12.524242 +162 476 -33.919102 +163 476 -28.038671 +169 476 -3.355050 +186 476 -12.581415 +189 476 -28.043283 +193 476 -12.511890 +198 476 -14.776294 +201 476 -228.943175 +203 476 -14.355894 +209 476 -12.139043 +211 476 -2.770129 +212 476 -25.579510 +215 476 -12.521536 +238 476 -28.943731 +242 476 -12.848372 +251 476 -14.065681 +268 476 -20.900137 +269 476 -21.043155 +270 476 -19.766796 +274 476 -21.216713 +298 476 -48.761741 +308 476 -136.476802 +309 476 -103.084195 +319 476 -73.930756 +320 476 -23.790392 +321 476 -77.717536 +322 476 -196.523653 +324 476 -88.120256 +325 476 -29.480545 +326 476 -19.046689 +328 476 -66.112469 +329 476 -48.217277 +330 476 -17.301952 +332 476 -50.471033 +333 476 -514.959024 +337 476 -31.886100 +338 476 -54.002645 +339 476 -73.503080 +340 476 -66.396207 +341 476 -17.213149 +342 476 -32.803774 +347 476 19283.328141 +348 476 957.290519 +353 476 16881.981174 +354 476 5252.070456 +355 476 47.260267 +360 476 3863.246938 +361 476 18827.646096 +362 476 549.371176 +369 476 1371.636032 +372 476 1173.718955 +373 476 21570.008508 +374 476 504.275205 +376 476 1511.463817 +377 476 35520.966374 +378 476 29739.420620 +379 476 2844.916855 +383 476 372.642465 +384 476 15357.085431 +385 476 14820.682385 +394 476 1813.531780 +395 476 3358.757503 +396 476 2860.239237 +398 476 4193.925718 +399 476 18271.293507 +400 476 85.102000 +401 476 5964.291407 +402 476 113545.783582 +403 476 21255.214993 +404 476 1021.154413 +405 476 6372.510043 +406 476 15656.904164 +407 476 12934.836702 +408 476 18088.620140 +409 476 3206.286778 +421 476 505.519896 +422 476 3373.776876 +423 476 3382.933018 +424 476 8341.061684 +425 476 13764.935275 +426 476 43524.672245 +427 476 102765.298120 +428 476 6677.755789 +429 476 19778.076790 +430 476 26946.284870 +431 476 17623.350816 +432 476 5439.224999 +444 476 5222.796175 +445 476 6599.547197 +446 476 6600.738966 +447 476 6602.095437 +448 476 6603.633817 +449 476 7495.539166 +450 476 32325.901164 +451 476 125889.940470 +452 476 67133.404939 +453 476 43066.893520 +454 476 27685.556627 +455 476 18013.979604 +456 476 1486.307844 +457 476 14445.681808 +458 476 14808.599462 +459 476 14816.932503 +460 476 12716.136264 +474 476 2677.640184 +475 476 74722.592692 +476 476 12702946.417069 +477 476 73302.034101 +478 476 27694.525289 +479 476 21233.588887 +480 476 14789.612394 +481 476 14795.103002 +482 476 355.701744 +499 476 142.691600 +500 476 42946.958876 +1 477 -12.245813 +3 477 -27.230770 +6 477 -18.374785 +7 477 -0.479330 +8 477 -27.514143 +10 477 -6.433955 +14 477 -27.495631 +15 477 -27.494088 +21 477 -12.209219 +22 477 -27.634705 +26 477 -12.330014 +31 477 -3.960713 +33 477 -12.102409 +36 477 -3.944144 +37 477 -12.102114 +41 477 -12.102331 +45 477 -48.199866 +46 477 -2.746153 +53 477 -27.496196 +54 477 -27.500383 +57 477 -27.492546 +58 477 -131.320148 +65 477 -27.231371 +72 477 -12.200451 +77 477 -9.578427 +78 477 -12.173700 +85 477 -11.380801 +90 477 -33.178349 +93 477 -12.106598 +119 477 -27.231826 +122 477 -27.753277 +125 477 -27.662535 +128 477 -13.186892 +133 477 -17.033846 +137 477 -9.423991 +138 477 -12.110069 +145 477 -42.150461 +156 477 -58.658612 +157 477 -42.681471 +160 477 -12.102170 +162 477 -29.770788 +166 477 -27.622962 +169 477 -9.004318 +187 477 -12.219238 +195 477 -27.478953 +198 477 -14.783608 +200 477 -12.108498 +201 477 -52.887351 +203 477 -29.866197 +209 477 -13.088161 +211 477 -46.570327 +212 477 -37.639442 +218 477 -27.615023 +220 477 -27.570594 +221 477 -27.580976 +222 477 -27.586362 +224 477 -12.260504 +225 477 -12.253338 +231 477 -12.280167 +233 477 -12.234532 +235 477 -110.364338 +241 477 -27.514452 +251 477 -15.884693 +268 477 -18.459623 +269 477 -15.659078 +270 477 -13.919152 +274 477 -7.015387 +297 477 -4.369451 +298 477 -12.626959 +300 477 -4.880475 +308 477 -95.513847 +309 477 -60.574527 +319 477 -20.686548 +320 477 -25.648447 +321 477 -50.189813 +322 477 -108.203545 +324 477 -17.383428 +325 477 -29.491743 +326 477 -115.447107 +327 477 -115.199437 +328 477 -66.127276 +329 477 -182.029609 +333 477 -869.189705 +337 477 -6.970607 +338 477 -37.669812 +339 477 -55.265050 +340 477 -63.480495 +341 477 -2.851554 +342 477 -9.623444 +347 477 12769.184731 +348 477 1181.828653 +353 477 20751.970622 +354 477 12484.558458 +355 477 1052.999924 +360 477 2292.565918 +361 477 12181.152542 +362 477 355.469411 +369 477 1549.019715 +372 477 191.822403 +373 477 15124.143133 +374 477 939.103413 +376 477 7301.258007 +377 477 58995.312468 +378 477 40610.076450 +379 477 17655.548106 +380 477 838.263588 +381 477 19.502244 +384 477 9665.573197 +385 477 9793.500634 +394 477 2048.062616 +395 477 3793.121110 +396 477 3230.133113 +398 477 327.119413 +399 477 15025.847285 +400 477 357.794808 +401 477 26778.929773 +402 477 161590.240814 +403 477 56958.062992 +404 477 18731.593046 +405 477 1306.803415 +406 477 4297.341540 +407 477 7910.242071 +408 477 11938.826545 +409 477 2340.761884 +421 477 570.895097 +422 477 3810.082829 +423 477 3820.423069 +424 477 1210.620020 +425 477 14239.852625 +426 477 23948.389912 +427 477 171424.617070 +428 477 70396.856945 +429 477 6221.327697 +430 477 14409.292359 +431 477 12068.892920 +432 477 3970.948970 +444 477 5224.781193 +445 477 6602.055507 +446 477 6603.247771 +447 477 6604.604805 +448 477 6606.143823 +449 477 7480.438423 +450 477 12433.678626 +451 477 16680.985063 +452 477 241957.469077 +453 477 54689.425903 +454 477 27312.987960 +455 477 16600.360524 +456 477 1421.469331 +457 477 14448.917049 +458 477 14811.916015 +459 477 14820.250923 +460 477 12718.984187 +474 477 2678.965505 +475 477 33254.567684 +476 477 73302.034101 +477 477 12895160.302257 +478 477 42521.982984 +479 477 21240.727709 +480 477 14792.924695 +481 477 14798.416533 +482 477 355.781440 +500 477 444.602886 +6 478 -10.037946 +7 478 -130.760401 +31 478 -23.427575 +36 478 -11.978916 +45 478 -13.459352 +46 478 -27.426484 +56 478 -28.820964 +58 478 -50.669460 +69 478 -4.908989 +70 478 -13.346608 +73 478 -10.957009 +83 478 -50.259639 +85 478 -67.864269 +92 478 -26.464970 +95 478 -42.221314 +101 478 -25.779904 +103 478 -12.746831 +104 478 -6.225577 +107 478 -13.594778 +110 478 -6.758754 +112 478 -44.456501 +123 478 -14.637544 +126 478 -12.731636 +133 478 -433.373629 +134 478 -14.482645 +137 478 -25.338804 +143 478 -12.590500 +145 478 -38.430513 +146 478 -12.656017 +154 478 -45.317134 +155 478 -5.187860 +156 478 -53.212283 +157 478 -53.140149 +162 478 -53.152471 +167 478 -11.473934 +168 478 -3.871003 +171 478 -38.133598 +173 478 -12.661379 +174 478 -8.508257 +175 478 -11.095840 +176 478 -14.548901 +182 478 -4.133123 +194 478 -11.721353 +197 478 -12.596288 +198 478 -14.791888 +201 478 -37.898732 +202 478 -1.421954 +203 478 -38.538210 +211 478 -29.290608 +212 478 -37.221232 +213 478 -28.002119 +214 478 -19.750981 +228 478 -6.927093 +268 478 -51.352768 +269 478 -61.886120 +274 478 -44.292513 +279 478 -8.144640 +297 478 -157.084700 +298 478 -16.176317 +300 478 -16.415025 +308 478 -66.486793 +309 478 -33.071646 +319 478 -188.266183 +320 478 -91.692890 +321 478 -12.413093 +322 478 -232.559483 +323 478 -156.873800 +324 478 -35.072555 +325 478 -20.455665 +327 478 -116.095174 +328 478 -86.454423 +329 478 -378.317597 +330 478 -11.986767 +331 478 -114.314349 +332 478 -20.279488 +333 478 -76.616482 +334 478 -118.497482 +336 478 -138.117946 +337 478 -139.647438 +338 478 -50.030818 +339 478 -139.700383 +340 478 -33.414415 +341 478 -17.911424 +342 478 -15.196588 +347 478 31403.941174 +348 478 18116.242567 +354 478 32373.742738 +355 478 708.306629 +361 478 2807.342782 +362 478 93.311451 +373 478 23949.553868 +374 478 31654.264353 +375 478 248.116995 +376 478 3458.282162 +377 478 5563.558283 +378 478 2784.208066 +379 478 72961.815163 +380 478 16270.482300 +381 478 5895.150529 +384 478 173.028543 +385 478 3143.845359 +386 478 379.463369 +399 478 10753.152803 +400 478 38947.578528 +401 478 12887.901561 +402 478 18641.300723 +403 478 20570.532411 +404 478 68791.017156 +405 478 33886.565914 +406 478 34609.416927 +408 478 1147.217089 +409 478 2935.356051 +425 478 3607.752179 +426 478 38960.522914 +427 478 34042.825746 +428 478 45596.129148 +429 478 84463.972295 +430 478 78041.412068 +431 478 12845.615831 +432 478 2587.235450 +433 478 1931.531826 +444 478 3627.062951 +445 478 4583.259748 +446 478 4584.198495 +447 478 4585.267043 +448 478 4586.478973 +449 478 1907.384486 +450 478 3159.481826 +451 478 8601.319197 +452 478 53103.932404 +453 478 145811.926135 +454 478 138730.210461 +455 478 32947.591719 +456 478 7315.145210 +457 478 19457.792811 +458 478 19355.994356 +459 478 19366.175364 +460 478 16619.718267 +474 478 2680.465910 +475 478 19258.412693 +476 478 27694.525289 +477 478 42521.982984 +478 478 13034434.353754 +479 478 145013.734037 +480 478 46413.385713 +481 478 41363.862325 +482 478 25919.128142 +483 478 23118.006431 +5 479 -16.166555 +7 479 -36.433050 +17 479 -4.542362 +30 479 -12.645940 +45 479 -52.300952 +46 479 -33.357521 +48 479 -21.940921 +56 479 -71.170527 +58 479 -40.611079 +69 479 -12.607878 +70 479 -26.494032 +73 479 -28.439723 +83 479 -102.283702 +85 479 -79.406139 +92 479 -36.382168 +95 479 -92.622103 +96 479 -25.281350 +101 479 -59.659007 +103 479 -42.258308 +104 479 -32.558510 +107 479 -37.164455 +110 479 -45.375155 +112 479 -128.626094 +118 479 -247.097298 +123 479 -18.743788 +126 479 -26.993859 +133 479 -208.424191 +134 479 -18.906985 +137 479 -35.731263 +145 479 -37.657709 +146 479 -31.790216 +154 479 -188.984705 +155 479 -116.560714 +156 479 -63.653194 +157 479 -26.041091 +158 479 -15.853835 +162 479 -37.590904 +167 479 -95.396713 +168 479 -75.561890 +171 479 -56.893662 +173 479 -97.021443 +174 479 -24.969552 +175 479 -95.120215 +176 479 -52.096958 +178 479 -13.624835 +179 479 -16.362342 +180 479 -18.033723 +182 479 -75.799325 +192 479 -31.059767 +194 479 -39.430807 +198 479 -12.257399 +201 479 -33.133533 +202 479 -65.534425 +203 479 -155.758802 +209 479 -26.261093 +211 479 -37.259814 +212 479 -130.087387 +214 479 -27.365546 +228 479 -42.532732 +237 479 -14.683324 +256 479 -15.874843 +268 479 -34.853875 +269 479 -69.651792 +274 479 -56.063319 +279 479 -30.741836 +281 479 -24.550334 +283 479 -6.181867 +295 479 -3.044941 +297 479 -45.877215 +298 479 -288.466534 +300 479 -13.074732 +308 479 -49.458756 +309 479 -33.081116 +319 479 -448.706576 +320 479 -171.916469 +321 479 -45.210493 +322 479 -102.636588 +323 479 -113.782966 +324 479 -70.612651 +325 479 -12.257399 +326 479 -65.317964 +327 479 -269.557201 +328 479 -99.193671 +329 479 -402.992712 +330 479 -11.550956 +331 479 -165.195044 +332 479 -114.742795 +333 479 -44.684602 +335 479 -289.136344 +336 479 -154.385997 +337 479 -215.789430 +338 479 -73.632099 +339 479 -322.699625 +340 479 -468.448348 +341 479 -256.818274 +342 479 -100.255529 +347 479 30969.608703 +348 479 22475.224723 +353 479 2772.600959 +354 479 27269.498466 +358 479 464.604407 +359 479 84.608717 +361 479 10098.336742 +362 479 341.369659 +373 479 19352.646034 +374 479 38902.801531 +375 479 1884.121152 +376 479 3123.488180 +377 479 3805.491708 +378 479 16144.443309 +379 479 60243.979466 +380 479 3710.920346 +381 479 1702.317610 +382 479 71.086336 +383 479 565.088327 +384 479 498.065089 +385 479 11230.816732 +386 479 1557.058356 +399 479 3210.518630 +400 479 40398.376356 +401 479 19543.086407 +402 479 23636.093002 +403 479 15881.403287 +404 479 96209.726716 +405 479 13739.533301 +406 479 81143.735385 +407 479 665.474446 +408 479 3529.978963 +409 479 10861.067125 +410 479 262.177256 +425 479 160.341161 +426 479 29414.575986 +427 479 91713.415045 +428 479 44836.474215 +429 479 118796.220217 +430 479 166603.272812 +431 479 48752.206472 +432 479 8728.721320 +433 479 7717.408174 +444 479 2175.734794 +445 479 2749.385835 +446 479 2750.031952 +447 479 2750.767451 +448 479 2751.601699 +449 479 531.359407 +450 479 1816.147211 +451 479 7428.009473 +452 479 26922.160519 +453 479 127727.591561 +454 479 381279.723627 +455 479 198083.646369 +456 479 34230.676475 +457 479 24512.717692 +458 479 22203.822288 +459 479 22215.160566 +460 479 19064.355229 +474 479 2221.186401 +475 479 15815.026142 +476 479 21233.588887 +477 479 21240.727709 +478 479 145013.734037 +479 479 13738385.830970 +480 479 209753.858743 +481 479 53527.181439 +482 479 37283.148377 +483 479 33394.019920 +2 480 -13.114869 +4 480 -12.293683 +7 480 -11.407530 +17 480 -26.701773 +18 480 -18.448030 +19 480 -5.102938 +27 480 -135.118354 +30 480 -2.661649 +36 480 -36.939436 +38 480 -29.642978 +40 480 -98.364707 +41 480 -15.536908 +44 480 -56.184500 +45 480 -11.535572 +46 480 -93.817949 +47 480 -14.136051 +48 480 -31.275797 +49 480 -10.070856 +50 480 -29.831163 +51 480 -43.460308 +52 480 -29.821048 +56 480 -99.558918 +58 480 -46.824378 +59 480 -20.211682 +60 480 -26.248698 +63 480 -2.088591 +69 480 -11.881770 +70 480 -6.249131 +83 480 -16.631856 +84 480 -25.669579 +85 480 -154.406313 +87 480 -11.604996 +92 480 -101.779294 +94 480 -31.965161 +95 480 -183.066746 +96 480 -198.998426 +98 480 -122.653711 +99 480 -40.037364 +100 480 -108.004609 +101 480 -37.171710 +103 480 -85.523979 +104 480 -55.704473 +105 480 -16.086648 +107 480 -123.037922 +110 480 -119.855031 +112 480 -68.005167 +117 480 -11.762163 +118 480 -79.305219 +123 480 -133.087214 +124 480 -38.108061 +125 480 -10.283870 +127 480 -29.589968 +128 480 -104.629081 +130 480 -0.683851 +131 480 -0.577539 +132 480 -4.686963 +133 480 -165.127459 +134 480 -45.447923 +136 480 -29.993776 +137 480 -17.947256 +140 480 -2.704457 +145 480 -61.681714 +146 480 -47.958567 +148 480 -14.304694 +150 480 -11.666624 +152 480 -7.281580 +154 480 -49.732630 +155 480 -135.704366 +156 480 -51.936790 +158 480 -88.488242 +159 480 -11.629367 +161 480 -132.349274 +162 480 -52.682208 +163 480 -32.827540 +164 480 -20.269629 +166 480 -22.745956 +167 480 -123.199989 +168 480 -122.854039 +169 480 -24.205738 +171 480 -187.077873 +172 480 -12.318488 +173 480 -165.574377 +174 480 -121.295930 +175 480 -123.251741 +176 480 -62.590279 +177 480 -8.443088 +179 480 -15.978150 +180 480 -42.209231 +181 480 -59.140008 +182 480 -122.401003 +183 480 -32.884864 +184 480 -26.550552 +185 480 -23.480583 +186 480 -147.882189 +189 480 -33.899766 +193 480 -26.516227 +194 480 -30.147194 +196 480 -15.370233 +201 480 -33.147403 +202 480 -129.394190 +203 480 -85.307117 +204 480 -138.281843 +206 480 -58.921014 +211 480 -30.103702 +212 480 -133.291827 +213 480 -28.799069 +214 480 -12.974802 +215 480 -38.117645 +216 480 -9.855923 +217 480 -10.335175 +222 480 -9.839629 +228 480 -30.555349 +229 480 -22.030419 +230 480 -20.239871 +231 480 -10.185618 +235 480 -9.799697 +237 480 -31.622710 +238 480 -27.589081 +239 480 -7.814269 +240 480 -108.120171 +241 480 -61.991282 +242 480 -39.822274 +244 480 -44.080175 +245 480 -13.556306 +247 480 -29.916425 +250 480 -10.066405 +252 480 -41.008288 +253 480 -14.072997 +256 480 -17.020968 +257 480 -9.670315 +263 480 -8.643612 +264 480 -56.792581 +265 480 -117.806802 +267 480 -47.454010 +269 480 -0.948834 +271 480 -16.103067 +273 480 -11.076118 +274 480 -4.777030 +275 480 -40.740009 +278 480 -21.872635 +281 480 -9.290604 +282 480 -12.959816 +283 480 -8.200898 +284 480 -43.397822 +292 480 -12.511294 +295 480 -34.182279 +297 480 -68.033042 +298 480 -65.529022 +300 480 -39.313470 +302 480 -8.128347 +304 480 -34.202297 +305 480 -33.946988 +308 480 -33.092691 +309 480 -33.091874 +310 480 -222.768531 +311 480 -49.613880 +312 480 -15.940440 +313 480 -24.329772 +315 480 -19.896840 +316 480 -19.735930 +317 480 -19.554272 +319 480 -1204.092240 +320 480 -626.098008 +321 480 -199.010695 +322 480 -128.180106 +323 480 -165.581045 +324 480 -120.901471 +326 480 -330.802842 +327 480 -103.379529 +328 480 -99.223008 +329 480 -109.788941 +330 480 -11.266506 +331 480 -165.236419 +332 480 -408.097099 +333 480 -299.107568 +335 480 -157.584660 +336 480 -220.080473 +337 480 -64.379932 +338 480 -131.759800 +339 480 -158.888532 +340 480 -2430.188271 +341 480 -519.077160 +342 480 -129.940234 +347 480 1055.251111 +348 480 1092.259172 +353 480 3885.804227 +354 480 37602.611544 +358 480 5215.613465 +359 480 949.810975 +361 480 39138.419670 +362 480 1582.374732 +373 480 380.309879 +374 480 1466.940018 +375 480 352.360828 +376 480 4282.036232 +377 480 31475.667758 +378 480 4373.333785 +379 480 82126.019485 +380 480 10179.131148 +381 480 1442.458452 +382 480 798.009757 +383 480 6343.638240 +384 480 250.170332 +385 480 36182.618853 +386 480 14710.358460 +399 480 14.712667 +400 480 1139.753397 +401 480 6116.843077 +402 480 40028.851705 +403 480 56166.844894 +404 480 98865.107712 +405 480 28746.228695 +406 480 173810.616057 +407 480 7470.565124 +408 480 2046.518581 +409 480 36929.821158 +410 480 16623.457065 +426 480 579.957882 +427 480 17028.725378 +428 480 50536.630822 +429 480 151321.869059 +430 480 213954.120235 +431 480 248321.956052 +432 480 8306.687391 +433 480 40299.281786 +434 480 14779.943762 +450 480 1816.907496 +451 480 7417.163137 +452 480 7557.706948 +453 480 18031.686488 +454 480 151104.956470 +455 480 667957.996721 +456 480 302059.127857 +457 480 66158.643913 +458 480 31127.051638 +459 480 22221.731942 +460 480 19069.994643 +475 480 10498.820006 +476 480 14789.612394 +477 480 14792.924695 +478 480 46413.385713 +479 480 209753.858743 +480 480 15646792.530750 +481 480 208845.979525 +482 480 38161.606659 +483 480 33402.388860 +1 481 -25.487253 +3 481 -10.853813 +5 481 -9.004540 +6 481 -9.366111 +8 481 -25.422662 +13 481 -25.316823 +14 481 -25.354980 +15 481 -25.353454 +16 481 -25.919695 +18 481 -18.453074 +19 481 -21.111450 +21 481 -25.255620 +22 481 -25.649140 +25 481 -25.330318 +26 481 -11.480109 +27 481 -6.336597 +28 481 -25.390810 +32 481 -10.828309 +34 481 -10.773038 +35 481 -67.791057 +36 481 -31.189397 +37 481 -24.326953 +39 481 -50.680972 +40 481 -46.666176 +41 481 -11.135896 +42 481 -25.454783 +43 481 -10.864019 +44 481 -50.213511 +45 481 -100.756870 +46 481 -8.368114 +47 481 -1.663387 +48 481 -55.921830 +49 481 -16.346546 +53 481 -25.358003 +54 481 -101.458367 +55 481 -14.444965 +56 481 -78.678543 +57 481 -25.351925 +58 481 -8.241846 +59 481 -6.710637 +60 481 -1.045727 +63 481 -24.014362 +64 481 -24.686684 +65 481 -10.856697 +66 481 -11.149664 +67 481 -25.098796 +68 481 -2.227964 +69 481 -37.600215 +70 481 -16.563038 +72 481 -11.228983 +75 481 -25.320900 +77 481 -11.519892 +78 481 -11.148995 +80 481 -10.806209 +81 481 -12.416688 +82 481 -105.015906 +83 481 -11.778975 +84 481 -1.586463 +85 481 -54.330830 +86 481 -11.290233 +87 481 -0.521786 +89 481 -24.733045 +91 481 -25.232269 +92 481 -46.263531 +93 481 -49.029173 +94 481 -20.623106 +95 481 -27.870242 +96 481 -68.210616 +98 481 -6.578216 +99 481 -13.159236 +101 481 -8.938682 +103 481 -70.178803 +104 481 -47.262110 +105 481 -10.613920 +106 481 -24.546460 +107 481 -121.755376 +108 481 -24.539337 +109 481 -24.544784 +110 481 -105.314430 +111 481 -25.499371 +112 481 -135.078315 +115 481 -12.822203 +117 481 -14.730431 +118 481 -18.693237 +119 481 -24.410745 +120 481 -24.415002 +122 481 -25.842227 +123 481 -195.668268 +124 481 -14.925726 +125 481 -12.642856 +126 481 -23.474551 +128 481 -55.718449 +129 481 -24.862844 +130 481 -10.908815 +131 481 -11.011402 +132 481 -7.063340 +133 481 -139.457705 +134 481 -168.481867 +137 481 -22.056239 +138 481 -15.112248 +140 481 -37.852783 +141 481 -24.558776 +145 481 -137.673691 +146 481 -82.211560 +148 481 -12.307318 +149 481 -25.261235 +150 481 -14.821634 +151 481 -11.229469 +152 481 -19.018710 +153 481 -11.243788 +154 481 -30.247406 +155 481 -62.686237 +156 481 -82.098061 +157 481 -27.547830 +158 481 -242.818413 +159 481 -14.857204 +160 481 -24.802035 +161 481 -417.141728 +162 481 -92.494848 +163 481 -19.816666 +164 481 -5.275353 +166 481 -28.729499 +167 481 -37.585664 +168 481 -37.658804 +169 481 -27.711479 +170 481 -75.342715 +171 481 -127.990523 +173 481 -149.293556 +174 481 -63.449926 +175 481 -37.591243 +176 481 -43.976367 +177 481 -28.103824 +178 481 -11.817540 +179 481 -1.443525 +180 481 -36.473427 +182 481 -37.665449 +183 481 -19.763214 +185 481 -28.206263 +187 481 -25.194077 +188 481 -9.840208 +189 481 -18.814687 +190 481 -35.675040 +191 481 -11.526292 +194 481 -20.070568 +195 481 -25.303647 +196 481 -30.988883 +197 481 -11.146222 +201 481 -33.163215 +202 481 -10.289852 +203 481 -44.887469 +211 481 -49.156653 +212 481 -62.770258 +214 481 -8.315352 +215 481 -14.916820 +216 481 -34.239677 +217 481 -26.904673 +219 481 -25.492980 +220 481 -25.550375 +221 481 -25.570835 +222 481 -27.179606 +223 481 -102.096496 +224 481 -25.576326 +227 481 -25.335604 +228 481 -23.593884 +229 481 -29.257509 +230 481 -30.657612 +231 481 -26.988463 +233 481 -25.450414 +234 481 -11.066680 +235 481 -27.201196 +237 481 -24.878485 +239 481 -8.627802 +250 481 -27.051319 +253 481 -36.026362 +256 481 -34.959214 +257 481 -27.279047 +258 481 -35.245466 +259 481 -10.771234 +261 481 -10.942991 +262 481 -7.742676 +263 481 -27.952242 +265 481 -14.886915 +266 481 -25.315390 +267 481 -6.457090 +271 481 -34.194756 +272 481 -25.016801 +273 481 -12.110663 +278 481 -29.377611 +279 481 -16.691392 +281 481 -29.794000 +282 481 -13.588046 +284 481 -10.106803 +285 481 -49.303301 +287 481 -11.223392 +289 481 -25.687016 +290 481 -25.662392 +293 481 -24.741283 +294 481 -24.751552 +295 481 -42.567563 +296 481 -24.556824 +297 481 -88.534260 +299 481 -21.883263 +300 481 -25.057727 +302 481 -28.340811 +304 481 -4.823615 +305 481 -5.056712 +306 481 -24.899942 +307 481 -11.188988 +308 481 -33.105002 +309 481 -33.104133 +311 481 -4.448511 +312 481 -10.752705 +314 481 -49.103542 +315 481 -30.937450 +316 481 -31.070207 +317 481 -31.220269 +318 481 -24.892660 +319 481 -2650.430019 +320 481 -220.026597 +321 481 -749.370226 +322 481 -85.727728 +323 481 -45.735096 +324 481 -714.940414 +326 481 -92.915377 +327 481 -29.458433 +328 481 -177.213541 +329 481 -15.715001 +330 481 -2.278227 +331 481 -218.816052 +332 481 -397.583271 +333 481 -110.759048 +334 481 -29.050937 +335 481 -39.757753 +336 481 -35.321062 +337 481 -277.985590 +338 481 -505.541249 +339 481 -503.814240 +340 481 -351.666614 +341 481 -125.975271 +342 481 -115.626794 +353 481 1199.288556 +354 481 72043.828309 +355 481 882.142167 +358 481 5027.877765 +359 481 1610.679491 +361 481 138881.478621 +362 481 6130.170183 +376 481 783.672388 +377 481 12431.913829 +378 481 1882.958075 +379 481 103703.636802 +380 481 19884.396277 +381 481 4996.712838 +383 481 7577.784324 +385 481 111698.185878 +386 481 69327.717216 +401 481 847.944845 +402 481 10492.452221 +403 481 23605.406865 +404 481 48066.419344 +405 481 103465.331936 +406 481 348168.709496 +407 481 1496.053673 +408 481 6337.506051 +409 481 103639.421335 +410 481 91827.786469 +427 481 245.077665 +428 481 10103.411924 +429 481 29861.070427 +430 481 288199.974656 +431 481 489554.899901 +432 481 8382.291098 +433 481 115117.931436 +434 481 96118.661402 +450 481 1817.774163 +451 481 7420.701134 +452 481 7422.835047 +453 481 2221.657438 +454 481 26002.711946 +455 481 344802.410007 +456 481 691741.718635 +457 481 182601.431326 +458 481 112749.670778 +459 481 38463.416846 +460 481 34273.428867 +475 481 10502.717494 +476 481 14795.103002 +477 481 14798.416533 +478 481 41363.862325 +479 481 53527.181439 +480 481 208845.979525 +481 481 17046166.293294 +482 481 137643.838380 +483 481 53242.648800 +484 481 1455.617129 +5 482 -34.397955 +6 482 -51.471789 +7 482 -52.354808 +20 482 -13.934504 +36 482 -36.281011 +39 482 -84.947374 +45 482 -27.072676 +48 482 -53.332503 +55 482 -3.391800 +56 482 -43.564410 +62 482 -24.060070 +68 482 -16.759690 +69 482 -1.424479 +81 482 -8.375015 +82 482 -80.868478 +83 482 -15.118480 +85 482 -15.262597 +92 482 -68.610553 +96 482 -6.716299 +101 482 -15.082077 +103 482 -11.782938 +104 482 -27.595647 +107 482 -12.182699 +110 482 -27.090474 +112 482 -28.248128 +115 482 -8.044566 +118 482 -34.448445 +126 482 -22.488435 +133 482 -132.156169 +134 482 -29.366413 +135 482 -24.062723 +137 482 -33.883454 +138 482 -29.353292 +140 482 -8.606555 +154 482 -33.937412 +155 482 -68.872267 +156 482 -12.941768 +158 482 -37.279813 +162 482 -29.019123 +167 482 -1.914852 +168 482 -3.134275 +170 482 -14.937910 +171 482 -27.030699 +174 482 -9.997076 +175 482 -1.160199 +176 482 -9.707151 +178 482 -24.518468 +179 482 -39.769974 +182 482 -3.326438 +188 482 -7.221465 +194 482 -25.277128 +197 482 -10.698144 +198 482 -23.965650 +201 482 -33.181307 +202 482 -33.334147 +203 482 -34.307071 +211 482 -10.965956 +212 482 -5.696139 +213 482 -35.830900 +214 482 -11.730813 +216 482 -6.340307 +228 482 -22.390812 +234 482 -24.058295 +237 482 -33.252302 +241 482 -10.202861 +248 482 -4.120394 +256 482 -91.449174 +262 482 -11.546698 +274 482 -19.520487 +277 482 -10.905614 +279 482 -28.053263 +281 482 -17.331545 +295 482 -25.986529 +297 482 -32.325863 +298 482 -32.922545 +308 482 -0.950581 +309 482 -0.641207 +319 482 -118.303314 +321 482 -489.779890 +323 482 -25.434182 +324 482 -192.095603 +328 482 -90.380178 +331 482 -311.120655 +332 482 -39.049628 +333 482 -3.391800 +334 482 -0.552347 +337 482 -251.474006 +338 482 -84.259622 +339 482 -4.476395 +340 482 -25.108470 +342 482 -368.665038 +347 482 3293.585090 +348 482 4614.728911 +349 482 3186.711810 +354 482 9200.253287 +355 482 5128.882271 +358 482 1967.842261 +359 482 1725.742180 +361 482 85055.137795 +362 482 4165.882281 +374 482 1438.924600 +375 482 4638.045704 +376 482 4451.967683 +377 482 422.999711 +378 482 1164.000512 +379 482 12164.964666 +380 482 22256.163825 +381 482 14198.940470 +383 482 4164.153252 +385 482 54652.051355 +386 482 56032.945992 +401 482 200.204567 +402 482 7482.894038 +403 482 5591.633370 +404 482 8573.983585 +405 482 29205.672602 +406 482 54419.269753 +407 482 554.705246 +408 482 4220.152875 +409 482 37033.807912 +410 482 81683.667443 +427 482 4051.725839 +428 482 7701.224852 +429 482 13963.884191 +430 482 51681.269457 +431 482 97680.710119 +432 482 17970.425304 +433 482 36953.214913 +434 482 93914.588143 +435 482 935.543614 +450 482 1818.765857 +451 482 7424.749527 +452 482 7426.884604 +453 482 2850.731659 +454 482 17648.786654 +455 482 41265.171387 +456 482 151449.387439 +457 482 118661.828001 +458 482 97909.671118 +459 482 18626.114920 +460 482 17949.795574 +475 482 251.468111 +476 482 355.701744 +477 482 355.781440 +478 482 25919.128142 +479 482 37283.148377 +480 482 38161.606659 +481 482 137643.838380 +482 482 15732443.093724 +483 482 98469.420461 +484 482 5530.856286 +6 483 -5.099449 +7 483 -25.768197 +17 483 -21.647505 +18 483 -24.520030 +20 483 -4.040770 +27 483 -107.389832 +36 483 -101.912482 +38 483 -9.830409 +45 483 -21.760883 +47 483 -51.365148 +48 483 -15.707034 +51 483 -18.160139 +52 483 -16.789944 +55 483 -11.961533 +79 483 -17.325258 +82 483 -2.491844 +83 483 -13.699633 +84 483 -0.301054 +85 483 -14.912926 +86 483 -1.114169 +87 483 -0.301397 +92 483 -24.294658 +99 483 -0.130433 +101 483 -15.117140 +118 483 -31.244931 +119 483 -0.263809 +120 483 -0.263896 +121 483 -1.084877 +124 483 -0.291761 +125 483 -0.125767 +129 483 -1.081069 +133 483 -119.504415 +136 483 -18.351716 +137 483 -33.958265 +138 483 -24.858508 +139 483 -8.992867 +140 483 -81.910622 +141 483 -0.118151 +144 483 -0.125800 +145 483 -133.623081 +148 483 -0.130415 +153 483 -0.275554 +154 483 -30.747171 +155 483 -34.400065 +156 483 -48.586212 +157 483 -48.861887 +158 483 -1.231453 +159 483 -0.291777 +160 483 -0.262891 +162 483 -140.783753 +164 483 -0.123267 +166 483 -0.282385 +167 483 -38.467805 +168 483 -38.104034 +169 483 -0.126400 +170 483 -13.099039 +173 483 -0.837887 +177 483 -0.275948 +178 483 -0.115999 +179 483 -3.128442 +180 483 -0.841401 +182 483 -3.241410 +183 483 -0.128572 +184 483 -0.291717 +185 483 -1.134445 +186 483 -12.318989 +187 483 -0.274252 +188 483 -12.171883 +190 483 -0.263878 +192 483 -8.400291 +193 483 -0.291289 +194 483 -11.302285 +195 483 -1.107584 +196 483 -11.913310 +198 483 -34.479334 +199 483 -11.443251 +201 483 -30.013713 +202 483 -7.227588 +203 483 -41.177786 +204 483 -0.306060 +205 483 -26.668236 +206 483 -15.889956 +208 483 -27.090311 +213 483 -13.644293 +214 483 -7.378220 +215 483 -0.291802 +216 483 -0.332543 +217 483 -0.282635 +218 483 -0.125303 +219 483 -0.279994 +220 483 -1.122766 +221 483 -0.280960 +222 483 -1.124467 +223 483 -0.280318 +224 483 -0.280988 +226 483 -0.281270 +227 483 -1.109574 +228 483 -15.564130 +229 483 -1.123343 +230 483 -1.110167 +231 483 -0.282846 +232 483 -0.282869 +237 483 -33.531038 +239 483 -26.347167 +241 483 -26.905704 +244 483 -19.947499 +245 483 -20.583792 +247 483 -15.479420 +248 483 -32.594103 +250 483 -0.282092 +252 483 -9.929534 +253 483 -0.120240 +254 483 -0.128650 +256 483 -12.949253 +257 483 -1.121172 +262 483 -1.360179 +263 483 -0.275844 +264 483 -0.209114 +265 483 -0.291790 +266 483 -1.108464 +267 483 -0.297161 +271 483 -1.089789 +272 483 -1.089373 +273 483 -0.285704 +274 483 -33.084600 +275 483 -0.351667 +278 483 -1.122589 +279 483 -10.116187 +281 483 -36.026780 +282 483 -0.129995 +283 483 -35.396999 +284 483 -0.294978 +285 483 -0.264421 +287 483 -0.122632 +289 483 -0.282400 +290 483 -0.282036 +291 483 -0.116627 +292 483 -19.123574 +293 483 -0.268643 +294 483 -0.268764 +295 483 -58.778914 +298 483 -31.883842 +299 483 -1.056244 +300 483 -0.328750 +302 483 -0.122381 +304 483 -17.879526 +305 483 -7.236640 +310 483 -34.943798 +311 483 -15.398623 +312 483 -0.131071 +313 483 -11.452063 +314 483 -1.050309 +315 483 -0.277069 +316 483 -0.123067 +318 483 -0.270264 +319 483 -235.744882 +321 483 -487.616538 +328 483 -368.910566 +331 483 -718.740851 +335 483 -10.342808 +337 483 -138.728255 +339 483 -24.086375 +341 483 -24.349731 +342 483 -200.322340 +347 483 5582.183675 +348 483 7821.344733 +349 483 5401.047843 +354 483 94896.253792 +355 483 2377.329526 +358 483 1744.043391 +359 483 6381.051104 +361 483 68580.129034 +362 483 5019.511656 +374 483 2438.783634 +375 483 7860.863561 +376 483 7545.486346 +378 483 1333.800061 +379 483 8012.571444 +380 483 97392.389199 +381 483 24811.879780 +383 483 8325.033622 +384 483 779.729656 +385 483 3065.352475 +386 483 86508.162862 +401 483 339.319810 +402 483 10461.464868 +403 483 7943.304439 +404 483 7288.739541 +405 483 22343.600872 +406 483 130962.651332 +407 483 23279.808445 +408 483 9198.014330 +409 483 144.188126 +410 483 81929.571942 +411 483 12011.752062 +427 483 3923.894328 +428 483 7458.252041 +429 483 16011.206620 +430 483 14863.856187 +431 483 53920.279582 +432 483 146667.824554 +433 483 9395.795813 +434 483 26716.302825 +435 483 72291.690189 +450 483 1645.140655 +451 483 6715.959207 +452 483 6717.890463 +453 483 2583.190149 +454 483 16034.861299 +455 483 26271.558819 +456 483 30504.479334 +457 483 136609.381055 +458 483 85832.618283 +459 483 116926.166746 +460 483 77119.288815 +478 483 23118.006431 +479 483 33394.019920 +480 483 33402.388860 +481 483 53242.648800 +482 483 98469.420461 +483 483 14720686.341944 +484 483 107010.872093 +485 483 423.486514 +2 484 -12.982873 +6 484 -14.165294 +7 484 -31.404320 +17 484 -27.348116 +18 484 -8.490021 +20 484 -16.385829 +38 484 -34.176393 +47 484 -74.765363 +50 484 -6.980270 +51 484 -14.028071 +52 484 -30.800801 +71 484 -14.447269 +79 484 -14.758132 +92 484 -9.939892 +97 484 -13.276053 +101 484 -3.721880 +136 484 -13.860647 +137 484 -6.809445 +138 484 -31.984341 +139 484 -14.975642 +140 484 -135.524557 +142 484 -30.761709 +145 484 -6.944770 +156 484 -15.735326 +157 484 -15.475564 +162 484 -17.215236 +167 484 -26.960342 +168 484 -27.466873 +172 484 -2.298902 +186 484 -19.477852 +192 484 -22.607117 +194 484 -36.954998 +198 484 -18.207771 +199 484 -1.325345 +202 484 -37.285444 +204 484 -3.378760 +205 484 -2.140555 +206 484 -11.462287 +208 484 -1.879696 +213 484 -15.597376 +214 484 -37.295592 +228 484 -36.092262 +237 484 -4.876676 +239 484 -2.330983 +242 484 -2.912622 +244 484 -12.467510 +245 484 -11.912744 +252 484 -24.158492 +262 484 -12.489367 +275 484 -39.618031 +279 484 -37.062875 +281 484 -28.332251 +283 484 -10.488068 +286 484 -13.274229 +292 484 -31.626217 +295 484 -30.567963 +304 484 -34.127840 +305 484 -6.964901 +310 484 -28.710477 +311 484 -24.459212 +313 484 -13.498014 +319 484 -20.165946 +320 484 -9.934887 +321 484 -365.682981 +326 484 -9.847370 +328 484 -755.093492 +332 484 -1.039554 +338 484 -9.746152 +342 484 -115.757078 +354 484 13735.494826 +355 484 3081.776801 +359 484 4219.243102 +361 484 48999.412225 +362 484 4013.825833 +380 484 15903.961089 +381 484 9543.008570 +384 484 4654.229161 +386 484 64245.954383 +406 484 21439.487499 +407 484 10415.367176 +409 484 4624.919105 +410 484 48285.859952 +411 484 18884.344872 +431 484 1070.781068 +432 484 25368.676270 +433 484 6203.368152 +434 484 7489.061050 +435 484 66972.030500 +436 484 495.954235 +457 484 4390.647523 +458 484 24758.947881 +459 484 84461.333761 +460 484 151595.671728 +481 484 1455.617129 +482 484 5530.856286 +483 484 107010.872093 +484 484 13710031.657530 +485 484 26670.559974 +8 485 -23.039351 +15 485 -10.250668 +16 485 -23.663163 +17 485 -16.452989 +19 485 -10.621010 +20 485 -2.610146 +21 485 -19.906323 +22 485 -46.762196 +23 485 -35.448594 +25 485 -10.184732 +27 485 -5.601739 +28 485 -11.901131 +31 485 -24.905360 +32 485 -21.604097 +34 485 -21.819119 +37 485 -21.493667 +38 485 -18.588203 +42 485 -46.295135 +43 485 -86.816621 +44 485 -48.812055 +50 485 -7.485079 +52 485 -16.919676 +53 485 -22.906210 +54 485 -33.167098 +55 485 -10.097953 +60 485 -36.302550 +61 485 -86.781814 +62 485 -9.644576 +63 485 -10.610042 +66 485 -7.379346 +67 485 -17.777734 +71 485 -3.519299 +77 485 -10.505790 +84 485 -25.157934 +87 485 -11.195498 +91 485 -10.101446 +100 485 -22.108970 +102 485 -21.528825 +106 485 -21.820431 +108 485 -21.809222 +109 485 -21.819169 +113 485 -9.871530 +117 485 -35.075960 +119 485 -86.468238 +120 485 -9.612901 +121 485 -3.199042 +122 485 -23.544010 +124 485 -24.281280 +125 485 -10.428302 +129 485 -3.536868 +131 485 -23.916601 +132 485 -96.923428 +135 485 -87.769855 +142 485 -8.761813 +143 485 -9.421332 +148 485 -24.445405 +150 485 -24.304167 +152 485 -34.844256 +153 485 -10.127899 +159 485 -35.077490 +160 485 -21.522746 +163 485 -24.046141 +164 485 -33.058670 +166 485 -20.856285 +169 485 -34.116712 +172 485 -9.150843 +183 485 -10.685878 +185 485 -23.523349 +187 485 -6.907424 +191 485 -9.260638 +193 485 -35.012657 +194 485 -1.117197 +195 485 -33.114241 +197 485 -9.413688 +202 485 -2.467110 +204 485 -47.760450 +206 485 -5.003207 +214 485 -2.506573 +215 485 -35.084808 +217 485 -33.901067 +218 485 -10.383035 +220 485 -23.353430 +221 485 -23.377566 +222 485 -23.391986 +223 485 -33.626621 +224 485 -33.716005 +227 485 -20.395399 +229 485 -93.450551 +230 485 -20.402296 +231 485 -47.026598 +232 485 -33.941329 +235 485 -33.666638 +238 485 -11.319741 +240 485 -22.137847 +242 485 -22.684491 +250 485 -46.859966 +252 485 -14.814235 +253 485 -13.408485 +254 485 -6.265401 +255 485 -49.677418 +257 485 -20.663539 +258 485 -21.387812 +259 485 -21.379641 +261 485 -21.901992 +263 485 -19.445449 +265 485 -35.081151 +266 485 -33.053539 +267 485 -49.536550 +271 485 -27.469368 +272 485 -27.288152 +275 485 -20.602288 +277 485 -31.656003 +278 485 -23.349307 +279 485 -1.572407 +282 485 -48.698200 +283 485 -5.513894 +284 485 -35.507238 +285 485 -86.794114 +286 485 -18.314620 +287 485 -22.873972 +288 485 -33.188649 +289 485 -46.903748 +290 485 -46.829755 +292 485 -15.333645 +293 485 -22.149196 +294 485 -22.160196 +295 485 -30.821732 +296 485 -21.836296 +299 485 -9.633407 +302 485 -9.317276 +304 485 -15.206282 +306 485 -28.537247 +307 485 -17.072663 +310 485 -9.774016 +311 485 -6.880977 +312 485 -21.862147 +313 485 -5.853516 +314 485 -21.486221 +315 485 -22.815847 +316 485 -33.013740 +317 485 -10.121079 +318 485 -9.110637 +321 485 -1344.869053 +328 485 -2135.740783 +332 485 -8.713328 +337 485 -22.108403 +359 485 4512.117059 +361 485 137556.624236 +362 485 27295.842362 +384 485 4917.571536 +386 485 195744.451109 +409 485 4825.059230 +411 485 200165.196559 +434 485 3231.515682 +435 485 22180.689468 +436 485 184347.992517 +459 485 1306.813147 +460 485 373724.909752 +461 485 72468.371834 +483 485 423.486514 +484 485 26670.559974 +485 485 13514804.130899 +486 485 6649.133641 +3 486 -9.413512 +9 486 -9.502861 +21 486 -0.345037 +24 486 -20.804282 +27 486 -15.550997 +32 486 -21.101946 +33 486 -9.355433 +34 486 -9.546845 +37 486 -20.938095 +40 486 -22.859938 +43 486 -21.229800 +66 486 -2.603719 +67 486 -2.312124 +80 486 -21.283539 +89 486 -21.690513 +102 486 -20.998322 +106 486 -21.374862 +108 486 -21.360116 +109 486 -85.493798 +119 486 -84.421375 +120 486 -9.387882 +121 486 -6.630337 +129 486 -18.459075 +135 486 -87.156457 +141 486 -21.398551 +143 486 -20.699412 +160 486 -20.982414 +178 486 -20.408557 +187 486 -3.056995 +188 486 -21.711146 +190 486 -21.157512 +191 486 -8.872796 +205 486 -10.106896 +208 486 -10.103955 +234 486 -21.015426 +239 486 -10.111648 +253 486 -18.503492 +254 486 -14.861728 +258 486 -20.799345 +259 486 -20.787924 +261 486 -85.901412 +262 486 -10.172622 +263 486 -0.771763 +271 486 -4.943849 +272 486 -5.107704 +277 486 -0.999234 +280 486 -20.962536 +293 486 -21.800365 +294 486 -21.813485 +295 486 -0.277585 +296 486 -21.395611 +302 486 -0.746180 +306 486 -15.921451 +307 486 -2.972012 +314 486 -20.931896 +318 486 -78.714539 +321 486 -1047.785536 +328 486 -93.767783 +342 486 -0.277585 +359 486 53.590324 +361 486 72689.823776 +362 486 49427.106693 +384 486 26.012881 +385 486 30.637473 +386 486 141715.704152 +387 486 1791.712242 +410 486 53.843728 +411 486 143929.626163 +412 486 1185.174867 +435 486 5.617984 +436 486 145829.517715 +437 486 1187.394495 +460 486 7363.856918 +461 486 151349.766831 +462 486 346.247716 +485 486 6649.133641 +486 486 12661118.190778 +487 486 46.233601 +196 487 -8.659360 +254 487 -19.471548 +262 487 -77.279634 +295 487 -24.638552 +321 487 -105.410542 +342 487 -24.638552 +359 487 4756.699400 +362 487 12448.450365 +384 487 2308.914107 +385 487 2719.394833 +387 487 14320.547924 +410 487 4779.191640 +412 487 14153.223753 +435 487 498.654554 +436 487 4052.062957 +437 487 14010.536760 +461 487 4341.440670 +462 487 13891.796931 +486 487 46.233601 +487 487 11999385.460055 +40 488 -19.439670 +199 488 -8.619327 +205 488 -19.382595 +207 488 -19.381840 +208 488 -19.382788 +216 488 -8.737248 +239 488 -19.383915 +321 488 -114.327382 +362 488 14192.064001 +387 488 16179.323400 +412 488 15836.571704 +437 488 14880.147864 +438 488 647.440705 +462 488 11402.787000 +463 488 3847.924568 +488 488 11487122.561199 +489 489 11111111.111111 +490 490 11111111.111111 +491 491 11111111.111111 +492 492 11111111.111111 +493 493 11489799.486771 +65 494 -15.284216 +75 494 -129.372245 +93 494 -35.074263 +100 494 -13.984932 +132 494 -14.041663 +141 494 -10.377315 +144 494 -128.312744 +163 494 -14.071707 +164 494 -32.234492 +166 494 -14.318037 +172 494 -13.944742 +177 494 -32.398058 +183 494 -31.656001 +184 494 -31.570685 +185 494 -32.072408 +189 494 -31.681555 +190 494 -5.392037 +193 494 -31.587090 +194 494 -3.639276 +242 494 -31.384867 +244 494 -3.265720 +246 494 -31.625796 +250 494 -32.203153 +251 494 -31.390962 +253 494 -32.345192 +257 494 -32.257283 +258 494 -2.657070 +263 494 -14.305133 +265 494 -31.574916 +266 494 -129.467054 +267 494 -13.973775 +271 494 -129.560987 +273 494 -14.094121 +280 494 -9.761564 +282 494 -14.020708 +283 494 -5.141353 +284 494 -14.006839 +285 494 -15.799203 +291 494 -11.791595 +293 494 -11.120902 +294 494 -25.709028 +296 494 -10.321116 +299 494 -10.819309 +302 494 -14.032214 +306 494 -13.241447 +307 494 -32.150835 +315 494 -14.366190 +316 494 -14.377451 +317 494 -14.382113 +318 494 -14.373415 +322 494 -31.390962 +325 494 -1365.143816 +369 494 1111.263250 +394 494 6724.022239 +419 494 6706.282053 +444 494 224138.941059 +469 494 305755.854356 +494 494 11832803.445334 +495 494 21632.327990 +51 495 -35.061679 +65 495 -17.847314 +93 495 -98.964117 +136 495 -35.022046 +141 495 -4.191539 +142 495 -34.791388 +143 495 -8.845403 +179 495 -21.303851 +186 495 -35.090527 +190 495 -9.408876 +194 495 -30.247713 +197 495 -3.949898 +202 495 -35.433068 +234 495 -51.335606 +244 495 -30.652038 +247 495 -10.612178 +251 495 -130.112415 +258 495 -12.322878 +275 495 -36.823929 +279 495 -34.422210 +280 495 -23.683772 +283 495 -28.626662 +285 495 -17.306442 +291 495 -21.530202 +293 495 -3.421095 +294 495 -6.986711 +296 495 -4.249836 +299 495 -22.560386 +301 495 -137.920621 +302 495 -0.419015 +306 495 -1.232377 +325 495 -814.263377 +327 495 -130.112415 +369 495 4900.700264 +394 495 29561.020175 +419 495 29320.662893 +444 495 157073.774073 +445 495 15008.083371 +469 495 156212.049303 +470 495 68236.437420 +494 495 21632.327990 +495 495 11979968.738148 +496 495 17689.753756 +97 496 -27.113529 +116 496 -30.974488 +135 496 -39.273899 +143 496 -33.437974 +175 496 -5.618848 +178 496 -11.532764 +179 496 -18.400188 +180 496 -14.402935 +182 496 -6.236453 +197 496 -14.838326 +206 496 -34.350017 +234 496 -114.184482 +241 496 -32.604207 +247 496 -31.261786 +251 496 -9.167953 +252 496 -173.726831 +268 496 -30.903204 +269 496 -13.737725 +270 496 -13.730860 +274 496 -30.911571 +292 496 -170.279454 +304 496 -60.178440 +305 496 -14.734937 +311 496 -17.422295 +322 496 -120.257848 +325 496 -819.597366 +341 496 -9.167953 +347 496 16056.512879 +369 496 392.438502 +371 496 443.699272 +372 496 17885.308094 +394 496 2358.077491 +396 496 5485.456063 +397 496 12895.461476 +419 496 657.136498 +420 496 1665.263933 +421 496 17619.637951 +422 496 819.844641 +444 496 182043.873929 +445 496 13066.852698 +446 496 18775.743661 +469 496 10299.905694 +470 496 216435.180172 +471 496 59615.154464 +472 496 1556.979242 +495 496 17689.753756 +496 496 12264456.757040 +497 496 50884.704558 +498 496 248.468230 +97 497 -21.955064 +116 497 -202.461642 +135 497 -6.617766 +137 497 -26.174758 +139 497 -23.005282 +175 497 -17.704271 +178 497 -39.689408 +180 497 -38.546470 +182 497 -17.350442 +196 497 -17.591945 +199 497 -5.575077 +206 497 -12.762101 +239 497 -12.397498 +241 497 -14.962299 +251 497 -42.624923 +252 497 -5.998548 +264 497 -29.374675 +268 497 -26.890160 +269 497 -9.524906 +270 497 -13.324858 +274 497 -32.480346 +292 497 -10.221126 +304 497 -150.785070 +305 497 -38.106419 +310 497 -32.918503 +311 497 -34.557034 +320 497 -15.195577 +325 497 -556.293756 +327 497 -51.893861 +329 497 -54.116658 +332 497 -10.339664 +334 497 -30.326409 +335 497 -128.101067 +336 497 -30.642240 +341 497 -6.691360 +347 497 14995.050188 +369 497 1963.748046 +372 497 16871.192123 +394 497 11606.062411 +395 497 170.737783 +397 497 16827.937780 +419 497 479.620350 +420 497 11076.575934 +422 497 16791.226680 +444 497 116363.127396 +445 497 47863.661122 +446 497 7523.318984 +447 497 16761.154453 +469 497 43.036328 +470 497 103697.063261 +471 497 105609.618321 +472 497 77722.345495 +496 497 50884.704558 +497 497 12291537.299648 +498 497 42520.663926 +499 497 3928.384018 +101 498 -4.050738 +116 498 -229.662502 +137 498 -35.942145 +138 498 -34.672444 +139 498 -37.305557 +175 498 -0.467063 +178 498 -2.675062 +196 498 -36.933613 +199 498 -16.275661 +239 498 -36.611598 +248 498 -11.851336 +251 498 -16.725730 +264 498 -31.613784 +268 498 -40.210303 +269 498 -41.041342 +274 498 -24.421197 +277 498 -25.632933 +310 498 -26.843607 +320 498 -21.856718 +323 498 -14.542406 +324 498 -171.754795 +325 498 -300.875539 +327 498 -17.951957 +329 498 -20.260299 +332 498 -28.154017 +336 498 -73.178479 +342 498 -4.362402 +347 498 18728.585602 +369 498 920.243020 +372 498 21985.933050 +394 498 3717.978654 +395 498 1774.978719 +397 498 20834.992905 +398 498 1019.056287 +420 498 3012.674895 +421 498 2328.806864 +422 498 18677.324742 +423 498 3053.225532 +444 498 58616.677012 +445 498 49569.989459 +446 498 2575.597134 +447 498 12281.118312 +448 498 12042.054951 +470 498 24811.222983 +471 498 74305.029126 +472 498 108344.962367 +473 498 29661.143270 +496 498 248.468230 +497 498 42520.663926 +498 498 12240850.653340 +499 498 39665.683695 +500 498 5295.602821 +58 499 -14.617538 +90 499 -29.741488 +101 499 -34.956970 +116 499 -39.255919 +126 499 -0.648692 +138 499 -36.030936 +139 499 -2.941873 +192 499 -29.492252 +194 499 -4.369629 +196 499 -10.704232 +199 499 -7.975875 +214 499 -35.821302 +239 499 -18.155779 +248 499 -15.863321 +251 499 -39.893546 +262 499 -3.576222 +268 499 -174.846976 +269 499 -67.862442 +270 499 -61.727969 +274 499 -74.654632 +277 499 -35.652207 +298 499 -4.197998 +308 499 -18.406507 +309 499 -20.191387 +322 499 -87.154919 +323 499 -12.356503 +324 499 -51.668591 +325 499 -195.349667 +326 499 -5.904328 +329 499 -196.962547 +333 499 -40.839623 +335 499 -57.314684 +338 499 -10.841358 +341 499 -106.553955 +342 499 -16.639516 +347 499 72487.522243 +369 499 2309.365415 +372 499 79954.618517 +373 499 3229.529917 +376 499 813.737654 +377 499 3213.135305 +394 499 8333.203958 +395 499 5432.639943 +397 499 17866.132378 +398 499 64323.220081 +400 499 1794.225669 +401 499 7534.857598 +402 499 2755.030736 +420 499 5850.511000 +421 499 7499.830676 +423 499 80931.469405 +424 499 290.674519 +425 499 3092.666570 +426 499 9904.924926 +427 499 132.203084 +444 499 36862.215962 +445 499 41973.891767 +446 499 9099.616415 +447 499 8368.794704 +448 499 67378.160080 +449 499 13858.278597 +450 499 10356.763302 +451 499 2773.364763 +470 499 4675.832378 +471 499 41527.965924 +472 499 56377.430040 +473 499 54527.259457 +474 499 63243.699539 +475 499 14662.254366 +476 499 142.691600 +497 499 3928.384018 +498 499 39665.683695 +499 499 12308364.476846 +500 499 32053.297605 +2 500 -4.747824 +5 500 -6.580751 +17 500 -6.489718 +58 500 -28.466389 +71 500 -12.295657 +82 500 -14.464465 +90 500 -173.244201 +101 500 -35.046396 +116 500 -33.097775 +126 500 -32.170967 +128 500 -13.800869 +138 500 -1.668796 +156 500 -32.385821 +157 500 -27.402382 +162 500 -29.140105 +188 500 -3.313445 +192 500 -34.806691 +194 500 -28.660383 +201 500 -169.306615 +203 500 -5.311735 +209 500 -15.342116 +212 500 -6.270051 +248 500 -5.778708 +251 500 -12.473217 +262 500 -34.308385 +268 500 -61.839990 +269 500 -59.994051 +270 500 -14.436067 +274 500 -60.579567 +277 500 -14.463080 +298 500 -132.124922 +308 500 -242.050488 +309 500 -377.327094 +320 500 -171.564225 +322 500 -294.311257 +323 500 -41.282014 +324 500 -56.120640 +325 500 -129.385503 +326 500 -114.191025 +327 500 -83.825070 +329 500 -170.725665 +333 500 -105.409765 +335 500 -89.103866 +336 500 -114.073893 +337 500 -42.410931 +338 500 -10.014547 +339 500 -51.331401 +341 500 -149.417225 +342 500 -106.221698 +347 500 40650.760407 +353 500 15555.543489 +354 500 4446.405571 +369 500 809.387924 +372 500 22398.783938 +373 500 24125.712382 +376 500 1458.713849 +377 500 7844.819828 +378 500 25306.513516 +379 500 503.144875 +394 500 2340.853153 +395 500 2393.139185 +396 500 74.392305 +398 500 45289.756958 +399 500 397.828708 +401 500 13812.180901 +402 500 31231.000054 +403 500 12985.946839 +420 500 940.078698 +421 500 3193.689293 +422 500 498.126361 +423 500 17114.606388 +424 500 27748.809868 +426 500 51409.245373 +427 500 31404.865054 +428 500 1100.574645 +444 500 23900.775162 +445 500 30048.197391 +446 500 11618.025888 +447 500 2982.191200 +448 500 1243.152213 +449 500 43165.539265 +450 500 13170.954570 +451 500 71570.859057 +452 500 11775.889629 +470 500 182.432796 +471 500 18741.137529 +472 500 37658.173661 +473 500 35007.293452 +474 500 36337.468045 +475 500 149189.337566 +476 500 42946.958876 +477 500 444.602886 +498 500 5295.602821 +499 500 32053.297605 +500 500 12741928.914287 \ No newline at end of file diff --git a/SPEX/ExampleMats/tomography.rhs b/SPEX/ExampleMats/tomography.rhs new file mode 100644 index 0000000000..d776bc42cb --- /dev/null +++ b/SPEX/ExampleMats/tomography.rhs @@ -0,0 +1,501 @@ +500 1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/SPEX/Include/SPEX.h b/SPEX/Include/SPEX.h index edfc198353..1670bc21ef 100644 --- a/SPEX/Include/SPEX.h +++ b/SPEX/Include/SPEX.h @@ -1,176 +1,20 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/Include/SPEX.h: user #include file for SPEX_Left_LU. +// SPEX/Include/SPEX.h: Include file for SPEX Library //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2023, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -#ifndef SPEX_LEFT_LU_H -#define SPEX_LEFT_LU_H +#ifndef SPEX_H +#define SPEX_H -// This software package exactly solves a sparse system of linear equations -// using the SPEX Left LU factorization. This code accompanies the paper (submitted -// to ACM Transactions on Mathematical Software): -// "Algorithm 1021: SPEX Left LU: Exactly Solving Sparse Linear Systems via -// A Sparse Left-Looking Integer-Preserving LU Factorization", C. Lourenco, -// J. Chen, E. Moreno-Centeno, T. Davis, ACM Trans. Mathematical Software, -// June 2022. https://doi.org/10.1145/3519024 - -// The theory associated with this software can be found in the paper -// (published in SIAM journal on matrix analysis and applications): - -// "Exact Solution of Sparse Linear Systems via Left-Looking -// Roundoff-Error-Free LU Factorization in Time Proportional to -// Arithmetic Work", C. Lourenco, A. R. Escobedo, E. Moreno-Centeno, -// T. Davis, SIAM J. Matrix Analysis and Applications. pp 609-638, -// vol 40, no 2, 2019. - -// If you use this code, you must first download and install the GMP and -// MPFR libraries. GMP and MPFR can be found at: -// https://gmplib.org/ -// http://www.mpfr.org/ - -// If you use SPEX Left LU for a publication, we request that you please cite -// the above two papers. - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//-------------------------Authors---------------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and Timothy Davis -// - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//-------------------------Contact Information---------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// Please contact Chris Lourenco (chrisjlourenco@gmail.com) -// or Tim Davis (timdavis@aldenmath.com, DrTimothyAldenDavis@gmail.com, -// davis@tamu.edu) - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//-------------------------Copyright-------------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// SPEX Left LU is free software; you can redistribute it and/or modify -// it under the terms of either: -// -// * the GNU Lesser General Public License as published by the -// Free Software Foundation; either version 3 of the License, -// or (at your option) any later version. -// -// or -// -// * the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any -// later version. -// -// or both in parallel, as here. -// -// See license.txt for license info. -// -// This software is copyright by Christopher Lourenco, Jinhao Chen, Erick -// Moreno-Centeno and Timothy A. Davis. All Rights Reserved. -// - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//---------------------------DISCLAIMER----------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// SPEX Left LU is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//--------------------------Summary--------------------------------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -// This software package solves the linear system Ax = b exactly. The input -// matrix and right hand side vectors are stored as either integers, double -// precision numbers, multiple precision floating points (through the mpfr -// library) or as rational numbers (as a collection of numerators and -// denominators using the GMP mpq_t data structure). Appropriate routines -// within the code transform the input into an integral matrix in compressed -// column form. - -// This package computes the factorization PAQ = LDU. Note that we store the -// "functional" form of the factorization by only storing L and U. The user -// is given some freedom to select the permutation matrices P and Q. The -// recommended default settings select Q using the COLAMD column ordering -// and select P via a partial pivoting scheme in which the diagonal entry -// in column k is selected if it is the same magnitude as the smallest -// entry, otherwise the smallest entry is selected as the kth pivot. -// Alternative strategies allowed to select Q include the AMD column -// ordering or no column permutation (Q=I). For pivots, there are a variety -// of potential schemes including traditional partial pivoting, diagonal -// pivoting, tolerance pivoting etc. This package does not allow pivoting -// based on sparsity criterion. - -// The factors L and U are computed via integer preserving operations via -// integer-preserving Gaussian elimination. The key part of this algorithm -// is a Roundoff Error Free (REF) sparse triangular solve function which -// exploits sparsity to reduce the number of operations that must be -// performed. - -// Once L and U are computed, a simplified version of the triangular solve -// is performed which assumes the vector b is dense. The final solution -// vector x is gauranteed to be exact. This vector can be output in one of -// three ways: 1) full precision rational arithmetic (as a sequence of -// numerators and denominators) using the GMP mpq_t data type, 2) double -// precision while not exact will produce a solution accurate to machine -// roundoff unless the size of the associated solution exceeds double -// precision (i.e., the solution is 10^500 or something), 3) variable -// precision floating point using the GMP mpfr_t data type. The associated -// precision is user defined. - - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -//---------------------Include files required by SPEX Left LU------------------- -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -#include -#include -#include -#include -#include -#include -#include -#include "SuiteSparse_config.h" -// #include "SPEX_Util.h" - - -//------------------------------------------------------------------------------ -// SPEX_Util/Include/SPEX_Util.h: Include file for utility functions for SPEX -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -#ifndef SPEX_UTIL_H -#define SPEX_UTIL_H - -// SPEX_Util is a collection of utility functions for the SParse EXact package. -// Included are several routines for memory management, matrix operations, and +// SPEX is a collection of functions for the SParse EXact package. +// Included are several routines for memory management, matrix operations, and // wrappers to the GMP library. // // This is the global include file and should be included in all SPEX_* packages @@ -181,9 +25,10 @@ //-------------------------Authors---------------------------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -// Unless otherwise noted all Utility functions are authored by: +// Unless otherwise noted all functions are authored by: // -// Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and Timothy Davis +// Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Erick Moreno-Centeno, and Timothy A. Davis // //------------------------------------------------------------------------------ @@ -192,8 +37,10 @@ //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -// Please contact Chris Lourenco (chrisjlourenco@gmail.com, lourenco@usna.edu) -// or Tim Davis (timdavis@aldenmath.com, DrTimothyAldenDavis@gmail.com, +// Please contact +// Chris Lourenco (chrisjlourenco@gmail.com, lourenco@usna.edu) +// or +// Tim Davis (timdavis@aldenmath.com, DrTimothyAldenDavis@gmail.com, // davis@tamu.edu) //------------------------------------------------------------------------------ @@ -219,8 +66,9 @@ // // See license.txt for license info. // -// This software is copyright by Christopher Lourenco, Jinhao Chen, Erick -// Moreno-Centeno and Timothy A. Davis. All Rights Reserved. +// This software is copyright by Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Erick Moreno-Centeno and Timothy A. Davis. +// All Rights Reserved. // //------------------------------------------------------------------------------ @@ -234,41 +82,47 @@ // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. - //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //---------------------Include files required by SPEX -------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -// #include -// #include -// #include -// #include -// #include -// #include -// #include -#include -#include -// #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +// #include +// #include +// #include +// #include #include "SuiteSparse_config.h" //------------------------------------------------------------------------------ -// Version +// SPEX Version //------------------------------------------------------------------------------ -#define SPEX_DATE "Jan 20, 2024" -#define SPEX_VERSION "2.3.2" -#define SPEX_VERSION_MAJOR 2 -#define SPEX_VERSION_MINOR 3 -#define SPEX_VERSION_SUB 2 +// Current version of the code +#define SPEX_DATE "Feb XX, 2024" +#define SPEX_VERSION_STRING "3.1.0" +#define SPEX_VERSION_MAJOR 3 +#define SPEX_VERSION_MINOR 1 +#define SPEX_VERSION_SUB 0 + +#define SPEX_VERSION_NUMBER(major,minor,sub) \ + (((major)*1000ULL + (minor))*1000ULL + (sub)) +#define SPEX_VERSION \ + SPEX_VERSION_NUMBER (SPEX_VERSION_MAJOR, \ + SPEX_VERSION_MINOR, \ + SPEX_VERSION_SUB) -#define SPEX__VERSION SUITESPARSE__VERCODE(2,3,2) +#define SPEX__VERSION SUITESPARSE__VERCODE(3,1,0) #if !defined (SUITESPARSE__VERSION) || \ - (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,6,0)) -#error "SPEX 2.3.2 requires SuiteSparse_config 7.6.0 or later" + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,7,0)) +#error "SPEX 3.1.0 requires SuiteSparse_config 7.7.0 or later" #endif #if defined ( __cplusplus ) @@ -276,12 +130,6 @@ extern "C" { #endif -//------------------------------------------------------------------------------ -// version -//------------------------------------------------------------------------------ - -void SPEX_version (int version [3]) ; - //------------------------------------------------------------------------------ // Error codes //------------------------------------------------------------------------------ @@ -292,49 +140,100 @@ void SPEX_version (int version [3]) ; typedef enum { - SPEX_OK = 0, // all is well - SPEX_OUT_OF_MEMORY = -1, // out of memory - SPEX_SINGULAR = -2, // the input matrix A is singular - SPEX_INCORRECT_INPUT = -3, // one or more input arguments are incorrect - SPEX_INCORRECT = -4, // The solution is incorrect - SPEX_UNSYMMETRIC = -5, // The input matrix is unsymmetric (for Cholesky) - SPEX_PANIC = -6 // SPEX used without proper initialization + + SPEX_OK = 0, // all is well + SPEX_OUT_OF_MEMORY = -1, // out of memory + SPEX_SINGULAR = -2, // the input matrix A is singular + SPEX_INCORRECT_INPUT = -3, // one or more input arguments are incorrect + SPEX_NOTSPD = -4, // The input matrix is not symmetric positive + // definite (for a Cholesky factorization) + SPEX_INCORRECT_ALGORITHM = -5,// The algorithm is not compatible with + // the factorization + SPEX_PANIC = -6 // SPEX used without proper initialization, + // or other unrecoverable error } SPEX_info ; +//------------------------------------------------------------------------------ +// SPEX Version, continued +//------------------------------------------------------------------------------ + +SPEX_info SPEX_version +( + int version [3], // SPEX major, minor, and sub version + char date [128] // date of this version +) ; + +// Requirements: SPEX requires GMP 6.1.2 or later, and MPFR 4.0.2 or later. +// NOTE that these version numbers are from the original source distributions. +// It is NOT the "number 10" assigned to libgmp.so.10 in the Ubuntu linux +// distro. + +// GMP v6.1.2 or later is required: +#if __GNU_MP_RELEASE < 60102 +#error "GMP v6.1.2 or later is required." +#endif + +// MPFR v4.0.2 or later is required: +#if MPFR_VERSION < MPFR_VERSION_NUM(4,0,2) +#error "MPFR v4.0.2 or later is required." +#endif + //------------------------------------------------------------------------------ // Pivot scheme codes //------------------------------------------------------------------------------ +// SPEX_DEFAULT is only used to define the defaults for the following enums but +// in all other places we use the appropiate default (ie SPEX_DEFAULT_ORDERING) +// for ease of reading +#define SPEX_DEFAULT 0 + // A code in SPEX_options to tell SPEX what type of pivoting to use for pivoting // in unsymmetric LU factorization. typedef enum { - SPEX_SMALLEST = 0, // Smallest pivot + SPEX_SMALLEST = SPEX_DEFAULT, // Smallest pivot (the default method) SPEX_DIAGONAL = 1, // Diagonal pivoting SPEX_FIRST_NONZERO = 2, // First nonzero per column chosen as pivot SPEX_TOL_SMALLEST = 3, // Diagonal pivoting with tol for smallest pivot. - // (Default) SPEX_TOL_LARGEST = 4, // Diagonal pivoting with tol. for largest pivot SPEX_LARGEST = 5 // Largest pivot } SPEX_pivot ; //------------------------------------------------------------------------------ -// Column ordering scheme codes +// Fill-reducing ordering scheme codes +//------------------------------------------------------------------------------ + +// A code in SPEX_options to tell SPEX which fill-reducing ordering to used +// prior to exact factorization + +typedef enum +{ + SPEX_DEFAULT_ORDERING = SPEX_DEFAULT, // Default: colamd for LU + // AMD for Cholesky + SPEX_NO_ORDERING = 1, // None: A is factorized as-is + SPEX_COLAMD = 2, // COLAMD: Default for LU (and QR in the FUTURE) + SPEX_AMD = 3 // AMD: Default for Cholesky +} +SPEX_preorder ; + +//------------------------------------------------------------------------------ +// Factorization type codes //------------------------------------------------------------------------------ -// A code in SPEX_options to tell SPEX which column ordering to used prior to -// exact factorization +// A code in SPEX_options to tell SPEX which factorization algorithm to use typedef enum { - SPEX_NO_ORDERING = 0, // None: A is factorized as-is - SPEX_COLAMD = 1, // COLAMD: Default - SPEX_AMD = 2 // AMD + SPEX_ALGORITHM_DEFAULT = SPEX_DEFAULT, // Defaults: Left for LU, + // Up for Chol + SPEX_LU_LEFT = 1, // Left looking LU factorization + SPEX_CHOL_LEFT = 2, // Left looking Cholesky factorization + SPEX_CHOL_UP = 3 // Up looking Cholesky factorization } -SPEX_col_order ; +SPEX_factorization_algorithm ; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ @@ -344,26 +243,52 @@ SPEX_col_order ; // This struct serves as a global struct to define all user-selectable options. -typedef struct SPEX_options +typedef struct { - SPEX_pivot pivot ; // row pivoting scheme used. - SPEX_col_order order ; // column ordering scheme used - double tol ; // tolerance for the row-pivotin methods + SPEX_pivot pivot ; // row pivoting scheme used (LU only) + SPEX_preorder order ; // ordering scheme used + double tol ; // tolerance for the row-pivoting methods for LU. // SPEX_TOL_SMALLEST and SPEX_TOL_LARGEST int print_level ; // 0: print nothing, 1: just errors, - // 2: terse (basic stats from COLAMD/AMD and - // SPEX Left LU), 3: all, with matrices and results - int32_t prec ; // Precision used to output file if MPFR is chosen + // 2: terse (basic stats from COLAMD/AMD and the + // factorization), 3: all, with matrices and results + uint64_t prec ; // Precision for MPFR mpfr_rnd_t round ; // Type of MPFR rounding used - bool check ; // Set true if the solution to the system should be - // checked. Intended for debugging only; SPEX is - // guaranteed to return the exact solution. -} SPEX_options ; + SPEX_factorization_algorithm algo ; // parameter which tells the function + // which factorization algorithm to use +} SPEX_options_struct ; + +// A SPEX_options object is a pointer to a SPEX_options_struct +typedef SPEX_options_struct *SPEX_options ; // Purpose: Create SPEX_options object with default parameters // upon successful allocation, which are defined in SPEX_util_nternal.h -// To free it, simply use SPEX_FREE (*option). -SPEX_info SPEX_create_default_options (SPEX_options **option) ; +// To free it, simply use SPEX_FREE (option). + +SPEX_info SPEX_create_default_options (SPEX_options *option_handle) ; + + +//------------------------------------------------------------------------------ +// SPEX_vector +//------------------------------------------------------------------------------ + +// NOTE: The SPEX_vector object will be used in a near-future version of SPEX. +// It appears here for future compatibility, but is currently unused. + +typedef struct +{ + int64_t nz; // number of explicit entries in the vector + int64_t nzmax;// size of array i and x, nz <= nzmax + int64_t *i; // array of size nzmax that contains the column/row indices + // of each nnz. + mpz_t *x; // array of size nzmax that contains the values of each nnz + mpq_t scale; // a scale factor that has not applied to entries in this v. + // The real value of the k-th nonzero entry in the list should + // be computed as x[k]*scale. x[k]/den(scale) must be integer. +} SPEX_vector_struct ; + +// A SPEX_vector is a pointer to a SPEX_vector_struct +typedef SPEX_vector_struct *SPEX_vector ; //------------------------------------------------------------------------------ @@ -371,18 +296,19 @@ SPEX_info SPEX_create_default_options (SPEX_options **option) ; //------------------------------------------------------------------------------ // SPEX uses a single matrix data type, SPEX_matrix, which can be held in -// one of three kinds of formats: sparse CSC (compressed sparse column), -// sparse triplet, and dense: +// one of four kinds of formats: sparse CSC (compressed sparse column), +// sparse triplet, dense, and sparse dynamic CSC. typedef enum { SPEX_CSC = 0, // matrix is in compressed sparse column format SPEX_TRIPLET = 1, // matrix is in sparse triplet format - SPEX_DENSE = 2 // matrix is in dense format + SPEX_DENSE = 2, // matrix is in dense format (held by column) } SPEX_kind ; -// Each of the three formats can have values of 5 different data types: mpz_t, +// The last format (SPEX_DYNAMIC_CSC) only support mpz_t type, while each of +// the first three formats can have values of 5 different data types: mpz_t, // mpq_t, mpfr_t, int64_t, and double: typedef enum @@ -395,8 +321,10 @@ typedef enum } SPEX_type ; -// This gives a total of 15 different matrix types. Not all functions accept -// all 15 matrices types, however. +// This gives a total of 16 different matrix types: +// (sparse CSC, triplet, dense) x (5 data types) = 15 formats, + +// Not all functions accept all 16 matrices types, however. // Suppose A is an m-by-n matrix with nz <= nzmax entries. // The p, i, j, and x components are defined as: @@ -419,34 +347,45 @@ SPEX_type ; // are all NULL. A->x.type is a pointer to an array of size m*n, stored // in column-oriented format. The value of A(i,j) is A->x.type [p] // with p = i + j*A->m. A->nz is ignored; nz is A->m * A->n. - +// // The SPEX_matrix may contain 'shallow' components, A->p, A->i, A->j, and // A->x. For example, if A->p_shallow is true, then a non-NULL A->p is a // pointer to a read-only array, and the A->p array is not freed by // SPEX_matrix_free. If A->p is NULL (for a triplet or dense matrix), then -// A->p_shallow has no effect. +// A->p_shallow has no effect. typedef struct { + SPEX_kind kind ; // CSC, triplet, dense + SPEX_type type ; // mpz, mpq, mpfr, int64, or fp64 (double) + + int64_t m ; // number of rows int64_t n ; // number of columns - int64_t nzmax ; // size of A->i, A->j, and A->x + + mpq_t scale ; // scale factor for mpz matrices (never shallow) + // For all matrices whose type is not mpz, + // mpz_scale = 1. + // The real value of the nonzero entry A(i,j) + // should be computed as A(i,j)/scale. + + //-------------------------------------------------------------------------- + // these are used for CSC, triplet or dense matrix + //-------------------------------------------------------------------------- + + int64_t nzmax ; // size of A->i, A->j, and A->x. int64_t nz ; // # nonzeros in a triplet matrix . - // Ignored for CSC and dense matrices. - SPEX_kind kind ; // CSC, triplet, or dense - SPEX_type type ; // mpz, mpq, mpfr, int64, or fp64 (double) + // Ignored for CSC, or dense. int64_t *p ; // if CSC: column pointers, an array size is n+1. // if triplet or dense: A->p is NULL. - bool p_shallow ; // if true, A->p is shallow. int64_t *i ; // if CSC or triplet: row indices, of size nzmax. // if dense: A->i is NULL. - bool i_shallow ; // if true, A->i is shallow. + int64_t *j ; // if triplet: column indices, of size nzmax. // if CSC or dense: A->j is NULL. - bool j_shallow ; // if true, A->j is shallow. union // A->x.type has size nzmax. { @@ -456,45 +395,71 @@ typedef struct int64_t *int64 ; // A->x.int64 double *fp64 ; // A->x.fp64 } x ; + + //-------------------------------------------------------------------------- + // This component is only used for SPEX_DYNAMIC_CSC matrix, and ignored for + // CSC, triplet and dense matrix, for a future version of SPEX. + //-------------------------------------------------------------------------- + + SPEX_vector *v; // In this version of SPEX, v is always NULL, and + // should not be used. + + //-------------------------------------------------------------------------- + // flags to indicate if any component is shallow + //-------------------------------------------------------------------------- + + bool p_shallow ; // if true, A->p is shallow. + bool i_shallow ; // if true, A->i is shallow. + bool j_shallow ; // if true, A->j is shallow. bool x_shallow ; // if true, A->x.type is shallow. - mpq_t scale ; // scale factor for mpz matrices (never shallow) - // For all matrices who's type is not mpz, - // mpz_scale = 1. +} SPEX_matrix_struct ; -} SPEX_matrix ; +// A SPEX_matrix is a pointer to a SPEX_matrix_struct +typedef SPEX_matrix_struct *SPEX_matrix ; //------------------------------------------------------------------------------ // SPEX_matrix_allocate: allocate an m-by-n SPEX_matrix //------------------------------------------------------------------------------ +// Allocate an m-by-n SPEX_matrix, in one of 15 data structures: +// (sparse CSC, sparse triplet, or dense) x +// (mpz, mpz, mfpr, int64, or double). + +// The matrix may be created as 'shallow', in +// which case A->p, A->i, A->j, and A->x are all returned as NULL, and all +// A->*_shallow flags are returned as true. The user can then set A->p, A->i, +// A->j, and/or A->x accordingly, from their own arrays. For non-shallow +// matrix, the components (p,i,j,x) are allocated according to the kind, type +// and size (m, n, nzmax) of the matrix. + + // if shallow is false: All components (p,i,j,x) are allocated and set to zero, // and then shallow flags are all false. // if shallow is true: All components (p,i,j,x) are NULL, and their shallow -// flags are all true. The user can then set A->p, -// A->i, A->j, and/or A->x accordingly, from their own -// arrays. +// flags are all true. SPEX_info SPEX_matrix_allocate ( - SPEX_matrix **A_handle, // matrix to allocate - SPEX_kind kind, // CSC, triplet, or dense + SPEX_matrix *A_handle, // matrix to allocate + SPEX_kind kind, // CSC, triplet, dense (and a future dynamic CSC) SPEX_type type, // mpz, mpq, mpfr, int64, or double int64_t m, // # of rows int64_t n, // # of columns - int64_t nzmax, // max # of entries + int64_t nzmax, // max # of entries for CSC or triplet + // (ignored if A is dense) bool shallow, // if true, matrix is shallow. A->p, A->i, A->j, // A->x are all returned as NULL and must be set // by the caller. All A->*_shallow are returned - // as true. + // as true. Ignored if kind is dynamic_CSC. bool init, // If true, and the data types are mpz, mpq, or // mpfr, the entries are initialized (using the // appropriate SPEX_mp*_init function). If false, - // the mpz, mpq, and mpfr arrays are allocated but - // not initialized. Meaningless for data types - // FP64 or INT64 - const SPEX_options *option + // the mpz, mpq, and mpfr arrays are malloced but + // not initialized. Utilized internally to reduce + // memory. Ignored if shallow is true. + const SPEX_options option ) ; //------------------------------------------------------------------------------ @@ -503,19 +468,29 @@ SPEX_info SPEX_matrix_allocate SPEX_info SPEX_matrix_free ( - SPEX_matrix **A_handle, // matrix to free - const SPEX_options *option + SPEX_matrix *A_handle, // matrix to free + const SPEX_options option ) ; //------------------------------------------------------------------------------ // SPEX_matrix_nnz: # of entries in a matrix //------------------------------------------------------------------------------ -SPEX_info SPEX_matrix_nnz // find the # of entries in A +SPEX_info SPEX_matrix_nnz // find the # of entries in A +( + int64_t *nnz, // # of entries in A, -1 if A is NULL + const SPEX_matrix A, // matrix to query + const SPEX_options option // command options, currently unused +) ; + +//------------------------------------------------------------------------------ +// SPEX_matrix_check: check and print a SPEX_matrix +//------------------------------------------------------------------------------ + +SPEX_info SPEX_matrix_check // returns a SPEX status code ( - int64_t *nnz, // # of entries in A, -1 if A is NULL - const SPEX_matrix *A, // matrix to query - const SPEX_options *option + const SPEX_matrix A, // matrix to check + const SPEX_options option ) ; //------------------------------------------------------------------------------ @@ -524,68 +499,174 @@ SPEX_info SPEX_matrix_nnz // find the # of entries in A // SPEX_matrix_copy: make a copy of a SPEX_matrix, into another kind and type. +// SPEX supports 16 matrix formats: 15 of them are all combinations of +// (CSC, triplet, dense) x (mpz, mpq, mpfr, int64, double). + SPEX_info SPEX_matrix_copy ( - SPEX_matrix **C_handle, // matrix to create (never shallow) + SPEX_matrix *C_handle, // matrix to create (never shallow) // inputs, not modified: - SPEX_kind C_kind, // C->kind: CSC, triplet, or dense + SPEX_kind C_kind, // C->kind: CSC, triplet, dense, + // (or future dynamic CSC) SPEX_type C_type, // C->type: mpz_t, mpq_t, mpfr_t, int64_t, or double - SPEX_matrix *A, // matrix to make a copy of (may be shallow) - const SPEX_options *option + const SPEX_matrix A, // matrix to make a copy of (may be shallow) + const SPEX_options option ) ; //------------------------------------------------------------------------------ -// SPEX_matrix macros +// SPEX symbolic analysis and factorization //------------------------------------------------------------------------------ -// These macros simplify the access to entries in a SPEX_matrix. -// The type parameter is one of: mpq, mpz, mpfr, int64, or fp64. - -// To access the kth entry in a SPEX_matrix using 1D linear addressing, -// in any matrix kind (CSC, triplet, or dense), in any type: -#define SPEX_1D(A,k,type) ((A)->x.type [k]) - -// To access the (i,j)th entry in a 2D SPEX_matrix, in any type: -#define SPEX_2D(A,i,j,type) SPEX_1D (A, (i)+(j)*((A)->m), type) +typedef enum +{ + SPEX_LU_FACTORIZATION = 0, // LU factorization + SPEX_CHOLESKY_FACTORIZATION = 1, // Cholesky factorization + SPEX_QR_FACTORIZATION = 2 // QR factorization (FUTURE) +} +SPEX_factorization_kind ; //------------------------------------------------------------------------------ -// SPEX_LU_analysis: symbolic pre-analysis +// SPEX_symbolic_analysis: symbolic pre-analysis //------------------------------------------------------------------------------ -// This struct stores the column permutation for LU and the estimate of the -// number of nonzeros in L and U. +// This struct stores the results of symbolic analysis + +// This object is constructed by SPEX_lu_analyze and SPEX_cholesky_analyze. +// All these functions allocate space and assign values, and thus do not +// require user to perform any memory allocation. Certain components of this +// object can still be NULL after it is constructed. User can access (read or +// print) components of this object, but should not try to modify any of them +// other than calling SPEX_symbolic_analysis_free to free the memory space. typedef struct { - int64_t *q ; // Column permutation for LU factorization, representing - // the permutation matrix Q. The matrix A*Q is factorized. - // If the kth column of L, U, and A*Q is column j of the - // unpermuted matrix A, then j = S->q [k]. - int64_t lnz ; // Approximate number of nonzeros in L. - int64_t unz ; // Approximate number of nonzeros in U. - // lnz and unz are used to allocate the initial space for - // L and U; the space is reallocated as needed. -} SPEX_LU_analysis ; - -// The symbolic analysis object is created by SPEX_LU_analyze. - -// SPEX_LU_analysis_free frees the SPEX_LU_analysis object. -SPEX_info SPEX_LU_analysis_free + SPEX_factorization_kind kind; // LU, Cholesky (or QR in the FUTURE) + + //-------------------------------------------------------------------------- + // The permutations of the matrix that are found during the symbolic + // analysis process. One or more of these permutations could be NULL for + // some SPEX_symbolic_analysis_kind. Specifically, + // For kind == SPEX_LU_FACTORIZATION, only Q_perm is not NULL. + // For kind == SPEX_CHOLESKY_FACTORIZATION, both Q_perm and Qinv_perm are + // NULL. + //-------------------------------------------------------------------------- + int64_t *P_perm; // row permutation + int64_t *Pinv_perm; // inverse of row permutation + + int64_t *Q_perm; // column permutation + int64_t *Qinv_perm; // inverse of column permutation + + //-------------------------------------------------------------------------- + // estimates of nonzeros that will apprear in the factorization + //-------------------------------------------------------------------------- + + int64_t lnz ; // Approximate number of nonzeros in L. + // Available only for SPEX_LU_FACTORIZATION + // or SPEX_CHOLESKY_FACTORIZATION. + int64_t unz ; // Approximate number of nonzeros in U. + // lnz and unz are used to allocate + // the initial space for L and U; the + // space is reallocated as needed. + // Available only for SPEX_LU_FACTORIZATION. + + //-------------------------------------------------------------------------- + // These are only used in the Cholesky analysis process + //-------------------------------------------------------------------------- + int64_t *parent; // Elimination tree of target matrix + // for Cholesky factorization. + int64_t *cp; // column pointers of L for Cholesky + // factorization. + +} SPEX_symbolic_analysis_struct ; + +// A SPEX_symbolic_analysis object is a pointer to a +// SPEX_symbolic_analysis_struct +typedef SPEX_symbolic_analysis_struct *SPEX_symbolic_analysis ; + +//------------------------------------------------------------------------------ +// SPEX_symbolic_analysis_free frees the SPEX_symbolic_analysis object. +//------------------------------------------------------------------------------ + +SPEX_info SPEX_symbolic_analysis_free ( - SPEX_LU_analysis **S, // Structure to be deleted - const SPEX_options *option + SPEX_symbolic_analysis *S_handle, // Structure to be deleted + const SPEX_options option ) ; -// SPEX_LU_analyze performs the symbolic ordering and analysis for LU factorization. -// Currently, there are three options: no ordering, COLAMD, and AMD. -SPEX_info SPEX_LU_analyze +//------------------------------------------------------------------------------ +// SPEX_factorization: data structure for factorization +//------------------------------------------------------------------------------ + +// The SPEX_factorization object holds an LU, Cholesky, or (in the future) QR +// numerical factorization, in either non-updatable (static) or updatable form +// (also future work). +// +// NOTE: +// The components of the factorization structure are accessible to the user +// application. However, they should only be modified by calling SPEX_* +// methods. Changing them directly can lead to undefined behavior. + +// To create this object, users can call SPEX_lu_factorize, or +// SPEX_cholesky_factorize. All these function will create a +// static factorization of corresponding kind. +// +// To free the factorization object, simply call SPEX_factorization_free. + +typedef struct +{ + SPEX_factorization_kind kind; // LU, Cholesky, QR factorization + + bool updatable; // flag to denote if the factorization + // is in the updatable format + // (for a future SPEX version) + + mpq_t scale_for_A; // the scale of the target matrix + + //-------------------------------------------------------------------------- + // These are used for LU or Cholesky factorization, but ignored for QR + // factorization. + //-------------------------------------------------------------------------- + + SPEX_matrix L; // The lower-triangular matrix from LU + // or Cholesky factorization. + SPEX_matrix U; // The upper-triangular matrix from LU + // factorization. NULL for Cholesky + // factorization. + SPEX_matrix rhos; // A n-by-1 dense matrix for the + // pivot values + + + //-------------------------------------------------------------------------- + // The permutations of the matrix that are used during the factorization. + // These are currently used only for LU or Cholesky factorization. + // One or more of these permutations could be NULL for some + // SPEX_factorization_kind. Specifically, + // For kind == SPEX_LU_FACTORIZATION, Qinv_perm can be NULL + // For kind == SPEX_CHOLESKY_FACTORIZATION, both Q_perm and Qinv_perm are + // NULL. + //-------------------------------------------------------------------------- + + int64_t *P_perm; // row permutation + int64_t *Pinv_perm; // inverse of row permutation + + int64_t *Q_perm; // column permutation + int64_t *Qinv_perm; // inverse of column permutation + +} SPEX_factorization_struct ; + +// A SPEX_factorization is a pointer to a SPEX_factorization_struct +typedef SPEX_factorization_struct *SPEX_factorization ; + +//------------------------------------------------------------------------------ +// SPEX_factorization_free frees the SPEX_factorization object. +//------------------------------------------------------------------------------ + +SPEX_info SPEX_factorization_free ( - SPEX_LU_analysis **S, // symbolic analysis (column permutation and nnz L,U) - const SPEX_matrix *A, // Input matrix - const SPEX_options *option // Control parameters + SPEX_factorization *F_handle, // Structure to be deleted + const SPEX_options option ) ; - //------------------------------------------------------------------------------ // Memory management //------------------------------------------------------------------------------ @@ -595,6 +676,7 @@ SPEX_info SPEX_LU_analyze // SuiteSparse_free. // Allocate and initialize memory space for SPEX + void *SPEX_calloc ( size_t nitems, // number of items to allocate @@ -602,12 +684,14 @@ void *SPEX_calloc ) ; // Allocate memory space for SPEX + void *SPEX_malloc ( size_t size // size of memory space to allocate ) ; // Free the memory allocated by SPEX_calloc, SPEX_malloc, or SPEX_realloc. + void SPEX_free ( void *p // pointer to memory space to free @@ -655,81 +739,73 @@ void *SPEX_realloc // pointer to reallocated block, or original block ) ; //------------------------------------------------------------------------------ -// SPEX memory environment routines +// SPEX environment routines //------------------------------------------------------------------------------ // SPEX_initialize: initializes the working evironment for SPEX library. // It must be called prior to calling any other SPEX_* function. -SPEX_info SPEX_initialize (void) ; + +SPEX_info SPEX_initialize ( void ) ; // SPEX_initialize_expert is the same as SPEX_initialize, except that it allows // for a redefinition of custom memory functions that are used for SPEX and // GMP. The four inputs to this function are pointers to four functions with // the same signatures as the ANSI C malloc, calloc, realloc, and free. + SPEX_info SPEX_initialize_expert ( - void* (*MyMalloc) (size_t), // user-defined malloc - void* (*MyCalloc) (size_t, size_t), // user-defined calloc - void* (*MyRealloc) (void *, size_t), // user-defined realloc + void *(*MyMalloc) (size_t), // user-defined malloc + void *(*MyCalloc) (size_t, size_t), // user-defined calloc + void *(*MyRealloc) (void *, size_t), // user-defined realloc void (*MyFree) (void *) // user-defined free ) ; // SPEX_finalize: This function finalizes the working evironment for SPEX // library, and frees any internal workspace created by SPEX. It must be // called as the last SPEX_* function called. -SPEX_info SPEX_finalize (void) ; - -// SPEX_matrix_check: check and print a SPEX_sparse matrix -SPEX_info SPEX_matrix_check // returns a SPEX status code +SPEX_info SPEX_finalize ( - const SPEX_matrix *A, // matrix to check - const SPEX_options* option // defines the print level + void ) ; +// SPEX is thread-safe but it requires each user thread to call +// SPEX_thread_initialize when it starts, and SPEX_thread_finalize when it +// finishes. These two functions must be called after the user's primary thread +// calls SPEX_initialize (or SPEX_initialize_experm) and before the user's +// primary thread calls SPEX_finalize. -/* Purpose: This function takes as input a mpz_t SPEX_matrix and divides - * it by an mpz_t constant storing the solution in a mpq_t dense SPEX_matrix - * array. - */ -SPEX_info SPEX_matrix_div // divides the x matrix by a scalar -( - SPEX_matrix **x2_handle, // x2 = x/scalar - SPEX_matrix* x, // input vector x - const mpz_t scalar, // the scalar - const SPEX_options *option -) ; +SPEX_info SPEX_thread_initialize ( void ) ; + +SPEX_info SPEX_thread_finalize ( void ) ; -/* Purpose: This function multiplies matrix x a scalar - */ -SPEX_info SPEX_matrix_mul // multiplies x by a scalar +//------------------------------------------------------------------------------ +// SPEX matrix utilities +//------------------------------------------------------------------------------ + +// Purpose: This function sets C = A', where A must be a SPEX_CSC matrix +// C_handle is NULL on input. On output, C_handle contains a pointer to A' + +SPEX_info SPEX_transpose ( - SPEX_matrix *x, // matrix to be multiplied - const mpz_t scalar // scalar to multiply by + SPEX_matrix *C_handle, // C = A' + SPEX_matrix A, // Matrix to be transposed + const SPEX_options option ) ; +// Purpose: Determine if the input A is symmetric. Since SPEX is an exact +// framework, the method checks if the matrix is symmetric both numerically +// and in its symbolic pattern. The method has no option for checking just +// pattern symmetry. -/* SPEX_check_solution: checks the solution of the linear system. Performs a - * quick rational arithmetic check of A*x=b. - */ -SPEX_info SPEX_check_solution -( - const SPEX_matrix *A, // input matrix - const SPEX_matrix *x, // solution vector - const SPEX_matrix *b, // right hand side - const SPEX_options* option // Command options -); - -/* Purpose: p [0..n] = cumulative sum of c [0..n-1], and then copy p [0..n-1] - * into c. This function is lightly modified from CSparse. - */ -SPEX_info SPEX_cumsum +SPEX_info SPEX_determine_symmetry ( - int64_t *p, // vector to store the sum of c - int64_t *c, // vector which is summed - int64_t n // size of c -); + bool *is_symmetric, // true if matrix is symmetric, false otherwise + const SPEX_matrix A, // Input matrix to be checked for symmetry + const SPEX_options option // Command options +) ; +// ended HERE on Apr 10. //------------------------------------------------------------------------------ //---------------------------SPEX GMP/MPFR Functions---------------------------- @@ -749,7 +825,7 @@ SPEX_info SPEX_cumsum // allocated by that function. The list is started fresh each time a GMP // function is called. If any allocation fails, the NULL pointer is not // returned to GMP. Instead, all allocated blocks in the list are freed, -// and spex_gmp_allocate returns directly to wrapper. +// and the allocation routine passed to GMP returns directly to the wrapper. SPEX_info SPEX_mpfr_asprintf (char **str, const char *format, ... ) ; @@ -757,7 +833,7 @@ SPEX_info SPEX_gmp_fscanf (FILE *fp, const char *format, ... ) ; SPEX_info SPEX_mpz_init (mpz_t x) ; -SPEX_info SPEX_mpz_init2(mpz_t x, const size_t size) ; +SPEX_info SPEX_mpz_init2(mpz_t x, const uint64_t size) ; SPEX_info SPEX_mpz_set (mpz_t x, const mpz_t y) ; @@ -765,28 +841,38 @@ SPEX_info SPEX_mpz_set_ui (mpz_t x, const uint64_t y) ; SPEX_info SPEX_mpz_set_si (mpz_t x, const int64_t y) ; +SPEX_info SPEX_mpz_swap (mpz_t x, mpz_t y); + SPEX_info SPEX_mpz_get_d (double *x, const mpz_t y) ; SPEX_info SPEX_mpz_get_si (int64_t *x, const mpz_t y) ; -SPEX_info SPEX_mpz_set_q (mpz_t x, const mpq_t y) ; - SPEX_info SPEX_mpz_mul (mpz_t a, const mpz_t b, const mpz_t c) ; -#if 0 +SPEX_info SPEX_mpz_mul_si (mpz_t a, const mpz_t b, const int64_t c) ; + +SPEX_info SPEX_mpz_sub (mpz_t a, const mpz_t b, const mpz_t c) ; + SPEX_info SPEX_mpz_add (mpz_t a, const mpz_t b, const mpz_t c) ; SPEX_info SPEX_mpz_addmul (mpz_t x, const mpz_t y, const mpz_t z) ; -#endif SPEX_info SPEX_mpz_submul (mpz_t x, const mpz_t y, const mpz_t z) ; +SPEX_info SPEX_mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d) ; + +SPEX_info SPEX_mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d) ; + +SPEX_info SPEX_mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d) ; + SPEX_info SPEX_mpz_divexact (mpz_t x, const mpz_t y, const mpz_t z) ; SPEX_info SPEX_mpz_gcd (mpz_t x, const mpz_t y, const mpz_t z) ; SPEX_info SPEX_mpz_lcm (mpz_t lcm, const mpz_t x, const mpz_t y) ; +SPEX_info SPEX_mpz_neg (mpz_t x, const mpz_t y) ; + SPEX_info SPEX_mpz_abs (mpz_t x, const mpz_t y) ; SPEX_info SPEX_mpz_cmp (int *r, const mpz_t x, const mpz_t y) ; @@ -795,6 +881,8 @@ SPEX_info SPEX_mpz_cmpabs (int *r, const mpz_t x, const mpz_t y) ; SPEX_info SPEX_mpz_cmp_ui (int *r, const mpz_t x, const uint64_t y) ; +SPEX_info SPEX_mpz_cmpabs_ui (int *r, const mpz_t x, const uint64_t y) ; + SPEX_info SPEX_mpz_sgn (int *sgn, const mpz_t x) ; SPEX_info SPEX_mpz_sizeinbase (size_t *size, const mpz_t x, int64_t base) ; @@ -805,6 +893,8 @@ SPEX_info SPEX_mpq_set (mpq_t x, const mpq_t y) ; SPEX_info SPEX_mpq_set_z (mpq_t x, const mpz_t y) ; +SPEX_info SPEX_mpq_canonicalize (mpq_t x); + SPEX_info SPEX_mpq_set_d (mpq_t x, const double y) ; SPEX_info SPEX_mpq_set_ui (mpq_t x, const uint64_t y, const uint64_t z) ; @@ -815,10 +905,10 @@ SPEX_info SPEX_mpq_set_num (mpq_t x, const mpz_t y) ; SPEX_info SPEX_mpq_set_den (mpq_t x, const mpz_t y) ; -SPEX_info SPEX_mpq_get_den (mpz_t x, const mpq_t y) ; - SPEX_info SPEX_mpq_get_d (double *x, const mpq_t y) ; +SPEX_info SPEX_mpq_neg (mpq_t x, const mpq_t y) ; + SPEX_info SPEX_mpq_abs (mpq_t x, const mpq_t y) ; SPEX_info SPEX_mpq_add (mpq_t x, const mpq_t y, const mpq_t z) ; @@ -874,83 +964,352 @@ SPEX_info SPEX_mpfr_free_cache (void) ; SPEX_info SPEX_mpfr_free_str (char *str) ; -#if 0 -// These functions are currently unused, but kept here for future reference. -SPEX_info SPEX_gmp_asprintf (char **str, const char *format, ... ) ; -SPEX_info SPEX_gmp_printf (const char *format, ... ) ; -SPEX_info SPEX_mpfr_printf ( const char *format, ... ) ; -SPEX_info SPEX_gmp_fprintf (FILE *fp, const char *format, ... ) ; -SPEX_info SPEX_mpfr_fprintf (FILE *fp, const char *format, ... ) ; -SPEX_info SPEX_mpz_set_d (mpz_t x, const double y) ; -SPEX_info SPEX_mpfr_log2(mpfr_t x, const mpfr_t y, const mpfr_rnd_t rnd) ; -#endif +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------SPEX Left LU----------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This portion of the SPEX library solves a sparse system of linear equations +// using the SPEX Left LU factorization. This code accompanies the paper +// (submitted to ACM Transactions on Mathematical Software): + +// "Algorithm 1021: SPEX Left LU, Exactly Solving Sparse Linear Systems via +// a Sparse Left-looking Integer-preserving LU Factorization", +// C. Lourenco, J. Chen, E. Moreno-Centeno, T. Davis, +// ACM Trans. Mathematical Software. pp 1-23, vol 48, no 2, 2022. + +// The theory associated with this software can be found in the paper +// (published in SIAM journal on matrix analysis and applications): + +// "Exact Solution of Sparse Linear Systems via Left-Looking +// Roundoff-Error-Free LU Factorization in Time Proportional to +// Arithmetic Work", C. Lourenco, A. R. Escobedo, E. Moreno-Centeno, +// T. Davis, SIAM J. Matrix Analysis and Applications. pp 609-638, +// vol 40, no 2, 2019. + +// If you use this code, you must first download and install the GMP and +// MPFR libraries. GMP and MPFR can be found at: +// https://gmplib.org/ +// http://www.mpfr.org/ + +// If you use SPEX Left LU for a publication, we request that you please cite +// the above two papers. + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------Authors---------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// Christopher Lourenco, Jinhao Chen, Timothy A. Davis, and Erick Moreno-Centeno + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//--------------------------Summary--------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This software package solves the linear system Ax = b exactly. The input +// matrix and right hand side vectors are stored as either integers, double +// precision numbers, multiple precision floating points (through the mpfr +// library) or as rational numbers (as a collection of numerators and +// denominators using the GMP mpq_t data structure). Appropriate routines +// within the code transform the input into an integral matrix in compressed +// column form. + +// This package computes the factorization PAQ = LDU. Note that we store the +// "functional" form of the factorization by only storing L and U. The user +// is given some freedom to select the permutation matrices P and Q. The +// recommended default settings select Q using the COLAMD column ordering +// and select P via a partial pivoting scheme in which the diagonal entry +// in column k is selected if it is the same magnitude as the smallest +// entry, otherwise the smallest entry is selected as the kth pivot. +// Alternative strategies allowed to select Q include the AMD column +// ordering or no column permutation (Q=I). For pivots, there are a variety +// of potential schemes including traditional partial pivoting, diagonal +// pivoting, tolerance pivoting etc. This package does not allow pivoting +// based on sparsity criterion. + +// The factors L and U are computed via integer preserving operations via +// integer-preserving Gaussian elimination. The key part of this algorithm +// is a Roundoff Error Free (REF) sparse triangular solve function which +// exploits sparsity to reduce the number of operations that must be +// performed. + +// Once L and U are computed, a simplified version of the triangular solve +// is performed which assumes the vector b is dense. The final solution +// vector x is gauranteed to be exact. This vector can be output in one of +// three ways: 1) full precision rational arithmetic (as a sequence of +// numerators and denominators) using the GMP mpq_t data type, 2) double +// precision while not exact will produce a solution accurate to machine +// roundoff unless the size of the associated solution exceeds double +// precision (i.e., the solution is 10^500 or something), 3) variable +// precision floating point using the GMP mpfr_t data type. The associated +// precision is user defined. -#endif //------------------------------------------------------------------------------ // Primary factorization & solve routines //------------------------------------------------------------------------------ -// SPEX_backslash solves the linear system Ax = b. This is the simplest way to -// use the SPEX Left LU package. This function encompasses both factorization and -// solve and returns the solution vector in the user desired type. It can be -// thought of as an exact version of MATLAB sparse backslash. -SPEX_info SPEX_Left_LU_backslash +// SPEX_lu_backslash solves the linear system Ax = b via LU factorization +// of A. This is the simplest way to use the SPEX Left LU package. This +// function encompasses both factorization and solve and returns the solution +// vector in the user desired type. It can be thought of as an exact version +// of MATLAB sparse backslash. +// x and b be can be single vectors, or matrices. + +SPEX_info SPEX_lu_backslash ( // Output - SPEX_matrix **X_handle, // Final solution vector + SPEX_matrix *x_handle, // Final solution vector // Input - SPEX_type type, // Type of output desired: - // Must be SPEX_MPQ, SPEX_MPFR, - // or SPEX_FP64 - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *b, // Right hand side vector(s) - const SPEX_options* option + SPEX_type type, // Type of output desired. Must be + // SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 + const SPEX_matrix A, // Input matrix + const SPEX_matrix b, // Right hand side vector(s) + const SPEX_options option // Command options ) ; -// SPEX_Left_LU_factorize performs the SPEX Left LU factorization. -// This factorization is done via n iterations of the sparse REF -// triangular solve function. The overall factorization is -// PAQ = LDU. The determinant can be obtained as rhos->x.mpz[n-1]. -// -// L: undefined on input, created on output -// U: undefined on input, created on output -// rhos: undefined on input, created on output -// pinv: undefined on input, created on output -// -// A: input only, not modified -// S: input only, not modified -// option: input only, not modified -SPEX_info SPEX_Left_LU_factorize +SPEX_info SPEX_lu_analyze +( + SPEX_symbolic_analysis *S_handle, // symbolic analysis including + // column perm. and nnz of L and U + const SPEX_matrix A, // Input matrix + const SPEX_options option // Control parameters, if NULL, use default +) ; + +SPEX_info SPEX_lu_factorize ( // output: - SPEX_matrix **L_handle, // lower triangular matrix - SPEX_matrix **U_handle, // upper triangular matrix - SPEX_matrix **rhos_handle, // sequence of pivots - int64_t **pinv_handle, // inverse row permutation + SPEX_factorization *F_handle, // LU factorization // input: - const SPEX_matrix *A, // matrix to be factored - const SPEX_LU_analysis *S, // column permutation and estimates - // of nnz in L and U - const SPEX_options* option + const SPEX_matrix A, // matrix to be factored + const SPEX_symbolic_analysis S, // symbolic analysis + const SPEX_options option // command options ) ; -// SPEX_Left_LU_solve solves the linear system LD^(-1)U x = b. -SPEX_info SPEX_Left_LU_solve // solves the linear system LD^(-1)U x = b +// solves the linear system Ax = b via LU factorization. +// x and b be can be single vectors, or matrices. + +SPEX_info SPEX_lu_solve // solves the linear system LD^(-1)U x = b ( // Output - SPEX_matrix **X_handle, // rational solution to the system + SPEX_matrix *x_handle, // rational solution to the system + // input/output: + SPEX_factorization F, // The LU factorization. + // Mathematically, F is unchanged. // input: - const SPEX_matrix *b, // right hand side vector - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *L, // lower triangular matrix - const SPEX_matrix *U, // upper triangular matrix - const SPEX_matrix *rhos, // sequence of pivots - const SPEX_LU_analysis *S, // symbolic analysis struct - const int64_t *pinv, // inverse row permutation - const SPEX_options* option + const SPEX_matrix b, // right hand side vector(s) + const SPEX_options option // Command options +) ; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------SPEX Cholesky---------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This portion of the SPEX library exactly solves a sparse symmetric positive +// definite (SPD) system of linear equations using one of two Integer- +// Preserving Cholesky factorizations. This code accompanies the paper (to be +// submitted to ACM TOMs) + +// "Algorithm 1xxx: Exactly Solving Sparse Symmetric Positive Definite +// Linear Systems via SPEX Cholesky factorization," C. Lourenco, L. Mejia +// Domenzain, E. Moreno-Centeno, T. Davis, to be submitted ACM TOMS. + +// The theory associated with this paper is found at: + +// "Exactly Solving Sparse Rational Linear Systems via Roundoff-Error-Free +// Cholesky Factorizations", C. Lourenco, E. Moreno-Centeno, +// SIAM J. Matrix Analysis and Applications. +// pp 609-638, vol 43, no 1, 2022. + +// To use this code you must first download and install the GMP, +// MPFR, AMD, and COLAMD libraries. GMP and MPFR can be found at: +// https://gmplib.org/ +// http://www.mpfr.org/ +// +// SPEX_Utilities, AMD, and COLAMD are distributed along with SPEX_Cholesky. +// The easiest way ensure these dependencies are met is to only access this +// package through the SPEX repository. +// +// All of these codes are components of the SPEX software library. This code +// may be found at: +// https://github.com/clouren/spex +// www.suitesparse.com +// +// + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------Authors---------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//--------------------------Summary--------------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// This software package solves the SPD linear system Ax = b exactly. The +// key property of this package is that it can exactly solve any SPD input +// system. The input matrix and right hand side vectors are stored as +// either integers, double precision numbers, multiple precision floating +// points (through the mpfr library) or as rational numbers (as a collection +// of numerators and denominators using the GMP mpq_t data structure). +// Appropriate routines within the code transform the input into an integral +// matrix in compressed column form. + +// This package computes the factorization PAP' = LDL'. Note that we store +// the "functional" form of the factorization by only storing the matrix L. +// The user is given some freedom to select the permutation matrix P. The +// recommended default settings select P using the AMD ordering. +// Alternative strategies allowed to select P include the COLAMD +// ordering or no column permutation (P=I). + +// The factor L is computed via integer preserving operations via +// integer-preserving Gaussian elimination. The key part of this algorithm +// is a REF Sparse triangular solve function which exploits sparsity and +// symmetry to reduce the number of operations that must be performed. + +// Once L is computed, a simplified version of the triangular solve +// is performed which assumes the vector b is dense. The final solution +// vector x is gauranteed to be exact. This vector can be output in one of +// three ways: 1) full precision rational arithmetic (as a sequence of +// numerators and denominators) using the GMP mpq_t data type, 2) double +// precision while not exact will produce a solution accurate to machine +// roundoff unless the size of the associated solution exceeds double +// precision (i.e., the solution is 10^500 or something), 3) variable +// precision floating point using the GMP mpfr_t data type. The associated +// precision is user defined. + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-----------------------Primary SPEX Cholesky routines------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// Purpose: Compute the exact solution of Ax = b via Cholesky factorization of A +// On input, A is expected to be SPD and x is NULL +// On output, x contains the solution of the linear system + +SPEX_info SPEX_cholesky_backslash +( + // Output + SPEX_matrix *x_handle, // On input: undefined. + // On output: solution vector(s) + // Input + SPEX_type type, // Type of output desired + // Must be SPEX_FP64, SPEX_MPFR, or SPEX_MPQ + const SPEX_matrix A, // Input matrix. Must be SPEX_MPZ and SPEX_CSC + const SPEX_matrix b, // Right hand side vector(s). Must be + // SPEX_MPZ and SPEX_DENSE + const SPEX_options option // Command options (Default if NULL) +) ; + +SPEX_info SPEX_cholesky_analyze +( + // Output + SPEX_symbolic_analysis *S_handle, // Symbolic analysis data structure + // Input + const SPEX_matrix A, // Input matrix. Must be SPEX_MPZ and SPEX_CSC + const SPEX_options option // Command options (Default if NULL) +) ; + +SPEX_info SPEX_cholesky_factorize +( + // Output + SPEX_factorization *F_handle, // Cholesky factorization struct + //Input + const SPEX_matrix A, // Matrix to be factored. Must be SPEX_MPZ + // and SPEX_CSC + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column + // pointers of L, and the exact number of + // nonzeros of L. + const SPEX_options option // command options. + // Notably, option->chol_type indicates + // whether CHOL_UP (default) or CHOL_LEFT + // is used. +) ; + +// Purpose: After computing the REF Cholesky factorization A = LDL', +// this function solves the associated linear system LDL' x = b. +// +// On input x is undefined, F contains the REF Cholesky factorization +// of A (including L, rhos, and row permutation), b contains +// the user's right hand side. +// +// On output x contains the rational solution of the system LDL' x = b +// x and b be can be single vectors, or matrices. + + +SPEX_info SPEX_cholesky_solve +( + // Output + SPEX_matrix *x_handle, // On input: undefined. + // On output: Rational solution (SPEX_MPQ) + // to the system. + // input/output: + SPEX_factorization F, // The Cholesky factorization. + // Mathematically, F is unchanged. + // input: + const SPEX_matrix b, // Right hand side vector + const SPEX_options option // command options +) ; + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//--------------------------SPEX Backslash-------------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// SPEX_backslash is a wrapper for the exact routines contained within the +// SPEX software package. + +// SPEX_BACKSLASH: solve Ax=b via sparse integer-preserving factorization. +// SPEX_backslash: computes the exact solution to the sparse linear system Ax = +// b. A and b may be stored as either int64, double precision, arbitrary +// precision floating point (mpfr_t), arbitrary sized integer (mpz_t), or +// arbitrary size rational numbers (mpq_t). The result x is computed exactly, +// represented in arbitrary-precision rational values. This solution vector +// may be returned in either this rational form, or in double precision or in +// arbitrary precision floating point. +// +// A must be square. If A is SPD, an exact up-looking Cholesky factorization is +// applied. Otherwise, an exact left-looking LU functionality is applied. +// x and b be can be single vectors, or matrices. + +//------------------------------------------------------------------------------ +// Purpose: Solve Ax = b by analyzing the input matrix and applying the +// appropiate factorization approach +//------------------------------------------------------------------------------ + +SPEX_info SPEX_backslash +( + // Output + SPEX_matrix *x_handle, // On output: Final solution vector(s) + // On input: undefined + // Input + const SPEX_type type, // Type of output desired + // Must be SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 + const SPEX_matrix A, // Input matrix + const SPEX_matrix b, // Right hand side vector(s) + SPEX_options option // Command options (NULL: means use defaults) ) ; #if defined ( __cplusplus ) @@ -958,3 +1317,4 @@ SPEX_info SPEX_Left_LU_solve // solves the linear system LD^(-1)U x = b #endif #endif + diff --git a/SPEX/LICENSE.txt b/SPEX/LICENSE.txt index 2803b23bac..0020fe095d 100644 --- a/SPEX/LICENSE.txt +++ b/SPEX/LICENSE.txt @@ -2,15 +2,14 @@ This file lists all licenses for all packages in SPEX, for your convenience. Each package has its own separate license, which can be found in the lists below. -==> SPEX_Left_LU/License/license.txt <== +==> SPEX/LICENSE <== - SPEX Left LU: a Sparse Left-looking Integer-Preserving LU Factorization + SPEX: a SParse EXact Factorization Framework for solving SLEs - Copyright (c) 2019-2022, Christopher Lourenco, JinHao Chen, Erick Moreno- - Centeno, and Timothy A. Davis. + Copyright (c) 2019-2023, Christopher Lourenco, Jinhao Chen, + Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. Available at: - https://github.com/clouren/SPEX http://suitesparse.com @@ -20,7 +19,7 @@ found in the lists below. -------------------------------------------------------------------------------- - SPEX Left LU is free software; you can redistribute it and/or modify + SPEX is free software; you can redistribute it and/or modify it under the terms of either: * the GNU Lesser General Public License as published by the Free @@ -35,7 +34,7 @@ found in the lists below. or both in parallel, as here. - SPEX Left LU is distributed in the hope that it will be useful, but + SPEX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -82,6 +81,7 @@ found in the lists below. DAMAGE. ==> COLAMD/Doc/License.txt <== + COLAMD, Copyright 1998-2016, Timothy A. Davis. http://www.suitesparse.com http://www.suitesparse.com diff --git a/SPEX/MATLAB/.gitignore b/SPEX/MATLAB/.gitignore new file mode 100644 index 0000000000..21dde81f4e --- /dev/null +++ b/SPEX/MATLAB/.gitignore @@ -0,0 +1,3 @@ +# Ignore the spex_deps.m file (constructed by cmake) +spex_deps.m +!.gitignore diff --git a/SPEX/MATLAB/Source/SPEX_mex.h b/SPEX/MATLAB/Source/SPEX_mex.h new file mode 100644 index 0000000000..a951aefd59 --- /dev/null +++ b/SPEX/MATLAB/Source/SPEX_mex.h @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// SPEX/MATLAB/SPEX_mex.h: include file for MATLAB functions +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// This file contains the routines for SPEX's MATLAB interface. +// The MATLAB interface can be used to solve linear systems Ax = b +// using either the left LU factorization, Cholesky factorization, +// or allowing SPEX to choose for the user the correct algorithm. + +// Note that the MATLAB interface of SPEX is intended to provide +// accurate solutions to linear systems within MATLAB. Note that there +// are two major limitations to the MATLAB interface: + +// 1) The MATLAB interface does not give access to the factors L and/or U. +// thus, one can not reuse the factors after a solution is computed (nor +// can they be updated). If a user desires this functionality, they should +// utilize the C interface. + +// +// 2) The MATLAB interface preserves 16 decimal digits of precision from +// MATLAB. That is, since the input is floating point, all numbers are +// assumed to be correct to 16 digits. This is due to the fact that +// epsilon is about 2e-16 thus, floating point numbers, such as fl(0.9) +// can not be expressed exactly. With an exact (floating-point) +// conversion, fl(0.9) is sent to SPEX as 45000000000000001 / +// 50000000000000000. Using 16 decimal digits of precision, this number is +// sent to spex as 9/10. If one wishes to preserve full floating point +// precision, they may either scale the matrix themselves within MATLAB, +// or if this is not possible, utilize the C interface, and copy the +// matrix twice. First it should be copied from SPEX_FP64 (double) to +// SPEX_MPFR and then from SPEX_MPFR to SPEX_MPQ. Either of these options +// will preserve as much floating-point precision as the user desires. + +#ifndef SPEX_BACKSLASH_MEX_H +#define SPEX_BACKSLASH_MEX_H + +#include "SPEX.h" +#include "matrix.h" +#include "mex.h" + +#define SPEX_MEX_OK(method) \ +{ \ + status = method ; \ + if (status != SPEX_OK) \ + { \ + spex_mex_error (status, "") ; \ + } \ +} + + +/* These enums determine the type of output desired by the user + */ +typedef enum +{ + SPEX_SOLUTION_DOUBLE = 0, // x as double + SPEX_SOLUTION_VPA = 1, // return x as vpa + SPEX_SOLUTION_CHAR = 2 // x as cell strings +} +SPEX_solution ; + + +typedef struct spex_mex_options +{ + SPEX_solution solution ; // how should x be returned to MATLAB + int32_t digits ; // # of digits to use for vpa +} +spex_mex_options ; + +/* Purpose: A GMP reallocation function + * This allows GMP to use MATLAB's default realloc function + */ +void *SPEX_gmp_mex_realloc +( + void *x, // void * to be reallocated + size_t a, // Previous size + size_t b // New size +); + +/* Purpose: A GMP free function. This allows GMP to use + * MATLAB's mxFree instead of free + */ +void SPEX_gmp_mex_free +( + void *x, // void * to be freed + size_t a // Size +); + +/* Purpose: get command options from MATLAB + */ +void spex_mex_get_matlab_options +( + SPEX_options option, // Control parameters + spex_mex_options *mexoptions, // MATLAB-specific options + const mxArray* input // options struct, may be NULL +) ; + +// Purpose: This function checks if the array x contains Inf's, NaN's, or +// if its values can be represented as int64_t values. + +bool spex_mex_check_for_inf // true if x can be represented as int64_t +( + double *x, // The array of numeric values + mwSize n // size of array +) ; + +/* Purpose: This function reads in the A matrix and right hand side vectors. */ +void spex_mex_get_A_and_b +( + SPEX_matrix *A_handle, // Internal SPEX Mat stored in CSC + SPEX_matrix *b_handle, // mpz matrix used internally + const mxArray* pargin[], // The input A matrix and options + SPEX_options option +) ; + +/* Purpose: Report errors if they arise + */ +void spex_mex_error +( + SPEX_info status, + char *message +) ; + +#endif + diff --git a/SPEX/MATLAB/Source/spex_mex_check_for_inf.c b/SPEX/MATLAB/Source/spex_mex_check_for_inf.c new file mode 100644 index 0000000000..6242b4f381 --- /dev/null +++ b/SPEX/MATLAB/Source/spex_mex_check_for_inf.c @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// SPEX/MATLAB/SPEX_mex_check_for_inf.c: Check A&B for inf/NAN +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function checks if the array x contains Inf's, NaN's, or + * if its values can be represented as int64_t values, useful for input + * arguments. + */ + +#include "SPEX_mex.h" + +bool spex_mex_check_for_inf // true if x can be represented as int64_t +( + double *x, // The array of numeric values + mwSize n // size of array +) +{ + // Assume it is int64 + bool x_is_int64 = true ; + + // Iterate through all entries + for (mwSize k = 0; k < n; k++) + { + double xk = x [k] ; + + // Check if inf + if (mxIsInf (xk)) + { + spex_mex_error (1, "A must not have any Inf values"); + } + + // Check if NAN + if (mxIsNaN (xk)) + { + spex_mex_error (1, "A must not have any NaN values"); + } + + // Check if int64 + if (x_is_int64) + { + if (xk < INT64_MIN || xk > INT64_MAX) + { + x_is_int64 = false ; + break; + } + else + { + int64_t xi = (int64_t) xk ; + if ((double) xi != xk) + { + x_is_int64 = false ; + break; + } + } + } + } + + return (x_is_int64); +} + diff --git a/SPEX/MATLAB/Source/spex_mex_error.c b/SPEX/MATLAB/Source/spex_mex_error.c new file mode 100644 index 0000000000..3d978a1a59 --- /dev/null +++ b/SPEX/MATLAB/Source/spex_mex_error.c @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// SPEX/MATLAB/SPEX_mex_error.c: Check error codes for MATLAB +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function prints error messages for MATLAB for debugging */ + +#include "SPEX_mex.h" + +void spex_mex_error +( + SPEX_info status, + char *message +) +{ + + switch (status) + { + case SPEX_OK : // all is well + return ; + + case SPEX_OUT_OF_MEMORY : // out of memory + SPEX_finalize ( ); + mexErrMsgTxt ("out of memory"); + + case SPEX_SINGULAR : // the input matrix A is singular + SPEX_finalize ( ); + mexErrMsgTxt ("input matrix is singular"); + + case SPEX_INCORRECT_INPUT : // one or more input arguments are + // incorrect + SPEX_finalize ( ); + mexErrMsgTxt ("invalid inputs"); + + + case SPEX_PANIC : // SPEX used without proper + // initialization + SPEX_finalize ( ); + mexErrMsgTxt ("panic"); + + default : + SPEX_finalize ( ); + mexErrMsgTxt (message); + } +} + diff --git a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_get_A_and_b.c b/SPEX/MATLAB/Source/spex_mex_get_A_and_b.c similarity index 70% rename from SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_get_A_and_b.c rename to SPEX/MATLAB/Source/spex_mex_get_A_and_b.c index 9c81ce8f20..f9c32d3d42 100644 --- a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_get_A_and_b.c +++ b/SPEX/MATLAB/Source/spex_mex_get_A_and_b.c @@ -1,23 +1,24 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/MATLAB/spex_left_lu_mex_get_A_and_b: Obtain user's A and b matrices +// SPEX/MATLAB/SPEX_mex_get_A_and_b.c: convert A&b to SPEX matrices //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ /* Purpose: This function reads in the A matrix and right hand side vectors. */ -#include "SPEX_Left_LU_mex.h" +#include "SPEX_mex.h" -void spex_left_lu_mex_get_A_and_b +void spex_mex_get_A_and_b ( - SPEX_matrix **A_handle, // Internal SPEX Mat stored in CSC - SPEX_matrix **b_handle, // mpz matrix used internally + SPEX_matrix *A_handle, // Internal SPEX Mat stored in CSC + SPEX_matrix *b_handle, // mpz matrix used internally const mxArray* pargin[], // The input A matrix and options - SPEX_options* option + SPEX_options option ) { @@ -27,7 +28,7 @@ void spex_left_lu_mex_get_A_and_b if (!A_handle || !pargin) { - spex_left_lu_mex_error (SPEX_INCORRECT_INPUT, ""); + spex_mex_error (SPEX_INCORRECT_INPUT, ""); } (*A_handle) = NULL ; @@ -45,36 +46,37 @@ void spex_left_lu_mex_get_A_and_b //-------------------------------------------------------------------------- // Read in Ap, Ai, Ax - Ap = (int64_t *) mxGetJc (pargin[0]) ; - Ai = (int64_t *) mxGetIr (pargin[0]) ; - Ax = mxGetDoubles (pargin[0]) ; + Ap = (int64_t *) mxGetJc (pargin[0]); + Ai = (int64_t *) mxGetIr (pargin[0]); + Ax = mxGetDoubles (pargin[0]); + if (!Ai || !Ap || !Ax) { - spex_left_lu_mex_error (SPEX_INCORRECT_INPUT, "") ; + spex_mex_error (SPEX_INCORRECT_INPUT, ""); } // Get info about A - nA = (int64_t) mxGetN (pargin[0]) ; - mA = (int64_t) mxGetM (pargin[0]) ; + nA = (int64_t) mxGetN (pargin[0]); + mA = (int64_t) mxGetM (pargin[0]); Anz = Ap[nA]; if (nA != mA) { - spex_left_lu_mex_error (1, "A must be square") ; + spex_mex_error (1, "A must be square"); } // check the values of A - bool A_has_int64_values = spex_left_lu_mex_check_for_inf (Ax, Anz) ; + bool A_has_int64_values = spex_mex_check_for_inf (Ax, Anz); - SPEX_matrix* A = NULL; - SPEX_matrix* A_matlab = NULL; + SPEX_matrix A = NULL; + SPEX_matrix A_matlab = NULL; if (A_has_int64_values) { // All entries in A can be typecast to int64_t without change in value. - int64_t *Ax_int64 = (int64_t*) SPEX_malloc (Anz* sizeof (int64_t)) ; + int64_t *Ax_int64 = (int64_t*) SPEX_malloc (Anz* sizeof (int64_t)); if (!Ax_int64) { - spex_left_lu_mex_error (SPEX_OUT_OF_MEMORY, "") ; + spex_mex_error (SPEX_OUT_OF_MEMORY, ""); } for (k = 0; k < Anz; k++) { @@ -105,36 +107,36 @@ void spex_left_lu_mex_get_A_and_b A_matlab->i = Ai ; // scale A and convert to MPZ - SPEX_MEX_OK (SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, A_matlab, option)) ; + SPEX_MEX_OK (SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, A_matlab, option)); // free the shallow copy of A - SPEX_MEX_OK (SPEX_matrix_free (&A_matlab, option)) ; + SPEX_MEX_OK (SPEX_matrix_free (&A_matlab, option)); //-------------------------------------------------------------------------- // Read in b //-------------------------------------------------------------------------- - SPEX_matrix* b = NULL; - SPEX_matrix* b_matlab = NULL; + SPEX_matrix b = NULL; + SPEX_matrix b_matlab = NULL; - bx = mxGetDoubles (pargin[1]) ; + bx = mxGetDoubles (pargin[1]); if (!bx) { - spex_left_lu_mex_error (SPEX_INCORRECT_INPUT, "") ; + spex_mex_error (SPEX_INCORRECT_INPUT, ""); } // Get info about RHS vector (s) - nb = mxGetN (pargin[1]) ; - mb = mxGetM (pargin[1]) ; + nb = mxGetN (pargin[1]); + mb = mxGetM (pargin[1]); if (mb != mA) { - spex_left_lu_mex_error (1, "dimension mismatch") ; + spex_mex_error (1, "dimension mismatch"); } int64_t count = 0; // check the values of b - bool b_has_int64_values = spex_left_lu_mex_check_for_inf (bx, nb*mb) ; + bool b_has_int64_values = spex_mex_check_for_inf (bx, nb*mb); if (b_has_int64_values) { @@ -162,10 +164,10 @@ void spex_left_lu_mex_get_A_and_b } // scale b and convert to MPZ - SPEX_MEX_OK (SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, b_matlab, option)) ; + SPEX_MEX_OK (SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, b_matlab, option)); // free the shallow copy of b - SPEX_MEX_OK (SPEX_matrix_free (&b_matlab, option)) ; + SPEX_MEX_OK (SPEX_matrix_free (&b_matlab, option)); (*A_handle) = A; (*b_handle) = b; diff --git a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_get_matlab_options.c b/SPEX/MATLAB/Source/spex_mex_get_matlab_options.c similarity index 77% rename from SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_get_matlab_options.c rename to SPEX/MATLAB/Source/spex_mex_get_matlab_options.c index f7879dc5cf..624b1f8710 100644 --- a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_get_matlab_options.c +++ b/SPEX/MATLAB/Source/spex_mex_get_matlab_options.c @@ -1,23 +1,28 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/MATLAB/spex_get_matlab_options: Set factorization options +// SPEX/MATLAB/SPEX_mex_get_matlab_optons.c: Get command options from user //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -#include "SPEX_Left_LU_mex.h" +/* Purpose: This function reads in the necessary information from the options + * struct for MATLAB. + */ -// Purpose: This function reads in the necessary information from the options -// struct for MATLAB. + +#include "SPEX_mex.h" #define MATCH(s,t) (strcmp (s,t) == 0) +#define SPEX_MIN(a,b) ( a < b ? a : b) +#define SPEX_MAX(a,b) (a > b ? a : b) -void spex_left_lu_get_matlab_options +void spex_mex_get_matlab_options ( - SPEX_options* option, // Control parameters + SPEX_options option, // Control parameters spex_mex_options *mexoptions, // MATLAB-specific options const mxArray* input // options struct, may be NULL ) @@ -31,8 +36,8 @@ void spex_left_lu_get_matlab_options #define LEN 256 char string [LEN+1] ; - // true if input options struct is present - bool present = (input != NULL) && !mxIsEmpty (input) && mxIsStruct (input) ; + // true if input options struct is present + bool present = (input != NULL) && !mxIsEmpty (input) && mxIsStruct (input); //-------------------------------------------------------------------------- // Get the column ordering @@ -42,8 +47,11 @@ void spex_left_lu_get_matlab_options field = present ? mxGetField (input, 0, "order") : NULL ; if (field != NULL) { - if (!mxIsChar (field)) spex_left_lu_mex_error (1, "option.order must be a string") ; - mxGetString (field, string, LEN) ; + if (!mxIsChar (field)) + { + spex_mex_error (1, "option.order must be a string"); + } + mxGetString (field, string, LEN); if (MATCH (string, "none")) { option->order = SPEX_NO_ORDERING ; // None: A is factorized as-is @@ -58,7 +66,7 @@ void spex_left_lu_get_matlab_options } else { - spex_left_lu_mex_error (1, "unknown option.order") ; + spex_mex_error (1, "unknown option.order"); } } @@ -70,8 +78,11 @@ void spex_left_lu_get_matlab_options field = present ? mxGetField (input, 0, "pivot") : NULL ; if (field != NULL) { - if (!mxIsChar (field)) spex_left_lu_mex_error (1, "option.pivot must be a string") ; - mxGetString (field, string, LEN) ; + if (!mxIsChar (field)) + { + spex_mex_error (1, "option.pivot must be a string"); + } + mxGetString (field, string, LEN); if (MATCH (string, "smallest")) { option->pivot = SPEX_SMALLEST ; // Smallest pivot @@ -100,7 +111,7 @@ void spex_left_lu_get_matlab_options } else { - spex_left_lu_mex_error (1, "unknown option.pivot") ; + spex_mex_error (1, "unknown option.pivot"); } } @@ -114,11 +125,11 @@ void spex_left_lu_get_matlab_options field = present ? mxGetField (input, 0, "tol") : NULL ; if (field != NULL) { - option->tol = mxGetScalar (field) ; + option->tol = mxGetScalar (field); if (option->tol > 1 || option->tol <= 0) { - spex_left_lu_mex_error (1, "invalid option.tol, " - "must be > 0 and <= 1") ; + spex_mex_error (1, "invalid option.tol, " + "must be > 0 and <= 1"); } } } @@ -131,7 +142,7 @@ void spex_left_lu_get_matlab_options field = present ? mxGetField (input, 0, "solution") : NULL ; if (field != NULL) { - mxGetString (field, string, LEN) ; + mxGetString (field, string, LEN); if (MATCH (string, "vpa")) { mexoptions->solution = SPEX_SOLUTION_VPA ; // return x as vpa @@ -146,7 +157,7 @@ void spex_left_lu_get_matlab_options } else { - spex_left_lu_mex_error (1, "unknown option.solution") ; + spex_mex_error (1, "unknown option.solution"); } } @@ -158,12 +169,12 @@ void spex_left_lu_get_matlab_options field = present ? mxGetField (input, 0, "digits") : NULL ; if (field != NULL) { - double d = mxGetScalar (field) ; + double d = mxGetScalar (field); if (d != trunc (d) || d < 2 || d > (1 << 29)) { // the MATLAB vpa requires digits between 2 and 2^29 - spex_left_lu_mex_error (1, "options.digits must be an integer " - "between 2 and 2^29") ; + spex_mex_error (1, "options.digits must be an integer " + "between 2 and 2^29"); } mexoptions->digits = (int32_t) d ; } @@ -177,9 +188,9 @@ void spex_left_lu_get_matlab_options if (field != NULL) { // silently convert to an integer 0, 1, 2, or 3 - option->print_level = (int) mxGetScalar (field) ; - option->print_level = SPEX_MIN (option->print_level, 3) ; - option->print_level = SPEX_MAX (option->print_level, 0) ; + option->print_level = (int) mxGetScalar (field); + option->print_level = SPEX_MIN (option->print_level, 3); + option->print_level = SPEX_MAX (option->print_level, 0); } } diff --git a/SPEX/MATLAB/spex_backslash.m b/SPEX/MATLAB/spex_backslash.m new file mode 100644 index 0000000000..73b30bdac5 --- /dev/null +++ b/SPEX/MATLAB/spex_backslash.m @@ -0,0 +1,132 @@ +function x = spex_backslash(A, b, option) +% SPEX_BACKSLASH: solve Ax=b via sparse integer-preserving factorization. +% spex_backslash: computes the exact solution to the sparse linear system Ax = b +% where A and b are stored as doubles. A must be stored as a sparse matrix. b +% must be stored as a set of dense right hand side vectors (b can be either 1 +% or multiple vector(s)). SPEX compues the result, x, exactly in +% arbitrary-precision rational numbers. The solution x can be returned in the +% following types: +% (a) [floating-poing double] - This final rational-to-double conversion means that x may no +% longer exactly solve Ax = b. +% (b) [vpa matrix] - This is the arbitrary precision type in MATLAB. +% (c) [cell array of strings] - x{i} = 'numerator/denominator', where the numerator +% and denominator are strings of decimal digits of arbitrary length. +% +% If A is SPD, an exact up-looking Cholesky factorization is applied. Otherwise, +% an exact left-looking LU factorization is applied. +% +% Usage: +% +% x = spex_backslash(A, b) returns the solution to Ax = b using default settings. +% +% x = spex_backslash(A, b, options) returns the solution to Ax = b with user +% defined settings in an options struct. Entries not present are treated as +% defaults. +% +% option.print: display the inputs and outputs +% 0: nothing (default), 1: just errors, 2: terse, 3: all +% +% option.solution: a string determining how x is to be returned: +% 'double': x is converted to a 64-bit floating-point approximate +% solution. This is the default. +% 'vpa': x is returned as a vpa array with option.digits digits (default +% is given by the MATLAB digits function). The result may be +% inexact, if an entry in x cannot be exactly represented in the +% specified number of digits. Note: the conversion from the SPEX +% exact solution (stored as a rational vector) to an arbitrary +% precision vpa number is very slow (it can be much slower than +% exactly solving the system Ax = b). +% 'char': x is returned as a cell array of strings, where +% x {i} = 'numerator/denominator' and both numerator and denominator +% are arbitrary-length strings of decimal digits. The result is +% always exact, although x cannot be directly used in MATLAB for +% numerical calculations. It can be inspected or analyzed using +% MATLAB string manipulation. Within MATLAB, x may be conversted to +% vpa, (x=vpa(x)), and then to double (x=double(vpa(x))). +% +% option.digits: the number of decimal digits to use for x, if +% option.solution is 'vpa'. Must be in range 2 to 2^29. +% +% Example: +% +% % In this first example, x = spex_backslash(A, b) returns an approximate +% % solution. Note that, since SPEX computes the solution exactly, the +% % only source of round-of-errors is the final rationa-to-double conversion. +% +% load west0479 +% A = west0479 ; +% n = size (A, 1) ; +% xtrue = rand (n,1) ; +% b = A*xtrue ; +% x = spex_backslash (A, b) ; +% err = norm (x-xtrue) +% x = A\b ; +% err = norm (x-xtrue) +% +% % In this example, x = spex_backslash(A,b) is returned exactly in the +% % MATLAB vector x, because x contains only integers representable exactly +% % in double precision. +% % In contrast using x = A\b results in floating-point roundoff error. +% +% amax = max (abs (A), [ ], 'all') ; +% A = floor (2^20 * (A / amax)) + n * speye (n) ; +% xtrue = floor (64 * xtrue) ; +% b = A*xtrue ; +% x = spex_backslash (A, b) ; +% % error and residual will be exactly zero: +% err = norm (x-xtrue) +% resid = norm (A*x-b) +% x = A\b ; +% % error and residual will be nonzero: +% err = norm (x-xtrue) +% resid = norm (A*x-b) +% +% See also vpa, spex_mex_install, spex_mex_test, spex_mex_demo. + +% spex_backslash is a wrapper for the exact routines contained within the SPEX +% software package. In order to use spex_backslash you must install the MATLAB +% interfaces of all SPEX packages. Typing spex_mex_install in this directory +% should do this correctly. + +% SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +% Lorena Mejia Domenzain, Timothy A. Davis and Erick Moreno-Centeno. +% All Rights Reserved. +% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +if (nargin < 3) + option = [ ]; % use default options +end + +if (~isnumeric(A) || ~isnumeric(b)) + error ('inputs must be numeric'); +end + +% SPEX Backslash expects sparse input. +% So, if A is not sprase it is sprasified. +if (~issparse(A)) + A = sparse(A); +end + +% Preprocessing complete. Now use SPEX Backslash to solve Ax = b. +x = spex_backslash_mex_soln(A, b, option); + +% At this point, depending on the user options, x is either +% (a) a 64-bit floating-point (i.e., double) approximate solution +% (in this case the only source of roundoff errors was the final +% conversion from a rational number to a double), or +% (b) a cell array of strings, where x {i} = 'numerator/denominator' +% and both numerator and denominator are arbitrary-length strings of decimal digits. + +% if requested, convert to vpa. +% if provided, use the requested number of digits (otherwise use +% the default in MATLAB). +if (isfield(option, 'solution') && isequal(option.solution, 'vpa')) + if (isfield(option, 'digits')) + x = vpa(x, option.digits); + else + % use the current default # of digits for vpa. The default is 32, + % but this can be changed as a global setting, by the MATLAB 'digits' + % command. + x = vpa(x); + end +end diff --git a/SPEX/MATLAB/spex_backslash_mex_soln.c b/SPEX/MATLAB/spex_backslash_mex_soln.c new file mode 100644 index 0000000000..a6b84e3a5a --- /dev/null +++ b/SPEX/MATLAB/spex_backslash_mex_soln.c @@ -0,0 +1,181 @@ +//------------------------------------------------------------------------------ +// SPEX/MATLAB/spex_backslash_mex_soln: Use SPEX Backslash within MATLAB +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: The .c file defining the SPEX Backslash MATLAB interface + * This function defines: x = spex_backslash_mex_soln(A, b, option) + */ + + +#include "SPEX_mex.h" + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + //-------------------------------------------------------------------------- + // Initialize SPEX Backslash library environment + //-------------------------------------------------------------------------- + + SPEX_info status; + SPEX_MEX_OK(SPEX_initialize_expert(mxMalloc, mxCalloc, mxRealloc, mxFree)); + + SuiteSparse_config_printf_func_set (mexPrintf); + + //-------------------------------------------------------------------------- + // Check that there is the correct number of input arguments + //-------------------------------------------------------------------------- + + if (nargout > 1 || nargin < 2 || nargin > 3) + { + spex_mex_error (1, "Usage: x = SPEX_backslash_soln (A,b,option)"); + } + + //-------------------------------------------------------------------------- + // check inputs for for reals and sparsity + //-------------------------------------------------------------------------- + + if (mxIsComplex(pargin [0]) || mxIsComplex(pargin [1])) + { + spex_mex_error(1, "inputs must be real"); + } + /***/ + if (!mxIsSparse(pargin [0])) // Is the matrix sparse? + { + spex_mex_error(1, "first input must be sparse"); + } + /**/ + if (mxIsSparse(pargin [1])) // Is b sparse? + { + spex_mex_error(1, "second input must be dense"); + } + + //-------------------------------------------------------------------------- + // get the input options + //-------------------------------------------------------------------------- + + SPEX_options option = NULL; + SPEX_create_default_options(&option); + if (option == NULL) + { + spex_mex_error (SPEX_OUT_OF_MEMORY, ""); + } + + spex_mex_options mexoptions; + if (nargin > 2) + { + spex_mex_get_matlab_options (option, &mexoptions, pargin [2]); + } + + //-------------------------------------------------------------------------- + // get A and b + //-------------------------------------------------------------------------- + + SPEX_matrix A = NULL ; + SPEX_matrix b = NULL ; + spex_mex_get_A_and_b (&A, &b, pargin, option); + + // Print the matrices if user specified a print level + if (option->print_level > 0) + { + printf ("\nScaled integer input matrix A:\n"); + SPEX_matrix_check (A, option); + } + + if (option->print_level > 0) + { + printf ("\nScaled integer right-hand-side b:\n"); + SPEX_matrix_check (b, option); + } + + //-------------------------------------------------------------------------- + // x = A\b via SPEX_backslash, returning result as SPEX_MPQ + //-------------------------------------------------------------------------- + + SPEX_matrix x = NULL ; + SPEX_MEX_OK(SPEX_backslash(&x, SPEX_MPQ, A, b, option)); + + //-------------------------------------------------------------------------- + // print the result, if requested + //-------------------------------------------------------------------------- + + if (option->print_level > 0) + { + printf ("\nSolution x:\n"); + SPEX_matrix_check(x, option); + } + + //-------------------------------------------------------------------------- + // return x to MATLAB + //-------------------------------------------------------------------------- + + if (mexoptions.solution == SPEX_SOLUTION_DOUBLE) + { + + //---------------------------------------------------------------------- + // return x as a double MATLAB matrix + //---------------------------------------------------------------------- + + // convert x to double + SPEX_matrix t = NULL; + SPEX_MEX_OK(SPEX_matrix_copy (&t, SPEX_DENSE, SPEX_FP64, x, option)); + SPEX_matrix_free(&x, NULL); + x = t; + t = NULL; + + // create an empty 0-by-0 MATLAB matrix and free its contents + pargout[0] = mxCreateDoubleMatrix(0, 0, mxREAL); + mxFree(mxGetDoubles(pargout[0])); + + // transplant x into the new MATLAB matrix and set its size + mxSetDoubles(pargout[0], x->x.fp64); + mxSetM(pargout[0], x->m); + mxSetN(pargout[0], x->n); + x->x.fp64 = NULL; // set to NULL so it is not freed by SPEX_matrix_free + } + else + { + + //---------------------------------------------------------------------- + // return x as a cell array of strings + //---------------------------------------------------------------------- + + pargout[0] = mxCreateCellMatrix(x->m, x->n); + int64_t mn = (x->m) * (x->n); + for (int64_t p = 0; p < mn; p++) + { + // convert x (i,j) into a C string + char *s; + status = SPEX_mpfr_asprintf(&s, "%Qd", x->x.mpq [p]); + if (status < 0) + { + spex_mex_error(1, "error converting x to string"); + } + // convert the string into a MATLAB string and store in x {i,j} + mxSetCell(pargout[0], p, mxCreateString(s)); + // free the C string + SPEX_mpfr_free_str(s); + } + } + + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- + + SPEX_matrix_free(&x, option); + SPEX_matrix_free(&b, option); + SPEX_matrix_free(&A, option); + SPEX_FREE(option); + SPEX_finalize( ); +} diff --git a/SPEX/MATLAB/spex_cholesky_backslash.m b/SPEX/MATLAB/spex_cholesky_backslash.m new file mode 100644 index 0000000000..791af8aed2 --- /dev/null +++ b/SPEX/MATLAB/spex_cholesky_backslash.m @@ -0,0 +1,133 @@ +function x = spex_cholesky_backslash (A,b,option) +% spex_cholesky_BACKSLASH: solve Ax=b via sparse integer-preserving Cholesky +% spex_cholesky_backslash: computes the exact solution to the sparse linear system Ax = +% b where A and b are stored as doubles. A must be stored as a sparse matrix and be SPD. b +% must be stored as a dense set of right hand side vectors. b can be either 1 +% or multiple vector(s). The result x is computed exactly, represented in +% arbitrary-precision rational values, and then returned to MATLAB as a +% floating-poing double result. This final conversion means that x may no +% longer exactly solve A*x=b, unless this final conversion is able to be +% done without modification. +% +% x may also be returned as a vpa matrix, or a cell array of strings, with +% x {i} = 'numerator/denominator', where the numerator and denominator are +% strings of decimal digits of arbitrary length. +% +% Usage: +% +% x = spex_cholesky_backslash (A,b) returns the solution to Ax=b using default settings. +% +% x = spex_cholesky_backslash (A,b,options) returns the solution to Ax=b with user +% defined settings in an options struct. Entries not present are treated as +% defaults. +% +% option.order: Column ordering used. +% 'none': no column ordering; factorize the matrix A as-is +% 'colamd': COLAMD (the default ordering) +% 'amd': AMD +% +% option.print: display the inputs and outputs +% 0: nothing (default), 1: just errors, 2: terse, 3: all +% +% option.solution: a string determining how x is to be returned: +% 'double': x is converted to a 64-bit floating-point approximate +% solution. This is the default. +% 'vpa': x is returned as a vpa array with option.digits digits (default +% is given by the MATLAB digits function). The result may be +% inexact, if an entry in x cannot be represented in the specified +% number of digits. To convert this x to double, use x=double(x). +% 'char': x is returned as a cell array of strings, where +% x {i} = 'numerator/denominator' and both numerator and denominator +% are arbitrary-length strings of decimal digits. The result is +% always exact, although x cannot be directly used in MATLAB for +% numerical calculations. It can be inspected or analyzed using +% MATLAB string manipulation. To convert x to vpa, use x=vpa(x). To +% convert x to double, use x=double(vpa(x)). +% +% option.digits: the number of decimal digits to use for x, if +% option.solution is 'vpa'. Must be in range 2 to 2^29. +% +% Example: +% +% % In this first example, x = spex_cholesky_backslash (A,b) returns an approximate +% % solution, not because it was computed incorrectly in spex_cholesky_backslash. It +% % is computed exactly as a rational result in SPEX_backslash with arbitrary +% % precision, but then converted to double precision on output. +% +% load west0479 +% A = west0479 ; +% A = A'*A; +% n = size (A, 1) ; +% xtrue = rand (n,1) ; +% b = A*xtrue ; +% x = spex_cholesky_backslash (A, b) ; +% err = norm (x-xtrue) +% x = A\b ; +% err = norm (x-xtrue) +% +% % In this example, x = spex_cholesky_backslash (A,b) is returned exactly +% % in the MATLAB vector x, because x contains only integers representable +% % exactly in double precision. x = A\b results in floating-point +% % roundoff error. +% +% amax = max (abs (A), [ ], 'all') ; +% A = floor (2^20 * (A / amax)) + n * speye (n) ; +% xtrue = floor (64 * xtrue) ; +% b = A*xtrue ; +% x = SPEX_backslash (A, b) ; +% % error and residual will be exactly zero: +% err = norm (x-xtrue) +% resid = norm (A*x-b) +% x = A\b ; +% % error and residual will be nonzero: +% err = norm (x-xtrue) +% resid = norm (A*x-b) +% +% See also vpa, spex_mex_install, spex_mex_test, spex_mex_demo, +% spex_lu_backslash + +% spex_cholesky_backslash is a wrapper for the exact routines contained within the SPEX +% software package. In order to use spex_cholesky_backslash you must install the MATLAB +% interfaces of all SPEX packages. Typing spex_mex_install in this directory +% should do this correctly. + +% SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +% Lorena Mejia Domenzain, Timothy A. Davis and Erick Moreno-Centeno. +% All Rights Reserved. +% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +if (nargin < 3) + option = [ ]; % use default options +end + +if (~isnumeric (A) || ~isnumeric (b)) + error ('inputs must be numeric') ; +end + +% Check if the input matrix is stored as sparse. If not, SPEX Chol expects +% sparse input, so convert to sparse. +if (~issparse (A)) + A = sparse (A) ; +end + +% Ensure that input appears to be symmetric. +if ( normest(A-A') > 1e-6) + error('inputs must be symmetric') +end + + +% Preprocessing complete. Now use SPEX Chol to solve A*x=b. +x=spex_cholesky_mex_soln (A, b, option) ; + +% convert to vpa, if requested +if (isfield (option, 'solution') && isequal (option.solution, 'vpa')) + if (isfield (option, 'digits')) + x = vpa (x, option.digits) ; + else + % use the current default # of digits for vpa. The default is 32, + % but this can be changed as a global setting, by the MATLAB 'digits' + % command. + x = vpa (x) ; + end +end + diff --git a/SPEX/MATLAB/spex_cholesky_mex_soln.c b/SPEX/MATLAB/spex_cholesky_mex_soln.c new file mode 100644 index 0000000000..7684c0e20f --- /dev/null +++ b/SPEX/MATLAB/spex_cholesky_mex_soln.c @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +// SPEX/MATLAB/spex_cholesky_mex_soln: Use SPEX Chol within MATLAB +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: The .c file defining the SPEX Chol MATLAB interfacee + * This function defines: x = spex_cholesky_mex_soln (A, b, option) + */ + + +#include "SPEX_mex.h" + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + //-------------------------------------------------------------------------- + // Initialize SPEX Chol library environment + //-------------------------------------------------------------------------- + + SPEX_info status ; + SPEX_MEX_OK (SPEX_initialize_expert + (mxMalloc, mxCalloc, mxRealloc, mxFree)); + + SuiteSparse_config_printf_func_set (mexPrintf); + + //-------------------------------------------------------------------------- + // Check inputs + //-------------------------------------------------------------------------- + + if (nargout > 1 || nargin < 2 || nargin > 3) + { + spex_mex_error (1, "Usage: x = SPEX_chol_soln (A,b,option)"); + } + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) + { + spex_mex_error (1, "inputs must be real"); + } + /***/ + if (!mxIsSparse (pargin [0])) // Is the matrix sparse? + { + spex_mex_error (1, "first input must be sparse"); + } + /**/ + if (mxIsSparse (pargin [1])) // Is b sparse? + { + spex_mex_error (1, "second input must be full"); + } + + //-------------------------------------------------------------------------- + // get the input options + //-------------------------------------------------------------------------- + + SPEX_options option = NULL; + SPEX_create_default_options(&option); + if (option == NULL) + { + spex_mex_error (SPEX_OUT_OF_MEMORY, ""); + } + + spex_mex_options mexoptions ; + if (nargin > 2) spex_mex_get_matlab_options (option, &mexoptions, pargin [2]); + + //-------------------------------------------------------------------------- + // get A and b + //-------------------------------------------------------------------------- + + SPEX_matrix A = NULL ; + SPEX_matrix b = NULL ; + spex_mex_get_A_and_b (&A, &b, pargin, option); +/**/ + if (option->print_level > 0) + { + printf ("\nScaled integer input matrix A:\n"); + SPEX_matrix_check (A, option); + } + + if (option->print_level > 0) + { + printf ("\nScaled integer right-hand-side b:\n"); + SPEX_matrix_check (b, option); + } + + //-------------------------------------------------------------------------- + // x = A\b via SPEX_Chol, returning result as SPEX_MPQ + //-------------------------------------------------------------------------- + + SPEX_matrix x = NULL ; + SPEX_MEX_OK (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option)); + + //-------------------------------------------------------------------------- + // print the result, if requested + //-------------------------------------------------------------------------- + + if (option->print_level > 0) + { + printf ("\nSolution x:\n"); + SPEX_matrix_check (x, option); + } + + //-------------------------------------------------------------------------- + // return x to MATLAB + //-------------------------------------------------------------------------- + + if (mexoptions.solution == SPEX_SOLUTION_DOUBLE) + { + + //---------------------------------------------------------------------- + // return x as a double MATLAB matrix + //---------------------------------------------------------------------- + + // convert x to double + SPEX_matrix t = NULL ; + SPEX_MEX_OK (SPEX_matrix_copy (&t, SPEX_DENSE, SPEX_FP64, x, option)); + SPEX_matrix_free (&x, NULL); + x = t ; + t = NULL ; + + // create an empty 0-by-0 MATLAB matrix and free its contents + pargout [0] = mxCreateDoubleMatrix (0, 0, mxREAL); + mxFree (mxGetDoubles (pargout [0])); + + // transplant x into the new MATLAB matrix and set its size + mxSetDoubles (pargout [0], x->x.fp64); + mxSetM (pargout [0], x->m); + mxSetN (pargout [0], x->n); + x->x.fp64 = NULL ; // set to NULL so it is not freed by SPEX_matrix_free + + } + else + { + + //---------------------------------------------------------------------- + // return x as a cell array of strings + //---------------------------------------------------------------------- + + pargout [0] = mxCreateCellMatrix (x->m, x->n); + int64_t mn = (x->m) * (x->n); + for (int64_t p = 0 ; p < mn ; p++) + { + // convert x (i,j) into a C string + char *s ; + status = SPEX_mpfr_asprintf (&s, "%Qd", x->x.mpq [p]); + if (status < 0) + { + spex_mex_error (1, "error converting x to string"); + } + // convert the string into a MATLAB string and store in x {i,j} + mxSetCell (pargout [0], p, mxCreateString (s)); + // free the C string + SPEX_mpfr_free_str (s); + } + } + + //-------------------------------------------------------------------------- + // free workspace + //-------------------------------------------------------------------------- + + SPEX_matrix_free (&x, option); + SPEX_matrix_free (&b, option); + SPEX_matrix_free (&A, option); + SPEX_FREE (option); + SPEX_finalize ( ); + /**/ + +} + diff --git a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_backslash.m b/SPEX/MATLAB/spex_lu_backslash.m similarity index 87% rename from SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_backslash.m rename to SPEX/MATLAB/spex_lu_backslash.m index dee21aa4f3..15f45be0b4 100644 --- a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_backslash.m +++ b/SPEX/MATLAB/spex_lu_backslash.m @@ -1,6 +1,6 @@ -function x = SPEX_Left_LU_backslash (A,b,option) -% SPEX_Left_LU_BACKSLASH: solve Ax=b via sparse left-looking integer-preserving LU -% SPEX_Left_LU_backslash: computes the exact solution to the sparse linear system Ax = +function x = SPEX_lu_backslash (A,b,option) +% SPEX_LU_BACKSLASH: solve Ax=b via sparse left-looking integer-preserving LU +% spex_lu_backslash: computes the exact solution to the sparse linear system Ax = % b where A and b are stored as doubles. A must be stored as a sparse matrix. b % must be stored as a dense set of right hand side vectors. b can be either 1 % or multiple vector(s). The result x is computed exactly, represented in @@ -15,9 +15,9 @@ % % Usage: % -% x = SPEX_Left_LU_backslash (A,b) returns the solution to Ax=b using default settings. +% x = spex_lu_backslash (A,b) returns the solution to Ax=b using default settings. % -% x = SPEX_Left_LU_backslash (A,b,options) returns the solution to Ax=b with user +% x = spex_lu_backslash (A,b,options) returns the solution to Ax=b with user % defined settings in an options struct. Entries not present are treated as % defaults. % @@ -70,7 +70,7 @@ % n = size (A, 1) ; % xtrue = rand (n,1) ; % b = A*xtrue ; -% x = SPEX_Left_LU_backslash (A, b) ; +% x = spex_lu_backslash (A, b) ; % err = norm (x-xtrue) % x = A\b ; % err = norm (x-xtrue) @@ -94,9 +94,11 @@ % % See also vpa, SPEX_install, SPEX_test, SPEX_demo. -% SPEX_Left_LU_LU: (c) 2019-2020, Chris Lourenco, Jinhao Chen, Erick Moreno-Centeno, -% Timothy A. Davis, Texas A&M University. All Rights Reserved. See -% SPEX_Left_LU/License for the license. +% SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +% Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +% All Rights Reserved. +% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + if (nargin < 3) option = [ ] ; % use default options @@ -113,7 +115,7 @@ end % Preprocessing complete. Now use SPEX Left LU to solve A*x=b. -x = SPEX_Left_LU_mex_soln (A, b, option) ; +x = spex_lu_mex_soln (A, b, option) ; % convert to vpa, if requested if (isfield (option, 'solution') && isequal (option.solution, 'vpa')) diff --git a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_mex_soln.c b/SPEX/MATLAB/spex_lu_mex_soln.c similarity index 65% rename from SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_mex_soln.c rename to SPEX/MATLAB/spex_lu_mex_soln.c index 7df9d9c15b..151d55f87d 100644 --- a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_mex_soln.c +++ b/SPEX/MATLAB/spex_lu_mex_soln.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU_/MATLAB/SPEX_Left_LU_mex_soln: Use SPEX Left LU within MATLAB +// SPEX/MATLAB/spex_lu_mex_soln: Use SPEX Left LU within MATLAB //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -12,7 +13,7 @@ * This function defines: x = SPEX_mex_soln (A, b, option) */ -#include "SPEX_Left_LU_mex.h" +#include "SPEX_mex.h" void mexFunction ( @@ -27,12 +28,10 @@ void mexFunction //-------------------------------------------------------------------------- SPEX_info status ; - if (!spex_initialized ( )) - { - SPEX_MEX_OK (SPEX_initialize_expert - (mxMalloc, mxCalloc, mxRealloc, mxFree)) ; - } - SuiteSparse_config_printf_func_set ((void *) mexPrintf) ; + SPEX_MEX_OK (SPEX_initialize_expert + (mxMalloc, mxCalloc, mxRealloc, mxFree)); + + SuiteSparse_config_printf_func_set (mexPrintf); //-------------------------------------------------------------------------- // Check inputs @@ -40,7 +39,7 @@ void mexFunction if (nargout > 1 || nargin < 2 || nargin > 3) { - spex_left_lu_mex_error (1, "Usage: x = SPEX_mex_soln (A,b,option)") ; + spex_mex_error (1, "Usage: x = SPEX_mex_soln (A,b,option)"); } //-------------------------------------------------------------------------- @@ -49,53 +48,53 @@ void mexFunction if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { - spex_left_lu_mex_error (1, "inputs must be real") ; + spex_mex_error (1, "inputs must be real"); } if (!mxIsSparse (pargin [0])) // Is the matrix sparse? { - spex_left_lu_mex_error (1, "first input must be sparse") ; + spex_mex_error (1, "first input must be sparse"); } if (mxIsSparse (pargin [1])) // Is b sparse? { - spex_left_lu_mex_error (1, "second input must be full") ; + spex_mex_error (1, "second input must be full"); } //-------------------------------------------------------------------------- // get the input options //-------------------------------------------------------------------------- - SPEX_options *option = NULL; + SPEX_options option = NULL; SPEX_MEX_OK(SPEX_create_default_options(&option)); spex_mex_options mexoptions ; - if (nargin > 2) spex_left_lu_get_matlab_options (option, &mexoptions, pargin [2]) ; + if (nargin > 2) spex_mex_get_matlab_options (option, &mexoptions, pargin [2]); //-------------------------------------------------------------------------- // get A and b //-------------------------------------------------------------------------- - SPEX_matrix *A = NULL ; - SPEX_matrix *b = NULL ; - spex_left_lu_mex_get_A_and_b (&A, &b, pargin, option) ; + SPEX_matrix A = NULL ; + SPEX_matrix b = NULL ; + spex_mex_get_A_and_b (&A, &b, pargin, option); if (option->print_level > 0) { - printf ("\nScaled integer input matrix A:\n") ; - SPEX_matrix_check (A, option) ; + printf ("\nScaled integer input matrix A:\n"); + SPEX_matrix_check (A, option); } if (option->print_level > 0) { - printf ("\nScaled integer right-hand-side b:\n") ; - SPEX_matrix_check (b, option) ; + printf ("\nScaled integer right-hand-side b:\n"); + SPEX_matrix_check (b, option); } //-------------------------------------------------------------------------- - // x = A\b via SPEX_Left_LU, returning result as SPEX_MPQ + // x = A\b via SPEX_LU, returning result as SPEX_MPQ //-------------------------------------------------------------------------- - SPEX_matrix *x = NULL ; - SPEX_MEX_OK (SPEX_Left_LU_backslash (&x, SPEX_MPQ, A, b, option)) ; + SPEX_matrix x = NULL ; + SPEX_MEX_OK (SPEX_lu_backslash (&x, SPEX_MPQ, A, b, option)); //-------------------------------------------------------------------------- // print the result, if requested @@ -103,8 +102,8 @@ void mexFunction if (option->print_level > 0) { - printf ("\nSolution x:\n") ; - SPEX_matrix_check (x, option) ; + printf ("\nSolution x:\n"); + SPEX_matrix_check (x, option); } //-------------------------------------------------------------------------- @@ -119,20 +118,20 @@ void mexFunction //---------------------------------------------------------------------- // convert x to double - SPEX_matrix* t = NULL ; - SPEX_MEX_OK (SPEX_matrix_copy (&t, SPEX_DENSE, SPEX_FP64, x, option)) ; - SPEX_matrix_free (&x, NULL) ; + SPEX_matrix t = NULL ; + SPEX_MEX_OK (SPEX_matrix_copy (&t, SPEX_DENSE, SPEX_FP64, x, option)); + SPEX_matrix_free (&x, NULL); x = t ; t = NULL ; // create an empty 0-by-0 MATLAB matrix and free its contents - pargout [0] = mxCreateDoubleMatrix (0, 0, mxREAL) ; - mxFree (mxGetDoubles (pargout [0])) ; + pargout [0] = mxCreateDoubleMatrix (0, 0, mxREAL); + mxFree (mxGetDoubles (pargout [0])); // transplant x into the new MATLAB matrix and set its size - mxSetDoubles (pargout [0], x->x.fp64) ; - mxSetM (pargout [0], x->m) ; - mxSetN (pargout [0], x->n) ; + mxSetDoubles (pargout [0], x->x.fp64); + mxSetM (pargout [0], x->m); + mxSetN (pargout [0], x->n); x->x.fp64 = NULL ; // set to NULL so it is not freed by SPEX_matrix_free } @@ -143,21 +142,21 @@ void mexFunction // return x as a cell array of strings //---------------------------------------------------------------------- - pargout [0] = mxCreateCellMatrix (x->m, x->n) ; - int64_t mn = (x->m) * (x->n) ; + pargout [0] = mxCreateCellMatrix (x->m, x->n); + int64_t mn = (x->m) * (x->n); for (int64_t p = 0 ; p < mn ; p++) { // convert x (i,j) into a C string char *s ; - status = SPEX_mpfr_asprintf (&s, "%Qd", x->x.mpq [p]) ; + status = SPEX_mpfr_asprintf (&s, "%Qd", x->x.mpq [p]); if (status < 0) { - spex_left_lu_mex_error (1, "error converting x to string") ; + spex_mex_error (1, "error converting x to string"); } // convert the string into a MATLAB string and store in x {i,j} - mxSetCell (pargout [0], p, mxCreateString (s)) ; + mxSetCell (pargout [0], p, mxCreateString (s)); // free the C string - SPEX_mpfr_free_str (s) ; + SPEX_mpfr_free_str (s); } } @@ -165,10 +164,10 @@ void mexFunction // free workspace //-------------------------------------------------------------------------- - SPEX_matrix_free (&x, option) ; - SPEX_matrix_free (&b, option) ; - SPEX_matrix_free (&A, option) ; - SPEX_FREE (option) ; - SPEX_finalize ( ) ; + SPEX_matrix_free (&x, option); + SPEX_matrix_free (&b, option); + SPEX_matrix_free (&A, option); + SPEX_FREE (option); + SPEX_finalize ( ); } diff --git a/SPEX/MATLAB/spex_mex_demo.m b/SPEX/MATLAB/spex_mex_demo.m new file mode 100644 index 0000000000..bb393a5cab --- /dev/null +++ b/SPEX/MATLAB/spex_mex_demo.m @@ -0,0 +1,159 @@ +%% spex_mex_demo a demo of SPEX MATLAB interface +% SPEX is a package for solving sparse linear systems of equations +% with a roundoff-free integer-preserving method. The result is +% always exact, unless the matrix A is perfectly singular. +% +% See also vpa, spex_mex_install, spex_mex_test. + +% SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +% Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +% All Rights Reserved. +% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + + +format compact + +%% SPEX vs MATLAB backslash: first example +% In this first example, x = spex_backslash (A, b) ; returns an approximate +% solution, but not because it was computed incorrectly in spex_backslash. +% It is computed exactly as a rational result in spex_lu_backslash with +% arbitrary precision, but then converted to double precision on output. + +format long g +load west0479 +A = west0479 ; +n = size (A, 1) ; +xtrue = rand (n,1) ; +b = A*xtrue ; +x = spex_backslash (A, b) ; +% error is nonzero: x is computed exactly in rational arbitrary-precision, +% but then lost precision when returned to MATLAB: +err_spex = norm (x-xtrue) +x = A\b ; +% error is nonzero: MATLAB x=A\b experiences floating-point error +% throughout its computations: +err_matlab = norm (x-xtrue) + +%% SPEX backslash: exact, vs MATLAB backslash: approximate +% In this example, x = spex_backslash (A, b) ; is returned exactly in the +% MATLAB vector x, because x contains only integers representable exactly +% in double precision. x = A\b results in floating-point roundoff error. + +amax = max (abs (A), [ ], 'all') ; +A = floor (2^20 * (A / amax)) + n * speye (n) ; +xtrue = floor (64 * xtrue) ; +b = A*xtrue ; +x = spex_backslash (A, b) ; +% error will be exactly zero: +err_spex = norm (x-xtrue) +x = A\b ; +% error will be small but nonzero: +err_matlab = norm (x-xtrue) + +%% SPEX Backslash on singular problems +% The matrix 2008 is a rank deficient rectangular matrix +% If we compute A = A'*A we obtain this 9*9 integer matrix: +% +% 4 -1 -1 0 -1 0 0 -1 0 +% -1 4 0 -1 0 -1 0 -1 0 +% -1 0 4 -1 -1 0 -1 0 0 +% 0 -1 -1 4 0 -1 -1 0 0 +% -1 0 -1 0 4 -1 0 0 -1 +% 0 -1 0 -1 -1 4 0 0 -1 +% 0 0 -1 -1 0 0 4 -1 -1 +% -1 -1 0 0 0 0 -1 4 -1 +% 0 0 0 0 -1 -1 -1 -1 4 +% +% Since this is an integer matrix, SPEX can obtain it exactly. +% This matrix is ill-conditioned and singular, SPEX correctly determines +% that it is. However, MATLAB Cholesky factorization both +% succeeds and returns a useless answer. +% Note that to continue the demo, the backslash line is wrapped in a try catch +% the default behavior of SPEX is to return an error to MATLAB and exit + +fprintf("Testing singular matrix"); +prob = ssget(2008); A = prob.A; +B = full(A'*A); +b = ones(9,1); + +try x = spex_backslash (B, b) ; +catch fprintf("\nError, spex determines matrix is singular\n"); +end + +R = chol(B); +x_chol = R \ (R' \ b) + +R = vpa(chol(B)); +x_vpa = vpa ( R \ vpa( (R'\b))) + +%% SPEX on an ill-conditioned problem +% x = spex_backslash (A,b) is able to accurately solve problems that x=A\b cannot. +% Consider the following matrix in the MATLAB gallery: + +[U, b] = gallery ('wilk', 3) + +%% vpa can find a good but not perfect solution: +xvpa = vpa (U) \ b + +% but MATLAB's numerical x = U\b computes a poor solution: +xapprox = U \ b + +%% spex_backslash computes the exact answer +% It returns it to MATLAB as a double vector, obtaining the exact results + +xspex = spex_backslash (U, b) +err = xvpa - xspex +relerr = double (err (2:3) ./ xvpa (2:3)) + +%% spex_lu_backslash with exact results +% spex_lu_backslash can also return x as a cell array of strings, which +% preserves the exact rational result. The printing option is also +% enabled in this example. The floating-point matrices U and b are +% converted into a scaled integer matrix before solving U*x=b with +% SPEX Left LU. +% +% Note that, importantly, SPEX obtains an integer matrix by scaling the +% input. SPEX scales all input by 1e16. This is because consider the number +% U(1,2). The value U(1,2)=0.9 is a floating point number and cannot be +% represented exactly in IEEE floating-point. Specifically, the rational +% represenation of it is fl(0.9) = 45000000000000001 / 50000000000000000. +% +% SPEX assumes the user wants what they typed in. Scaling this matrix exactly +% gives the above rational. Conversely scaling with 16 digits of precision +% gives the exact fraction 9/10. +% +% If one wishes to obtain FULL floating-point precision and/or support +% for floating point values smaller than 1e-16 there are two options: +% +% 1) Within MATLAB the user scaes the matrix themselves. If SPEX is +% given an integer matrix it is preserved exactly +% +% 2) Within C convert the matrix to a SPEX_MPFR. MPFR numbers +% can exactly store doubles. The conversion from MPFR to integer +% is fully exact and all one would obtain the rational representation +% of the floating-point number itself. This can be done with 1 call +% to the SPEX matrix copy function. +% +% In any case, below is the exact solution with U(1,2) = 9/10 + +option.print = 3 ; % also print the details +option.solution = 'char' ; % return x as a cell array of strings + +%% + +xspex = spex_lu_backslash (U, b, option) + +%% Converting an exact rational result to vpa or double +% If spex_lu_backslash returns x as a cell array of strings, it cannot +% be immediately used in computations in MATLAB. It can be converted +% into a vpa or double matrix, as illustrated below. + +xspex_as_vpa = vpa (xspex) +xspex_as_double = double (vpa (xspex)) +xvpa_as_double = double (xvpa) + +%% Comparing the VPA and SPEX_BACKSLASH solutions in double +% Both vpa(U)\b and spex_backslash(U,b) compute the same result +% in the end, when their results are converted to double. +err = xvpa_as_double - xspex_as_double + diff --git a/SPEX/MATLAB/spex_mex_install.m b/SPEX/MATLAB/spex_mex_install.m new file mode 100644 index 0000000000..267e65cbe1 --- /dev/null +++ b/SPEX/MATLAB/spex_mex_install.m @@ -0,0 +1,128 @@ +function spex_mex_install(run_demo) +% spex_mex_INSTALL: install and test the MATLAB interface to SPEX MATLAB functions. +% +% Usage: spex_mex_install +% +% Required Libraries: GMP, MPFR, AMD, COLAMD, SPEX. If -lamd and -lcolamd are +% not available, install them with 'make install' first, in the top-level +% SuiteSparse folder. +% +% You may need to add the top-level lib folder (SPEX/lib, or SuiteSparse/lib +% if SPEX is inside SuiteSparse) to your LD_LIBRARY_PATH (DYLD_LIBRARY_PATH +% on the Mac). See instructions in the spex_deps.m file. + +% SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +% Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +% All Rights Reserved. +% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + + +if (nargin < 1) + run_demo = true ; +end + +fprintf ('Compiling the SPEX mexFunctions for use:\n') ; + +% Find all source files and add them to the src string +src = ''; +path = './Source/'; +files = dir('./Source/*.c'); +[m n] = size(files); +for k = 1:m + tmp = [' ', path, files(k).name]; + src = [src, tmp]; +end +path = '../SPEX_Utilities/Source/'; +files = dir('../SPEX_Utilities/Source/*.c'); +[m n] = size(files); +for k = 1:m + tmp = [' ', path, files(k).name]; + src = [src, tmp]; +end + +path = '../SPEX_LU/Source/'; +files = dir('../SPEX_LU/Source/*.c'); +[m n] = size(files); +for k = 1:m + tmp = [' ', path, files(k).name]; + src = [src, tmp]; +end + +path = '../SPEX_Cholesky/Source/'; +files = dir('../SPEX_Cholesky/Source/*.c'); +[m n] = size(files); +for k = 1:m + tmp = [' ', path, files(k).name]; + src = [src, tmp]; +end +path = '../SPEX_Backslash/Source/'; +files = dir('../SPEX_Backslash/Source/*.c'); +[m n] = size(files); +for k = 1:m + tmp = [' ', path, files(k).name]; + src = [src, tmp]; +end + +% Compiler flags +flags = 'CFLAGS=''-std=c99 -fPIC'' LDFLAGS=''-Wl,-rpath=''../../lib'''''; + +% External libraries: GMP, MPRF, AMD, and COLAMD +[suitesparse_libdir, suitesparse_incdir, gmp_lib, gmp_include, mpfr_lib, mpfr_include] = spex_deps ; + +% libraries: +if (isempty (suitesparse_libdir)) + suitesparse_libdir = ' ' ; +else + suitesparse_libdir = [' -L' suitesparse_libdir ' '] ; +end +libs = [suitesparse_libdir ' -lamd -lcolamd -lsuitesparseconfig ' gmp_lib ' ' mpfr_lib ' -lm'] ; + +% Path to headers +if (isempty (suitesparse_incdir)) + suitesparse_incdir = ' ' ; +else + suitesparse_incdir = ['-I' suitesparse_incdir ' '] ; +end +if (isempty (gmp_include)) + gmp_include = ' ' ; +else + gmp_include = [' -I' gmp_include ' '] ; +end +if (isempty (mpfr_include)) + mpfr_include = ' ' ; +else + mpfr_include = [' -I' mpfr_include ' '] ; +end + +includes = [ suitesparse_incdir ' -ISource/ -I../Include/ -I../../SuiteSparse_config -I../../COLAMD/Include -I../../AMD/Include -I../SPEX_Utilities/Source ' gmp_include mpfr_include ] ; + +% verbose = ' -v ' +verbose = '' ; + +% Generate the mex commands here +% having -R2018a here for function mxGetDoubles +m1 = ['mex ', verbose, ' -R2018a ', includes, ' spex_lu_mex_soln.c ' , src, ' ', flags, ' ', libs] ; +m2 = ['mex ', verbose, ' -R2018a ', includes, ' spex_cholesky_mex_soln.c ' , src, ' ', flags, ' ', libs]; +m3 = ['mex ', verbose, ' -R2018a ', includes, ' spex_backslash_mex_soln.c ' , src, ' ', flags, ' ', libs]; + +if (~isempty (verbose)) + fprintf ('%s\n', m1) ; +end + +% Now, we evaluate each one +eval (m1) ; +eval (m2) ; +eval (m3) ; + +if (run_demo) + % Test SPEX + spex_mex_test ; +end + +fprintf ('To use SPEX MATLAB Interface in future MATLAB sessions, add the following\n') ; +fprintf ('line to your startup.m file:\n') ; +fprintf (' addpath (''%s'') ;\n', pwd) ; +fprintf ('Type ''doc startup'' for more info on how to use startup.m\n') ; +fprintf ('To run a demo, type:\n') ; +fprintf (' echodemo spex_mex_demo ;\n') ; + diff --git a/SPEX/MATLAB/spex_mex_test.m b/SPEX/MATLAB/spex_mex_test.m new file mode 100644 index 0000000000..b10f041ba7 --- /dev/null +++ b/SPEX/MATLAB/spex_mex_test.m @@ -0,0 +1,224 @@ +function spex_mex_test +% spex_mex_test: run a set of tests for SPEX matlab interface +% +% Usage: spex_mex_test +% +% See also spex_mex_install, spex_mex_demo. + +% SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +% Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +% All Rights Reserved. +% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +maxerr = 0 ; +rng ('default') ; + +fprintf ('Testing SPEX Left LU: ') ; + +% First, check if we can use a real life sparse matrix via ssget +if (exist ('ssget') ~= 0) + fprintf ('. (please wait) ') ; + % 159 is a square SPD matrix + prob = ssget(159); + A = prob.A; + [m n] = size(A); + b = rand(m, 1); + fprintf ('.') ; + x = spex_lu_backslash(A,b); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + + % now convert to an integer problem (x will not be integer) + A = floor (2^20 * A) ; + b = floor (2^20 * b) ; + fprintf ('.') ; + x = spex_lu_backslash (A, b) ; + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + fprintf ('.') ; +end + +orderings = { 'none', 'colamd', 'amd' } ; +pivotings = { 'smallest', 'diagonal', 'first', ... + 'tol smallest', 'tol largest', 'largest' } ; + +for n = [1 10 100] + for density = [0.001 0.05 0.5] + + % construct a well-conditioned problem to solve + A = sprand(n,n,density); + A = A+A' + n * speye (n) ; + b = rand(n,1); + + for korder = 1:length (orderings) + for kpiv = 1:length (pivotings) + for tol = [0.1 0.5] + + clear option + option.order = orderings {korder} ; + option.pivot = pivotings {kpiv} ; + option.tol = tol ; + + fprintf ('.') ; + x = spex_lu_backslash(A,b, option); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + + % now convert to an integer problem (x will not be integer) + A = floor (2^20 * A) ; + b = floor (2^20 * b) ; + x = spex_lu_backslash(A,b, option); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + end + end + end + end +end + +fprintf ('\nmaxerr: %g\n', maxerr) ; + +if (maxerr < 1e-6) + fprintf('\nLeft LU installation successful\n') +else + error ('\nTesting failure! error too high please reinstall\n') +end + +fprintf ('Testing SPEX Cholesky: ') ; + +% First, check if we can use a real life sparse matrix via ssget +if (exist ('ssget') ~= 0) + fprintf ('. (please wait) ') ; + % 2 is a square SPD matrix + prob = ssget(2); + A = prob.A; + [m n] = size(A); + b = rand(m, 1); + fprintf ('.') ; + x = spex_cholesky_backslash(A,b); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + + % now convert to an integer problem (x will not be integer) + A = floor (2^20 * A) ; + b = floor (2^20 * b) ; + fprintf ('.') ; + x = spex_cholesky_backslash (A, b) ; + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + fprintf ('.') ; +end + +orderings = { 'none', 'colamd', 'amd' } ; +%pivotings = { 'smallest', 'diagonal', 'first', ... +% 'tol smallest', 'tol largest', 'largest' } ; + +for n = [1 10 100] + for density = [0.001 0.05 0.5] + + % construct a well-conditioned problem to solve + A = sprand(n,n,density); + A = A+A' + n * speye (n) ; + b = rand(n,1); + + for korder = 1:length (orderings) + %for kpiv = 1:length (pivotings) + % for tol = [0.1 0.5] + + clear option + option.order = orderings {korder} ; +% option.pivot = pivotings {kpiv} ; +% option.tol = tol ; + + fprintf ('.') ; + x = spex_cholesky_backslash(A,b, option); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + + % now convert to an integer problem (x will not be integer) + A = floor (2^20 * A) ; + b = floor (2^20 * b) ; + x = spex_cholesky_backslash(A,b, option); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + %end + %end + end + end +end + +fprintf ('\nmaxerr: %g\n', maxerr) ; + +if (maxerr < 1e-6) + fprintf('\nSPEX Cholesky installation successful\n') +else + error ('spex_cholesky_backslash:test', '\nTesting failure! error too high, please reinstall\n') +end + + +fprintf ('Testing SPEX Backslash: ') ; +for n = [1 10 100] + for density = [0.001 0.05 0.5] + + % construct a well-conditioned problem to solve + A = sprand(n,n,density); + A = A + n*speye(n); + A2 = A+A' + n * speye (n) ; + b = rand(n,1); + + for korder = 1:length (orderings) + %for kpiv = 1:length (pivotings) + % for tol = [0.1 0.5] + + clear option + option.order = orderings {korder} ; +% option.pivot = pivotings {kpiv} ; +% option.tol = tol ; + + fprintf ('.') ; + x = spex_cholesky_backslash(A2,b, option); + x2 = A2\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + + fprintf ('.') + x = spex_lu_backslash(A, b, option); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max( maxerr, err); + + % now convert to an integer problem (x will not be integer) + A2 = floor (2^20 * A2) ; + b = floor (2^20 * b) ; + x = spex_cholesky_backslash(A2,b, option); + x2 = A2\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + + % now convert to an integer problem (x will not be integer) + A = floor (2^20 * A) ; + x = spex_lu_backslash(A,b, option); + x2 = A\b; + err = norm(x-x2)/norm(x); + maxerr = max (maxerr, err) ; + %end + %end + end + end +end + +if (maxerr < 1e-6) + fprintf('\nSPEX Backslash installation successful\n') +else + error ('SPEX_backslash:test', '\nTesting failure! error too high. Please reinstall\n') +end + +fprintf("\nAll testing complete, ready to go!\n"); diff --git a/SPEX/Makefile b/SPEX/Makefile index 268f14acdd..cd662c172f 100644 --- a/SPEX/Makefile +++ b/SPEX/Makefile @@ -1,9 +1,10 @@ #------------------------------------------------------------------------------- -# SuiteSparse/SPEX/Makefile +# SuiteSparse/SPEX/Makefile: Makefile for SPEX #------------------------------------------------------------------------------- -# SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -# Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +# SPEX: (c) 2019-2024, Christopher Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. # SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later #------------------------------------------------------------------------------- @@ -51,14 +52,20 @@ debug: all: library -demos: library +demos: ( cd build && cmake $(CMAKE_OPTIONS) -DSUITESPARSE_DEMOS=1 .. && cmake --build . --config Release -j${JOBS} ) - ( cd SPEX_Left_LU/Demo && ../../build/example ) - ( cd SPEX_Left_LU/Demo && ../../build/example2 ) - ( cd SPEX_Left_LU/Demo && ../../build/spexlu_demo ) + ./build/spex_demo_lu_simple1 + ./build/spex_demo_lu_simple2 ExampleMats/10teams.mat.txt ExampleMats/10teams.rhs.txt + ./build/spex_demo_lu_extended f ExampleMats/10teams.mat.txt ExampleMats/10teams.rhs.txt + ./build/spex_demo_lu_doub f ExampleMats/10teams.mat.txt ExampleMats/10teams.rhs.txt + ./build/spex_demo_backslash f ExampleMats/10teams.mat.txt ExampleMats/10teams.rhs.txt + ./build/spex_demo_backslash f ExampleMats/Trefethen_500.mat.txt ExampleMats/Trefethen_500.rhs.txt + ./build/spex_demo_cholesky_simple f ExampleMats/494_bus.mat.txt ExampleMats/494_bus.rhs.txt + ./build/spex_demo_cholesky_extended f ExampleMats/494_bus.mat.txt ExampleMats/494_bus.rhs.txt + ./build/spex_demo_threaded f ExampleMats/10teams.mat.txt ExampleMats/10teams.rhs.txt cov: - ( cd SPEX_Left_LU/Tcov && $(MAKE) ) + ( cd Tcov && $(MAKE) ) # just compile after running cmake; do not run cmake again remake: @@ -78,7 +85,7 @@ uninstall: # remove all files not in the distribution clean: - $(RM) -rf build/* Config/*.tmp MATLAB/*.o MATLAB/*.mex* - ( cd SPEX_Left_LU/Tcov && $(MAKE) clean ) + ( cd Tcov && $(MAKE) clean ) purge: clean diff --git a/SPEX/Python/.gitignore b/SPEX/Python/.gitignore new file mode 100644 index 0000000000..e1254e5398 --- /dev/null +++ b/SPEX/Python/.gitignore @@ -0,0 +1,7 @@ +# Ignore these files: +*.o +*.so.* +*.so +*.dylib +*.a +*.obj diff --git a/SPEX/Python/SPEXpy/Options.py b/SPEX/Python/SPEXpy/Options.py new file mode 100644 index 0000000000..85a28f7541 --- /dev/null +++ b/SPEX/Python/SPEXpy/Options.py @@ -0,0 +1,47 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/utilities/Options.py: class Options +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +class Options: + def __init__(self, out="double", ordering=None): + self.ordering = ordering + self.output = out + + def default_lu(self): + self.ordering="colamd" + + def default_chol(self): + self.ordering="amd" + + def order(self): + + if self.ordering=="none": + order=0 + elif self.ordering=="colamd": ##colamd is the default ordering for Left LU + order=1 + elif self.ordering=="amd": ##amd is the default ordering for Cholesky + order=2 + else: + raise ValueError("Invalid order options") + + return order + + def charOut(self): + + if self.output=="double": + charOut=False + elif self.output=="string": + charOut=True + else: + raise ValueError("Invalid output type options") + + return charOut + + diff --git a/SPEX/Python/SPEXpy/SPEX_error.py b/SPEX/Python/SPEXpy/SPEX_error.py new file mode 100644 index 0000000000..5680bb2a5b --- /dev/null +++ b/SPEX/Python/SPEXpy/SPEX_error.py @@ -0,0 +1,25 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/SPEXpy/SPEX_error.py: class SPEX_error +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +class SPEX_error(LookupError): + '''raise this when there's a lookup error for spex''' + + +def determine_error(ok): + errorMessages={ + 1:"out of memory", + 2:"the input matrix A is singular", + 3:"one or more input arguments are incorrect", + 4:"the input matrix is unsymmetric", + 5:"the algorithm is not compatible with the factorization", + 6:"SPEX used without proper initialization", + } + return errorMessages.get(ok*(-1)) diff --git a/SPEX/Python/SPEXpy/Source/spex_python_connect.c b/SPEX/Python/SPEXpy/Source/spex_python_connect.c new file mode 100644 index 0000000000..728505f891 --- /dev/null +++ b/SPEX/Python/SPEXpy/Source/spex_python_connect.c @@ -0,0 +1,168 @@ +//------------------------------------------------------------------------------ +// SPEX/Python/spex_connect.c: use SPEX in Python +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#include "spex_python_connect.h" +#include "spex_cholesky_internal.h" + +#define FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&A, option); \ + SPEX_matrix_free(&b, option); \ + SPEX_matrix_free(&x, option); \ + SPEX_matrix_free(&A_in, option); \ + SPEX_matrix_free(&b_in, option); \ + SPEX_FREE(option); \ + SPEX_finalize(); \ +} + + +SPEX_info spex_python +( + //output + void **sol_void, // solution + //input + int64_t *Ap, // column pointers of A, an array size is n+1 + int64_t *Ai, // row indices of A, of size nzmax. + double *Ax, // values of A + double *bx, // values of b + int m, // Number of rows of A + int n, // Number of columns of A + int nz, // Number of nonzeros in A + int ordering, // type of ordering: 0-none, 1-colamd, 2-amd, + int algorithm, // 1-backslash, 2-left lu, 3-cholesky + bool charOut // True if char ** output, false if double +) +{ + // this function will make the SPEX_matrix A, b and x and call + // spex_cholesky_backslash + SPEX_info info; + + //-------------------------------------------------------------------------- + // Prior to using SPEX Chol, its environment must be initialized. This is + // done by calling the SPEX_initialize() function. + //-------------------------------------------------------------------------- + SPEX_initialize(); + + //-------------------------------------------------------------------------- + // Validate Inputs + //-------------------------------------------------------------------------- + + if (!Ap || !Ai || !Ax || !bx) + { + return SPEX_INCORRECT_INPUT; + } + + // ordering must be acceptable + if (ordering != 0 && ordering != 1 && ordering != 2) + { + return SPEX_INCORRECT_INPUT; + } + + if (n == 0 || m == 0 || n != m) + { + return SPEX_INCORRECT_INPUT; + } + + //-------------------------------------------------------------------------- + // Declare our data structures + //-------------------------------------------------------------------------- + SPEX_matrix A_in = NULL; //input matrix + SPEX_matrix b_in = NULL; //input rhs + SPEX_matrix A = NULL; //copy of input matrix in CSC MPZ + SPEX_matrix b = NULL; //copy of input rhs in CSC MPZ + SPEX_matrix x = NULL; //solution + + SPEX_options option = NULL; + SPEX_create_default_options(&option); + SPEX_preorder order_in = ordering; + option->order = ordering; + + //-------------------------------------------------------------------------- + // Allocate memory, populate in A and b + //-------------------------------------------------------------------------- + + SPEX_matrix_allocate(&A_in, SPEX_CSC, SPEX_FP64, n, n, nz, true, true, + option); + SPEX_matrix_allocate(&b_in, SPEX_DENSE, SPEX_FP64, n, 1, n, true, true, + option); + + A_in->p=Ap; + A_in->i=Ai; + A_in->x.fp64=Ax; + + b_in->x.fp64=bx; + + // At this point, A_in is a shallow double CSC matrix. We make a copy of it + // with A. A is a CSC matrix with mpz entries + + SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, A_in, option); + // b is a dense matrix with mpz entries + SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, b_in, option); + + //-------------------------------------------------------------------------- + // solve Ax=b + //------------------------------------------------------------------------- + switch(algorithm) + { + case 1: + SPEX_CHECK( SPEX_backslash(&x, SPEX_MPQ, A, b, option)); + break; + case 2: + SPEX_CHECK( SPEX_lu_backslash(&x, SPEX_MPQ, A, b, option)); + break; + case 3: + SPEX_CHECK( SPEX_cholesky_backslash(&x, SPEX_MPQ, A, b, option)); + break; + default: + return SPEX_INCORRECT_INPUT; + } + + //-------------------------------------------------------------------------- + // Return output as desired type + //----------------------------------------------------------------------- + if(charOut) + { + //solution as string + for (int i = 0; i < n; ++i) + { + char *s ; + int status = SPEX_mpfr_asprintf (&s, "%Qd", x->x.mpq [i]); + if (status < 0) + { + printf("error converting x to string"); + } + //check string size + int sizeStr; + sizeStr=strlen(s); + //allocate sol_char[i] + sol_void[i] = (void*) malloc (sizeStr*sizeof(char)); + //copy s into sol_char[i] + strcpy(sol_void[i],s); + } + } + else + { + //solution as double + SPEX_matrix x2 = NULL ; + SPEX_matrix_copy(&x2, SPEX_DENSE, SPEX_FP64, x, option); + /*for (int i = 0; i < n; ++i) + { + sol_doub[i]=x2->x.fp64[i]; + }*/ + for (int i = 0; i < n; ++i) + { + (sol_void[i])=&(x2->x.fp64[i]); + } + } + + FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/Python/SPEXpy/Source/spex_python_connect.h b/SPEX/Python/SPEXpy/Source/spex_python_connect.h new file mode 100644 index 0000000000..eb227efd49 --- /dev/null +++ b/SPEX/Python/SPEXpy/Source/spex_python_connect.h @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// SPEX/Python/spex_connect.h: use SPEX in Python +//------------------------------------------------------------------------------ + +// SPEX: (c) 2022-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#include "SPEX.h" + +SPEX_info spex_python +( + //output + void **sol_void, // solution + //input + int64_t *Ap, // column pointers of A, an array size is n+1 + int64_t *Ai, // row indices of A, of size nzmax. + double *Ax, // values of A + double *bx, // values of b + int m, // Number of rows of A + int n, // Number of columns of A + int nz, // Number of nonzeros in A + int ordering, // type of ordering: 0-none, 1-colamd, 2-amd + int algorithm, // 1-backslash, 2-left lu, 3-cholesky + bool charOut // True if char ** output, false if double +); + diff --git a/SPEX/Python/SPEXpy/__init__.py b/SPEX/Python/SPEXpy/__init__.py new file mode 100644 index 0000000000..0d348eab60 --- /dev/null +++ b/SPEX/Python/SPEXpy/__init__.py @@ -0,0 +1,33 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/SPEXpy/__init__.py +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +from .backslash import backslash +from .cholesky_backslash import cholesky_backslash +from .lu_backslash import lu_backslash + +from .spex_connect import spex_connect +from .spex_matrix_from_file import spex_matrix_from_file +from .Options import Options +from .SPEX_error import SPEX_error + +__all__=[ + 'backslash', + 'cholesky_backslash', + 'lu_backslash', + + 'spex_connect.py', + 'spex_matrix_from_file', + + 'SPEX_error', + 'Options' +] + + diff --git a/SPEX/Python/SPEXpy/backslash.py b/SPEX/Python/SPEXpy/backslash.py new file mode 100644 index 0000000000..b057b94fad --- /dev/null +++ b/SPEX/Python/SPEXpy/backslash.py @@ -0,0 +1,43 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/SPEXpy/backslash.py: solve Ax=b +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +from .Options import Options +from .SPEX_error import * +from .spex_connect import spex_connect + +import scipy +from scipy.sparse import isspmatrix, isspmatrix_csc, linalg + +def backslash( A, b):#, options=Options('double')): + ## A is a scipy.sparse(data must be float64) #technically it only needs to be numerical + ## b is a numpy.array (data must be float64) + ## options is a dictionary that specifies what tipe the solution should be, this by default is double + + ##-------------------------------------------------------------------------- + ## Verify inputs + ##-------------------------------------------------------------------------- + if not isspmatrix(A): + raise SPEX_error(determine_error(3)) + ## If the sparse input matrix is not in csc form, convert it into csc form + if not isspmatrix_csc(A): + A.tocsc() + # Check input shape + if A.shape[1]!=b.shape[0]: + raise SPEX_error(determine_error(3)) + + ##-------------------------------------------------------------------------- + ## Call SPEX + ##-------------------------------------------------------------------------- + x=spex_connect(A,b,0,False,1) + #x=spex_connect(A,b,0,options.charOut(),1) #1 calls the general backslash + + return x + diff --git a/SPEX/Python/SPEXpy/cholesky_backslash.py b/SPEX/Python/SPEXpy/cholesky_backslash.py new file mode 100644 index 0000000000..bde5ff4ce1 --- /dev/null +++ b/SPEX/Python/SPEXpy/cholesky_backslash.py @@ -0,0 +1,49 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/SPEXpy/cholesky_backslash.py: solve Ax=b using Cholesky factorization +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +from .Options import Options +from .SPEX_error import * +from .spex_connect import spex_connect + +import scipy +from scipy.sparse import isspmatrix, isspmatrix_csc, linalg + +def cholesky_backslash( A, b, options=Options('double', 'amd')): + ## A is a scipy.sparse(data must be float64) #technically it only needs to be numerical + ## b is a numpy.array (data must be float64) + ## options is a dictionary that specifies what tipe the solution should be, this by default is double + + ##-------------------------------------------------------------------------- + ## Verify inputs + ##-------------------------------------------------------------------------- + if not isspmatrix(A): + raise SPEXerror(determine_error(3)) + ## If the sparse input matrix is not in csc form, convert it into csc form + if not isspmatrix_csc(A): + A.tocsc() + ## Check symmetry + tol=1e-8 + if linalg.norm(A-A.T, scipy.Inf) > tol: + raise SPEX_error(determine_error(-4)) + # Check input shape + if A.shape[1]!=b.shape[0]: + raise SPEX_error(determine_error(-3)) + + if options.ordering==None: + options.default_chol() + + ##-------------------------------------------------------------------------- + ## Call SPEX + ##-------------------------------------------------------------------------- + x=spex_connect(A,b,options.order(),options.charOut(),3) #3 calls the Cholesky + + return x + diff --git a/SPEX/Python/SPEXpy/lu_backslash.py b/SPEX/Python/SPEXpy/lu_backslash.py new file mode 100644 index 0000000000..3810af8820 --- /dev/null +++ b/SPEX/Python/SPEXpy/lu_backslash.py @@ -0,0 +1,45 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/SPEXpy/lu_backslash.py: solve Ax=b using LU factorization +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +from .Options import Options +from .SPEX_error import * +from .spex_connect import spex_connect + +import scipy +from scipy.sparse import isspmatrix, isspmatrix_csc, linalg + +def lu_backslash( A, b, options=Options('double', 'colamd')): + ## A is a scipy.sparse(data must be float64) #technically it only needs to be numerical + ## b is a numpy.array (data must be float64) + ## options is a dictionary that specifies what tipe the solution should be, this by default is double + + ##-------------------------------------------------------------------------- + ## Verify inputs + ##-------------------------------------------------------------------------- + if not isspmatrix(A): + raise SPEX_error(determine_error(3)) + ## If the sparse input matrix is not in csc form, convert it into csc form + if not isspmatrix_csc(A): + A.tocsc() + # Check input shape + if A.shape[1]!=b.shape[0]: + raise SPEX_error(determine_error(3)) + + if options.ordering==None: + options.default_lu() + + ##-------------------------------------------------------------------------- + ## Call SPEX + ##-------------------------------------------------------------------------- + x=spex_connect(A,b,options.order(),options.charOut(),2) #2 calls lu + + return x + diff --git a/SPEX/Python/SPEXpy/setup.py b/SPEX/Python/SPEXpy/setup.py new file mode 100644 index 0000000000..f1ab038c1a --- /dev/null +++ b/SPEX/Python/SPEXpy/setup.py @@ -0,0 +1,15 @@ +from setuptools import find_packages, setup + +setup( + name='SPEXpy', + packages=find_packages(include=['SPEXpy']), + install_requires=[ +        'numpy', +        'scipy', +    ], + version='0.1.0', + description='Python interface for SPEX', + author='Lorena Mejia Domenzain', + license='SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later', +) + diff --git a/SPEX/Python/SPEXpy/spex_connect.py b/SPEX/Python/SPEXpy/spex_connect.py new file mode 100644 index 0000000000..b8c4a1a273 --- /dev/null +++ b/SPEX/Python/SPEXpy/spex_connect.py @@ -0,0 +1,80 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/SPEX/spex_connect.py: link SPEX to use in Python +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +import ctypes +import numpy as np +from numpy.ctypeslib import ndpointer +from .SPEX_error import * + +def spex_connect( A, b, order, charOut, algorithm ): + ## A is a scipy.sparse.csc_matrix (data must be float64) #technically it only needs to be numerical + ## b is a numpy.array (data must be float64) + + ##-------------------------------------------------------------------------- + ## Load the library with the "C bridge code" + ##-------------------------------------------------------------------------- + lib = ctypes.CDLL('../build/libspexpython.so') + c_backslash = lib.spex_python + + ##-------------------------------------------------------------------------- + ## Specify the parameter types and return type of the C function + ##-------------------------------------------------------------------------- + c_backslash.argtypes = [ctypes.POINTER(ctypes.c_void_p), + ndpointer(dtype=np.int64, ndim=1, flags=None), + ndpointer(dtype=np.int64, ndim=1, flags=None), + ndpointer(dtype=np.float64, ndim=1, flags=None), + ndpointer(dtype=np.float64, ndim=1, flags=None), + ctypes.c_int, + ctypes.c_int, + ctypes.c_int, + ctypes.c_int, + ctypes.c_int, + ctypes.c_bool] + c_backslash.restype = ctypes.c_int + + n=A.shape[0] #number of columns/rows of A + + x_v = (ctypes.c_void_p*n)() + + ##-------------------------------------------------------------------------- + ## Solve Ax=b using REF Sparse Cholesky Factorization + ##-------------------------------------------------------------------------- + ok=c_backslash(x_v, + A.indptr.astype(np.int64), #without the cast it would be int32 and it would not be compatible with the C method + A.indices.astype(np.int64), + A.data.astype(np.float64), + b, + n, + n, + A.nnz, + order, + algorithm, + charOut) + + if ok!=0: + raise SPEX_error(determine_error(ok)) + + ##-------------------------------------------------------------------------- + ## Cast solution into correct type (string or double) + ##-------------------------------------------------------------------------- + if charOut: + val = ctypes.cast(x_v, ctypes.POINTER(ctypes.c_char_p)) + x=[] + for i in range(n): + x.append(val[i]) + else: + #x = ctypes.cast(x_v, ctypes.POINTER(ctypes.c_double)) + x=[] + for i in range(n): + val=ctypes.cast(x_v[i], ctypes.POINTER(ctypes.c_double)) + x.append(val[0]) ##this can also be changed to be a numpy array instead of a list + + return np.array(x) diff --git a/SPEX/Python/SPEXpy/spex_matrix_from_file.py b/SPEX/Python/SPEXpy/spex_matrix_from_file.py new file mode 100644 index 0000000000..37e151356b --- /dev/null +++ b/SPEX/Python/SPEXpy/spex_matrix_from_file.py @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/SPEXpy/spex_from_matrix_file.py: read matrix from file +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + + +import numpy as np +from scipy.sparse import coo_matrix + +def spex_matrix_from_file(fname): + #fname is the name of the file that contains matrix A + + ##-------------------------------------------------------------------------- + ## Load file data and store it in mat + ##-------------------------------------------------------------------------- + mat = np.loadtxt(fname, delimiter=' ') + + ##-------------------------------------------------------------------------- + ## Splice mat to get the componets of matrix A and populate a scipy sparse matrix + ##-------------------------------------------------------------------------- + data = mat[1:,2] + row = mat[1:,0].astype(int) + col = mat[1:,1].astype(int) + n = mat[0][0].astype(int) + m = mat[0][1].astype(int) + ## The matrix in the file is in triplet form + triplet=coo_matrix((data, (row, col)),shape=(n, m)) + ## Change the triplet matrix into a csc matrix + A = triplet.tocsc() + + return A diff --git a/SPEX/Python/spex_python_demo.py b/SPEX/Python/spex_python_demo.py new file mode 100644 index 0000000000..f1e7e01621 --- /dev/null +++ b/SPEX/Python/spex_python_demo.py @@ -0,0 +1,72 @@ +#------------------------------------------------------------------------------- +# SPEX/Python/spex_python_demo.py: demo of 3 backslash functions with different input +# matrices +#------------------------------------------------------------------------------- + +# SPEX: (c) 2022, Chris Lourenco, Jinhao Chen, +# Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +# All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +#------------------------------------------------------------------------------ + +# SPEX is a package for solving sparse linear systems of equations +# with a roundoff-free integer-preserving method. The result is +# always exact, unless the matrix A is perfectly singular. + +# Import SPEX +import SPEXpy as SPEX +from SPEXpy import Options + +# Import scientific computing +import numpy as np +from numpy.random import default_rng +from scipy.sparse import csc_matrix +from scipy.sparse import random +from scipy import stats + + +##-------------------------------------------------------------------------- +## Cholesky +##-------------------------------------------------------------------------- + +# Create A and B +row = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2]) +col = np.array([0, 1, 2, 0, 1, 2, 0, 1, 2]) +data = np.array([4, 12, -16, 12, 37, -43, -16, -43, 98],dtype=np.float64) +A=csc_matrix((data, (row, col)), shape=(3, 3)) +b=np.ones(3,dtype=np.float64) + +# Solve +x=SPEX.cholesky_backslash(A,b) +print(x) + + +##-------------------------------------------------------------------------- +## Left LU +##-------------------------------------------------------------------------- + +# Generate a random sparse matrix A and populate b +n=10 +rng = default_rng() +rvs = stats.poisson(25, loc=10).rvs +S = random(n, n, density=0.7, random_state=rng, data_rvs=rvs) +S2=S+np.eye(n) +A=csc_matrix(S2) +b=np.ones(n,dtype=np.float64) + +# Solve +options=Options("string") +x=SPEX.lu_backslash(A,b,options) +print(x) + +##-------------------------------------------------------------------------- +## Backslash +##-------------------------------------------------------------------------- + +# Use the previous matrices + +# Solve +x=SPEX.backslash(A,b) +print(x) +#SPEX.backslash always returns the output as float64 diff --git a/SPEX/README.md b/SPEX/README.md index 24c2748fc4..5a4b77ef03 100644 --- a/SPEX/README.md +++ b/SPEX/README.md @@ -3,51 +3,71 @@ SPEX is a software package for SParse EXact algebra Files and folders in this distribution: README.md this file - - - SPEX_Left_LU Sparse left-looking integer-preserving - LU factorization for exactly solve - sparse linear systems (Release) - + + build Contains the SPEX C library as well + as the .so files + + DOC User guide for the SPEX software package + + MATLAB MATLAB interface for the SPEX software package + + SPEX_Backslash Exactly solve sparse linear systems with + default settings. This is the easiest + starting point for the SPEX software package. + SPEX_Backslash will automatically determine the + appropriate factorization algorithm for use in + solving your problem A x = b (Developmental) + + SPEX_Cholesky Sparse integer-preserving SPEX_Cholesky + factorization for exactly solving SPD + linear systems (Developmental) + + SPEX_LU Sparse left-looking integer-preserving + LU factorization for exactly solve + sparse linear systems. (Release) + + SPEX_QR Sparse integer-preserving QR factorization + (Developmental) + + SPEX_Update Sparse column replacement and rank 1 updates + for the SPEX factorizations + SPEX_UTIL Utility functions for all SPEX components - + Makefile compiles SPEX and its dependencies Dependencies: AMD approximate minimum degree ordering - + COLAMD column approximate minimum degree ordering - + SuiteSparse_config configuration for all of SuiteSparse - - GNU GMP GNU Multiple Precision Arithmetic Library - for big integer operations - + + GNU GMP GNU Multiple Precision Arithmetic Library + for big integer operations. v6.1.2 or later + is required. + GNU MPFR GNU Multiple Precision Floating-Point Reliable Library for arbitrary precision floating point - operations + operations. v4.0.2 or later is required. -Default instalation locations: +Default installation locations: include lib share - -To compile SPEX and its dependencies, just type "make" in this folder. -To run a few short demos, type "make demos" -To install the package system-wide, type "sudo make install". -Primary Author: Chris Lourenco +To compile SPEX and its dependencies, just type "make" in this folder. +This will also run a few short demos +To install the package system-wide, copy the `lib/*` to /usr/local/lib, +and copy `include/*` to /usr/local/include. -Coauthors (alphabetical order): +Authors (alphabetical order): Jinhao Chen - Tim Davis + Timothy A. Davis + Christopher Lourenco + Lorena Mejia-Domenzain Erick Moreno-Centeno -NOTE: The cmake build system for SPEX 2.0.3 in SuiteSparse v7.0.0 -works on Windows, but (so far) only when using the MSYS2 build -system. It doesn't yet work in MS Visual Studio, because the GMP -library isn't available on Windows for MSVC (just msys2 and -cygwin). We hope to resolve this issue in the future. diff --git a/SPEX/SPEX_Util/License/CONTRIBUTOR-LICENSE.txt b/SPEX/SPEX_Backslash/License/CONTRIBUTOR-LICENSE.txt similarity index 97% rename from SPEX/SPEX_Util/License/CONTRIBUTOR-LICENSE.txt rename to SPEX/SPEX_Backslash/License/CONTRIBUTOR-LICENSE.txt index 68e035b4e9..7f8e28675b 100644 --- a/SPEX/SPEX_Util/License/CONTRIBUTOR-LICENSE.txt +++ b/SPEX/SPEX_Backslash/License/CONTRIBUTOR-LICENSE.txt @@ -1,6 +1,6 @@ -SPEX Individual Contributor License Agreement +SPEX_Backslash Individual Contributor License Agreement -Thank you for your interest in contributing to SPEX ("We" or "Us"). +Thank you for your interest in contributing to SPEX_Backslash ("We" or "Us"). This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please sign it and send it @@ -161,8 +161,9 @@ software project managed by Us. any limited remedy to the maximum extent possible under law. Us -Christopher Lourenco, and all SPEX co-authors: +All SPEX co-authors: +Christopher Lourenco Jinhao Chen +Lorena Mejia Domenzain Timothy A. Davis Erick Moreno-Centeno - diff --git a/SPEX/SPEX_Left_LU/License/GPLv2.txt b/SPEX/SPEX_Backslash/License/GPLv2.txt similarity index 100% rename from SPEX/SPEX_Left_LU/License/GPLv2.txt rename to SPEX/SPEX_Backslash/License/GPLv2.txt diff --git a/SPEX/SPEX_Left_LU/License/lesserv3.txt b/SPEX/SPEX_Backslash/License/lesserv3.txt similarity index 100% rename from SPEX/SPEX_Left_LU/License/lesserv3.txt rename to SPEX/SPEX_Backslash/License/lesserv3.txt diff --git a/SPEX/SPEX_Util/License/license.txt b/SPEX/SPEX_Backslash/License/license.txt similarity index 88% rename from SPEX/SPEX_Util/License/license.txt rename to SPEX/SPEX_Backslash/License/license.txt index 3544ee7d76..f81e281688 100644 --- a/SPEX/SPEX_Util/License/license.txt +++ b/SPEX/SPEX_Backslash/License/license.txt @@ -1,10 +1,9 @@ -SPEX_Util: Utility functions for SParse EXact package +SPEX Backslash: -Copyright (c) 2019-2022, Christopher Lourenco, JinHao Chen, Erick Moreno- -Centeno, and Timothy A. Davis. +Copyright (c) 2021-2023, Christopher Lourenco, Jinhao Chen, +Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. Available at: - https://github.com/clouren/SPEX http://suitesparse.com diff --git a/SPEX/SPEX_Backslash/README.md b/SPEX/SPEX_Backslash/README.md new file mode 100644 index 0000000000..9762930baf --- /dev/null +++ b/SPEX/SPEX_Backslash/README.md @@ -0,0 +1,14 @@ + +SPEX_Backslash is software package used to solve a sparse systems of linear +equations. +exactly using Integer-Preserving factorizations. + +*********SPEX_Backslash********* +Purpose: Exactly solve a sparse system of linear equations using a given input + matrix and right hand side vector file. This code can output the final + solution to a user specified output file in either double precision or + full precision rational numbers. If you intend to use SPEX_Backslash + within another program, refer to examples for help with this. + +*********SPEX_Backslash_Demo********* + Purpose: Demonstrate SPEX_Backslash for a matrix to be read in diff --git a/SPEX/SPEX_Backslash/Source/SPEX_backslash.c b/SPEX/SPEX_Backslash/Source/SPEX_backslash.c new file mode 100644 index 0000000000..76433e5082 --- /dev/null +++ b/SPEX/SPEX_Backslash/Source/SPEX_backslash.c @@ -0,0 +1,163 @@ +//------------------------------------------------------------------------------ +// SPEX_Backslash/SPEX_backslash.c: Solve a system Ax=b +//------------------------------------------------------------------------------ + +// SPEX_Backslash: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: Exactly solve sparse linear systems using SPEX Software package, + * automatically determining the most appropriate factorization method. + * + * Input/Output arguments: + * + * x_handle: A pointer to the solution of the linear system. + * Null on input. The output can be in double precision, mpfr_t, or + * rational mpq_t + * + * type: Type of output desired, must be either SPEX_MPQ, + * SPEX_FP64, or SPEX_MPFR + * + * A: User's input matrix. It must be populated prior to calling this + * function. + * + * b: Collection of right hand side vectors. Must be populated prior + * to factorization. + * + * option: Struct containing various command parameters for the + * factorization. If NULL on input, default values are used. + */ + +#include "spex_util_internal.h" +#include "SPEX.h" + +SPEX_info SPEX_backslash +( + // Output + SPEX_matrix *x_handle, // On output: Final solution vector(s) + // On input: undefined + // Input + const SPEX_type type, // Type of output desired + // Must be SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 + const SPEX_matrix A, // Input matrix + const SPEX_matrix b, // Right hand side vector(s) + SPEX_options option // Command options (NULL: means use defaults) +) +{ + + SPEX_info info; + // Check inputs + if (!spex_initialized()) return SPEX_PANIC; + + // Check for NULL pointers + if (!x_handle || !A || !b ) + { + return SPEX_INCORRECT_INPUT; + } + + // Check for data types and dimension of A and b + if (A->m != A->n || A->type != SPEX_MPZ || A->kind != SPEX_CSC + || b->type != SPEX_MPZ || b->kind != SPEX_DENSE) + { + return SPEX_INCORRECT_INPUT; + } + + // Check that output type is correct + if (type != SPEX_MPQ && type != SPEX_FP64 && type != SPEX_MPFR) + { + return SPEX_INCORRECT_INPUT; + } + + + SPEX_options backslash_options = NULL; + info = SPEX_create_default_options(&backslash_options); + if (info != SPEX_OK) + { + return SPEX_OUT_OF_MEMORY; + } + + if (option != NULL) + { + // IF the options are not NULL, copy the important parts. + // Otherwise do nothing + backslash_options->print_level = option->print_level; // print level + backslash_options->prec = option->prec; // MPFR precision + backslash_options->round = option->round; // MPFR rounding + } + + // Declare output + SPEX_matrix x = NULL; + + // Attempt a Cholesky factorization of A. + // If Cholesky is occuring, we update the option + // struct to do AMD and diagonal pivoting + backslash_options->order = SPEX_AMD; + backslash_options->pivot = SPEX_DIAGONAL; + + // Try SPEX Cholesky. The output for this function + // is either: + // SPEX_OK: Cholesky success, x is the exact solution + // SPEX_NOTSPD: Cholesky failed. This means + // A is not SPD. In this case, we try LU + // Other error code: Some error. Return the error code and exit + info = SPEX_cholesky_backslash(&x, type, A, b, backslash_options); + if (info == SPEX_OK) + { + // Cholesky was successful. Set x_handle = x + (*x_handle) = x; + + // x_handle contains the exact solution of Ax = b and is + // stored in the user desired type. Now, we exit and return ok + SPEX_FREE(backslash_options); + return SPEX_OK; + } + else if (info == SPEX_NOTSPD) + { + // Cholesky factorization failed. Must try + // LU factorization now + + // Since LU is occuring, we update the option + // struct to do COLAMD and small pivoting + backslash_options->order = SPEX_COLAMD; + backslash_options->pivot = SPEX_SMALLEST; + + // The LU factorization can return either: + // SPEX_OK: LU success, x is the exact solution + // Other error code: Some error. Return the error + // code and exit + info = SPEX_lu_backslash(&x, type, A, b, backslash_options); + if (info == SPEX_OK) + { + // LU success, set x_handle = x + (*x_handle) = x; + + // x_handle contains the exact solution of Ax = b and is + // stored in the user desired type. Now, we exit and return ok + SPEX_FREE(backslash_options); + return SPEX_OK; + } + else + { + // Both Cholesky and LU have failed, info contains + // the problem, most likely that A is singular + // Note that, because LU failed, x_handle is still + // NULL so there is no potential for a memory leak here + SPEX_FREE(backslash_options); + return info; + } + } + else + { + // Cholesky failed, but not due to a SPEX_NOTSPD + // error code. Most likely invalid input or out of + // memory condition. + // Note that since Cholesky failed, x_handle is still NULL + // so there is no potential for a memory leak here + SPEX_FREE(backslash_options); + return info; + } + +} diff --git a/SPEX/SPEX_Cholesky/License/CONTRIBUTOR-LICENSE.txt b/SPEX/SPEX_Cholesky/License/CONTRIBUTOR-LICENSE.txt new file mode 100644 index 0000000000..a8f18db254 --- /dev/null +++ b/SPEX/SPEX_Cholesky/License/CONTRIBUTOR-LICENSE.txt @@ -0,0 +1,169 @@ +SPEX_Cholesky Individual Contributor License Agreement + +Thank you for your interest in contributing to SPEX_Cholesky ("We" or "Us"). + +This contributor agreement ("Agreement") documents the rights granted by +contributors to Us. To make this document effective, please sign it and send it +to Us by electronic submission. This is a legally binding document, so please +read it carefully before agreeing to it. The Agreement may cover more than one +software project managed by Us. + +1. Definitions + + "You" means the individual who Submits a Contribution to Us. + + "Contribution" means any work of authorship that is Submitted by You to Us + in which You own or assert ownership of the Copyright. + + "Copyright" means all rights protecting works of authorship owned or + controlled by You, including copyright, moral and neighboring rights, as + appropriate, for the full term of their existence including any extensions + by You. + + "Material" means the work of authorship which is made available by Us to + third parties. When this Agreement covers more than one software project, + the Material means the work of authorship to which the Contribution was + Submitted. After You Submit the Contribution, it may be included in the + Material. + + "Submit" means any form of electronic, verbal, or written communication + sent to Us or our representatives, including but not limited to electronic + mailing lists, source code control systems, and issue tracking systems that + are managed by, or on behalf of, Us for the purpose of discussing and + improving the Material, but excluding communication that is conspicuously + marked or otherwise designated in writing by You as "Not a Contribution." + + "Submission Date" means the date on which You Submit a Contribution to Us. + + "Effective Date" means the date You execute this Agreement or the date You + first Submit a Contribution to Us, whichever is earlier. + +2. Grant of Rights + + 2.1 Copyright License + + (a) You retain ownership of the Copyright in Your Contribution and have + the same rights to use or license the Contribution which You would have + had without entering into the Agreement. + + (b) To the maximum extent permitted by the relevant law, You grant to + Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, + irrevocable license under the Copyright covering the Contribution, with + the right to sublicense such rights through multiple tiers of + sublicensees, to reproduce, modify, display, perform and distribute the + Contribution as part of the Material; provided that this license is + conditioned upon compliance with Section 2.3. + + 2.2 Patent License + + For patent claims including, without limitation, method, process, and + apparatus claims which You own, control or have the right to grant, now + or in the future, You grant to Us a perpetual, worldwide, + non-exclusive, transferable, royalty-free, irrevocable patent license, + with the right to sublicense these rights to multiple tiers of + sublicensees, to make, have made, use, sell, offer for sale, import and + otherwise transfer the Contribution and the Contribution in combination + with the Material (and portions of such combination). This license is + granted only to the extent that the exercise of the licensed rights + infringes such patent claims; and provided that this license is + conditioned upon compliance with Section 2.3. + + 2.3 Outbound License + + Based on the grant of rights in Sections 2.1 and 2.2, if We include + Your Contribution in a Material, We may license the Contribution under + any license, including copyleft, permissive, commercial, or proprietary + licenses. + + 2.4 Moral Rights. + + If moral rights apply to the Contribution, to the maximum extent + permitted by law, You waive and agree not to assert such moral rights + against Us or our successors in interest, or any of our licensees, + either direct or indirect. + + 2.5 Our Rights. + + You acknowledge that We are not obligated to use Your Contribution as + part of the Material and may decide to include any Contribution We + consider appropriate. + + 2.6 Reservation of Rights. + + Any rights not expressly licensed under this section are expressly + reserved by You. + +3. Agreement + + You confirm that: + + (a) You have the legal authority to enter into this Agreement. + + (b) You own the Copyright and patent claims covering the Contribution which + are required to grant the rights under Section 2. + + (c) The grant of rights under Section 2 does not violate any grant of + rights which You have made to third parties, including Your employer. If + You are an employee, You have had Your employer approve this Agreement or + sign the Entity version of this document. If You are less than eighteen + years old, please have Your parents or guardian sign the Agreement. + +4. Disclaimer + + EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS + PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES + INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY + DISCLAIMED BY YOU TO US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE + DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD + PERMITTED BY LAW. + +5. Consequential Damage Waiver + + TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE + LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, + INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING + OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY + (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. + +6. Miscellaneous + + 6.1 This Agreement will be governed by and construed in accordance with the + laws of the State of Texas excluding its conflicts of law provisions. Under + certain circumstances, the governing law in this section might be + superseded by the United Nations Convention on Contracts for the + International Sale of Goods ("UN Convention") and the parties intend to + avoid the application of the UN Convention to this Agreement and, thus, + exclude the application of the UN Convention in its entirety to this + Agreement. + + 6.2 This Agreement sets out the entire agreement between You and Us for + Your Contributions to Us and overrides all other agreements or + understandings. + + 6.3 If You or We assign the rights or obligations received through this + Agreement to a third party, as a condition of the assignment, that third + party must agree in writing to abide by all the rights and obligations in + the Agreement. + + 6.4 The failure of either party to require performance by the other party + of any provision of this Agreement in one situation shall not affect the + right of a party to require such performance at any time in the future. A + waiver of performance under a provision in one situation shall not be + considered a waiver of the performance of the provision in the future or a + waiver of the provision in its entirety. + + 6.5 If any provision of this Agreement is found void and unenforceable, + such provision will be replaced to the extent possible with a provision + that comes closest to the meaning of the original provision and which is + enforceable. The terms and conditions set forth in this Agreement shall + apply notwithstanding any failure of essential purpose of this Agreement or + any limited remedy to the maximum extent possible under law. + +Us +All SPEX_Cholesky co-authors: +Christopher Lourenco +Jinhao Chen +Lorena Mejia Domenzain +Timothy A. Davis +Erick Moreno-Centeno diff --git a/SPEX/SPEX_Util/License/GPLv2.txt b/SPEX/SPEX_Cholesky/License/GPLv2.txt similarity index 100% rename from SPEX/SPEX_Util/License/GPLv2.txt rename to SPEX/SPEX_Cholesky/License/GPLv2.txt diff --git a/SPEX/SPEX_Util/License/lesserv3.txt b/SPEX/SPEX_Cholesky/License/lesserv3.txt similarity index 100% rename from SPEX/SPEX_Util/License/lesserv3.txt rename to SPEX/SPEX_Cholesky/License/lesserv3.txt diff --git a/SPEX/SPEX_Cholesky/License/license.txt b/SPEX/SPEX_Cholesky/License/license.txt new file mode 100644 index 0000000000..ac5cd4a939 --- /dev/null +++ b/SPEX/SPEX_Cholesky/License/license.txt @@ -0,0 +1,39 @@ +SPEX_Chol: Integer-Preserving Cholesky Factorization + +Copyright (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +All Rights Reserved. + +Available at: + https://github.com/clouren/SPEX/SPEX_Cholesky + http://suitesparse.com + +Contact Christopher Lourenco, chrisjlourenco@gmail.com, or Tim Davis +(timdavis@aldenmath.com or DrTimothyAldenDavis@gmail.com) for a commercial +license. + +-------------------------------------------------------------------------------- + +SPEX_Chol is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +SPEX_Chol is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with this software. If not, +see https://www.gnu.org/licenses/. diff --git a/SPEX/SPEX_Cholesky/README.txt b/SPEX/SPEX_Cholesky/README.txt new file mode 100644 index 0000000000..3978bd03c8 --- /dev/null +++ b/SPEX/SPEX_Cholesky/README.txt @@ -0,0 +1,16 @@ + +SPEX_Cholesky is software package used to solve a sparse SPD linear systems exactly using the Sparse Cholesky factorization. It comprises both an integer-preserving up-looking and integer-preserving left-looking Cholesky factorization. + +*********SPEX_Cholesky********* +Purpose: Exactly solve an SPD sparse system of linear equations using a given + input matrix and right hand side vector file. This code can output the + final solution to a user specified output file in either double + precision or full precision rational numbers. If you intend to use + SPEX_Cholesky within another program, refer to examples for help with + this. + +*********example_simple********* + Purpose: Demonstrate the simple interface of SPEX_Cholesky for a matrix to be read in + +*********example_extended********* +Purpose: Demonstrate the extended interface of SPEX_Cholesky for a matrix to be read in diff --git a/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_analyze.c b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_analyze.c new file mode 100644 index 0000000000..05e169045f --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_analyze.c @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/SPEX_cholesky_analyze: Perform the symbolic analysis of A +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: perform the symbolic analysis of A for the Cholesky factorization, + * that is, preordering A, computing the elimination tree, getting the column + * counts of A, setting the column pointers and exact number of non zeros of L. + * + * Input arguments of the function: + * + * S: Symbolic analysis struct for Cholesky factorization. + * On input it's NULL + * On output it contains the row/column permutation, the elimination + * tree, and the number of nonzeros in L. + * + * A: User's input matrix (Must be SPEX_MPZ and SPEX_CSC) + * + * option: Command options (Default if NULL) + * + */ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&PAP, NULL); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE ; \ + SPEX_symbolic_analysis_free (&S, option); \ +} + +#include "spex_cholesky_internal.h" + +SPEX_info SPEX_cholesky_analyze +( + // Output + SPEX_symbolic_analysis *S_handle, // Symbolic analysis data structure + // Input + const SPEX_matrix A, // Input matrix. Must be SPEX_MPZ and SPEX_CSC + const SPEX_options option // Command options (Default if NULL) +) +{ + + SPEX_info info; + // SPEX must be initialized + if (!spex_initialized()) + { + return SPEX_PANIC; + } + + // Check inputs + if ( !S_handle || !A) + { + return SPEX_INCORRECT_INPUT; + } + + // SPEX must be CSC + SPEX_REQUIRE_KIND(A, SPEX_CSC); + + // Declare permuted matrix and S + SPEX_matrix PAP = NULL; + SPEX_symbolic_analysis S = NULL; + + //-------------------------------------------------------------------------- + // Determine if A is indeed symmetric. If so, we try Cholesky. + // This symmetry check checks for both the nonzero pattern and values. + //-------------------------------------------------------------------------- + + bool is_symmetric ; + SPEX_CHECK( SPEX_determine_symmetry(&is_symmetric, A, option) ); + if (!is_symmetric) + { + SPEX_FREE_WORKSPACE ; + return SPEX_NOTSPD ; + } + + //-------------------------------------------------------------------------- + // Preorder: obtain the row/column ordering of A (Default is AMD) + //-------------------------------------------------------------------------- + + SPEX_CHECK( spex_cholesky_preorder(&S, A, option) ); + + //-------------------------------------------------------------------------- + // Permute matrix A, that is apply the row/column ordering from the + // symbolic analysis step to get the permuted matrix PAP. + //-------------------------------------------------------------------------- + + SPEX_CHECK( spex_cholesky_permute_A(&PAP, A, false, S) ); + + //-------------------------------------------------------------------------- + // Symbolic Analysis: compute the elimination tree of PAP + //-------------------------------------------------------------------------- + + SPEX_CHECK( spex_cholesky_symbolic_analysis(S, PAP, option) ); + + //-------------------------------------------------------------------------- + // Set output, free all workspace and return success + //-------------------------------------------------------------------------- + + (*S_handle) = S ; + SPEX_FREE_WORKSPACE ; + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_backslash.c b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_backslash.c new file mode 100644 index 0000000000..575812b01a --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_backslash.c @@ -0,0 +1,180 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/SPEX_cholesky_backslash: solve Ax=b +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This code utilizes the SPEX Cholesky factorization to exactly solve + * the linear system Ax = b. + * + * Input/Output arguments: + * + * x_handle: A pointer to the solution of the linear system. The output + * can be returned in double precision, + * mpfr_t (user-specified precision floating point), or + * mpq_t (rational) + * + * type: Type of output desired. + * Must be SPEX_MPQ, SPEX_FP64 or SPEX_MPFR + * + * A: User's input matrix. + * Must be populated prior to calling this function. + * + * b: Collection of right hand side vector(s). + * Must be populated prior to calling this function. + * + * option: Struct containing various command parameters for the + * factorization. If NULL on input, default values are used. + */ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_factorization_free(&F, option); \ + SPEX_symbolic_analysis_free (&S, option); \ + SPEX_matrix_free (&PAP, option); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE \ + SPEX_matrix_free(&x, NULL); \ +} + +#include "spex_cholesky_internal.h" + +SPEX_info SPEX_cholesky_backslash +( + // Output + SPEX_matrix *x_handle, // On input: undefined. + // On output: solution vector(s) + // Input + SPEX_type type, // Type of output desired + // Must be SPEX_FP64, SPEX_MPFR, or SPEX_MPQ + const SPEX_matrix A, // Input matrix. Must be SPEX_MPZ and SPEX_CSC + const SPEX_matrix b, // Right hand side vector(s). Must be + // SPEX_MPZ and SPEX_DENSE + const SPEX_options option // Command options (Default if NULL) +) +{ + + SPEX_info info; + // SPEX must be initialized + if (!spex_initialized()) + { + return SPEX_PANIC; + } + + //------------------------------------------------------------------------- + // check inputs + //------------------------------------------------------------------------- + + // x, A, B can't be NULL + if (!x_handle || !A || !b) + { + return SPEX_INCORRECT_INPUT; + } + + // type must be acceptable + if (type != SPEX_MPQ && type != SPEX_FP64 && type != SPEX_MPFR) + { + return SPEX_INCORRECT_INPUT; + } + + // A must be the appropriate dimension + if (A->n == 0 || A->m == 0) + { + return SPEX_INCORRECT_INPUT; + } + + // Make sure A and b are in the correct format + if (A->type != SPEX_MPZ || A->kind != SPEX_CSC || b->type != SPEX_MPZ + || b->kind != SPEX_DENSE) + { + return SPEX_INCORRECT_INPUT; + } + + // Declare memory + SPEX_symbolic_analysis S = NULL; + SPEX_factorization F = NULL ; + SPEX_matrix x = NULL; + SPEX_matrix PAP = NULL; + + //-------------------------------------------------------------------------- + // Determine if A is indeed symmetric. If so, we try Cholesky. This + // symmetry check checks for both the nonzero pattern and values. + //-------------------------------------------------------------------------- + + bool is_symmetric ; + SPEX_CHECK( SPEX_determine_symmetry(&is_symmetric, A, option) ); + if (!is_symmetric) + { + SPEX_FREE_WORKSPACE ; + return SPEX_NOTSPD ; + } + + //-------------------------------------------------------------------------- + // Preorder: obtain the row/column ordering of A (Default is AMD) + //-------------------------------------------------------------------------- + + SPEX_CHECK( spex_cholesky_preorder(&S, A, option) ); + + //-------------------------------------------------------------------------- + // Permute matrix A, that is apply the row/column ordering from the + // symbolic analysis step to get the permuted matrix PAP. + //-------------------------------------------------------------------------- + + SPEX_CHECK( spex_cholesky_permute_A(&PAP, A, true, S) ); + + //-------------------------------------------------------------------------- + // Symbolic Analysis: compute the elimination tree of PAP + //-------------------------------------------------------------------------- + + SPEX_CHECK( spex_cholesky_symbolic_analysis(S, PAP, option) ); + + //-------------------------------------------------------------------------- + // Factorization: Perform the REF Cholesky factorization of PAP. + // By default, up-looking Cholesky factorization is done; however, + // the left looking factorization is done if option->algo=SPEX_CHOL_LEFT + //-------------------------------------------------------------------------- + + SPEX_CHECK( spex_cholesky_factor(&F, S, PAP, option) ); + + //-------------------------------------------------------------------------- + // Solve: Solve Ax = b using the REF Cholesky factorization. That is, + // apply the factorization LDL' = PAP' to solve the linear system LDL'x = b. + // At the conclusion of the solve function, x is the exact solution of + // Ax = b stored as a set of numerators and denominators (mpq_t) + //-------------------------------------------------------------------------- + + SPEX_CHECK( SPEX_cholesky_solve(&x, F, b, option) ); + + //-------------------------------------------------------------------------- + // At this point x is stored as mpq_t. If the user desires the output + // to be mpq_t we set x_handle = x. Otherwise, we create a copy, x2, of x + // of the desired type. We then set x_handle = x2 and free x. + //-------------------------------------------------------------------------- + + if (type == SPEX_MPQ) + { + (*x_handle) = x; + } + else + { + SPEX_matrix x2 = NULL; + SPEX_CHECK( SPEX_matrix_copy(&x2, SPEX_DENSE, type, x, option) ); + (*x_handle) = x2; + SPEX_matrix_free (&x, NULL); + } + + //-------------------------------------------------------------------------- + // Free all workspace and return success + //-------------------------------------------------------------------------- + + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_factorize.c b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_factorize.c new file mode 100644 index 0000000000..c662cb9acb --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_factorize.c @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/SPEX_cholesky_factorize: Perform SPEX Chol factorization of A +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function performs the integer preserving Cholesky factorization. + * First it permutes the input matrix according to the symbolic analysis. + * Then it performs the left-looking or up-looking integer-preserving Cholesky + * factorization. In order to compute the L matrix, it performs n iterations of + * a sparse REF symmetric triangular solve function. The overall factorization + * is PAP' = LDL' + * + * + * Input arguments of the function: + * + * F_handle: Handle to the factorization struct. Null on input. + * On output, contains a pointer to the factorization. + * + * A: User's input matrix. Must be SPEX_MPZ and SPEX_CSC. + * + * S: Symbolic analysis struct for Cholesky factorization. + * On input it contains the elimination tree and + * the number of nonzeros in L. + * + * option: Command options. Default if NULL. Notably, option->chol_type + * indicates whether it is performing the default up-looking + * factorization (SPEX_CHOL_UP) or the left-looking factorization + * (SPEX_CHOL_LEFT). + */ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_matrix_free (&PAP, option); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE ; \ +} + +#include "spex_cholesky_internal.h" + +SPEX_info SPEX_cholesky_factorize +( + // Output + SPEX_factorization *F_handle, // Cholesky factorization struct + //Input + const SPEX_matrix A, // Matrix to be factored. Must be SPEX_MPZ + // and SPEX_CSC + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column + // pointers of L, and the exact number of + // nonzeros of L. + const SPEX_options option // command options. + // Notably, option->chol_type indicates + // whether CHOL_UP (default) or CHOL_LEFT + // is used. +) +{ + + SPEX_info info; + + if (!spex_initialized()) + { + return SPEX_PANIC; + } + + // Check inputs for NULL + if (!F_handle || !A || !S) + { + return (SPEX_INCORRECT_INPUT); + } + + // Ensure inputs are in the correct format + if (A->kind != SPEX_CSC || A->type != SPEX_MPZ + || S->kind != SPEX_CHOLESKY_FACTORIZATION) + { + return (SPEX_INCORRECT_INPUT); + } + + SPEX_matrix PAP = NULL ; + SPEX_factorization F = NULL ; + + //-------------------------------------------------------------------------- + // Numerically permute matrix A, that is apply the row/column ordering from + // the symbolic analysis step to get the permuted matrix PAP. + //-------------------------------------------------------------------------- + + SPEX_CHECK(spex_cholesky_permute_A(&PAP, A, true, S)); + + //-------------------------------------------------------------------------- + // Factorization: Perform the REF Cholesky factorization of + // A. By default, up-looking Cholesky factorization is done; however, + // the left looking factorization is done if option->algo=SPEX_CHOL_LEFT + //-------------------------------------------------------------------------- + + SPEX_CHECK(spex_cholesky_factor(&F, S, PAP, option)); + + //-------------------------------------------------------------------------- + // Set F_handle = F, free all workspace and return success + //-------------------------------------------------------------------------- + + (*F_handle) = F ; + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_solve.c b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_solve.c new file mode 100644 index 0000000000..f42f15a7f4 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/SPEX_cholesky_solve.c @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/SPEX_cholesky_solve: Solve the SPD linear system after +// factorization +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&b2, option); \ +} + +# define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE \ + SPEX_matrix_free(&x, NULL); \ +} + +#include "spex_cholesky_internal.h" + +/* Purpose: This function solves the linear system LDL' x = b. + * + * Input arguments: + * + * x_handle: A handle to the solution matrix. On input this is NULL, + * on output x_handle contains a pointer to the solution + * vector(s) + * + * F: The factorization struct containing the REF cholesky + * factorization of A, permutation, etc + * + * S: Symbolic analysis struct (contains row/column permutation + * and its inverse + * + * option: Command options * + */ + +SPEX_info SPEX_cholesky_solve +( + // Output + SPEX_matrix *x_handle, // On input: undefined. + // On output: Rational solution (SPEX_MPQ) + // to the system. + // input/output: + SPEX_factorization F, // The non-updatable Cholesky factorization. + // Mathematically, F is unchanged. However, if + // F is updatable on input, it is converted to + // non-updatable. If F is already + // non-updatable, it is not modified. + // input: + const SPEX_matrix b, // Right hand side vector + const SPEX_options option // command options +) +{ + + SPEX_info info; + + // Ensure SPEX is initialized + if (!spex_initialized()) + { + return SPEX_PANIC; + } + + // Check the inputs + if (!x_handle || b->type != SPEX_MPZ || b->kind != SPEX_DENSE + || F->kind != SPEX_CHOLESKY_FACTORIZATION) + { + return SPEX_INCORRECT_INPUT; + } + + // det is the determinant of the PAP matrix. It is obtained for free + // from the SPEX Cholesky factorization det = rhos[n-1] = L[n,n] + mpz_t *det = NULL; + + //-------------------------------------------------------------------------- + // Declare workspace and output + //-------------------------------------------------------------------------- + // x is the permuted final solution vector returned to the user + SPEX_matrix x = NULL; + // b2 is the permuted right hand side vector(s) + SPEX_matrix b2 = NULL; + + //-------------------------------------------------------------------------- + // get b2 = Pinv*b + //-------------------------------------------------------------------------- + + SPEX_CHECK (spex_permute_dense_matrix (&b2, b, F->Pinv_perm, option)); + + //-------------------------------------------------------------------------- + // Forward substitution, b2 = L \ b2. Note that b2 is overwritten + //-------------------------------------------------------------------------- + + SPEX_CHECK(spex_cholesky_forward_sub(b2, F->L, F->rhos)); + + //-------------------------------------------------------------------------- + // Apply the determinant to b2, b2 = det*b2 + //-------------------------------------------------------------------------- + + // Set the value of the determinant det = rhos[n-1] + det = &(F->rhos->x.mpz[F->L->n-1]); + + // Multiply b2 by the determinant. This multiplication ensures that the next + // backsolve is integral + SPEX_CHECK(spex_matrix_mul(b2, (*det) )); + + //-------------------------------------------------------------------------- + // Backsolve, b2 = L' \ b2. Note that, again, b2 is overwritten + //-------------------------------------------------------------------------- + + SPEX_CHECK(spex_cholesky_backward_sub(b2, F->L)); + + //-------------------------------------------------------------------------- + // get real solution x by applying both permutation and scale + // x = P*b2/scale + //-------------------------------------------------------------------------- + + // Scale is the scaling factor for the solution vectors. + // When the forward/backsolve is complete, the entries in + // x/det are rational, but are solving the scaled linear system + // A' x = b' (that is if A had input which was rational or floating point + // and had to be converted to integers). Thus, the scale here is used + // to convert x into into the actual solution of A x = b. + // Mathematically, set scale = b->scale * rhos[n-1] / PAP->scale + + SPEX_MPQ_SET_Z(b2->scale, (*det)); + SPEX_MPQ_MUL(b2->scale, b2->scale, b->scale); + SPEX_MPQ_DIV(b2->scale, b2->scale, F->scale_for_A); + + // allocate space for x as dense MPQ matrix + SPEX_CHECK (SPEX_matrix_allocate (&x, SPEX_DENSE, SPEX_MPQ, b->m, b->n, + 0, false, true, option)); + + // obtain x from permuted b2 with scale applied + for (int64_t i = 0 ; i < b->m ; i++) + { + int64_t pi = F->P_perm[i]; + for (int64_t j = 0 ; j < b->n ; j++) + { + + SPEX_MPQ_SET_Z(SPEX_2D(x, pi, j, mpq), + SPEX_2D(b2, i, j, mpz)); + SPEX_MPQ_DIV(SPEX_2D(x, pi, j, mpq), + SPEX_2D(x, pi, j, mpq), b2->scale); + } + } + + // Set output, free memory + (*x_handle) = x; + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_backward_sub.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_backward_sub.c new file mode 100644 index 0000000000..6e70d9f283 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_backward_sub.c @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_backward_sub: Solve L' x = b for Cholesky +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_ALL ; + +#include "spex_cholesky_internal.h" + + +/* Purpose: This function solves the linear system L' x = x for Cholesky + * factorization. On input, x contains the forward substitution solution vector + * (that is the solution of L D x = b. On output, x contains the exact solution + * of the system Ax = (det A)*b L is the lower triangular REF Cholesky factor of + * A. It is not modified on input/output + */ + +SPEX_info spex_cholesky_backward_sub +( + // Output + SPEX_matrix x, // Solution vector to A x = det(A) * b + // Input + const SPEX_matrix L // The lower triangular matrix +) +{ + + SPEX_info info; + // All inputs have been checked by the caller, asserts are + // here as a reminder + ASSERT(L->type == SPEX_MPZ); + ASSERT(L->kind == SPEX_CSC); + ASSERT(x->type == SPEX_MPZ); + ASSERT(x->kind == SPEX_DENSE); + + int64_t k, p, j, n = L->n; + int sgn, sgn2; + + // Iterate across the RHS vectors + for (k = 0; k < x->n; k++) + { + // Iterate across the rows of x + for (j = n-1; j >= 0; j--) + { + // Iterate across column j of L + for (p = L->p[j]+1; p < L->p[j+1]; p++) + { + // If either x[p,k] or L[p,k] is 0, skip the operation + SPEX_MPZ_SGN(&sgn, SPEX_2D(x, L->i[p], k, mpz)); + SPEX_MPZ_SGN(&sgn2, L->x.mpz[p]); + if (sgn == 0 || sgn2 ==0 ) continue; + + // Compute x[j,k] = x[j,k] - L[p,k]*x[p,k] + SPEX_MPZ_SUBMUL(SPEX_2D(x, j, k, mpz), + L->x.mpz[p], SPEX_2D(x, L->i[p], k, mpz)); + } + + // Compute x[j,k] = x[j,k] / L[j,j] + SPEX_MPZ_DIVEXACT(SPEX_2D(x, j, k, mpz), + SPEX_2D(x, j, k, mpz), L->x.mpz[ L->p[j]]); + + } + } + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_counts.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_counts.c new file mode 100644 index 0000000000..1802865a97 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_counts.c @@ -0,0 +1,124 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_counts: Column counts for Cholesky factorization +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_FREE(w); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE; \ + SPEX_FREE(colcount); \ +} + +#include "spex_cholesky_internal.h" + +#define HEAD(k,j) ( j) +#define NEXT(J) (-1) + +/* Purpose: Obtain the column counts of an SPD matrix for Cholesky + * factorization. This is a modified version of Csparse's cs_chol_counts + * function + */ + +SPEX_info spex_cholesky_counts +( + // Output + int64_t **c_handle, // On ouptut: column counts + // On input: undefined + // Input + const SPEX_matrix A, // Input matrix + const int64_t *parent, // Elimination tree + const int64_t *post // Post-order of the tree +) +{ + + SPEX_info info; + int64_t i, j, k, n, J, s, p, q, jleaf, *colcount = NULL, *w = NULL; + // Auxiliary variables + int64_t *maxfirst, *prevleaf, *ancestor, *first, *delta ; + n = A->n ; + // Can not have negative n + ASSERT(n >= 0); + // Size of workspace + s = 4*n ; + // Allocate result in delta + colcount = (int64_t*) SPEX_malloc(n* sizeof (int64_t)); + // Create a workspace of size s + w = (int64_t*) SPEX_malloc (s* sizeof (int64_t)); + if (colcount == NULL || w == NULL) + { + SPEX_FREE_ALL; + return SPEX_OUT_OF_MEMORY; + } + delta = colcount; + ancestor = w ; maxfirst = w+n ; prevleaf = w+2*n ; first = w+3*n ; + // Clear workspace + for (k = 0 ; k < s ; k++) + { + w [k] = -1 ; + } + // Find first j + for (k = 0 ; k < n ; k++) + { + j = post[k] ; + delta[j] = (first[j] == -1) ? 1 : 0 ; /* delta[j]=1 if j is a leaf */ + for ( ; j != -1 && first[j] == -1 ; j = parent[j]) + { + first [j] = k ; + } + } + // Initialize ancestor of each node + for (i = 0 ; i < n ; i++) + { + ancestor[i] = i ; + } + for (k = 0 ; k < n ; k++) + { + j = post[k] ; /* j is the kth node in postordered etree */ + if (parent[j] != -1) + { + delta[parent[j]]-- ; /* j is not a root */ + } + for (J = HEAD(k,j); J != -1 ; J = NEXT(J)) /* J=j for LL'=A case */ + { + for (p = A->p[J] ; p < A->p[J+1] ; p++) + { + i = A->i[p] ; + SPEX_CHECK(spex_cholesky_leaf(&q, i, j, first, maxfirst, + prevleaf, ancestor, &jleaf)); + if (jleaf >= 1) + { + delta[j]++ ; /* A(i,j) is in skeleton */ + } + if (jleaf == 2) + { + delta[q]-- ; /* account for overlap in q */ + } + } + } + if (parent[j] != -1) + { + ancestor[j] = parent[j] ; + } + } + for (j = 0 ; j < n ; j++) /* sum up delta's of each child */ + { + if (parent[j] != -1) + { + colcount[parent[j]] += colcount[j] ; + } + } + (*c_handle) = colcount; + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_ereach.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_ereach.c new file mode 100644 index 0000000000..a7559a0b53 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_ereach.c @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_ereach: Compute reach of an elimination tree +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#include "spex_cholesky_internal.h" + +/* Purpose: This function computes the reach of the kth row of A onto the graph + * of L using the elimination tree. It finds the nonzero pattern of row k of L + * and uses the upper triangular part of A(:,k) */ + +SPEX_info spex_cholesky_ereach +( + // Output + int64_t *top_handle, // On output: starting point of nonzero pattern + // On input: undefined + int64_t *xi, // On output: contains the nonzero pattern in + // xi[top..n-1] + // On input: undefined + // Input + const SPEX_matrix A, // Matrix to be analyzed + const int64_t k, // Node to start at + const int64_t *parent, // Elimination tree of A + int64_t *w // Workspace array +) +{ + + // Check inputs + ASSERT(A->n >= 0); + ASSERT(A->kind == SPEX_CSC); + ASSERT(A->type == SPEX_MPZ); + + // Declare variables + int64_t i, p, n, len, top ; + top = n = A->n ; + + // Mark node k as visited + SPEX_MARK(w, k); + + // Iterate across nonzeros in A(:,k) + for (p = A->p[k] ; p < A->p[k+1] ; p++) + { + // A(i,k) is nonzero + i = A->i[p] ; + if (i > k) + { + continue ; // only use upper triangular part of A + } + for (len = 0 ; !SPEX_MARKED(w,i); i = parent[i]) // traverse up etree + { + ASSERT (i >= 0 && i < n); + xi[len++] = i ; // L(k,i) is nonzero + SPEX_MARK(w, i); // mark i as visited + } + while (len > 0) xi[--top] = xi[--len] ; // push path onto stack + } + for (p = top ; p < n ; p++) SPEX_MARK(w, xi[p]); // unmark all nodes + SPEX_MARK(w, k); // unmark node k + (*top_handle) = top ; + return SPEX_OK ; // xi [top..n-1] contains pattern of L(k,:) +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_etree.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_etree.c new file mode 100644 index 0000000000..8c2d8f2fc5 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_etree.c @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_etree: Compute the elimination tree of a matrix A +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_FREE(w); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE ; \ + SPEX_FREE(parent); \ +} + +#include "spex_cholesky_internal.h" + + +/* Purpose: Compute the elimination tree of A */ + +SPEX_info spex_cholesky_etree +( + // Output + int64_t **tree_handle, // On output: contains the elimination tree of A + // On input: undefined. + // Input + const SPEX_matrix A // Input matrix (must be SPD). +) +{ + + // All inputs are checked by the caller so asserts are used here as a + // reminder of the appropriate formats + ASSERT (A != NULL); + ASSERT(A->kind == SPEX_CSC); + ASSERT(A->type == SPEX_MPZ); + ASSERT(A->n == A->m); + ASSERT (tree_handle != NULL); + (*tree_handle) = NULL ; + + // Declare variables + int64_t i, k, p, n, inext, *w = NULL, *parent = NULL, *ancestor ; + n = A->n ; + + // Allocate parent + parent = (int64_t*) SPEX_malloc( n * sizeof(int64_t)); + // Allocate workspace + w = (int64_t*) SPEX_malloc( n * sizeof(int64_t) ); + if (!parent || !w) + { + SPEX_FREE_ALL; + return SPEX_OUT_OF_MEMORY; + } + ancestor = w ; + for (k = 0 ; k < n ; k++) + { + parent [k] = -1 ; // node k has no parent yet + ancestor [k] = -1 ; // nor does k have an ancestor + for (p = A->p [k] ; p < A->p [k+1] ; p++) + { + i = A->i [p] ; + for ( ; i != -1 && i < k ; i = inext) // traverse from i to k + { + inext = ancestor [i] ; // inext = ancestor of i + ancestor [i] = k ; // path compression + if (inext == -1) parent [i] = k ; // no anc., parent is k + } + } + } + SPEX_FREE_WORKSPACE ; + (*tree_handle) = parent; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_factor.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_factor.c new file mode 100644 index 0000000000..e899145edf --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_factor.c @@ -0,0 +1,141 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_factor: Integer preserving Cholesky factorization +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +# define SPEX_FREE_ALL \ +{ \ + SPEX_factorization_free(&F, option); \ +} + + +#include "spex_cholesky_internal.h" + +/* Purpose: This function performs the integer preserving Cholesky + * factorization. It allows either the left-looking or up-looking + * integer-preserving Cholesky factorization. In order to compute the L matrix, + * it performs n iterations of a sparse REF symmetric triangular solve + * function. The overall factorization is PAP' = LDL' + * + * Importantly, this function assumes that A has already been permuted, + * and symbolically analyzed. + * + * Input arguments of the function: + * + * F_handle: A handle to the factorization struct. Null on input. + * On output, contains a pointer to the factorization (this + * includes matrix L) + * + * S: Symbolic analysis struct for Cholesky factorization. + * On input it contains the elimination tree and + * the number of nonzeros in L. + * + * A: The user's permuted input matrix + * + * option: Command options. Notably, option->chol_type indicates whether + * it is performing a left-looking (SPEX_CHOL_LEFT) or up-looking + * factorization (SPEX_CHOL_UP) (default) + */ + +SPEX_info spex_cholesky_factor +( + // Output + SPEX_factorization *F_handle, // Cholesky factorization + //Input + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column pointers of + // L, and the exact number of nonzeros of L. + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // Command options + // Notably, option->chol_type indicates whether + // CHOL_UP (default) or CHOL_LEFT is used. +) +{ + + SPEX_info info; + + SPEX_factorization F = NULL ; + + //-------------------------------------------------------------------------- + // Check inputs + //-------------------------------------------------------------------------- + // All inputs have been checked by the caller, asserts are used here as a + // reminder of the appropriate data types + ASSERT(A->type == SPEX_MPZ); + ASSERT(A->kind == SPEX_CSC); + + // Number of nonzeros in A + int64_t anz; + SPEX_CHECK( SPEX_matrix_nnz(&anz, A, option) ); + ASSERT(anz > 0); + + (*F_handle) = NULL ; + + //-------------------------------------------------------------------------- + // Declare and initialize workspace + //-------------------------------------------------------------------------- + + // Dimension of A + int64_t n = A->n ; + + // Allocate memory for the factorization + F = (SPEX_factorization) SPEX_calloc(1, sizeof(SPEX_factorization_struct)); + if (F == NULL) return SPEX_OUT_OF_MEMORY; + + // set factorization kind + F->kind = SPEX_CHOLESKY_FACTORIZATION; + + // Allocate and set scale_for_A + SPEX_MPQ_INIT(F->scale_for_A); + SPEX_MPQ_SET(F->scale_for_A, A->scale); + + // Inverse pivot ordering + F->Pinv_perm = (int64_t*) SPEX_malloc ( n*sizeof(int64_t) ); + // row/column permutation, to be copied from S->P_perm + F->P_perm = (int64_t*) SPEX_malloc ( n*sizeof(int64_t) ); + if (!(F->Pinv_perm) || !(F->P_perm)) + { + // out of memory: free everything and return + SPEX_FREE_ALL; + return SPEX_OUT_OF_MEMORY; + } + + // Copy row/column permutation from symbolic analysis to factorization + memcpy(F->P_perm, S->P_perm, n*sizeof(int64_t)); + memcpy(F->Pinv_perm, S->Pinv_perm, n*sizeof(int64_t)); + + //-------------------------------------------------------------------------- + // factorization: up-looking or left-looking + //-------------------------------------------------------------------------- + + SPEX_factorization_algorithm algo = SPEX_OPTION_ALGORITHM(option); + switch(algo) + { + case SPEX_ALGORITHM_DEFAULT: + // fall through to up-looking Cholesky (the default) + case SPEX_CHOL_UP: + SPEX_CHECK( spex_cholesky_up_factor(&(F->L), &(F->rhos), S, A, + option)); + break; + case SPEX_CHOL_LEFT: + SPEX_CHECK( spex_cholesky_left_factor(&(F->L), &(F->rhos), S, A, + option) ); + break; + default: + SPEX_FREE_ALL; + return SPEX_INCORRECT_ALGORITHM; + } + + //-------------------------------------------------------------------------- + // Set outputs, return ok + //-------------------------------------------------------------------------- + + (*F_handle) = F ; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_forward_sub.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_forward_sub.c new file mode 100644 index 0000000000..d4880ffeec --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_forward_sub.c @@ -0,0 +1,190 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_forward_sub: Solve the system LDx = b +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function performs sparse REF forward substitution This is + * essentially the same as the sparse REF triangular solve applied to each + * column of the right hand side vectors. Like the normal one, this + * function expects that the vector x is dense. As a result,the nonzero + * pattern is not computed and each nonzero in x is iterated across. + * The system to solve is LDx = x + * + * On output, the matrix x structure is modified + * + */ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&h, NULL); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE \ +} + +#include "spex_cholesky_internal.h" + +SPEX_info spex_cholesky_forward_sub +( + // Input/Output + SPEX_matrix x, // Right hand side matrix. + // On input: contains b + // On output: contains the solution of LD x = x + // Input + const SPEX_matrix L, // REF Cholesky factor of A (lower triangular) + const SPEX_matrix rhos // Sequence of pivots used in factorization +) +{ + + SPEX_info info; + int64_t i, p, k, n = L->n, m, mnew; + + // All inputs have been checked by the caller. Asserts are + // here for reminder + ASSERT(n >= 0); + ASSERT(L->n == x->m); + ASSERT(L->kind == SPEX_CSC); + ASSERT(L->type == SPEX_MPZ); + ASSERT(x->kind == SPEX_DENSE); + ASSERT(x->type == SPEX_MPZ); + + int sgn; + + // Build the history matrix + SPEX_matrix h = NULL ; + SPEX_CHECK(SPEX_matrix_allocate(&h, SPEX_DENSE, SPEX_INT64, x->m, x->n, + x->nzmax, false, true, NULL)); + + // initialize entries of history matrix to be -1 + int xnz = x->n * x->m; + for (i = 0; i < xnz; i++) + { + h->x.int64[i] = -1; + } + + //-------------------------------------------------------------------------- + // Iterate across each RHS vector + //-------------------------------------------------------------------------- + for (k = 0; k < x->n; k++) + { + //---------------------------------------------------------------------- + // Iterate accross all nonzeros in x. Assumes x is dense + //---------------------------------------------------------------------- + for (i = 0; i < n; i++) + { + // p is the history value of x[i,k] that is p = h[i,k] + p = SPEX_2D(h, i, k, int64); + // If x[i][k] = 0, can skip operations and continue to next i + SPEX_MPZ_SGN(&sgn, SPEX_2D(x, i, k, mpz)); + if (sgn == 0) continue; + + //------------------------------------------------------------------ + // History Update x[i,k] + //------------------------------------------------------------------ + if (p < i-1) + { + // x[i,l] = x[i,k] * rhos[i-1] + SPEX_MPZ_MUL(SPEX_2D(x, i, k, mpz), + SPEX_2D(x, i, k, mpz),rhos->x.mpz[i-1]); + + // Only divide by the previous pivot if it is not =1 + // (the default for the first iteration) + if (p > -1) + { + // x[i,k] = x[i,k] / rhos[p] + SPEX_MPZ_DIVEXACT(SPEX_2D(x, i, k, mpz), + SPEX_2D(x, i, k, mpz), rhos->x.mpz[p]); + } + } + + //------------------------------------------------------------------ + // IPGE updates + //------------------------------------------------------------------ + // Access entry L[m,i] + for (m = L->p[i]; m < L->p[i+1]; m++) + { + // mnew is the row index of L[m,i] + mnew = L->i[m]; + // skip if L[m,i] is zero + SPEX_MPZ_SGN(&sgn, L->x.mpz[m]); + if (sgn == 0) continue; + + if (mnew > i) + { + // p is the history value of x[m,k] + p = SPEX_2D(h, mnew, k, int64); + // Check if x[m,k] is zero + SPEX_MPZ_SGN(&sgn, SPEX_2D(x, mnew, k, mpz)); + if (sgn == 0) + { + // In this case x[m,k] is zero, + // so we compute x[m,k] = 0 - l[m,i]*x[i,k] + SPEX_MPZ_SUBMUL(SPEX_2D(x, mnew, k, mpz), + L->x.mpz[m], SPEX_2D(x, i, k, mpz)); + // x[m,k] = x[m,k]/rhos[i-1] if we are not in the first + // iteration (in which case rhos[i-1] = 1 + if (i > 0) + { + SPEX_MPZ_DIVEXACT(SPEX_2D(x, mnew, k, mpz), + SPEX_2D(x, mnew, k, mpz), + rhos->x.mpz[i-1]); + } + } + else + { + // In this case, x[m,k] is not equal to zero. We first + // check if a history update is necessary + if (p < i-1) + { + // x[m,k] = x[m,k] * rhos[i-1] + SPEX_MPZ_MUL(SPEX_2D(x, mnew, k, mpz), + SPEX_2D(x, mnew, k, mpz), + rhos->x.mpz[i-1]); + // Divide by the history pivot if we are not in the + // first interation (in which case rhos[p] = 1) + // x[m,k] = x[m,k] / rhos[p] + if (p > -1) + { + SPEX_mpz_divexact(SPEX_2D(x, mnew, k, mpz), + SPEX_2D(x, mnew, k, mpz), + rhos->x.mpz[p]); + } + } + // x[m,k] = x[m,k] * rhos[i] + SPEX_MPZ_MUL(SPEX_2D(x, mnew, k, mpz), + SPEX_2D(x, mnew, k, mpz),rhos->x.mpz[i]); + // x[m,k] = x[m,k] - l[m,i] *x[i,k] + SPEX_MPZ_SUBMUL(SPEX_2D(x, mnew, k, mpz), + L->x.mpz[m], SPEX_2D(x, i, k, mpz)); + // Divide by the previous pivot if not in iteration 0. + // If at iteration 0, the pivot is equal to 1 so no + // division is necessary + // x[m,k] = x[m,k] / rhos[i-1] + if (i > 0) + { + SPEX_MPZ_DIVEXACT(SPEX_2D(x, mnew, k, mpz), + SPEX_2D(x, mnew, k, mpz), + rhos->x.mpz[i-1]); + } + } + // Update the history value of x[m,k] + SPEX_2D(h, mnew, k, int64) = i; + } + } + } + } + + //-------------------------------------------------------------------------- + // Free h memory and return success + //-------------------------------------------------------------------------- + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_internal.h b/SPEX/SPEX_Cholesky/Source/spex_cholesky_internal.h new file mode 100644 index 0000000000..67013e6264 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_internal.h @@ -0,0 +1,355 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_internal.h: include file for internal use in SPEX_Cholesky +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// This file is not intended to be #include'd in user applications. Use +// SPEX.h instead. + +#ifndef SPEX_CHOL_INTERNAL_H +#define SPEX_CHOL_INTERNAL_H + +// Definition of SPEX macros, SPEX data structures, etc +#include "spex_util_internal.h" + +// ============================================================================ +// Internal Functions +// ============================================================================ + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//---------Routines to compute and anayze the elimination tree------------------ +// ----These routines are taken and lightly modified from Tim Davis' Csparse---- +// -------------------------www.suitesparse.com--------------------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Routines to compute and postorder the etree +//------------------------------------------------------------------------------ + +/* Purpose: Compute the elimination tree of A */ + +SPEX_info spex_cholesky_etree +( + // Output + int64_t **tree_handle, // On output: contains the elimination tree of A + // On input: undefined. + // Input + const SPEX_matrix A // Input matrix (must be SPD). +) ; + +/* Purpose: post order a forest */ + +SPEX_info spex_cholesky_post +( + // Output + int64_t **post_handle, // On output: post-order of the forest + // On input: undefied + // Input + const int64_t *parent, // Parent[j] is parent of node j in forest + const int64_t n // Number of nodes in the forest +) ; + +/* Purpose: Depth-first search and postorder of a tree rooted at node j */ + +SPEX_info spex_cholesky_tdfs +( + int64_t *k, // Index (kth node) + const int64_t j, // Root node + int64_t *head, // Head of list + int64_t *next, // Next node in the list + int64_t *post, // Post ordered tree + int64_t *stack // Stack of nodes +) ; + +//------------------------------------------------------------------------------ +// Routines to compute the column counts (number of nonzeros per column) of L +//------------------------------------------------------------------------------ + +/* Purpose: consider A(i,j), node j in ith row subtree and return lca(jprev,j) + Used to determine Column counts of cholesky factor*/ + +SPEX_info spex_cholesky_leaf +( + int64_t *lca_handle, // Least common ancestor (jprev,j) + const int64_t i, // Index (subtree i) + const int64_t j, // Index (node j) + const int64_t *first, // first[j] is the first descendant of node j + int64_t *maxfirst, // maxfirst[j] is the maximum first descendant of + // node j + int64_t *prevleaf, // prevleaf[i] is the previous leaf of ith subtree + int64_t *ancestor, // ancestor[i] is the ancestor of ith subtree + int64_t *jleaf // indicates whether j is the first leaf (value of + // 1) or not (value of 2) +) ; + +/* Purpose: Obtain the column counts of an SPD matrix for Cholesky factorization + * This is a modified version of Csparse's cs_chol_counts function + */ + +SPEX_info spex_cholesky_counts +( + // Output + int64_t **c_handle, // On ouptut: column counts + // On input: undefined + // Input + const SPEX_matrix A, // Input matrix + const int64_t *parent, // Elimination tree + const int64_t *post // Post-order of the tree +) ; + +//------------------------------------------------------------------------------ +// Routine to compute the reach (nonzeros of L) using the etree +//------------------------------------------------------------------------------ + +/* Purpose: This function computes the reach of the kth row of A on the + * elimination tree of A. + * On input, k is the iteration of the algorithm, parent contains the + * elimination tree and w is workspace. + * On output, xi[top_handle..n-1] contains the nonzero pattern of the + * kth row of L (or the kth column of L') + */ + +SPEX_info spex_cholesky_ereach +( + // Output + int64_t *top_handle, // On output: starting point of nonzero pattern + // On input: undefined + int64_t *xi, // On output: contains the nonzero pattern in + // xi[top..n-1] + // On input: undefined + // Input + const SPEX_matrix A, // Matrix to be analyzed + const int64_t k, // Node to start at + const int64_t *parent, // Elimination tree of A + int64_t *w // Workspace array +) ; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------Internal REF Chol Factorization Routines------------------- +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + + +/* Purpose: Perform the up-looking Cholesky factorization */ + +SPEX_info spex_cholesky_up_factor +( + // Output + SPEX_matrix* L_handle, // Lower triangular matrix. NULL on input. + SPEX_matrix* rhos_handle, // Sequence of pivots. NULL on input. + // Input + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column pointers of + // L, and the exact number of nonzeros of L. + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // command options +) ; + +/* Purpose: Perform the left-looking Cholesky factorization*/ + +SPEX_info spex_cholesky_left_factor +( + // Output + SPEX_matrix *L_handle, // Lower triangular matrix. NULL on input. + SPEX_matrix *rhos_handle, // Sequence of pivots. NULL on input. + // Input + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column pointers of + // L, and the exact number of nonzeros of L. + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // command options +) ; + +/* Purpose: This function performs a symbolic left-looking factorization. + * On input, A is the matrix to be factored, parent contains the elimination + * tree and S contains the row/column permutations and number of nonzeros in L + * On output, L_handle is allocated to contain the nonzero pattern of L and + * memory for the values. + */ + +SPEX_info spex_cholesky_pre_left_factor +( + // Output + SPEX_matrix *L_handle, // On output: partial L matrix + // On input: undefined + // Input + int64_t *xi, // Workspace nonzero pattern vector + const SPEX_matrix A, // Input Matrix + const SPEX_symbolic_analysis S // Symbolic analysis struct containing the + // number of nonzeros in L, the elimination + // tree, the row/coluimn permutation and its + // inverse +) ; + +/* Purpose: This function performs the symmetric sparse REF triangular solve. + * i.e.,(LD) x = A(:,k). + */ + +SPEX_info spex_cholesky_left_triangular_solve +( + // Output + int64_t *top_output, // On output: the beginning of nonzero pattern of + // L(:,k). The nonzero pattern is contained in + // xi[top_output...n-1] + // On input: undefined + SPEX_matrix x, // On output: Solution of LD x = A(:,k) ==> kth row + // of L but really, the ONLY valid values of x are + // those in x[xi] since x is a working vector its + // other positions are jumbled. + int64_t *xi, // On output: Nonzero pattern vector + // Input + const SPEX_matrix L, // Partial L matrix + const SPEX_matrix A, // Input matrix + const int64_t k, // Iteration of algorithm + const SPEX_matrix rhos, // Partial sequence of pivots + int64_t *h, // History vector + const int64_t *parent, // Elimination tree + int64_t *c // Column pointers of L but they don't point to the + // top position of each column of L. Instead they + // point to the position on each column where the + // next value of L will be grabbed, since at + // iteration k we need to grab the kth of L in + // order to not recompute those values. +) ; + +/* Purpose: This function performs the symmetric sparse REF triangular solve. + * for uplooking Cholesky factorization. i.e., (LD) x = A(1:k-1,k). At the + * given iteration k it computes the k-th column of L' (k-th row of L) + */ + +SPEX_info spex_cholesky_up_triangular_solve +( + //Output + int64_t *top_output, // On input NULL. On output contains the + // beginning of nonzero pattern + // The nonzero pattern is contained in + // xi[top_output...n-1] + int64_t *xi, // Nonzero pattern vector + SPEX_matrix x, // Solution of system ==> kth row of L + // Input + const SPEX_matrix L, // Partial L matrix + const SPEX_matrix A, // Input matrix + const int64_t k, // Iteration of algorithm + const int64_t *parent, // Elimination tree + int64_t *c, // Column pointers + const SPEX_matrix rhos, // sequence of pivots + int64_t *h // History vector +) ; + +/* Purpose: This function performs sparse REF forward substitution for Cholesky + * factorization. On input, x contains the righ hand side vectors, L is the + * Cholesky factor of A and rhos is the sequence of pivots used during + * factorization. On output, x contains the solution to LD x = x Note that + * this function assumes that x is stored as a dense matrix + */ + +SPEX_info spex_cholesky_forward_sub +( + // Input/Output + SPEX_matrix x, // Right hand side matrix. + // On input: contains b + // On output: contains the solution of LD x = x + // Input + const SPEX_matrix L, // REF Cholesky factor of A (lower triangular) + const SPEX_matrix rhos // Sequence of pivots used in factorization +) ; + +/* Purpose: This solves the system L'x = b for Cholesky factorization + * On input, x contains the scaled solution of L D x = b and L is the + * REF Cholesky factor of A. + * On output, x is the solution to the linear system Ax = (det A)b. + */ + +SPEX_info spex_cholesky_backward_sub +( + // Output + SPEX_matrix x, // Solution vector to A x = det(A) * b + // Input + const SPEX_matrix L // The lower triangular matrix +) ; + +/* Purpose: Matrix preordering for integer-preserving Cholesky factorization. + * On input, S is undefined + * On output, S contains the row/column permutation of A + */ + +SPEX_info spex_cholesky_preorder +( + // Output + SPEX_symbolic_analysis *S_handle, // Symbolic analysis data structure + // On input: undefined + // On output: contains the + // row/column permutation and its + // inverse. + // Input + const SPEX_matrix A, // Input matrix + const SPEX_options option // Control parameters (use default if NULL) +) ; + +/* Purpose: Permute the matrix A and return PAP = PAP' + * On input PAP is undefined and A contains the input matrix + * On output PAP contains the permuted matrix (PAP') + */ + +SPEX_info spex_cholesky_permute_A +( + //Output + SPEX_matrix* PAP_handle, // On input: undefined + // On output: contains the permuted matrix + //Input + const SPEX_matrix A, // Input matrix + const bool numeric, // True if user wants to permute pattern and + // numbers, false if only pattern + const SPEX_symbolic_analysis S // Symbolic analysis struct that contains + // row/column permutations +) ; + +/* Purpose: perform the symbolic analysis for the SPEX Cholesky factorization, + * that is, computing and postordering the elimination tree, getting the column + * counts of the SPD matrix A, setting the column pointers and exact number of + * non zeros of L. + */ + +SPEX_info spex_cholesky_symbolic_analysis +( + //Output + SPEX_symbolic_analysis S, // Symbolic analysis + //Input + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // Command options +) ; + +/* Purpose: Compute the REF Cholesky factorization A = LDL' + * only appropriate if A is SPD. + * On input A contains the user's matrix, option->algo indicates which + * factorization algorithm is used; up-looking (default) or left-looking + * On output, L contains the REF Cholesky factor of A, rhos contains + * the REF Cholesky pivot elements and S contains the elimination tree + * lower triangular matrix and rhos contains the pivots' values + * used in the factorization + */ + +SPEX_info spex_cholesky_factor +( + // Output + SPEX_factorization *F_handle, // Cholesky factorization + //Input + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column pointers of + // L, and the exact number of nonzeros of L. + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // Command options + // Notably, option->chol_type indicates whether + // CHOL_UP (default) or CHOL_LEFT is used. +) ; + +#endif diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_leaf.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_leaf.c new file mode 100644 index 0000000000..1ac8814249 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_leaf.c @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_leaf: Subroutine for column counts of Cholesky +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#include "spex_cholesky_internal.h" + +/* Purpose: consider A(i,j), node j in ith row subtree and return + * the Least Common Ancestor (lca(jprev,j)) + * Used to determine Column counts of Cholesky factor + */ + +SPEX_info spex_cholesky_leaf +( + int64_t *lca_handle, // Least common ancestor (jprev,j) + const int64_t i, // Index (subtree i) + const int64_t j, // Index (node j) + const int64_t *first, // first[j] is the first descendant of node j + int64_t *maxfirst, // maxfirst[j] is the maximum first descendant of + // node j + int64_t *prevleaf, // prevleaf[i] is the previous leaf of ith subtree + int64_t *ancestor, // ancestor[i] is the ancestor of ith subtree + int64_t *jleaf // indicates whether j is the first leaf (value of + // 1) or not (value of 2) +) +{ + + *jleaf = 0 ; + if (i <= j || first [j] <= maxfirst [i]) + { + (*lca_handle) = -1; + return (SPEX_OK); // j not a leaf + } + + // Declare variables + int64_t q, s, sparent, jprev ; + + maxfirst [i] = first [j] ; // update max first[j] seen so far + jprev = prevleaf [i] ; // jprev = previous leaf of ith subtree + prevleaf [i] = j ; + (*jleaf) = (jprev == -1) ? 1:2 ; // j is first or subsequent leaf + + if ((*jleaf) == 1) + { + (*lca_handle) = i; + return SPEX_OK ; // if 1st leaf, q = root of ith subtree + } + for (q = jprev ; q != ancestor [q] ; q = ancestor [q]); + for (s = jprev ; s != q ; s = sparent) + { + sparent = ancestor [s] ; // path compression + ancestor [s] = q ; + } + (*lca_handle) = q; + return SPEX_OK ; // q = least common ancestor (jprev,j) +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_left_factor.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_left_factor.c new file mode 100644 index 0000000000..d9c03227e9 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_left_factor.c @@ -0,0 +1,244 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_left_factor: Left-looking REF Chol. factorization +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&x, NULL); \ + SPEX_FREE(xi); \ + SPEX_FREE(h); \ + SPEX_FREE(c); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_matrix_free(&L, NULL); \ + SPEX_matrix_free(&rhos, NULL); \ + SPEX_FREE_WORKSPACE \ +} + +#include "spex_cholesky_internal.h" + +/* Purpose: This function performs the left-looking REF Cholesky factorization. + * In order to compute the L matrix, it performs n iterations of a sparse REF + * symmetric triangular solve function which, at each iteration, computes the + * kth column of L. + * + * Importantly, this function assumes that A has already been permuted. + * + * Input arguments of the function: + * + * L_handle: A handle to the L matrix. Null on input. + * On output, contains a pointer to the L matrix. + * + * rhos_handle: A handle to the sequence of pivots. NULL on input. + * On output it contains a pointer to the pivots matrix. + * + * S: Symbolic analysis struct for Cholesky factorization. + * On input it contains information that is not used in this + * function such as the row/column permutation + * On output it contains the elimination tree and + * the number of nonzeros in L. + * + * A: The user's permuted input matrix + * + * option: Command options + * + */ + +SPEX_info spex_cholesky_left_factor +( + // Output + SPEX_matrix *L_handle, // Lower triangular matrix. NULL on input. + SPEX_matrix *rhos_handle, // Sequence of pivots. NULL on input. + // Input + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column pointers of + // L, and the exact number of nonzeros of L. + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // command options +) +{ + + //-------------------------------------------------------------------------- + // Check inputs + //-------------------------------------------------------------------------- + + SPEX_info info; + ASSERT (A != NULL); + ASSERT (A->type == SPEX_MPZ); + ASSERT (A->kind == SPEX_CSC); + ASSERT (L_handle != NULL); + ASSERT (rhos_handle != NULL); + (*L_handle) = NULL ; + (*rhos_handle) = NULL ; + + //-------------------------------------------------------------------------- + // Declare and initialize workspace + //-------------------------------------------------------------------------- + + SPEX_matrix L = NULL ; + SPEX_matrix rhos = NULL ; + int64_t *xi = NULL ; + int64_t *h = NULL ; + int64_t *c; + SPEX_matrix x = NULL ; + + // Declare variables + int64_t n = A->n, top, i, j, lnz = 0, jnew, k; + int sgn; + size_t size; + + c = (int64_t*) SPEX_malloc(n* sizeof (int64_t)); + + // h is the history vector utilized for the sparse REF + // triangular solve algorithm. h serves as a global + // vector which is repeatedly passed into the triangular + // solve algorithm + h = (int64_t*) SPEX_malloc(n* sizeof(int64_t)); + + // xi serves as a global nonzero pattern vector. It stores + // the pattern of nonzeros of the kth column of L + // for the triangular solve. + xi = (int64_t*) SPEX_malloc(2*n* sizeof(int64_t)); + + if (!h || !xi || !c) + { + SPEX_FREE_WORKSPACE; + return SPEX_OUT_OF_MEMORY; + } + // initialize workspace history array + for (i = 0; i < n; i++) + { + h[i] = -1; + } + + //-------------------------------------------------------------------------- + // Allocate and initialize the workspace x + //-------------------------------------------------------------------------- + + // SPEX utilizes arbitrary sized integers which can grow beyond the + // default 64 bits allocated by GMP. If the integers frequently grow, GMP + // can get bogged down by performing intermediate reallocations. Instead, + // we utilize a larger estimate on the workspace x vector so that computing + // the values in L and U do not require too many extra intermediate calls to + // realloc. + // + // The bound given in the paper is that the number of bits is <= n log sigma + // where sigma is the largest entry in A. Because this bound is extremely + // pessimistic, instead of using this bound, we use a very rough estimate: + // 64*max(2, log (n)) + // + // Note that the estimate presented here is not an upper bound nor a lower + // bound. It is still possible that more bits will be required which is + // correctly handled internally. + int64_t estimate = 64 * SPEX_MAX (2, ceil (log2 ((double) n))); + + // Create x, a "global" dense mpz_t matrix of dimension n*1 (i.e., it is + // used as workspace re-used at each iteration). The second boolean + // parameter is set to false, indicating that the size of each mpz entry + // will be initialized afterwards (and should not be initialized with the + // default size). + SPEX_CHECK (SPEX_matrix_allocate(&x, SPEX_DENSE, SPEX_MPZ, n, 1, n, + false, /* do not initialize the entries of x: */ false, option)); + + // Create rhos, a "global" dense mpz_t matrix of dimension n*1. + // As inidicated with the second boolean parameter true, the mpz entries in + // rhos are initialized to the default size (unlike x). + + SPEX_CHECK (SPEX_matrix_allocate(&(rhos), SPEX_DENSE, SPEX_MPZ, n, 1, n, + false, true, option)); + + // initialize the entries of x + for (i = 0; i < n; i++) + { + // Allocate memory for entries of x + SPEX_MPZ_INIT2(x->x.mpz[i], estimate); + } + + //-------------------------------------------------------------------------- + // Declare memory for L + //-------------------------------------------------------------------------- + + // Since we are performing a left-looking factorization, we pre-allocate L + // by performing a symbolic version of the factorization and obtaining the + // exact nonzero pattern of L. + // That said, the individual (x) values of L are not allocated. Instead, + // a more efficient method to allocate these values is done inside the + // factorization to reduce memory usage. + + SPEX_CHECK(spex_cholesky_pre_left_factor(&(L), xi, A, S)); + + // Set the column pointers of L + for (k = 0; k < n; k++) + { + L->p[k] = c[k] = (S->cp)[k]; + } + + //-------------------------------------------------------------------------- + // Perform the factorization + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // Iterations 0:n-1 (1:n in standard) + //-------------------------------------------------------------------------- + for (k = 0; k < n; k++) + { + // LDx = A(:,k) + SPEX_CHECK(spex_cholesky_left_triangular_solve(&top, x, xi, L, A, k, + rhos, h, S->parent, c)); + + // Set the pivot element If this element is equal to zero, no pivot + // element exists and the matrix is either not SPD or singular + SPEX_MPZ_SGN(&sgn, x->x.mpz[k]); + if (sgn != 0) + { + SPEX_MPZ_SET(rhos->x.mpz[k], x->x.mpz[k]); + } + else + { + // A is not symmetric positive definite + SPEX_FREE_ALL; + return SPEX_NOTSPD; + } + //---------------------------------------------------------------------- + // Add the nonzeros to the L matrix + //---------------------------------------------------------------------- + for (j = top; j < n; j++) + { + // Index of x[i] + jnew = xi[j]; + if (jnew >= k) + { + // Find the size of x[j] + size = mpz_sizeinbase(x->x.mpz[jnew],2); + + // GMP manual: Allocated size should be size+2 + SPEX_MPZ_INIT2(L->x.mpz[lnz], size+2); + + // Place the x value of this nonzero in row jnew of L + SPEX_MPZ_SET(L->x.mpz[lnz],x->x.mpz[jnew]); + + // Increment lnz + lnz += 1; + } + } + } + // Finalize L->p + L->p[n] = S->lnz; + + //-------------------------------------------------------------------------- + // Free memory + //-------------------------------------------------------------------------- + (*L_handle) = L; + (*rhos_handle) = rhos; + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_left_triangular_solve.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_left_triangular_solve.c new file mode 100644 index 0000000000..1caa721e28 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_left_triangular_solve.c @@ -0,0 +1,345 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_left_triangular_solve: sparse symmetric +// left-looking triangular solve +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_ALL ; + +#include "spex_cholesky_internal.h" + +/* Purpose: This function performs the REF triangular solve for left-looking + * REF Cholesky factorization. At iteration k, it solves the linear system + * LD x = A(:,k). Upon completion of this function, x contains the kth column of + * L + * + * Input arguments of the function: + * + * top_output: A pointer to the beginning of the nonzero pattern of L(:,k) + * Undefined on input. On output xi[top_output..n-1] contains + * the beginning of the nonzero pattern. + * + * x: Solution of linear system. Undefined on input. On output + * contains the kth column of L. + * + * xi: Nonzero pattern. Undefined on input. On output contains the + * nonzero pattern of the kth row of L + * + * L: Lower triangular matrix. + * + * A: Input matrix + * + * k: Current iteration of the algorithm (i.e., column of A) + * + * rhos: Sequence of pivots used in factorization + * + * h: History vector. + * + * parent: Elimination tree + * + * c: Column pointers of L but they don't point to the top + * position of each column of L. Instead they point to the + * position on each column where the next value of L will be + * grabbed, since at iteration k we need to grab the kth of L + * in order to not recompute those values. + */ + + +// Comparison function used for the quicksort in the factorization +// Each iteration of the triangular solve requires that the nonzero pattern +// is sorted prior to numeric operations. This is the helper function for +// c's default qsort +static inline int compare (const void * a, const void * b) +{ + return ( *(int64_t*)a - *(int64_t*)b ); +} + +SPEX_info spex_cholesky_left_triangular_solve +( + // Output + int64_t *top_output, // On output: the beginning of nonzero pattern of + // L(:,k). The nonzero pattern is contained in + // xi[top_output...n-1] + // On input: undefined + SPEX_matrix x, // On output: Solution of LD x = A(:,k) ==> kth row + // of L but really, the ONLY valid values of x are + // those in x[xi] since x is a working vector its + // other positions are jumbled. + int64_t *xi, // On output: Nonzero pattern vector + // Input + const SPEX_matrix L, // Partial L matrix + const SPEX_matrix A, // Input matrix + const int64_t k, // Iteration of algorithm + const SPEX_matrix rhos, // Partial sequence of pivots + int64_t *h, // History vector + const int64_t *parent, // Elimination tree + int64_t *c // Column pointers of L but they don't point to the + // top position of each column of L. Instead they + // point to the position on each column where the + // next value of L will be grabbed, since at + // iteration k we need to grab the kth of L in + // order to not recompute those values. +) +{ + + SPEX_info info; + + // Input checks. All pointers are checked by the callersm these are here to + // remind us of the correct formats of each matrix + ASSERT(top_output != NULL); + ASSERT (x != NULL); + ASSERT (xi != NULL); + ASSERT (L != NULL); + ASSERT (A != NULL); + ASSERT (rhos != NULL); + ASSERT (h != NULL); + ASSERT (parent != NULL); + ASSERT (c != NULL); + ASSERT(L->type == SPEX_MPZ); + ASSERT(L->kind == SPEX_CSC); + ASSERT(A->type == SPEX_MPZ); + ASSERT(A->kind == SPEX_CSC); + ASSERT(rhos->type == SPEX_MPZ); + ASSERT(rhos->kind == SPEX_DENSE); + ASSERT(x->type == SPEX_MPZ); + ASSERT(x->kind == SPEX_DENSE); + + int64_t j, i, p, m, top, n; + int sgn; + + // row_top is the start of the nonzero pattern obtained after analyzing the + // elimination tree xi[row_top..n-1] contains the nonzero pattern of the kth + // row of L which is the first k-1 entries of the kth column of L + int64_t row_top; + + //---------------------------------------------------------------- + // Initialize REF Triangular Solve by getting nonzero patern of x + // This is done in two steps: + // 1) Obtain the nonzero pattern of L[1:k-1,k] + // We could get this from L[k,1:k], but it is cheaper to do it with + // ereach. + // 2) Obtain the nonzero pattern of L[k:n,k] + // This is obtained from the preallocation of L + //---------------------------------------------------------------- + + // Obtain dimension of the matrix, which is also the dimension of the dense + // vectors + n = A->n; + ASSERT(n >= 0); + + //---------------------------------------------------------------- + // 1) Obtain the nonzero pattern of L[1:k-1,k] + //---------------------------------------------------------------- + + // Obtain the nonzero pattern of the kth row of L which is entries + // L(1:k-1,k) Note that the left-looking Cholesky factorization performs + // two elimination tree analyses. The first is done prior to here in the + // preallocation of the L matrix. The second, performed here, gets the + // nonzero pattern of L(k,:) (To compute L(:,k) you need the prealocation + // first). + + SPEX_CHECK(spex_cholesky_ereach(&row_top, xi, A, k, parent, c)); + + // After eReach, xi[rowtop..n-1] stores the location of the nonzeros + // located in rows 1:k-1. Note that the values of these nonzeros have + // already been computed by the left-looking algorithm as they lie in row k + // of columns 1:k-1 of L, so we do not need to compute these values from + // scratch however we need to obtain their values. + + //---------------------------------------------------------------- + // 2) Obtain the nonzero pattern of L[1:k-1,k] + //---------------------------------------------------------------- + // Now we populate the remainder of the nonzero pattern + // (i.e., the indices of the nonzeros on rows k:n of L). + // Note that these indices are known + // because L was preallocated prior to factorization. Thus, we simply need + // to iterate across the remainder of the kth column of L. + // Oddly, this 'second' part of the nonzero pattern will be stored in the + // top part of xi. (becuase of how the ereach works, it is easier to store + // the nonzero pattern in rows 1:k-1 in the 'bottom' part of xi). + top = row_top; //top starts in the last position, and it is decreased until + // it reaches the actual top position of xi + for (i = L->p[k]; i < L->p[k+1]; i++) + { + top -= 1; // One more nonzero in column k + xi[top] = L->i[i]; // Index of the new nonzero + } + // At this point xi[top..n-1] contains the FULL nonzero pattern of column k. + // Any entry lying in rows 1:k-1 of L already have their correct final value + // currently stored in L. Any entry lying in rows k:n should take their + // default value in A prior to the left-looking solve. We need the entries + // in rows 1:k-1 of L in order to perform the IPGE_Updates & History_Updates + // that are needed to compute the values of the entries in rows k:n of L. + + //---------------------------------------------------------------- + // Initialize x (only the positions of its nonzeros) + //---------------------------------------------------------------- + + // Reset only the essential positions in the x working vector. That is, so + // that x[i] = 0 for all row indices i located in xi (i.e., the nonzero + // pattern of L(:,k)) (HOWEVER, you don't need to zero out the nonzeros + // that will be grabbed directly from L[k,1:k-1] that is why the loop ends + // in row_top and not in n) + + for (i = top; i < row_top; i++) + { + SPEX_mpz_set_ui(x->x.mpz[ xi[i] ], 0); + } + + SPEX_mpz_set_ui(x->x.mpz[k], 0); + + // Now x[xi] has been zeroed. We obtain the values of any nonzero located in + // L[k,1:k-1] which already reside in the previously computed kth row of L. + // This is done by using the column pointer vector and a helper index p. + for (i = row_top; i < n; i++) + { + m = xi[i]; // m is the row index of the current nonzero. + p = ++c[m]; // this increases the column pointer of the mth column by + // one; because c[m] needs to be pointing to the next place + // on column m where a value will be taken from (when we + // grab another row of L) + mpz_set(x->x.mpz[m], L->x.mpz[p]); + } + + //-------------------------------------------------------------------------- + // Obtain A(:,k) to finish populating L(k+1:n,k) with its starting values. + //-------------------------------------------------------------------------- + for (i = A->p[k]; i < A->p[k+1]; i++) + { + if ( A->i[i] >= k) + { + SPEX_MPZ_SET(x->x.mpz[A->i[i]], A->x.mpz[i]); + } + } + // Sort the nonzero pattern xi using quicksort + qsort(&xi[top], n-top, sizeof(int64_t), compare); + + // Reset the history vector h + for (i = top; i < n; i++) + { + h[xi[i]] = -1; + } + + //-------------------------------------------------------------------------- + // Iterate accross nonzeros in x + //-------------------------------------------------------------------------- + for ( p = top; p < n; p++) + { + /* Finalize x[j] */ + j = xi[p]; // Current nonzero term + // If x[j] == 0 no work must be done (this zero is due to numerical + // cancellation, not a structural/symbolic zero) + SPEX_MPZ_SGN(&sgn, x->x.mpz[j]); + if (sgn == 0) continue; + if (j < k) // j < k implies already computed entries + { + //------------------------------------------------------------------ + // IPGE updates + //------------------------------------------------------------------ + // ----------- Iterate accross nonzeros in Lij --------------------- + for (m = L->p[j]; m < L->p[j+1]; m++) + { + i = L->i[m]; // i value of Lij + if (i >= k) + { + /*************** If lij==0 then no update******************/ + SPEX_MPZ_SGN(&sgn, L->x.mpz[m]); + if (sgn == 0) continue; + + //---------------------------------------------------------- + /************* lij is nonzero, x[i] is zero****************/ + // x[i] = 0 then only perform IPGE update subtraction/div + //---------------------------------------------------------- + SPEX_MPZ_SGN(&sgn, x->x.mpz[i]); + if (sgn == 0) + { + // No previous pivot (because this entry has never been + // updated before) + if (j < 1) + { + SPEX_MPZ_SUBMUL(x->x.mpz[i],L->x.mpz[m], + x->x.mpz[j]);// x[i] = 0 - lij*x[j] + h[i] = j; // Entry is up to date + } + // Previous pivot exists + else + { + SPEX_MPZ_SUBMUL(x->x.mpz[i],L->x.mpz[m], + x->x.mpz[j]);// x[i] = 0 - lij*x[j] + SPEX_MPZ_DIVEXACT(x->x.mpz[i], + x->x.mpz[i], + rhos->x.mpz[j-1]);// x[i] = x[i] / rho[j-1] + h[i] = j; // Entry is up to date + } + } + + //---------------------------------------------------------- + /************ Both lij and x[i] are nonzero****************/ + // x[i] != 0 --> History & IPGE update on x[i] + //---------------------------------------------------------- + else + { + // No previous pivot in this case + if (j < 1) + { + SPEX_MPZ_MUL(x->x.mpz[i],x->x.mpz[i], + rhos->x.mpz[0]); // x[i] = x[i]*rho[0] + SPEX_MPZ_SUBMUL(x->x.mpz[i], L->x.mpz[m], + x->x.mpz[j]);// x[i] = x[i] - lij*xj + h[i] = j; // Entry is now up to date + } + // There is a previous pivot + else + { + // History update if necessary + if (h[i] < j - 1) + { + SPEX_MPZ_MUL(x->x.mpz[i],x->x.mpz[i], + rhos->x.mpz[j-1]);// x[i] = x[i] * rho[j-1] + if (h[i] > -1) + { + SPEX_MPZ_DIVEXACT(x->x.mpz[i], + x->x.mpz[i],rhos->x.mpz[h[i]]); + // x[i] = x[i] / rho[h[i]] + } + } + SPEX_MPZ_MUL(x->x.mpz[i],x->x.mpz[i], + rhos->x.mpz[j]);// x[i] = x[i] * rho[j] + SPEX_MPZ_SUBMUL(x->x.mpz[i], L->x.mpz[m], + x->x.mpz[j]);// x[i] = x[i] - lij*xj + SPEX_MPZ_DIVEXACT(x->x.mpz[i], + x->x.mpz[i], + rhos->x.mpz[j-1]);// x[i] = x[i] / rho[j-1] + h[i] = j; // Entry is up to date + } + } + } + } + } + else // Entries of L + { + //------------------------------------------------------------------ + // History update + //------------------------------------------------------------------ + if (h[j] < k-1) + { + SPEX_MPZ_MUL(x->x.mpz[j],x->x.mpz[j], + rhos->x.mpz[k-1]); // x[j] = x[j] * rho[k-1] + if (h[j] > -1) + { + SPEX_MPZ_DIVEXACT(x->x.mpz[j],x->x.mpz[j], + rhos->x.mpz[h[j]]);// x[j] = x[j] / rho[h[j]] + } + } + } + } + // Output the beginning of nonzero pattern + (*top_output) = top; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_permute_A.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_permute_A.c new file mode 100644 index 0000000000..bcc3a5d7b8 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_permute_A.c @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_permute_A: Symmetric permutation of matrix A +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#include "spex_cholesky_internal.h" + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL { SPEX_matrix_free (&PAP, NULL); } + +/* Purpose: Given the row/column permutation P stored in S, permute the matrix + * A and return PAP' + * Input arguments: + * + * PAP_handle: The user's permuted input matrix. + * + * A: The user's input matrix + * + * S: Symbolic analysis struct for Cholesky factorization. + * Contains row/column permutation of A + */ + +SPEX_info spex_cholesky_permute_A +( + //Output + SPEX_matrix* PAP_handle, // On input: undefined + // On output: contains the permuted matrix + //Input + const SPEX_matrix A, // Input matrix + const bool numeric, // True if user wants to permute pattern and + // numbers, false if only pattern + const SPEX_symbolic_analysis S // Symbolic analysis struct that contains + // row/column permutations +) +{ + + SPEX_info info; + + //-------------------------------------------------------------------------- + // Check inputs + //-------------------------------------------------------------------------- + + ASSERT(A != NULL); + ASSERT(S != NULL); + ASSERT(PAP_handle != NULL); + ASSERT(A->type == SPEX_MPZ); + ASSERT(A->kind == SPEX_CSC); + + // Create indices and pinv, the inverse row permutation + int64_t j, k, t, nz = 0, n = A->n; + (*PAP_handle) = NULL ; + //int64_t *pinv = NULL; + + // Allocate memory for PAP which is a permuted copy of A + SPEX_matrix PAP = NULL ; + SPEX_CHECK(SPEX_matrix_allocate(&PAP, SPEX_CSC, SPEX_MPZ, n, n, A->p[n], + false, true, NULL)); + + if(numeric) + { + + //---------------------------------------------------------------------- + // construct PAP with numerical values + //---------------------------------------------------------------------- + + // Set PAP scale + SPEX_MPQ_SET(PAP->scale, A->scale); + + // Populate the entries in PAP + for (k = 0; k < n; k++) + { + // Set the number of nonzeros in the kth column of PAP + PAP->p[k] = nz; + // Column k of PAP is equal to column S->P_perm[k] of A. j is the + // starting point for nonzeros and indices for column S->P_perm[k] + // of A + j = S->P_perm[k]; + // Iterate across the nonzeros in column S->P_perm[k] + for (t = A->p[j]; t < A->p[j+1]; t++) + { + // Set the nonzero value and location of the entries in column + // k of PAP + SPEX_MPZ_SET(PAP->x.mpz[nz], A->x.mpz[t]); + // Row i of this nonzero is equal to pinv[A->i[t]] + PAP->i[nz] = S->Pinv_perm[ A->i[t] ]; + // Move to the next nonzero element of PAP + nz++; + } + } + } + else + { + + //---------------------------------------------------------------------- + // construct PAP with just its pattern, not the values + //---------------------------------------------------------------------- + + // FUTURE: tell SPEX_matrix_allocate not to allocate PAP->x at all. + SPEX_FREE (PAP->x.mpz); + ASSERT (PAP->x.mpz == NULL); + PAP->x_shallow = true ; + + // Populate the entries in PAP + for (k = 0; k < n; k++) + { + // Set the number of nonzeros in the kth column of PAP + PAP->p[k] = nz; + // Column k of PAP is equal to column S->p[k] of A. j is the + // starting point for nonzeros and indices for column S->p[k] of A + j = S->P_perm[k]; + // Iterate across the nonzeros in column S->p[k] + for (t = A->p[j]; t < A->p[j+1]; t++) + { + // Row i of this nonzero is equal to pinv[A->i[t]] + PAP->i[nz] = S->Pinv_perm[ A->i[t] ]; + // Move to the next nonzero element of PAP + nz++; + } + } + } + + // Finalize the last column of PAP + PAP->p[n] = nz; + // Set output, return success + (*PAP_handle) = PAP; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_post.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_post.c new file mode 100644 index 0000000000..6142df5330 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_post.c @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_post: Postorder a forest +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_FREE (w); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE (post); \ + SPEX_FREE_WORKSPACE ; \ +} + +#include "spex_cholesky_internal.h" + +/* Purpose: post order a forest. */ + +SPEX_info spex_cholesky_post +( + // Output + int64_t **post_handle, // On output: post-order of the forest + // On input: undefied + // Input + const int64_t *parent, // Parent[j] is parent of node j in forest + const int64_t n // Number of nodes in the forest +) +{ + + SPEX_info info ; + + // All inputs have been checked by the caller + ASSERT( n >= 0); + + // Declare variables + int64_t j, k = 0, *post = NULL, *w = NULL, *head, *next, *stack ; + + // Allocate the postordering result + post = (int64_t*) SPEX_malloc(n* sizeof(int64_t)); + + // Create a workspace + w = (int64_t*) SPEX_malloc (3*n* sizeof (int64_t)); + if ((w == NULL) || (post == NULL)) + { + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + head = w ; next = w + n ; stack = w + 2*n ; + + // Empty linked lists + for (j = 0 ; j < n ; j++) + { + head [j] = -1 ; + } + for (j = n-1 ; j >= 0 ; j--) // traverse nodes in reverse order + { + if (parent [j] == -1) continue ; // j is a root + next [j] = head [parent [j]] ; // add j to list of its parent + head [parent [j]] = j ; + } + for (j = 0 ; j < n ; j++) + { + if (parent [j] != -1) continue ; // skip j if it is not a root + SPEX_CHECK(spex_cholesky_tdfs (&k, j, head, next, post, stack)); + } + SPEX_FREE_WORKSPACE ; + (*post_handle) = post; + return (SPEX_OK); +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_pre_left_factor.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_pre_left_factor.c new file mode 100644 index 0000000000..5b42a4e363 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_pre_left_factor.c @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_pre_left_factor: Symbolic left-looking Cholesky +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_FREE(c); \ +} + +# define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE \ + SPEX_matrix_free(&L, NULL); \ +} + +#include "spex_cholesky_internal.h" + + +/* Purpose: This function performs a symbolic left-looking factorization. + * It allocates the memory for the L matrix and determines the full nonzero + * pattern of L + * + * Importantly, this function assumes that A has already been permuted. + * + * Input arguments of the function: + * + * L_handle: A handle to the L matrix. Null on input. + * On output, contains a pointer to the partial L matrix. + * + * xi: Workspace nonzero pattern vector. It stores the pattern of + * nonzeros of the kth column of L for the triangular solve. + * + * A: The user's permuted input matrix + * + * S: Symbolic analysis struct for Cholesky factorization. + * On input it contains information that is not used in this + * function such as the row/column permutation + * On output it contains the number of nonzeros in L. + */ + +SPEX_info spex_cholesky_pre_left_factor +( + // Output + SPEX_matrix *L_handle, // On output: partial L matrix + // On input: undefined + // Input + int64_t *xi, // Workspace nonzero pattern vector + const SPEX_matrix A, // Input Matrix + const SPEX_symbolic_analysis S // Symbolic analysis struct containing the + // number of nonzeros in L, the elimination + // tree, the row/coluimn permutation and its + // inverse +) +{ + + // All inputs have been checked by the caller, thus asserts are used here + // as a reminder of the expected data types + SPEX_info info; + ASSERT(A->kind == SPEX_CSC); + ASSERT(A->type == SPEX_MPZ); + + int64_t top, k, j, jnew, n = A->n, p = 0; + int64_t *c = NULL; + SPEX_matrix L = NULL; + ASSERT(n >= 0); + + //-------------------------------------------------------------------------- + // Declare memory for L and c + //-------------------------------------------------------------------------- + + // Allocate L + SPEX_CHECK(SPEX_matrix_allocate(&L, SPEX_CSC, SPEX_MPZ, n, n, S->lnz, + false, false, NULL)); + + // Allocate c + c = (int64_t*) SPEX_malloc(n* sizeof (int64_t)); + if (!c) + { + SPEX_FREE_ALL; + return SPEX_OUT_OF_MEMORY; + } + + // Set the column pointers of L and c + for (k = 0; k < n; k++) + { + L->p[k] = c[k] = S->cp[k]; + } + + L->i[0] = 0; + c[0]++; + + //-------------------------------------------------------------------------- + // Iterations 1:n-1 + //-------------------------------------------------------------------------- + for (k = 1; k < n; k++) + { + // Obtain nonzero pattern in xi[top..n] + SPEX_CHECK(spex_cholesky_ereach(&top, xi, A, k, S->parent, c)); + + //---------------------------------------------------------------------- + // Iterate accross the nonzeros in x + //---------------------------------------------------------------------- + for (j = top; j < n; j++) + { + jnew = xi[j]; + if (jnew == k) continue; + p = c[jnew]++; + // Place the i location of the next nonzero + L->i[p] = k; + } + p = c[k]++; + L->i[p] = k; + } + // Finalize L->p + L->p[n] = S->lnz; + (*L_handle) = L; + + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_preorder.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_preorder.c new file mode 100644 index 0000000000..4c953fdfff --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_preorder.c @@ -0,0 +1,185 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_preorder: symbolic ordering/analysis for Cholesky +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function performs the symbolic ordering for SPEX Cholesky. + * Currently, there are three options: user-defined order, COLAMD, or AMD. + * It is *highly* recommended that AMD is used for Cholesky factorization. + * + * Input/output arguments: + * + * S: Symbolic analysis struct. Undefined on input; contains column + * permutation and estimates of nnz on output (is the exact + * number of nonzeros if AMD is used) + * + * A: Input matrix, unmodified on input/output + * + * option: option->order tells the function which ordering scheme to use + */ + + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE ; \ + SPEX_symbolic_analysis_free(&S, option); \ +} + +#include "spex_cholesky_internal.h" + +SPEX_info spex_cholesky_preorder +( + // Output + SPEX_symbolic_analysis *S_handle, // Symbolic analysis data structure + // On input: undefined + // On output: contains the + // row/column permutation and its + // inverse. + // Input + const SPEX_matrix A, // Input matrix + const SPEX_options option // Control parameters (use default if NULL) +) +{ + + //-------------------------------------------------------------------------- + // Check inputs + //-------------------------------------------------------------------------- + + SPEX_info info ; + if ( !spex_initialized() ) return SPEX_PANIC; + + // All inputs have been checked by the caller so ASSERTS are used instead + // of ifs A can have any data type, but must be in sparse CSC format + ASSERT(A->type == SPEX_MPZ); + ASSERT(A->kind == SPEX_CSC); + + // m = n for Cholesky factorization + ASSERT(A->n == A->m); + + // Dimension can't be negative + ASSERT(A->n >= 0); + + (*S_handle) = NULL ; + + //-------------------------------------------------------------------------- + // Allocate symbolic analysis object + //-------------------------------------------------------------------------- + + SPEX_symbolic_analysis S = NULL; + + // declare indices and dimension of matrix + int64_t i, k, index, n = A->n; + + int64_t anz; // Number of nonzeros in A + SPEX_CHECK (SPEX_matrix_nnz(&anz, A, option)); + + // Allocate memory for S + S = (SPEX_symbolic_analysis) + SPEX_calloc(1, sizeof(SPEX_symbolic_analysis_struct)); + if (S == NULL) + { + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + + S->kind = SPEX_CHOLESKY_FACTORIZATION ; + + //Check which ordering to use. + SPEX_preorder order = SPEX_OPTION_ORDER(option); + switch(order) + { + default: + case SPEX_DEFAULT_ORDERING: + case SPEX_AMD: + // ---AMD ordering is used (DEFAULT)--- + // S->p is set to AMD's column ordering on A. + // The number of nonzeros in L is given as AMD's computed + // number of nonzeros in the Cholesky factor L of A which is the exact + // nnz(L) for Cholesky factorization (barring numeric cancellation) + { + SPEX_CHECK( spex_amd(&(S->P_perm),&(S->lnz),A,option)); + } + break; + + case SPEX_NO_ORDERING: + // ---No ordering is used--- + // S->p is set to [0 ... n] and the number of nonzeros in L is estimated + // to be 10 times the number of nonzeros in A. + // This is a very crude estimate on the nnz(L) + { + S->P_perm = (int64_t*)SPEX_malloc( (n+1)*sizeof(int64_t) ); + if (S->P_perm == NULL) + { + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + + for (i = 0; i < n+1; i++) + { + S->P_perm[i] = i; + } + // Very crude estimate for number of L and U nonzeros + S->lnz = 10*anz; + } + break; + + case SPEX_COLAMD: + // --- COLAMD ordering is used + // S->p is set as COLAMD's column ordering. + // The number of nonzeros in L is set as 10 times the number of + // nonzeros in A. This is a crude estimate. + { + SPEX_CHECK( spex_colamd(&(S->P_perm),&(S->lnz),A,option)); + } + break; + } + + //-------------------------------------------------------------------------- + // Make sure appropriate space is allocated. It is possible to return + // estimates which exceed the dimension of L or estimates which are + // too small for L. In this case, this block of code ensures that the + // estimates on nnz(L) and nnz(U) are at least n and no more than n*n. + //-------------------------------------------------------------------------- + + // estimate exceeds max number of nnz in A + if (S->lnz > (double) n*n) + { + int64_t nnz = ceil(0.5*n*n); + S->lnz = nnz; + } + // If estimate < n, it is possible that the first iteration of triangular + // solve may fail, so we make sure that the estimate is at least n + if (S->lnz < n) + { + S->lnz += n; + } + + // Allocate pinv + S->Pinv_perm = (int64_t*)SPEX_calloc(n, sizeof(int64_t)); + if(!(S->Pinv_perm)) + { + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + + // Populate pinv + for (k = 0; k < n; k++) + { + index = S->P_perm[k]; + S->Pinv_perm[index] = k; + } + + //-------------------------------------------------------------------------- + // Set result, report success + //-------------------------------------------------------------------------- + + SPEX_FREE_WORKSPACE ; + (*S_handle) = S; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_symbolic_analysis.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_symbolic_analysis.c new file mode 100644 index 0000000000..52836c3fb2 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_symbolic_analysis.c @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_symbolic_analysis: Symbolic analysis for Cholesky +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_FREE(post); \ + SPEX_FREE(c); \ +} + +# define SPEX_FREE_ALL \ +{ \ + SPEX_FREE_WORKSPACE \ +} + +#include "spex_cholesky_internal.h" + +/* Purpose: perform the symbolic analysis for the SPEX Cholesky factorization, + * that is, computing and postordering the elimination tree, getting the column + * counts of the SPD matrix A, setting the column pointers and exact number of + * non zeros of L. + * + * IMPORTANT: This function assumes that A has already been permuted. + * + * Input arguments of the function: + * + * S: Symbolic analysis struct for Cholesky factorization. + * On input it contains information that is not used in this + * function such as the row/column permutation + * On output it contains the elimination tree and + * the number of nonzeros in L. + * + * A: The user's permuted input matrix + * + * option: Command options + */ + +SPEX_info spex_cholesky_symbolic_analysis +( + //Output + SPEX_symbolic_analysis S, // Symbolic analysis + //Input + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // Command options +) +{ + + SPEX_info info; + + //-------------------------------------------------------------------------- + // Check inputs + //-------------------------------------------------------------------------- + + // Inputs are checked by the caller, asserts are here as a reminder of the + // format + ASSERT(A->type == SPEX_MPZ); + ASSERT(A->kind == SPEX_CSC); + + // Declare local variables + int64_t n = A->n; + int64_t *post = NULL; + int64_t *c = NULL; + + // Obtain elimination tree of A + SPEX_CHECK( spex_cholesky_etree(&S->parent, A) ); + + // Postorder the elimination tree of A + SPEX_CHECK( spex_cholesky_post(&post, S->parent, n) ); + + // Get the column counts of A + SPEX_CHECK( spex_cholesky_counts(&c, A, S->parent, post) ); + + // Set the column pointers of L + S->cp = (int64_t*) SPEX_malloc( (n+1)*sizeof(int64_t*)); + if (S->cp == NULL) + { + SPEX_FREE_ALL; + return SPEX_OUT_OF_MEMORY; + } + SPEX_CHECK( spex_cumsum(S->cp, c, n)); + + // Set the exact number of nonzeros in L + S->lnz = S->cp[n]; + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_tdfs.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_tdfs.c new file mode 100644 index 0000000000..a1456cfc4d --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_tdfs.c @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_tdfs: DFS of a tree rooted at a node +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#include "spex_cholesky_internal.h" + + +/* Purpose: Depth-first search and postorder of a tree rooted at node j */ + +SPEX_info spex_cholesky_tdfs +( + int64_t *k, // Index (kth node) + const int64_t j, // Root node + int64_t *head, // Head of list + int64_t *next, // Next node in the list + int64_t *post, // Post ordered tree + int64_t *stack // Stack of nodes +) +{ + + int64_t i, p, top = 0 ; + stack [0] = j ; // place j on the stack + while (top >= 0) // while (stack is not empty) + { + p = stack[top] ; // p = top of stack + i = head[p] ; // i = youngest child of p + if (i == -1) + { + top-- ; // p has no unordered children left + post[(*k)++] = p ; // node p is the kth postordered node + } + else + { + head[p] = next[i] ; // remove i from children of p + stack[++top] = i ; // start dfs on child node i + } + } + return SPEX_OK ; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_up_factor.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_up_factor.c new file mode 100644 index 0000000000..a223426ca0 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_up_factor.c @@ -0,0 +1,259 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_up_factor: Up-looking REF Cholesky factorization +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORKSPACE \ +{ \ + SPEX_matrix_free(&x, NULL); \ + SPEX_FREE(xi); \ + SPEX_FREE(h); \ + SPEX_FREE(c); \ +} + +#define SPEX_FREE_ALL \ +{ \ + SPEX_matrix_free(&L, NULL); \ + SPEX_matrix_free(&rhos, NULL); \ + SPEX_FREE_WORKSPACE \ +} + +#include "spex_cholesky_internal.h" + +/* Purpose: This function performs the up-looking REF Cholesky factorization. + * In order to compute the L matrix, it performs n iterations of a sparse REF + * symmetric triangular solve function which, at each iteration, computes the + * kth row of L. + * + * Importantly, this function assumes that A has already been permuted. + * + * Input arguments of the function: + * + * L_handle: A handle to the L matrix. Null on input. + * On output, contains a pointer to the L matrix. + * + * rhos_handle: A handle to the sequence of pivots. NULL on input. + * On output it contains a pointer to the pivots matrix. + * + * S: Symbolic analysis struct for Cholesky factorization. + * On input it contains information that is not used in this + * function such as the row/column permutation + * On output it contains the elimination tree and + * the number of nonzeros in L. + * + * A: The user's permuted input matrix + * + * option: Command options + * + */ + +SPEX_info spex_cholesky_up_factor +( + // Output + SPEX_matrix* L_handle, // Lower triangular matrix. NULL on input. + SPEX_matrix* rhos_handle, // Sequence of pivots. NULL on input. + // Input + const SPEX_symbolic_analysis S, // Symbolic analysis struct containing the + // elimination tree of A, the column pointers of + // L, and the exact number of nonzeros of L. + const SPEX_matrix A, // Matrix to be factored + const SPEX_options option // command options +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + SPEX_info info; + ASSERT (A != NULL); + ASSERT (A->type == SPEX_MPZ); + ASSERT (A->kind == SPEX_CSC); + ASSERT (L_handle != NULL); + ASSERT (rhos_handle != NULL); + (*L_handle) = NULL ; + (*rhos_handle) = NULL ; + + //-------------------------------------------------------------------------- + // Declare and initialize workspace + //-------------------------------------------------------------------------- + + SPEX_matrix L = NULL ; + SPEX_matrix rhos = NULL ; + int64_t *xi = NULL ; + int64_t *h = NULL ; + SPEX_matrix x = NULL ; + int64_t *c = NULL; + + // Declare variables + int64_t n = A->n, top, i, j, jnew, k; + int sgn, prev_sgn; + size_t size; + + c = (int64_t*) SPEX_malloc(n*sizeof(int64_t)); + + // h is the history vector utilized for the sparse REF + // triangular solve algorithm. h serves as a global + // vector which is repeatedly passed into the triangular + // solve algorithm + h = (int64_t*) SPEX_malloc(n*sizeof(int64_t)); + + // xi serves as a global nonzero pattern vector. It stores + // the pattern of nonzeros of the kth column of L + // for the triangular solve. + xi = (int64_t*) SPEX_malloc(2*n*sizeof(int64_t)); + + if (!h || !xi || !c) + { + SPEX_FREE_WORKSPACE; + return SPEX_OUT_OF_MEMORY; + } + + // initialize workspace history array + for (i = 0; i < n; i++) + { + h[i] = -1; + } + + //-------------------------------------------------------------------------- + // Allocate and initialize the workspace x + //-------------------------------------------------------------------------- + + // SPEX utilizes arbitrary sized integers which can grow beyond the + // default 64 bits allocated by GMP. If the integers frequently grow, GMP + // can get bogged down by performing intermediate reallocations. Instead, + // we utilize a larger estimate on the workspace x vector so that computing + // the values in L and U do not require too many extra intermediate calls to + // realloc. + // + // The bound given in the paper is that the number of bits is <= n log sigma + // where sigma is the largest entry in A. Because this bound is extremely + // pessimistic, instead of using this bound, we use a very rough estimate: + // 64*max(2, log (n)) + // + // Note that the estimate presented here is not an upper bound nor a lower + // bound. It is still possible that more bits will be required which is + // correctly handled internally. + int64_t estimate = 64 * SPEX_MAX (2, ceil (log2 ((double) n))); + + // Create x, a "global" dense mpz_t matrix of dimension n*1 (i.e., it is + // used as workspace re-used at each iteration). The second boolean + // parameter is set to false, indicating that the size of each mpz entry + // will be initialized afterwards (and should not be initialized with the + // default size) + SPEX_CHECK (SPEX_matrix_allocate(&x, SPEX_DENSE, SPEX_MPZ, n, 1, n, + false, /* do not initialize the entries of x: */ false, option)); + + // Create rhos, a "global" dense mpz_t matrix of dimension n*1. + // As indicated with the second boolean parameter true, the mpz entries in + // rhos are initialized to the default size (unlike x). + SPEX_CHECK (SPEX_matrix_allocate(&(rhos), SPEX_DENSE, SPEX_MPZ, n, 1, n, + false, true, option)); + + // initialize the entries of x + for (i = 0; i < n; i++) + { + // Allocate memory for entries of x to be estimate bits + SPEX_MPZ_INIT2(x->x.mpz[i], estimate); + } + + //-------------------------------------------------------------------------- + // Declare memory for L + //-------------------------------------------------------------------------- + + // Since we are performing an up-looking factorization, we allocate + // L without initializing each entry. + // Note that, the inidividual (x) values of L are not allocated. Instead, + // a more efficient method to allocate these values is done inside the + // factorization to reduce memory usage. + + SPEX_CHECK(SPEX_matrix_allocate(&(L), SPEX_CSC, SPEX_MPZ, n, n, S->lnz, + false, false, option)); + + // Set the column pointers of L + for (k = 0; k < n; k++) + { + L->p[k] = c[k] = S->cp[k]; + } + + + //-------------------------------------------------------------------------- + // Perform the up-looking factorization + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // Iterations 0:n-1 (1:n in standard) + //-------------------------------------------------------------------------- + SPEX_MPZ_SGN(&prev_sgn, x->x.mpz[0]); + + for (k = 0; k < n; k++) + { + // LDx = A(:,k) + SPEX_CHECK(spex_cholesky_up_triangular_solve(&top, xi, x, L, A, k, + S->parent, c, rhos, h)); + + // If x[k] is nonzero choose it as pivot. Otherwise, the matrix is + // not SPD (indeed, it may even be singular). + SPEX_MPZ_SGN(&sgn, x->x.mpz[k]); + if (sgn != 0) + { + SPEX_MPZ_SET(rhos->x.mpz[k], x->x.mpz[k]); + } + else + { + // A is not symmetric positive definite + SPEX_FREE_ALL; + return SPEX_NOTSPD; + } + + //---------------------------------------------------------------------- + // Add the nonzeros (i.e. x) to L + //---------------------------------------------------------------------- + int64_t p = 0; + for (j = top; j < n; j++) + { + // Obtain the row index of x[j] + jnew = xi[j]; + if (jnew == k) continue; + + // Determine the column where x[j] belongs to + p = c[jnew]++; + + // Place the i index of this nonzero. Should always be k because at + // iteration k, the up-looking algorithm computes row k of L + L->i[p] = k; + + // Find the number of bits of x[j] + size = mpz_sizeinbase(x->x.mpz[jnew],2); + + // GMP manual: Allocated size should be size+2 + SPEX_MPZ_INIT2(L->x.mpz[p], size+2); + + // Place the x value of this nonzero + SPEX_MPZ_SET(L->x.mpz[p],x->x.mpz[jnew]); + } + // Now, place L(k,k) + p = c[k]++; + L->i[p] = k; + size = mpz_sizeinbase(x->x.mpz[k], 2); + SPEX_MPZ_INIT2(L->x.mpz[p], size+2); + SPEX_MPZ_SET(L->x.mpz[p], x->x.mpz[k]); + } + // Finalize L->p + L->p[n] = S->lnz; + + //-------------------------------------------------------------------------- + // Free memory and set output + //-------------------------------------------------------------------------- + + (*L_handle) = L; + (*rhos_handle) = rhos; + SPEX_FREE_WORKSPACE; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Cholesky/Source/spex_cholesky_up_triangular_solve.c b/SPEX/SPEX_Cholesky/Source/spex_cholesky_up_triangular_solve.c new file mode 100644 index 0000000000..79c5e0bf03 --- /dev/null +++ b/SPEX/SPEX_Cholesky/Source/spex_cholesky_up_triangular_solve.c @@ -0,0 +1,309 @@ +//------------------------------------------------------------------------------ +// SPEX_Cholesky/spex_cholesky_up_triangular_solve: Sparse sym REF tri. solve +//------------------------------------------------------------------------------ + +// SPEX_Cholesky: (c) 2020-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_ALL ; + +#include "spex_cholesky_internal.h" + +/* Purpose: This function performs the symmetric sparse REF triangular solve + * for the up-looking Cholesky factorization. i,e, LD x = A(1:k-1, k). At the + * end of this function, the vector x contains the values of the kth row of the + * integer- preserving matrix L. + * + * Input arguments of the function: + * + * top_output: A pointer to the beginning of the nonzero pattern. Undefined + * on input, on output xi[top_output..n] contains the beginning + * of the nonzero pattern. + * + * xi: Nonzero pattern. Undefined on input, on output contains teh + * nonzero pattern of the kth row of L + * + * x: Solution of linear system. Undefined on input, on output + * contains the kth row of L. + * + * L: Lower triangular matrix. + * + * A: Input matrix + * + * k: Current iteration of the algorithm + * + * parent: Elimination tree + * + * c: Column pointers of L but they don't point to the top + * position of each column of L. Instead they point to the + * position on each column where the next value of L will be + * grabbed, since at iteration k we need to grab the kth of L + * in order to not recompute those values. + * + * rhos: Pivot matrix + * + * h: History vector + */ + +// Comparison function used for the quicksort in the factorization +// Each iteration of the triangular solve requires that the nonzero pattern +// is sorted prior to numeric operations. This is the helper function for +// c's default qsort +static inline int compare (const void * a, const void * b) +{ + return ( *(int64_t*)a - *(int64_t*)b ); +} + +SPEX_info spex_cholesky_up_triangular_solve +( + //Output + int64_t *top_output, // On input NULL. On output contains the + // beginning of nonzero pattern + // The nonzero pattern is contained in + // xi[top_output...n-1] + int64_t *xi, // Nonzero pattern vector + SPEX_matrix x, // Solution of system ==> kth row of L + // Input + const SPEX_matrix L, // Partial L matrix + const SPEX_matrix A, // Input matrix + const int64_t k, // Iteration of algorithm + const int64_t *parent, // Elimination tree + int64_t *c, // Column pointers + const SPEX_matrix rhos, // sequence of pivots + int64_t *h // History vector +) +{ + + SPEX_info info; + + // All inputs are checked by the caller. Here we include + // asserts as a reminder of the expected data types of the inputs + ASSERT(L->type == SPEX_MPZ); + ASSERT(L->kind == SPEX_CSC); + ASSERT(A->type == SPEX_MPZ); + ASSERT(A->kind == SPEX_CSC); + ASSERT(x->type == SPEX_MPZ); + ASSERT(x->kind == SPEX_DENSE); + ASSERT(rhos->type == SPEX_MPZ); + ASSERT(rhos->kind == SPEX_DENSE); + + int64_t j, i, p, m, top, n = A->n; + int sgn; + + ASSERT(n >= 0); + + //-------------------------------------------------------------------------- + // Initialize REF Triangular Solve by getting the nonzero patern of x && + // obtaining A(:,k) + //-------------------------------------------------------------------------- + // Obtain the nonzero pattern of the kth row of L by analyzing the + // elimination tree of A. The indices of these nonzeros are stored in + // xi[top..n-1] + SPEX_CHECK(spex_cholesky_ereach(&top, xi, A, k, parent, c)); + + // Sort the nonzero pattern using quicksort (required by IPGE unlike in GE) + qsort(&xi[top], n-top, sizeof(int64_t*), compare); + + // Reset x[i] = 0 for all i in nonzero pattern xi [top..n-1] + for (i = top; i < n; i++) + { + SPEX_MPZ_SET_UI(x->x.mpz[xi[i]],0); + } + + // Reset value of x[k]. If the matrix is nonsingular, x[k] will + // be a part of the nonzero pattern and reset in the above loop. + // However, in some rare cases, the matrix can be singular but x[k] + // will be nonzero from a previous iteration. Thus, here we reset + // x[k] to account for this extremely rare case. + SPEX_MPZ_SET_UI(x->x.mpz[k],0); + + // Reset h[i] = -1 for all i in nonzero pattern + for (i = top; i < n; i++) + { + h[xi[i]] = -1; + } + + // Set x = A(:,k) + // Note: The if is needed since the columns of A are allowed to be unsorted. + for (i = A->p[k]; i < A->p[k+1]; i++) + { + if (A->i[i] <= k) + { + SPEX_MPZ_SET(x->x.mpz[A->i[i]], A->x.mpz[i]); + } + } + + //-------------------------------------------------------------------------- + // Perform the REF Triangular Solve. Note that, unlike the left-looking + // Cholesky triangular solve where L is lower trapezoidal, the up-looking L + // matrix is actually lower triangular; thus this is a true triangular + // solve. + //-------------------------------------------------------------------------- + for (p = top; p < n; p++) + { + // Obtain the index of the current nonzero + j = xi[p]; + SPEX_MPZ_SGN(&sgn, x->x.mpz[j]); + if (sgn == 0) continue; // If x[j] == 0 no work must be done + + // Initial history update to finalize x[j] if necessary + if (h[j] < j-1) + { + // History update x[j]: x[j] = x[j]*rhos[j-1]/rhos[h[j]] + // x[j] = x[j]*rhos[j-1] + SPEX_MPZ_MUL(x->x.mpz[j], x->x.mpz[j], + rhos->x.mpz[j-1]); + if (h[j] > -1) + { + // x[j] = x[j] / rhos [ h[j] ] + SPEX_MPZ_DIVEXACT(x->x.mpz[j], x->x.mpz[j], + rhos->x.mpz[h[j]]); + } + } + + //------------------------------------------------------------------ + // IPGE updates + //------------------------------------------------------------------ + // ----------- Iterate accross nonzeros in Lij --------------------- + for (m = L->p[j]+1; m < c[j]; m++) + { + i = L->i[m]; // i value of Lij + if (i > j && i < k) // Update all dependent x[i] excluding x[k] + { + /*************** If lij==0 then no update******************/ + SPEX_MPZ_SGN(&sgn, L->x.mpz[m]); + if (sgn == 0) continue; + + //---------------------------------------------------------- + /************* lij is nonzero, x[i] is zero****************/ + // x[i] = 0 then only perform IPGE update subtraction/division + //---------------------------------------------------------- + SPEX_MPZ_SGN(&sgn, x->x.mpz[i]); + if (sgn == 0) + { + // First, get the correct value of x[i] = 0 - lij * x[j] + SPEX_MPZ_MUL(x->x.mpz[i], L->x.mpz[m], + x->x.mpz[j]); + SPEX_MPZ_NEG(x->x.mpz[i],x->x.mpz[i]); + // Do a division by the pivot if necessary. + if (j >= 1) + { + // x[i] = x[i] / rho[j-1] + SPEX_MPZ_DIVEXACT(x->x.mpz[i], x->x.mpz[i], + rhos->x.mpz[j-1]); + } + // Update the history value of x[i] + h[i] = j; + + } + + //---------------------------------------------------------- + /************ Both lij and x[i] are nonzero****************/ + // x[i] != 0 --> History & IPGE update on x[i] + //---------------------------------------------------------- + else + { + // There is no previous pivot + if (j < 1) + { + // History update x[i] = x[i]*rhos[0] + SPEX_MPZ_MUL(x->x.mpz[i],x->x.mpz[i], + rhos->x.mpz[0]); + // x[i] = x[i] - lij x[j] + SPEX_MPZ_SUBMUL(x->x.mpz[i], L->x.mpz[m], + x->x.mpz[j]); + // Update the history value of x[i] + h[i] = j; + } + // There is a previous pivot + else + { + // History update if necessary + if (h[i] < j - 1) + { + // x[i] = x[i] * rhos[j-1] + SPEX_MPZ_MUL(x->x.mpz[i],x->x.mpz[i], + rhos->x.mpz[j-1]); + // Divide by the history pivot only if the history + // pivot is not the rho[-1] (which equals 1) (rho[0] + // in the 1-based logic of othe IPGE algorithm) + if (h[i] > -1) + { + // x[i] = x[i] / rho[h[i]] + SPEX_MPZ_DIVEXACT(x->x.mpz[i], + x->x.mpz[i],rhos->x.mpz[h[i]]); + } + } + // ---- IPGE Update : + // x[i] = (x[i]*rhos[j] - lij*xj) / rho[j-1] + // x[i] = x[i]*rhos[j] + SPEX_MPZ_MUL(x->x.mpz[i],x->x.mpz[i], + rhos->x.mpz[j]); + // x[i] = x[i] - lij*xj + SPEX_MPZ_SUBMUL(x->x.mpz[i], L->x.mpz[m], + x->x.mpz[j]); + // x[i] = x[i] / rho[j-1] + SPEX_MPZ_DIVEXACT(x->x.mpz[i],x->x.mpz[i], + rhos->x.mpz[j-1]); + // Entry is up to date; + h[i] = j; + } + } + } + } + // ------ History Update x[k] if necessary ----- + if (h[k] < j - 1) + { + // x[k] = x[k] * rho[j-1] + SPEX_MPZ_MUL(x->x.mpz[k],x->x.mpz[k],rhos->x.mpz[j-1]); + // Divide by the history pivot only if the history pivot is not the + // rho[-1] (which equals 1) (rho[0] in the 1-based logic of the + // IPGE algorithm) + if (h[k] > -1) + { + // x[k] = x[k] / rho[h[k]] + SPEX_MPZ_DIVEXACT(x->x.mpz[k],x->x.mpz[k], + rhos->x.mpz[h[k]]); + } + } + // ---- IPGE Update x[k] = (x[k]*rhos[j] - xj*xj) / rho[j-1] ------ + // x[k] = x[k] * rho[j] + SPEX_MPZ_MUL(x->x.mpz[k],x->x.mpz[k],rhos->x.mpz[j]); + // x[k] = x[k] - xj*xj + SPEX_MPZ_SUBMUL(x->x.mpz[k], x->x.mpz[j], x->x.mpz[j]); + // Only divide by previous pivot if the previous pivot is not 1 (which + // is always the case in the first IPGE iteration) + if (j > 0) + // x[k] = x[k] / rho[j-1] + SPEX_MPZ_DIVEXACT(x->x.mpz[k],x->x.mpz[k], + rhos->x.mpz[j-1]); + // Entry is up to date; + h[k] = j; + } + //---------------------------------------------------------- + // At this point, x[k] has been updated throughout the + // triangular solve. The last step is to make sure x[k] + // has its correct final value. Thus, a final history + // update is done to x[k] if necessary + //---------------------------------------------------------- + if (h[k] < k-1) + { + // x[k] = x[k] * rhos[k-1] + SPEX_MPZ_MUL(x->x.mpz[k], x->x.mpz[k], rhos->x.mpz[k-1]); + // Only divide by previous pivot if the previous pivot is not 1 (which + // is always the case in the first IPGE iteration) + if (h[k] > -1) + { + // x[k] = x[k] / rhos[h[k]] + SPEX_MPZ_DIVEXACT(x->x.mpz[k], x->x.mpz[k], + rhos->x.mpz[ h[k]]); + } + } + // Output the top of the nonzero pattern + (*top_output) = top; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Left_LU/License/CONTRIBUTOR-LICENSE.txt b/SPEX/SPEX_LU/License/CONTRIBUTOR-LICENSE.txt similarity index 97% rename from SPEX/SPEX_Left_LU/License/CONTRIBUTOR-LICENSE.txt rename to SPEX/SPEX_LU/License/CONTRIBUTOR-LICENSE.txt index 68e035b4e9..96d0a1fdb5 100644 --- a/SPEX/SPEX_Left_LU/License/CONTRIBUTOR-LICENSE.txt +++ b/SPEX/SPEX_LU/License/CONTRIBUTOR-LICENSE.txt @@ -1,6 +1,6 @@ -SPEX Individual Contributor License Agreement +SPEX_LU Individual Contributor License Agreement -Thank you for your interest in contributing to SPEX ("We" or "Us"). +Thank you for your interest in contributing to SPEX_LU ("We" or "Us"). This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please sign it and send it @@ -161,8 +161,8 @@ software project managed by Us. any limited remedy to the maximum extent possible under law. Us -Christopher Lourenco, and all SPEX co-authors: +All SPEX_LU co-authors: +Christopher Lourenco Jinhao Chen Timothy A. Davis Erick Moreno-Centeno - diff --git a/SPEX/SPEX_LU/License/GPLv2.txt b/SPEX/SPEX_LU/License/GPLv2.txt new file mode 100644 index 0000000000..d159169d10 --- /dev/null +++ b/SPEX/SPEX_LU/License/GPLv2.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/SPEX/SPEX_LU/License/lesserv3.txt b/SPEX/SPEX_LU/License/lesserv3.txt new file mode 100644 index 0000000000..fc8a5de7ed --- /dev/null +++ b/SPEX/SPEX_LU/License/lesserv3.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/SPEX/SPEX_Left_LU/License/license.txt b/SPEX/SPEX_LU/License/license.txt similarity index 82% rename from SPEX/SPEX_Left_LU/License/license.txt rename to SPEX/SPEX_LU/License/license.txt index 54f28eafc4..5174d2bd10 100644 --- a/SPEX/SPEX_Left_LU/License/license.txt +++ b/SPEX/SPEX_LU/License/license.txt @@ -1,14 +1,13 @@ -SPEX_Left_LU: a Sparse Left-looking Integer-Preserving LU Factorization +SPEX_LU: a Sparse Left-looking Integer-Preserving LU Factorization -Copyright (c) 2019-2022, Christopher Lourenco, JinHao Chen, Erick Moreno- -Centeno, and Timothy A. Davis. +Copyright (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. Available at: - https://github.com/clouren/SPEX http://suitesparse.com -Contact Chris Lourenco, chrisjlourenco@gmail.com, or Tim Davis +Contact Christopher Lourenco, chrisjlourenco@gmail.com, or Tim Davis (timdavis@aldenmath.com or DrTimothyAldenDavis@gmail.com) for a commercial license. diff --git a/SPEX/SPEX_Left_LU/README.md b/SPEX/SPEX_LU/README.md similarity index 68% rename from SPEX/SPEX_Left_LU/README.md rename to SPEX/SPEX_LU/README.md index 8a01b3e99d..cad52b6cf8 100644 --- a/SPEX/SPEX_Left_LU/README.md +++ b/SPEX/SPEX_LU/README.md @@ -1,12 +1,12 @@ -SPEX_Left_LU is software package used to solve a sparse systems of linear equations +SPEX_LU is software package used to solve a sparse systems of linear equations exactly using the Sparse Left-looking Integer-Preserving LU factorization. -*********SPEX_Left_LU********* +*********SPEX_LU********* Purpose: Exactly solve a sparse system of linear equations using a given input matrix and right hand side vector file. This code can output the final solution to a user specified output file in either double precision or - full precision rational numbers. If you intend to use SPEX_Left_LU within + full precision rational numbers. If you intend to use SPEX_LU within another program, refer to examples for help with this. ./spexlu_demo followed by the listed args: @@ -15,11 +15,11 @@ help. e.g., ./spexlu_demo help, which indicates to print to guideline for using this function. f (or file) Filename. e.g., ./spexlu_demo f MATRIX_NAME RHS_NAME, which indicates -SPEX_Left_LU will read matrix from MATRIX_NAME and right hand side from RHS_NAME. +SPEX_LU will read matrix from MATRIX_NAME and right hand side from RHS_NAME. For this demo, the matrix is stored in a triplet format. Refer to -SPEX_Left_LU/ExampleMats for examples. +SPEX_LU/ExampleMats for examples. -p (or piv) Pivot_param. e.g., ./spexlu_demo p 0, which indicates SPEX_Left_LU will use +p (or piv) Pivot_param. e.g., ./spexlu_demo p 0, which indicates SPEX_LU will use smallest pivot for pivot scheme. Other available options are listed as follows: 0: Smallest pivot @@ -29,35 +29,28 @@ as follows: 4: Diagonal pivoting with tolerance for largest pivot 5: Largest pivot -q (or col) Column_order_param. e.g., ./spexlu_demo q 0, which indicates SPEX_Left_LU +q (or col) Column_order_param. e.g., ./spexlu_demo q 0, which indicates SPEX_LU will use COLAMD for column ordering. Other available options are: 0: None: Not recommended for sparse matrices 1: COLAMD: Default 2: AMD -t (or tol) tolerance_param. e.g., ./spexlu_demo t 1e-10, which indicates SPEX_Left_LU +t (or tol) tolerance_param. e.g., ./spexlu_demo t 1e-10, which indicates SPEX_LU will use 1e-10 as the tolerance for pivot scheme 3 and 4 mentioned above. Therefore, it is only necessary if pivot scheme 3 or 4 is used. -o (or out). e.g., ./spexlu_demo o 1, which indicates SPEX_Left_LU will output the +o (or out). e.g., ./spexlu_demo o 1, which indicates SPEX_LU will output the errors and warnings during the process. Other available options are: 0: print nothing 1: just errors and warnings: Default - 2: terse, with basic stats from COLAMD/AMD and SPEX and solution + 2: terse, with basic stats from COLAMD/AMD and SLIP and solution -If none of the above args is given, they are set to the following default: - - mat_name = "../ExampleMats/10teams_mat.txt" - rhs_name = "../ExampleMats/10teams_v.txt" - p = 3, - q = 1, - t = 1, *********example********* -Purpose: Demonstrate the simple interface of SPEX_Left_LU for a randomly generated +Purpose: Demonstrate the simple interface of SPEX_LU for a randomly generated matrix *********example2********* -Purpose: Demonstrate the simple interface of SPEX_Left_LU for a matrix to be read in +Purpose: Demonstrate the simple interface of SPEX_LU for a matrix to be read in diff --git a/SPEX/SPEX_LU/Source/SPEX_lu_analyze.c b/SPEX/SPEX_LU/Source/SPEX_lu_analyze.c new file mode 100644 index 0000000000..970a4347b7 --- /dev/null +++ b/SPEX/SPEX_LU/Source/SPEX_lu_analyze.c @@ -0,0 +1,160 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_lu_analyze: symbolic ordering and analysis for sparse LU +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function performs the symbolic ordering for unsymmetric + * matrices. Currently, there are three options: user-defined order, COLAMD, + * or AMD. + * + * Input/output arguments: + * + * S: Symbolic analysis struct. Undefined on input; contains column + * permutation and estimates of nnz(L) and nnz(U) nnz on output + * + * A: Input matrix, unmodified on input/output + * + * option: option->order tells the function which ordering scheme to use + * + */ + +#define SPEX_FREE_ALL \ +{ \ + SPEX_symbolic_analysis_free (&S, option); \ +} + +#include "spex_lu_internal.h" + +SPEX_info SPEX_lu_analyze +( + SPEX_symbolic_analysis *S_handle, // symbolic analysis including + // column perm. and nnz of L and U + const SPEX_matrix A, // Input matrix + const SPEX_options option // Control parameters, if NULL, use default +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + if (!spex_initialized()) return SPEX_PANIC; + SPEX_info info ; + + // A can have any data type, but must be in sparse CSC format + SPEX_REQUIRE_KIND (A, SPEX_CSC); + + if (!S_handle) + { + return SPEX_INCORRECT_INPUT; + } + (*S_handle) = NULL; + if (A->n != A->m) + { + return SPEX_INCORRECT_INPUT; + } + + //-------------------------------------------------------------------------- + // allocate symbolic analysis object + //-------------------------------------------------------------------------- + + SPEX_symbolic_analysis S = NULL ; + int64_t i, n = A->n, anz; + // SPEX enviroment is checked to be init'ed and A is checked to be not NULL + // and a SPEX_CSC kind, so there shouldnt be any error from this function + SPEX_matrix_nnz(&anz, A, option); + + // ALlocate memory for S + S = (SPEX_symbolic_analysis) SPEX_calloc(1, + sizeof(SPEX_symbolic_analysis_struct)); + if (S == NULL) {return SPEX_OUT_OF_MEMORY;} + S->kind = SPEX_LU_FACTORIZATION; + + //-------------------------------------------------------------------------- + // No ordering is used. S->Q_perm is set to [0...n] and the number of + // nonzeros in L and U is estimated to be 10 times the number of nonzeros + // in A. This is a very crude estimate on the nnz(L) and nnz(U) + //-------------------------------------------------------------------------- + + SPEX_preorder order = SPEX_OPTION_ORDER (option); + switch(order) + { + default: + case SPEX_DEFAULT_ORDERING: + case SPEX_COLAMD: + // ---COLAMD ordering is used (DEFAULT)--- + // S->q is set to COLAMD's column ordering on A. + + { + SPEX_CHECK( spex_colamd(&(S->Q_perm),&(S->unz),A,option)); + S->lnz = S->unz; + } + break; + + case SPEX_NO_ORDERING: + // ---No ordering is used--- + // S->q is set to [0 ... n] and the number of nonzeros in L is estimated + // to be 10 times the number of nonzeros in A. + // This is a very crude estimate on the nnz(L) + { + S->Q_perm = (int64_t*)SPEX_malloc( (n+1)*sizeof(int64_t) ); + if (S->Q_perm == NULL) + { + // out of memory + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + for (i = 0; i < n+1; i++) + { + S->Q_perm[i] = i; + } + // Very crude estimate for number of L and U nonzeros + S->lnz = S->unz = 10*anz; + } + break; + + case SPEX_AMD: + // --- AMD ordering is used + // S->q is set as AMD's column ordering. + { + SPEX_CHECK( spex_amd(&(S->Q_perm),&(S->unz),A,option)); + S->lnz = S->unz; + } + break; + } + + //-------------------------------------------------------------------------- + // Make sure appropriate space is allocated. It's possible to return + // estimates which exceed the dimension of L and U or estimates which are + // too small for L U. In this case, this block of code ensures that the + // estimates on nnz(L) and nnz(U) are at least n and no more than n*n. + //-------------------------------------------------------------------------- + // estimate exceeds max number of nnz in A + if (S->lnz > (double) n*n) + { + int64_t nnz = ceil(0.5*n*n); + S->lnz = S->unz = nnz; + } + // If estimate < n, first column of triangular solve may fail + if (S->lnz < n) + { + S->lnz = S->lnz + n; + } + if (S->unz < n) + { + S->unz = S->unz + n; + } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + (*S_handle) = S ; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_backslash.c b/SPEX/SPEX_LU/Source/SPEX_lu_backslash.c similarity index 53% rename from SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_backslash.c rename to SPEX/SPEX_LU/Source/SPEX_lu_backslash.c index 849fa0f22a..8739db221c 100644 --- a/SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_backslash.c +++ b/SPEX/SPEX_LU/Source/SPEX_lu_backslash.c @@ -1,20 +1,20 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/SPEX_Left_LU_backslash: solve Ax=b, returning solution as desired data type +// SPEX_LU/SPEX_lu_backslash: solve Ax=b, return solution as desired data type //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -/* Purpose: This code utilizes the SPEX Left LU factorization to exactly solve the - * linear system Ax = b. This is essentially an exact version of - * MATLAB sparse backslash +/* Purpose: This code utilizes the SPEX Left LU factorization to exactly solve + * the linear system Ax = b. This is essentially an exact version of MATLAB + * sparse backslash * * Input/Output arguments: * - * X_handle: A pointer to the solution of the linear system. The output is + * x_handle: A pointer to the solution of the linear system. The output is * allowed to be returned in either double precision, mpfr_t, or * rational mpq_t * @@ -24,36 +24,33 @@ * A: User's input matrix. It must be populated prior to calling this * function. * - * b: Collection of right hand side vectors. Must be populated prior to - * factorization. + * b: Collection of right hand side vectors. Must be populated prior + * to factorization. * - * option: Struct containing various command parameters for the factorization. If - * NULL on input, default values are used. + * option: Struct containing various command parameters for the + * factorization. If NULL on input, default values are used. */ -# define SPEX_FREE_WORK \ - SPEX_matrix_free(&L, NULL); \ - SPEX_matrix_free(&U, NULL); \ - SPEX_FREE(pinv); \ - SPEX_matrix_free(&rhos, NULL); \ - SPEX_LU_analysis_free (&S, NULL); +# define SPEX_FREE_WORKSPACE \ + SPEX_factorization_free(&F, option); \ + SPEX_symbolic_analysis_free (&S, option); # define SPEX_FREE_ALL \ - SPEX_FREE_WORK \ + SPEX_FREE_WORKSPACE \ SPEX_matrix_free(&x, NULL); \ -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" -SPEX_info SPEX_Left_LU_backslash +SPEX_info SPEX_lu_backslash ( // Output - SPEX_matrix **X_handle, // Final solution vector + SPEX_matrix *x_handle, // Final solution vector // Input - SPEX_type type, // Type of output desired - // Must be SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *b, // Right hand side vector(s) - const SPEX_options* option // Command options + SPEX_type type, // Type of output desired. Must be + // SPEX_MPQ, SPEX_MPFR, or SPEX_FP64 + const SPEX_matrix A, // Input matrix + const SPEX_matrix b, // Right hand side vector(s) + const SPEX_options option // Command options ) { @@ -62,52 +59,43 @@ SPEX_info SPEX_Left_LU_backslash //------------------------------------------------------------------------- SPEX_info info ; - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!spex_initialized ( )) return (SPEX_PANIC); - if (X_handle == NULL) + if (x_handle == NULL) { return SPEX_INCORRECT_INPUT; } - (*X_handle) = NULL; + (*x_handle) = NULL; if (type != SPEX_MPQ && type != SPEX_FP64 && type != SPEX_MPFR) { return SPEX_INCORRECT_INPUT; } - SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ) ; - SPEX_REQUIRE (b, SPEX_DENSE, SPEX_MPZ) ; + SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ); + SPEX_REQUIRE (b, SPEX_DENSE, SPEX_MPZ); - SPEX_matrix *L = NULL ; - SPEX_matrix *U = NULL ; - SPEX_matrix *x = NULL; - int64_t *pinv = NULL ; - SPEX_matrix *rhos = NULL ; - SPEX_LU_analysis *S = NULL; + SPEX_symbolic_analysis S = NULL; + SPEX_factorization F = NULL ; + SPEX_matrix x = NULL; //-------------------------------------------------------------------------- // Symbolic Analysis //-------------------------------------------------------------------------- - SPEX_CHECK(SPEX_LU_analyze(&S, A, option)); + SPEX_CHECK(SPEX_lu_analyze(&S, A, option)); //-------------------------------------------------------------------------- // LU Factorization //-------------------------------------------------------------------------- - SPEX_CHECK(SPEX_Left_LU_factorize(&L, &U, &rhos, &pinv, A, S, option)); + SPEX_CHECK(SPEX_lu_factorize(&F, A, S, option)); //-------------------------------------------------------------------------- // Solve //-------------------------------------------------------------------------- - SPEX_CHECK (SPEX_Left_LU_solve (&x, b, A, - (const SPEX_matrix *) L, - (const SPEX_matrix *) U, - (const SPEX_matrix *) rhos, - S, - (const int64_t *) pinv, - option)) ; + SPEX_CHECK (SPEX_lu_solve (&x, F, b, option)); //-------------------------------------------------------------------------- // Now, x contains the exact solution of the linear system in mpq_t @@ -116,21 +104,21 @@ SPEX_info SPEX_Left_LU_backslash if (type == SPEX_MPQ) { - (*X_handle) = x ; + (*x_handle) = x ; } else { - SPEX_matrix* x2 = NULL ; - SPEX_CHECK (SPEX_matrix_copy (&x2, SPEX_DENSE, type, x, option)) ; - (*X_handle) = x2 ; - SPEX_matrix_free (&x, NULL) ; + SPEX_matrix x2 = NULL ; + SPEX_CHECK (SPEX_matrix_copy (&x2, SPEX_DENSE, type, x, option)); + (*x_handle) = x2 ; + SPEX_matrix_free (&x, NULL); } //-------------------------------------------------------------------------- // Free memory //-------------------------------------------------------------------------- - SPEX_FREE_WORK ; - return (SPEX_OK) ; + SPEX_FREE_WORKSPACE ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_factorize.c b/SPEX/SPEX_LU/Source/SPEX_lu_factorize.c similarity index 68% rename from SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_factorize.c rename to SPEX/SPEX_LU/Source/SPEX_lu_factorize.c index 8129310f89..eac7505861 100644 --- a/SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_factorize.c +++ b/SPEX/SPEX_LU/Source/SPEX_lu_factorize.c @@ -1,56 +1,46 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/SPEX_Left_LU_factorize: exact sparse LU factorization +//----------------------------------------------------------------------------- +// SPEX_LU/SPEX_lu_factorize: exact sparse LU factorization //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -/* Purpose: This function performs the SPEX Left LU factorization. This - * factorization is done via n iterations of the sparse REF triangular solve - * function. The overall factorization is PAQ = LDU - * The determinant of A can be obtained as determinant = rhos[n-1] +/* Purpose: This internal function performs the SPEX Left LU factorization, but + * does not free the row permutation when finished. This factorization is done + * via n iterations of the sparse REF triangular solve function. The overall + * factorization is PAQ = LDU The determinant of A can be obtained as + * determinant = rhos[n-1] * - * L: undefined on input, created on output - * U: undefined on input, created on output - * rhos: undefined on input, created on output - * pinv: undefined on input, created on output + * F: undefined on input, created on output * * A: input only, not modified * S: input only, not modified * option: input only, not modified */ -#define SPEX_FREE_WORK \ +#define SPEX_FREE_WORKSPACE \ SPEX_matrix_free(&x, NULL); \ SPEX_FREE(xi); \ SPEX_FREE(h); \ SPEX_FREE(pivs); \ - SPEX_FREE(row_perm); \ #define SPEX_FREE_ALL \ - SPEX_FREE_WORK \ - SPEX_matrix_free(&L, NULL); \ - SPEX_matrix_free(&U, NULL); \ - SPEX_matrix_free(&rhos, NULL); \ - SPEX_FREE(pinv); + SPEX_FREE_WORKSPACE; \ + SPEX_factorization_free(&F, option); -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" -SPEX_info SPEX_Left_LU_factorize +SPEX_info SPEX_lu_factorize ( // output: - SPEX_matrix **L_handle, // lower triangular matrix - SPEX_matrix **U_handle, // upper triangular matrix - SPEX_matrix **rhos_handle, // sequence of pivots - int64_t **pinv_handle, // inverse row permutation + SPEX_factorization *F_handle, // LU factorization // input: - const SPEX_matrix *A, // matrix to be factored - const SPEX_LU_analysis *S, // column permutation and estimates - // of nnz in L and U - const SPEX_options* option // command options + const SPEX_matrix A, // matrix to be factored + const SPEX_symbolic_analysis S, // symbolic analysis + const SPEX_options option // command options ) { @@ -58,46 +48,56 @@ SPEX_info SPEX_Left_LU_factorize // check inputs //-------------------------------------------------------------------------- - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!spex_initialized ( )) return (SPEX_PANIC); - SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ) ; + SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ); int64_t anz; // SPEX enviroment is checked to be init'ed and A is a SPEX_CSC matrix that // is not NULL, so SPEX_matrix_nnz must return SPEX_OK - SPEX_info info = SPEX_matrix_nnz (&anz, A, option) ; + SPEX_info info = SPEX_matrix_nnz (&anz, A, option); ASSERT(info == SPEX_OK); - if (!L_handle || !U_handle || !rhos_handle || !pinv_handle || !S || anz < 0) + if (!F_handle || !S || anz < 0) { return SPEX_INCORRECT_INPUT; } - (*L_handle) = NULL ; - (*U_handle) = NULL ; - (*rhos_handle) = NULL ; - (*pinv_handle) = NULL ; + (*F_handle) = NULL ; //-------------------------------------------------------------------------- // Declare and initialize workspace //-------------------------------------------------------------------------- - SPEX_matrix *L = NULL ; - SPEX_matrix *U = NULL ; - SPEX_matrix *rhos = NULL ; - int64_t *pinv = NULL ; + SPEX_factorization F = NULL ; int64_t *xi = NULL ; int64_t *h = NULL ; int64_t *pivs = NULL ; - int64_t *row_perm = NULL ; - SPEX_matrix *x = NULL ; + SPEX_matrix x = NULL ; int64_t n = A->n ; int64_t k = 0, top, i, j, col, loc, lnz = 0, unz = 0, pivot, jnew ; size_t size ; + // allocate memory space for the factorization + F = (SPEX_factorization) SPEX_calloc(1, sizeof(SPEX_factorization_struct)); + if (F == NULL) + { + return SPEX_OUT_OF_MEMORY; + } + // set factorization kind + F->kind = SPEX_LU_FACTORIZATION; + // Allocate and set scale_for_A + SPEX_MPQ_INIT(F->scale_for_A); + SPEX_MPQ_SET (F->scale_for_A, A->scale); + // Inverse pivot ordering - pinv = (int64_t *) SPEX_malloc (n * sizeof (int64_t)) ; + F->Pinv_perm = (int64_t*) SPEX_malloc (n * sizeof(int64_t)); + // Actual row permutation, the inverse of pinv. This + // is used for sorting + F->P_perm = (int64_t*) SPEX_malloc (n * sizeof(int64_t)); + // column permutation, to be copied from S->Q_perm + F->Q_perm = (int64_t*) SPEX_malloc (n * sizeof(int64_t)); // Indicator of which rows have been pivotal // pivs[i] = 1 if row i has been selected as a pivot @@ -115,25 +115,25 @@ SPEX_info SPEX_Left_LU_factorize // for the triangular solve. xi = (int64_t*) SPEX_malloc(2*n* sizeof(int64_t)); - // Actual row permutation, the inverse of pinv. This - // is used for sorting - row_perm = (int64_t*) SPEX_malloc(n* sizeof(int64_t)); - - if (!pivs || !h || !xi || !row_perm || !pinv) + if (!(F->Pinv_perm) || !(F->P_perm) || !(F->Q_perm) || + !pivs || !h || !xi) { // out of memory: free everything and return SPEX_FREE_ALL ; return SPEX_OUT_OF_MEMORY; } + // copy column permutation from symbolic analysis to factorization + memcpy(F->Q_perm, S->Q_perm, n * sizeof(int64_t)); + // initialize workspace and pivot status for (i = 0; i < n; i++) { h[i] = -1; pivs[i] = -1; // Initialize location based vectors - pinv[i] = i; - row_perm[i] = i; + F->Pinv_perm[i] = i; + F->P_perm[i] = i; } //-------------------------------------------------------------------------- @@ -141,7 +141,7 @@ SPEX_info SPEX_Left_LU_factorize //-------------------------------------------------------------------------- // Create rhos, a global dense mpz_t matrix of dimension n*1 - SPEX_CHECK (SPEX_matrix_allocate(&rhos, SPEX_DENSE, SPEX_MPZ, n, 1, n, + SPEX_CHECK (SPEX_matrix_allocate(&(F->rhos), SPEX_DENSE, SPEX_MPZ, n, 1, n, false, false, option)); // Allocate L and U without initializing each entry. @@ -151,9 +151,9 @@ SPEX_info SPEX_Left_LU_factorize // L and U are not allocated. Instead, a more efficient method to // allocate these values is done in the factorization to reduce // memory usage. - SPEX_CHECK (SPEX_matrix_allocate(&L, SPEX_CSC, SPEX_MPZ, n, n, S->lnz, + SPEX_CHECK (SPEX_matrix_allocate(&(F->L), SPEX_CSC, SPEX_MPZ, n, n, S->lnz, false, false, option)); - SPEX_CHECK (SPEX_matrix_allocate(&U, SPEX_CSC, SPEX_MPZ, n, n, S->unz, + SPEX_CHECK (SPEX_matrix_allocate(&(F->U), SPEX_CSC, SPEX_MPZ, n, n, S->unz, false, false, option)); //-------------------------------------------------------------------------- @@ -170,7 +170,7 @@ SPEX_info SPEX_Left_LU_factorize // Note that the estimate presented here is not an upper bound nor a lower // bound. It is still possible that more bits will be required which is // correctly handled internally. - int64_t estimate = 64 * SPEX_MAX (2, ceil (log2 ((double) n))) ; + int64_t estimate = 64 * SPEX_MAX (2, ceil (log2 ((double) n))); // Create x, a global dense mpz_t matrix of dimension n*1. Unlike rhos, the // second boolean parameter is set to false to avoid initializing @@ -182,7 +182,7 @@ SPEX_info SPEX_Left_LU_factorize for (i = 0; i < n; i++) { // Allocate memory for entries of x - SPEX_CHECK(SPEX_mpz_init2(x->x.mpz[i], estimate)); + SPEX_MPZ_INIT2(x->x.mpz[i], estimate); } //-------------------------------------------------------------------------- @@ -192,41 +192,41 @@ SPEX_info SPEX_Left_LU_factorize for (k = 0; k < n; k++) { // Column pointers for column k of L and U - L->p[k] = lnz; - U->p[k] = unz; - col = S->q[k]; + F->L->p[k] = lnz; + F->U->p[k] = unz; + col = F->Q_perm[k]; //---------------------------------------------------------------------- // Reallocate memory if necessary // if lnz+n > L->nzmax, L needs to expand to accomodate new nonzeros. // To do so, we double the size of the L and U matrices. //---------------------------------------------------------------------- - if (lnz + n > L->nzmax) + if (lnz + n > F->L->nzmax) { // Double the size of L - SPEX_CHECK(spex_sparse_realloc(L)); + SPEX_CHECK(spex_sparse_realloc(F->L)); } - if (unz + n > U->nzmax) + if (unz + n > F->U->nzmax) { // Double the size of U - SPEX_CHECK(spex_sparse_realloc(U)); + SPEX_CHECK(spex_sparse_realloc(F->U)); } //---------------------------------------------------------------------- // Triangular solve to compute LDx = A(:,k) //---------------------------------------------------------------------- - SPEX_CHECK(spex_left_lu_ref_triangular_solve(&top, L, A, k, xi, - (const int64_t *) (S->q), - rhos, - (const int64_t *) pinv, - (const int64_t *) row_perm, - h, x)) ; + SPEX_CHECK(spex_left_lu_ref_triangular_solve(&top, F->L, A, k, xi, + (const int64_t *) (F->Q_perm), + F->rhos, + (const int64_t *) (F->Pinv_perm), + (const int64_t *) (F->P_perm), + h, x)); //---------------------------------------------------------------------- // Obtain pivot //---------------------------------------------------------------------- SPEX_CHECK(spex_left_lu_get_pivot(&pivot, x, pivs, n, top, xi, - col, k, rhos, pinv, row_perm, option)); + col, k, F->rhos, F->Pinv_perm, F->P_perm, option)); //---------------------------------------------------------------------- // Populate L and U. We iterate across all nonzeros in x @@ -235,7 +235,7 @@ SPEX_info SPEX_Left_LU_factorize { jnew = xi[j]; // Location of x[j] in final matrix - loc = pinv[jnew]; + loc = F->Pinv_perm[jnew]; //------------------------------------------------------------------ // loc <= k are rows above k, thus go to U @@ -243,13 +243,13 @@ SPEX_info SPEX_Left_LU_factorize if (loc <= k) { // Place the i location of the unz nonzero - U->i[unz] = jnew; + F->U->i[unz] = jnew; // Find the size in bits of x[j] - SPEX_CHECK(SPEX_mpz_sizeinbase(&size, x->x.mpz[jnew], 2)); + SPEX_MPZ_SIZEINBASE(&size, x->x.mpz[jnew], 2); // GMP manual: Allocated size should be size+2 - SPEX_CHECK(SPEX_mpz_init2(U->x.mpz[unz], size+2)); + SPEX_MPZ_INIT2(F->U->x.mpz[unz], size+2); // Place the x value of the unz nonzero - SPEX_CHECK(SPEX_mpz_set(U->x.mpz[unz], x->x.mpz[jnew])); + SPEX_MPZ_SET(F->U->x.mpz[unz], x->x.mpz[jnew]); // Increment unz unz++; } @@ -260,13 +260,13 @@ SPEX_info SPEX_Left_LU_factorize if (loc >= k) { // Place the i location of the lnz nonzero - L->i[lnz] = jnew; + F->L->i[lnz] = jnew; // Set the size of x[j] - SPEX_CHECK(SPEX_mpz_sizeinbase(&size, x->x.mpz[jnew], 2)); + SPEX_MPZ_SIZEINBASE(&size, x->x.mpz[jnew], 2); // GMP manual: Allocated size should be size+2 - SPEX_CHECK(SPEX_mpz_init2(L->x.mpz[lnz], size+2)); + SPEX_MPZ_INIT2(F->L->x.mpz[lnz], size+2); // Place the x value of the lnz nonzero - SPEX_CHECK(SPEX_mpz_set(L->x.mpz[lnz], x->x.mpz[jnew])); + SPEX_MPZ_SET(F->L->x.mpz[lnz], x->x.mpz[jnew]); // Increment lnz lnz++; } @@ -274,21 +274,21 @@ SPEX_info SPEX_Left_LU_factorize } // Finalize L->p, U->p - L->p[n] = lnz; - U->p[n] = unz; + F->L->p[n] = lnz; + F->U->p[n] = unz; //-------------------------------------------------------------------------- // Free memory //-------------------------------------------------------------------------- - // free everything, but keep L, U, rhos, and pinv - SPEX_FREE_WORK ; + // free everything, but keep F + SPEX_FREE_WORKSPACE ; // This cannot fail since the size of L and U are shrinking. // Collapse L - spex_sparse_collapse(L); + spex_sparse_collapse(F->L); // Collapse U - spex_sparse_collapse(U); + spex_sparse_collapse(F->U); //-------------------------------------------------------------------------- // finalize the row indices in L and U @@ -297,12 +297,12 @@ SPEX_info SPEX_Left_LU_factorize // Permute entries in L for (i = 0; i < lnz; i++) { - L->i[i] = pinv[L->i[i]]; + F->L->i[i] = F->Pinv_perm[F->L->i[i]]; } // Permute entries in U for (i = 0; i < unz; i++) { - U->i[i] = pinv[U->i[i]]; + F->U->i[i] = F->Pinv_perm[F->U->i[i]]; } //-------------------------------------------------------------------------- @@ -310,18 +310,15 @@ SPEX_info SPEX_Left_LU_factorize //-------------------------------------------------------------------------- #if 0 - SPEX_CHECK (SPEX_matrix_check (L, option)) ; - SPEX_CHECK (SPEX_matrix_check (U, option)) ; + SPEX_CHECK (SPEX_matrix_check (F->L, option)); + SPEX_CHECK (SPEX_matrix_check (F->U, option)); #endif //-------------------------------------------------------------------------- // return result //-------------------------------------------------------------------------- - (*L_handle) = L ; - (*U_handle) = U ; - (*rhos_handle) = rhos ; - (*pinv_handle) = pinv ; - return (SPEX_OK) ; + (*F_handle) = F ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_LU/Source/SPEX_lu_solve.c b/SPEX/SPEX_LU/Source/SPEX_lu_solve.c new file mode 100644 index 0000000000..4dca51d78c --- /dev/null +++ b/SPEX/SPEX_LU/Source/SPEX_lu_solve.c @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +// SPEX_LU/SPEX_lu_solve: exact solution of Ax=b +//------------------------------------------------------------------------------ + +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function solves the linear system LD^(-1)U x = b. It + * essnetially serves as a wrapper for all forward and backward substitution + * routines. This function always returns the solution matrix x as a mpq_t + * matrix. If a user desires to have double or mpfr output, they must create + * a matrix copy. + * + * Input/output arguments: + * + * x_handle: A pointer to the solution vectors. Unitialized on input. + * on output, contains the exact rational solution of the system + * + * b: Set of RHS vectors + * + * F: LU factorization of A. Mathematically, F is unchanged. + * However, if F is updatable on input, it is converted to + * non-updatable. If F is already non-updatable, + * it is not modified. + * + * option: command options + */ + +#define SPEX_FREE_WORKSPACE \ + SPEX_matrix_free (&b2, NULL); + +#define SPEX_FREE_ALL \ + SPEX_FREE_WORKSPACE \ + SPEX_matrix_free (&x, NULL); + +#include "spex_lu_internal.h" + +SPEX_info SPEX_lu_solve // solves the linear system LD^(-1)U x = b +( + // Output + SPEX_matrix *x_handle, // rational solution to the system + // input/output: + SPEX_factorization F, // The non-updatable LU factorization. + // Mathematically, F is unchanged. However, if F + // is updatable on input, it is converted to + // non-updatable. If F is already non-updatable, + // it is not modified. + // input: + const SPEX_matrix b, // right hand side vector + const SPEX_options option // Command options +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + SPEX_info info ; + if (!spex_initialized ( )) return (SPEX_PANIC); + + SPEX_REQUIRE (b, SPEX_DENSE, SPEX_MPZ); + + if (!x_handle || !F || F->kind != SPEX_LU_FACTORIZATION) + { + return SPEX_INCORRECT_INPUT; + } + + // check components of F in debug mode + ASSERT_MATRIX (F->L, SPEX_CSC, SPEX_MPZ); + ASSERT_MATRIX (F->U, SPEX_CSC, SPEX_MPZ); + ASSERT_MATRIX (F->rhos, SPEX_DENSE, SPEX_MPZ); + + //-------------------------------------------------------------------------- + // Declare and initialize workspace + //-------------------------------------------------------------------------- + + (*x_handle) = NULL; + int64_t n = F->L->n; + + SPEX_matrix x = NULL; // final solution + SPEX_matrix b2 = NULL; // permuted b + + //-------------------------------------------------------------------------- + // b2 (Pinv_perm) = b + //-------------------------------------------------------------------------- + + SPEX_CHECK (spex_permute_dense_matrix (&b2, b, F->Pinv_perm, option)); + + //-------------------------------------------------------------------------- + // b2 = L\b2, via forward substitution + //-------------------------------------------------------------------------- + + SPEX_CHECK(spex_left_lu_forward_sub(F->L, b2, F->rhos)); + + //-------------------------------------------------------------------------- + // b2 = b2 * det, where det=rhos[n-1] + //-------------------------------------------------------------------------- + + SPEX_CHECK(spex_matrix_mul(b2, F->rhos->x.mpz[n-1])); + + //-------------------------------------------------------------------------- + // b2 = U\b2, via back substitution + //-------------------------------------------------------------------------- + SPEX_CHECK(spex_left_lu_back_sub(F->U, b2)); + + //-------------------------------------------------------------------------- + // x = Q*b2/scale + //-------------------------------------------------------------------------- + // set scale = b->scale * rhos[n-1] / A_scale + SPEX_MPQ_SET_Z(b2->scale, F->rhos->x.mpz[n-1]); + SPEX_MPQ_MUL(b2->scale, b2->scale, b->scale); + SPEX_MPQ_DIV(b2->scale, b2->scale, F->scale_for_A); + + // allocate space for x as dense MPQ matrix + SPEX_CHECK (SPEX_matrix_allocate (&x, SPEX_DENSE, SPEX_MPQ, b->m, b->n, + 0, false, true, option)); + + // obtain x from permuted b2 with scale applied + for (int64_t i = 0 ; i < b->m ; i++) + { + int64_t qi = F->Q_perm[i]; + for (int64_t j = 0 ; j < b->n ; j++) + { + SPEX_MPQ_SET_Z(SPEX_2D(x, qi, j, mpq), + SPEX_2D(b2, i, j, mpz)); + SPEX_MPQ_DIV(SPEX_2D(x, qi, j, mpq), + SPEX_2D(x, qi, j, mpq), b2->scale); + } + } + + //-------------------------------------------------------------------------- + // free workspace and return result + //-------------------------------------------------------------------------- + + SPEX_FREE_WORKSPACE ; + (*x_handle) = x ; + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_back_sub.c b/SPEX/SPEX_LU/Source/spex_left_lu_back_sub.c similarity index 65% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_back_sub.c rename to SPEX/SPEX_LU/Source/spex_left_lu_back_sub.c index 105d2ae857..6cc147e7c1 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_back_sub.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_back_sub.c @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_back_sub: sparse REF backward substitution (x = U\x) +// SPEX_LU/spex_left_lu_back_sub: sparse REF backward substitution (x = U\x) //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -19,12 +19,13 @@ * by the solution x. */ -#include "spex_left_lu_internal.h" + +#include "spex_lu_internal.h" SPEX_info spex_left_lu_back_sub // performs sparse REF backward substitution ( - const SPEX_matrix *U, // input upper triangular matrix - SPEX_matrix *bx // right hand side matrix + const SPEX_matrix U, // input upper triangular matrix + SPEX_matrix bx // right hand side matrix ) { @@ -33,8 +34,8 @@ SPEX_info spex_left_lu_back_sub // performs sparse REF backward substitution //-------------------------------------------------------------------------- SPEX_info info ; - SPEX_REQUIRE (U, SPEX_CSC, SPEX_MPZ) ; - SPEX_REQUIRE (bx, SPEX_DENSE, SPEX_MPZ) ; + SPEX_REQUIRE (U, SPEX_CSC, SPEX_MPZ); + SPEX_REQUIRE (bx, SPEX_DENSE, SPEX_MPZ); //-------------------------------------------------------------------------- @@ -49,24 +50,24 @@ SPEX_info spex_left_lu_back_sub // performs sparse REF backward substitution for (int64_t j = U->n-1; j >= 0; j--) { // If bx[j] is zero skip this iteration - SPEX_CHECK( SPEX_mpz_sgn( &sgn, SPEX_2D( bx, j, k, mpz))); + SPEX_MPZ_SGN(&sgn, SPEX_2D( bx, j, k, mpz)); if (sgn == 0) {continue;} // Obtain bx[j] - SPEX_CHECK(SPEX_mpz_divexact( SPEX_2D(bx, j, k, mpz), + SPEX_MPZ_DIVEXACT(SPEX_2D(bx, j, k, mpz), SPEX_2D(bx, j, k, mpz), - Ux[Up[j+1]-1])); + Ux[Up[j+1]-1]); for (int64_t i = Up[j]; i < Up[j+1]-1; i++) { - SPEX_CHECK(SPEX_mpz_sgn(&sgn, Ux[i])); + SPEX_MPZ_SGN(&sgn, Ux[i]); if (sgn == 0) {continue;} // bx[i] = bx[i] - Ux[i]*bx[j] - SPEX_CHECK(SPEX_mpz_submul( SPEX_2D(bx, Ui[i], k, mpz), - Ux[i], SPEX_2D(bx, j, k, mpz))); + SPEX_MPZ_SUBMUL(SPEX_2D(bx, Ui[i], k, mpz), + Ux[i], SPEX_2D(bx, j, k, mpz)); } } } - return (SPEX_OK) ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_dfs.c b/SPEX/SPEX_LU/Source/spex_left_lu_dfs.c similarity index 77% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_dfs.c rename to SPEX/SPEX_LU/Source/spex_left_lu_dfs.c index d9b33be931..2f0b8cbeaf 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_dfs.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_dfs.c @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_dfs: depth-first search +// SPEX_LU/spex_left_lu_dfs: depth-first search //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -13,16 +13,16 @@ * indices in the xi vector. This function is modified from CSparse/cs_dfs. */ -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" -void spex_left_lu_dfs // performs a dfs of the graph of the matrix starting at node j +void spex_left_lu_dfs // dfs of the graph of the matrix starting at node j ( - int64_t *top, // beginning of stack - int64_t j, // What node to start DFS at - SPEX_matrix* L, // matrix which represents the Graph of L - int64_t* xi, // the nonzero pattern - int64_t* pstack, // workspace vector - const int64_t* pinv // row permutation + int64_t *top, // beginning of stack + int64_t j, // What node to start DFS at + SPEX_matrix L, // matrix which represents the Graph of L + int64_t *xi, // the nonzero pattern + int64_t *pstack, // workspace vector + const int64_t *pinv // row permutation ) { @@ -30,7 +30,7 @@ void spex_left_lu_dfs // performs a dfs of the graph of the matrix starting at n // check inputs //-------------------------------------------------------------------------- - ASSERT_KIND (L, SPEX_CSC) ; + ASSERT_KIND (L, SPEX_CSC); // top xi etc already checked in the caller function diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_forward_sub.c b/SPEX/SPEX_LU/Source/spex_left_lu_forward_sub.c similarity index 63% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_forward_sub.c rename to SPEX/SPEX_LU/Source/spex_left_lu_forward_sub.c index 7d4b41ccc1..1e1366905e 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_forward_sub.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_forward_sub.c @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_forward_sub: sparse forward substitution (x = (LD)\x) +// SPEX_LU/spex_left_lu_forward_sub: sparse forward substitution (x = (LD)\x) //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -16,19 +16,19 @@ * system to solve is L*D*x_output = x_input, overwriting the right-hand-side * with the solution. * - * On output, the SPEX_matrix* x structure is modified. + * On output, the SPEX_matrix x is modified. */ -#define SPEX_FREE_ALL \ - SPEX_matrix_free(&h, NULL) ; +#define SPEX_FREE_ALL \ + SPEX_matrix_free(&h, NULL); -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" SPEX_info spex_left_lu_forward_sub ( - const SPEX_matrix *L, // lower triangular matrix - SPEX_matrix *x, // right hand side matrix of size n*numRHS - const SPEX_matrix *rhos // sequence of pivots used in factorization + const SPEX_matrix L, // lower triangular matrix + SPEX_matrix x, // right hand side matrix of size n*numRHS + const SPEX_matrix rhos // sequence of pivots used in factorization ) { @@ -47,7 +47,7 @@ SPEX_info spex_left_lu_forward_sub int sgn ; // Build the history matrix - SPEX_matrix *h; + SPEX_matrix h = NULL ; SPEX_CHECK (SPEX_matrix_allocate(&h, SPEX_DENSE, SPEX_INT64, x->m, x->n, x->nzmax, false, true, NULL)); @@ -73,7 +73,7 @@ SPEX_info spex_left_lu_forward_sub { hx = SPEX_2D(h, i, k, int64); // If x[i][k] = 0, can skip operations and continue to next i - SPEX_CHECK(SPEX_mpz_sgn(&sgn, SPEX_2D(x, i, k, mpz))); + SPEX_MPZ_SGN(&sgn, SPEX_2D(x, i, k, mpz)); if (sgn == 0) {continue;} //------------------------------------------------------------------ @@ -83,15 +83,15 @@ SPEX_info spex_left_lu_forward_sub if (hx < i-1) { // x[i] = x[i] * rhos[i-1] - SPEX_CHECK(SPEX_mpz_mul( SPEX_2D(x, i, k, mpz), - SPEX_2D(x, i, k, mpz), - SPEX_1D(rhos, i-1, mpz))); + SPEX_MPZ_MUL(SPEX_2D(x, i, k, mpz), + SPEX_2D(x, i, k, mpz), + SPEX_1D(rhos, i-1, mpz)); // x[i] = x[i] / rhos[hx] if (hx > -1) { - SPEX_CHECK(SPEX_mpz_divexact( SPEX_2D(x, i, k, mpz), - SPEX_2D(x, i, k, mpz), - SPEX_1D(rhos, hx, mpz))); + SPEX_MPZ_DIVEXACT(SPEX_2D(x, i, k, mpz), + SPEX_2D(x, i, k, mpz), + SPEX_1D(rhos, hx, mpz)); } } @@ -106,27 +106,26 @@ SPEX_info spex_left_lu_forward_sub jnew = L->i[j]; // skip if Lx[j] is zero - SPEX_CHECK(SPEX_mpz_sgn(&sgn, L->x.mpz[j])); + SPEX_MPZ_SGN(&sgn, L->x.mpz[j]); if (sgn == 0) {continue;} // j > i if (jnew > i) { // check if x[jnew] is zero - SPEX_CHECK(SPEX_mpz_sgn(&sgn, SPEX_2D(x, jnew, k, mpz))); + SPEX_MPZ_SGN(&sgn, SPEX_2D(x, jnew, k, mpz)); if (sgn == 0) { // x[j] = x[j] - lji xi - SPEX_CHECK(SPEX_mpz_submul(SPEX_2D(x, jnew, k, mpz), - SPEX_1D(L, j, mpz), - SPEX_2D(x, i, k, mpz))); + SPEX_MPZ_SUBMUL(SPEX_2D(x, jnew, k, mpz), + SPEX_1D(L, j, mpz), + SPEX_2D(x, i, k, mpz)); // x[j] = x[j] / rhos[i-1] if (i > 0) { - SPEX_CHECK( - SPEX_mpz_divexact(SPEX_2D(x, jnew, k, mpz), - SPEX_2D(x, jnew, k, mpz), - SPEX_1D(rhos, i-1, mpz))); + SPEX_MPZ_DIVEXACT(SPEX_2D(x, jnew, k, mpz), + SPEX_2D(x, jnew, k, mpz), + SPEX_1D(rhos, i-1, mpz)); } } else @@ -136,33 +135,31 @@ SPEX_info spex_left_lu_forward_sub if (hx < i-1) { // x[j] = x[j] * rhos[i-1] - SPEX_CHECK(SPEX_mpz_mul(SPEX_2D(x, jnew, k, mpz), - SPEX_2D(x, jnew, k, mpz), - SPEX_1D(rhos, i-1, mpz))); + SPEX_MPZ_MUL(SPEX_2D(x, jnew, k, mpz), + SPEX_2D(x, jnew, k, mpz), + SPEX_1D(rhos, i-1, mpz)); // x[j] = x[j] / rhos[hx] if (hx > -1) { - SPEX_CHECK( - SPEX_mpz_divexact(SPEX_2D(x, jnew, k, mpz), - SPEX_2D(x, jnew, k, mpz), - SPEX_1D(rhos, hx, mpz))); + SPEX_MPZ_DIVEXACT(SPEX_2D(x, jnew, k, mpz), + SPEX_2D(x, jnew, k, mpz), + SPEX_1D(rhos, hx, mpz)); } } // x[j] = x[j] * rhos[i] - SPEX_CHECK(SPEX_mpz_mul(SPEX_2D(x, jnew, k, mpz), - SPEX_2D(x, jnew, k, mpz), - SPEX_1D(rhos, i, mpz))); + SPEX_MPZ_MUL(SPEX_2D(x, jnew, k, mpz), + SPEX_2D(x, jnew, k, mpz), + SPEX_1D(rhos, i, mpz)); // x[j] = x[j] - lmi xi - SPEX_CHECK(SPEX_mpz_submul(SPEX_2D(x, jnew, k, mpz), - SPEX_1D(L, j, mpz), - SPEX_2D(x, i, k, mpz))); + SPEX_MPZ_SUBMUL(SPEX_2D(x, jnew, k, mpz), + SPEX_1D(L, j, mpz), + SPEX_2D(x, i, k, mpz)); // x[j] = x[j] / rhos[i-1] if (i > 0) { - SPEX_CHECK( - SPEX_mpz_divexact(SPEX_2D(x, jnew, k, mpz), - SPEX_2D(x, jnew, k, mpz), - SPEX_1D(rhos, i-1, mpz))); + SPEX_MPZ_DIVEXACT(SPEX_2D(x, jnew, k, mpz), + SPEX_2D(x, jnew, k, mpz), + SPEX_1D(rhos, i-1, mpz)); } } //h[jnew][k] = i; diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_largest_pivot.c b/SPEX/SPEX_LU/Source/spex_left_lu_get_largest_pivot.c similarity index 78% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_get_largest_pivot.c rename to SPEX/SPEX_LU/Source/spex_left_lu_get_largest_pivot.c index d2fb454fd6..cd96bb01ed 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_largest_pivot.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_get_largest_pivot.c @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_get_largest_pivot: find a pivot entry in a column +// SPEX_LU/spex_left_lu_get_largest_pivot: find a pivot entry in a column //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -17,20 +17,20 @@ * On output, the index of the largest pivot is returned. */ -#define SPEX_FREE_ALL \ +#define SPEX_FREE_ALL \ SPEX_MPZ_CLEAR(big); -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" SPEX_info spex_left_lu_get_largest_pivot ( int64_t *pivot, // the index of largest pivot - SPEX_matrix* x, // kth column of L and U - int64_t* pivs, // vector which indicates whether each row + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector which indicates whether each row // has been pivotal int64_t n, // dimension of problem int64_t top, // nonzero pattern is located in xi[top..n-1] - int64_t* xi // nonzero pattern of x + int64_t *xi // nonzero pattern of x ) { @@ -51,8 +51,8 @@ SPEX_info spex_left_lu_get_largest_pivot int r ; (*pivot) = -1 ; mpz_t big ; - SPEX_MPZ_SET_NULL (big) ; - SPEX_CHECK (SPEX_mpz_init (big)) ; + SPEX_MPZ_SET_NULL (big); + SPEX_MPZ_INIT (big); //-------------------------------------------------------------------------- // Iterate accross the nonzeros in x @@ -63,13 +63,13 @@ SPEX_info spex_left_lu_get_largest_pivot // Location of the ith nonzero inew = xi[i]; // inew can be pivotal - SPEX_CHECK(SPEX_mpz_cmpabs(&r, big, x->x.mpz[inew])); + SPEX_MPZ_CMPABS(&r, big, x->x.mpz[inew]); if (pivs[inew] < 0 && r < 0) { // Current largest pivot location (*pivot) = inew; // Current largest pivot value - SPEX_CHECK(SPEX_mpz_set(big, x->x.mpz[inew])); + SPEX_MPZ_SET(big, x->x.mpz[inew]); } } diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_nonzero_pivot.c b/SPEX/SPEX_LU/Source/spex_left_lu_get_nonzero_pivot.c similarity index 72% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_get_nonzero_pivot.c rename to SPEX/SPEX_LU/Source/spex_left_lu_get_nonzero_pivot.c index 94311aee73..3dc8e88bf0 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_nonzero_pivot.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_get_nonzero_pivot.c @@ -1,32 +1,32 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_get_nonzero_pivot: find a nonzero pivot in a column +// SPEX_LU/spex_left_lu_get_nonzero_pivot: find a nonzero pivot in a column //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -/* Purpose: This function obtains the first eligible nonzero pivot - * This is enabled if the user sets option->pivot = SPEX_FIRST_NONZERO +/* Purpose: This function obtains the first eligible nonzero pivot. This is + * enabled if the user sets option->pivot = SPEX_FIRST_NONZERO * - * Note: This pivoting scheme is NOT recommended for SPEX Left LU. It is provided - * for comparison with other pivoting options. + * Note: This pivoting scheme is NOT recommended for SPEX Left LU. It is + * provided for comparison with other pivoting options. * * On output, the kth pivot is returned. */ -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" -SPEX_info spex_left_lu_get_nonzero_pivot // find the first eligible nonzero pivot +SPEX_info spex_left_lu_get_nonzero_pivot // find first eligible nonzero pivot ( int64_t *pivot, // the index of first eligible nonzero pivot - SPEX_matrix* x, // kth column of L and U - int64_t* pivs, // vector indicating which rows are pivotal + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector indicating which rows are pivotal int64_t n, // size of x int64_t top, // nonzero pattern is located in xi[top..n-1] - int64_t* xi // nonzero pattern of x + int64_t *xi // nonzero pattern of x ) { @@ -55,7 +55,7 @@ SPEX_info spex_left_lu_get_nonzero_pivot // find the first eligible nonzero pivo int64_t inew = xi[i]; // check if x[inew] is an eligible pivot int sgn ; - SPEX_CHECK (SPEX_mpz_sgn (&sgn, x->x.mpz[inew])) ; + SPEX_MPZ_SGN (&sgn, x->x.mpz[inew]); if (sgn != 0 && pivs [inew] < 0) { (*pivot) = inew; diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_pivot.c b/SPEX/SPEX_LU/Source/spex_left_lu_get_pivot.c similarity index 63% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_get_pivot.c rename to SPEX/SPEX_LU/Source/spex_left_lu_get_pivot.c index a0f2f39289..3e8753b18f 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_pivot.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_get_pivot.c @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_get_pivot: find a pivot entry in a column +// SPEX_LU/spex_left_lu_get_pivot: find a pivot entry in a column //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -14,7 +14,7 @@ * SPEX_SMALLEST = 0, Smallest pivot * SPEX_DIAGONAL = 1, Diagonal pivoting * SPEX_FIRST_NONZERO = 2, First nonzero per column chosen as pivot - * SPEX_TOL_SMALLEST = 3, Diagonal pivoting with tolerance for pivot. (Default) + * SPEX_TOL_SMALLEST = 3, Diagonal pivoting with tolerance for pivot (default) * SPEX_TOL_LARGEST = 4, Diagonal pivoting with tolerance for largest pivot * SPEX_LARGEST = 5 Largest pivot * @@ -25,26 +25,26 @@ */ #define SPEX_FREE_ALL \ - SPEX_MPQ_CLEAR (tol) ; \ - SPEX_MPQ_CLEAR (ratio) ; + SPEX_MPQ_CLEAR (tol); \ + SPEX_MPQ_CLEAR (ratio); -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" SPEX_info spex_left_lu_get_pivot ( int64_t *pivot, // found index of pivot entry - SPEX_matrix* x, // kth column of L and U - int64_t* pivs, // vector indicating which rows have been pivotal + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector indicating which rows have been pivotal int64_t n, // dimension of the problem int64_t top, // nonzero pattern is located in xi[top..n-1] - int64_t* xi, // nonzero pattern of x + int64_t *xi, // nonzero pattern of x int64_t col, // current column of A (real kth column i.e., q[k]) int64_t k, // iteration of the algorithm - SPEX_matrix* rhos, // vector of pivots - int64_t* pinv, // row permutation - int64_t* row_perm, // opposite of pinv. + SPEX_matrix rhos, // vector of pivots + int64_t *pinv, // row permutation + int64_t *row_perm, // opposite of pinv. // if pinv[i] = j then row_perm[j] = i - const SPEX_options* option // command options + const SPEX_options option // command options ) { @@ -56,14 +56,6 @@ SPEX_info spex_left_lu_get_pivot SPEX_REQUIRE(rhos, SPEX_DENSE, SPEX_MPZ); SPEX_REQUIRE(x, SPEX_DENSE, SPEX_MPZ); - // inputs have been checked in the only caller SPEX_Left_LU_factorize - // they are kept here for future reference -#if 0 - if (!pivot || !pivs || !xi || !pinv || !row_perm ) - { - return SPEX_INCORRECT_INPUT; - } -#endif // pivoting method to use (see above description) SPEX_pivot order = SPEX_OPTION_PIVOT(option); // tolerance used if some tol-based pivoting is used @@ -78,107 +70,120 @@ SPEX_info spex_left_lu_get_pivot SPEX_MPQ_SET_NULL(tol); SPEX_MPQ_SET_NULL(ratio); - //-------------------------------------------------------------------------- - // Smallest pivot - //-------------------------------------------------------------------------- - if (order == SPEX_SMALLEST) { + + //---------------------------------------------------------------------- + // Smallest pivot + //---------------------------------------------------------------------- + SPEX_CHECK(spex_left_lu_get_smallest_pivot(pivot, x, pivs, n, top, xi)); - } - //-------------------------------------------------------------------------- - // Diagonal - //-------------------------------------------------------------------------- + } else if (order == SPEX_DIAGONAL) { + + //---------------------------------------------------------------------- + // Diagonal + //---------------------------------------------------------------------- + // Check if x[col] is eligible. take smallest pivot if not - SPEX_CHECK (SPEX_mpz_sgn(&sgn, x->x.mpz[col])); + SPEX_MPZ_SGN(&sgn, x->x.mpz[col]); if (sgn != 0 && pivs[col] < 0) { *pivot = col; } else { - SPEX_CHECK (spex_left_lu_get_smallest_pivot(pivot, x, pivs, n, top, xi)); + SPEX_CHECK (spex_left_lu_get_smallest_pivot(pivot, x, pivs, n, + top, xi)); } - } - //-------------------------------------------------------------------------- - // First nonzero - //-------------------------------------------------------------------------- + } else if (order == SPEX_FIRST_NONZERO) { + + //---------------------------------------------------------------------- + // First nonzero + //---------------------------------------------------------------------- + SPEX_CHECK (spex_left_lu_get_nonzero_pivot(pivot, x, pivs, n, top, xi)); - } - //-------------------------------------------------------------------------- - // Tolerance with largest pivot - //-------------------------------------------------------------------------- + } else if (order == SPEX_TOL_LARGEST) { + + //---------------------------------------------------------------------- + // Tolerance with largest pivot + //---------------------------------------------------------------------- + SPEX_CHECK (spex_left_lu_get_largest_pivot(pivot, x, pivs, n, top, xi)); //---------------------------------------------------------------------- // Check x[col] vs largest potential pivot //---------------------------------------------------------------------- - SPEX_CHECK (SPEX_mpz_sgn(&sgn, x->x.mpz[col])); + SPEX_MPZ_SGN(&sgn, x->x.mpz[col]); if (sgn != 0 && pivs[col] < 0) { - SPEX_CHECK(SPEX_mpq_init(tol)); - SPEX_CHECK(SPEX_mpq_init(ratio)); + SPEX_MPQ_INIT(tol); + SPEX_MPQ_INIT(ratio); // tol = user specified tolerance - SPEX_CHECK(SPEX_mpq_set_d(tol, tolerance)); + SPEX_MPQ_SET_D(tol, tolerance); // ratio = diagonal/largest - SPEX_CHECK(SPEX_mpq_set_num(ratio, x->x.mpz[col])); - SPEX_CHECK(SPEX_mpq_set_den(ratio, x->x.mpz[*pivot])); + SPEX_MPQ_SET_NUM(ratio, x->x.mpz[col]); + SPEX_MPQ_SET_DEN(ratio, x->x.mpz[*pivot]); // ratio = |ratio| - SPEX_CHECK(SPEX_mpq_abs(ratio, ratio)); + SPEX_MPQ_ABS(ratio, ratio); // Is ratio >= tol? - SPEX_CHECK(SPEX_mpq_cmp(&r, ratio, tol)); + SPEX_MPQ_CMP(&r, ratio, tol); if (r >= 0) { *pivot = col; } } - } - //-------------------------------------------------------------------------- - // Use the largest potential pivot - //-------------------------------------------------------------------------- + } else if (order == SPEX_LARGEST) { + + //---------------------------------------------------------------------- + // Use the largest potential pivot + //---------------------------------------------------------------------- + SPEX_CHECK (spex_left_lu_get_largest_pivot(pivot, x, pivs, n, top, xi)); - } - //-------------------------------------------------------------------------- - // Tolerance with smallest pivot (default option) - //-------------------------------------------------------------------------- + } else // if (order == SPEX_TOL_SMALLEST) { - SPEX_CHECK (spex_left_lu_get_smallest_pivot(pivot, x, pivs, n, top, xi)) ; + + //---------------------------------------------------------------------- + // Tolerance with smallest pivot (default option) + //---------------------------------------------------------------------- + + SPEX_CHECK (spex_left_lu_get_smallest_pivot(pivot, x, pivs, n, top, + xi)); //---------------------------------------------------------------------- // Checking x[col] vs smallest pivot //---------------------------------------------------------------------- - SPEX_CHECK (SPEX_mpz_sgn(&sgn, x->x.mpz[col])); + SPEX_MPZ_SGN(&sgn, x->x.mpz[col]); if (sgn != 0 && pivs[col] < 0) { // Initialize tolerance and ratio - SPEX_CHECK(SPEX_mpq_init(tol)); - SPEX_CHECK(SPEX_mpq_init(ratio)); + SPEX_MPQ_INIT(tol); + SPEX_MPQ_INIT(ratio); // ratio = |smallest/diagonal| - SPEX_CHECK(SPEX_mpz_abs(SPEX_MPQ_NUM(ratio), x->x.mpz[*pivot])); - SPEX_CHECK(SPEX_mpz_abs(SPEX_MPQ_DEN(ratio), x->x.mpz[col])); + SPEX_MPZ_ABS(SPEX_MPQ_NUM(ratio), x->x.mpz[*pivot]); + SPEX_MPZ_ABS(SPEX_MPQ_DEN(ratio), x->x.mpz[col]); // Set user specified tolerance - SPEX_CHECK(SPEX_mpq_set_d(tol, tolerance)); + SPEX_MPQ_SET_D(tol, tolerance); // Is ratio >= tol? - SPEX_CHECK(SPEX_mpq_cmp(&r, ratio, tol)); + SPEX_MPQ_CMP(&r, ratio, tol); if (r >= 0) { *pivot = col; @@ -189,6 +194,7 @@ SPEX_info spex_left_lu_get_pivot //-------------------------------------------------------------------------- // Reflect changes in row location & row_perm //-------------------------------------------------------------------------- + // Must move pivot into position k int64_t intermed = pinv[*pivot]; int64_t intermed2 = row_perm[k]; @@ -203,15 +209,15 @@ SPEX_info spex_left_lu_get_pivot pinv[intermed2] = intermed; // Row pivot is now pivotal pivs[*pivot] = 1; - + // Set the kth pivot. size_t size; // Get the size of x[pivot] - SPEX_CHECK(SPEX_mpz_sizeinbase(&size, x->x.mpz[*pivot], 2)); + SPEX_MPZ_SIZEINBASE(&size, x->x.mpz[*pivot], 2); // GMP manual: Allocated size should be size+2 - SPEX_CHECK(SPEX_mpz_init2(rhos->x.mpz[k], size+2)); - // The kth pivot is x[pivot] - SPEX_CHECK (SPEX_mpz_set(rhos->x.mpz[k], x->x.mpz[*pivot])); + SPEX_MPZ_INIT2(rhos->x.mpz[k], size+2); + // The kth pivot is x[pivot] + SPEX_MPZ_SET(rhos->x.mpz[k], x->x.mpz[*pivot]); // Free memory SPEX_FREE_ALL; diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_smallest_pivot.c b/SPEX/SPEX_LU/Source/spex_left_lu_get_smallest_pivot.c similarity index 79% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_get_smallest_pivot.c rename to SPEX/SPEX_LU/Source/spex_left_lu_get_smallest_pivot.c index 2f3c9b544b..2769471194 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_get_smallest_pivot.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_get_smallest_pivot.c @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_get_smallest_pivot: find the smallest entry in a column +// SPEX_LU/spex_left_lu_get_smallest_pivot: find the smallest entry in a column //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -15,19 +15,19 @@ * On output, the index of kth pivot is returned. */ -#define SPEX_FREE_ALL \ +#define SPEX_FREE_ALL \ SPEX_MPZ_CLEAR(small); -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" SPEX_info spex_left_lu_get_smallest_pivot ( int64_t *pivot, // the index of smallest pivot - SPEX_matrix* x, // kth column of L and U - int64_t* pivs, // vector indicating if each row has been pivotal + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector indicating if each row has been pivotal int64_t n, // dimension of problem int64_t top, // nonzeros are stored in xi[top..n-1] - int64_t* xi // nonzero pattern of x + int64_t *xi // nonzero pattern of x ) { @@ -50,7 +50,7 @@ SPEX_info spex_left_lu_get_smallest_pivot j = n; flag = top; mpz_t small; SPEX_MPZ_SET_NULL(small); - SPEX_CHECK(SPEX_mpz_init(small)); + SPEX_MPZ_INIT(small); //-------------------------------------------------------------------------- // Find an initial pivot. Fails if all terms are 0 in array x @@ -62,11 +62,11 @@ SPEX_info spex_left_lu_get_smallest_pivot inew = xi[flag]; //check if inew can be pivotal - SPEX_CHECK(SPEX_mpz_sgn(&sgn, x->x.mpz[inew])); + SPEX_MPZ_SGN(&sgn, x->x.mpz[inew]); if (pivs[inew] < 0 && sgn != 0) { // Current smallest pivot - SPEX_CHECK(SPEX_mpz_set(small, x->x.mpz[inew])); + SPEX_MPZ_SET(small, x->x.mpz[inew]); // Current smallest pivot location *pivot = inew; // Where to start the search for rest of nonzeros @@ -86,16 +86,16 @@ SPEX_info spex_left_lu_get_smallest_pivot { inew = xi[i]; // check if inew can be pivotal - SPEX_CHECK(SPEX_mpz_cmpabs(&r, small, x->x.mpz[inew])); + SPEX_MPZ_CMPABS(&r, small, x->x.mpz[inew]); if (pivs[inew] < 0 && r > 0) { - SPEX_CHECK(SPEX_mpz_sgn(&sgn, x->x.mpz[inew])); + SPEX_MPZ_SGN(&sgn, x->x.mpz[inew]); if (sgn != 0) { // Current best pivot location *pivot = inew; // Current best pivot value - SPEX_CHECK(SPEX_mpz_set(small, x->x.mpz[inew])); + SPEX_MPZ_SET(small, x->x.mpz[inew]); } } } diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_reach.c b/SPEX/SPEX_LU/Source/spex_left_lu_reach.c similarity index 71% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_reach.c rename to SPEX/SPEX_LU/Source/spex_left_lu_reach.c index d3efec73d0..e73d84f413 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_reach.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_reach.c @@ -1,14 +1,14 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_reach: compute the set of nodes reachable from an input set +// SPEX_LU/spex_left_lu_reach: compute set of nodes reachable from an input set //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -#include "spex_left_lu_internal.h" +#include "spex_lu_internal.h" /* Purpose: This function computes the reach of column k of A on the graph of L * mathematically that is: xi = Reach(A(:,k))_G_L @@ -16,14 +16,14 @@ * This function is derived from CSparse/cs_reach.c */ -void spex_left_lu_reach // compute the reach of column k of A on the graph of L +void spex_left_lu_reach // compute reach of column k of A on the graph of L ( int64_t *top, - SPEX_matrix* L, // matrix representing graph of L - const SPEX_matrix* A, // input matrix + SPEX_matrix L, // matrix representing graph of L + const SPEX_matrix A, // input matrix int64_t k, // column of A of interest - int64_t* xi, // nonzero pattern - const int64_t* pinv // row permutation + int64_t *xi, // nonzero pattern + const int64_t *pinv // row permutation ) { @@ -33,7 +33,7 @@ void spex_left_lu_reach // compute the reach of column k of A on the graph of if (top == NULL) { return ;} // inputs have been checked in spex_ref_triangular_solve int64_t p, n = L->n; - *top = n; + (*top) = n; //-------------------------------------------------------------------------- // Iterating across number of nonzero in column k diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_ref_triangular_solve.c b/SPEX/SPEX_LU/Source/spex_left_lu_ref_triangular_solve.c similarity index 77% rename from SPEX/SPEX_Left_LU/Source/spex_left_lu_ref_triangular_solve.c rename to SPEX/SPEX_LU/Source/spex_left_lu_ref_triangular_solve.c index 1fd62319da..f28161020e 100644 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_ref_triangular_solve.c +++ b/SPEX/SPEX_LU/Source/spex_left_lu_ref_triangular_solve.c @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_ref_triangular_solve: sparse REF triangular solve +// SPEX_LU/spex_left_lu_ref_triangular_solve: sparse REF triangular solve //------------------------------------------------------------------------------ -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -67,36 +67,28 @@ * output. */ -#include "spex_left_lu_internal.h" + +#include "spex_lu_internal.h" // Sorting function static inline int compare (const void * a, const void * b) { - int64_t delta = ( *(int64_t*)a - *(int64_t*)b ) ; - //return value for delta==0 won't matter since it's not happening here - if (delta < 0) - { - return (-1) ; - } - else// if (delta >= 0) - { - return (1) ; - } + return ( *(int64_t*)a - *(int64_t*)b ); } -SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangular solve +SPEX_info spex_left_lu_ref_triangular_solve // sparse REF triangular solve ( int64_t *top_output, // Output the beginning of nonzero pattern - SPEX_matrix* L, // partial L matrix - const SPEX_matrix* A, // input matrix + SPEX_matrix L, // partial L matrix + const SPEX_matrix A, // input matrix int64_t k, // constructing L(:,k) - int64_t* xi, // nonzero pattern vector - const int64_t* q, // column permutation, not modified - SPEX_matrix* rhos, // sequence of pivots - const int64_t* pinv, // inverse row permutation - const int64_t* row_perm, // row permutation - int64_t* h, // history vector - SPEX_matrix* x // solution of system ==> kth column of L and U + int64_t *xi, // nonzero pattern vector + const int64_t *q, // column permutation, not modified + SPEX_matrix rhos, // sequence of pivots + const int64_t *pinv, // inverse row permutation + const int64_t *row_perm, // row permutation + int64_t *h, // history vector + SPEX_matrix x // solution of system ==> kth column of L and U ) { @@ -104,7 +96,7 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula // check inputs //-------------------------------------------------------------------------- - // inputs have been validated in SPEX_Left_LU_factorize.c + // inputs have been validated in SPEX_lu_factorize SPEX_info info ; SPEX_REQUIRE(L, SPEX_CSC, SPEX_MPZ); SPEX_REQUIRE(A, SPEX_CSC, SPEX_MPZ); @@ -151,7 +143,7 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula // Reset x[i] = 0 for all i in nonzero pattern xi [top..n-1] for (i = top; i < n; i++) { - SPEX_CHECK (SPEX_mpz_set_ui (x_mpz[xi [i]], 0)) ; + SPEX_MPZ_SET_UI (x_mpz[xi [i]], 0); } // Set x[col] = 0. A(col,col) is the diagonal entry in the original // matrix. The pivot search prefers to select the diagonal, if it is @@ -159,7 +151,7 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula // not in the pattern xi [top..n-1]. The value x[col] is set to zero // here, in case the entry A(col,col) is not present, so that the pivot // search query the value of the diagonal. - SPEX_CHECK(SPEX_mpz_set_ui(x_mpz[col], 0)); + SPEX_MPZ_SET_UI(x_mpz[col], 0); // Reset h[i] = -1 for all i in nonzero pattern xi [top..n-1] for (i = top; i < n; i++) @@ -171,7 +163,7 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula for (i = A->p[col]; i < A->p[col + 1]; i++) { // Value of the ith nonzero - SPEX_CHECK(SPEX_mpz_set(x_mpz[A->i[i]], Ax_mpz[i])); + SPEX_MPZ_SET(x_mpz[A->i[i]], Ax_mpz[i]); } @@ -184,7 +176,7 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula j = xi[p]; // First nonzero term jnew = pinv[j]; // Location of nonzero term // Check if x[j] == 0, if so continue to next nonzero - SPEX_CHECK(SPEX_mpz_sgn(&sgn, x_mpz[j])); + SPEX_MPZ_SGN(&sgn, x_mpz[j]); if (sgn == 0) {continue;} // x[j] = 0 no work must be done // x[j] is nonzero @@ -196,13 +188,13 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula if (h[j] < jnew - 1) // HU must be performed { // x[j] = x[j] * rho[j-1] - SPEX_CHECK(SPEX_mpz_mul(x_mpz[j],x_mpz[j],rhos_mpz[jnew-1])); + SPEX_MPZ_MUL(x_mpz[j],x_mpz[j],rhos_mpz[jnew-1]); if (h[j] > -1) { // x[j] = x[j] / rho[h[j]] - SPEX_CHECK(SPEX_mpz_divexact(x_mpz[j],x_mpz[j], - rhos_mpz[h[j]])); + SPEX_MPZ_DIVEXACT(x_mpz[j],x_mpz[j], + rhos_mpz[h[j]]); } } @@ -218,11 +210,11 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula if (inew > jnew) { /*************** If lij==0 then no update******************/ - SPEX_CHECK(SPEX_mpz_sgn(&sgn, Lx_mpz[m])); + SPEX_MPZ_SGN(&sgn, Lx_mpz[m]); if (sgn == 0) {continue;} // lij is nonzero. Check if x[i] is nonzero - SPEX_CHECK(SPEX_mpz_sgn(&sgn, x_mpz[i])); + SPEX_MPZ_SGN(&sgn, x_mpz[i]); //---------------------------------------------------------- /************* lij is nonzero, x[i] is zero****************/ @@ -236,8 +228,8 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula if (jnew < 1) { // x[i] = 0 - lij*x[j] - SPEX_CHECK(SPEX_mpz_submul(x_mpz[i], Lx_mpz[m], - x_mpz[j])); + SPEX_MPZ_SUBMUL(x_mpz[i], Lx_mpz[m], + x_mpz[j]); h[i] = jnew; // Entry is up to date } @@ -245,12 +237,12 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula else { // x[i] = 0 - lij*x[j] - SPEX_CHECK(SPEX_mpz_submul(x_mpz[i], Lx_mpz[m], - x_mpz[j])); + SPEX_MPZ_SUBMUL(x_mpz[i], Lx_mpz[m], + x_mpz[j]); // x[i] = x[i] / rho[j-1] - SPEX_CHECK(SPEX_mpz_divexact(x_mpz[i], x_mpz[i], - rhos_mpz[jnew-1])); + SPEX_MPZ_DIVEXACT(x_mpz[i], x_mpz[i], + rhos_mpz[jnew-1]); h[i] = jnew; // Entry is up to date } } @@ -265,12 +257,11 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula if (jnew < 1) { // x[i] = x[i]*rho[0] - SPEX_CHECK(SPEX_mpz_mul(x_mpz[i],x_mpz[i], - rhos_mpz[0])); + SPEX_MPZ_MUL(x_mpz[i], x_mpz[i], rhos_mpz[0]); // x[i] = x[i] - lij*xj - SPEX_CHECK(SPEX_mpz_submul(x_mpz[i], Lx_mpz[m], - x_mpz[j])); + SPEX_MPZ_SUBMUL(x_mpz[i], Lx_mpz[m], + x_mpz[j]); h[i] = jnew; // Entry is now up to date } // There is a previous pivot @@ -280,24 +271,23 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula if (h[i] < jnew - 1) { // x[i] = x[i] * rho[j-1] - SPEX_CHECK(SPEX_mpz_mul(x_mpz[i], x_mpz[i], - rhos_mpz[jnew-1])); + SPEX_MPZ_MUL(x_mpz[i], x_mpz[i], + rhos_mpz[jnew-1]); if (h[i] > -1) { // x[i] = x[i] / rho[h[i]] - SPEX_CHECK(SPEX_mpz_divexact(x_mpz[i], - x_mpz[i], rhos_mpz[h[i]])); + SPEX_MPZ_DIVEXACT(x_mpz[i], + x_mpz[i], rhos_mpz[h[i]]); } } // x[i] = x[i] * rho[j] - SPEX_CHECK(SPEX_mpz_mul(x_mpz[i],x_mpz[i], - rhos_mpz[jnew])); + SPEX_MPZ_MUL(x_mpz[i], x_mpz[i], rhos_mpz[jnew]); // x[i] = x[i] - lij*xj - SPEX_CHECK(SPEX_mpz_submul(x_mpz[i], Lx_mpz[m], - x_mpz[j])); + SPEX_MPZ_SUBMUL(x_mpz[i], Lx_mpz[m], + x_mpz[j]); // x[i] = x[i] / rho[j-1] - SPEX_CHECK(SPEX_mpz_divexact(x_mpz[i], x_mpz[i], - rhos_mpz[jnew-1])); + SPEX_MPZ_DIVEXACT(x_mpz[i], x_mpz[i], + rhos_mpz[jnew-1]); h[i] = jnew; // Entry is up to date } } @@ -312,18 +302,18 @@ SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangula if (h[j] < k-1) { // x[j] = x[j] * rho[k-1] - SPEX_CHECK(SPEX_mpz_mul(x_mpz[j], x_mpz[j], rhos_mpz[k-1])); + SPEX_MPZ_MUL(x_mpz[j], x_mpz[j], rhos_mpz[k-1]); if (h[j] > -1) { // x[j] = x[j] / rho[h[j]] - SPEX_CHECK(SPEX_mpz_divexact(x_mpz[j], x_mpz[j], - rhos_mpz[h[j]])); + SPEX_MPZ_DIVEXACT(x_mpz[j], x_mpz[j], + rhos_mpz[h[j]]); } } } } // Output the beginning of nonzero pattern - *top_output = top; + (*top_output) = top; return SPEX_OK; } diff --git a/SPEX/SPEX_LU/Source/spex_lu_internal.h b/SPEX/SPEX_LU/Source/spex_lu_internal.h new file mode 100644 index 0000000000..577e4bf463 --- /dev/null +++ b/SPEX/SPEX_LU/Source/spex_lu_internal.h @@ -0,0 +1,183 @@ +//------------------------------------------------------------------------------ +// SPEX_LU/Source/spex_left_lu_internal: include file for internal use in +// SPEX_LU +//------------------------------------------------------------------------------ + +// SPEX_LU: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Timothy A. Davis, and Erick Moreno-Centeno. All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// This file is not intended to be #include'd in user applications. Use +// SPEX.h instead. + +#ifndef SPEX_LEFT_LU_INTERNAL_H +#define SPEX_LEFT_LU_INTERNAL_H + +#include "spex_util_internal.h" + +// ============================================================================ +// Internal Functions +// ============================================================================ + +/* Purpose: This function performs sparse REF forward substitution. This is + * essentially the same as the sparse REF triangular solve applied to each + * column of the right hand side vectors. Like the normal one, this function + * expects that the matrix x is dense. As a result,the nonzero pattern is not + * computed and each nonzero in x is iterated across. The system to solve is + * LDx = x. On output, the mpz_t** x structure is modified. + */ + +SPEX_info spex_left_lu_forward_sub +( + const SPEX_matrix L, // lower triangular matrix + SPEX_matrix x, // right hand side matrix of size n*numRHS + const SPEX_matrix rhos // sequence of pivots used in factorization +) ; + +/* Purpose: This function performs sparse REF backward substitution. In essense + * it solves the sysem Ux = x. Note that prior to this, we expect x to be + * multiplied by the determinant of A. The input argument bx is modified on + * output. + */ + +SPEX_info spex_left_lu_back_sub // performs sparse REF backward substitution +( + const SPEX_matrix U, // input upper triangular matrix + SPEX_matrix bx // right hand side matrix +) ; + +/* Purpose: This function performs a depth first search of the graph of the + * matrix starting at node j. The output of this function is the set of nonzero + * indices in the xi vector. + */ + +void spex_left_lu_dfs // dfs of the graph of the matrix starting at node j +( + int64_t *top, // beginning of stack + int64_t j, // What node to start DFS at + SPEX_matrix L, // matrix which represents the Graph of L + int64_t *xi, // the nonzero pattern + int64_t *pstack, // workspace vector + const int64_t *pinv // row permutation +) ; + +/* This function performs the pivoting for the SPEX Left LU factorization. + * The optional Order is: + * 0: Smallest pivot + * 1: Natural/Diagonal pivoting + * 2: Choose first nonzero (not recommended, for comparison only) + * 3: Diagonal with tolerance and smallest pivot (default) + * 4: Diagonal with tolerance and largest pivoting + * 5: Largest pivot (not recommended, for comparison only) + * + * On output, the pivs, pinv, and row_perm arrays and rhos matrix are all + * modified. + */ + +SPEX_info spex_left_lu_get_pivot +( + int64_t *pivot, // found index of pivot entry + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector indicating which rows have been pivotal + int64_t n, // dimension of the problem + int64_t top, // nonzero pattern is located in xi[top..n-1] + int64_t *xi, // nonzero pattern of x + int64_t col, // current column of A (real kth column i.e., q[k]) + int64_t k, // iteration of the algorithm + SPEX_matrix rhos, // vector of pivots + int64_t *pinv, // row permutation + int64_t *row_perm, // opposite of pinv. + // if pinv[i] = j then row_perm[j] = i + const SPEX_options option // command options +) ; + +/* Purpose: This function selects the pivot element as the largest in the + * column. This is activated if the user sets option->pivot = SPEX_LARGEST. + * NOTE: This pivoting scheme is NOT recommended for SPEX Left LU. On output + * the index of the largest pivot is returned. + */ + +SPEX_info spex_left_lu_get_largest_pivot +( + int64_t *pivot, // the index of largest pivot + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector which indicates whether each row + // has been pivotal + int64_t n, // dimension of problem + int64_t top, // nonzero pattern is located in xi[top..n-1] + int64_t *xi // nonzero pattern of x +) ; + +/* This function obtains the first eligible nonzero pivot. This is enabled if + * the user sets option->pivot = SPEX_FIRST_NONZERO. NOTE: This pivoting + * scheme is not recommended. On output, the kth pivot is returned. + */ + +SPEX_info spex_left_lu_get_nonzero_pivot // find first eligible nonzero pivot +( + int64_t *pivot, // the index of first eligible nonzero pivot + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector indicating which rows are pivotal + int64_t n, // size of x + int64_t top, // nonzero pattern is located in xi[top..n-1] + int64_t *xi // nonzero pattern of x +) ; + +/* Purpose: This function selects the pivot element as the smallest in the + * column. This is activated by default or if the user sets option->pivot = + * SPEX_SMALLEST. This is a recommended pivoting scheme for SPEX Left LU. + * On output, the index of kth pivot is returned. + */ + +SPEX_info spex_left_lu_get_smallest_pivot +( + int64_t *pivot, // the index of smallest pivot + SPEX_matrix x, // kth column of L and U + int64_t *pivs, // vector indicating if each row has been pivotal + int64_t n, // dimension of problem + int64_t top, // nonzeros are stored in xi[top..n-1] + int64_t *xi // nonzero pattern of x +) ; + +/* Purpose: This function computes the reach of column k of A on the graph of L + * mathematically that is: xi = Reach(A(:,k))_G_L. + */ + +void spex_left_lu_reach // compute reach of column k of A on the graph of L +( + int64_t *top, + SPEX_matrix L, // matrix representing graph of L + const SPEX_matrix A, // input matrix + int64_t k, // column of A of interest + int64_t *xi, // nonzero pattern + const int64_t *pinv // row permutation +) ; + +/* Purpose: This function performs the sparse REF triangular solve; that is, + * (LD) x = A(:,k). The algorithm is described in the paper; however in essence + * it computes the nonzero pattern xi, then performs a sequence of IPGE + * operations on the nonzeros to obtain their final value. All operations are + * gauranteed to be integral. There are various enhancements in this code used + * to reduce the overall cost of the operations and minimize operations as much + * as possible. + */ + +SPEX_info spex_left_lu_ref_triangular_solve // sparse REF triangular solve +( + int64_t *top_output, // Output the beginning of nonzero pattern + SPEX_matrix L, // partial L matrix + const SPEX_matrix A, // input matrix + int64_t k, // constructing L(:,k) + int64_t *xi, // nonzero pattern vector + const int64_t *q, // column permutation, not modified + SPEX_matrix rhos, // sequence of pivots + const int64_t *pinv, // inverse row permutation + const int64_t *row_perm, // row permutation + int64_t *h, // history vector + SPEX_matrix x // solution of system ==> kth column of L and U +) ; + +#endif + diff --git a/SPEX/SPEX_Left_LU/Demo/.gitignore b/SPEX/SPEX_Left_LU/Demo/.gitignore deleted file mode 100644 index e360d332e1..0000000000 --- a/SPEX/SPEX_Left_LU/Demo/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Ignore these files: -example -example2 -example3 -example4 -example5 -spexlu_demo diff --git a/SPEX/SPEX_Left_LU/Demo/demos.c b/SPEX/SPEX_Left_LU/Demo/demos.c deleted file mode 100644 index 50ec654175..0000000000 --- a/SPEX/SPEX_Left_LU/Demo/demos.c +++ /dev/null @@ -1,464 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/Demo/demos.c: support functions for the demo programs -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -// SPEX_print_options: print user options. -// SPEX_process_command_line: process command line for demo programs. -// SPEX_tripread: read a matrix from a file in triplet format. -// SPEX_tripread_double: read a double matrix from a file in triplet format. -// SPEX_read_dense: read a dense matrix from a file. - -#include "demos.h" - -#if defined (__GNUC__) -// ignore warnings about unused parameters in this file -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - -//------------------------------------------------------------------------------ -// SPEX_print_options -//------------------------------------------------------------------------------ - -/* Purpose: This function prints out the user specified/default options. - * this is primarily intended for debugging - */ - -void SPEX_print_options // display specified/default options to user -( - SPEX_options* option // options (cannot be NULL) -) -{ - - char *piv, *order; - if (option->order == SPEX_COLAMD) - { - order = "the COLAMD"; - } - else if (option->order == SPEX_AMD) - { - order = "the AMD"; - } - else if (option->order == SPEX_NO_ORDERING) - { - order = "No"; - } - else - { - order = "(undefined)"; - } - - if (option->pivot == SPEX_SMALLEST) - { - piv = "smallest"; - } - else if (option->pivot == SPEX_DIAGONAL) - { - piv = "diagonal"; - } - else if (option->pivot == SPEX_FIRST_NONZERO) - { - piv = "first nonzero"; - } - else if (option->pivot == SPEX_TOL_SMALLEST) - { - piv = "diagonal small tolerance"; - } - else if (option->pivot == SPEX_TOL_LARGEST) - { - piv = "diagonal large tolerance"; - } - else - { - piv = "largest"; - } - - printf("\n\n****COMMAND PARAMETERS****"); - printf("\nUsing %s ordering and selecting the %s pivot", order, piv); - if (option->pivot == SPEX_TOL_SMALLEST || - option->pivot == SPEX_TOL_LARGEST) - { - printf("\nTolerance used: %lf\n",option->tol); - } -} - -//------------------------------------------------------------------------------ -// SPEX_process_command_line -//------------------------------------------------------------------------------ - -/* Purpose: This processes the command line for user specified options */ - -SPEX_info SPEX_process_command_line //processes the command line -( - int argc, // number of command line arguments - char* argv[], // set of command line arguments - SPEX_options* option, // options (cannot be NULL) - char** mat_name, // Name of the matrix to be read in - char** rhs_name, // Name of the RHS vector to be read in - SPEX_type *rat // data type of output solution: - // 1:SPEX_MPZ (default), 2:SPEX_FP64, 3:SPEX_MPFR -) -{ - (*rat) = SPEX_MPZ ; - - for (int i = 1; i < argc; i++) - { - char* arg = (char*) argv[i]; - if ( strcmp(arg,"p") == 0 || strcmp(arg,"piv") == 0) - { - if (!argv[++i]) - { - printf("\n****ERROR! There must be a pivot argument between" - " 0-5 following p\n"); - return SPEX_INCORRECT_INPUT; - } - option->pivot = atoi(argv[i]); - if (option->pivot < 0 || option->pivot > 5) - { - printf("\n****ERROR! Invalid pivot selection!" - "\nDefaulting to smallest pivot\n\n"); - option->pivot = SPEX_SMALLEST; - } - } - else if ( strcmp(arg, "q") == 0 || strcmp(arg,"col") == 0) - { - if (!argv[++i]) - { - printf("\n****ERROR! There must be an argument between 0-2" - "following q\n"); - return SPEX_INCORRECT_INPUT; - } - option->order = atoi(argv[i]); - if (option->order < 0 || option->order > 2) - { - printf("\n****ERROR! Invalid column ordering" - "\nDefaulting to COLAMD\n\n"); - option->order = SPEX_COLAMD; - } - } - else if ( strcmp(arg,"t") == 0 || strcmp(arg, "tol") == 0) - { - if (!argv[++i]) - { - printf("\n****ERROR! There must be a non negative tolerance" - " value following t\n"); - return SPEX_INCORRECT_INPUT; - } - else if (!atof(argv[i])) - { - printf("\n****ERROR! There must be a non negative tolerance" - " value following t\n"); - return SPEX_INCORRECT_INPUT; - } - option->tol = atof(argv[i]); - if (option->tol < 0) - { - printf("\n****ERROR! Invalid Tolerance, tolerance must be" - " non-negative\n"); - return SPEX_INCORRECT_INPUT; - } - } - else if ( strcmp(arg,"out") == 0 || strcmp(arg, "o") == 0) - { - if (!argv[++i]) - { - printf("\n****ERROR! o or out must be followed by" - " 0 (print nothing) 1 (print err) or 2 (terse) \n"); - return SPEX_INCORRECT_INPUT; - } - else if (!atoi(argv[i])) - { - printf("\n****ERROR! o or out must be followed by" - " 0 (print nothing) 1 (print err) or 2 (terse) \n"); - return SPEX_INCORRECT_INPUT; - } - option->print_level = atoi(argv[i]); - } - else if ( strcmp(arg, "f") == 0 || strcmp(arg, "file") == 0) - { - if (!argv[++i]) - { - printf("\n****ERROR! Matrix name must be entered\n"); - return SPEX_INCORRECT_INPUT; - } - *mat_name = argv[i]; - if (!argv[++i]) - { - printf("\n****ERROR! Right hand side vector name must" - " be entered\n"); - return SPEX_INCORRECT_INPUT; - } - *rhs_name = argv[i]; - } - else - { - printf("\n\n**ERROR! Unknown command line parameter: %s" - "\nIgnoring this parameter\n",arg); - return SPEX_INCORRECT_INPUT; - } - } - - return SPEX_OK; -} - -//------------------------------------------------------------------------------ -// SPEX_tripread -//------------------------------------------------------------------------------ - -/* Purpose: This function reads in a matrix stored in a triplet format - * This format used can be seen in any of the example mat files. - * - * The first line of the file contains three integers: m, n, nnz, - * where the matrix is m-by-n with nnz entries. - * - * This is followed by nnz lines, each containing a single triplet: i, j, aij, - * which defines the row index (i), column index (j), and value (aij) of - * the entry A(i,j). The value aij is an integer. - */ - -SPEX_info SPEX_tripread -( - SPEX_matrix **A_handle, // Matrix to be constructed - FILE* file, // file to read from (must already be open) - SPEX_options* option // Command options -) -{ - - SPEX_info info ; - if (A_handle == NULL || file == NULL) - { - printf ("invalid input\n") ; - return SPEX_INCORRECT_INPUT; - } - - (*A_handle) = NULL ; - - int64_t m, n, nz; - - // Read in size of matrix & number of nonzeros - int s = fscanf(file, "%"PRId64" %"PRId64" %"PRId64"\n", &m, &n, &nz); - if (feof(file) || s < 3) - { - printf ("premature end-of-file\n") ; - return SPEX_INCORRECT_INPUT; - } - - // Allocate memory for A - // A is a triplet mpz_t matrix - SPEX_matrix* A = NULL; - info = SPEX_matrix_allocate(&A, SPEX_TRIPLET, SPEX_MPZ, m, n, nz, - false, true, option); - if (info != SPEX_OK) - { - return (info) ; - } - - // Read in first values of A - info = SPEX_gmp_fscanf(file, "%"PRId64" %"PRId64" %Zd\n", - &A->i[0], &A->j[0], &A->x.mpz[0]); - if (feof (file) || info != SPEX_OK) - { - printf ("premature end-of-file\n") ; - SPEX_matrix_free(&A, option); - return SPEX_INCORRECT_INPUT; - } - - // Matrices in this format are 1 based, so we decrement by 1 to get - // 0 based for internal functions - A->i[0] -= 1; - A->j[0] -= 1; - - // Read in the values from file - for (int64_t p = 1; p < nz; p++) - { - info = SPEX_gmp_fscanf(file, "%"PRId64" %"PRId64" %Zd\n", - &A->i[p], &A->j[p], &A->x.mpz[p]); - if ((feof(file) && p != nz-1) || info != SPEX_OK) - { - printf ("premature end-of-file\n") ; - SPEX_matrix_free(&A, option); - return SPEX_INCORRECT_INPUT; - } - // Conversion from 1 based to 0 based if necessary - A->i[p] -= 1; - A->j[p] -= 1; - } - - // the triplet matrix now has nz entries - A->nz = nz; - - // A now contains our input matrix in triplet format. We now - // do a matrix copy to get it into CSC form - // C is a copy of A which is CSC and mpz_t - SPEX_matrix* C = NULL; - SPEX_matrix_copy(&C, SPEX_CSC, SPEX_MPZ, A, option); - - // Free A, set A_handle - SPEX_matrix_free(&A, option); - (*A_handle) = C; - return (info) ; -} - -//------------------------------------------------------------------------------ -// SPEX_tripread_double -//------------------------------------------------------------------------------ - -/* Purpose: This function reads in a double matrix stored in a triplet format - * This format used can be seen in any of the example mat files. - * - * The first line of the file contains three integers: m, n, nnz, - * where the matrix is m-by-n with nnz entries. - * - * This is followed by nnz lines, each containing a single triplet: i, j, aij, - * which defines the row index (i), column index (j), and value (aij) of - * the entry A(i,j). The value aij is a floating-point number. - */ - -SPEX_info SPEX_tripread_double -( - SPEX_matrix **A_handle, // Matrix to be populated - FILE* file, // file to read from (must already be open) - SPEX_options* option -) -{ - - SPEX_info info ; - if (A_handle == NULL || file == NULL) - { - printf ("invalid input\n") ; - return SPEX_INCORRECT_INPUT; - } - (*A_handle) = NULL ; - - // Read in triplet form first - int64_t m, n, nz; - - // Read in size of matrix & number of nonzeros - int s = fscanf(file, "%"PRId64" %"PRId64" %"PRId64"\n", &m, &n, &nz); - if (feof(file) || s < 3) - { - printf ("premature end-of-file\n") ; - return SPEX_INCORRECT_INPUT; - } - - // First, we create our A matrix which is triplet double - SPEX_matrix *A = NULL; - info = SPEX_matrix_allocate(&A, SPEX_TRIPLET, SPEX_FP64, m, n, nz, - false, true, option); - if (info != SPEX_OK) - { - return (info) ; - } - - info = fscanf (file, "%"PRId64" %"PRId64" %lf\n", - &(A->i[0]), &(A->j[0]), &(A->x.fp64[0])) ; - if (feof(file) || info != SPEX_OK) - { - printf ("premature end-of-file\n") ; - SPEX_matrix_free(&A, option); - return SPEX_INCORRECT_INPUT; - } - - // Matrices in this format are 1 based. We decrement - // the indices by 1 to use internally - A->i[0] -= 1; - A->j[0] -= 1; - - // Read in the values from file - for (int64_t k = 1; k < nz; k++) - { - s = fscanf(file, "%"PRId64" %"PRId64" %lf\n", - &(A->i[k]), &(A->j[k]), &(A->x.fp64[k])); - if ((feof(file) && k != nz-1) || s < 3) - { - printf ("premature end-of-file\n") ; - SPEX_matrix_free(&A, option); - return SPEX_INCORRECT_INPUT; - } - // Conversion from 1 based to 0 based - A->i[k] -= 1; - A->j[k] -= 1; - } - - // the triplet matrix now has nz entries - A->nz = nz; - - // At this point, A is a double triplet matrix. We make a copy of it with C - - SPEX_matrix* C = NULL; - SPEX_matrix_copy(&C, SPEX_CSC, SPEX_MPZ, A, option); - - // Success. Set A_handle = C and free A - - SPEX_matrix_free(&A, option); - (*A_handle) = C; - return (info) ; -} - -//------------------------------------------------------------------------------ -// SPEX_read_dense -//------------------------------------------------------------------------------ - -/* Purpose: Read a dense matrix for RHS vectors. - * the values in the file must be integers - */ - -SPEX_info SPEX_read_dense -( - SPEX_matrix **b_handle, // Matrix to be constructed - FILE* file, // file to read from (must already be open) - SPEX_options* option -) -{ - - if (file == NULL) - { - printf ("invalid inputs\n") ; - return SPEX_INCORRECT_INPUT; - } - int64_t nrows, ncols; - SPEX_info info ; - - // First, we obtain the dimension of the matrix - int s = fscanf(file, "%"PRId64" %"PRId64, &nrows, &ncols) ; - if (feof(file) || s < 2) - { - printf ("premature end-of-file\n") ; - return SPEX_INCORRECT_INPUT; - } - - // Now, we create our dense mpz_t matrix - SPEX_matrix* A = NULL; - info = SPEX_matrix_allocate(&A, SPEX_DENSE, SPEX_MPZ, nrows, ncols, - nrows*ncols, false, true, option); - if (info != SPEX_OK) - { - return (info) ; - } - - // We now populate the matrix b. - for (int64_t i = 0; i < nrows; i++) - { - for (int64_t j = 0; j < ncols; j++) - { - info = SPEX_gmp_fscanf(file, "%Zd", &(SPEX_2D(A, i, j, mpz))); - if (info != SPEX_OK) - { - printf("\n\nhere at i = %"PRId64" and j = %"PRId64"", i, j); - return SPEX_INCORRECT_INPUT; - } - } - } - - //-------------------------------------------------------------------------- - // Success, set b_handle = A - //-------------------------------------------------------------------------- - - (*b_handle) = A; - return (info) ; -} diff --git a/SPEX/SPEX_Left_LU/Demo/demos.h b/SPEX/SPEX_Left_LU/Demo/demos.h deleted file mode 100644 index fc77d659df..0000000000 --- a/SPEX/SPEX_Left_LU/Demo/demos.h +++ /dev/null @@ -1,76 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/Demo/demos.h: #include file the demo programs -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -#include "SPEX.h" -#include -#include -#include - -#define OK(method) \ -{ \ - ok = method ; \ - if (ok != SPEX_OK) \ - { \ - printf ("Error: %d line %d file %s\n", ok, __LINE__, __FILE__) ; \ - FREE_WORKSPACE ; \ - return 0 ; \ - } \ -} - -#define SPEX_MIN(a,b) (((a) < (b)) ? (a) : (b)) - -/* Purpose: This processes the command line for user specified options */ -SPEX_info SPEX_process_command_line //processes the command line -( - int argc, // number of command line arguments - char* argv[], // set of command line arguments - SPEX_options* option, // struct containing the command options - char** mat_name, // Name of the matrix to be read in - char** rhs_name, // Name of the RHS vector to be read in - SPEX_type *rat // data type of output solution: - // 1:SPEX_MPZ (default), 2:SPEX_FP64, 3:SPEX_MPFR -); - -/* Purpose: This function prints out the user specified/default options*/ -void SPEX_print_options // display specified/default options to user -( - SPEX_options* option // struct containing all of the options -); - -/* Purpose: This function shows the usage of the code.*/ -void SPEX_show_usage(void); - -/* Purpose: This function reads in a matrix stored in a triplet format. - * This format used can be seen in any of the example mat files. - */ -SPEX_info SPEX_tripread -( - SPEX_matrix **A_handle, // Matrix to be constructed - FILE* file, // file to read from (must already be open) - SPEX_options* option -) ; - -/* Purpose: This function reads in a double matrix stored in a triplet format. - * This format used can be seen in any of the example mat files. - */ -SPEX_info SPEX_tripread_double -( - SPEX_matrix **A_handle, // Matrix to be constructed - FILE* file, // file to read from (must already be open) - SPEX_options* option -) ; - -/* Purpose: SPEX_read_dense: read a dense matrix. */ -SPEX_info SPEX_read_dense -( - SPEX_matrix **b_handle, // Matrix to be constructed - FILE* file, // file to read from (must already be open) - SPEX_options* option -) ; diff --git a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_demo.m b/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_demo.m deleted file mode 100644 index c9b75f71dd..0000000000 --- a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_demo.m +++ /dev/null @@ -1,109 +0,0 @@ -% SPEX_Left_LU_DEMO a demo of SPEX_Left_LU_backslash -% SPEX_Left_LU_LU is a package for solving sparse linear systems of equations -% with a roundoff-free integer-preserving method. The result is -% always exact, unless the matrix A is perfectly singular. -% -% See also vpa, SPEX_Left_LU_backslash, SPEX_Left_LU_install, SPEX_Left_LU_test. -% -% SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -% Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -format compact - -%% SPEX_Left_LU_backslash vs MATLAB backslash: first example -% In this first example, x = SPEX_Left_LU_backslash (A,b) returns an approximate -% solution, but not because it was computed incorrectly in SPEX_Left_LU_backslash. -% It is computed exactly as a rational result in SPEX_backslash with -% arbitrary precision, but then converted to double precision on output. - -format long g -load west0479 -A = west0479 ; -n = size (A, 1) ; -xtrue = rand (n,1) ; -b = A*xtrue ; -x = SPEX_Left_LU_backslash (A, b) ; -% error is nonzero: x is computed exactly in rational arbitrary-precision, -% but then lost precision when returned to MATLAB: -err_spex = norm (x-xtrue) -x = A\b ; -% error is nonzero: MATLAB x=A\b experiences floating-point error -% throughout its computations: -err_matlab = norm (x-xtrue) - -%% SPEX_Left_LU_backslash: exact, vs MATLAB backslash: approximate -% In this example, x = SPEX_Left_LU_backslash (A,b) is returned exactly in the -% MATLAB vector x, because x contains only integers representable exactly -% in double precision. x = A\b results in floating-point roundoff error. - -amax = max (abs (A), [ ], 'all') ; -A = floor (2^20 * (A / amax)) + n * speye (n) ; -xtrue = floor (64 * xtrue) ; -b = A*xtrue ; -x = SPEX_Left_LU_backslash (A, b) ; -% error will be exactly zero: -err_spex = norm (x-xtrue) -x = A\b ; -% error will be small but nonzero: -err_matlab = norm (x-xtrue) - -%% SPEX_Left_LU_backslash on ill-conditioned problems -% x = SPEX_Left_LU_backslash (A,b) is able to solve problems that x=A\b cannot. -% Consider the following matrix in the MATLAB gallery: - -[U, b] = gallery ('wilk', 3) - -%% vpa can find a good but not perfect solution: -xvpa = vpa (U) \ b - -% but MATLAB's numerical x = U\b computes a poor solution: -xapprox = U \ b - -%% SPEX_Left_LU_backslash computes the exact answer -% It returns it to MATLAB as a double vector, obtaining the exact results, -% except for a final floating-point error in x(2): - -xspex = SPEX_Left_LU_backslash (U, b) -err = xvpa - xspex -relerr = double (err (2:3) ./ xvpa (2:3)) - -%% SPEX_Left_LU_backslash with exact results -% SPEX_Left_LU_backslash can also return x as a cell array of strings, which -% preserves the exact rational result. The printing option is also -% enabled in this example. The floating-point matrices U and b are -% converted into a scaled integer matrix before solving U*x=b with -% SPEX Left LU. -% -% The value U(1,2)=0.9 is a floating-point number, and 0.9 cannot be -% exactly represented in IEEE floating-point representation. It is -% converted exactly into the rational number, -% fl(0.9) = 45000000000000001 / 50000000000000000. - -option.print = 3 ; % also print the details -option.solution = 'char' ; % return x as a cell array of strings - -%% - -xspex = SPEX_Left_LU_backslash (U, b, option) - -%% Converting an exact rational result to vpa or double -% If SPEX_backslash returns x as a cell array of strings, it cannot -% be immediately used in computations in MATLAB. It can be converted -% into a vpa or double matrix, as illustrated below. The solution -% differs slightly from the vpa solution xvpa = vpa (U)\b, since -% the MATLAB vpa converts fl(0.9) into a decimal representation 0.9, -% or exactly 9/10; this is not exactly equal to fl(0.9), since the -% value 9/10 is not representable in IEEE floating-point. SPEX_backslash, -% by contrast, converts fl(0.9) into its exact rational representation, -% 45000000000000001 / 50000000000000000. - -xspex_as_vpa = vpa (xspex) -xspex_as_double = double (vpa (xspex)) -xvpa_as_double = double (xvpa) - -%% Comparing the VPA and SPEX_Left_LU_BACKSLASH solutions in double -% Both vpa(U)\b and SPEX_backslash(U,b) compute the same result -% in the end, when their results are converted to double. -err = xvpa_as_double - xspex_as_double - diff --git a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_install.m b/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_install.m deleted file mode 100644 index 2446672404..0000000000 --- a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_install.m +++ /dev/null @@ -1,85 +0,0 @@ -function SPEX_Left_LU_install(run_demo) -% SPEX_Left_LU_INSTALL: install and test the MATLAB interface to SPEX_backslash. -% This function installs the SPEX Left LU mexFunction for use by the m-file -% SPEX_Left_LU_backslash.m. -% -% Usage: SPEX_Left_LU_install -% -% Required Libraries: GMP, MPFR, AMD, COLAMD. If -lamd and -lcolamd are not -% available, install them with 'make install' first, in the top-level -% SuiteSparse/lib folder, and add SuiteSparse/lib to your LD_LIBRARY_PATH -% and restart MATLAB. -% -% See also SPEX_Left_LU_backslash, SPEX_Left_LU_test, SPEX_Left_LU_demo. - -% SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -% Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -help SPEX_Left_LU_install - -if (nargin < 1) - run_demo = true ; -end - -fprintf ('Compiling the SPEX Left LU mexFunction for use in SPEX_Left_LU_backslash:\n') ; - -% Find all source files and add them to the src string -src = ''; -path = './Source/'; -files = dir('./Source/*.c'); -[m n] = size(files); -for k = 1:m - tmp = [' ', path, files(k).name]; - src = [src, tmp]; -end -path = '../Source/'; -files = dir('../Source/*.c'); -[m n] = size(files); -for k = 1:m - tmp = [' ', path, files(k).name]; - src = [src, tmp]; -end -path = '../../SPEX_Util/Source/'; -files = dir('../../SPEX_Util/Source/*.c'); -[m n] = size(files); -for k = 1:m - tmp = [' ', path, files(k).name]; - src = [src, tmp]; -end - -% Compiler flags -flags = 'CFLAGS=''-std=c99 -fPIC'''; - -% External libraries: GMP, MPRF, AMD, and COLAMD -libs = '-L../../../lib -lgmp -lmpfr -lamd -lcolamd -lsuitesparseconfig' ; - -% Path to headers -includes = '-ISource/ -I../Source/ -I../../Include -I../../../SuiteSparse_config -I../../../COLAMD/Include -I../../../AMD/Include -I../../SPEX_Util/Source'; - -% verbose = ' -v ' -verbose = '' ; - -% Generate the mex commands here -% having -R2018a here for function mxGetDoubles -m1 = ['mex ', verbose, ' -R2018a ', includes, ' SPEX_Left_LU_mex_soln.c ' , src, ' ', flags, ' ', libs]; - -if (~isempty (verbose)) - fprintf ('%s\n', m1) ; -end - -% Now, we evaluate each one -eval (m1) ; - -if (run_demo) - % Test SPEX_backslash. - SPEX_Left_LU_test ; -end - -fprintf ('To use SPEX_Left_LU_backslash in future MATLAB sessions, add the following\n') ; -fprintf ('line to your startup.m file:\n') ; -fprintf (' addpath (''%s'') ;\n', pwd) ; -fprintf ('Type ''doc startup'' for more info on how to use startup.m\n') ; -fprintf ('To run a demo, type:\n') ; -fprintf (' echodemo SPEX_Left_LU_demo ;\n') ; - diff --git a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_test.m b/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_test.m deleted file mode 100644 index 4de9424f3b..0000000000 --- a/SPEX/SPEX_Left_LU/MATLAB/SPEX_Left_LU_test.m +++ /dev/null @@ -1,89 +0,0 @@ -function SPEX_Left_LU_test -%SPEX_Left_LU_test: run a set of tests for SPEX_Left_LU_backslash -% -% Usage: SPEX_Left_LU_test -% -% See also SPEX_install, SPEX_demo. - -% SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -% Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -% SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -maxerr = 0 ; -rng ('default') ; - -fprintf ('Testing SPEX_Left_LU_backslash: ') ; - -% First, check if we can use a real life sparse matrix via ssget -if (exist ('ssget') ~= 0) - fprintf ('. (please wait) ') ; - % 159 is a square SPD matrix - prob = ssget(159); - A = prob.A; - [m n] = size(A); - b = rand(m, 1); - fprintf ('.') ; - x = SPEX_Left_LU_backslash(A,b); - x2 = A\b; - err = norm(x-x2)/norm(x); - maxerr = max (maxerr, err) ; - - % now convert to an integer problem (x will not be integer) - A = floor (2^20 * A) ; - b = floor (2^20 * b) ; - fprintf ('.') ; - x = SPEX_Left_LU_backslash (A, b) ; - x2 = A\b; - err = norm(x-x2)/norm(x); - maxerr = max (maxerr, err) ; - fprintf ('.') ; -end - -orderings = { 'none', 'colamd', 'amd' } ; -pivotings = { 'smallest', 'diagonal', 'first', ... - 'tol smallest', 'tol largest', 'largest' } ; - -for n = [1 10 100] - for density = [0.001 0.05 0.5 1] - - % construct a well-conditioned problem to solve - A = sprand(n,n,density); - A = A+A' + n * speye (n) ; - b = rand(n,1); - - for korder = 1:length (orderings) - for kpiv = 1:length (pivotings) - for tol = [0.1 0.5] - - clear option - option.order = orderings {korder} ; - option.pivot = pivotings {kpiv} ; - option.tol = tol ; - - fprintf ('.') ; - x = SPEX_Left_LU_backslash(A,b, option); - x2 = A\b; - err = norm(x-x2)/norm(x); - maxerr = max (maxerr, err) ; - - % now convert to an integer problem (x will not be integer) - A = floor (2^20 * A) ; - b = floor (2^20 * b) ; - x = SPEX_Left_LU_backslash(A,b, option); - x2 = A\b; - err = norm(x-x2)/norm(x); - maxerr = max (maxerr, err) ; - end - end - end - end -end - -fprintf ('\nmaxerr: %g\n', maxerr) ; - -if (maxerr < 1e-6) - fprintf('\nTesting complete, installation successful\n') -else - error ('SPEX_Left_LU_backslash:test', '\nTesting failure! error too high\n') -end - diff --git a/SPEX/SPEX_Left_LU/MATLAB/Source/SPEX_Left_LU_mex.h b/SPEX/SPEX_Left_LU/MATLAB/Source/SPEX_Left_LU_mex.h deleted file mode 100644 index be95af676a..0000000000 --- a/SPEX/SPEX_Left_LU/MATLAB/Source/SPEX_Left_LU_mex.h +++ /dev/null @@ -1,94 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/MATLAB/SPEX_Left_LU_mex.h: include file for MATLAB functions -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -#ifndef SPEX_LEFT_LU_MEX_H -#define SPEX_LEFT_LU_MEX_H - -#include "spex_left_lu_internal.h" -#include "matrix.h" - -#define SPEX_MEX_OK(method) \ -{ \ - status = method ; \ - if (status != SPEX_OK) \ - { \ - spex_left_lu_mex_error (status, "") ; \ - } \ -} - -typedef enum -{ - SPEX_SOLUTION_DOUBLE = 0, // x as double - SPEX_SOLUTION_VPA = 1, // return x as vpa - SPEX_SOLUTION_CHAR = 2 // x as cell strings -} -SPEX_solution ; - -typedef struct spex_mex_options -{ - SPEX_solution solution ; // how should x be returned to MATLAB - int32_t digits ; // # of digits to use for vpa -} -spex_mex_options ; - -/* Purpose: A GMP reallocation function - * This allows GMP to use MATLAB's default realloc function - */ -void* SPEX_gmp_mex_realloc -( - void* x, // void* to be reallocated - size_t a, // Previous size - size_t b // New size -); - -/* Purpose: A GMP free function. This allows GMP to use - * MATLAB's mxFree instead of free - */ -void SPEX_gmp_mex_free -( - void* x, // void* to be freed - size_t a // Size -); - -void spex_left_lu_get_matlab_options -( - SPEX_options* option, // Control parameters - spex_mex_options *mexoptions, // MATLAB-specific options - const mxArray* input // options struct, may be NULL -) ; - -// Purpose: This function checks if the array x contains Inf's, NaN's, or -// if its values can be represented as int64_t values. - -bool spex_left_lu_mex_check_for_inf // true if x can be represented as int64_t -( - double* x, // The array of numeric values - mwSize n // size of array -) ; - -/* Purpose: This function reads in the A matrix and right hand side vectors. */ -void spex_left_lu_mex_get_A_and_b -( - SPEX_matrix **A_handle, // Internal SPEX Mat stored in CSC - SPEX_matrix **b_handle, // mpz matrix used internally - const mxArray* pargin[], // The input A matrix and options - SPEX_options* option -) ; - -/* Purpose: Report errors if they arise - */ -void spex_left_lu_mex_error -( - SPEX_info status, - char *message -) ; - -#endif - diff --git a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_check_for_inf.c b/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_check_for_inf.c deleted file mode 100644 index 2fe2711fc0..0000000000 --- a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_check_for_inf.c +++ /dev/null @@ -1,58 +0,0 @@ -// //------------------------------------------------------------------------------ -// SPEX_Left_LU/MATLAB/spex_left_lu_mex_check_for_inf: Check A and b for inf -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -// Purpose: This function checks if the array x contains Inf's, NaN's, or -// if its values can be represented as int64_t values, useful for input arguments. - -#include "SPEX_Left_LU_mex.h" - -bool spex_left_lu_mex_check_for_inf // true if x can be represented as int64_t -( - double* x, // The array of numeric values - mwSize n // size of array -) -{ - - bool x_is_int64 = true ; - - for (mwSize k = 0; k < n; k++) - { - double xk = x [k] ; - - if (mxIsInf (xk)) - { - spex_left_lu_mex_error (1, "A must not have any Inf values") ; - } - - if (mxIsNaN (xk)) - { - spex_left_lu_mex_error (1, "A must not have any NaN values") ; - } - - if (x_is_int64) - { - if (xk < INT64_MIN || xk > INT64_MAX) - { - x_is_int64 = false ; - } - else - { - int64_t xi = (int64_t) xk ; - if ((double) xi != xk) - { - x_is_int64 = false ; - } - } - } - } - - return (x_is_int64) ; -} - diff --git a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_error.c b/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_error.c deleted file mode 100644 index fd3185fe19..0000000000 --- a/SPEX/SPEX_Left_LU/MATLAB/Source/spex_left_lu_mex_error.c +++ /dev/null @@ -1,52 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/MATLAB/spex_left_lu_mex_error: Return error messages to matlab -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function prints error messages for MATLAB for debugging*/ - -#include "SPEX_Left_LU_mex.h" - -void spex_left_lu_mex_error -( - SPEX_info status, - char *message -) -{ - - switch (status) - { - case SPEX_OK : // all is well - return ; - - case SPEX_OUT_OF_MEMORY : // out of memory - SPEX_finalize ( ) ; - mexErrMsgTxt ("out of memory") ; - - case SPEX_SINGULAR : // the input matrix A is singular - SPEX_finalize ( ) ; - mexErrMsgTxt ("input matrix is singular") ; - - case SPEX_INCORRECT_INPUT : // one or more input arguments are incorrect - SPEX_finalize ( ) ; - mexErrMsgTxt ("invalid inputs") ; - - case SPEX_INCORRECT : // The solution is incorrect - SPEX_finalize ( ) ; - mexErrMsgTxt ("result invalid") ; - - case SPEX_PANIC : // SPEX_Left_LU used without proper initialization - SPEX_finalize ( ) ; - mexErrMsgTxt ("panic") ; - - default : - SPEX_finalize ( ) ; - mexErrMsgTxt (message) ; - } -} - diff --git a/SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_solve.c b/SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_solve.c deleted file mode 100644 index b1daa9bbfe..0000000000 --- a/SPEX/SPEX_Left_LU/Source/SPEX_Left_LU_solve.c +++ /dev/null @@ -1,176 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/SPEX_Left_LU_solve: exact solution of Ax=b -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function solves the linear system LD^(-1)U x = b. It - * essnetially serves as a wrapper for all forward and backward substitution - * routines. This function always returns the solution matrix x as a rational - * matrix. If a user desires to have double or mpfr output, they must create - * a matrix copy. - * - * Input/output arguments: - * - * x_handle: A pointer to the solution vectors. Unitialized on input. - * on output, contains the exact rational solution of the system - * - * b: Set of RHS vectors - * - * A: Input matrix. Unmodified on input/output - * - * L: Lower triangular matrix. Unmodified on input/output - * - * U: Upper triangular matrix. Unmodified on input/output - * - * rhos: dense mpz_t matrix of pivots. Contains the sequence of pivots - * encountered during factorization and is used for forward/back - * substitution. Unmodified on input/output. - * - * S: symbolic analysis struct, used for vector permutation - * - * pinv: inverse row permutation vector, used to permute the b vectors. - * unmodified on input/output. - * - * option: command options - */ - -#define SPEX_FREE_WORK \ - SPEX_matrix_free (&b2, NULL) ; \ - SPEX_matrix_free (&x2, NULL) ; \ - SPEX_MPQ_CLEAR (scale) ; - -#define SPEX_FREE_ALL \ - SPEX_FREE_WORK \ - SPEX_matrix_free (&x, NULL) ; - -#include "spex_left_lu_internal.h" - -SPEX_info SPEX_Left_LU_solve // solves the linear system LD^(-1)U x = b -( - // Output - SPEX_matrix **x_handle, // rational solution to the system - // input: - const SPEX_matrix *b, // right hand side vector - const SPEX_matrix *A, // Input matrix - const SPEX_matrix *L, // lower triangular matrix - const SPEX_matrix *U, // upper triangular matrix - const SPEX_matrix *rhos,// sequence of pivots - const SPEX_LU_analysis *S,// symbolic analysis struct - const int64_t *pinv, // inverse row permutation - const SPEX_options* option // Command options -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - SPEX_info info ; - if (!spex_initialized ( )) return (SPEX_PANIC) ; - - SPEX_REQUIRE (b, SPEX_DENSE, SPEX_MPZ) ; - SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ) ; - SPEX_REQUIRE (L, SPEX_CSC, SPEX_MPZ) ; - SPEX_REQUIRE (U, SPEX_CSC, SPEX_MPZ) ; - SPEX_REQUIRE (rhos, SPEX_DENSE, SPEX_MPZ) ; - - if (!x_handle || !S || !pinv || L->m != A->m || L->n != U->m || - U->n != A->n || A->n != A->m || A->m != b->m ) - { - return SPEX_INCORRECT_INPUT; - } - *x_handle = NULL; - - //-------------------------------------------------------------------------- - // Declare and initialize workspace - //-------------------------------------------------------------------------- - - int64_t i, n = L->n; - mpq_t scale ; - SPEX_MPQ_SET_NULL (scale) ; - - SPEX_matrix *x = NULL; // final solution - SPEX_matrix *x2 = NULL; // unpermuted solution - SPEX_matrix *b2 = NULL; // permuted b - - //-------------------------------------------------------------------------- - // b2 (pinv) = b - //-------------------------------------------------------------------------- - - SPEX_CHECK (spex_left_lu_permute_b (&b2, b, pinv, option)) ; - - //-------------------------------------------------------------------------- - // b2 = L\b2, via forward substitution - //-------------------------------------------------------------------------- - - SPEX_CHECK(spex_left_lu_forward_sub(L, b2, (SPEX_matrix*) rhos)); - - //-------------------------------------------------------------------------- - // b2 = b2 * det, where det=rhos[n-1] - //-------------------------------------------------------------------------- - - SPEX_CHECK(SPEX_matrix_mul(b2, rhos->x.mpz[n-1])); - - //-------------------------------------------------------------------------- - // b2 = U\b2, via back substitution - //-------------------------------------------------------------------------- - SPEX_CHECK(spex_left_lu_back_sub(U, b2)); - - //-------------------------------------------------------------------------- - // x2 = b2/det, where det=rhos[n-1] - //-------------------------------------------------------------------------- - - SPEX_CHECK (SPEX_matrix_div (&x2, b2, rhos->x.mpz[n-1], option)) ; - - //-------------------------------------------------------------------------- - // x = Q*x2 - //-------------------------------------------------------------------------- - - SPEX_CHECK (spex_left_lu_permute_x (&x, x2, (SPEX_LU_analysis *) S, option)) ; - SPEX_matrix_free (&x2, NULL) ; - - //-------------------------------------------------------------------------- - // Check the solution if desired (debugging only) - //-------------------------------------------------------------------------- - - bool check = SPEX_OPTION_CHECK (option) ; - if (check) - { - SPEX_CHECK (SPEX_check_solution (A, x, b, option)) ; - } - - //-------------------------------------------------------------------------- - // Scale the solution if necessary. - //-------------------------------------------------------------------------- - - SPEX_CHECK(SPEX_mpq_init(scale)); - - // set the scaling factor scale = A->scale / b->scale - SPEX_CHECK( SPEX_mpq_div(scale, A->scale, b->scale)); - - // Determine if the scaling factor is 1 - int r; - SPEX_CHECK(SPEX_mpq_cmp_ui(&r, scale, 1, 1)); - int64_t nz = x->m * x->n; - if (r != 0 ) - { - for (i = 0; i < nz; i++) - { - SPEX_CHECK(SPEX_mpq_mul(x->x.mpq[i], x->x.mpq[i], scale)); - } - } - - //-------------------------------------------------------------------------- - // free workspace and return result - //-------------------------------------------------------------------------- - - SPEX_FREE_WORK ; - (*x_handle) = x ; - return (SPEX_OK) ; -} - diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_internal.h b/SPEX/SPEX_Left_LU/Source/spex_left_lu_internal.h deleted file mode 100644 index c7aa29e67b..0000000000 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_internal.h +++ /dev/null @@ -1,199 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/Source/spex_left_lu_internal: include file for internal use in -// SPEX_Left_LU -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -// This file is not intended to be #include'd in user applications. Use -// SPEX.h instead. - -#ifndef SPEX_LEFT_LU_INTERNAL_H -#define SPEX_LEFT_LU_INTERNAL_H - -#include "spex_util_internal.h" -#include "SPEX.h" - -// ============================================================================ -// Internal Functions -// ============================================================================ - - -/* Purpose: This function performs sparse REF forward substitution. This is - * essentially the same as the sparse REF triangular solve applied to each - * column of the right hand side vectors. Like the normal one, this function - * expects that the matrix x is dense. As a result,the nonzero pattern is not - * computed and each nonzero in x is iterated across. The system to solve is - * LDx = x. On output, the mpz_t** x structure is modified. - */ -SPEX_info spex_left_lu_forward_sub -( - const SPEX_matrix *L, // lower triangular matrix - SPEX_matrix *x, // right hand side matrix - const SPEX_matrix *rhos // sequence of pivots used in factorization -); - -/* Purpose: This function performs sparse REF backward substitution. In essense - * it solves the sysem Ux = x. Note that prior to this, we expect x to be - * multiplied by the determinant of A. The input argument bx is modified on - * output. - */ -SPEX_info spex_left_lu_back_sub // performs sparse REF backward substitution -( - const SPEX_matrix *U, // input upper triangular matrix - SPEX_matrix *bx // right hand side matrix of size n*numRHS -) ; - - -/* Purpose: This function performs a depth first search of the graph of the - * matrix starting at node j. The output of this function is the set of nonzero - * indices in the xi vector. - */ -void spex_left_lu_dfs // performs a dfs of the graph of the matrix starting at node j -( - int64_t *top, // beginning of stack - int64_t j, // What node to start DFS at - SPEX_matrix* L, // matrix which represents the Graph of L - int64_t* xi, // the nonzero pattern - int64_t* pstack, // workspace vector - const int64_t* pinv // row permutation -); - - -/* This function performs the pivoting for the SPEX Left LU factorization. - * The optional Order is: - * 0: Smallest pivot - * 1: Natural/Diagonal pivoting - * 2: Choose first nonzero (not recommended, for comparison only) - * 3: Diagonal with tolerance and smallest pivot (default) - * 4: Diagonal with tolerance and largest pivoting - * 5: Largest pivot (not recommended, for comparison only) - * - * On output, the pivs, pinv, and row_perm arrays and rhos matrix are all modified. - */ -SPEX_info spex_left_lu_get_pivot -( - int64_t *pivot, // found index of pivot entry - SPEX_matrix* x, // kth column of L and U - int64_t* pivs, // vector indicating which rows have been pivotal - int64_t n, // dimension of the problem - int64_t top, // nonzero pattern is located in xi[top..n-1] - int64_t* xi, // nonzero pattern of x - int64_t col, // current column of A (real kth column i.e., q[k]) - int64_t k, // iteration of the algorithm - SPEX_matrix* rhos, // vector of pivots - int64_t* pinv, // row permutation - int64_t* row_perm, // opposite of pinv. if pinv[i] = j then row_perm[j] = i - const SPEX_options *option // command option -); - -/* Purpose: This function selects the pivot element as the largest in the - * column. This is activated if the user sets option->pivot = SPEX_LARGEST. - * NOTE: This pivoting scheme is NOT recommended for SPEX Left LU. On output - * the index of the largest pivot is returned. - */ -SPEX_info spex_left_lu_get_largest_pivot -( - int64_t *pivot, // the index of largest pivot - SPEX_matrix* x, // kth column of L and U - int64_t* pivs, // vector which indicates whether each row has been pivotal - int64_t n, // dimension of problem - int64_t top, // nonzero pattern is located in xi[top..n-1] - int64_t* xi // nonzero pattern of x -); - -/* This function obtains the first eligible nonzero pivot. This is enabled if - * the user sets option->pivot = SPEX_FIRST_NONZERO. NOTE: This pivoting - * scheme is not recommended. On output, the kth pivot is returned. - */ -SPEX_info spex_left_lu_get_nonzero_pivot // find the first eligible nonzero pivot -( - int64_t *pivot, // the index of first eligible nonzero pivot - SPEX_matrix* x, // kth column of L and U - int64_t* pivs, // vector indicating which rows are pivotal - int64_t n, // size of x - int64_t top, // nonzero pattern is located in xi[top..n-1] - int64_t* xi // nonzero pattern of x -); - -/* Purpose: This function selects the pivot element as the smallest in the - * column. This is activated by default or if the user sets option->pivot = - * SPEX_SMALLEST. This is a recommended pivoting scheme for SPEX Left LU. - * On output, the index of kth pivot is returned. - */ -SPEX_info spex_left_lu_get_smallest_pivot -( - int64_t *pivot, // index of smallest pivot - SPEX_matrix *x, // kth column of L and U - int64_t* pivs, // vector indicating whether each row has been pivotal - int64_t n, // dimension of problem - int64_t top, // nonzeros are stored in xi[top..n-1] - int64_t* xi // nonzero pattern of x -); - - -/* Purpose: This function permutes b for forward substitution. - * That is, b = P'*b. - */ -SPEX_info spex_left_lu_permute_b -( - SPEX_matrix **b_handle, // permuted RHS vector - const SPEX_matrix *b2, // unpermuted RHS vector (not modified) - const int64_t *pinv, // inverse row permutation - const SPEX_options* option -); - -/* Purpose: SPEX_permute_x permutes x to get it back in its original form. - * That is x = Q*x. - */ -SPEX_info spex_left_lu_permute_x -( - SPEX_matrix **x_handle, // permuted Solution vector - SPEX_matrix *x2, // unpermuted Solution vector (not modified) - SPEX_LU_analysis *S, // symbolic analysis with the column ordering Q - const SPEX_options* option // Command options - // has been checked in the only caller SPEX_Left_LU_solve -) ; - -/* Purpose: This function computes the reach of column k of A on the graph of L - * mathematically that is: xi = Reach(A(:,k))_G_L. - */ -void spex_left_lu_reach // compute the reach of column k of A on the graph of L -( - int64_t *top, - SPEX_matrix* L, // matrix representing graph of L - const SPEX_matrix* A, // input matrix - int64_t k, // column of A of interest - int64_t* xi, // nonzero pattern - const int64_t* pinv // row permutation -) ; - -/* Purpose: This function performs the sparse REF triangular solve; that is, - * (LD) x = A(:,k). The algorithm is described in the paper; however in essence - * it computes the nonzero pattern xi, then performs a sequence of IPGE - * operations on the nonzeros to obtain their final value. All operations are - * gauranteed to be integral. There are various enhancements in this code used - * to reduce the overall cost of the operations and minimize operations as much - * as possible. - */ -SPEX_info spex_left_lu_ref_triangular_solve // performs the sparse REF triangular solve -( - int64_t *top_output, // Output the beginning of nonzero pattern - SPEX_matrix* L, // partial L matrix - const SPEX_matrix* A, // input matrix - int64_t k, // iteration of algorithm - int64_t* xi, // nonzero pattern vector - const int64_t* q, // column permutation - SPEX_matrix* rhos, // sequence of pivots - const int64_t* pinv, // inverse row permutation - const int64_t* row_perm, // row permutation - int64_t* h, // history vector - SPEX_matrix* x // solution of system ==> kth column of L and U -); - -#endif - diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_b.c b/SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_b.c deleted file mode 100644 index 403ffabb79..0000000000 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_b.c +++ /dev/null @@ -1,68 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_permute_b: permute b, as b = P'*b -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function permutes b for forward substitution. - * That is, b = P'*b. - */ - -#define SPEX_FREE_ALL \ - SPEX_matrix_free (&b, NULL) ; - -#include "spex_left_lu_internal.h" - -SPEX_info spex_left_lu_permute_b -( - SPEX_matrix **b_handle, // permuted RHS vector - const SPEX_matrix *b2, // unpermuted RHS vector (not modified) - const int64_t *pinv, // inverse row permutation - const SPEX_options* option -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - SPEX_info info ; - SPEX_REQUIRE (b2, SPEX_DENSE, SPEX_MPZ) ; - - if (b_handle == NULL || !pinv) {return SPEX_INCORRECT_INPUT;} - (*b_handle) = NULL ; - - //-------------------------------------------------------------------------- - // b(pinv) = b2 - //-------------------------------------------------------------------------- - - int64_t m = b2->m ; - int64_t n = b2->n ; - - // allocate x - SPEX_matrix *b = NULL ; - SPEX_CHECK (SPEX_matrix_allocate (&b, SPEX_DENSE, SPEX_MPZ, m, n, - 0, false, true, option)) ; - - // Set b = P'*b2 - for (int64_t i = 0 ; i < m ; i++) - { - for (int64_t j = 0 ; j < n ; j++) - { - SPEX_CHECK(SPEX_mpz_set(SPEX_2D(b, pinv[i], j, mpz), - SPEX_2D(b2, i, j, mpz))); - } - } - - //-------------------------------------------------------------------------- - // return result - //-------------------------------------------------------------------------- - - (*b_handle) = b ; - return SPEX_OK; -} - diff --git a/SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_x.c b/SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_x.c deleted file mode 100644 index 55b0214e47..0000000000 --- a/SPEX/SPEX_Left_LU/Source/spex_left_lu_permute_x.c +++ /dev/null @@ -1,69 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Left_LU/spex_left_lu_permute_x: permute x, as x = Q*x -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function permutes x to get it back in its original form. - * That is, x = Q*x. - */ - -#define SPEX_FREE_ALL \ - SPEX_matrix_free (&x, NULL) ; - -#include "spex_left_lu_internal.h" - -SPEX_info spex_left_lu_permute_x -( - SPEX_matrix **x_handle, // permuted Solution vector - SPEX_matrix *x2, // unpermuted Solution vector (not modified) - SPEX_LU_analysis *S, // symbolic analysis with the column ordering Q - const SPEX_options* option -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - SPEX_info info ; - SPEX_REQUIRE (x2, SPEX_DENSE, SPEX_MPQ) ; - - if (x_handle == NULL || !S || !S->q) {return SPEX_INCORRECT_INPUT;} - (*x_handle) = NULL ; - - //-------------------------------------------------------------------------- - // x (q) = x2 - //-------------------------------------------------------------------------- - - int64_t *q = S->q ; // column permutation - int64_t m = x2->m ; - int64_t n = x2->n ; - - // allocate x - SPEX_matrix *x = NULL ; - SPEX_CHECK (SPEX_matrix_allocate (&x, SPEX_DENSE, SPEX_MPQ, m, n, - 0, false, true, option)) ; - - // Set x = Q*x2 - for (int64_t i = 0 ; i < m ; i++) - { - for (int64_t j = 0 ; j < n ; j++) - { - SPEX_CHECK(SPEX_mpq_set(SPEX_2D(x, q[i], j, mpq), - SPEX_2D(x2, i, j, mpq))); - } - } - - //-------------------------------------------------------------------------- - // return result - //-------------------------------------------------------------------------- - - (*x_handle) = x ; - return SPEX_OK; -} - diff --git a/SPEX/SPEX_Left_LU/Tcov/.gitignore b/SPEX/SPEX_Left_LU/Tcov/.gitignore deleted file mode 100644 index 1397e8084b..0000000000 --- a/SPEX/SPEX_Left_LU/Tcov/.gitignore +++ /dev/null @@ -1,56 +0,0 @@ -# Ignore these files: -cov.out -cov.sort -cover.out -covs.out -spexlu_demo -spexlu_demo.c -tcov_test -demos.c -SPEX_calloc.c -SPEX_matrix_div.c -spex_cast_array.c -spex_cast_matrix.c -SPEX_check_solution.c -SPEX_create_default_options.c -spex_create_mpfr_array.c -spex_create_mpq_array.c -spex_create_mpz_array.c -SPEX_cumsum.c -spex_expand_double_array.c -spex_expand_mpfr_array.c -spex_expand_mpq_array.c -SPEX_finalize.c -SPEX_free.c -SPEX_gmp.c -SPEX_initialize.c -SPEX_initialize_expert.c -SPEX_LU_analysis_free.c -SPEX_LU_analyze.c -SPEX_malloc.c -SPEX_matrix_allocate.c -SPEX_matrix_check.c -SPEX_matrix_copy.c -SPEX_matrix_free.c -SPEX_matrix_mul.c -SPEX_matrix_nnz.c -SPEX_realloc.c -spex_sparse_collapse.c -spex_sparse_realloc.c -SPEX_Left_LU_analyze.c -SPEX_Left_LU_backslash.c -spex_left_lu_back_sub.c -spex_left_lu_dfs.c -SPEX_Left_LU_factorize.c -spex_left_lu_forward_sub.c -spex_left_lu_get_largest_pivot.c -spex_left_lu_get_nonzero_pivot.c -spex_left_lu_get_pivot.c -spex_left_lu_get_smallest_pivot.c -spex_left_lu_permute_b.c -spex_left_lu_permute_x.c -spex_left_lu_reach.c -spex_left_lu_ref_triangular_solve.c -SPEX_Left_LU_solve.c -SPEX_determine_symmetry.c -SPEX_transpose.c diff --git a/SPEX/SPEX_Left_LU/Tcov/Makefile b/SPEX/SPEX_Left_LU/Tcov/Makefile deleted file mode 100644 index f4b767b016..0000000000 --- a/SPEX/SPEX_Left_LU/Tcov/Makefile +++ /dev/null @@ -1,160 +0,0 @@ -#------------------------------------------------------------------------------- -# SPEX/SPEX/SPEX_Left_LU/Tcov/Makefile: compile and run SPEX test coverage -#------------------------------------------------------------------------------- - -# SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -# Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -# SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -#------------------------------------------------------------------------------- - -default: run - -SUITESPARSE ?= $(realpath $(CURDIR)/../../..) - -################################################################################ - - INSTALL_LIB ?= $(SUITESPARSE)/lib - - # use 8 jobs by default - JOBS ?= 8 - - LDFLAGS = --coverage - LDFLAGS += -L$(INSTALL_LIB) - LDFLAGS += -Wl,-rpath=$(INSTALL_LIB) - - # remove object files, but keep compiled libraries via 'make clean' - CLEAN = *.o *.obj *.ln *.bb *.bbg *.da *.tcov *.gcov gmon.out *.bak *.d \ - *.gcda *.gcno *.aux *.bbl *.blg *.log *.toc *.dvi *.lof *.lot - - # also remove compiled libraries, via 'make distclean' - PURGE = *.so* *.a *.dll *.dylib *.dSYM - -################################################################################ - -# Linux test coverage (gcc is required for test coverage) -CC = gcc -CFLAGS = -g -fprofile-arcs -ftest-coverage \ - -Wall -W -Wshadow -Wmissing-prototypes -Wstrict-prototypes \ - -Wredundant-decls -Wnested-externs -Wdisabled-optimization -std=c99 \ - -Wno-unused-parameter -I../../Include -I../Source -I../Demo \ - -I../../SPEX_Util/Include/ -I../../SPEX_Util/Source/ \ - -I../../../SuiteSparse_config -I../../../COLAMD/Include \ - -I../../../AMD/Include \ - -DSPEX_GMP_LIST_INIT=2 - -LDLIBS += -lmpfr -lgmp -lcolamd -lamd -lsuitesparseconfig -lm - -# run all statement coverage tests, and then check for 100% coverage -run: runtests - ./covall - -all: test SPEXLLU - -CS = \ - SPEX_calloc.o \ - SPEX_matrix_div.o \ - spex_cast_array.o \ - spex_cast_matrix.o \ - SPEX_check_solution.o \ - SPEX_create_default_options.o \ - spex_create_mpfr_array.o \ - spex_create_mpq_array.o \ - spex_create_mpz_array.o \ - SPEX_cumsum.o \ - spex_expand_double_array.o \ - spex_expand_mpfr_array.o \ - spex_expand_mpq_array.o \ - SPEX_finalize.o \ - SPEX_free.o \ - SPEX_gmp.o \ - SPEX_initialize.o \ - SPEX_initialize_expert.o \ - SPEX_malloc.o \ - SPEX_matrix_allocate.o \ - SPEX_matrix_check.o \ - SPEX_matrix_copy.o \ - SPEX_matrix_free.o \ - SPEX_matrix_mul.o \ - SPEX_matrix_nnz.o \ - SPEX_realloc.o \ - spex_sparse_collapse.o \ - spex_sparse_realloc.o \ - SPEX_LU_analysis_free.o \ - SPEX_LU_analyze.o \ - tcov_malloc_test.o \ - SPEX_Left_LU_backslash.o \ - spex_left_lu_back_sub.o \ - spex_left_lu_dfs.o \ - SPEX_Left_LU_factorize.o \ - spex_left_lu_forward_sub.o \ - spex_left_lu_get_largest_pivot.o \ - spex_left_lu_get_nonzero_pivot.o \ - spex_left_lu_get_pivot.o \ - spex_left_lu_get_smallest_pivot.o \ - spex_left_lu_permute_b.o \ - spex_left_lu_permute_x.o \ - spex_left_lu_reach.o \ - spex_left_lu_ref_triangular_solve.o \ - SPEX_Left_LU_solve.o - #SPEX_determine_symmetry.o SPEX_transpose.o \ - -$(CS): ../../Include/SPEX.h ../Source/spex_left_lu_internal.h ../../SPEX_Util/Source/spex_util_internal.h tcov_malloc_test.h ../Demo/demos.h - -.PRECIOUS: SPEX_Left_LU_%.c spex_left_lu_%.c spexlu_demo.c demos.c SPEX_%.c spex_%.c - -SPEX_Left_LU_%.c: - - ln -s ../Source/$@ - -spex_left_lu_%.c: - - ln -s ../Source/$@ - -spexlu_demo.c: - - ln -s ../Demo/$@ - -demos.c: - - ln -s ../Demo/$@ - -SPEX_%.c: - - ln -s ../../SPEX_Util/Source/$@ - -spex_%.c: - - ln -s ../../SPEX_Util/Source/$@ - -test: $(CS) tcov_test.c demos.c - $(CC) $(LDFLAGS) tcov_test.c demos.c $(CFLAGS) -o tcov_test $(CS) $(LDLIBS) - -SPEXLLU: $(CS) spexlu_demo.c demos.c - $(CC) $(LDFLAGS) spexlu_demo.c demos.c $(CFLAGS) -o spexlu_demo $(CS) $(LDLIBS) - -# run all statement coverage tests -runtests: all - - ./spexlu_demo p 2 q 0 - - ./spexlu_demo p 3 q 1 o 1 - - ./spexlu_demo p 4 q 2 o 1 f ../ExampleMats/test_mat.txt ../ExampleMats/test_rhs.txt - - ./spexlu_demo p 5 - - ./tcov_test - - ./tcov_test 0 1 1 - -# To run with valgrind: -V = valgrind #--leak-check=full - -# run all statement coverage tests but with valgrind -vtests: all - - $(V) ./spexlu_demo p 2 q 0 - - $(V) ./spexlu_demo p 3 q 1 o 1 - - $(V) ./spexlu_demo p 4 q 2 o 1 f ../ExampleMats/test_mat.txt ../ExampleMats/test_rhs.txt - - $(V) ./spexlu_demo p 5 - - $(V) ./tcov_test - - $(V) ./tcov_test 0 1 1 - -# remove all files not in the original distribution, including symbolic links -clean: - - $(RM) *.o *.bbg *.da *.gcov *.gcda *gcno - - $(RM) tcov_test spexlu_demo *.out *.a cov.sort out - - $(RM) -r SPEX_*.c spex_*.c *.dSYM spexlu_demo.c demos.c - -purge: distclean - -distclean: clean - diff --git a/SPEX/SPEX_Left_LU/Tcov/covall b/SPEX/SPEX_Left_LU/Tcov/covall deleted file mode 100755 index 413f422473..0000000000 --- a/SPEX/SPEX_Left_LU/Tcov/covall +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - ./gcovs SPEX_*.c spex_*.c 2>&1 | awk -f cov.awk | sort -n > cov.out - sort -n cov.out > cov.sort - ./covs > covs.out - echo -n "statments not yet tested: " - grep "#####" *.*.gcov | wc -l - ./cover *.*.gcov > cover.out diff --git a/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.c b/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.c deleted file mode 100644 index 9892b31551..0000000000 --- a/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.c +++ /dev/null @@ -1,94 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.c -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -#include "tcov_malloc_test.h" - -int64_t malloc_count = INT64_MAX ; - -// Note that only the ANSI C memory manager is used here -// (malloc, calloc, realloc, free) - -// wrapper for malloc -void *tcov_malloc -( - size_t size // Size to alloc -) -{ - if (--malloc_count < 0) - { - /* pretend to fail */ - printf("malloc pretend to fail\n"); - return (NULL) ; - } - return (malloc (size)) ; -} - -// wrapper for calloc -void *tcov_calloc -( - size_t n, // Size of array - size_t size // Size to alloc -) -{ - if (--malloc_count < 0) - { - /* pretend to fail */ - printf ("calloc pretend to fail\n"); - return (NULL) ; - } - // ensure at least one byte is calloc'd - return (calloc (n, size)) ; -} - -// wrapper for realloc -void *tcov_realloc -( - void *p, // Pointer to be realloced - size_t new_size // Size to alloc -) -{ - if (--malloc_count < 0) - { - /* pretend to fail */ - printf("realloc pretend to fail\n"); - return (NULL); - } - return (realloc (p, new_size)) ; -} - -// wrapper for free -void tcov_free -( - void *p // Pointer to be free -) -{ - // This not really needed, but placed here anyway in case the Tcov tests - // want to do something different that free(p) in the future. - free (p) ; -} - -extern jmp_buf spex_gmp_environment ; // for setjmp and longjmp - -int spex_gmp_realloc_test -( - void **p_new, - void * p_old, - size_t old_size, - size_t new_size -) -{ - int spex_gmp_status = setjmp (spex_gmp_environment); - if (spex_gmp_status != 0) - { - return SPEX_OUT_OF_MEMORY; - } - *p_new = spex_gmp_reallocate(p_old, old_size, new_size); - return SPEX_OK; -} diff --git a/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.h b/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.h deleted file mode 100644 index 791793d4e0..0000000000 --- a/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.h +++ /dev/null @@ -1,88 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX/SPEX/SPEX_Left_LU/Tcov/tcov_malloc_test.h -//------------------------------------------------------------------------------ - -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -#ifndef TCOV_SPEX_MALLOC_TEST_H -#define TCOV_SPEX_MALLOC_TEST_H - -#include "spex_left_lu_internal.h" -#include "spex_util_internal.h" -#include "SPEX_gmp.h" - -extern int64_t malloc_count ; - -#define GOTCHA \ - printf ("%s, line %d, spex_gmp_ntrials = %ld, malloc_count = %ld\n", \ - __FILE__, __LINE__, spex_gmp_ntrials, malloc_count); - -#define SPEX_PRINT_INFO(info) \ -{ \ - /*printf ("file %s line %d: ", __FILE__, __LINE__) ; */ \ - switch(info) \ - { \ - case SPEX_OK: printf("SPEX_OK\n"); break; \ - case SPEX_OUT_OF_MEMORY: printf("OUT OF MEMORY\n"); break; \ - case SPEX_SINGULAR: printf("Matrix is SINGULAR\n"); break; \ - case SPEX_INCORRECT_INPUT: printf("INCORRECT INPUT\n"); break; \ - case SPEX_INCORRECT: printf("SPEX_INCORRECT\n"); break; \ - default: printf("unknown!\n"); \ - } \ -} - -#ifdef SPEX_CHECK -#undef SPEX_CHECK -#endif - -#define SPEX_CHECK(method) \ -{ \ - info = (method) ; \ - if (info != SPEX_OK) \ - { \ - SPEX_PRINT_INFO (info) \ - SPEX_FREE_ALL ; \ - return (info) ; \ - } \ -} - -// wrapper for malloc -void *tcov_malloc -( - size_t size // Size to alloc -) ; - -// wrapper for calloc -void *tcov_calloc -( - size_t n, // Size of array - size_t size // Size to alloc -) ; - -// wrapper for realloc -void *tcov_realloc -( - void *p, // Pointer to be realloced - size_t new_size // Size to alloc -) ; - -// wrapper for free -void tcov_free -( - void *p // Pointer to be free -) ; - -// used to test spex_gmp_reallocate -int spex_gmp_realloc_test -( - void **p_new, - void * p_old, - size_t old_size, - size_t new_size -); -#endif - diff --git a/SPEX/SPEX_Util/Source/SPEX_LU_analysis_free.c b/SPEX/SPEX_Util/Source/SPEX_LU_analysis_free.c deleted file mode 100644 index 099a36689a..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_LU_analysis_free.c +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/SPEX_LU_analysis_free: Free memory from symbolic analysis struct -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function frees the memory of the SPEX_LU_analysis struct - * - * Input is the SPEX_LU_analysis structure, it is destroyed on function - * termination. - */ - -#include "spex_util_internal.h" - -SPEX_info SPEX_LU_analysis_free -( - SPEX_LU_analysis **S, // Structure to be deleted - const SPEX_options *option -) -{ - if (!spex_initialized ( )) return (SPEX_PANIC) ; - - if ((S != NULL) && (*S != NULL)) - { - SPEX_FREE ((*S)->q) ; - SPEX_FREE (*S) ; - } - - return (SPEX_OK) ; -} - diff --git a/SPEX/SPEX_Util/Source/SPEX_LU_analyze.c b/SPEX/SPEX_Util/Source/SPEX_LU_analyze.c deleted file mode 100644 index ab16d9b689..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_LU_analyze.c +++ /dev/null @@ -1,187 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/SPEX_LU_analyze: symbolic ordering and analysis for sparse LU -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function performs the symbolic ordering for unsymmetric matrices. - * Currently, there are three options: user-defined order, COLAMD, or AMD. - * - * Input/output arguments: - * - * S: Symbolic analysis struct. Undefined on input; contains column - * permutation and estimates of nnz(L) and nnz(U) nnz on output - * - * A: Input matrix, unmodified on input/output - * - * option: option->order tells the function which ordering scheme to use - * - */ - -// SPEX_LU_analyze creates the SPEX_LU_analysis object S. Use -// SPEX_LU_analysis_free to delete it. - -#include "spex_util_internal.h" - -SPEX_info SPEX_LU_analyze -( - SPEX_LU_analysis** S_handle, // symbolic analysis (column perm. and nnz L,U) - const SPEX_matrix *A, // Input matrix - const SPEX_options *option // Control parameters, if NULL, use default -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - if (!spex_initialized ( )) return (SPEX_PANIC) ; - - // A can have any data type, but must be in sparse CSC format - SPEX_REQUIRE_KIND (A, SPEX_CSC) ; - - if (!S_handle || A->n != A->m) - { - return SPEX_INCORRECT_INPUT; - } - (*S_handle) = NULL ; - - //-------------------------------------------------------------------------- - // allocate symbolic analysis object - //-------------------------------------------------------------------------- - - SPEX_LU_analysis *S = NULL ; - int64_t i, n = A->n, anz; - // SPEX enviroment is checked to be init'ed and A is checked to be not NULL - // and a SPEX_CSC kind, so there shouldnt be any error from this function - SPEX_matrix_nnz(&anz, A, option); - // ALlocate memory for S - S = (SPEX_LU_analysis*) SPEX_malloc(sizeof(SPEX_LU_analysis)); - if (S == NULL) {return SPEX_OUT_OF_MEMORY;} - - // Allocate memory for column permutation - S->q = (int64_t*) SPEX_malloc((n+1) * sizeof(int64_t)); - if (S->q == NULL) - { - SPEX_FREE(S); - return SPEX_OUT_OF_MEMORY; - } - - //-------------------------------------------------------------------------- - // No ordering is used. S->q is set to [0 ... n] and the number of nonzeros - // in L and U is estimated to be 10 times the number of nonzeros in A. This - // is a very crude estimate on the nnz(L) and nnz(U) - //-------------------------------------------------------------------------- - - SPEX_col_order order = SPEX_OPTION_ORDER (option) ; - int pr = SPEX_OPTION_PRINT_LEVEL (option) ; - - if (order == SPEX_NO_ORDERING) - { - for (i = 0; i < n+1; i++) - { - S->q[i] = i; - } - // estimates for number of L and U nonzeros - S->lnz = S->unz = 10*anz; - } - - //-------------------------------------------------------------------------- - // The AMD ordering is used. S->q is set to AMD's column ordering on - // A+A'. The number of nonzeros in L and U is given as AMD's computed - // number of nonzeros in the Cholesky factor L of A+A' - //-------------------------------------------------------------------------- - else if (order == SPEX_AMD) - { - double Control [AMD_CONTROL]; // Declare AMD control - amd_l_defaults (Control) ; // Set AMD defaults - double Info [AMD_INFO]; - // Perform AMD - amd_l_order(n, (int64_t *) A->p, (int64_t *) A->i, - (int64_t *) S->q, Control, Info) ; - S->lnz = S->unz = Info[AMD_LNZ]; // estimate for unz and lnz - if (pr > 0) // Output AMD info if desired - { - SPEX_PRINTF ("\n****Column Ordering Information****\n") ; - amd_l_control (Control) ; - amd_l_info (Info) ; - } - } - - //-------------------------------------------------------------------------- - // The COLAMD ordering is used. S->q is set as COLAMD's column ordering. - // The number of nonzeros in L and U is set as 10 times the number of - // nonzeros in A. This is a crude estimate. - //-------------------------------------------------------------------------- - else - { - // Declared as per COLAMD documentation - int64_t Alen = 2*anz + 6 *(n+1) + 6*(n+1) + n; - int64_t* A2 = (int64_t*) SPEX_malloc(Alen* sizeof(int64_t)); - if (!A2) - { - // out of memory - SPEX_LU_analysis_free (&S, option) ; - return (SPEX_OUT_OF_MEMORY) ; - } - // Initialize S->q as per COLAMD documentation - for (i = 0; i < n+1; i++) - { - S->q[i] = A->p[i]; - } - // Initialize A2 per COLAMD documentation - for (i = 0; i < anz; i++) - { - A2[i] = A->i[i]; - } - int64_t stats [COLAMD_STATS]; - colamd_l (n, n, Alen, (int64_t *) A2, - (int64_t *) S->q, (double *) NULL, - (int64_t *) stats) ; - // estimate for lnz and unz - S->lnz = S->unz = 10*anz; - - // Print stats if desired - if (pr > 0) - { - SPEX_PRINTF ("\n****Column Ordering Information****\n") ; - colamd_l_report ((int64_t *) stats) ; - SPEX_PRINTF ("\nEstimated L and U nonzeros: %" PRId64 "\n", S->lnz); - } - SPEX_FREE(A2); - } - - //-------------------------------------------------------------------------- - // Make sure appropriate space is allocated. It's possible to return - // estimates which exceed the dimension of L and U or estimates which are - // too small for L U. In this case, this block of code ensures that the - // estimates on nnz(L) and nnz(U) are at least n and no more than n*n. - //-------------------------------------------------------------------------- - // estimate exceeds max number of nnz in A - if (S->lnz > (double) n*n) - { - int64_t nnz = ceil(0.5*n*n); - S->lnz = S->unz = nnz; - } - // If estimate < n, first column of triangular solve may fail - if (S->lnz < n) - { - S->lnz = S->lnz + n; - } - if (S->unz < n) - { - S->unz = S->unz + n; - } - - //-------------------------------------------------------------------------- - // return result - //-------------------------------------------------------------------------- - - (*S_handle) = S ; - return SPEX_OK; -} - diff --git a/SPEX/SPEX_Util/Source/SPEX_finalize.c b/SPEX/SPEX_Util/Source/SPEX_finalize.c deleted file mode 100644 index 1627357ee1..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_finalize.c +++ /dev/null @@ -1,28 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/SPEX_finalize: finalize SPEX -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -// SPEX_finalize frees the working environment for SPEX library. - -#include "spex_util_internal.h" - -SPEX_info SPEX_finalize -( - void -) -{ - if (!spex_initialized ( )) { return (SPEX_PANIC) ; } - - SPEX_mpfr_free_cache ( ) ; // Free mpfr internal cache - spex_gmp_finalize ( ) ; // Reset GMP memory variables - - spex_set_initialized (false) ; - return (SPEX_OK) ; -} - diff --git a/SPEX/SPEX_Util/Source/SPEX_gmp.h b/SPEX/SPEX_Util/Source/SPEX_gmp.h deleted file mode 100644 index f03f3686e2..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_gmp.h +++ /dev/null @@ -1,99 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/SPEX_gmp.h: definitions for SPEX_gmp.c -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -// These macros are used by SPEX_gmp.c to create wrapper functions around all -// GMP functions used by SPEX, to safely handle out-of-memory conditions. -// They are placed in this separate #include file so that a future developer -// can use them to construct their own wrappers around GMP functions. See -// SPEX_gmp.c for more details. - -#ifndef SPEX_GMP_H -#define SPEX_GMP_H - -#define SPEX_GMP_WRAPPER_START \ -{ \ - spex_gmp_nmalloc = 0 ; \ - /* setjmp returns 0 if called from here, or > 0 if from longjmp */ \ - int spex_gmp_status = setjmp (spex_gmp_environment) ; \ - if (spex_gmp_status != 0) \ - { \ - /* failure from longjmp */ \ - spex_gmp_failure (spex_gmp_status) ; \ - return (SPEX_OUT_OF_MEMORY) ; \ - } \ -} - -#define SPEX_GMPZ_WRAPPER_START(x) \ -{ \ - spex_gmpz_archive = x; \ - spex_gmpq_archive = NULL; \ - spex_gmpfr_archive = NULL; \ - SPEX_GMP_WRAPPER_START; \ -} - -#define SPEX_GMPQ_WRAPPER_START(x) \ -{ \ - spex_gmpz_archive = NULL; \ - spex_gmpq_archive = x; \ - spex_gmpfr_archive = NULL; \ - SPEX_GMP_WRAPPER_START; \ -} - -#define SPEX_GMPFR_WRAPPER_START(x) \ -{ \ - spex_gmpz_archive = NULL; \ - spex_gmpq_archive = NULL; \ - spex_gmpfr_archive = x; \ - SPEX_GMP_WRAPPER_START; \ -} - -#define SPEX_GMP_WRAPPER_FINISH \ -{ \ - /* clear (but do not free) the list. The caller must ensure */ \ - /* the result is eventually freed. */ \ - spex_gmpz_archive = NULL ; \ - spex_gmpq_archive = NULL ; \ - spex_gmpfr_archive = NULL ; \ - spex_gmp_nmalloc = 0 ; \ -} - -// free a block of memory, and also remove it from the archive if it's there -#define SPEX_GMP_SAFE_FREE(p) \ -{ \ - if (spex_gmpz_archive != NULL) \ - { \ - if (p == SPEX_MPZ_PTR(spex_gmpz_archive)) \ - { \ - SPEX_MPZ_PTR(spex_gmpz_archive) = NULL ; \ - } \ - } \ - else if (spex_gmpq_archive != NULL) \ - { \ - if (p == SPEX_MPZ_PTR(SPEX_MPQ_NUM(spex_gmpq_archive))) \ - { \ - SPEX_MPZ_PTR(SPEX_MPQ_NUM(spex_gmpq_archive)) = NULL ; \ - } \ - if (p == SPEX_MPZ_PTR(SPEX_MPQ_DEN(spex_gmpq_archive))) \ - { \ - SPEX_MPZ_PTR(SPEX_MPQ_DEN(spex_gmpq_archive)) = NULL ; \ - } \ - } \ - else if (spex_gmpfr_archive != NULL) \ - { \ - if (p == SPEX_MPFR_REAL_PTR(spex_gmpfr_archive)) \ - { \ - SPEX_MPFR_MANT(spex_gmpfr_archive) = NULL ; \ - } \ - } \ - SPEX_FREE (p) ; \ -} - -#endif - diff --git a/SPEX/SPEX_Util/Source/SPEX_initialize.c b/SPEX/SPEX_Util/Source/SPEX_initialize.c deleted file mode 100644 index 4bc26d3f7d..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_initialize.c +++ /dev/null @@ -1,48 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/SPEX_initialize: initialize SPEX -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -// SPEX_initialize initializes the working evironment for SPEX - -#include "spex_util_internal.h" - -//------------------------------------------------------------------------------ -// global variable access -//------------------------------------------------------------------------------ - -// a global variable, but only accessible within this file. -extern bool spex_initialize_has_been_called ; - -bool spex_initialize_has_been_called = false ; - -bool spex_initialized ( void ) -{ - return (spex_initialize_has_been_called) ; -} - -void spex_set_initialized (bool s) -{ - spex_initialize_has_been_called = s ; -} - -//------------------------------------------------------------------------------ -// SPEX_initialize -//------------------------------------------------------------------------------ - -SPEX_info SPEX_initialize ( void ) -{ - if (spex_initialized ( )) return (SPEX_PANIC) ; - - mp_set_memory_functions (spex_gmp_allocate, spex_gmp_reallocate, - spex_gmp_free) ; - - spex_set_initialized (true) ; - return (SPEX_OK) ; -} - diff --git a/SPEX/SPEX_Util/Source/SPEX_matrix_div.c b/SPEX/SPEX_Util/Source/SPEX_matrix_div.c deleted file mode 100644 index 8917281038..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_matrix_div.c +++ /dev/null @@ -1,86 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/SPEX_matrix_div: divide a matrix by a scalar -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function takes as input a dense SPEX_matrix x, which is MPZ, - * and divides it a scalar. This division is then stored in a dense MPQ - * matrix, which must have the same number of entries as x. This is used - * internally to divide the solution vector by the determinant of the matrix. - * - * On output, the contents of the matrix x2 are modified. - */ - -#define SPEX_FREE_WORK \ - SPEX_MPQ_CLEAR(scalar2); - -#define SPEX_FREE_ALL \ - SPEX_FREE_WORK \ - SPEX_matrix_free (&x2, NULL) ; - -#include "spex_util_internal.h" - - -SPEX_info SPEX_matrix_div // divides the x matrix by a scalar -( - SPEX_matrix **x2_handle, // x2 = x/scalar - SPEX_matrix* x, // input vector x - const mpz_t scalar, // the scalar - const SPEX_options *option -) -{ - if (!spex_initialized ( )) return (SPEX_PANIC) ; - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - SPEX_info info ; - SPEX_matrix *x2 = NULL ; - (*x2_handle) = NULL ; - SPEX_REQUIRE (x, SPEX_DENSE, SPEX_MPZ) ; - - //-------------------------------------------------------------------------- - // Set scalar2 = scalar - //-------------------------------------------------------------------------- - - mpq_t scalar2 ; - SPEX_MPQ_SET_NULL (scalar2) ; - SPEX_CHECK (SPEX_mpq_init (scalar2)) ; - SPEX_CHECK (SPEX_mpq_set_num (scalar2, scalar)) ; - - //-------------------------------------------------------------------------- - // allocate x2 - //-------------------------------------------------------------------------- - - SPEX_CHECK (SPEX_matrix_allocate(&x2, SPEX_DENSE, SPEX_MPQ, x->m, x->n, - 0, false, true, option)) ; - - //-------------------------------------------------------------------------- - // iterate each entry of x, copy to x2 and divide it by scalar - //-------------------------------------------------------------------------- - - int64_t nz; - SPEX_CHECK (SPEX_matrix_nnz (&nz, x, option)) ; - for (int64_t i = 0; i < nz; i++) - { - // Set x2[i] = x[i] - SPEX_CHECK (SPEX_mpq_set_num (x2->x.mpq[i], x->x.mpz[i])) ; - // x2[i] = x2[i] / scalar2 - SPEX_CHECK (SPEX_mpq_div (x2->x.mpq[i], x2->x.mpq[i], scalar2)) ; - } - - //-------------------------------------------------------------------------- - // free workspace and return result - //-------------------------------------------------------------------------- - - SPEX_FREE_WORK ; - (*x2_handle) = x2 ; - return (SPEX_OK) ; -} - diff --git a/SPEX/SPEX_Util/Source/SPEX_matrix_free.c b/SPEX/SPEX_Util/Source/SPEX_matrix_free.c deleted file mode 100644 index fcf5561d44..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_matrix_free.c +++ /dev/null @@ -1,114 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/SPEX_matrix_free: free a SPEX_matrix -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -// Free a SPEX_matrix. Any shallow component is not freed. -#if defined (__GNUC__) -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - -#include "spex_util_internal.h" - -SPEX_info SPEX_matrix_free -( - SPEX_matrix **A_handle, // matrix to free - const SPEX_options *option -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - - if (!spex_initialized ( )) { return (SPEX_PANIC) ; } ; - - if (A_handle == NULL || (*A_handle) == NULL) - { - // nothing to free (not an error) - return (SPEX_OK) ; - } - SPEX_matrix *A = (*A_handle) ; - - //-------------------------------------------------------------------------- - // free any non-shallow components - //-------------------------------------------------------------------------- - - // free the integer pattern - if (!(A->p_shallow)) SPEX_FREE (A->p) ; - if (!(A->i_shallow)) SPEX_FREE (A->i) ; - if (!(A->j_shallow)) SPEX_FREE (A->j) ; - - // free the values - if (!(A->x_shallow)) - { - switch (A->type) - { - case SPEX_MPZ: - if ( A->x.mpz) - for (int64_t i = 0; i < A->nzmax; i++) - { - if ( A->x.mpz[i] != NULL) - { - SPEX_MPZ_CLEAR( A->x.mpz[i]); - } - } - SPEX_FREE (A->x.mpz); - break ; - - case SPEX_MPQ: - if ( A->x.mpq) - for (int64_t i = 0; i < A->nzmax; i++) - { - if ( A->x.mpq[i] != NULL) - { - SPEX_MPQ_CLEAR( A->x.mpq[i]); - } - } - SPEX_FREE (A->x.mpq); - break ; - - case SPEX_MPFR: - if ( A->x.mpfr) - for (int64_t i = 0; i < A->nzmax; i++) - { - if ( A->x.mpfr[i] != NULL) - { - SPEX_MPFR_CLEAR( A->x.mpfr[i]); - } - } - SPEX_FREE (A->x.mpfr); - break ; - - case SPEX_INT64: - SPEX_FREE (A->x.int64) ; - break ; - - case SPEX_FP64: - SPEX_FREE (A->x.fp64) ; - break ; - - default: - // do nothing - break ; - } - } - - // A->scale is never shallow - SPEX_MPQ_CLEAR (A->scale) ; - - //-------------------------------------------------------------------------- - // free the header - //-------------------------------------------------------------------------- - - // the header is never shallow - SPEX_FREE (A) ; - (*A_handle) = NULL ; - return (SPEX_OK) ; -} - diff --git a/SPEX/SPEX_Util/Source/SPEX_version.c b/SPEX/SPEX_Util/Source/SPEX_version.c deleted file mode 100644 index 2687e3a98a..0000000000 --- a/SPEX/SPEX_Util/Source/SPEX_version.c +++ /dev/null @@ -1,19 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX/Source/amd_version: return SPEX version -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2023, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -#include "spex_util_internal.h" - -void SPEX_version (int version [3]) -{ - version [0] = SPEX_VERSION_MAJOR ; - version [1] = SPEX_VERSION_MINOR ; - version [2] = SPEX_VERSION_SUB ; -} - diff --git a/SPEX/SPEX_Util/Source/spex_expand_mpfr_array.c b/SPEX/SPEX_Util/Source/spex_expand_mpfr_array.c deleted file mode 100644 index 9a9d9d2deb..0000000000 --- a/SPEX/SPEX_Util/Source/spex_expand_mpfr_array.c +++ /dev/null @@ -1,65 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/spex_expand_mpfr_array: convert mpfr aray to mpz -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function converts a mpfr array of size n and precision prec to - * an appropriate mpz array of size n. To do this, the number is cast to an - * equivalent mpq_t (rational number) a conversion which MPFR gaurantees to be - * exact. Then, this rational array is converted to an mpz_t array - * This function allows mpfr arrays to be used within SPEX. - */ - -#define SPEX_FREE_ALL \ - SPEX_matrix_free(&x3, NULL); \ - -#include "spex_util_internal.h" - -SPEX_info spex_expand_mpfr_array -( - mpz_t* x_out, // full precision mpz array - mpfr_t* x, // mpfr array to be expanded - mpq_t scale, // scaling factor used (x_out = scale*x) - int64_t n, // size of x - const SPEX_options *option // command options containing the prec - // and rounding for mpfr -) -{ - - //-------------------------------------------------------------------------- - // Input has already been checked - //-------------------------------------------------------------------------- - ASSERT(n >= 0); - SPEX_info info ; - - //-------------------------------------------------------------------------- - // initializations - //-------------------------------------------------------------------------- - - int64_t i; - SPEX_matrix* x3 = NULL; - mpfr_rnd_t round = SPEX_OPTION_ROUND (option) ; - - SPEX_CHECK (SPEX_matrix_allocate(&x3, SPEX_DENSE, SPEX_MPQ, n, 1, n, - false, true, option)); - - // Cast the mpfr array to a rational array - for (i = 0; i < n; i++) - { - // x3[i] = x[i] - SPEX_CHECK(SPEX_mpfr_get_q(x3->x.mpq[i],x[i],round)); - } - - // Expand the mpq array - SPEX_CHECK( spex_expand_mpq_array( x_out, x3->x.mpq, scale, n, option)); - - // Free memory - SPEX_FREE_ALL; - return SPEX_OK; -} - diff --git a/SPEX/SPEX_Util/Source/spex_expand_mpq_array.c b/SPEX/SPEX_Util/Source/spex_expand_mpq_array.c deleted file mode 100644 index d6aa6fe948..0000000000 --- a/SPEX/SPEX_Util/Source/spex_expand_mpq_array.c +++ /dev/null @@ -1,62 +0,0 @@ -//------------------------------------------------------------------------------ -// SPEX_Util/spex_expand_mpq_array: convert mpq array to mpz -//------------------------------------------------------------------------------ - -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. -// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later - -//------------------------------------------------------------------------------ - -/* Purpose: This function converts a mpq array of size n into an appropriate - * mpz array of size n. To do this, the lcm of the denominators is found as a - * scaling factor. This function allows mpq arrays to be used in SPEX. - */ - -#define SPEX_FREE_ALL \ - SPEX_MPZ_CLEAR(temp); - -#include "spex_util_internal.h" - -SPEX_info spex_expand_mpq_array -( - mpz_t* x_out, // mpz array, on output x_out = x*scale - mpq_t* x, // mpq array that needs to be converted - mpq_t scale, // scaling factor. x_out = scale*x - int64_t n, // size of x - const SPEX_options* option // Command options -) -{ - - //-------------------------------------------------------------------------- - // check inputs - //-------------------------------------------------------------------------- - // inputs have been checked in the only caller spex_cast_array - ASSERT(n >= 0); - SPEX_info info ; - - //-------------------------------------------------------------------------- - // Define temporary mpz_t variable - //-------------------------------------------------------------------------- - mpz_t temp; - SPEX_MPZ_SET_NULL(temp); - SPEX_CHECK (SPEX_mpz_init(temp)) ; - - // Find LCM of denominators of x - SPEX_CHECK(SPEX_mpz_set(temp, SPEX_MPQ_DEN(x[0]))); - for (int64_t i = 1; i < n; i++) - { - SPEX_CHECK(SPEX_mpz_lcm(temp, SPEX_MPQ_DEN(x[i]), temp)); - } - SPEX_CHECK(SPEX_mpq_set_z(scale,temp)); - - for (int64_t i = 0; i < n; i++) - { - // x_out[i] = x[i]*temp - SPEX_CHECK(SPEX_mpz_divexact(x_out[i], temp, SPEX_MPQ_DEN(x[i]))); - SPEX_CHECK(SPEX_mpz_mul(x_out[i], x_out[i], SPEX_MPQ_NUM(x[i]))); - } - SPEX_FREE_ALL; - return SPEX_OK; -} - diff --git a/SPEX/SPEX_Utilities/License/CONTRIBUTOR-LICENSE.txt b/SPEX/SPEX_Utilities/License/CONTRIBUTOR-LICENSE.txt new file mode 100644 index 0000000000..c6fa3b44dc --- /dev/null +++ b/SPEX/SPEX_Utilities/License/CONTRIBUTOR-LICENSE.txt @@ -0,0 +1,170 @@ +SPEX_Utilities Individual Contributor License Agreement + +Thank you for your interest in contributing to SPEX_Utilities ("We" or "Us"). + +This contributor agreement ("Agreement") documents the rights granted by +contributors to Us. To make this document effective, please sign it and send it +to Us by electronic submission. This is a legally binding document, so please +read it carefully before agreeing to it. The Agreement may cover more than one +software project managed by Us. + +1. Definitions + + "You" means the individual who Submits a Contribution to Us. + + "Contribution" means any work of authorship that is Submitted by You to Us + in which You own or assert ownership of the Copyright. + + "Copyright" means all rights protecting works of authorship owned or + controlled by You, including copyright, moral and neighboring rights, as + appropriate, for the full term of their existence including any extensions + by You. + + "Material" means the work of authorship which is made available by Us to + third parties. When this Agreement covers more than one software project, + the Material means the work of authorship to which the Contribution was + Submitted. After You Submit the Contribution, it may be included in the + Material. + + "Submit" means any form of electronic, verbal, or written communication + sent to Us or our representatives, including but not limited to electronic + mailing lists, source code control systems, and issue tracking systems that + are managed by, or on behalf of, Us for the purpose of discussing and + improving the Material, but excluding communication that is conspicuously + marked or otherwise designated in writing by You as "Not a Contribution." + + "Submission Date" means the date on which You Submit a Contribution to Us. + + "Effective Date" means the date You execute this Agreement or the date You + first Submit a Contribution to Us, whichever is earlier. + +2. Grant of Rights + + 2.1 Copyright License + + (a) You retain ownership of the Copyright in Your Contribution and have + the same rights to use or license the Contribution which You would have + had without entering into the Agreement. + + (b) To the maximum extent permitted by the relevant law, You grant to + Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, + irrevocable license under the Copyright covering the Contribution, with + the right to sublicense such rights through multiple tiers of + sublicensees, to reproduce, modify, display, perform and distribute the + Contribution as part of the Material; provided that this license is + conditioned upon compliance with Section 2.3. + + 2.2 Patent License + + For patent claims including, without limitation, method, process, and + apparatus claims which You own, control or have the right to grant, now + or in the future, You grant to Us a perpetual, worldwide, + non-exclusive, transferable, royalty-free, irrevocable patent license, + with the right to sublicense these rights to multiple tiers of + sublicensees, to make, have made, use, sell, offer for sale, import and + otherwise transfer the Contribution and the Contribution in combination + with the Material (and portions of such combination). This license is + granted only to the extent that the exercise of the licensed rights + infringes such patent claims; and provided that this license is + conditioned upon compliance with Section 2.3. + + 2.3 Outbound License + + Based on the grant of rights in Sections 2.1 and 2.2, if We include + Your Contribution in a Material, We may license the Contribution under + any license, including copyleft, permissive, commercial, or proprietary + licenses. + + 2.4 Moral Rights. + + If moral rights apply to the Contribution, to the maximum extent + permitted by law, You waive and agree not to assert such moral rights + against Us or our successors in interest, or any of our licensees, + either direct or indirect. + + 2.5 Our Rights. + + You acknowledge that We are not obligated to use Your Contribution as + part of the Material and may decide to include any Contribution We + consider appropriate. + + 2.6 Reservation of Rights. + + Any rights not expressly licensed under this section are expressly + reserved by You. + +3. Agreement + + You confirm that: + + (a) You have the legal authority to enter into this Agreement. + + (b) You own the Copyright and patent claims covering the Contribution which + are required to grant the rights under Section 2. + + (c) The grant of rights under Section 2 does not violate any grant of + rights which You have made to third parties, including Your employer. If + You are an employee, You have had Your employer approve this Agreement or + sign the Entity version of this document. If You are less than eighteen + years old, please have Your parents or guardian sign the Agreement. + +4. Disclaimer + + EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS + PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES + INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY + DISCLAIMED BY YOU TO US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE + DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD + PERMITTED BY LAW. + +5. Consequential Damage Waiver + + TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE + LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, + INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING + OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY + (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. + +6. Miscellaneous + + 6.1 This Agreement will be governed by and construed in accordance with the + laws of the State of Texas excluding its conflicts of law provisions. Under + certain circumstances, the governing law in this section might be + superseded by the United Nations Convention on Contracts for the + International Sale of Goods ("UN Convention") and the parties intend to + avoid the application of the UN Convention to this Agreement and, thus, + exclude the application of the UN Convention in its entirety to this + Agreement. + + 6.2 This Agreement sets out the entire agreement between You and Us for + Your Contributions to Us and overrides all other agreements or + understandings. + + 6.3 If You or We assign the rights or obligations received through this + Agreement to a third party, as a condition of the assignment, that third + party must agree in writing to abide by all the rights and obligations in + the Agreement. + + 6.4 The failure of either party to require performance by the other party + of any provision of this Agreement in one situation shall not affect the + right of a party to require such performance at any time in the future. A + waiver of performance under a provision in one situation shall not be + considered a waiver of the performance of the provision in the future or a + waiver of the provision in its entirety. + + 6.5 If any provision of this Agreement is found void and unenforceable, + such provision will be replaced to the extent possible with a provision + that comes closest to the meaning of the original provision and which is + enforceable. The terms and conditions set forth in this Agreement shall + apply notwithstanding any failure of essential purpose of this Agreement or + any limited remedy to the maximum extent possible under law. + + +Us +All SPEX co-authors: +Christopher Lourenco +Jinhao Chen +Lorena Mejia Domenzain +Timothy A. Davis +Erick Moreno-Centeno diff --git a/SPEX/SPEX_Utilities/License/GPLv2.txt b/SPEX/SPEX_Utilities/License/GPLv2.txt new file mode 100644 index 0000000000..d159169d10 --- /dev/null +++ b/SPEX/SPEX_Utilities/License/GPLv2.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/SPEX/SPEX_Utilities/License/lesserv3.txt b/SPEX/SPEX_Utilities/License/lesserv3.txt new file mode 100644 index 0000000000..fc8a5de7ed --- /dev/null +++ b/SPEX/SPEX_Utilities/License/lesserv3.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/SPEX/SPEX_Utilities/License/license.txt b/SPEX/SPEX_Utilities/License/license.txt new file mode 100644 index 0000000000..44cb885689 --- /dev/null +++ b/SPEX/SPEX_Utilities/License/license.txt @@ -0,0 +1,41 @@ +SPEX_Utilities: Utility functions for SParse EXact package + +Copyright (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +All Rights Reserved. + +Available at: + + https://github.com/clouren/SPEX + http://suitesparse.com + +Contact Chris Lourenco, chrisjlourenco@gmail.com, or Tim Davis +(timdavis@aldenmath.com or DrTimothyAldenDavis@gmail.com) for a commercial +license. + +-------------------------------------------------------------------------------- + +SPEX is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. Each distributor and end-user of SPEX may +select either license, at their option. + +SPEX is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with this software. If not, +see https://www.gnu.org/licenses/. diff --git a/SPEX/SPEX_Util/README.md b/SPEX/SPEX_Utilities/README.md similarity index 60% rename from SPEX/SPEX_Util/README.md rename to SPEX/SPEX_Utilities/README.md index 469e7fca26..360e1a6a4c 100644 --- a/SPEX/SPEX_Util/README.md +++ b/SPEX/SPEX_Utilities/README.md @@ -2,14 +2,11 @@ This folder contains utility functions for the SPEX software package. These functions are shared amongst all other SPEX packages. Key subroutines within this folder: - + -All SPEX GMP/MPFR wrapper functions -All SPEX matrix functions -All SPEX memory handling functions - -General Ax = b sanity check function Other functions that may be useful can be added in the future. -Note that all of these functions are test covered by the respective -packages that use them. For example, SPEX Left LU performs test coverage -on every used utility function. +Note that all of these functions are test covered in SPEX/Tcov. diff --git a/SPEX/SPEX_Util/Source/SPEX_calloc.c b/SPEX/SPEX_Utilities/Source/SPEX_calloc.c similarity index 64% rename from SPEX/SPEX_Util/Source/SPEX_calloc.c rename to SPEX/SPEX_Utilities/Source/SPEX_calloc.c index 8497fbd74c..49bdc9d4f8 100644 --- a/SPEX/SPEX_Util/Source/SPEX_calloc.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_calloc.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_calloc: wrapper for calloc +// SPEX_Utilities/SPEX_calloc: wrapper for calloc //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -18,8 +19,7 @@ void *SPEX_calloc size_t size // size of each item ) { - if (!spex_initialized ( )) return (NULL) ; - return (SuiteSparse_calloc (nitems, size)) ; + return (SuiteSparse_calloc (nitems, size)); } diff --git a/SPEX/SPEX_Util/Source/SPEX_create_default_options.c b/SPEX/SPEX_Utilities/Source/SPEX_create_default_options.c similarity index 55% rename from SPEX/SPEX_Util/Source/SPEX_create_default_options.c rename to SPEX/SPEX_Utilities/Source/SPEX_create_default_options.c index 544172cb95..e521a3e8df 100644 --- a/SPEX/SPEX_Util/Source/SPEX_create_default_options.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_create_default_options.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_create_default_options: set defaults +// SPEX_Utilities/SPEX_create_default_options: set defaults //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -14,34 +15,33 @@ #include "spex_util_internal.h" - -SPEX_info SPEX_create_default_options (SPEX_options **option ) +SPEX_info SPEX_create_default_options (SPEX_options *option_handle) { - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!spex_initialized ( )) return (SPEX_PANIC); //-------------------------------------------------------------------------- // allocate the option struct //-------------------------------------------------------------------------- - *option = SPEX_malloc(sizeof(SPEX_options)) ; - if (!(*option)) + (*option_handle) = SPEX_malloc(sizeof(SPEX_options_struct)); + if (!(*option_handle)) { // out of memory - return (SPEX_OUT_OF_MEMORY) ; + return (SPEX_OUT_OF_MEMORY); } //-------------------------------------------------------------------------- // set defaults //-------------------------------------------------------------------------- - (*option)->pivot = SPEX_DEFAULT_PIVOT ; - (*option)->order = SPEX_DEFAULT_ORDER ; - (*option)->print_level = SPEX_DEFAULT_PRINT_LEVEL ; - (*option)->prec = SPEX_DEFAULT_PRECISION ; - (*option)->tol = SPEX_DEFAULT_TOL ; - (*option)->round = SPEX_DEFAULT_MPFR_ROUND ; - (*option)->check = false ; + (*option_handle)->pivot = SPEX_DEFAULT_PIVOT ; + (*option_handle)->order = SPEX_DEFAULT_ORDER ; + (*option_handle)->print_level = SPEX_DEFAULT_PRINT_LEVEL ; + (*option_handle)->prec = SPEX_DEFAULT_PRECISION ; + (*option_handle)->tol = SPEX_DEFAULT_TOL ; + (*option_handle)->round = SPEX_DEFAULT_MPFR_ROUND ; + (*option_handle)->algo = SPEX_DEFAULT_ALGORITHM ; //-------------------------------------------------------------------------- // return result diff --git a/SPEX/SPEX_Utilities/Source/SPEX_determine_symmetry.c b/SPEX/SPEX_Utilities/Source/SPEX_determine_symmetry.c new file mode 100644 index 0000000000..a6f14b86d8 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_determine_symmetry.c @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_determine_symmetry: Determine if given matrix is +// *numerically* (thus pattern-wise) symmetric +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: Determine if the input A is *numerically* (thus pattern-wise) + * symmetric. Since SPEX is an exact framework, it doesn't make sense to check + * only pattern symmetry. + * + * If the matrix is determined to be symmetric, is_symmetric is returned as + * true. + */ + +#define SPEX_FREE_ALL \ +{ \ + SPEX_matrix_free(&T,NULL); \ + SPEX_matrix_free(&R,NULL); \ +} + +#include "spex_util_internal.h" + +SPEX_info SPEX_determine_symmetry +( + bool *is_symmetric, // true if matrix is symmetric, false otherwise + const SPEX_matrix A, // Input matrix to be checked for symmetry + const SPEX_options option // Command options +) +{ + + SPEX_info info; + + // Check for null pointers + if (!A || !option || !is_symmetric) + { + return SPEX_INCORRECT_INPUT; + } + (*is_symmetric) = false ; + + // A must be CSC and mpz_t + if (A->kind != SPEX_CSC || A->type != SPEX_MPZ) + { + return SPEX_INCORRECT_INPUT; + } + + if (A->n != A->m) + { + // matrix is rectangular (and thus unsymmetric) + return SPEX_OK ; + } + + // Only used index + int64_t j; + + // Declare matrices T and R. T = A' and R = T' = A'' + SPEX_matrix T = NULL, R = NULL ; + // T = A' + SPEX_CHECK( SPEX_transpose(&T, A, option) ); + + // Check if the number of nonzeros in the columns + // of A are equal to the number of nonzeros in + // the rows of A. This is a quick check to + // ensure the matrix is candidate to be symmetric. + // Moreover, this check is important becuase + // otherwise the ensuing block could seg-fault + for (j = 0; j <= A->n; j++) + { + if (T->p[j] != A->p[j]) + { + // Number of nonzeros in column k of A + // is not the same as the number of nonzeros + // in row k of A. So free all and exit + // nnz( A(:,k)) != nnz( A(k,:)) + SPEX_FREE_ALL; + return SPEX_OK ; + } + } + + // Set R = T' + SPEX_CHECK( SPEX_transpose(&R, T, option) ); + + // Check whether A[i][j] = A[j][i] in both pattern and numerics + for (j = 0; j < R->p[R->n]; j++) + { + // Check pattern + if (T->i[j] != R->i[j]) + { + // Not pattern symmetric as row indices do not match + SPEX_FREE_ALL; + return SPEX_OK ; + } + // Check numerics + int r; + SPEX_MPZ_CMP(&r, R->x.mpz[j], T->x.mpz[j]); + if (r != 0) + { + // Not numeric symmetric + SPEX_FREE_ALL; + return SPEX_OK ; + } + } + + // Free memory and return OK, and return is_symmetric as true + SPEX_FREE_ALL; + (*is_symmetric) = true ; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Utilities/Source/SPEX_factorization_free.c b/SPEX/SPEX_Utilities/Source/SPEX_factorization_free.c new file mode 100644 index 0000000000..c9ae0116cc --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_factorization_free.c @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_factorization_free: Free memory for the +// SPEX_factorization data type. +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function frees the memory of the SPEX_factorization struct + * + * Input is the SPEX_factorization structure, it is destroyed on function + * termination. + */ + +#include "spex_util_internal.h" + +SPEX_info SPEX_factorization_free +( + SPEX_factorization *F_handle, // Structure to be deleted + const SPEX_options option +) +{ + + if (!spex_initialized ( )) return (SPEX_PANIC); + + if ((F_handle != NULL) && (*F_handle != NULL)) + { + SPEX_MPQ_CLEAR((*F_handle)->scale_for_A); + + SPEX_matrix_free(&((*F_handle)->L), option); + SPEX_matrix_free(&((*F_handle)->U), option); + SPEX_matrix_free(&((*F_handle)->rhos), option); + + SPEX_FREE((*F_handle)->P_perm); + SPEX_FREE((*F_handle)->Pinv_perm); + SPEX_FREE((*F_handle)->Q_perm); + SPEX_FREE((*F_handle)->Qinv_perm); + + SPEX_FREE (*F_handle); + } + + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Utilities/Source/SPEX_finalize.c b/SPEX/SPEX_Utilities/Source/SPEX_finalize.c new file mode 100644 index 0000000000..9276f9fcef --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_finalize.c @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_finalize: finalize SPEX +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// SPEX_finalize frees the working environment for SPEX library. +// This function must be called by the same user thread that called +// SPEX_initialize or SPEX_initialize_expert. + +#include "spex_util_internal.h" + +SPEX_info SPEX_finalize +( + void +) +{ + + if (!spex_initialized ( )) { return (SPEX_PANIC); } + + SPEX_mpfr_free_cache ( ); // Free mpfr internal cache + + // the primary thread always frees the spex_gmp object + spex_gmp_finalize (1); + + spex_set_initialized (false); + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Util/Source/SPEX_free.c b/SPEX/SPEX_Utilities/Source/SPEX_free.c similarity index 67% rename from SPEX/SPEX_Util/Source/SPEX_free.c rename to SPEX/SPEX_Utilities/Source/SPEX_free.c index d0187e6420..28db44e25e 100644 --- a/SPEX/SPEX_Util/Source/SPEX_free.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_free.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_free: wrapper for free +// SPEX_Utilities/SPEX_free: wrapper for free //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -17,6 +18,6 @@ void SPEX_free void *p // pointer to memory space to free ) { - SuiteSparse_free (p) ; + SuiteSparse_free (p); } diff --git a/SPEX/SPEX_Util/Source/SPEX_gmp.c b/SPEX/SPEX_Utilities/Source/SPEX_gmp.c similarity index 60% rename from SPEX/SPEX_Util/Source/SPEX_gmp.c rename to SPEX/SPEX_Utilities/Source/SPEX_gmp.c index 0f065799ae..a7c8e35180 100644 --- a/SPEX/SPEX_Util/Source/SPEX_gmp.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_gmp.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_gmp.c: interface to the gmp library +// SPEX_Utilities/SPEX_gmp.c: interface to the gmp library //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -31,9 +32,9 @@ SPEX_info SPEX_gmpfunc (args) { SPEX_GMP_WRAPPER_START ; - gmpfunc (args) ; + gmpfunc (args); SPEX_GMP_WRAPPER_FINISH ; - return SPEX_OK ; + return (SPEX_OK); } */ @@ -47,84 +48,230 @@ // is passed as the first argument to the SPEX_gmpfunc: /* - SPEX_info SPEX_gmfunc (result, args) + SPEX_info SPEX_gmpfunc (int *result, args) { SPEX_GMP_WRAPPER_START ; - (*result) = gmpfunc (args) ; + (*result) = gmpfunc (args); SPEX_GMP_WRAPPER_FINISH ; - return SPEX_OK ; + return (SPEX_OK); } */ -// The SPEX_GMP*_WRAPPER_START macros also take an single 'archive' parameter, +// The SPEX_GMP*_WRAPPER_START macros also take one or two 'archive' parameters, // for the current mpz, mpq, or mpfr object being operated on. A pointer // parameter to this parameter is kept so that it can be safely freed in case -// a memory error occurs (avoiding a double-free), in SPEX_GMP_SAFE_FREE. +// a memory error occurs (avoiding a double-free), in spex_gmp_safe_free. +// See the examples below. #include "spex_util_internal.h" -#include "SPEX_gmp.h" -#if defined (__GNUC__) // ignore warnings about unused parameters in this file +#if defined (__GNUC__) #pragma GCC diagnostic ignored "-Wunused-parameter" #endif //------------------------------------------------------------------------------ -// global variables +// thread-local-storage //------------------------------------------------------------------------------ -jmp_buf spex_gmp_environment ; // for setjmp and longjmp -int64_t spex_gmp_nmalloc = 0 ; // number of malloc'd objects in SPEX_gmp_list -int64_t spex_gmp_nlist = 0 ; // size of the SPEX_gmp_list -void **spex_gmp_list = NULL ; // list of malloc'd objects +// SPEX is thread-safe as long as all of the following conditions hold: +// +// (1) GMP and MPFR are both thread-safe. This is the typical case, but it is +// possible to compile GMP and MPFR with thread-safety disabled. See: +// https://gmplib.org/manual/Reentrancy +// https://www.mpfr.org/mpfr-3.1.0/ +// +// (2) only one user thread calls SPEX_initialize and SPEX_finalize. +// +// (3) each subsequent user thread must call SPEX_thread_initialize when it +// starts, and SPEX_thread_finalize when it finishes. +// +// (4) Multiple user threads may not write to the same SPEX objects. If +// declared as an input-only variable, multiple user threads may access +// them in parallel. +// +// (5) SPEX is compiled with either OpenMP, or a compiler that supports +// thread-local-storage (most of them do). + +#if defined ( _OPENMP ) + + // OpenMP threadprivate is preferred + #include + spex_gmp_t *spex_gmp = NULL ; + #pragma omp threadprivate (spex_gmp) + +#elif defined ( HAVE_KEYWORD__THREAD ) + + // gcc and many other compilers support the __thread keyword + __thread spex_gmp_t *spex_gmp = NULL ; + +#elif defined ( HAVE_KEYWORD__DECLSPEC_THREAD ) + + // Windows: __declspec (thread) + __declspec ( thread ) spex_gmp_t *spex_gmp = NULL ; + +#elif defined ( HAVE_KEYWORD__THREAD_LOCAL ) + + // ANSI C11 threads + #include + _Thread_local spex_gmp_t *spex_gmp = NULL ; -int64_t spex_gmp_ntrials = -1 ; // number of malloc's allowed (for - // testing only): -1 means unlimited. +#else -mpz_ptr spex_gmpz_archive = NULL ; // current mpz object -mpq_ptr spex_gmpq_archive = NULL ; // current mpq object -mpfr_ptr spex_gmpfr_archive = NULL ; // current mpfr object + // SPEX will not be thread-safe. + spex_gmp_t *spex_gmp = NULL ; + +#endif //------------------------------------------------------------------------------ -// spex_gmp_init: initialize gmp +// GMP/MPFR wrapper macros //------------------------------------------------------------------------------ -/* Purpose: Create the list of malloc'd objects. This should be called before - * calling any GMP function. It is also called by SPEX_gmp_allocate when - * SPEX_gmp_list is NULL - */ +#define SPEX_GMP_WRAPPER_START_HELPER(z1,z2,q,fr) \ + /* spex_gmp_t *spex_gmp = spex_gmp_get ( ) ; */ \ + if (spex_gmp == NULL) return (SPEX_OUT_OF_MEMORY); \ + spex_gmp->mpz_archive = z1 ; \ + spex_gmp->mpz_archive2 = z2 ; \ + spex_gmp->mpq_archive = q ; \ + spex_gmp->mpfr_archive = fr ; \ + /* setjmp returns 0 if called from here, or > 0 if from longjmp */ \ + int status = setjmp (spex_gmp->environment) ; \ + if (status != 0) \ + { \ + /* failure from longjmp */ \ + return (spex_gmp_failure (status)) ; \ + } + +#define SPEX_GMP_WRAPPER_START \ + SPEX_GMP_WRAPPER_START_HELPER (NULL, NULL, NULL, NULL) ; + +#define SPEX_GMPZ_WRAPPER_START(z1) \ + SPEX_GMP_WRAPPER_START_HELPER (z1, NULL, NULL, NULL) ; + +#define SPEX_GMPZ_WRAPPER_START2(z1,z2) \ + SPEX_GMP_WRAPPER_START_HELPER (z1, z2, NULL, NULL) ; + +#define SPEX_GMPQ_WRAPPER_START(q) \ + SPEX_GMP_WRAPPER_START_HELPER (NULL, NULL, q, NULL) ; + +#define SPEX_GMPFR_WRAPPER_START(fr) \ + SPEX_GMP_WRAPPER_START_HELPER (NULL, NULL, NULL, fr) ; + +#define SPEX_GMP_WRAPPER_FINISH \ + spex_gmp->nmalloc = 0 ; \ + spex_gmp->mpz_archive = NULL ; \ + spex_gmp->mpz_archive2 = NULL ; \ + spex_gmp->mpq_archive = NULL ; \ + spex_gmp->mpfr_archive = NULL ; + +//------------------------------------------------------------------------------ +// spex_gmp_initialize: initialize the SPEX GMP interface +//------------------------------------------------------------------------------ + +// Called by SPEX_initialize* with primary == 1, and by SPEX_thread_initialize +// with primary == 0. The object is not allocated if it already exists. + +SPEX_info spex_gmp_initialize (int primary) +{ + if (spex_gmp == NULL) + { + // allocate the spex_gmp object + spex_gmp = SPEX_calloc (1, sizeof (spex_gmp_t)); + if (spex_gmp == NULL) + { + // out of memory + return (SPEX_OUT_OF_MEMORY); + } + + // allocate an empty spex_gmp->list + spex_gmp->list = (void **) SPEX_calloc (SPEX_GMP_LIST_INIT, + sizeof (void *)); + + if (spex_gmp->list == NULL) + { + // out of memory + SPEX_FREE (spex_gmp); + return (SPEX_OUT_OF_MEMORY); + } + + // initialize the spex_gmp + spex_gmp->nlist = SPEX_GMP_LIST_INIT ; + spex_gmp->nmalloc = 0 ; + spex_gmp->mpz_archive = NULL ; + spex_gmp->mpz_archive2 = NULL ; + spex_gmp->mpq_archive = NULL ; + spex_gmp->mpfr_archive = NULL ; + spex_gmp->primary = primary ; + } + return (SPEX_OK); +} + +//------------------------------------------------------------------------------ +// spex_gmp_finalize: finalize the SPEX GMP interface +//------------------------------------------------------------------------------ + +// called by SPEX_finalize* with primary == 1, and by SPEX_thread_finalize with +// primary == 0. -bool spex_gmp_init ( ) +void spex_gmp_finalize (int primary) { - spex_gmp_nmalloc = 0 ; - spex_gmp_nlist = SPEX_GMP_LIST_INIT ; - spex_gmp_list = (void **) SPEX_malloc (spex_gmp_nlist * sizeof (void *)) ; - return (spex_gmp_list != NULL) ; + // free the spex_gmp object for this thread, if it exists. If this function + // is called by SPEX_finalize, then primary == 1 on input, and the spex_gmp + // object is always freed. If primary == 0 on input, then the caller is + // SPEX_thread_finalize, and in this case the spex_gmp object is freed only + // if spex_gmp->primary is also zero. + + if (spex_gmp != NULL && primary >= spex_gmp->primary) + { + // free the spex_gmp->list, if it exists + SPEX_FREE (spex_gmp->list) ; + // free the spex_gmp object itself + SPEX_FREE (spex_gmp); + } } //------------------------------------------------------------------------------ -// SPEX_gmp_finalize: finalize gmp +// spex_gmp_get: get the thread-local spex_gmp object and initialize it //------------------------------------------------------------------------------ -/* Purpose: Free the list. Must be called when all use of GMP is done */ -void spex_gmp_finalize ( ) +spex_gmp_t *spex_gmp_get (void) { - spex_gmpz_archive = NULL ; - spex_gmpq_archive = NULL ; - spex_gmpfr_archive = NULL ; - spex_gmp_nmalloc = 0 ; - spex_gmp_nlist = 0 ; - SPEX_FREE (spex_gmp_list) ; + if (spex_gmp != NULL) + { + // clear the list of allocated objects in the spex_gmp->list + spex_gmp->nmalloc = 0 ; + } + + // return the spex_gmp object for this thread (or NULL if none) + return (spex_gmp); } //------------------------------------------------------------------------------ -// SPEX_gmp_allocate: malloc space for gmp +// spex_gmp_ntrials: pretend to fail, for test coverage only +//------------------------------------------------------------------------------ + +#ifdef SPEX_GMP_TEST_COVERAGE +static int64_t spex_gmp_ntrials = -1 ; // for test coverage only + +void spex_set_gmp_ntrials (int64_t ntrials) +{ + spex_gmp_ntrials = ntrials ; +} + +int64_t spex_get_gmp_ntrials (void) +{ + return (spex_gmp_ntrials) ; +} +#endif + +//------------------------------------------------------------------------------ +// spex_gmp_allocate: malloc space for gmp //------------------------------------------------------------------------------ /* Purpose: malloc space for gmp. A NULL pointer is never returned to the GMP - * library. If the allocation fails, all memory allocated since the start of - * the SPEX_gmp_wrapper is freed and an error is thrown to the GMP wrapper via - * longjmp + * library. If the allocation fails, all memory allocated since the + * SPEX_GMP*_WRAPPER_START is freed and an error is thrown to the GMP wrapper + * via longjmp */ void *spex_gmp_allocate @@ -133,88 +280,134 @@ void *spex_gmp_allocate ) { - #ifdef SPEX_GMP_MEMORY_DEBUG - SPEX_PRINTF ("spex_gmp_malloc (%g): ", (double) size) ; - #endif - //-------------------------------------------------------------------------- - // for testing only: + // check inputs //-------------------------------------------------------------------------- - if (spex_gmp_ntrials == 0) - { - // pretend to fail - #ifdef SPEX_GMP_MEMORY_DEBUG - SPEX_PRINTF ("spex_gmp_allocate pretends to fail\n") ; - #endif - longjmp (spex_gmp_environment, 1) ; - } - else if (spex_gmp_ntrials > 0) - { - // one more malloc has been used up - spex_gmp_ntrials-- ; - } + // if spex_gmp does not exist, memory cannot be allocarted + if (spex_gmp == NULL) return (NULL) ; //-------------------------------------------------------------------------- - // ensure the SPEX_gmp_list is large enough + // for testing only: //-------------------------------------------------------------------------- - if (spex_gmp_list == NULL) + #ifdef SPEX_GMP_TEST_COVERAGE { - // create the initial SPEX_gmp_list - if (!spex_gmp_init ( )) + if (spex_gmp_ntrials == 0) + { + // pretend to fail + #ifdef SPEX_GMP_MEMORY_DEBUG + SPEX_PRINTF ("spex_gmp_allocate pretends to fail\n"); + #endif + longjmp (spex_gmp->environment, 1); + } + else if (spex_gmp_ntrials > 0) { - // failure to create the SPEX_gmp_list - longjmp (spex_gmp_environment, 2) ; + // one more malloc has been used up + spex_gmp_ntrials-- ; } } - else if (spex_gmp_nmalloc == spex_gmp_nlist) + #endif + + //-------------------------------------------------------------------------- + // ensure the spex_gmp->list is large enough + //-------------------------------------------------------------------------- + + if (spex_gmp->nmalloc == spex_gmp->nlist) { - // double the size of the SPEX_gmp_list + // double the size of the spex_gmp->list bool ok ; - int64_t newsize = 2 * spex_gmp_nlist ; - spex_gmp_list = (void **) - SPEX_realloc (newsize, spex_gmp_nlist, sizeof (void *), - spex_gmp_list, &ok) ; + int64_t newsize = 2 * spex_gmp->nlist ; + spex_gmp->list = (void **) + SPEX_realloc (newsize, spex_gmp->nlist, sizeof (void *), + spex_gmp->list, &ok); if (!ok) { - // failure to double the size of the SPEX_gmp_list. - // The existing SPEX_gmp_list is still valid, with the old size, - // (SPEX_gmp_nlist). This is required so that the error handler - // can traverse the SPEX_gmp_list to free all objects there. - longjmp (spex_gmp_environment, 3) ; + // failure to double the size of the spex_gmp->list. + // The existing spex_gmp->list is still valid, with the old size, + // (spex_gmp->nlist). This is required so that the error handler + // can traverse the spex_gmp->list to free all objects there. + longjmp (spex_gmp->environment, 3); } - // success; the old SPEX_gmp_list has been freed, and replaced with + // success: the old spex_gmp->list has been freed, and replaced with // the larger newlist. - spex_gmp_nlist = newsize ; + spex_gmp->nlist = newsize ; } //-------------------------------------------------------------------------- // malloc the block //-------------------------------------------------------------------------- - void *p = SPEX_malloc (size) ; + #ifdef SPEX_GMP_MEMORY_DEBUG + SPEX_PRINTF ("spex_gmp_malloc (%g): ", (double) size); + #endif + + void *p = SPEX_malloc (size); if (p == NULL) { // failure to allocate the new block - longjmp (spex_gmp_environment, 4) ; + longjmp (spex_gmp->environment, 4); } //-------------------------------------------------------------------------- - // save p in the SPEX_gmp_list and return result to GMP + // save p in the spex_gmp->list and return result to GMP //-------------------------------------------------------------------------- - spex_gmp_list [spex_gmp_nmalloc++] = p ; + spex_gmp->list [spex_gmp->nmalloc++] = p ; #ifdef SPEX_GMP_MEMORY_DEBUG - SPEX_PRINTF (" %p\n", p) ; - spex_gmp_dump ( ) ; + SPEX_PRINTF (" %p\n", p); + spex_gmp_dump ( ); #endif // return p to SPEX_gmp_function (NEVER return a NULL pointer to GMP!) - ASSERT (p != NULL) ; - return (p) ; + ASSERT (p != NULL); + return (p); +} + +//------------------------------------------------------------------------------ +// spex_gmp_safe_free: free a block of memory and remove it from the archive +//------------------------------------------------------------------------------ + +static inline void spex_gmp_safe_free (void *p) +{ + if (spex_gmp != NULL) + { + if (spex_gmp->mpz_archive != NULL) + { + if (p == SPEX_MPZ_PTR((spex_gmp->mpz_archive))) + { + SPEX_MPZ_PTR((spex_gmp->mpz_archive)) = NULL ; + } + } + if (spex_gmp->mpz_archive2 != NULL) + { + if (p == SPEX_MPZ_PTR((spex_gmp->mpz_archive2))) + { + SPEX_MPZ_PTR((spex_gmp->mpz_archive2)) = NULL ; + } + } + if (spex_gmp->mpq_archive != NULL) + { + if (p == SPEX_MPZ_PTR(SPEX_MPQ_NUM(spex_gmp->mpq_archive))) + { + SPEX_MPZ_PTR(SPEX_MPQ_NUM(spex_gmp->mpq_archive)) = NULL ; + } + if (p == SPEX_MPZ_PTR(SPEX_MPQ_DEN(spex_gmp->mpq_archive))) + { + SPEX_MPZ_PTR(SPEX_MPQ_DEN(spex_gmp->mpq_archive)) = NULL ; + } + } + if (spex_gmp->mpfr_archive != NULL) + { + if (p == SPEX_MPFR_REAL_PTR(spex_gmp->mpfr_archive)) + { + SPEX_MPFR_MANT(spex_gmp->mpfr_archive) = NULL ; + } + } + } + SPEX_FREE (p) ; } //------------------------------------------------------------------------------ @@ -228,36 +421,58 @@ void spex_gmp_free size_t size // Size of p (currently an unused parameter) ) { - #ifdef SPEX_GMP_MEMORY_DEBUG - SPEX_PRINTF ("\n=================== free %p\n", p) ; - spex_gmp_dump ( ) ; - #endif - if (p != NULL && spex_gmp_list != NULL) + //-------------------------------------------------------------------------- + // quick return if p is NULL + //-------------------------------------------------------------------------- + + if (p == NULL) { - // remove p from the SPEX_gmp_list - for (int64_t i = 0 ; i < spex_gmp_nmalloc ; i++) + return ; + } + + //-------------------------------------------------------------------------- + // remove the block from the spex_gmp->list + //-------------------------------------------------------------------------- + + if (spex_gmp != NULL) + { + + #ifdef SPEX_GMP_MEMORY_DEBUG + SPEX_PRINTF ("\n=================== free %p\n", p); + spex_gmp_dump ( ); + #endif + + if (spex_gmp->list != NULL) { - if (spex_gmp_list [i] == p) + // remove p from the spex_gmp->list + for (int64_t i = 0 ; i < spex_gmp->nmalloc ; i++) { - #ifdef SPEX_GMP_MEMORY_DEBUG - SPEX_PRINTF (" found at i = %d\n", i) ; - #endif - spex_gmp_list [i] = spex_gmp_list [--spex_gmp_nmalloc] ; - break ; + if (spex_gmp->list [i] == p) + { + #ifdef SPEX_GMP_MEMORY_DEBUG + SPEX_PRINTF (" found at i = %d\n", i); + #endif + spex_gmp->list [i] = spex_gmp->list [--spex_gmp->nmalloc] ; + break ; + } } } + + #ifdef SPEX_GMP_MEMORY_DEBUG + spex_gmp_dump ( ); + #endif } - #ifdef SPEX_GMP_MEMORY_DEBUG - spex_gmp_dump ( ) ; - #endif + //-------------------------------------------------------------------------- + // free the block + //-------------------------------------------------------------------------- - // free p, even if it is not found in the SPEX_gmp_list. p is only in the - // SPEX_gmp_list if it was allocated inside the current GMP function. + // free p, even if it is not found in the spex_gmp->list. p is only in the + // spex_gmp->list if it was allocated inside the current GMP function. // If the block was allocated by one GMP function and freed by another, // it is not in the list. - SPEX_GMP_SAFE_FREE (p) ; + spex_gmp_safe_free (p); } //------------------------------------------------------------------------------ @@ -272,31 +487,43 @@ void *spex_gmp_reallocate size_t new_size // New size of p ) { + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + // if spex_gmp does not exist, memory cannot be allocated + if (spex_gmp == NULL) return (NULL) ; + + //-------------------------------------------------------------------------- + // reallocate the space + //-------------------------------------------------------------------------- + #ifdef SPEX_GMP_MEMORY_DEBUG SPEX_PRINTF ("spex_gmp_realloc (%p, %g, %g)\n", p_old, - (double) old_size, (double) new_size) ; + (double) old_size, (double) new_size); #endif if (p_old == NULL) { // realloc (NULL, size) is the same as malloc (size) - return (spex_gmp_allocate (new_size)) ; + return (spex_gmp_allocate (new_size)); } else if (new_size == 0) { // realloc (p, 0) is the same as free (p), and returns NULL - spex_gmp_free (p_old, old_size) ; - return (NULL) ; + spex_gmp_free (p_old, old_size); + return (NULL); } else { // change the size of the block - void *p_new = spex_gmp_allocate (new_size) ; - // Note that p_new will never be NULL here, since SPEX_gmp_allocate + void *p_new = spex_gmp_allocate (new_size); + // Note that p_new will never be NULL here, since spex_gmp_allocate // does not return if it fails. - memcpy (p_new, p_old, SPEX_MIN (old_size, new_size)) ; - spex_gmp_free (p_old, old_size) ; - return (p_new) ; + memcpy (p_new, p_old, SPEX_MIN (old_size, new_size)); + spex_gmp_free (p_old, old_size); + return (p_new); } } @@ -305,19 +532,36 @@ void *spex_gmp_reallocate //------------------------------------------------------------------------------ /* Purpose: Dump the list of malloc'd objects */ + #ifdef SPEX_GMP_MEMORY_DEBUG void spex_gmp_dump ( ) { - // dump the SPEX_gmp_list - SPEX_PRINTF ("nmalloc = %g, SPEX_gmp_nlist = %g\n", - (double) spex_gmp_nmalloc, (double) spex_gmp_nlist) ; - if (spex_gmp_list != NULL) + + //-------------------------------------------------------------------------- + // dump the spex_gmp->list + //-------------------------------------------------------------------------- + + if (spex_gmp == NULL) + { + SPEX_PRINTF ("spex_gmp is NULL\n") ; + return ; + } + + SPEX_PRINTF ("nmalloc = %g, spex_gmp->nlist = %g\n", + (double) spex_gmp->nmalloc, (double) spex_gmp->nlist); + if (spex_gmp->list != NULL) { - for (int64_t i = 0 ; i < spex_gmp_nmalloc ; i++) + for (int64_t i = 0 ; i < spex_gmp->nmalloc ; i++) { - SPEX_PRINTF (" spex_gmp_list [%d] = %p\n", i, spex_gmp_list [i]); + SPEX_PRINTF (" spex_gmp->list [%d] = %p\n", i, + spex_gmp->list [i]); } } + + SPEX_PRINTF (" spex_gmp->mpz_archive : %p\n", spex_gmp->mpz_archive); + SPEX_PRINTF (" spex_gmp->mpz_archive2 : %p\n", spex_gmp->mpz_archive2); + SPEX_PRINTF (" spex_gmp->mpq_archive : %p\n", spex_gmp->mpq_archive); + SPEX_PRINTF (" spex_gmp->mpfr_archive : %p\n", spex_gmp->mpfr_archive); } #endif @@ -326,28 +570,50 @@ void spex_gmp_dump ( ) //------------------------------------------------------------------------------ /* Purpose: Catch an error from longjmp */ -void spex_gmp_failure + +SPEX_info spex_gmp_failure ( int status // Status returned from longjmp // (unused parameter unless debugging) ) { + + //-------------------------------------------------------------------------- + // get the spex_gmp object for this thread + //-------------------------------------------------------------------------- + #ifdef SPEX_GMP_MEMORY_DEBUG - SPEX_PRINTF ("failure from longjmp: status: %d\n", status) ; + SPEX_PRINTF ("failure from longjmp: status: %d\n", status); #endif - // first free all caches - mpfr_free_cache ( ) ; + //-------------------------------------------------------------------------- + // free all MPFR caches + //-------------------------------------------------------------------------- - // Free the list - if (spex_gmp_list != NULL) + mpfr_free_cache ( ); + + //-------------------------------------------------------------------------- + // free the contents of the spex_gmp_t list + //-------------------------------------------------------------------------- + + if (spex_gmp != NULL) { - for (int64_t i = 0 ; i < spex_gmp_nmalloc ; i++) + if (spex_gmp->list != NULL) { - SPEX_GMP_SAFE_FREE (spex_gmp_list [i]) ; + for (int64_t i = 0 ; i < spex_gmp->nmalloc ; i++) + { + spex_gmp_safe_free (spex_gmp->list [i]); + spex_gmp->list [i] = NULL ; + } } + SPEX_GMP_WRAPPER_FINISH ; } - spex_gmp_finalize ( ) ; + + //-------------------------------------------------------------------------- + // tell the caller that the GMP/MPFR function ran out of memory + //-------------------------------------------------------------------------- + + return (SPEX_OUT_OF_MEMORY); } //------------------------------------------------------------------------------ @@ -378,15 +644,15 @@ SPEX_info SPEX_gmp_fprintf SPEX_GMP_WRAPPER_START ; // call gmp_vfprintf - va_list args; - va_start (args, format) ; - int n = gmp_vfprintf (fp, format, args) ; - va_end (args) ; + va_list args ; + va_start (args, format); + int n = gmp_vfprintf (fp, format, args); + va_end (args); // Finish the wrapper SPEX_GMP_WRAPPER_FINISH ; // gmp_vfprintf returns -1 if an error occurred. - return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } #endif @@ -397,6 +663,7 @@ SPEX_info SPEX_gmp_fprintf /* Safely print to the standard output stdout. Return positive value (the number * of characters written) upon success, otherwise return negative value (error * code) */ + #if 0 /* This function is currently unused, but kept here for future reference. */ SPEX_info SPEX_gmp_printf @@ -409,18 +676,19 @@ SPEX_info SPEX_gmp_printf SPEX_GMP_WRAPPER_START ; // call gmp_vprintf - va_list args; - va_start (args, format) ; - int n = gmp_vprintf (format, args) ; - va_end (args) ; + va_list args ; + va_start (args, format); + int n = gmp_vprintf (format, args); + va_end (args); // Finish the wrapper SPEX_GMP_WRAPPER_FINISH ; // gmp_vprintf returns -1 if an error occurred. - return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } #endif + //------------------------------------------------------------------------------ // SPEX_gmp_asprintf //------------------------------------------------------------------------------ @@ -440,15 +708,15 @@ SPEX_info SPEX_gmp_asprintf (char **str, const char *format, ... ) SPEX_GMP_WRAPPER_START ; // call gmp_vasprintf - va_list args; - va_start (args, format) ; - int n = gmp_vasprintf (str, format, args) ; - va_end (args) ; + va_list args ; + va_start (args, format); + int n = gmp_vasprintf (str, format, args); + va_end (args); // Finish the wrapper SPEX_GMP_WRAPPER_FINISH ; // gmp_vasprintf returns a negative value if an error occurred - return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } #endif @@ -471,17 +739,17 @@ SPEX_info SPEX_gmp_fscanf SPEX_GMP_WRAPPER_START ; // call gmp_vfscanf - va_list args; - va_start (args, format) ; - int n = gmp_vfscanf (fp, format, args) ; - va_end (args) ; + va_list args ; + va_start (args, format); + int n = gmp_vfscanf (fp, format, args); + va_end (args); // Finish the wrapper SPEX_GMP_WRAPPER_FINISH ; // If end of input (or a file error) is reached before a character // for a field or a literal, and if no previous non-suppressed fields have // matched, then the return value is EOF instead of 0 - return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } //------------------------------------------------------------------------------ @@ -500,15 +768,15 @@ SPEX_info SPEX_mpfr_asprintf (char **str, const char *format, ... ) SPEX_GMP_WRAPPER_START ; // call mpfr_vasprintf - va_list args; - va_start (args, format) ; - int n = mpfr_vasprintf (str, format, args) ; - va_end (args) ; + va_list args ; + va_start (args, format); + int n = mpfr_vasprintf (str, format, args); + va_end (args); // Finish the wrapper SPEX_GMP_WRAPPER_FINISH ; // mpfr_vasprintf returns a negative value if an error occurred - return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } //------------------------------------------------------------------------------ @@ -516,19 +784,20 @@ SPEX_info SPEX_mpfr_asprintf (char **str, const char *format, ... ) //------------------------------------------------------------------------------ /* Safely free a string allocated by SPEX_mpfr_asprintf. */ -/* DONT TRY TO FREE NULL PONITER USING THIS FUNCTION*/ SPEX_info SPEX_mpfr_free_str (char *str) { + if (str == NULL) return (SPEX_OK); // nothing to do + // Start the GMP wrapper SPEX_GMP_WRAPPER_START ; // call mpfr_free_str - mpfr_free_str (str) ; + mpfr_free_str (str); // Finish the wrapper and return 0 if successful SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -553,19 +822,19 @@ SPEX_info SPEX_mpfr_fprintf SPEX_GMP_WRAPPER_START ; // call mpfr_vfprintf - va_list args; - va_start (args, format) ; - int n = mpfr_vfprintf (fp, format, args) ; - va_end (args) ; + va_list args ; + va_start (args, format); + int n = mpfr_vfprintf (fp, format, args); + va_end (args); // Free cache from mpfr_vfprintf. Even though mpfr_free_cache is // called in SPEX_finalize ( ), it has to be called here to // prevent memory leak in some rare situations. - mpfr_free_cache ( ) ; + mpfr_free_cache ( ); // Finish the wrapper SPEX_GMP_WRAPPER_FINISH ; // mpfr_vfprintf returns -1 if an error occurred. - return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } #endif @@ -589,19 +858,19 @@ SPEX_info SPEX_mpfr_printf SPEX_GMP_WRAPPER_START ; // call mpfr_vprintf - va_list args; - va_start (args, format) ; - int n = mpfr_vprintf (format, args) ; - va_end (args) ; + va_list args ; + va_start (args, format); + int n = mpfr_vprintf (format, args); + va_end (args); // Free cache from mpfr_vprintf. Even though mpfr_free_cache is // called in SPEX_finalize ( ), it has to be called here to // prevent memory leak in some rare situations. - mpfr_free_cache ( ) ; + mpfr_free_cache ( ); // Finish the wrapper SPEX_GMP_WRAPPER_FINISH ; // mpfr_vprintf returns -1 if an error occurred. - return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + return ((n < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } #endif //------------------------------------------------------------------------------ @@ -615,16 +884,19 @@ SPEX_info SPEX_mpfr_printf //------------------------------------------------------------------------------ /* Purpose: Safely initialize an mpz_t number */ +// NOTE: This function never returns out-of-memory error with GMP-6.2.1 or +// later versions (since there will be no memory allocation). But it could +// return such error for GMP-6.1.2 or ealier versions. SPEX_info SPEX_mpz_init ( mpz_t x ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_init (x) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_init (x); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -636,13 +908,13 @@ SPEX_info SPEX_mpz_init SPEX_info SPEX_mpz_init2 ( mpz_t x, // Number to be initialized - const size_t size // size of the number + const uint64_t size // size of the number ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_init2 (x, (mp_bitcnt_t) size) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_init2 (x, (mp_bitcnt_t) size); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -657,10 +929,10 @@ SPEX_info SPEX_mpz_set const mpz_t y ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_set (x, y) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_set (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -675,10 +947,10 @@ SPEX_info SPEX_mpz_set_ui const uint64_t y ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_set_ui (x, (unsigned long int) y) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_set_ui (x, (unsigned long int) y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -693,18 +965,18 @@ SPEX_info SPEX_mpz_set_si const int64_t y ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_set_si (x, (signed long int) y) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_set_si (x, (signed long int) y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } -#if 0 -/* This function is currently unused, but kept here for future reference. */ //------------------------------------------------------------------------------ // SPEX_mpz_set_d //------------------------------------------------------------------------------ /* Purpose: Safely set an mpz number = a double */ +#if 0 +/* This function is currently unused, but kept here for future reference. */ SPEX_info SPEX_mpz_set_d ( @@ -712,10 +984,10 @@ SPEX_info SPEX_mpz_set_d const double y ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_set_d (x, y) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_set_d (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } #endif @@ -732,9 +1004,9 @@ SPEX_info SPEX_mpz_get_d ) { SPEX_GMP_WRAPPER_START ; - *x = mpz_get_d (y) ; + *x = mpz_get_d (y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -750,109 +1022,122 @@ SPEX_info SPEX_mpz_get_si ) { SPEX_GMP_WRAPPER_START ; - *x = mpz_get_si (y) ; + *x = (int64_t) mpz_get_si (y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } + //------------------------------------------------------------------------------ -// SPEX_mpz_set_q +// SPEX_mpz_mul //------------------------------------------------------------------------------ -/* Purpose: Safely set an mpz number = mpq number */ +/* Purpose: Safely compute a = b*c */ -SPEX_info SPEX_mpz_set_q +SPEX_info SPEX_mpz_mul ( - mpz_t x, - const mpq_t y + mpz_t a, + const mpz_t b, + const mpz_t c ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_set_q (x, y) ; + SPEX_GMPZ_WRAPPER_START (a); + mpz_mul (a, b, c); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } + //------------------------------------------------------------------------------ -// SPEX_mpz_mul +// SPEX_mpz_addmul //------------------------------------------------------------------------------ -/* Purpose: Safely compute a = b*c */ - -SPEX_info SPEX_mpz_mul +/* Purpose: Safely set an mpz number += product of two mpz numbers, + * i.e., x = x + y*z */ +#if 0 +SPEX_info SPEX_mpz_addmul ( - mpz_t a, - const mpz_t b, - const mpz_t c + mpz_t x, + const mpz_t y, + const mpz_t z ) { - SPEX_GMPZ_WRAPPER_START (a) ; - mpz_mul (a, b, c) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_addmul (x, y, z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } +#endif -#if 0 //------------------------------------------------------------------------------ -// SPEX_mpz_add +// SPEX_mpz_sub //------------------------------------------------------------------------------ -/* Purpose: Safely compute a = b+c */ +/* Purpose: Safely compute a = b-c */ -SPEX_info SPEX_mpz_add +SPEX_info SPEX_mpz_sub ( mpz_t a, const mpz_t b, const mpz_t c ) { - SPEX_GMPZ_WRAPPER_START (a) ; - mpz_add (a,b,c) ; + SPEX_GMPZ_WRAPPER_START (a); + mpz_sub (a,b,c); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } + //------------------------------------------------------------------------------ -// SPEX_mpz_addmul +// SPEX_mpz_submul //------------------------------------------------------------------------------ -/* Purpose: Safely set an mpz number += product of two mpz numbers, - * i.e., x = x + y*z */ +/* Purpose: Safely set an mpz number = itself minus a product of + * mpz numbers, i.e., x = x - y*z + */ -SPEX_info SPEX_mpz_addmul +SPEX_info SPEX_mpz_submul ( mpz_t x, const mpz_t y, const mpz_t z ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_addmul (x, y, z) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_submul (x, y, z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } -#endif //------------------------------------------------------------------------------ -// SPEX_mpz_submul +// SPEX_mpz_cdiv_qr //------------------------------------------------------------------------------ -/* Purpose: Safely set an mpz number = itself minus a product of - * mpz numbers, i.e., x = x - y*z +/* Purpose: Safe version of dividing n by d, forming a quotient q and/or + * remainder r. + * cdiv rounds q up towards +infinity, and r will have the opposite sign to d. + * The c stands for “ceil”. That is, q = ceil(n/d) */ -SPEX_info SPEX_mpz_submul +SPEX_info SPEX_mpz_cdiv_qr ( - mpz_t x, - const mpz_t y, - const mpz_t z + mpz_t q, + mpz_t r, + const mpz_t n, + const mpz_t d ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_submul (x, y, z) ; + SPEX_GMPZ_WRAPPER_START2 (q, r); + if (mpz_sgn (d) == 0) + { + SPEX_GMP_WRAPPER_FINISH ; + return (SPEX_PANIC); + } + mpz_cdiv_qr (q, r, n, d); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -868,15 +1153,32 @@ SPEX_info SPEX_mpz_divexact const mpz_t z ) { - SPEX_GMPZ_WRAPPER_START (x) ; - if (mpz_sgn(z) == 0) + SPEX_GMPZ_WRAPPER_START (x); + if (mpz_sgn (z) == 0) { - SPEX_GMP_WRAPPER_FINISH; - return SPEX_PANIC; + SPEX_GMP_WRAPPER_FINISH ; + return (SPEX_PANIC); } - mpz_divexact (x, y, z) ; + + #ifdef SPEX_DEBUG + mpq_t r ; + mpq_init (r); // r = 0/1 + mpz_fdiv_r (SPEX_MPQ_NUM (r), y, z); + if (mpz_sgn (SPEX_MPQ_NUM (r)) != 0) + { + mpq_set_den (r, z); + mpq_canonicalize (r); + gmp_printf ("not exact division! remainder=%Qd\n", r); + mpq_clear (r); + SPEX_GMP_WRAPPER_FINISH ; + return (SPEX_PANIC); + } + mpq_clear (r); + #endif + + mpz_divexact (x, y, z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -892,10 +1194,10 @@ SPEX_info SPEX_mpz_gcd const mpz_t z ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_gcd (x, y, z) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_gcd (x, y, z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -911,10 +1213,28 @@ SPEX_info SPEX_mpz_lcm const mpz_t y ) { - SPEX_GMPZ_WRAPPER_START (lcm) ; - mpz_lcm (lcm, x, y) ; + SPEX_GMPZ_WRAPPER_START (lcm); + mpz_lcm (lcm, x, y); + SPEX_GMP_WRAPPER_FINISH ; + return (SPEX_OK); +} + +//------------------------------------------------------------------------------ +// SPEX_mpz_neg +//------------------------------------------------------------------------------ + +/* Purpose: Safely set x = -y */ + +SPEX_info SPEX_mpz_neg +( + mpz_t x, + const mpz_t y +) +{ + SPEX_GMPZ_WRAPPER_START (x); + mpz_neg (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -929,10 +1249,10 @@ SPEX_info SPEX_mpz_abs const mpz_t y ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpz_abs (x, y) ; + SPEX_GMPZ_WRAPPER_START (x); + mpz_abs (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -950,9 +1270,9 @@ SPEX_info SPEX_mpz_cmp ) { SPEX_GMP_WRAPPER_START ; - *r = mpz_cmp (x, y) ; + *r = mpz_cmp (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -970,9 +1290,9 @@ SPEX_info SPEX_mpz_cmpabs ) { SPEX_GMP_WRAPPER_START ; - *r = mpz_cmpabs (x, y) ; + *r = mpz_cmpabs (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -989,11 +1309,12 @@ SPEX_info SPEX_mpz_cmp_ui ) { SPEX_GMP_WRAPPER_START ; - *r = mpz_cmp_ui (x, (unsigned long int) y) ; + *r = mpz_cmp_ui (x, (unsigned long int) y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } + //------------------------------------------------------------------------------ // SPEX_mpz_sgn //------------------------------------------------------------------------------ @@ -1007,9 +1328,9 @@ SPEX_info SPEX_mpz_sgn ) { SPEX_GMP_WRAPPER_START ; - *sgn = mpz_sgn (x) ; + *sgn = mpz_sgn (x); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1026,9 +1347,9 @@ SPEX_info SPEX_mpz_sizeinbase ) { SPEX_GMP_WRAPPER_START ; - *size = mpz_sizeinbase (x, (int) base) ; + *size = mpz_sizeinbase (x, (int) base); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1048,10 +1369,10 @@ SPEX_info SPEX_mpq_init mpq_t x ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_init (x) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_init (x); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1066,10 +1387,10 @@ SPEX_info SPEX_mpq_set const mpq_t y ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_set (x, y) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_set (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1084,10 +1405,10 @@ SPEX_info SPEX_mpq_set_z const mpz_t y ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_set_z (x, y) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_set_z (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1102,10 +1423,10 @@ SPEX_info SPEX_mpq_set_d const double y ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_set_d (x, y) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_set_d (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1123,10 +1444,10 @@ SPEX_info SPEX_mpq_set_ui const uint64_t z ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_set_ui (x, (unsigned long int) y, (unsigned long int) z) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_set_ui (x, (unsigned long int) y, (unsigned long int) z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1145,7 +1466,7 @@ SPEX_info SPEX_mpq_set_si SPEX_GMPQ_WRAPPER_START (x) ; mpq_set_si (x, (signed long int) y, (unsigned long int) z) ; SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1160,10 +1481,10 @@ SPEX_info SPEX_mpq_set_num const mpz_t y ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_set_num (x, y) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_set_num (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1178,16 +1499,19 @@ SPEX_info SPEX_mpq_set_den const mpz_t y ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_set_den (x, y) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_set_den (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ // SPEX_mpq_get_den //------------------------------------------------------------------------------ +#if 0 +/* This function is currently unused, but kept here for future reference. */ + /* Purpose: Safely set an mpz number = denominator of an mpq number */ SPEX_info SPEX_mpq_get_den @@ -1196,11 +1520,12 @@ SPEX_info SPEX_mpq_get_den const mpq_t y ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpq_get_den (x, y) ; + SPEX_GMPZ_WRAPPER_START (x); + mpq_get_den (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } +#endif //------------------------------------------------------------------------------ // SPEX_mpq_get_d @@ -1215,9 +1540,50 @@ SPEX_info SPEX_mpq_get_d ) { SPEX_GMP_WRAPPER_START ; - *x = mpq_get_d (y) ; + *x = mpq_get_d (y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); +} + +//------------------------------------------------------------------------------ +// SPEX_mpq_swap +//------------------------------------------------------------------------------ + +#if 0 +/* This function is currently unused, but kept here for future reference. */ + +/* Purpose: Safely swap the values x and y efficiently */ + +SPEX_info SPEX_mpq_swap +( + mpq_t x, + mpq_t y +) +{ + SPEX_GMP_WRAPPER_START ; + mpq_swap (x, y); + SPEX_GMP_WRAPPER_FINISH ; + return (SPEX_OK); +} + +#endif + +//------------------------------------------------------------------------------ +// SPEX_mpq_neg +//------------------------------------------------------------------------------ + +/* Purpose: Safely set an mpq number x = -y */ + +SPEX_info SPEX_mpq_neg +( + mpq_t x, + const mpq_t y +) +{ + SPEX_GMPQ_WRAPPER_START (x); + mpq_neg (x, y); + SPEX_GMP_WRAPPER_FINISH ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1232,10 +1598,10 @@ SPEX_info SPEX_mpq_abs const mpq_t y ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_abs (x, y) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_abs (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1251,10 +1617,10 @@ SPEX_info SPEX_mpq_add const mpq_t z ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_add (x, y, z) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_add (x, y, z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1269,10 +1635,10 @@ SPEX_info SPEX_mpq_mul const mpq_t z ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_mul (x, y, z) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_mul (x, y, z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1288,10 +1654,10 @@ SPEX_info SPEX_mpq_div const mpq_t z ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpq_div (x, y, z) ; + SPEX_GMPQ_WRAPPER_START (x); + mpq_div (x, y, z); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1309,9 +1675,9 @@ SPEX_info SPEX_mpq_cmp ) { SPEX_GMP_WRAPPER_START ; - *r = mpq_cmp (x, y) ; + *r = mpq_cmp (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1330,11 +1696,36 @@ SPEX_info SPEX_mpq_cmp_ui ) { SPEX_GMP_WRAPPER_START ; - *r = mpq_cmp_ui (x, (unsigned long int) num, (unsigned long int) den) ; + *r = mpq_cmp_ui (x, (unsigned long int) num, (unsigned long int) den); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } +//------------------------------------------------------------------------------ +// SPEX_mpq_cmp_z +//------------------------------------------------------------------------------ + +#if 0 +/* This function is currently unused, but kept here for future reference. */ + +/* Purpose: Safely check if a mpq number equals to a mpz number, + * r = 0 (r = false) if x != y, r < 0 if x < y, or r > 0 if x > y */ + +SPEX_info SPEX_mpq_cmp_z +( + int *r, + const mpq_t x, + const mpz_t y +) +{ + SPEX_GMP_WRAPPER_START ; + *r = mpq_cmp_z (x, y); + SPEX_GMP_WRAPPER_FINISH ; + return (SPEX_OK); +} + +#endif + //------------------------------------------------------------------------------ // SPEX_mpq_equal //------------------------------------------------------------------------------ @@ -1350,9 +1741,9 @@ SPEX_info SPEX_mpq_equal ) { SPEX_GMP_WRAPPER_START ; - *r = mpq_equal (x, y) ; + *r = mpq_equal (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1368,9 +1759,9 @@ SPEX_info SPEX_mpq_sgn ) { SPEX_GMP_WRAPPER_START ; - *sgn = mpq_sgn (x) ; + *sgn = mpq_sgn (x); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1388,13 +1779,17 @@ SPEX_info SPEX_mpq_sgn SPEX_info SPEX_mpfr_init2 ( mpfr_t x, // Floating point number to initialize - uint64_t size // # of bits in x + const uint64_t size // # of bits in x ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_init2 (x, (unsigned long int) size) ; + // ensure the mpfr number is not too big + if (size > MPFR_PREC_MAX/2) return (SPEX_PANIC); + + // initialize the mpfr number + SPEX_GMPFR_WRAPPER_START (x); + mpfr_init2 (x, (mpfr_prec_t) size); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1410,10 +1805,10 @@ SPEX_info SPEX_mpfr_set const mpfr_rnd_t rnd ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_set (x, y, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_set (x, y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1429,10 +1824,10 @@ SPEX_info SPEX_mpfr_set_d const mpfr_rnd_t rnd // MPFR rounding scheme used ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_set_d (x, y, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_set_d (x, y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } @@ -1449,10 +1844,10 @@ SPEX_info SPEX_mpfr_set_si const mpfr_rnd_t rnd // MPFR rounding scheme used ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_set_si (x, y, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_set_si (x, (long int) y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1468,10 +1863,10 @@ SPEX_info SPEX_mpfr_set_q const mpfr_rnd_t rnd ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_set_q (x, y, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_set_q (x, y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1487,10 +1882,10 @@ SPEX_info SPEX_mpfr_set_z const mpfr_rnd_t rnd ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_set_z (x, y, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_set_z (x, y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1506,10 +1901,10 @@ SPEX_info SPEX_mpfr_get_z const mpfr_rnd_t rnd // MPFR rounding scheme used ) { - SPEX_GMPZ_WRAPPER_START (x) ; - mpfr_get_z (x, y, rnd) ; + SPEX_GMPZ_WRAPPER_START (x); + mpfr_get_z (x, y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1525,10 +1920,10 @@ SPEX_info SPEX_mpfr_get_q const mpfr_rnd_t rnd // MPFR rounding scheme used ) { - SPEX_GMPQ_WRAPPER_START (x) ; - mpfr_get_q (x, y) ; + SPEX_GMPQ_WRAPPER_START (x); + mpfr_get_q (x, y); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1545,9 +1940,9 @@ SPEX_info SPEX_mpfr_get_d ) { SPEX_GMP_WRAPPER_START ; - *x = mpfr_get_d (y, rnd) ; + *x = mpfr_get_d (y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1564,9 +1959,9 @@ SPEX_info SPEX_mpfr_get_si ) { SPEX_GMP_WRAPPER_START ; - *x = mpfr_get_si (y, rnd) ; + *x = (int64_t) mpfr_get_si (y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1583,10 +1978,10 @@ SPEX_info SPEX_mpfr_mul const mpfr_rnd_t rnd // MPFR rounding mode ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_mul (x, y, z, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_mul (x, y, z, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1605,10 +2000,10 @@ SPEX_info SPEX_mpfr_mul_d const mpfr_rnd_t rnd // MPFR rounding scheme used ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_mul_d (x, y, z, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_mul_d (x, y, z, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1627,10 +2022,10 @@ SPEX_info SPEX_mpfr_div_d const mpfr_rnd_t rnd // MPFR rounding scheme used ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_div_d (x, y, z, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_div_d (x, y, z, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1649,10 +2044,10 @@ SPEX_info SPEX_mpfr_ui_pow_ui const mpfr_rnd_t rnd // MPFR rounding mode ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_ui_pow_ui (x, (unsigned long int) y, (unsigned long int) z, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_ui_pow_ui (x, (unsigned long int) y, (unsigned long int) z, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1671,10 +2066,10 @@ SPEX_info SPEX_mpfr_log2 const mpfr_rnd_t rnd ) { - SPEX_GMPFR_WRAPPER_START (x) ; - mpfr_log2 (x, y, rnd) ; + SPEX_GMPFR_WRAPPER_START (x); + mpfr_log2 (x, y, rnd); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } #endif @@ -1692,9 +2087,9 @@ SPEX_info SPEX_mpfr_sgn ) { SPEX_GMP_WRAPPER_START ; - *sgn = mpfr_sgn (x) ; + *sgn = mpfr_sgn (x); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } //------------------------------------------------------------------------------ @@ -1706,8 +2101,8 @@ SPEX_info SPEX_mpfr_sgn SPEX_info SPEX_mpfr_free_cache ( void ) { SPEX_GMP_WRAPPER_START ; - mpfr_free_cache ( ) ; + mpfr_free_cache ( ); SPEX_GMP_WRAPPER_FINISH ; - return (SPEX_OK) ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Utilities/Source/SPEX_initialize.c b/SPEX/SPEX_Utilities/Source/SPEX_initialize.c new file mode 100644 index 0000000000..424802b4d2 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_initialize.c @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_initialize: initialize SPEX +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// SPEX_initialize initializes the working evironment for SPEX + +#include "spex_util_internal.h" + +//------------------------------------------------------------------------------ +// global variable access +//------------------------------------------------------------------------------ + +// a global variable, but only accessible within this file. + +bool spex_initialize_has_been_called ; +bool spex_initialize_has_been_called = false; + +bool spex_initialized ( void ) +{ + return (spex_initialize_has_been_called); +} + +void spex_set_initialized (bool s) +{ + spex_initialize_has_been_called = s; +} + +//------------------------------------------------------------------------------ +// SPEX_initialize +//------------------------------------------------------------------------------ + +SPEX_info SPEX_initialize ( void ) +{ + if (spex_initialized( )) return (SPEX_PANIC); + + // SPEX requires GMP to support bit counts that are 64-bit integers + if (sizeof (mp_bitcnt_t) < sizeof (uint64_t)) return (SPEX_PANIC); + + // tell GMP and MPFR which memory allocation functions to use + mp_set_memory_functions + ( + spex_gmp_allocate, // malloc function + spex_gmp_reallocate, // realloc function + spex_gmp_free // free function + ); + + // initialize the SPEX GMP interface for the primary thread + SPEX_info info = spex_gmp_initialize (1) ; + if (info == SPEX_OK) + { + spex_set_initialized (true); + } + return (info) ; +} + diff --git a/SPEX/SPEX_Util/Source/SPEX_initialize_expert.c b/SPEX/SPEX_Utilities/Source/SPEX_initialize_expert.c similarity index 51% rename from SPEX/SPEX_Util/Source/SPEX_initialize_expert.c rename to SPEX/SPEX_Utilities/Source/SPEX_initialize_expert.c index 2d783f2f44..5d1d7e58b3 100644 --- a/SPEX/SPEX_Util/Source/SPEX_initialize_expert.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_initialize_expert.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_initialize_expert: intialize SPEX memory functions for GMP +// SPEX_Utilities/SPEX_initialize_expert: intialize SPEX memory functions for GMP //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -16,37 +17,37 @@ // That is: // #include -// void *malloc (size_t size) ; -// void *calloc (size_t nmemb, size_t size) ; -// void *realloc (void *ptr, size_t size) ; -// void free (void *ptr) ; +// void *malloc (size_t size); +// void *calloc (size_t nmemb, size_t size); +// void *realloc (void *ptr, size_t size); +// void free (void *ptr); #include "spex_util_internal.h" SPEX_info SPEX_initialize_expert ( - void* (*user_malloc) (size_t), // user-defined malloc - void* (*user_calloc) (size_t, size_t), // user-defined calloc - void* (*user_realloc) (void *, size_t), // user-defined realloc - void (*user_free) (void *) // user-defined free + void *(*MyMalloc) (size_t), // user-defined malloc + void *(*MyCalloc) (size_t, size_t), // user-defined calloc + void *(*MyRealloc) (void *, size_t), // user-defined realloc + void (*MyFree) (void *) // user-defined free ) { - if (spex_initialized ( )) return (SPEX_PANIC) ; + if (spex_initialized ( )) return (SPEX_PANIC); //-------------------------------------------------------------------------- - // define the malloc/calloc/realloc/free functions + // define the malloc/calloc/realloc/free functions //-------------------------------------------------------------------------- - SuiteSparse_config_malloc_func_set (user_malloc) ; - SuiteSparse_config_calloc_func_set (user_calloc) ; - SuiteSparse_config_realloc_func_set (user_realloc) ; - SuiteSparse_config_free_func_set (user_free) ; + SuiteSparse_config_malloc_func_set (MyMalloc); + SuiteSparse_config_calloc_func_set (MyCalloc); + SuiteSparse_config_realloc_func_set (MyRealloc); + SuiteSparse_config_free_func_set (MyFree); //-------------------------------------------------------------------------- // Set GMP memory functions //-------------------------------------------------------------------------- - return (SPEX_initialize ( )) ; + return (SPEX_initialize ( )); } diff --git a/SPEX/SPEX_Util/Source/SPEX_malloc.c b/SPEX/SPEX_Utilities/Source/SPEX_malloc.c similarity index 62% rename from SPEX/SPEX_Util/Source/SPEX_malloc.c rename to SPEX/SPEX_Utilities/Source/SPEX_malloc.c index 69dafd7ef4..422a138f61 100644 --- a/SPEX/SPEX_Util/Source/SPEX_malloc.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_malloc.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_malloc: wrapper for malloc +// SPEX_Utilities/SPEX_malloc: wrapper for malloc //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -17,7 +18,7 @@ void *SPEX_malloc size_t size // size of memory space to allocate ) { - if (!spex_initialized ( )) return (NULL) ; - return (SuiteSparse_malloc (1, size)) ; + + return (SuiteSparse_malloc (1, size)); } diff --git a/SPEX/SPEX_Util/Source/SPEX_matrix_allocate.c b/SPEX/SPEX_Utilities/Source/SPEX_matrix_allocate.c similarity index 67% rename from SPEX/SPEX_Util/Source/SPEX_matrix_allocate.c rename to SPEX/SPEX_Utilities/Source/SPEX_matrix_allocate.c index eaf97f30e8..52da8ab0d2 100644 --- a/SPEX/SPEX_Util/Source/SPEX_matrix_allocate.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_matrix_allocate.c @@ -1,23 +1,31 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_matrix_allocate: allocate a SPEX_matrix +// SPEX_Utilities/SPEX_matrix_allocate: allocate a SPEX_matrix //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ -// Allocate an m-by-n SPEX_matrix, in one of 15 data structures: +// Allocate an m-by-n SPEX_matrix, in either dynamic_CSC x mpz or one of +// 15 data structures: // (sparse CSC, sparse triplet, or dense) x -// (mpz, mpz, mfpr, int64, or double). +// (mpz, mpq, mfpr, int64, or double). -// The matrix may be created as 'shallow', in which case A->p, A->i, A->j, and -// A->x are all returned as NULL, and all A->*_shallow flags are returned as -// true. +// If the matrix is not dynamic_CSC, then it may be created as 'shallow', in +// which case A->p, A->i, A->j, and A->x are all returned as NULL, and all +// A->*_shallow flags are returned as true. -#define SPEX_FREE_ALL \ - SPEX_matrix_free (&A, option) ; +// If the matrix is dynamic_CSC, each column of the returned matrix will be +// allocated as SPEX_vector with zero available entry. Additional reallocation +// for each column will be needed. + +#define SPEX_FREE_ALL \ +{ \ + SPEX_matrix_free (&A, option); \ +} #include "spex_util_internal.h" @@ -32,8 +40,8 @@ SPEX_info SPEX_matrix_allocate ( - SPEX_matrix **A_handle, // matrix to allocate - SPEX_kind kind, // CSC, triplet, or dense + SPEX_matrix *A_handle, // matrix to allocate + SPEX_kind kind, // CSC, triplet, dense, dynamic_CSC SPEX_type type, // mpz, mpq, mpfr, int64, or double int64_t m, // # of rows int64_t n, // # of columns @@ -42,14 +50,14 @@ SPEX_info SPEX_matrix_allocate bool shallow, // if true, matrix is shallow. A->p, A->i, A->j, // A->x are all returned as NULL and must be set // by the caller. All A->*_shallow are returned - // as true. + // as true. Ignored if kind is dynamic_CSC. bool init, // If true, and the data types are mpz, mpq, or // mpfr, the entries are initialized (using the // appropriate SPEX_mp*_init function). If false, // the mpz, mpq, and mpfr arrays are malloced but // not initialized. Utilized internally to reduce // memory. Ignored if shallow is true. - const SPEX_options *option + const SPEX_options option ) { @@ -58,36 +66,35 @@ SPEX_info SPEX_matrix_allocate //-------------------------------------------------------------------------- SPEX_info info ; - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!spex_initialized ( )) return (SPEX_PANIC); if (A_handle == NULL) { - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } (*A_handle) = NULL ; if (m < 0 || n < 0 || kind < SPEX_CSC || kind > SPEX_DENSE || - type < SPEX_MPZ || type > SPEX_FP64) - + type < SPEX_MPZ || type > SPEX_FP64) { - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } //-------------------------------------------------------------------------- // allocate the header //-------------------------------------------------------------------------- - SPEX_matrix *A = (SPEX_matrix *) SPEX_calloc (1, sizeof (SPEX_matrix)) ; + SPEX_matrix A = (SPEX_matrix) SPEX_calloc (1, sizeof (SPEX_matrix_struct)); if (A == NULL) { - return (SPEX_OUT_OF_MEMORY) ; + return (SPEX_OUT_OF_MEMORY); } if (kind == SPEX_DENSE) { nzmax = m*n ; } - nzmax = SPEX_MAX (nzmax, 1) ; + nzmax = SPEX_MAX (nzmax, 1); A->m = m ; A->n = n ; @@ -103,15 +110,14 @@ SPEX_info SPEX_matrix_allocate A->x_shallow = false ; // A->scale = 1 - SPEX_MPQ_SET_NULL (A->scale) ; - SPEX_CHECK (SPEX_mpq_init (A->scale)) ; - SPEX_CHECK (SPEX_mpq_set_ui (A->scale, 1, 1)) ; + SPEX_CHECK (spex_create_mpq (A->scale)); + SPEX_MPQ_SET_UI (A->scale, 1, 1); //-------------------------------------------------------------------------- // allocate the p, i, j, and x components //-------------------------------------------------------------------------- - if (shallow) + if(shallow) { // all components are shallow. The caller can modify individual @@ -131,20 +137,19 @@ SPEX_info SPEX_matrix_allocate switch (kind) { case SPEX_CSC: - A->p = (int64_t *) SPEX_calloc (n+1, sizeof (int64_t)) ; - A->i = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)) ; - ok = (A->p != NULL && A->i != NULL) ; + A->p = (int64_t *) SPEX_calloc (n+1, sizeof (int64_t)); + A->i = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)); + ok = (A->p != NULL && A->i != NULL); break ; case SPEX_TRIPLET: - A->i = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)) ; - A->j = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)) ; - ok = (A->i != NULL && A->j != NULL) ; + A->i = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)); + A->j = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)); + ok = (A->i != NULL && A->j != NULL); break ; - case SPEX_DENSE: - // nothing to do - break ; + default: //SPEX_DENSE or SPEX_DYNAMIC_CSC + ;// nothing to do } @@ -157,44 +162,56 @@ SPEX_info SPEX_matrix_allocate // allocate the array but do not allocate the individual // mpz, mpq, or mpfr if (init) - A->x.mpz = spex_create_mpz_array (nzmax) ; + { + A->x.mpz = spex_create_mpz_array (nzmax); + } else + { A->x.mpz = SPEX_calloc(nzmax, sizeof(mpz_t)); - ok = ok && (A->x.mpz != NULL) ; + } + ok = ok && (A->x.mpz != NULL); break ; case SPEX_MPQ: if (init) - A->x.mpq = spex_create_mpq_array (nzmax) ; + { + A->x.mpq = spex_create_mpq_array (nzmax); + } else + { A->x.mpq = SPEX_calloc(nzmax, sizeof(mpq_t)); - ok = ok && (A->x.mpq != NULL) ; + } + ok = ok && (A->x.mpq != NULL); break ; case SPEX_MPFR: if (init) - A->x.mpfr = spex_create_mpfr_array (nzmax, option) ; + { + A->x.mpfr = spex_create_mpfr_array (nzmax, option); + } else + { A->x.mpfr = SPEX_calloc(nzmax, sizeof(mpfr_t)); - ok = ok && (A->x.mpfr != NULL) ; + } + ok = ok && (A->x.mpfr != NULL); break ; case SPEX_INT64: - A->x.int64 = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)) ; - ok = ok && (A->x.int64 != NULL) ; + A->x.int64 = (int64_t *) SPEX_calloc (nzmax, sizeof (int64_t)); + ok = ok && (A->x.int64 != NULL); break ; case SPEX_FP64: - A->x.fp64 = (double *) SPEX_calloc (nzmax, sizeof (double)) ; - ok = ok && (A->x.fp64 != NULL) ; + A->x.fp64 = (double *) SPEX_calloc (nzmax, sizeof (double)); + ok = ok && (A->x.fp64 != NULL); break ; } if (!ok) { - SPEX_FREE_ALL ; - return (SPEX_OUT_OF_MEMORY) ; + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); } } @@ -203,6 +220,6 @@ SPEX_info SPEX_matrix_allocate //-------------------------------------------------------------------------- (*A_handle) = A ; - return (SPEX_OK) ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Util/Source/SPEX_matrix_check.c b/SPEX/SPEX_Utilities/Source/SPEX_matrix_check.c similarity index 72% rename from SPEX/SPEX_Util/Source/SPEX_matrix_check.c rename to SPEX/SPEX_Utilities/Source/SPEX_matrix_check.c index 0c1108be96..a1c5da5342 100644 --- a/SPEX/SPEX_Util/Source/SPEX_matrix_check.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_matrix_check.c @@ -1,15 +1,18 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_matrix_check: check if a matrix is OK +// SPEX_Utilities/SPEX_matrix_check: check if a matrix is OK //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ #define SPEX_FREE_ALL \ - SPEX_FREE (work) ; + SPEX_FREE (work); \ + SPEX_MPZ_CLEAR(q); \ + SPEX_MPZ_CLEAR(r); #include "spex_util_internal.h" @@ -18,11 +21,11 @@ lines++ ; \ if (pr == 2 && lines > 30) \ { \ - SPEX_PRINTF (" ...\n") ; \ + SPEX_PRINTF (" ...\n"); \ pr = 1 ; \ } -int compar (const void *x, const void *y) ; +int compar (const void *x, const void *y); int compar (const void *x, const void *y) { @@ -31,23 +34,23 @@ int compar (const void *x, const void *y) int64_t *b = (int64_t *) y ; if (a [0] < b [0]) { - return (-1) ; + return (-1); } else if (a [0] > b [0]) { - return (1) ; + return (1); } else if (a [1] < b [1]) { - return (-1) ; + return (-1); } else if (a [1] > b [1]) { - return (1) ; + return (1); } else { - return (0) ; + return (0); } } @@ -61,12 +64,12 @@ int compar (const void *x, const void *y) SPEX_info SPEX_matrix_check // returns a SPEX status code ( - const SPEX_matrix *A, // matrix to check - const SPEX_options* option + const SPEX_matrix A, // matrix to check + const SPEX_options option ) { - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!spex_initialized ( )) return (SPEX_PANIC); //-------------------------------------------------------------------------- // check the dimensions @@ -74,7 +77,7 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code SPEX_info status = 0 ; char * buff = NULL ; - int pr = SPEX_OPTION_PRINT_LEVEL (option) ; + int pr = SPEX_OPTION_PRINT_LEVEL (option); int64_t nz; // Number of nonzeros in A status = SPEX_matrix_nnz(&nz, A, option); if (status != SPEX_OK) {return status;} @@ -85,18 +88,18 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (m < 0) { - SPEX_PR1 ("m invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("m invalid\n"); + return (SPEX_INCORRECT_INPUT); } if (n < 0) { - SPEX_PR1 ("n invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("n invalid\n"); + return (SPEX_INCORRECT_INPUT); } if (nzmax < 0) { - SPEX_PR1 ("nzmax invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("nzmax invalid\n"); + return (SPEX_INCORRECT_INPUT); } //-------------------------------------------------------------------------- @@ -106,24 +109,27 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (A->type < SPEX_MPZ || A->type > SPEX_FP64) // A->kind < SPEX_CSC || A->kind > SPEX_DENSE // checked in SPEX_matrix_nnz { - SPEX_PR1 ("A has invalid type.\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("A has invalid type.\n"); + return (SPEX_INCORRECT_INPUT); } SPEX_PR2 ("SPEX_matrix: nrows: %"PRId64", ncols: %"PRId64", nz:" - "%"PRId64", nzmax: %"PRId64", kind: %s, type: %s\n", m, n, nz, - nzmax, A->kind < 1 ? "CSC" : A->kind < 2 ? "Triplet" : "Dense", + "%"PRId64", nzmax: %"PRId64", kind: %s, type: %s\n", m, n, nz, nzmax, + A->kind < 1 ? "CSC" : A->kind < 2 ? "Triplet" : + "Dense", A->type < 1 ? "MPZ" : A->type < 2 ? "MPQ" : A->type < 3 ? - "MPFR" : A->type < 4 ? "int64" : "double") ; + "MPFR" : A->type < 4 ? "int64" : "double"); if (pr >= 2) { - SPEX_PR2 ("scale factor: ") ; - status = SPEX_mpfr_asprintf (&buff,"%Qd\n", A->scale) ; + SPEX_PR2 ("scale factor: "); + // use mpfr_asprintf so that we can use SPEX_PR*, which + // employs either printf or mexprintf + status = SPEX_mpfr_asprintf (&buff,"%Qd\n", A->scale); if (status >= 0) { - SPEX_PR2 ("%s", buff) ; - SPEX_mpfr_free_str (buff) ; + SPEX_PR2 ("%s", buff); + SPEX_mpfr_free_str (buff); } } @@ -132,8 +138,13 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code //-------------------------------------------------------------------------- int64_t i, j, p, pend ; - int64_t* work = NULL; // used for checking duplicates for CSC and triplet + int64_t *work = NULL; // used for checking duplicates for CSC and triplet uint64_t prec = SPEX_OPTION_PREC (option); + // paranoia: check prec here: cast to mprf_prec_t, and back, assert + // equality, if not equal then return SPEX_PANIC + mpz_t q, r; + SPEX_MPZ_SET_NULL(q); + SPEX_MPZ_SET_NULL(r); int64_t lines = 0 ; // # of lines printed so far @@ -150,8 +161,8 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code case SPEX_CSC: { - int64_t* Ap = A->p; - int64_t* Ai = A->i; + int64_t *Ap = A->p; + int64_t *Ai = A->i; //------------------------------------------------------------------ // check the column pointers @@ -160,8 +171,8 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (nzmax > 0 && (Ap == NULL || Ap [0] != 0)) { // column pointers invalid - SPEX_PR1 ("p invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("p invalid\n"); + return (SPEX_INCORRECT_INPUT); } for (j = 0 ; j < n ; j++) { @@ -170,8 +181,8 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (pend < p || pend > nz) { // column pointers not monotonically non-decreasing - SPEX_PR1 ("p invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("p invalid\n"); + return (SPEX_INCORRECT_INPUT); } } @@ -182,24 +193,24 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (nzmax > 0 && (Ai == NULL || SPEX_X(A) == NULL)) { // row indices or values not present - SPEX_PR1 ("i or x invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("i or x invalid\n"); + return (SPEX_INCORRECT_INPUT); } // allocate workspace to check for duplicates - work = (int64_t *) SPEX_calloc (m, sizeof (int64_t)) ; + work = (int64_t *) SPEX_calloc (m, sizeof (int64_t)); if (work == NULL) { // out of memory - SPEX_PR1 ("out of memory\n") ; + SPEX_PR1 ("out of memory\n"); SPEX_FREE_ALL; - return (SPEX_OUT_OF_MEMORY) ; + return (SPEX_OUT_OF_MEMORY); } for (j = 0 ; j < n ; j++) // iterate across columns { SPEX_PR_LIMIT ; - SPEX_PR2 ("column %"PRId64" :\n", j) ; + SPEX_PR2 ("column %"PRId64" :\n", j); int64_t marked = j+1 ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { @@ -207,26 +218,29 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (i < 0 || i >= m) { // row indices out of range - SPEX_PR1 ("index out of range: (%ld,%ld)\n", i, j) ; - SPEX_FREE_ALL ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("index out of range: (%ld,%ld)\n", i, j); + SPEX_FREE_ALL; + return (SPEX_INCORRECT_INPUT); } else if (work [i] == marked) { // duplicate - SPEX_PR1 ("duplicate index: (%ld,%ld)\n", i, j) ; - SPEX_FREE_ALL ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("duplicate index: (%ld,%ld)\n", i, j); + SPEX_FREE_ALL; + return (SPEX_INCORRECT_INPUT); } if (pr >= 2) { SPEX_PR_LIMIT ; - SPEX_PR2 (" row %"PRId64" : ", i) ; + SPEX_PR2 (" row %"PRId64" : ", i); switch ( A->type) { case SPEX_MPZ: { + // use mpfr_asprintf so that we can use + // SPEX_PR*, which employs either printf or + // mexprintf status = SPEX_mpfr_asprintf(&buff, "%Zd \n", A->x.mpz[p]); if (status >= 0) @@ -251,7 +265,7 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code { status = SPEX_mpfr_asprintf(&buff, "%.*Rf \n", prec, A->x.mpfr [p]); - if (status >= 0) + if (status >= 0) { SPEX_PR2("%s", buff); SPEX_mpfr_free_str (buff); @@ -271,9 +285,9 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code } if (status < 0) { - SPEX_FREE_ALL ; - SPEX_PRINTF (" error: %d\n", status) ; - return (status) ; + SPEX_FREE_ALL; + SPEX_PRINTF (" error: %d\n", status); + return (status); } } work [i] = marked ; @@ -289,8 +303,8 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code case SPEX_TRIPLET: { - int64_t* Aj = A->j; - int64_t* Ai = A->i; + int64_t *Aj = A->j; + int64_t *Ai = A->i; //------------------------------------------------------------------ // basic pointer checking @@ -299,8 +313,8 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (nzmax > 0 && (Ai == NULL || Aj == NULL || SPEX_X(A) == NULL)) { // row indices or values not present - SPEX_PR1 ("i or j or x invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("i or j or x invalid\n"); + return (SPEX_INCORRECT_INPUT); } //------------------------------------------------------------------ @@ -311,25 +325,21 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code { i = Ai[p]; j = Aj[p]; - if (i < 0 || i >= m || j < 0 || j >= n) - { - // row indices out of range - SPEX_PR1 ("invalid index\n") ; - SPEX_FREE_ALL ; - return (SPEX_INCORRECT_INPUT) ; - } + if (pr >= 2) { SPEX_PR_LIMIT ; - SPEX_PR2 (" %"PRId64" %"PRId64" : ", i, j) ; + SPEX_PR2 (" %"PRId64" %"PRId64" : ", i, j); switch ( A->type) { case SPEX_MPZ: { + // use mpfr_asprintf so that we can use SPEX_PR*, + // which employs either printf or mexprintf status = SPEX_mpfr_asprintf(&buff, "%Zd \n", A->x.mpz [p]); - if (status >= 0) + if (status >= 0) { SPEX_PR2("%s", buff); SPEX_mpfr_free_str (buff); @@ -340,10 +350,10 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code { status = SPEX_mpfr_asprintf (&buff,"%Qd \n", A->x.mpq [p]); - if (status >= 0) - { - SPEX_PR2("%s", buff); - SPEX_mpfr_free_str (buff); + if (status >= 0) + { + SPEX_PR2("%s", buff); + SPEX_mpfr_free_str (buff); } break; } @@ -351,10 +361,10 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code { status = SPEX_mpfr_asprintf(&buff, "%.*Rf \n", prec, A->x.mpfr [p]); - if (status >= 0) - { - SPEX_PR2("%s", buff); - SPEX_mpfr_free_str (buff); + if (status >= 0) + { + SPEX_PR2("%s", buff); + SPEX_mpfr_free_str (buff); } break; } @@ -371,11 +381,19 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code } if (status < 0) { - SPEX_FREE_ALL ; - SPEX_PRINTF (" error: %d\n", status) ; - return (status) ; + SPEX_FREE_ALL; + SPEX_PRINTF (" error: %d\n", status); + return (status); } } + + if (i < 0 || i >= m || j < 0 || j >= n) + { + // row indices out of range + SPEX_PR1 ("invalid index\n"); + SPEX_FREE_ALL; + return (SPEX_INCORRECT_INPUT); + } } //------------------------------------------------------------------ @@ -383,13 +401,13 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code //------------------------------------------------------------------ // allocate workspace to check for duplicates - work = (int64_t *) SPEX_malloc (nz * 2 * sizeof (int64_t)) ; + work = (int64_t *) SPEX_malloc (nz * 2 * sizeof (int64_t)); if (work == NULL) { // out of memory - SPEX_PR1 ("out of memory\n") ; + SPEX_PR1 ("out of memory\n"); SPEX_FREE_ALL; - return (SPEX_OUT_OF_MEMORY) ; + return (SPEX_OUT_OF_MEMORY); } // load the (i,j) indices of the triplets into the workspace @@ -400,7 +418,7 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code } // sort the (i,j) indices - qsort (work, nz, 2 * sizeof (int64_t), compar) ; + qsort (work, nz, 2 * sizeof (int64_t), compar); // check for duplicates for (p = 1 ; p < nz ; p++) @@ -411,9 +429,9 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code int64_t last_i = work [2*(p-1)+1] ; if (this_j == last_j && this_i == last_i) { - SPEX_PR1 ("duplicate index: (%ld, %ld)\n", this_i, this_j) ; - SPEX_FREE_ALL ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("duplicate index: (%ld, %ld)\n", this_i, this_j); + SPEX_FREE_ALL; + return (SPEX_INCORRECT_INPUT); } } @@ -433,8 +451,8 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code if (nzmax > 0 && SPEX_X(A) == NULL) { // row indices or values not present - SPEX_PR1 ("x invalid\n") ; - return (SPEX_INCORRECT_INPUT) ; + SPEX_PR1 ("x invalid\n"); + return (SPEX_INCORRECT_INPUT); } //------------------------------------------------------------------ @@ -444,24 +462,27 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code for (j = 0 ; j < n ; j++) { SPEX_PR_LIMIT ; - SPEX_PR2 ("column %"PRId64" :\n", j) ; + SPEX_PR2 ("column %"PRId64" :\n", j); for (i = 0; i < m; i++) { if (pr >= 2) { SPEX_PR_LIMIT ; - SPEX_PR2 (" row %"PRId64" : ", i) ; + SPEX_PR2 (" row %"PRId64" : ", i); switch ( A->type) { case SPEX_MPZ: { + // use mpfr_asprintf so that we can use + // SPEX_PR*, which employs either printf or + // mexprintf status = SPEX_mpfr_asprintf (&buff, "%Zd \n" , - SPEX_2D(A, i, j, mpz)) ; - if (status >= 0) - { - SPEX_PR2("%s", buff); - SPEX_mpfr_free_str (buff); + SPEX_2D(A, i, j, mpz)); + if (status >= 0) + { + SPEX_PR2("%s", buff); + SPEX_mpfr_free_str (buff); } break; } @@ -469,10 +490,10 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code { status = SPEX_mpfr_asprintf (&buff, "%Qd \n", SPEX_2D(A, i, j, mpq)); - if (status >= 0) - { - SPEX_PR2("%s", buff); - SPEX_mpfr_free_str (buff); + if (status >= 0) + { + SPEX_PR2("%s", buff); + SPEX_mpfr_free_str (buff); } break; } @@ -480,10 +501,10 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code { status = SPEX_mpfr_asprintf (&buff, "%.*Rf \n", prec, SPEX_2D(A, i, j, mpfr)); - if (status >= 0) - { - SPEX_PR2("%s", buff); - SPEX_mpfr_free_str (buff); + if (status >= 0) + { + SPEX_PR2("%s", buff); + SPEX_mpfr_free_str (buff); } break; } @@ -500,21 +521,23 @@ SPEX_info SPEX_matrix_check // returns a SPEX status code } if (status < 0) { - SPEX_PR2 (" error: %d\n", status) ; - return (status) ; + SPEX_PR2 (" error: %d\n", status); + return (status); } } } } } break; + + } //-------------------------------------------------------------------------- // free workspace and return result //-------------------------------------------------------------------------- - SPEX_FREE_ALL ; - return (SPEX_OK) ; + SPEX_FREE_ALL; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Util/Source/SPEX_matrix_copy.c b/SPEX/SPEX_Utilities/Source/SPEX_matrix_copy.c similarity index 79% rename from SPEX/SPEX_Util/Source/SPEX_matrix_copy.c rename to SPEX/SPEX_Utilities/Source/SPEX_matrix_copy.c index 5c98c14ed9..efb5fafe75 100644 --- a/SPEX/SPEX_Util/Source/SPEX_matrix_copy.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_matrix_copy.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_matrix_copy: create a copy of a matrix +// SPEX_Utilities/SPEX_matrix_copy: create a copy of a matrix //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -16,56 +17,61 @@ // SPEX_matrix_check, if desired. If the input matrix A is not valid, results // are undefined. -#define SPEX_FREE_WORK \ - SPEX_matrix_free (&T, option) ; \ - SPEX_matrix_free (&Y, option) ; \ - SPEX_FREE (W) ; +// SPEX supports 16 matrix formats: 15 of them are all combinations of +// (CSC, triplet, dense) x (mpz, mpq, mpfr, int64, double). +// This function can convert an input +// matrix A in any of these 16 formats, into an output matrix C in any of the +// 16 supported formats. -#define SPEX_FREE_ALL \ - SPEX_FREE_WORK ; \ - SPEX_matrix_free (&C, option) ; +#define SPEX_FREE_WORK \ + SPEX_matrix_free(&T, option); \ + SPEX_matrix_free(&Y, option); \ + SPEX_FREE(W); + +#define SPEX_FREE_ALL \ + SPEX_FREE_WORK; \ + SPEX_matrix_free(&C, option); #include "spex_util_internal.h" SPEX_info SPEX_matrix_copy ( - SPEX_matrix **C_handle, // matrix to create (never shallow) + SPEX_matrix *C_handle, // matrix to create (never shallow) // inputs, not modified: - SPEX_kind C_kind, // C->kind: CSC, triplet, or dense + SPEX_kind C_kind, // C->kind: CSC, triplet, dense SPEX_type C_type, // C->type: mpz_t, mpq_t, mpfr_t, int64_t, or double - SPEX_matrix *A, // matrix to make a copy of (may be shallow) - const SPEX_options *option + const SPEX_matrix A, // matrix to make a copy of (may be shallow) + const SPEX_options option ) { //-------------------------------------------------------------------------- // check inputs //-------------------------------------------------------------------------- - SPEX_info info ; - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!spex_initialized ( )) return (SPEX_PANIC); int64_t nz; - SPEX_matrix *C = NULL ; - SPEX_matrix *Y = NULL ; - SPEX_matrix *T = NULL ; + SPEX_matrix C = NULL ; + SPEX_matrix Y = NULL ; + SPEX_matrix T = NULL ; int64_t *W = NULL ; - SPEX_CHECK (SPEX_matrix_nnz (&nz, A, option)) ; + SPEX_CHECK (SPEX_matrix_nnz (&nz, A, option)); ASSERT( nz >= 0); if (C_handle == NULL || nz < 0 || - //checked in SPEX_matrix_nnz - //A == NULL || A->kind < SPEX_CSC || A->kind > SPEX_DENSE || + // checked in SPEX_matrix_nnz: + //A == NULL || A->kind < SPEX_CSC A->type < SPEX_MPZ || A->type > SPEX_FP64 || C_kind < SPEX_CSC || C_kind > SPEX_DENSE || - C_type < SPEX_MPZ || C_type > SPEX_FP64) + C_type < SPEX_MPZ || C_type > SPEX_FP64 ) { - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } (*C_handle) = NULL ; int64_t m = A->m ; int64_t n = A->n ; - mpfr_rnd_t round = SPEX_OPTION_ROUND (option) ; + mpfr_rnd_t round = SPEX_OPTION_ROUND (option); //-------------------------------------------------------------------------- // copy and convert A into C @@ -92,13 +98,13 @@ SPEX_info SPEX_matrix_copy { // allocate C SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_CSC, C_type, - m, n, nz, false, true, option)) ; + m, n, nz, false, true, option)); // copy the pattern of A into C - memcpy (C->p, A->p, (n+1) * sizeof (int64_t)) ; - memcpy (C->i, A->i, nz * sizeof (int64_t)) ; + memcpy (C->p, A->p, (n+1) * sizeof (int64_t)); + memcpy (C->i, A->i, nz * sizeof (int64_t)); // copy and typecast A->x into C->x SPEX_CHECK (spex_cast_array (SPEX_X (C), C->type, - SPEX_X (A), A->type, nz, C->scale, A->scale, option)) ; + SPEX_X (A), A->type, nz, C->scale, A->scale, option)); } break ; @@ -111,24 +117,24 @@ SPEX_info SPEX_matrix_copy // Y = typecast the values of A into the type of C // (not the pattern; Y is SPEX_DENSE) - SPEX_CHECK (spex_cast_matrix (&Y, C_type, A, option)) ; + SPEX_CHECK (spex_cast_matrix (&Y, C_type, A, option)); // allocate workspace - W = (int64_t *) SPEX_calloc (n, sizeof (int64_t)) ; + W = (int64_t *) SPEX_calloc (n, sizeof (int64_t)); if (W == NULL) { - SPEX_FREE_ALL ; - return (SPEX_OUT_OF_MEMORY) ; + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); } // allocate C SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_CSC, - C_type, m, n, nz, false, true, option)) ; + C_type, m, n, nz, false, true, option)); // Scaling factor of C is currently in Y, set it // here SPEX_mpq_set(C->scale, Y->scale); - + // count the # of entries in each column for (int64_t k = 0 ; k < nz ; k++) { @@ -136,7 +142,7 @@ SPEX_info SPEX_matrix_copy } // C->p = cumulative sum of W - SPEX_cumsum (C->p, W, n) ; + spex_cumsum (C->p, W, n); // build the matrix switch (C->type) @@ -146,9 +152,9 @@ SPEX_info SPEX_matrix_copy { int64_t p = W [A->j [k]]++ ; C->i [p] = A->i [k] ; - SPEX_CHECK (SPEX_mpz_set ( + SPEX_MPZ_SET ( SPEX_1D (C, p, mpz), - SPEX_1D (Y, k, mpz))) ; + SPEX_1D (Y, k, mpz)); } break ; @@ -157,9 +163,9 @@ SPEX_info SPEX_matrix_copy { int64_t p = W [A->j [k]]++ ; C->i [p] = A->i [k] ; - SPEX_CHECK (SPEX_mpq_set ( + SPEX_MPQ_SET ( SPEX_1D (C, p, mpq), - SPEX_1D (Y, k, mpq))) ; + SPEX_1D (Y, k, mpq)); } break ; @@ -168,10 +174,10 @@ SPEX_info SPEX_matrix_copy { int64_t p = W [A->j [k]]++ ; C->i [p] = A->i [k] ; - SPEX_CHECK (SPEX_mpfr_set ( + SPEX_MPFR_SET ( SPEX_1D (C, p, mpfr), SPEX_1D (Y, k, mpfr), - round)) ; + round); } break ; @@ -181,7 +187,7 @@ SPEX_info SPEX_matrix_copy int64_t p = W [A->j [k]]++ ; C->i [p] = A->i [k] ; SPEX_1D (C, p, int64) = - SPEX_1D (Y, k, int64) ; + SPEX_1D (Y, k, int64); } break ; @@ -191,7 +197,7 @@ SPEX_info SPEX_matrix_copy int64_t p = W [A->j [k]]++ ; C->i [p] = A->i [k] ; SPEX_1D (C, p, fp64) = - SPEX_1D (Y, k, fp64) ; + SPEX_1D (Y, k, fp64); } break ; @@ -207,7 +213,7 @@ SPEX_info SPEX_matrix_copy case SPEX_DENSE: { // Y = typecast the values of A into the type of C - SPEX_CHECK (spex_cast_matrix (&Y, C_type, A, option)) ; + SPEX_CHECK( spex_cast_matrix(&Y, C_type, A, option) ); int s ; // count the actual nonzeros in Y @@ -218,8 +224,8 @@ SPEX_info SPEX_matrix_copy case SPEX_MPZ: for (int64_t k = 0 ; k < nz ; k++) { - SPEX_CHECK (SPEX_mpz_sgn (&s, - SPEX_1D (Y, k, mpz))) ; + SPEX_MPZ_SGN (&s, + SPEX_1D (Y, k, mpz)); if (s != 0) actual++ ; } break ; @@ -227,8 +233,8 @@ SPEX_info SPEX_matrix_copy case SPEX_MPQ: for (int64_t k = 0 ; k < nz ; k++) { - SPEX_CHECK (SPEX_mpq_sgn (&s, - SPEX_1D (Y, k, mpq))) ; + SPEX_MPQ_SGN (&s, + SPEX_1D (Y, k, mpq)); if (s != 0) actual++ ; } break ; @@ -236,8 +242,8 @@ SPEX_info SPEX_matrix_copy case SPEX_MPFR: for (int64_t k = 0 ; k < nz ; k++) { - SPEX_CHECK (SPEX_mpfr_sgn (&s, - SPEX_1D (Y, k, mpfr))) ; + SPEX_MPFR_SGN (&s, + SPEX_1D (Y, k, mpfr)); if (s != 0) actual++ ; } break ; @@ -259,8 +265,8 @@ SPEX_info SPEX_matrix_copy } // allocate C SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_CSC, C_type, - m, n, actual, false, true, option)) ; - + m, n, actual, false, true, option)); + // C's scaling factor is currently in Y. Set it here SPEX_mpq_set(C->scale, Y->scale); @@ -275,12 +281,14 @@ SPEX_info SPEX_matrix_copy C->p [j] = nz ; for (int64_t i = 0 ; i < m ; i++) { - SPEX_CHECK( SPEX_mpz_sgn( &s, Y->x.mpz[ i + j*A->m])); + SPEX_MPZ_SGN(&s, + Y->x.mpz[ i + j*A->m]); if (s != 0) { C->i [nz] = i ; - SPEX_CHECK( SPEX_mpz_set ( SPEX_1D (C, nz, mpz), - Y->x.mpz[ i + j*A->m] )); + SPEX_MPZ_SET ( + SPEX_1D (C, nz, mpz), + Y->x.mpz[ i + j*A->m] ); nz++ ; } } @@ -293,14 +301,14 @@ SPEX_info SPEX_matrix_copy C->p [j] = nz ; for (int64_t i = 0 ; i < m ; i++) { - SPEX_CHECK (SPEX_mpq_sgn (&s, - Y->x.mpq[ i + j*A->m])) ; + SPEX_MPQ_SGN (&s, + Y->x.mpq[ i + j*A->m]); if (s != 0) { C->i [nz] = i ; - SPEX_CHECK(SPEX_mpq_set ( + SPEX_MPQ_SET ( SPEX_1D(C, nz, mpq), - Y->x.mpq[ i + j*A->m])); + Y->x.mpq[ i + j*A->m]); nz++ ; } } @@ -313,16 +321,16 @@ SPEX_info SPEX_matrix_copy C->p [j] = nz ; for (int64_t i = 0 ; i < m ; i++) { - SPEX_CHECK (SPEX_mpfr_sgn (&s, - Y->x.mpfr[i + j*A->m])) ; + SPEX_MPFR_SGN (&s, + Y->x.mpfr[i + j*A->m]); if (s != 0) { - C->i [nz] = i ; - SPEX_CHECK (SPEX_mpfr_set ( + C->i [nz] = i ; + SPEX_MPFR_SET ( SPEX_1D (C, nz, mpfr), Y->x.mpfr[i + j*A->m], - round)) ; - + round); + nz++ ; } } @@ -390,12 +398,12 @@ SPEX_info SPEX_matrix_copy { // allocate C SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_TRIPLET, C_type, - m, n, nz, false, true, option)) ; + m, n, nz, false, true, option)); // copy and typecast A->x into C->x SPEX_CHECK (spex_cast_array (SPEX_X (C), C->type, - SPEX_X (A), A->type, nz, C->scale, A->scale, option)) ; + SPEX_X (A), A->type, nz, C->scale, A->scale, option)); // copy the row indices A->i into C->i - memcpy (C->i, A->i, nz * sizeof (int64_t)) ; + memcpy (C->i, A->i, nz * sizeof (int64_t)); // construct C->j for (int64_t j = 0 ; j < n ; j++) { @@ -417,13 +425,13 @@ SPEX_info SPEX_matrix_copy { // allocate C SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_TRIPLET, C_type, - m, n, nz, false, true, option)) ; + m, n, nz, false, true, option)); // copy the pattern of A into C - memcpy (C->j, A->j, nz * sizeof (int64_t)) ; - memcpy (C->i, A->i, nz * sizeof (int64_t)) ; + memcpy (C->j, A->j, nz * sizeof (int64_t)); + memcpy (C->i, A->i, nz * sizeof (int64_t)); // copy and typecast A->x into C->x SPEX_CHECK (spex_cast_array (SPEX_X (C), C->type, - SPEX_X (A), A->type, nz, C->scale, A->scale, option)) ; + SPEX_X (A), A->type, nz, C->scale, A->scale, option)); // set C->nz C->nz = nz; } @@ -437,11 +445,11 @@ SPEX_info SPEX_matrix_copy { // convert A to a temporary CSC matrix SPEX_CHECK (SPEX_matrix_copy (&T, SPEX_CSC, C_type, - A, option)) ; + A, option)); // convert T from CSC to triplet SPEX_CHECK (SPEX_matrix_copy (&C, SPEX_TRIPLET, C_type, - T, option)) ; - SPEX_matrix_free (&T, option) ; + T, option)); + SPEX_matrix_free (&T, option); // set C->nz C->nz = nz; } @@ -459,10 +467,6 @@ SPEX_info SPEX_matrix_copy case SPEX_DENSE: { - // allocate C - SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_DENSE, C_type, - m, n, nz, false, true, option)) ; - switch (A->kind) { @@ -472,9 +476,13 @@ SPEX_info SPEX_matrix_copy case SPEX_CSC: { + // allocate C + SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_DENSE, C_type, + m, n, nz, false, true, option)); + // Y = typecast the values of A into the type of C - SPEX_CHECK (spex_cast_matrix (&Y, C->type, A, option)) ; - + SPEX_CHECK (spex_cast_matrix (&Y, C->type, A, option)); + // Set C's scaling factor SPEX_mpq_set(C->scale, Y->scale); @@ -487,9 +495,9 @@ SPEX_info SPEX_matrix_copy for (int64_t p = A->p [j] ; p < A->p [j+1] ;p++) { int64_t i = A->i [p] ; - SPEX_CHECK (SPEX_mpz_set ( + SPEX_MPZ_SET ( SPEX_2D (C, i, j, mpz), - SPEX_1D (Y, p, mpz))) ; + SPEX_1D (Y, p, mpz)); } } break ; @@ -500,9 +508,9 @@ SPEX_info SPEX_matrix_copy for (int64_t p = A->p [j] ; p < A->p [j+1] ;p++) { int64_t i = A->i [p] ; - SPEX_CHECK (SPEX_mpq_set ( + SPEX_MPQ_SET ( SPEX_2D (C, i, j, mpq), - SPEX_1D (Y, p, mpq))) ; + SPEX_1D (Y, p, mpq)); } } break ; @@ -513,10 +521,10 @@ SPEX_info SPEX_matrix_copy for (int64_t p = A->p [j] ; p < A->p [j+1] ;p++) { int64_t i = A->i [p] ; - SPEX_CHECK (SPEX_mpfr_set ( + SPEX_MPFR_SET ( SPEX_2D (C, i, j, mpfr), SPEX_1D (Y, p, mpfr), - round)) ; + round); } } break ; @@ -528,7 +536,7 @@ SPEX_info SPEX_matrix_copy { int64_t i = A->i [p] ; SPEX_2D (C, i, j, int64) = - SPEX_1D (Y, p, int64) ; + SPEX_1D (Y, p, int64); } } break ; @@ -540,7 +548,7 @@ SPEX_info SPEX_matrix_copy { int64_t i = A->i [p] ; SPEX_2D (C, i, j, fp64) = - SPEX_1D (Y, p, fp64) ; + SPEX_1D (Y, p, fp64); } } break ; @@ -556,8 +564,12 @@ SPEX_info SPEX_matrix_copy case SPEX_TRIPLET: { + // allocate C + SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_DENSE, C_type, + m, n, nz, false, true, option)); + // Y = typecast the values of A into the type of C - SPEX_CHECK (spex_cast_matrix (&Y, C->type, A, option)) ; + SPEX_CHECK (spex_cast_matrix (&Y, C->type, A, option)); // Set C's scaling factor SPEX_mpq_set(C->scale, Y->scale); @@ -569,9 +581,9 @@ SPEX_info SPEX_matrix_copy { int64_t i = A->i [k] ; int64_t j = A->j [k] ; - SPEX_CHECK (SPEX_mpz_set ( + SPEX_MPZ_SET ( SPEX_2D (C, i, j, mpz), - SPEX_1D (Y, k, mpz))) ; + SPEX_1D (Y, k, mpz)); } break ; @@ -580,9 +592,9 @@ SPEX_info SPEX_matrix_copy { int64_t i = A->i [k] ; int64_t j = A->j [k] ; - SPEX_CHECK (SPEX_mpq_set ( + SPEX_MPQ_SET ( SPEX_2D (C, i, j, mpq), - SPEX_1D (Y, k, mpq))) ; + SPEX_1D (Y, k, mpq)); } break ; @@ -591,10 +603,10 @@ SPEX_info SPEX_matrix_copy { int64_t i = A->i [k] ; int64_t j = A->j [k] ; - SPEX_CHECK (SPEX_mpfr_set ( + SPEX_MPFR_SET ( SPEX_2D (C, i, j, mpfr), SPEX_1D (Y, k, mpfr), - round)) ; + round); } break ; @@ -604,7 +616,7 @@ SPEX_info SPEX_matrix_copy int64_t i = A->i [k] ; int64_t j = A->j [k] ; SPEX_2D (C, i, j, int64) = - SPEX_1D (Y, k, int64) ; + SPEX_1D (Y, k, int64); } break ; @@ -614,7 +626,7 @@ SPEX_info SPEX_matrix_copy int64_t i = A->i [k] ; int64_t j = A->j [k] ; SPEX_2D (C, i, j, fp64) = - SPEX_1D (Y, k, fp64) ; + SPEX_1D (Y, k, fp64); } break ; @@ -628,9 +640,13 @@ SPEX_info SPEX_matrix_copy case SPEX_DENSE: { + // allocate C + SPEX_CHECK (SPEX_matrix_allocate (&C, SPEX_DENSE, C_type, + m, n, nz, false, true, option)); + // copy and typecast A->x into C->x SPEX_CHECK (spex_cast_array (SPEX_X (C), C->type, - SPEX_X (A), A->type, nz, C->scale, A->scale, option)) ; + SPEX_X (A), A->type, nz, C->scale, A->scale, option)); } break ; @@ -639,15 +655,16 @@ SPEX_info SPEX_matrix_copy } break ; + + } //-------------------------------------------------------------------------- // free workspace and return result //-------------------------------------------------------------------------- - SPEX_FREE_WORK ; - (*C_handle) = C ; - - return (SPEX_OK) ; + SPEX_FREE_WORK; + (*C_handle) = C; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Utilities/Source/SPEX_matrix_free.c b/SPEX/SPEX_Utilities/Source/SPEX_matrix_free.c new file mode 100644 index 0000000000..500ac8a2d0 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_matrix_free.c @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_matrix_free: free a SPEX_matrix +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// Free a SPEX_matrix. Any shallow component is not freed. +#if defined (__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif +#include "spex_util_internal.h" + +SPEX_info SPEX_matrix_free +( + SPEX_matrix *A_handle, // matrix to free + const SPEX_options option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + if (!spex_initialized ( )) { return (SPEX_PANIC); } ; + + if (A_handle == NULL || (*A_handle) == NULL) + { + // nothing to free (not an error) + return (SPEX_OK); + } + SPEX_matrix A = (*A_handle); + + //-------------------------------------------------------------------------- + // free any non-shallow components + //-------------------------------------------------------------------------- + + + // free the integer pattern + if (!(A->p_shallow)) SPEX_FREE (A->p); + if (!(A->i_shallow)) SPEX_FREE (A->i); + if (!(A->j_shallow)) SPEX_FREE (A->j); + + // free the values + if (!(A->x_shallow)) + { + switch (A->type) + { + case SPEX_MPZ: + if ( A->x.mpz != NULL) + { + for (int64_t i = 0; i < A->nzmax; i++) + { + SPEX_MPZ_CLEAR( A->x.mpz[i]); + } + } + SPEX_FREE (A->x.mpz); + break ; + + case SPEX_MPQ: + if ( A->x.mpq != NULL) + { + for (int64_t i = 0; i < A->nzmax; i++) + { + SPEX_MPQ_CLEAR( A->x.mpq[i]); + } + } + SPEX_FREE (A->x.mpq); + break ; + + case SPEX_MPFR: + if ( A->x.mpfr != NULL) + { + for (int64_t i = 0; i < A->nzmax; i++) + { + SPEX_MPFR_CLEAR( A->x.mpfr[i]); + } + } + SPEX_FREE (A->x.mpfr); + break ; + + case SPEX_INT64: + SPEX_FREE (A->x.int64); + break ; + + case SPEX_FP64: + SPEX_FREE (A->x.fp64); + break ; + + default: + // do nothing + break ; + } + } + + + // A->scale is never shallow + SPEX_MPQ_CLEAR (A->scale); + + //-------------------------------------------------------------------------- + // free the header + //-------------------------------------------------------------------------- + + // the header is never shallow + SPEX_FREE (A); + (*A_handle) = NULL ; + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Util/Source/SPEX_matrix_nnz.c b/SPEX/SPEX_Utilities/Source/SPEX_matrix_nnz.c similarity index 60% rename from SPEX/SPEX_Util/Source/SPEX_matrix_nnz.c rename to SPEX/SPEX_Utilities/Source/SPEX_matrix_nnz.c index dbb7a6040c..12ee7faca6 100644 --- a/SPEX/SPEX_Util/Source/SPEX_matrix_nnz.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_matrix_nnz.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_matrix_nnz: find # of entries in a matrix +// SPEX_Utilities/SPEX_matrix_nnz: find # of entries in a matrix //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -11,15 +12,13 @@ #if defined (__GNUC__) #pragma GCC diagnostic ignored "-Wunused-variable" #endif - #include "spex_util_internal.h" - -SPEX_info SPEX_matrix_nnz // find the # of entries in A +SPEX_info SPEX_matrix_nnz // find the # of entries in A ( - int64_t *nnz, // # of entries in A, -1 if A is NULL - const SPEX_matrix *A, // matrix to query - const SPEX_options *option // command options, currently unused + int64_t *nnz, // # of entries in A, -1 if A is NULL + const SPEX_matrix A, // matrix to query + const SPEX_options option // command options, currently unused ) { @@ -27,19 +26,25 @@ SPEX_info SPEX_matrix_nnz // find the # of entries in A // check inputs //-------------------------------------------------------------------------- - if (!spex_initialized ( )) return (SPEX_PANIC) ; + if (!spex_initialized ( )) return (SPEX_PANIC); + + if (nnz == NULL) + { + return (SPEX_INCORRECT_INPUT); + } + + (*nnz) = -1 ; if (A == NULL) { - *nnz = -1; - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } //-------------------------------------------------------------------------- // find nnz (A) //-------------------------------------------------------------------------- - // In all three cases, SPEX_matrix_nnz(&nnz, A, option) returns + // If kind != SPEX_DYNAMIC_CSC, SPEX_matrix_nnz(&nnz, A, option) returns // with nnz <= A->nzmax. switch (A->kind) @@ -61,13 +66,15 @@ SPEX_info SPEX_matrix_nnz // find the # of entries in A case SPEX_DENSE: { // dense matrices: nnz(A) is always m*n. A->nz is ignored. - *nnz = (A->m < 0 || A->n < 0)? (-1) : (A->m * A->n) ; + *nnz = (A->m < 0 || A->n < 0)? (-1) : (A->m * A->n); } break; + default: - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } - return ((*nnz < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK) ; + + return ((*nnz < 0) ? SPEX_INCORRECT_INPUT : SPEX_OK); } diff --git a/SPEX/SPEX_Util/Source/SPEX_realloc.c b/SPEX/SPEX_Utilities/Source/SPEX_realloc.c similarity index 76% rename from SPEX/SPEX_Util/Source/SPEX_realloc.c rename to SPEX/SPEX_Utilities/Source/SPEX_realloc.c index 70aaaf0036..b5e9ebcede 100644 --- a/SPEX/SPEX_Util/Source/SPEX_realloc.c +++ b/SPEX/SPEX_Utilities/Source/SPEX_realloc.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_realloc: wrapper for realloc +// SPEX_Utilities/SPEX_realloc: wrapper for realloc //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -25,14 +26,14 @@ // of size 10. // // int *p ; -// p = SPEX_malloc (10 * sizeof (int)) ; +// p = SPEX_malloc (10 * sizeof (int)); // if (p == NULL) { error here ... } -// printf ("p points to an array of size 10 * sizeof (int)\n") ; +// printf ("p points to an array of size 10 * sizeof (int)\n"); // bool ok ; -// p = SPEX_realloc (20, 10, sizeof (int), p, &ok) ; -// if (ok) printf ("p has size 20 * sizeof (int)\n") ; -// else printf ("realloc failed; p still has size 10 * sizeof (int)\n") ; -// SPEX_FREE (p) ; +// p = SPEX_realloc (20, 10, sizeof (int), p, &ok); +// if (ok) printf ("p has size 20 * sizeof (int)\n"); +// else printf ("realloc failed; p still has size 10 * sizeof (int)\n"); +// SPEX_FREE (p); void *SPEX_realloc // pointer to reallocated block, or original block // if the realloc failed @@ -44,16 +45,11 @@ void *SPEX_realloc // pointer to reallocated block, or original block bool *ok // true if success, false on failure ) { - if (!spex_initialized ( )) - { - (*ok) = false ; - return (p) ; - } int result ; void *pnew = SuiteSparse_realloc ((size_t) nitems_new, (size_t) nitems_old, - size_of_item, p, &result) ; - (*ok) = (result != 0) ; - return (pnew) ; + size_of_item, p, &result); + (*ok) = (result != 0); + return (pnew); } diff --git a/SPEX/SPEX_Utilities/Source/SPEX_symbolic_analysis_free.c b/SPEX/SPEX_Utilities/Source/SPEX_symbolic_analysis_free.c new file mode 100644 index 0000000000..7666123b80 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_symbolic_analysis_free.c @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_symbolic_analysis_free: Free memory for the +// SPEX_symbolic_analysis data type. +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function frees the memory of the SPEX_symbolic_analysis struct + * + * Input is the SPEX_symbolic_analysis structure, it is destroyed on function + * termination. + */ + +#include "spex_util_internal.h" + +SPEX_info SPEX_symbolic_analysis_free +( + SPEX_symbolic_analysis *S_handle, // Structure to be deleted + const SPEX_options option +) +{ + + if (!spex_initialized ( )) return (SPEX_PANIC); + + if ((S_handle != NULL) && (*S_handle != NULL)) + { + + SPEX_FREE((*S_handle)->P_perm); + SPEX_FREE((*S_handle)->Pinv_perm); + SPEX_FREE((*S_handle)->Q_perm); + SPEX_FREE((*S_handle)->Qinv_perm); + + SPEX_FREE((*S_handle)->parent); + SPEX_FREE((*S_handle)->cp); + SPEX_FREE (*S_handle); + } + + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Utilities/Source/SPEX_thread_finalize.c b/SPEX/SPEX_Utilities/Source/SPEX_thread_finalize.c new file mode 100644 index 0000000000..2e53c7a85e --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_thread_finalize.c @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_thread_finalize: finish SPEX for a single user thread +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// SPEX_thread_finalize frees the working evironment for SPEX for a +// single user thread. + +#include "spex_util_internal.h" + +SPEX_info SPEX_thread_finalize ( void ) +{ + if (!spex_initialized ( )) return (SPEX_PANIC); + spex_gmp_finalize (0); + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Utilities/Source/SPEX_thread_initialize.c b/SPEX/SPEX_Utilities/Source/SPEX_thread_initialize.c new file mode 100644 index 0000000000..67ab3bd2b5 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_thread_initialize.c @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_thread_initialize: init SPEX for a single user thread +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// SPEX_thread_initialize initializes the working evironment for SPEX for a +// single user thread. + +#include "spex_util_internal.h" + +SPEX_info SPEX_thread_initialize ( void ) +{ + if (!spex_initialized ( )) return (SPEX_PANIC); + return (spex_gmp_initialize (0)) ; +} + diff --git a/SPEX/SPEX_Utilities/Source/SPEX_transpose.c b/SPEX/SPEX_Utilities/Source/SPEX_transpose.c new file mode 100644 index 0000000000..177ee8c361 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_transpose.c @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_transpose: Transpose a CSC matrix +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_WORK \ + SPEX_FREE(w); + +#define SPEX_FREE_ALL \ + SPEX_FREE_WORK; \ + SPEX_matrix_free(&C, option); + +#include "spex_util_internal.h" + +/* Purpose: This function sets C = A', where A must be a SPEX_CSC matrix + * C_handle is NULL on input. On output, C_handle contains a pointer to A' + */ + +SPEX_info SPEX_transpose +( + SPEX_matrix *C_handle, // C = A' + SPEX_matrix A, // Matrix to be transposed + const SPEX_options option +) +{ + + SPEX_info info; + if (!spex_initialized ( )) return (SPEX_PANIC); + // Check input + SPEX_REQUIRE_KIND (A, SPEX_CSC); + if (!C_handle) { return SPEX_INCORRECT_INPUT;} + + // Declare workspace and C + int64_t *w = NULL; + SPEX_matrix C = NULL; + int64_t nz; // Number of nonzeros in A + int64_t p, q, j, n, m; + info = SPEX_matrix_nnz(&nz, A, option); + if (info != SPEX_OK) {return info;} + m = A->m ; n = A->n ; + ASSERT( m >= 0); + ASSERT( n >= 0); + + // C is also CSC and its type is the same as A + SPEX_CHECK(SPEX_matrix_allocate(&C, SPEX_CSC, A->type, n, m, nz, + false, true, option)); + + // Declare workspace + w = (int64_t*) SPEX_calloc(m, sizeof(int64_t)); + if (!w) + { + SPEX_FREE_ALL; + return SPEX_OUT_OF_MEMORY; + } + // Compute row counts + for (p = 0 ; p < nz ; p++) + { + w [A->i [p]]++ ; + } + + // Compute row pointers + spex_cumsum (C->p, w, m); + // Populate C + for (j = 0 ; j < n ; j++) + { + for (p = A->p [j] ; p < A->p [j+1] ; p++) + { + q = w [A->i [p]]++; + C->i [q] = j ; // place A(i,j) as entry C(j,i) + + // assign C->x[q] = A->x[p] + if (A->type == SPEX_MPZ) + { + SPEX_MPZ_SET(C->x.mpz[q], A->x.mpz[p]); + } + else if (A->type == SPEX_MPQ) + { + SPEX_MPQ_SET(C->x.mpq[q], A->x.mpq[p]); + } + else if (A->type == SPEX_MPFR) + { + SPEX_MPFR_SET(C->x.mpfr[q], A->x.mpfr[p], + SPEX_OPTION_ROUND(option)); + } + else if (A->type == SPEX_INT64) + { + C->x.int64[q] = A->x.int64[p]; + } + else + { + C->x.fp64[q] = A->x.fp64[p]; + } + } + } + SPEX_MPQ_SET(C->scale, A->scale); + + (*C_handle) = C; + SPEX_FREE_WORK; + return SPEX_OK; +} diff --git a/SPEX/SPEX_Utilities/Source/SPEX_version.c b/SPEX/SPEX_Utilities/Source/SPEX_version.c new file mode 100644 index 0000000000..de4c09d4a4 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/SPEX_version.c @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/SPEX_version: report SPEX version information +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// Returns the library version and date. + +#include "spex_util_internal.h" + +SPEX_info SPEX_version +( + // output + int version [3], // SPEX major, minor, and sub version + char date [128] // date of this version +) +{ + + if (version != NULL) + { + version [0] = SPEX_VERSION_MAJOR ; + version [1] = SPEX_VERSION_MINOR ; + version [2] = SPEX_VERSION_SUB ; + } + + if (date != NULL) + { + strncpy (date, SPEX_DATE, 127); + } + + return (SPEX_OK); +} + diff --git a/SPEX/SPEX_Utilities/Source/spex_amd.c b/SPEX/SPEX_Utilities/Source/spex_amd.c new file mode 100644 index 0000000000..7f41ab8949 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/spex_amd.c @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/spex_amd: Call AMD for matrix ordering +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +#define SPEX_FREE_ALL \ +{ \ + SPEX_free (perm); \ +} + +#include "spex_util_internal.h" + +/* Purpose: SPEX interface to AMD + */ + +SPEX_info spex_amd +( + int64_t **perm_handle, + int64_t *nnz, + const SPEX_matrix A, + const SPEX_options option +) +{ + + (*nnz) = 0 ; + (*perm_handle) = NULL ; + + int pr = SPEX_OPTION_PRINT_LEVEL(option); + int64_t n = A->n; + int64_t *perm = NULL ; + + // Allocate memory for permutation + perm = (int64_t*)SPEX_malloc( (n+1)*sizeof(int64_t) ); + if (perm == NULL) + { + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + + double Control[AMD_CONTROL]; // Declare AMD control + amd_l_defaults(Control); // Set AMD defaults + double Info [AMD_INFO]; + // Perform AMD + int64_t amd_result = amd_l_order(n, + (int64_t *)A->p, (int64_t *)A->i, + (int64_t *)perm, Control, Info); + if (pr > 0) // Output AMD info if desired + { + SPEX_PRINTF("\n****Ordering Information****\n"); + amd_l_control(Control); + amd_l_info(Info); + } + if (!(amd_result == AMD_OK || amd_result == AMD_OK_BUT_JUMBLED)) + { + // AMD failed: either out of memory, or bad input + SPEX_FREE_ALL; + if (amd_result == AMD_OUT_OF_MEMORY) + { + // AMD ran out of memory + return (SPEX_OUT_OF_MEMORY); + } + // input matrix is invalid + return (SPEX_INCORRECT_INPUT); + } + + (*nnz) = Info[AMD_LNZ]; // Exact number of nonzeros for Cholesky + (*perm_handle)=perm; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Util/Source/spex_cast_array.c b/SPEX/SPEX_Utilities/Source/spex_cast_array.c similarity index 79% rename from SPEX/SPEX_Util/Source/spex_cast_array.c rename to SPEX/SPEX_Utilities/Source/spex_cast_array.c index 5b436d6ca4..2f08588cac 100644 --- a/SPEX/SPEX_Util/Source/spex_cast_array.c +++ b/SPEX/SPEX_Utilities/Source/spex_cast_array.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_cast_array: scale and typecast an array +// SPEX_Utilities/spex_cast_array: scale and typecast an array //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -38,7 +39,6 @@ SPEX_MPQ_CLEAR(temp); \ #include "spex_util_internal.h" - #if defined (__GNUC__) #pragma GCC diagnostic ignored "-Wunused-variable" #endif @@ -51,8 +51,8 @@ SPEX_info spex_cast_array SPEX_type xtype, // type of X int64_t n, // size of Y and X mpq_t y_scale, // scale factor applied if Y is mpz_t - mpq_t x_scale, // scale factor applied if x is mpz_t - const SPEX_options *option// Command options. If NULL, set to default values + const mpq_t x_scale, // scale factor applied if x is mpz_t + const SPEX_options option // Command options. If NULL, use defaults ) { @@ -63,13 +63,13 @@ SPEX_info spex_cast_array if (Y == NULL || X == NULL) { - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } SPEX_info info ; int r; mpq_t temp; SPEX_MPQ_SET_NULL(temp); - mpfr_rnd_t round = SPEX_OPTION_ROUND (option) ; + mpfr_rnd_t round = SPEX_OPTION_ROUND (option); //-------------------------------------------------------------------------- // Y [0:n-1] = (ytype) X [0:n-1] @@ -95,10 +95,10 @@ SPEX_info spex_cast_array mpz_t *x = (mpz_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpz_set (y [k], x[k])) ; + SPEX_MPZ_SET (y [k], x[k]); } // y is a direct copy of x. Set y_scale = x_scale - SPEX_CHECK(SPEX_mpq_set(y_scale, x_scale)); + SPEX_MPQ_SET(y_scale, x_scale); } break ; @@ -113,7 +113,7 @@ SPEX_info spex_cast_array { mpfr_t *x = (mpfr_t *) X ; SPEX_CHECK (spex_expand_mpfr_array (Y, X, y_scale, n, - option)) ; + option)); } break ; @@ -122,9 +122,9 @@ SPEX_info spex_cast_array int64_t *x = (int64_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpz_set_si (y [k], x [k])) ; + SPEX_MPZ_SET_SI(y [k], x [k]); } - SPEX_CHECK (SPEX_mpq_set_ui (y_scale, 1, 1)) ; + SPEX_MPQ_SET_UI(y_scale, 1, 1); } break ; @@ -132,7 +132,7 @@ SPEX_info spex_cast_array { double *x = (double *) X ; SPEX_CHECK (spex_expand_double_array (y, x, y_scale, n, - option)) ; + option)); } break ; @@ -157,7 +157,7 @@ SPEX_info spex_cast_array // 1, each value in y is divided by x_scale // Check if x_scale == 1 - SPEX_CHECK(SPEX_mpq_cmp_ui(&r, x_scale, 1, 1)); + SPEX_MPQ_CMP_UI(&r, x_scale, 1, 1); mpz_t *x = (mpz_t *) X ; if (r == 0) @@ -165,7 +165,7 @@ SPEX_info spex_cast_array // x_scale = 1. Simply do a direct copy. for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpq_set_z (y [k], x [k])) ; + SPEX_MPQ_SET_Z(y [k], x [k]); } } else @@ -174,8 +174,8 @@ SPEX_info spex_cast_array // of Y by x_scale for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpq_set_z (y [k], x [k])) ; - SPEX_CHECK (SPEX_mpq_div(y[k], y[k], x_scale)); + SPEX_MPQ_SET_Z(y [k], x [k]); + SPEX_MPQ_DIV(y[k], y[k], x_scale); } } } @@ -186,7 +186,7 @@ SPEX_info spex_cast_array mpq_t *x = (mpq_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpq_set (y [k], x [k])) ; + SPEX_MPQ_SET (y [k], x [k]); } } break ; @@ -196,7 +196,7 @@ SPEX_info spex_cast_array mpfr_t *x = (mpfr_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpfr_get_q( y[k], x[k], round)); + SPEX_MPFR_GET_Q( y[k], x[k], round); } } break ; @@ -206,7 +206,7 @@ SPEX_info spex_cast_array int64_t *x = (int64_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpq_set_si (y [k], x [k], 1)) ; + SPEX_MPQ_SET_SI (y [k], x [k], 1); } } break ; @@ -216,7 +216,7 @@ SPEX_info spex_cast_array double *x = (double *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpq_set_d (y [k], x [k])) ; + SPEX_MPQ_SET_D (y [k], x [k]); } } break ; @@ -241,14 +241,14 @@ SPEX_info spex_cast_array // case, if the scaling factor of x is not equal to 1, the // values of y must be scaled. mpz_t *x = (mpz_t *) X ; - SPEX_CHECK(SPEX_mpq_cmp_ui(&r, x_scale, 1, 1)); + SPEX_MPQ_CMP_UI(&r, x_scale, 1, 1); if (r == 0) { // x_scale = 1. Simply do a direct copy. for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpfr_set_z (y [k], x [k], round)) ; + SPEX_MPFR_SET_Z(y [k], x [k], round); } } else @@ -257,12 +257,12 @@ SPEX_info spex_cast_array // of Y by x_scale. To do this, we will cast each // x_k to mpq_t, then divide by the scale, then // cast the result to mpfr_t - SPEX_CHECK(SPEX_mpq_init(temp)); + SPEX_MPQ_INIT(temp); for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK( SPEX_mpq_set_z( temp, x[k])); - SPEX_CHECK( SPEX_mpq_div(temp, temp, x_scale)); - SPEX_CHECK(SPEX_mpfr_set_q(y[k], temp, round)); + SPEX_MPQ_SET_Z( temp, x[k]); + SPEX_MPQ_DIV(temp, temp, x_scale); + SPEX_MPFR_SET_Q(y[k], temp, round); } } } @@ -273,7 +273,7 @@ SPEX_info spex_cast_array mpq_t *x = (mpq_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpfr_set_q (y [k], x [k], round)) ; + SPEX_MPFR_SET_Q(y [k], x [k], round); } } break ; @@ -283,7 +283,7 @@ SPEX_info spex_cast_array mpfr_t *x = (mpfr_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpfr_set (y [k], x [k], round)) ; + SPEX_MPFR_SET(y [k], x [k], round); } } break ; @@ -293,7 +293,7 @@ SPEX_info spex_cast_array int64_t *x = (int64_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK(SPEX_mpfr_set_si(y[k], x[k], round)); + SPEX_MPFR_SET_SI(y[k], x[k], round); } } break ; @@ -303,7 +303,7 @@ SPEX_info spex_cast_array double *x = (double *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpfr_set_d (y [k], x [k], round)) ; + SPEX_MPFR_SET_D(y [k], x [k], round); } } break ; @@ -327,14 +327,14 @@ SPEX_info spex_cast_array // x is mpz_t and y is int64_t. Same as above, // if x_scale > 1 it is applied mpz_t *x = (mpz_t *) X ; - SPEX_CHECK(SPEX_mpq_cmp_ui(&r, x_scale, 1, 1)); + SPEX_MPQ_CMP_UI(&r, x_scale, 1, 1); if (r == 0) { // x_scale = 1. Simply do a direct copy. for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK(SPEX_mpz_get_si( &(y[k]), x[k])); + SPEX_MPZ_GET_SI( &(y[k]), x[k]); } } else @@ -343,13 +343,13 @@ SPEX_info spex_cast_array // of Y by x_scale. To do this, we will cast each // x_k to mpq_t, then divide by the scale, then // cast the result to double and cast the double to int - SPEX_CHECK(SPEX_mpq_init(temp)); + SPEX_MPQ_INIT(temp); for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK( SPEX_mpq_set_z( temp, x[k])); - SPEX_CHECK( SPEX_mpq_div(temp, temp, x_scale)); + SPEX_MPQ_SET_Z( temp, x[k]); + SPEX_MPQ_DIV(temp, temp, x_scale); double temp2; - SPEX_CHECK(SPEX_mpq_get_d(&temp2, temp)); + SPEX_MPQ_GET_D(&temp2, temp); y[k] = spex_cast_double_to_int64(temp2); } } @@ -362,8 +362,8 @@ SPEX_info spex_cast_array for (int64_t k = 0 ; k < n ; k++) { double t ; - SPEX_CHECK (SPEX_mpq_get_d (&t, x [k])) ; - y [k] = spex_cast_double_to_int64 (t) ; + SPEX_MPQ_GET_D(&t, x [k]); + y [k] = spex_cast_double_to_int64 (t); } } break ; @@ -373,14 +373,14 @@ SPEX_info spex_cast_array mpfr_t *x = (mpfr_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK( SPEX_mpfr_get_si( &(y[k]),x[k], round)); + SPEX_MPFR_GET_SI( &(y[k]),x[k], round); } } break ; case SPEX_INT64: // int64_t to int64_t { - memcpy (Y, X, n * sizeof (int64_t)) ; + memcpy (Y, X, n * sizeof (int64_t)); } break ; @@ -389,7 +389,7 @@ SPEX_info spex_cast_array double *x = (double *) X ; for (int64_t k = 0 ; k < n ; k++) { - y [k] = spex_cast_double_to_int64 (x [k]) ; + y [k] = spex_cast_double_to_int64 (x [k]); } } break ; @@ -413,14 +413,14 @@ SPEX_info spex_cast_array // Same as above, x is mpz_t, y is double. Must // divide by x_scale if x_scale != 1. mpz_t *x = (mpz_t *) X ; - SPEX_CHECK(SPEX_mpq_cmp_ui(&r, x_scale, 1, 1)); + SPEX_MPQ_CMP_UI(&r, x_scale, 1, 1); if (r == 0) { // x_scale = 1. Simply do a direct copy. for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK(SPEX_mpz_get_d( &(y[k]), x[k])); + SPEX_MPZ_GET_D( &(y[k]), x[k]); } } else @@ -429,12 +429,12 @@ SPEX_info spex_cast_array // of Y by x_scale. To do this, we will cast each // x_k to mpq_t, then divide by the scale, then // cast the result to double - SPEX_CHECK(SPEX_mpq_init(temp)); + SPEX_MPQ_INIT(temp); for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK( SPEX_mpq_set_z( temp, x[k])); - SPEX_CHECK( SPEX_mpq_div(temp, temp, x_scale)); - SPEX_CHECK(SPEX_mpq_get_d(&(y[k]), temp)); + SPEX_MPQ_SET_Z(temp, x[k]); + SPEX_MPQ_DIV(temp, temp, x_scale); + SPEX_MPQ_GET_D(&(y[k]), temp); } } } @@ -445,7 +445,7 @@ SPEX_info spex_cast_array mpq_t *x = (mpq_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpq_get_d (&(y [k]), x [k])) ; + SPEX_MPQ_GET_D(&(y[k]), x[k]); } } break ; @@ -455,8 +455,7 @@ SPEX_info spex_cast_array mpfr_t *x = (mpfr_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - SPEX_CHECK (SPEX_mpfr_get_d (&(y [k]), x [k], - round)); + SPEX_MPFR_GET_D(&(y[k]), x[k], round); } } break ; @@ -466,14 +465,14 @@ SPEX_info spex_cast_array int64_t *x = (int64_t *) X ; for (int64_t k = 0 ; k < n ; k++) { - y [k] = (double) (x [k]) ; + y [k] = (double) (x[k]); } } break ; case SPEX_FP64: // double to double { - memcpy (Y, X, n * sizeof (double)) ; + memcpy (Y, X, n * sizeof (double)); } break ; @@ -482,6 +481,6 @@ SPEX_info spex_cast_array break ; } - SPEX_FREE_ALL - return (SPEX_OK) ; + SPEX_FREE_ALL; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Util/Source/spex_cast_matrix.c b/SPEX/SPEX_Utilities/Source/spex_cast_matrix.c similarity index 80% rename from SPEX/SPEX_Util/Source/spex_cast_matrix.c rename to SPEX/SPEX_Utilities/Source/spex_cast_matrix.c index 746b8a4f77..223971e2c0 100644 --- a/SPEX/SPEX_Util/Source/spex_cast_matrix.c +++ b/SPEX/SPEX_Utilities/Source/spex_cast_matrix.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_cast_matrix: create a dense typecasted matrix +// SPEX_Utilities/spex_cast_matrix: create a dense typecasted matrix //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -13,16 +14,16 @@ // kind (CSC, triplet, or dense) and any type. #define SPEX_FREE_ALL \ - SPEX_matrix_free (&Y, option) ; + SPEX_matrix_free (&Y, option); #include "spex_util_internal.h" SPEX_info spex_cast_matrix ( - SPEX_matrix **Y_handle, // nz-by-1 dense matrix to create + SPEX_matrix *Y_handle, // nz-by-1 dense matrix to create SPEX_type Y_type, // type of Y - SPEX_matrix *A, // matrix with nz entries - const SPEX_options *option // Command options, if NULL defaults are used + const SPEX_matrix A, // matrix with nz entries + const SPEX_options option // Command options, if NULL defaults are used ) { @@ -34,19 +35,19 @@ SPEX_info spex_cast_matrix #if 0 if (Y_handle == NULL || A == NULL) { - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } if (nz < 0) { - return (SPEX_INCORRECT_INPUT) ; + return (SPEX_INCORRECT_INPUT); } (*Y_handle) = NULL ; #endif int64_t nz; SPEX_info info = SPEX_OK ; - SPEX_matrix *Y = NULL ; - SPEX_CHECK (SPEX_matrix_nnz (&nz, A, option)) ; + SPEX_matrix Y = NULL ; + SPEX_CHECK (SPEX_matrix_nnz (&nz, A, option)); //-------------------------------------------------------------------------- @@ -54,7 +55,7 @@ SPEX_info spex_cast_matrix //-------------------------------------------------------------------------- SPEX_CHECK (SPEX_matrix_allocate (&Y, SPEX_DENSE, Y_type, - nz, 1, nz, Y_type == A->type, true, option)) ; + nz, 1, nz, Y_type == A->type, true, option)); //-------------------------------------------------------------------------- // typecast the values from A into Y @@ -90,7 +91,7 @@ SPEX_info spex_cast_matrix //---------------------------------------------------------------------- SPEX_CHECK (spex_cast_array (SPEX_X (Y), Y->type, - SPEX_X (A), A->type, nz, Y->scale, A->scale, option)) ; + SPEX_X (A), A->type, nz, Y->scale, A->scale, option)); } @@ -99,7 +100,7 @@ SPEX_info spex_cast_matrix //-------------------------------------------------------------------------- (*Y_handle) = Y; - SPEX_CHECK (info) ; - return (SPEX_OK) ; + SPEX_CHECK (info); + return (SPEX_OK); } diff --git a/SPEX/SPEX_Utilities/Source/spex_colamd.c b/SPEX/SPEX_Utilities/Source/spex_colamd.c new file mode 100644 index 0000000000..ff9cfb27f1 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/spex_colamd.c @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/spex_colamd: Call COLAMD for matrix ordering +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + + +#define SPEX_FREE_ALL \ +{ \ + SPEX_FREE (perm); \ + SPEX_FREE (A2); \ +} + +#include "spex_util_internal.h" + +/* Purpose: SPEX interface to COLAMD + */ + +SPEX_info spex_colamd +( + int64_t **perm_handle, + int64_t *nnz, + const SPEX_matrix A, + const SPEX_options option +) +{ + + SPEX_info info; + (*nnz) = 0 ; + (*perm_handle) = NULL ; + int64_t *A2 = NULL, *perm = NULL ; + + int64_t anz; // Number of nonzeros in A + SPEX_CHECK (SPEX_matrix_nnz(&anz, A, option)); + int64_t i, n = A->n; + + int pr = SPEX_OPTION_PRINT_LEVEL(option); + + // Allocate memory for permutation + perm = (int64_t*)SPEX_malloc( (n+1)*sizeof(int64_t) ); + if (perm == NULL) + { + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + + // determine workspace required for COLAMD + int64_t Alen = colamd_l_recommended (anz, n, n) + 2*n ; + A2 = (int64_t*) SPEX_malloc (Alen*sizeof(int64_t)); + if (!A2) + { + // out of memory + SPEX_FREE_ALL; + return (SPEX_OUT_OF_MEMORY); + } + + // Initialize S->p as per COLAMD documentation + for (i = 0; i < n+1; i++) + { + perm[i] = A->p[i]; + } + + // Initialize A2 per COLAMD documentation + for (i = 0; i < anz; i++) + { + A2[i] = A->i[i]; + } + + // find the colamd ordering + int64_t stats[COLAMD_STATS]; + int64_t colamd_result = colamd_l (n, n, Alen, A2, perm, + (double *) NULL, stats); + if (!colamd_result) + { + printf("fail\n"); + // COLAMD failed: matrix is invalid + SPEX_FREE_ALL; + return (SPEX_INCORRECT_INPUT); + } + + // very rough estimate for lnz and unz + (*nnz) = 10*anz; + + // Print stats if desired + if (pr > 0) + { + SPEX_PRINTF ("\n****Ordering Information****\n"); + colamd_l_report ((int64_t *) stats); + } + + // free workspace and return result + SPEX_FREE (A2); + (*perm_handle) = perm ; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Util/Source/spex_create_mpfr_array.c b/SPEX/SPEX_Utilities/Source/spex_create_mpfr_array.c similarity index 60% rename from SPEX/SPEX_Util/Source/spex_create_mpfr_array.c rename to SPEX/SPEX_Utilities/Source/spex_create_mpfr_array.c index 72ba801111..7b737460fe 100644 --- a/SPEX/SPEX_Util/Source/spex_create_mpfr_array.c +++ b/SPEX/SPEX_Utilities/Source/spex_create_mpfr_array.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_create_mpfr_array: create a dense mpfr array +// SPEX_Utilities/spex_create_mpfr_array: create a dense mpfr array //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -13,10 +14,10 @@ #include "spex_util_internal.h" -mpfr_t* spex_create_mpfr_array +mpfr_t *spex_create_mpfr_array ( - int64_t n, // size of the array - const SPEX_options *option // command options containing the prec for mpfr + int64_t n, // size of the array + const SPEX_options option // command options containing the prec for mpfr ) { @@ -25,23 +26,22 @@ mpfr_t* spex_create_mpfr_array //-------------------------------------------------------------------------- if (n <= 0) {return NULL;} - uint64_t prec = SPEX_OPTION_PREC (option) ; + uint64_t prec = SPEX_OPTION_PREC (option); + // paranoia: check prec here: cast to mprf_prec_t, and back, assert + // equality, if not equal then return SPEX_PANIC //-------------------------------------------------------------------------- - mpfr_t* x = (mpfr_t*) SPEX_calloc(n, sizeof(mpfr_t)); + mpfr_t *x = (mpfr_t*) SPEX_calloc(n, sizeof(mpfr_t)); if (!x) {return NULL;} for (int64_t i = 0; i < n; i++) { if (SPEX_mpfr_init2(x[i], prec) != SPEX_OK) { SPEX_MPFR_SET_NULL(x[i]); - for (int64_t j = 0; j < n; j++) + for (int64_t j = 0; j < i; j++) { - if ( x[j] != NULL) - { - SPEX_MPFR_CLEAR( x[j]); - } + SPEX_MPFR_CLEAR( x[j]); } SPEX_FREE(x); return NULL; diff --git a/SPEX/SPEX_Utilities/Source/spex_create_mpq.c b/SPEX/SPEX_Utilities/Source/spex_create_mpq.c new file mode 100644 index 0000000000..1571e204e2 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/spex_create_mpq.c @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/spex_create_mpq: create an mpq_t entry +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function safely creates and initializes an mpq_t entry. + */ + +// The SPEX_mpq_init function is wrapped in this method to avoid a spurious +// compiler warning in SPEX_MPQ_SET_NULL, about writing past the size of a +// variable. The warning arises when a high level of optimization is used. +// The warning cannot be supressed entirely because it would require a +// modifcation to GMP itself. + +#include "spex_util_internal.h" +SPEX_info spex_create_mpq +( + mpq_t x // mpq_t entry to be initialized +) +{ + + SPEX_info info = SPEX_mpq_init(x); + if (info != SPEX_OK) + { + // Out of memory + SPEX_MPQ_SET_NULL(x); + return info; + } + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Util/Source/spex_create_mpq_array.c b/SPEX/SPEX_Utilities/Source/spex_create_mpq_array.c similarity index 70% rename from SPEX/SPEX_Util/Source/spex_create_mpq_array.c rename to SPEX/SPEX_Utilities/Source/spex_create_mpq_array.c index 8e205f3cc3..4e28bc6944 100644 --- a/SPEX/SPEX_Util/Source/spex_create_mpq_array.c +++ b/SPEX/SPEX_Utilities/Source/spex_create_mpq_array.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_create_mpq_array: create a dense mpq array +// SPEX_Utilities/spex_create_mpq_array: create a dense mpq array //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -14,7 +15,7 @@ #include "spex_util_internal.h" -mpq_t* spex_create_mpq_array +mpq_t *spex_create_mpq_array ( int64_t n // size of the array ) @@ -28,8 +29,8 @@ mpq_t* spex_create_mpq_array //-------------------------------------------------------------------------- - // Malloc space - mpq_t* x = (mpq_t*) SPEX_calloc(n, sizeof(mpq_t)); + // calloc space + mpq_t *x = (mpq_t*) SPEX_calloc(n, sizeof(mpq_t)); if (!x) {return NULL;} for (int64_t i = 0; i < n; i++) { @@ -37,12 +38,9 @@ mpq_t* spex_create_mpq_array { // Out of memory SPEX_MPQ_SET_NULL(x[i]); - for (int64_t j = 0; j < n; j++) + for (int64_t j = 0; j < i; j++) { - if ( x[j] != NULL) - { - SPEX_MPQ_CLEAR( x[j]); - } + SPEX_MPQ_CLEAR( x[j]); } SPEX_FREE(x); return NULL; diff --git a/SPEX/SPEX_Util/Source/spex_create_mpz_array.c b/SPEX/SPEX_Utilities/Source/spex_create_mpz_array.c similarity index 56% rename from SPEX/SPEX_Util/Source/spex_create_mpz_array.c rename to SPEX/SPEX_Utilities/Source/spex_create_mpz_array.c index a61cede806..1e87b38724 100644 --- a/SPEX/SPEX_Util/Source/spex_create_mpz_array.c +++ b/SPEX/SPEX_Utilities/Source/spex_create_mpz_array.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_create_mpz_array: create a dense mpz array +// SPEX_Utilities/spex_create_mpz_array: create a dense mpz array //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -14,7 +15,7 @@ #include "spex_util_internal.h" -mpz_t* spex_create_mpz_array +mpz_t *spex_create_mpz_array ( int64_t n // size of the array ) @@ -29,15 +30,24 @@ mpz_t* spex_create_mpz_array //-------------------------------------------------------------------------- // Malloc space - mpz_t* x = (mpz_t*) SPEX_calloc(n, sizeof(mpz_t)); + mpz_t *x = (mpz_t*) SPEX_calloc(n, sizeof(mpz_t)); if (!x) {return NULL;} for (int64_t i = 0; i < n; i++) { - if (SPEX_mpz_init(x[i]) != SPEX_OK) + #if __GNU_MP_RELEASE < 60200 + SPEX_info info = + #endif + SPEX_mpz_init (x [i]); + #if __GNU_MP_RELEASE < 60200 + if (info != SPEX_OK) { - // Out of memory + // out of memory. NOTE: This can be triggered only when using GMP + // v6.1.2 or earlier versions. For GMP v6.2.0 or later versions, + // there is no memory allocation, and thus such failure will never + // occur. As a result, this code cannot be untested by the tests + // in SPEX/Tcov, when using GMP v6.2.0 or later. SPEX_MPZ_SET_NULL(x[i]); - for (int64_t j = 0; j < n; j++) + for (int64_t j = 0; j < i; j++) { if ( x[j] != NULL) { @@ -47,6 +57,7 @@ mpz_t* spex_create_mpz_array SPEX_FREE(x); return NULL; } + #endif } return x; } diff --git a/SPEX/SPEX_Util/Source/SPEX_cumsum.c b/SPEX/SPEX_Utilities/Source/spex_cumsum.c similarity index 73% rename from SPEX/SPEX_Util/Source/SPEX_cumsum.c rename to SPEX/SPEX_Utilities/Source/spex_cumsum.c index 72b4ff4b63..d7f8ccd887 100644 --- a/SPEX/SPEX_Util/Source/SPEX_cumsum.c +++ b/SPEX/SPEX_Utilities/Source/spex_cumsum.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_cumsum: cumulative sum +// SPEX_Utilities/spex_cumsum: cumulative sum //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -14,17 +15,18 @@ #include "spex_util_internal.h" -SPEX_info SPEX_cumsum +SPEX_info spex_cumsum ( int64_t *p, // vector to store the sum of c int64_t *c, // vector which is summed int64_t n // size of c ) { - if (!spex_initialized ( )) return (SPEX_PANIC) ; + + if (!spex_initialized ( )) return (SPEX_PANIC); if (!p || !c) return SPEX_INCORRECT_INPUT; - ASSERT(n >= 0); + ASSERT(n >= 0); int64_t i, nz = 0 ; for (i = 0 ; i < n ; i++) { diff --git a/SPEX/SPEX_Util/Source/spex_expand_double_array.c b/SPEX/SPEX_Utilities/Source/spex_expand_double_array.c similarity index 55% rename from SPEX/SPEX_Util/Source/spex_expand_double_array.c rename to SPEX/SPEX_Utilities/Source/spex_expand_double_array.c index a14306b926..ce6de0d8dc 100644 --- a/SPEX/SPEX_Util/Source/spex_expand_double_array.c +++ b/SPEX/SPEX_Utilities/Source/spex_expand_double_array.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_expand_double_array: convert double vector to mpz +// SPEX_Utilities/spex_expand_double_array: convert double vector to mpz //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -12,24 +13,26 @@ * mpz array of size n. To do this, the number is multiplied by an appropriate * power, then, the GCD is found. This function allows the use of matrices in * double precision to work with SPEX. - * */ -#define SPEX_FREE_ALL \ +#define SPEX_FREE_WORKSPACE \ SPEX_MPZ_CLEAR(gcd); \ SPEX_MPZ_CLEAR(one); \ SPEX_MPQ_CLEAR(temp); \ SPEX_matrix_free(&x3, NULL); \ +#define SPEX_FREE_ALL \ + SPEX_FREE_WORKSPACE \ + #include "spex_util_internal.h" SPEX_info spex_expand_double_array ( - mpz_t* x_out, // integral final array - double* x, // double array that needs to be made integral + mpz_t *x_out, // integral final array + double *x, // double array that needs to be made integral mpq_t scale, // the scaling factor used (x_out = scale * x) int64_t n, // size of x - const SPEX_options* option // Command options + const SPEX_options option // Command options ) { @@ -45,61 +48,72 @@ SPEX_info spex_expand_double_array int r1, r2 = 1; bool nz_found = false; SPEX_info info ; - // Machine epsilon is about 2e-16. We multiply by 10e16 to convert - // which is a slight overestimate to be safe but preserves the 16 decimal digits - // If more than 16 decimal digits are desired by the user, one should use the - // MPFR input which allows an arbitrary number of decimal digits. + + // Double precision accurate to about 2e-16. We multiply by 1e16 to convert + // Note that this conversion allows a number like 0.9 to be represented + // exactly fl(0.9) is not exact in double precision; in fact the exact + // conversion is fl(0.9) = 45000000000000001 / 50000000000000000. + // Multiplying by 1e16 gives the actual value of 9/10 when scaled. Note + // that if this type of conversion is not desired by the user it is + // suggested they first convert from double to MPFR then from MPFR to MPQ + // as that will be fully exact. + double expon = pow(10, 16); - // Quad precision in case input is huge - SPEX_matrix* x3 = NULL; + + // Convert the input x into a quad precision matrix. This is to handle the + // (rare) case that the user gives an input double which is close to + // DOUBLE_MAX. In that case the multiplication could lead to inf. + + SPEX_matrix x3 = NULL; mpz_t gcd, one; SPEX_MPZ_SET_NULL(gcd); SPEX_MPZ_SET_NULL(one); mpq_t temp; SPEX_MPQ_SET_NULL(temp); - mpfr_rnd_t round = SPEX_OPTION_ROUND (option) ; + mpfr_rnd_t round = SPEX_OPTION_ROUND (option); - SPEX_CHECK(SPEX_mpq_init(temp)); - SPEX_CHECK(SPEX_mpz_init(gcd)); - SPEX_CHECK(SPEX_mpz_init(one)); + SPEX_MPQ_INIT(temp); + SPEX_MPZ_INIT(gcd); + SPEX_MPZ_INIT(one); SPEX_CHECK (SPEX_matrix_allocate(&x3, SPEX_DENSE, SPEX_MPFR, n, 1, n, false, true, option)); - SPEX_CHECK(SPEX_mpq_set_d(scale, expon)); // scale = 10^16 + SPEX_MPQ_SET_D(scale, expon); // scale = 10^16 for (i = 0; i < n; i++) { - // Set x3[i] = x[i] - SPEX_CHECK(SPEX_mpfr_set_d(x3->x.mpfr[i], x[i], round)); + // x3[i] = x[i], cast double to MPFR + SPEX_MPFR_SET_D(x3->x.mpfr[i], x[i], round); - // x3[i] = x[i] * 10^16 - SPEX_CHECK(SPEX_mpfr_mul_d(x3->x.mpfr[i], x3->x.mpfr[i], expon, round)); + // x3[i] = x[i] * 10^16, multiply MPFR by 10^16 + SPEX_MPFR_MUL_D(x3->x.mpfr[i], x3->x.mpfr[i], expon, round); - // x_out[i] = x3[i] - SPEX_CHECK(SPEX_mpfr_get_z(x_out[i], x3->x.mpfr[i], round)); + // x_out[i] = x3[i], cast MPFR to integer truncating remaining decimal + // component + SPEX_MPFR_GET_Z(x_out[i], x3->x.mpfr[i], round); } //-------------------------------------------------------------------------- // Compute the GCD to reduce the size of scale //-------------------------------------------------------------------------- - SPEX_CHECK(SPEX_mpz_set_ui(one, 1)); + SPEX_MPZ_SET_UI(one, 1); // Find an initial GCD for (i = 0; i < n; i++) { if (!nz_found) { - SPEX_CHECK(SPEX_mpz_cmp_ui(&r1, x_out[i], 0)); // Check if x[i] == 0 + SPEX_MPZ_CMP_UI(&r1, x_out[i], 0); // Check if x[i] == 0 if (r1 != 0) { nz_found = true; k = i; - SPEX_CHECK(SPEX_mpz_set(gcd, x_out[i])); + SPEX_MPZ_SET(gcd, x_out[i]); } } else { // Compute the GCD, stop if gcd == 1 - SPEX_CHECK(SPEX_mpz_gcd(gcd, gcd, x_out[i])); - SPEX_CHECK(SPEX_mpz_cmp(&r2, gcd, one)); + SPEX_MPZ_GCD(gcd, gcd, x_out[i]); + SPEX_MPZ_CMP(&r2, gcd, one); if (r2 == 0) { break; @@ -122,12 +136,12 @@ SPEX_info spex_expand_double_array { for (i = k; i < n; i++) { - SPEX_CHECK(SPEX_mpz_divexact(x_out[i], x_out[i], gcd)); + SPEX_MPZ_DIVEXACT(x_out[i], x_out[i], gcd); } - SPEX_CHECK(SPEX_mpq_set_z(temp, gcd)); - SPEX_CHECK(SPEX_mpq_div(scale, scale, temp)); + SPEX_MPQ_SET_Z(temp, gcd); + SPEX_MPQ_DIV(scale, scale, temp); } - SPEX_FREE_ALL; + SPEX_FREE_WORKSPACE; return SPEX_OK; } diff --git a/SPEX/SPEX_Utilities/Source/spex_expand_mpfr_array.c b/SPEX/SPEX_Utilities/Source/spex_expand_mpfr_array.c new file mode 100644 index 0000000000..b3f06e2f9c --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/spex_expand_mpfr_array.c @@ -0,0 +1,135 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/spex_expand_mpfr_array: convert mpfr aray to mpz +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function converts a mpfr array of size n and precision prec to + * an appropriate mpz array of size n. To do this, the number is multiplied by + * the appropriate power of 10 then the gcd is found. This function allows mpfr + * arrays to be used within SPEX. + */ + +#define SPEX_FREE_ALL \ + SPEX_MPZ_CLEAR(gcd); \ + SPEX_MPZ_CLEAR(one); \ + SPEX_MPQ_CLEAR(temp); \ + if (x_mpq) \ + { \ + for (i = 0; i < n; i++) \ + { \ + if ( x_mpq[i] != NULL) \ + { \ + SPEX_MPQ_CLEAR(x_mpq[i]); \ + } \ + } \ + } \ + SPEX_FREE(x_mpq); + +#include "spex_util_internal.h" + +SPEX_info spex_expand_mpfr_array +( + mpz_t *x_out, // full precision mpz array + mpfr_t *x, // mpfr array to be expanded + mpq_t scale, // scaling factor used (x_out = scale*x) + int64_t n, // size of x + const SPEX_options option // command options containing the prec + // and rounding for mpfr +) +{ + + //-------------------------------------------------------------------------- + // Input has already been checked + //-------------------------------------------------------------------------- + ASSERT(n >= 0); + SPEX_info info ; + + //-------------------------------------------------------------------------- + // initializations + //-------------------------------------------------------------------------- + + int64_t i, k ; + int r1, r2 = 1 ; + bool nz_found = false; + mpz_t gcd, one; + mpq_t *x_mpq = NULL; + SPEX_MPZ_SET_NULL(gcd); + SPEX_MPZ_SET_NULL(one); + mpq_t temp; SPEX_MPQ_SET_NULL(temp); + + SPEX_MPQ_INIT(temp); + SPEX_MPZ_INIT(gcd); + SPEX_MPZ_INIT(one); + + x_mpq = spex_create_mpq_array (n); + if (x_mpq == NULL) + { + SPEX_FREE_ALL; + return SPEX_OUT_OF_MEMORY; + } + + SPEX_CHECK(spex_cast_array(x_mpq, SPEX_MPQ, x , SPEX_MPFR,n, NULL, NULL, + option)); + SPEX_CHECK(spex_cast_array(x_out, SPEX_MPZ, x_mpq, SPEX_MPQ, n, scale, NULL, + option)); + + //-------------------------------------------------------------------------- + // Find the gcd to reduce scale + //-------------------------------------------------------------------------- + + SPEX_MPZ_SET_UI(one, 1); + // Find an initial GCD + for (i = 0; i < n; i++) + { + if (!nz_found) + { + SPEX_MPZ_CMP_UI(&r1, x_out[i], 0); + if (r1 != 0) + { + nz_found = true; + k = i; + SPEX_MPZ_SET(gcd, x_out[i]); + } + } + else + { + // Compute the GCD of the numbers, stop if gcd == 1 + SPEX_MPZ_GCD(gcd, gcd, x_out[i]); + SPEX_MPZ_CMP(&r2, gcd, one); + if (r2 == 0) + { + break; + } + } + } + + if (!nz_found) // Array is all zeros + { + SPEX_mpq_set_z(scale, one); + SPEX_FREE_ALL; + return SPEX_OK; + } + + //-------------------------------------------------------------------------- + // Scale all entries to make as small as possible + //-------------------------------------------------------------------------- + + if (r2 != 0) // If gcd == 1 stop + { + for (i = k; i < n; i++) + { + SPEX_MPZ_DIVEXACT(x_out[i],x_out[i],gcd); + } + SPEX_MPQ_SET_Z(temp,gcd); + SPEX_MPQ_DIV(scale,scale,temp); + } + SPEX_FREE_ALL; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Utilities/Source/spex_expand_mpq_array.c b/SPEX/SPEX_Utilities/Source/spex_expand_mpq_array.c new file mode 100644 index 0000000000..a7097fba2c --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/spex_expand_mpq_array.c @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/spex_expand_mpq_array: convert mpq array to mpz +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function converts a mpq array of size n into an appropriate + * mpz array of size n. To do this, the lcm of the denominators is found as a + * scaling factor. This function allows mpq arrays to be used in SPEX. + */ + +#define SPEX_FREE_ALL \ + SPEX_MPZ_CLEAR(temp); + +#include "spex_util_internal.h" + +SPEX_info spex_expand_mpq_array +( + mpz_t *x_out, // mpz array, on output x_out = x*scale + mpq_t *x, // mpq array that needs to be converted + mpq_t scale, // scaling factor. x_out = scale*x + int64_t n, // size of x + const SPEX_options option // Command options +) +{ + + // inputs have checked in the only caller spex_cast_array + ASSERT(n >= 0); + SPEX_info info ; + mpz_t temp; + SPEX_MPZ_SET_NULL(temp); + SPEX_MPZ_INIT(temp); + + // Find LCM of denominators of x + SPEX_MPZ_SET(temp,SPEX_MPQ_DEN(x[0])); + for (int64_t i = 1; i < n; i++) + { + SPEX_MPZ_LCM(temp, SPEX_MPQ_DEN(x[i]), temp); + } + SPEX_MPQ_SET_Z(scale,temp); + + for (int64_t i = 0; i < n; i++) + { + // x_out[i] = x[i]*temp + SPEX_MPZ_DIVEXACT(x_out[i], temp, SPEX_MPQ_DEN(x[i])); + SPEX_MPZ_MUL(x_out[i], x_out[i], SPEX_MPQ_NUM(x[i])); + } + SPEX_FREE_ALL; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Utilities/Source/spex_gmp.h b/SPEX/SPEX_Utilities/Source/spex_gmp.h new file mode 100644 index 0000000000..3e684c51f0 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/spex_gmp.h @@ -0,0 +1,246 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/spex_gmp.h: definitions for SPEX_gmp.c +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +// These macros are used by SPEX_gmp.c to create wrapper functions around all +// GMP functions used by SPEX, to safely handle out-of-memory conditions. +// They are placed in this separate #include file so that a future developer +// can use them to construct their own wrappers around GMP functions. See +// SPEX_gmp.c for more details. + +#ifndef SPEX_GMP_H +#define SPEX_GMP_H + +#include "SPEX.h" + +//------------------------------------------------------------------------------ +// spex_gmp environment +//------------------------------------------------------------------------------ + +#include + +typedef struct +{ + jmp_buf environment ; // for setjmp and longjmp + int64_t nmalloc ; // # of malloc'd objects in spex_gmp->list + int64_t nlist ; // size of the spex_gmp->list + void **list ; // list of malloc'd objects + mpz_ptr mpz_archive ; // current mpz object + mpz_ptr mpz_archive2 ; // current second mpz object + mpq_ptr mpq_archive ; // current mpq object + mpfr_ptr mpfr_archive ; // current mpfr object + int primary ; // 1 if created by SPEX_initialize; 0 for + // SPEX_thread_initialize +} spex_gmp_t ; + +#ifndef SPEX_GMP_LIST_INIT +// Initial size of the spex_gmp->list. A size of 32 ensures that the list +// never needs to be increased in size (at least in practice; it is possible +// that GMP or MPFR could exceed this size). The test coverage suite in +// SPEX/Tcov reduces this initial size to exercise the code, in +// SPEX/Tcov/Makefile. +#define SPEX_GMP_LIST_INIT 32 +#endif + +#ifdef SPEX_GMP_TEST_COVERAGE +// For testing only +void spex_set_gmp_ntrials (int64_t ntrials) ; +int64_t spex_get_gmp_ntrials (void) ; +#endif + +//------------------------------------------------------------------------------ +// SPEX GMP functions +//------------------------------------------------------------------------------ + +// uncomment this to print memory debugging info +// #define SPEX_GMP_MEMORY_DEBUG + +int spex_gmp_initialize (int primary) ; + +void spex_gmp_finalize (int primary) ; + +spex_gmp_t *spex_gmp_get (void) ; + +void *spex_gmp_allocate (size_t size) ; + +void spex_gmp_free (void *p, size_t size) ; + +void *spex_gmp_reallocate (void *p_old, size_t old_size, size_t new_size ); + +#ifdef SPEX_GMP_MEMORY_DEBUG +void spex_gmp_dump ( void ) ; +#endif + +SPEX_info spex_gmp_failure (int status) ; + +//------------------------------------------------------------------------------ +// Field access macros for MPZ/MPQ/MPFR struct +//------------------------------------------------------------------------------ +// FUTURE: make these accessible to the end user? + +// (similar definition in gmp-impl.h and mpfr-impl.h) + +#define SPEX_MPZ_SIZ(x) ((x)->_mp_size) +#define SPEX_MPZ_PTR(x) ((x)->_mp_d) +#define SPEX_MPZ_ALLOC(x) ((x)->_mp_alloc) +#define SPEX_MPQ_NUM(x) mpq_numref(x) +#define SPEX_MPQ_DEN(x) mpq_denref(x) +#define SPEX_MPFR_MANT(x) ((x)->_mpfr_d) +#define SPEX_MPFR_EXP(x) ((x)->_mpfr_exp) +#define SPEX_MPFR_PREC(x) ((x)->_mpfr_prec) +#define SPEX_MPFR_SIGN(x) ((x)->_mpfr_sign) + +/*re-define but same result: */ +#define SPEX_MPFR_REAL_PTR(x) (&((x)->_mpfr_d[-1])) + +/* Invalid exponent value (to track bugs...) */ +#define SPEX_MPFR_EXP_INVALID \ + ((mpfr_exp_t) 1 << (GMP_NUMB_BITS*sizeof(mpfr_exp_t)/sizeof(mp_limb_t)-2)) + +/* Macros to set the pointer in mpz_t/mpq_t/mpfr_t variable to NULL. It is best + * practice to call these macros immediately after mpz_t/mpq_t/mpfr_t variable + * is declared, and before the mp*_init function is called. It would help to + * prevent error when SPEX_MP*_CLEAR is called before the variable is + * successfully initialized. + */ + +#define SPEX_MPZ_SET_NULL(x) \ +{ \ + SPEX_MPZ_PTR(x) = NULL; \ + SPEX_MPZ_SIZ(x) = 0; \ + SPEX_MPZ_ALLOC(x) = 0; \ +} + +#define SPEX_MPQ_SET_NULL(x) \ +{ \ + SPEX_MPZ_PTR(SPEX_MPQ_NUM(x)) = NULL; \ + SPEX_MPZ_SIZ(SPEX_MPQ_NUM(x)) = 0; \ + SPEX_MPZ_ALLOC(SPEX_MPQ_NUM(x)) = 0; \ + SPEX_MPZ_PTR(SPEX_MPQ_DEN(x)) = NULL; \ + SPEX_MPZ_SIZ(SPEX_MPQ_DEN(x)) = 0; \ + SPEX_MPZ_ALLOC(SPEX_MPQ_DEN(x)) = 0; \ +} + +#define SPEX_MPFR_SET_NULL(x) \ +{ \ + SPEX_MPFR_MANT(x) = NULL; \ + SPEX_MPFR_PREC(x) = 0; \ + SPEX_MPFR_SIGN(x) = 1; \ + SPEX_MPFR_EXP(x) = SPEX_MPFR_EXP_INVALID; \ +} + +/* GMP does not give a mechanism to tell a user when an mpz, mpq, or mpfr + * item has been cleared; thus, if mp*_clear is called on an object that + * has already been cleared, gmp will crash. It is also not possible to + * set a mp*_t = NULL. Thus, this mechanism modifies the internal GMP + * size of entries to avoid crashing in the case that a mp*_t is cleared + * multiple times. + */ + +#define SPEX_MPZ_CLEAR(x) \ +{ \ + if ((x) != NULL && SPEX_MPZ_PTR(x) != NULL) \ + { \ + mpz_clear(x); \ + SPEX_MPZ_SET_NULL(x); \ + } \ +} + +#define SPEX_MPQ_CLEAR(x) \ +{ \ + SPEX_MPZ_CLEAR(SPEX_MPQ_NUM(x)); \ + SPEX_MPZ_CLEAR(SPEX_MPQ_DEN(x)); \ +} + +#define SPEX_MPFR_CLEAR(x) \ +{ \ + if ((x) != NULL && SPEX_MPFR_MANT(x) != NULL)\ + { \ + mpfr_clear(x); \ + SPEX_MPFR_SET_NULL(x); \ + } \ +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//-------------------------------GMP/MPFR wrapper macros------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// GMP/MPFR wrapper macros that already incorporate the SPEX_CHECK macro, which +// is use to prevent segmentation faults in case gmp runs out of memory inside +// a gmp call. +//------------------------------------------------------------------------------ + +#define SPEX_MPZ_INIT(x) SPEX_CHECK( SPEX_mpz_init (x) ) +#define SPEX_MPZ_INIT2(x,size) SPEX_CHECK( SPEX_mpz_init2 (x,size) ) +#define SPEX_MPZ_SET(x,y) SPEX_CHECK( SPEX_mpz_set (x,y) ) +#define SPEX_MPZ_SET_UI(x,y) SPEX_CHECK( SPEX_mpz_set_ui (x,y) ) +#define SPEX_MPZ_SET_SI(x,y) SPEX_CHECK( SPEX_mpz_set_si (x,y) ) +#define SPEX_MPZ_SET_D(x,y) SPEX_CHECK( SPEX_mpz_set_d (x,y) ) +#define SPEX_MPZ_GET_D(x,y) SPEX_CHECK( SPEX_mpz_get_d (x,y) ) +#define SPEX_MPZ_GET_SI(x,y) SPEX_CHECK( SPEX_mpz_get_si (x,y) ) +#define SPEX_MPZ_MUL(a,b,c) SPEX_CHECK( SPEX_mpz_mul (a,b,c) ) +#define SPEX_MPZ_ADDMUL(x,y,z) SPEX_CHECK( SPEX_mpz_addmul (x,y,z) ) +#define SPEX_MPZ_SUB(x,y,z) SPEX_CHECK( SPEX_mpz_sub (x,y,z) ) +#define SPEX_MPZ_SUBMUL(x,y,z) SPEX_CHECK( SPEX_mpz_submul (x,y,z) ) +#define SPEX_MPZ_CDIV_QR(q,r,n,d) SPEX_CHECK( SPEX_mpz_cdiv_qr (q,r,n,d) ) +#define SPEX_MPZ_DIVEXACT(x,y,z) SPEX_CHECK( SPEX_mpz_divexact (x,y,z) ) +#define SPEX_MPZ_GCD(x,y,z) SPEX_CHECK( SPEX_mpz_gcd (x,y,z) ) +#define SPEX_MPZ_LCM(lcm,x,y) SPEX_CHECK( SPEX_mpz_lcm (lcm,x,y) ) +#define SPEX_MPZ_NEG(x,y) SPEX_CHECK( SPEX_mpz_neg (x,y) ) +#define SPEX_MPZ_ABS(x,y) SPEX_CHECK( SPEX_mpz_abs (x,y) ) +#define SPEX_MPZ_CMP(r,x,y) SPEX_CHECK( SPEX_mpz_cmp (r,x,y) ) +#define SPEX_MPZ_CMPABS(r,x,y) SPEX_CHECK( SPEX_mpz_cmpabs (r,x,y) ) +#define SPEX_MPZ_CMP_UI(r,x,y) SPEX_CHECK( SPEX_mpz_cmp_ui (r,x,y) ) +#define SPEX_MPZ_SGN(sgn,x) SPEX_CHECK( SPEX_mpz_sgn (sgn,x) ) +#define SPEX_MPZ_SIZEINBASE(size,x,base) SPEX_CHECK( SPEX_mpz_sizeinbase (size,x,base) ) +#define SPEX_MPQ_INIT(x) SPEX_CHECK( SPEX_mpq_init (x) ) +#define SPEX_MPQ_SET(x,y) SPEX_CHECK( SPEX_mpq_set (x,y) ) +#define SPEX_MPQ_SET_Z(x,y) SPEX_CHECK( SPEX_mpq_set_z (x,y) ) +#define SPEX_MPQ_SET_D(x,y) SPEX_CHECK( SPEX_mpq_set_d (x,y) ) +#define SPEX_MPQ_SET_UI(x,y,z) SPEX_CHECK( SPEX_mpq_set_ui (x,y,z) ) +#define SPEX_MPQ_SET_SI(x,y,z) SPEX_CHECK( SPEX_mpq_set_si (x,y,z) ) +#define SPEX_MPQ_SET_NUM(x,y) SPEX_CHECK( SPEX_mpq_set_num (x,y) ) +#define SPEX_MPQ_SET_DEN(x,y) SPEX_CHECK( SPEX_mpq_set_den (x,y) ) +#define SPEX_MPQ_GET_DEN(x,y) SPEX_CHECK( SPEX_mpq_get_den (x,y) ) +#define SPEX_MPQ_GET_D(x,y) SPEX_CHECK( SPEX_mpq_get_d (x,y) ) +#define SPEX_MPQ_SWAP(x,y) SPEX_CHECK( SPEX_mpq_swap (x,y) ) +#define SPEX_MPQ_NEG(x,y) SPEX_CHECK( SPEX_mpq_neg (x,y) ) +#define SPEX_MPQ_ABS(x,y) SPEX_CHECK( SPEX_mpq_abs (x,y) ) +#define SPEX_MPQ_ADD(x,y,z) SPEX_CHECK( SPEX_mpq_add (x,y,z) ) +#define SPEX_MPQ_MUL(x,y,z) SPEX_CHECK( SPEX_mpq_mul (x,y,z) ) +#define SPEX_MPQ_DIV(x,y,z) SPEX_CHECK( SPEX_mpq_div (x,y,z) ) +#define SPEX_MPQ_CMP(r,x,y) SPEX_CHECK( SPEX_mpq_cmp (r,x,y) ) +#define SPEX_MPQ_CMP_UI(r,x,num,den) SPEX_CHECK( SPEX_mpq_cmp_ui (r,x,num,den) ) +#define SPEX_MPQ_CMP_Z(r,x,y) SPEX_CHECK( SPEX_mpq_cmp_z (r,x,y) ) +#define SPEX_MPQ_EQUAL(r,x,y) SPEX_CHECK( SPEX_mpq_equal (r,x,y) ) +#define SPEX_MPQ_SGN(sgn,x) SPEX_CHECK( SPEX_mpq_sgn (sgn,x) ) +#define SPEX_MPFR_INIT2(x,size) SPEX_CHECK( SPEX_mpfr_init2 (x,size) ) +#define SPEX_MPFR_SET(x,y,rnd) SPEX_CHECK( SPEX_mpfr_set (x,y,rnd) ) +#define SPEX_MPFR_SET_D(x,y,rnd) SPEX_CHECK( SPEX_mpfr_set_d (x,y,rnd) ) +#define SPEX_MPFR_SET_SI(x,y,rnd) SPEX_CHECK( SPEX_mpfr_set_si (x,y,rnd) ) +#define SPEX_MPFR_SET_Q(x,y,rnd) SPEX_CHECK( SPEX_mpfr_set_q (x,y,rnd) ) +#define SPEX_MPFR_SET_Z(x,y,rnd) SPEX_CHECK( SPEX_mpfr_set_z (x,y,rnd) ) +#define SPEX_MPFR_GET_Z(x,y,rnd) SPEX_CHECK( SPEX_mpfr_get_z (x,y,rnd) ) +#define SPEX_MPFR_GET_Q(x,y,rnd) SPEX_CHECK( SPEX_mpfr_get_q (x,y,rnd) ) +#define SPEX_MPFR_GET_D(x,y,rnd) SPEX_CHECK( SPEX_mpfr_get_d (x,y,rnd) ) +#define SPEX_MPFR_GET_SI(x,y,rnd) SPEX_CHECK( SPEX_mpfr_get_si (x,y,rnd) ) +#define SPEX_MPFR_MUL(x,y,z,rnd) SPEX_CHECK( SPEX_mpfr_mul (x,y,z,rnd) ) +#define SPEX_MPFR_MUL_D(x,y,z,rnd) SPEX_CHECK( SPEX_mpfr_mul_d (x,y,z,rnd) ) +#define SPEX_MPFR_DIV_D(x,y,z,rnd) SPEX_CHECK( SPEX_mpfr_div_d (x,y,z,rnd) ) +#define SPEX_MPFR_UI_POW_UI(x,y,z,rnd) SPEX_CHECK( SPEX_mpfr_ui_pow_ui (x,y,z,rnd) ) +#define SPEX_MPFR_LOG2(x,y,rnd) SPEX_CHECK( SPEX_mpfr_log2 (x,y,rnd) ) +#define SPEX_MPFR_SGN(sgn,x) SPEX_CHECK( SPEX_mpfr_sgn (sgn,x) ) +#define SPEX_MPFR_FREE_CACHE() SPEX_CHECK( SPEX_mpfr_free_cache () ) + + +#endif diff --git a/SPEX/SPEX_Util/Source/SPEX_matrix_mul.c b/SPEX/SPEX_Utilities/Source/spex_matrix_mul.c similarity index 66% rename from SPEX/SPEX_Util/Source/SPEX_matrix_mul.c rename to SPEX/SPEX_Utilities/Source/spex_matrix_mul.c index 801ac85f72..bb7ba8a0c0 100644 --- a/SPEX/SPEX_Util/Source/SPEX_matrix_mul.c +++ b/SPEX/SPEX_Utilities/Source/spex_matrix_mul.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/SPEX_matrix_mul: multiplies a matrix by a scalar +// SPEX_Utilities/spex_matrix_mul: multiplies a MPZ matrix by a scalar //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -16,35 +17,36 @@ #include "spex_util_internal.h" -SPEX_info SPEX_matrix_mul // multiplies x by a scalar +SPEX_info spex_matrix_mul // multiplies x by a scalar ( - SPEX_matrix *x, // matrix to be multiplied + SPEX_matrix x, // matrix to be multiplied const mpz_t scalar // scalar to multiply by ) { - if (!spex_initialized ( )) return (SPEX_PANIC) ; //-------------------------------------------------------------------------- // check inputs //-------------------------------------------------------------------------- + if (!spex_initialized ( )) return (SPEX_PANIC); SPEX_info info ; - SPEX_REQUIRE_TYPE (x, SPEX_MPZ) ; + SPEX_REQUIRE_TYPE (x, SPEX_MPZ); + //-------------------------------------------------------------------------- // x = x * scalar //-------------------------------------------------------------------------- int64_t nz; - info = SPEX_matrix_nnz (&nz, x, NULL) ; + info = SPEX_matrix_nnz (&nz, x, NULL); if (info != SPEX_OK) {return info;} for (int64_t i = 0; i < nz; i++) { // x[i] = x[i]*scalar - SPEX_CHECK( SPEX_mpz_mul( x->x.mpz[i], x->x.mpz[i], scalar)); + SPEX_MPZ_MUL( x->x.mpz[i], x->x.mpz[i], scalar); } - return (SPEX_OK) ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Utilities/Source/spex_permute_dense_matrix.c b/SPEX/SPEX_Utilities/Source/spex_permute_dense_matrix.c new file mode 100644 index 0000000000..0e886696a4 --- /dev/null +++ b/SPEX/SPEX_Utilities/Source/spex_permute_dense_matrix.c @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// SPEX_Utilities/spex_permute_dense_matrix: permute rows of a dense matrix A, +// as A_out = P*A_in +//------------------------------------------------------------------------------ + +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//------------------------------------------------------------------------------ + +/* Purpose: This function gets a copy of a row-wise permuted dense matrix as + * A_out = P*A_in. + */ + +#define SPEX_FREE_ALL \ + SPEX_matrix_free (&Atmp, NULL); + +#include "spex_util_internal.h" + +SPEX_info spex_permute_dense_matrix +( + SPEX_matrix *A_handle, // permuted A + const SPEX_matrix A_in, // unpermuted A (not modified) + const int64_t *P, // row permutation + const SPEX_options option +) +{ + + //-------------------------------------------------------------------------- + // check inputs + //-------------------------------------------------------------------------- + + SPEX_info info ; + SPEX_REQUIRE (A_in, SPEX_DENSE, SPEX_MPZ); + + if (A_handle == NULL || !P) {return SPEX_INCORRECT_INPUT;} + (*A_handle) = NULL ; + + //-------------------------------------------------------------------------- + // b(pinv) = b2 + //-------------------------------------------------------------------------- + + int64_t m = A_in->m ; + int64_t n = A_in->n ; + + // allocate x + SPEX_matrix Atmp = NULL ; + SPEX_CHECK (SPEX_matrix_allocate (&Atmp, SPEX_DENSE, SPEX_MPZ, m, n, + 0, false, true, option)); + + // Set Atmp = P*A + for (int64_t i = 0 ; i < m ; i++) + { + for (int64_t j = 0 ; j < n ; j++) + { + SPEX_MPZ_SET(SPEX_2D(Atmp, P[i], j, mpz), + SPEX_2D(A_in, i , j, mpz)); + } + } + + //-------------------------------------------------------------------------- + // return result + //-------------------------------------------------------------------------- + + (*A_handle) = Atmp ; + return SPEX_OK; +} + diff --git a/SPEX/SPEX_Util/Source/spex_sparse_collapse.c b/SPEX/SPEX_Utilities/Source/spex_sparse_collapse.c similarity index 81% rename from SPEX/SPEX_Util/Source/spex_sparse_collapse.c rename to SPEX/SPEX_Utilities/Source/spex_sparse_collapse.c index d5fc43d2d2..3754bf6d92 100644 --- a/SPEX/SPEX_Util/Source/spex_sparse_collapse.c +++ b/SPEX/SPEX_Utilities/Source/spex_sparse_collapse.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_sparse_collapse: shrink space required by a CSC mpz matrix +// SPEX_Utilities/spex_sparse_collapse: shrink space required by CSC mpz matrix //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -19,7 +20,7 @@ SPEX_info spex_sparse_collapse ( - SPEX_matrix* A // matrix to be shrunk + SPEX_matrix A // matrix to be shrunk ) { @@ -27,7 +28,7 @@ SPEX_info spex_sparse_collapse // check inputs //-------------------------------------------------------------------------- - SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ) ; + SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ); //-------------------------------------------------------------------------- @@ -40,14 +41,14 @@ SPEX_info spex_sparse_collapse bool ok ; A->i = (int64_t *) - SPEX_realloc (anz, A->nzmax, sizeof (int64_t), A->i, &ok) ; + SPEX_realloc (anz, A->nzmax, sizeof (int64_t), A->i, &ok); if (!ok) {return SPEX_OUT_OF_MEMORY;} A->x.mpz = (mpz_t *) - SPEX_realloc (anz, A->nzmax, sizeof (mpz_t), A->x.mpz, &ok) ; + SPEX_realloc (anz, A->nzmax, sizeof (mpz_t), A->x.mpz, &ok); if (!ok) {return SPEX_OUT_OF_MEMORY;} A->nzmax = anz ; - return (SPEX_OK) ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Util/Source/spex_sparse_realloc.c b/SPEX/SPEX_Utilities/Source/spex_sparse_realloc.c similarity index 78% rename from SPEX/SPEX_Util/Source/spex_sparse_realloc.c rename to SPEX/SPEX_Utilities/Source/spex_sparse_realloc.c index 6d003fbf0a..0607a5cd6e 100644 --- a/SPEX/SPEX_Util/Source/spex_sparse_realloc.c +++ b/SPEX/SPEX_Utilities/Source/spex_sparse_realloc.c @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_sparse_realloc: double the space for a sparse mpz matrix +// SPEX_Utilities/spex_sparse_realloc: double the space for a sparse mpz matrix //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ @@ -18,7 +19,7 @@ SPEX_info spex_sparse_realloc ( - SPEX_matrix* A // the matrix to be expanded + SPEX_matrix A // the matrix to be expanded ) { @@ -26,7 +27,7 @@ SPEX_info spex_sparse_realloc // check inputs //-------------------------------------------------------------------------- - SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ) ; + SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ); //-------------------------------------------------------------------------- // double the size of A->x and A->i @@ -36,12 +37,12 @@ SPEX_info spex_sparse_realloc bool okx, oki ; A->x.mpz = (mpz_t *) - SPEX_realloc (2*nzmax, nzmax, sizeof (mpz_t), A->x.mpz, &okx) ; + SPEX_realloc (2*nzmax, nzmax, sizeof (mpz_t), A->x.mpz, &okx); A->i = (int64_t *) - SPEX_realloc (2*nzmax, nzmax, sizeof (int64_t), A->i, &oki) ; + SPEX_realloc (2*nzmax, nzmax, sizeof (int64_t), A->i, &oki); if (!oki || !okx) { - return (SPEX_OUT_OF_MEMORY) ; + return (SPEX_OUT_OF_MEMORY); } A->nzmax = 2*nzmax ; @@ -52,9 +53,9 @@ SPEX_info spex_sparse_realloc for (int64_t p = nzmax ; p < 2*nzmax ; p++) { - SPEX_MPZ_SET_NULL (A->x.mpz [p]) ; + SPEX_MPZ_SET_NULL (A->x.mpz [p]); } - return (SPEX_OK) ; + return (SPEX_OK); } diff --git a/SPEX/SPEX_Util/Source/spex_util_internal.h b/SPEX/SPEX_Utilities/Source/spex_util_internal.h similarity index 57% rename from SPEX/SPEX_Util/Source/spex_util_internal.h rename to SPEX/SPEX_Utilities/Source/spex_util_internal.h index 7fe654e93d..8bbc742928 100644 --- a/SPEX/SPEX_Util/Source/spex_util_internal.h +++ b/SPEX/SPEX_Utilities/Source/spex_util_internal.h @@ -1,15 +1,16 @@ //------------------------------------------------------------------------------ -// SPEX_Util/spex_util_internal: include file for internal use in SPEX_Utility functions +// SPEX_Utilities/spex_util_internal: include file for internal use in SPEX_Utility functions //------------------------------------------------------------------------------ -// SPEX_Util: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX_Utilities: (c) 2019-2023, Christopher Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later //------------------------------------------------------------------------------ // This file is not intended to be #include'd in user applications. Use -// SPEX_Util.h instead. +// SPEX.h instead. #ifndef SPEX_UTIL_INTERNAL_H #define SPEX_UTIL_INTERNAL_H @@ -32,6 +33,12 @@ #include #include +// user-callable functions +#include "SPEX.h" + +// SPEX interface to GMP and MPFR +#include "spex_gmp.h" + // SuiteSparse headers #include "SuiteSparse_config.h" #include "colamd.h" @@ -41,31 +48,42 @@ // debugging //------------------------------------------------------------------------------ -#ifdef SPEX_DEBUG +#undef SPEX_DEBUG +// uncomment this line to enable debugging +// #define SPEX_DEBUG -#ifdef MATLAB_MEX_FILE +#ifdef SPEX_DEBUG -#define ASSERT(x) \ -{ \ - if (!(x)) \ - { \ - mexErrMsgTxt ("assertion failed: %s line %d\n", __FILE__, __LINE__) ; \ - } \ -} + // debugging enabled + #ifdef MATLAB_MEX_FILE + // debuging enabled for MATLAB interface + #define ASSERT(x) \ + { \ + if (!(x)) \ + { \ + mexErrMsgTxt ("assertion failed: %s line %d\n", \ + __FILE__, __LINE__) ; \ + } \ + } + #else + // debuging enabled for C library + #include + #define ASSERT(x) assert (x) + #endif #else -#include -#define ASSERT(x) assert (x) + // debugging disabled + #define ASSERT(x) #endif -#else - -// debugging disabled -#define ASSERT(x) - -#endif +#undef GOTCHA +#define GOTCHA \ +{ \ + printf ("GOTCHA: %s, line %d\n", __FILE__, __LINE__) ; \ + abort ( ) ; \ +} //------------------------------------------------------------------------------ //-------------------------Common Macros---------------------------------------- @@ -90,22 +108,75 @@ // frees all workspace if an error occurs. The method can be a scalar as well, // so that SPEX_CHECK(info) works. -// the default is to free nothing +// To create a SPEX_FREE_WORKSPACE and SPEX_FREE_ALL, use this approach: + +/* + #define SPEX_FREE_WORKSPACE \ + { \ + free all workspace \ + } + #define SPEX_FREE_ALL \ + { \ + SPEX_FREE_WORKSPACE ; \ + free all output objects \ + } + #include "this file.h" +*/ + +// then, since SPEX_FREE_ALL is already defined, it isn't #defined below. +// +// Definitions of these macros: +// +// SPEX_FREE_ALL: frees everything, including both workspace and the result +// SPEX_FREE_WORKSPACE: frees just the internal workspace of the method, not +// the final result + +// SPEX_FREE_ALL: Frees workspace and memory that would be returned. Only used +// when there is an error and we need to cleanly close things (like out of +// memory conditions and failed SPEX_CHECK) + #ifndef SPEX_FREE_ALL #define SPEX_FREE_ALL #endif -#define SPEX_CHECK(method) \ -{ \ - info = (method) ; \ - if (info != SPEX_OK) \ - { \ - SPEX_FREE_ALL ; \ - return (info) ; \ - } \ -} +// SPEX_FREE_WORKSPACE: Frees all workspace (but not memory that was allocated +// and meant to be returned). Used usually at the end of the function. This +// workspace mechanism should be used even if the function only has one +// workspace variable (it can be risky otherwise with further development) -#include "SPEX.h" +#ifndef SPEX_FREE_WORKSPACE +#define SPEX_FREE_WORKSPACE +#endif + +// Local variables (only declared, allocated and freed inside an if, for +// example) do not go inside the workspace. + +#ifdef SPEX_DEBUG + + #define SPEX_CHECK(method) \ + { \ + info = (method); \ + if (info != SPEX_OK) \ + { \ + printf("file %s line %d\n",__FILE__,__LINE__);\ + SPEX_FREE_ALL; \ + return (info); \ + } \ + } + +#else + + #define SPEX_CHECK(method) \ + { \ + info = (method); \ + if (info != SPEX_OK) \ + { \ + SPEX_FREE_ALL; \ + return (info); \ + } \ + } + +#endif #if !defined (SUITESPARSE_VERSION) || \ (SUITESPARSE_VERSION < SUITESPARSE_VER_CODE(7,5)) @@ -124,17 +195,17 @@ // printing control //------------------------------------------------------------------------------ -// SPEX uses the SuiteSparse_config printf_func instead of a mere call to -// printf (the default function is printf, or mexPrintf when in MATLAB). If -// this function pointer is NULL, no printing is done. +// SPEX uses SuiteSparse_config.printf_func instead of a mere call to printf +// (the default function is printf, or mexPrintf when in MATLAB). If this +// function pointer is NULL, no printing is done. #define SPEX_PRINTF(...) \ { \ - int (*printf_func) (const char *, ...) ; \ - printf_func = SuiteSparse_config_printf_func_get ( ) ; \ - if (printf_func != NULL) \ + int (*prfunc)(const char *, ...); \ + prfunc = SuiteSparse_config_printf_func_get( ); \ + if (prfunc != NULL) \ { \ - (void) (printf_func) (__VA_ARGS__) ; \ + prfunc(__VA_ARGS__); \ } \ } @@ -142,40 +213,13 @@ #define SPEX_PR2(...) { if (pr >= 2) SPEX_PRINTF (__VA_ARGS__) } #define SPEX_PR3(...) { if (pr >= 3) SPEX_PRINTF (__VA_ARGS__) } + + //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -//-------------------------functions for GMP wrapper---------------------------- +//----------------------------------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -// uncomment this to print memory debugging info -// #define SPEX_GMP_MEMORY_DEBUG - -#ifdef SPEX_GMP_MEMORY_DEBUG -void spex_gmp_dump ( void ) ; -#endif - -extern int64_t spex_gmp_ntrials ; - -#ifndef SPEX_GMP_LIST_INIT -// A size of 32 ensures that the list never needs to be increased in size. -// The test coverage suite in SPEX_Left_LU/Tcov reduces this initial size to -// exercise the code, in SPEX_Left_LU/Tcov/Makefile. -#define SPEX_GMP_LIST_INIT 32 -#endif - - -bool spex_gmp_init (void) ; - -void spex_gmp_finalize (void) ; - -void *spex_gmp_allocate (size_t size) ; - -void spex_gmp_free (void *p, size_t size) ; - -void *spex_gmp_reallocate (void *p_old, size_t old_size, size_t new_size ); - -void spex_gmp_failure (int status) ; - // Tolerance used in the pivoting schemes. This number can be anything in // between 0 and 1. A value of 0 selects the diagonal element exclusively and a @@ -183,9 +227,6 @@ void spex_gmp_failure (int status) ; // tolerance pivoting based method #define SPEX_DEFAULT_TOL 1 -// Check parameter. If this = 1 then the solution to the system is checked -// for accuracy -#define SPEX_DEFAULT_CHECK false // Pivoting scheme used for SPEX Left LU. // SPEX_SMALLEST = 0, Smallest pivot @@ -197,10 +238,11 @@ void spex_gmp_failure (int status) ; #define SPEX_DEFAULT_PIVOT SPEX_SMALLEST // Column ordering used. -// SPEX_NO_ORDERING = 0, None: Not recommended for sparse matrices -// SPEX_COLAMD = 1, COLAMD: Default -// SPEX_AMD = 2 AMD -#define SPEX_DEFAULT_ORDER SPEX_COLAMD +// SPEX_DEFAULT_ORDERING = 0, COLAMD for LU, AMD for Cholesky +// SPEX_NO_ORDERING = 1, None: Not recommended for sparse matrices +// SPEX_COLAMD = 2, COLAMD +// SPEX_AMD = 3 AMD +#define SPEX_DEFAULT_ORDER SPEX_DEFAULT // Defines printing to be done #define SPEX_DEFAULT_PRINT_LEVEL 0 @@ -208,6 +250,15 @@ void spex_gmp_failure (int status) ; // MPFR precision used (quad is default) #define SPEX_DEFAULT_PRECISION 128 +// Defines the algorithm used +// SPEX_DEFAULT = 0, Defaults: Left for LU, Up for Chol, Gram for QR looking +// LU factorization +// SPEX_LU_LEFT = 1, Left looking LU factorization +// SPEX_CHOL_LEFT = 2, Left looking Cholesky factorization +// SPEX_CHOL_UP = 3, Up looking Cholesky factorization +// SPEX_QR_GRAM = 4 Default factorization for QR +#define SPEX_DEFAULT_ALGORITHM SPEX_DEFAULT + //------------------------------------------------------------------------------ // Type of MPFR rounding used. //------------------------------------------------------------------------------ @@ -236,9 +287,6 @@ void spex_gmp_failure (int status) ; #define SPEX_OPTION_TOL(option) \ SPEX_OPTION (option, tol, SPEX_DEFAULT_TOL) -#define SPEX_OPTION_CHECK(option) \ - SPEX_OPTION (option, check, false) - #define SPEX_OPTION_PIVOT(option) \ SPEX_OPTION (option, pivot, SPEX_DEFAULT_PIVOT) @@ -254,88 +302,9 @@ void spex_gmp_failure (int status) ; #define SPEX_OPTION_ROUND(option) \ SPEX_OPTION (option, round, SPEX_DEFAULT_MPFR_ROUND) -//------------------------------------------------------------------------------ -// Field access macros for MPZ/MPQ/MPFR struct -//------------------------------------------------------------------------------ - -// FUTURE: make these accessible to the end user? - -// (similar definition in gmp-impl.h and mpfr-impl.h) +#define SPEX_OPTION_ALGORITHM(option) \ + SPEX_OPTION (option, algo, SPEX_DEFAULT_ALGORITHM) -#define SPEX_MPZ_SIZ(x) ((x)->_mp_size) -#define SPEX_MPZ_PTR(x) ((x)->_mp_d) -#define SPEX_MPZ_ALLOC(x) ((x)->_mp_alloc) -#define SPEX_MPQ_NUM(x) mpq_numref(x) -#define SPEX_MPQ_DEN(x) mpq_denref(x) -#define SPEX_MPFR_MANT(x) ((x)->_mpfr_d) -#define SPEX_MPFR_EXP(x) ((x)->_mpfr_exp) -#define SPEX_MPFR_PREC(x) ((x)->_mpfr_prec) -#define SPEX_MPFR_SIGN(x) ((x)->_mpfr_sign) - -/*re-define but same result: */ -#define SPEX_MPFR_REAL_PTR(x) (&((x)->_mpfr_d[-1])) - -/* Invalid exponent value (to track bugs...) */ -#define SPEX_MPFR_EXP_INVALID \ - ((mpfr_exp_t) 1 << (GMP_NUMB_BITS*sizeof(mpfr_exp_t)/sizeof(mp_limb_t)-2)) - -/* Macros to set the pointer in mpz_t/mpq_t/mpfr_t variable to NULL. It is best - * practice to call these macros immediately after mpz_t/mpq_t/mpfr_t variable - * is declared, and before the mp*_init function is called. It would help to - * prevent error when SPEX_MP*_CLEAR is called before the variable is - * successfully initialized. - */ - -#define SPEX_MPZ_SET_NULL(x) \ - SPEX_MPZ_PTR(x) = NULL; \ - SPEX_MPZ_SIZ(x) = 0; \ - SPEX_MPZ_ALLOC(x) = 0; - -#define SPEX_MPQ_SET_NULL(x) \ - SPEX_MPZ_PTR(SPEX_MPQ_NUM(x)) = NULL; \ - SPEX_MPZ_SIZ(SPEX_MPQ_NUM(x)) = 0; \ - SPEX_MPZ_ALLOC(SPEX_MPQ_NUM(x)) = 0; \ - SPEX_MPZ_PTR(SPEX_MPQ_DEN(x)) = NULL; \ - SPEX_MPZ_SIZ(SPEX_MPQ_DEN(x)) = 0; \ - SPEX_MPZ_ALLOC(SPEX_MPQ_DEN(x)) = 0; - -#define SPEX_MPFR_SET_NULL(x) \ - SPEX_MPFR_MANT(x) = NULL; \ - SPEX_MPFR_PREC(x) = 0; \ - SPEX_MPFR_SIGN(x) = 1; \ - SPEX_MPFR_EXP(x) = SPEX_MPFR_EXP_INVALID; - -/* GMP does not give a mechanism to tell a user when an mpz, mpq, or mpfr - * item has been cleared; thus, if mp*_clear is called on an object that - * has already been cleared, gmp will crash. It is also not possible to - * set a mp*_t = NULL. Thus, this mechanism modifies the internal GMP - * size of entries to avoid crashing in the case that a mp*_t is cleared - * multiple times. - */ - -#define SPEX_MPZ_CLEAR(x) \ -{ \ - if ((x) != NULL && SPEX_MPZ_PTR(x) != NULL) \ - { \ - mpz_clear(x); \ - SPEX_MPZ_SET_NULL(x); \ - } \ -} - -#define SPEX_MPQ_CLEAR(x) \ -{ \ - SPEX_MPZ_CLEAR(SPEX_MPQ_NUM(x)); \ - SPEX_MPZ_CLEAR(SPEX_MPQ_DEN(x)); \ -} - -#define SPEX_MPFR_CLEAR(x) \ -{ \ - if ((x) != NULL && SPEX_MPFR_MANT(x) != NULL) \ - { \ - mpfr_clear(x); \ - SPEX_MPFR_SET_NULL(x); \ - } \ -} // ============================================================================ @@ -348,31 +317,43 @@ void spex_set_initialized (bool s) ; // set global initialzed flag to s //------------------------------------------------------------------------------ -// mpfr_vector: a 1D mpfr_t array +// spex_create_mpfr_array: create a 1D mpfr_t array //------------------------------------------------------------------------------ // Creates a simple 1D array, where A[i] is an entry of type mpfr_t. /* Purpose: This function creates a MPFR array of desired precision*/ -mpfr_t* spex_create_mpfr_array + +mpfr_t *spex_create_mpfr_array ( - int64_t n, // size of the array - const SPEX_options* option -); + int64_t n, // size of the array + const SPEX_options option // command options containing the prec for mpfr +) ; + +//------------------------------------------------------------------------------ +// spex_create_mpq_array: Creates a 1D array, whose entries are all mpq_t type. +//------------------------------------------------------------------------------ // Creates a simple 1D array, where A[i] is an entry of type mpq_t. /* Purpose: This function creates an mpq array of size n. * This function must be called for all mpq arrays created. */ -mpq_t* spex_create_mpq_array + +mpq_t *spex_create_mpq_array ( int64_t n // size of the array -); +) ; +// Create and initialize a single mpq_t variable + +SPEX_info spex_create_mpq +( + mpq_t x // mpq_t entry to be initialized +) ; //------------------------------------------------------------------------------ -// mpz_vector: a 1D mpz_t array +// spex_create_mpz_array: create a 1D mpz_t array //------------------------------------------------------------------------------ // Creates a simple 1D array, where A[i] is an entry of type mpz_t. @@ -380,52 +361,71 @@ mpq_t* spex_create_mpq_array /* Purpose: This function creates an mpz array of size n and allocates * default size. */ -mpz_t* spex_create_mpz_array + +mpz_t *spex_create_mpz_array ( - int64_t n // Size of x -); + int64_t n // size of the array +) ; + +//------------------------------------------------------------------------------ +// spex_delete_mpz_array: delete a 1D mpz_t array +//------------------------------------------------------------------------------ +// Delete a simple 1D array, where A[i] is an entry of type mpz_t. + +/* Purpose: This function deletes a mpz array of size n + */ + +void spex_delete_mpz_array +( + mpz_t **x, // mpz array to be deleted + int64_t n // Size of x +) ; /* Purpose: This function converts a double array of size n to an appropriate * mpz array of size n. To do this, the number is multiplied by 10^17 then, the * GCD is found. This function allows the use of matrices in double precision * to work with SPEX. */ + SPEX_info spex_expand_double_array ( - mpz_t *x_out, // integral final array - double* x, // double array that needs to be made integral - mpq_t scale, // the scaling factor used (x_out = scale * x) - int64_t n, // size of x - const SPEX_options* option -); + mpz_t *x_out, // integral final array + double *x, // double array that needs to be made integral + mpq_t scale, // the scaling factor used (x_out = scale * x) + int64_t n, // size of x + const SPEX_options option // Command options +) ; /* Purpose: This function converts a mpfr array of size n and precision prec to * an appropriate mpz array of size n. To do this, the number is multiplied by * the appropriate power of 10 then the gcd is found. This function allows mpfr * arrays to be used within SPEX. */ + SPEX_info spex_expand_mpfr_array ( - mpz_t *x_out, // integral final array - mpfr_t* x, // mpfr array to be expanded - mpq_t scale, // scaling factor used (x_out = scale*x) - int64_t n, // size of x - const SPEX_options *option // command options containing the prec for mpfr -); + mpz_t *x_out, // full precision mpz array + mpfr_t *x, // mpfr array to be expanded + mpq_t scale, // scaling factor used (x_out = scale*x) + int64_t n, // size of x + const SPEX_options option // command options containing the prec + // and rounding for mpfr +) ; /* Purpose: This function converts a mpq array of size n into an appropriate mpz * array of size n. To do this, the lcm of the denominators is found as a * scaling factor. This function allows mpq arrays to be used in SPEX */ + SPEX_info spex_expand_mpq_array ( - mpz_t *x_out, // integral final array - mpq_t* x, // mpq array that needs to be converted - mpq_t scale, // scaling factor. x_out = scale*x - int64_t n, // size of x - const SPEX_options* option // Command options -); + mpz_t *x_out, // mpz array, on output x_out = x*scale + mpq_t *x, // mpq array that needs to be converted + mpq_t scale, // scaling factor. x_out = scale*x + int64_t n, // size of x + const SPEX_options option // Command options +) ; /* Purpose: This function converts a mpq matrix of size m*n into an appropriate * mpz matrix of size m*n. To do this, the lcm of the denominators is found as a @@ -470,36 +470,89 @@ SPEX_info spex_cast_array void *X, // input array, of size n SPEX_type xtype, // type of X int64_t n, // size of Y and X - mpq_t y_scale, // scale factor applied if y is mpz_t - mpq_t x_scale, // scale factor applied if x is mpz_t - const SPEX_options *option + mpq_t y_scale, // scale factor applied if Y is mpz_t + const mpq_t x_scale, // scale factor applied if x is mpz_t + const SPEX_options option // Command options. If NULL, use defaults ) ; SPEX_info spex_cast_matrix ( - SPEX_matrix **Y_handle, // nz-by-1 dense matrix to create + SPEX_matrix *Y_handle, // nz-by-1 dense matrix to create SPEX_type Y_type, // type of Y - SPEX_matrix *A, // matrix with nz entries - const SPEX_options *option + const SPEX_matrix A, // matrix with nz entries + const SPEX_options option // Command options, if NULL defaults are used ) ; + + /* Purpose: This function collapses a SPEX matrix. Essentially it shrinks the * size of x and i. so that they only take up the number of elements in the * matrix. For example if A->nzmax = 1000 but nnz(A) = 500, i and x are of size * 1000, so this function shrinks them to size 500. */ + SPEX_info spex_sparse_collapse ( - SPEX_matrix* A // matrix to be shrunk -); + SPEX_matrix A // matrix to be shrunk +) ; /* Purpose: This function expands a SPEX matrix by doubling its size. It * merely expands x and i and does not initialize/allocate the values. */ + SPEX_info spex_sparse_realloc ( - SPEX_matrix* A // the matrix to be expanded -); + SPEX_matrix A // the matrix to be expanded +) ; + +/* Purpose: This function gets a copy of a row-wise permuted dense matrix as + * A_out = P*A_in. + */ + +SPEX_info spex_permute_dense_matrix +( + SPEX_matrix *A_handle, // permuted A + const SPEX_matrix A_in, // unpermuted A (not modified) + const int64_t *P, // row permutation + const SPEX_options option +) ; + +/* Purpose: This function multiplies matrix x a scalar + */ + +SPEX_info spex_matrix_mul // multiplies x by a scalar +( + SPEX_matrix x, // matrix to be multiplied + const mpz_t scalar // scalar to multiply by +) ; + +/* Purpose: p [0..n] = cumulative sum of c [0..n-1], and then copy p [0..n-1] + * into c. This function is lightly modified from CSparse. + */ + +SPEX_info spex_cumsum +( + int64_t *p, // vector to store the sum of c + int64_t *c, // vector which is summed + int64_t n // size of c +) ; + + +SPEX_info spex_colamd +( + int64_t **perm_handle, + int64_t *nnz, + const SPEX_matrix A, + const SPEX_options option +) ; + +SPEX_info spex_amd +( + int64_t **perm_handle, + int64_t *nnz, + const SPEX_matrix A, + const SPEX_options option +) ; // (void *) pointer to the values of A. A must be non-NULL with a valid type #define SPEX_X(A) \ @@ -532,5 +585,19 @@ SPEX_info spex_sparse_realloc ASSERT_KIND (A,required_kind) ; \ ASSERT_TYPE (A,required_type) ; +//------------------------------------------------------------------------------ +// SPEX_matrix macros +//------------------------------------------------------------------------------ + +// These macros simplify the access to entries in a SPEX_matrix. +// The type parameter is one of: mpq, mpz, mpfr, int64, or fp64. + +// To access the kth entry in a SPEX_matrix using 1D linear addressing, +// in any matrix kind (CSC, triplet, or dense), in any type: +#define SPEX_1D(A,k,type) ((A)->x.type [k]) + +// To access the (i,j)th entry in a 2D SPEX_matrix, in any type: +#define SPEX_2D(A,i,j,type) SPEX_1D (A, (i)+(j)*((A)->m), type) + #endif diff --git a/SPEX/SPEX_Left_LU/Tcov/README.txt b/SPEX/Tcov/README.txt similarity index 69% rename from SPEX/SPEX_Left_LU/Tcov/README.txt rename to SPEX/Tcov/README.txt index ced74e3281..8cab5f01b7 100644 --- a/SPEX/SPEX_Left_LU/Tcov/README.txt +++ b/SPEX/Tcov/README.txt @@ -1,8 +1,8 @@ -SPEX/SPEX/SPEX_Left_LU/Tcov: comprehensive test coverage for SPEX Left LU. +SPEX/Tcov: comprehensive test coverage for SPEX. -Requires Linux. Type "make" to compile, and then "make run" to run the +Requires Linux. Type "make" to compile, and run the tests, or "make vtests" to run the tests with valgrind for memory leakage -checking. +checking. The test coverage is in cover.out. The test output is printed on stdout, except for cov_test (which prints its output in various diff --git a/SPEX/SPEX_Left_LU/Tcov/cov.awk b/SPEX/Tcov/cov.awk similarity index 100% rename from SPEX/SPEX_Left_LU/Tcov/cov.awk rename to SPEX/Tcov/cov.awk diff --git a/SPEX/Tcov/covall b/SPEX/Tcov/covall new file mode 100755 index 0000000000..4eca3df2e9 --- /dev/null +++ b/SPEX/Tcov/covall @@ -0,0 +1,6 @@ +#!/bin/bash + ./gcovs SPEX_*.c spex_*.c 2>&1 > gcovs.out + ./covs > covs.out + echo -n "statements not yet tested: " + grep "#####" *.*.gcov | wc -l + ./cover *.*.gcov > cover.out diff --git a/SPEX/SPEX_Left_LU/Tcov/cover b/SPEX/Tcov/cover similarity index 100% rename from SPEX/SPEX_Left_LU/Tcov/cover rename to SPEX/Tcov/cover diff --git a/SPEX/SPEX_Left_LU/Tcov/covs b/SPEX/Tcov/covs similarity index 100% rename from SPEX/SPEX_Left_LU/Tcov/covs rename to SPEX/Tcov/covs diff --git a/SPEX/SPEX_Left_LU/Tcov/gcovs b/SPEX/Tcov/gcovs similarity index 86% rename from SPEX/SPEX_Left_LU/Tcov/gcovs rename to SPEX/Tcov/gcovs index 6a24317170..bc58c6d990 100755 --- a/SPEX/SPEX_Left_LU/Tcov/gcovs +++ b/SPEX/Tcov/gcovs @@ -3,6 +3,6 @@ echo '=================================================================' for file in $* do - gcov -f $file + gcov -f $file 2>&1 echo '=================================================================' -done +done diff --git a/SPEX/Tcov/simple_rand.c b/SPEX/Tcov/simple_rand.c new file mode 100644 index 0000000000..c61c65a414 --- /dev/null +++ b/SPEX/Tcov/simple_rand.c @@ -0,0 +1,64 @@ +// ---------------------------------------------------------------------------- +// SPEX/Tcov/simple_rand.c: a very simple random number generator +// ---------------------------------------------------------------------------- + +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//----------------------------------------------------------------------------- + +// The POSIX.1-2001 example of rand, duplicated here so that the same sequence +// will be generated on different machines. The purpose is not to generate +// high-quality random numbers, but to ensure the same sequence is generated +// on any computer or operating system. This allows the test coverage to be +// repeatable. + +// Since the simple_rand ( ) function is replicated from the POSIX.1-2001 +// standard, no copyright claim is intended for this specific file. The +// copyright statement above applies to all of SPEX, not this file. + +#include "simple_rand.h" + +/* simple_rand is not thread-safe */ +uint64_t simple_rand_next = 1 ; + +#define SIMPLE_RAND_MAX 32767 + +/* return a random number between 0 and SIMPLE_RAND_MAX */ +uint64_t simple_rand (void) +{ + simple_rand_next = simple_rand_next * 1103515245 + 12345 ; + return ((simple_rand_next/65536) % (SIMPLE_RAND_MAX + 1)); +} + +/* set the seed */ +void simple_rand_seed (uint64_t seed) +{ + simple_rand_next = seed ; +} + +/* get the seed */ +uint64_t simple_rand_getseed (void) +{ + return (simple_rand_next); +} + +/* return a random double between 0 and 1, inclusive */ +double simple_rand_x (void ) +{ + return (((double) simple_rand ( )) / ((double) SIMPLE_RAND_MAX)); +} + +/* return a random uint64_t */ +uint64_t simple_rand_i (void ) +{ + uint64_t i = 0 ; + for (int k = 0 ; k < 5 ; k++) + { + i = SIMPLE_RAND_MAX * i + simple_rand ( ); + } + return (i); +} + diff --git a/SPEX/Tcov/simple_rand.h b/SPEX/Tcov/simple_rand.h new file mode 100644 index 0000000000..ba362469b3 --- /dev/null +++ b/SPEX/Tcov/simple_rand.h @@ -0,0 +1,34 @@ +// ---------------------------------------------------------------------------- +// SPEX/Tcov/simple_rand.h: a very simple random number generator +// ---------------------------------------------------------------------------- + +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//----------------------------------------------------------------------------- + +// Since the simple_rand ( ) function is replicated from the POSIX.1-2001 +// standard, no copyright claim is intended for this specific file. The +// copyright statement above applies to all of SPEX, not this file. + +#include + +#define SIMPLE_RAND_MAX 32767 + +/* return a random number between 0 and SIMPLE_RAND_MAX */ +uint64_t simple_rand (void) ; + +/* set the seed */ +void simple_rand_seed (uint64_t seed) ; + +/* get the seed */ +uint64_t simple_rand_getseed (void) ; + +/* return a random double between 0 and 1, inclusive */ +double simple_rand_x ( void) ; + +/* return a random uint64_t */ +uint64_t simple_rand_i (void ) ; + diff --git a/SPEX/Tcov/tcov_for_cholesky.c b/SPEX/Tcov/tcov_for_cholesky.c new file mode 100644 index 0000000000..3d4f774855 --- /dev/null +++ b/SPEX/Tcov/tcov_for_cholesky.c @@ -0,0 +1,564 @@ +// ---------------------------------------------------------------------------- +// SPEX/Tcov/tcov_for_cholesky.c: test coverage for SPEX_Cholesky +// ---------------------------------------------------------------------------- + +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//----------------------------------------------------------------------------- + +/* This program will exactly solve the sparse linear system Ax = b by performing + * the SPEX Cholesky factorization. + */ + +#include "tcov_utilities.h" +#include "spex_demos.h" + +// test wrapper for SPEX_* function when expected error would produce +#define ERR(method,expected_error) \ +{ \ + SPEX_info info5 = (method) ; \ + if (info5 != expected_error) \ + { \ + printf ("SPEX method was expected to fail, but succeeded!\n") ; \ + printf ("this error was expected:\n") ; \ + SPEX_PRINT_INFO (expected_error) ; \ + printf ("but this error was obtained:\n") ; \ + TEST_ABORT (info5) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// BRUTAL: test a method with debug malloc, until it succeeds +//------------------------------------------------------------------------------ + +// The method must return a bool (true if successful, false if failure). + +#define NTRIAL_MAX 10000 + +#define BRUTAL(method) \ +{ \ + int64_t trial = 0 ; \ + SPEX_info info2 = SPEX_OK ; \ + for (trial = 0 ; trial <= NTRIAL_MAX ; trial++) \ + { \ + malloc_count = trial ; \ + info2 = (method) ; \ + if (info2 != SPEX_OUT_OF_MEMORY) break ; \ + } \ + if (info2 != SPEX_OK) TEST_ABORT (info2) ; \ + malloc_count = INT64_MAX ; \ + printf ("\nBrutal Cholesky trials %ld: tests passed\n", trial); \ +} + +//------------------------------------------------------------------------------ +// read_test_matrix: read in a matrix from a file +//------------------------------------------------------------------------------ + +void read_test_matrix (SPEX_matrix *A_handle, char *filename); + +void read_test_matrix (SPEX_matrix *A_handle, char *filename) +{ + FILE *f = fopen (filename, "r"); + OK (f == NULL ? SPEX_PANIC : SPEX_OK); + OK (spex_demo_tripread (A_handle, f, SPEX_FP64, NULL)); + fclose (f); +} + +//------------------------------------------------------------------------------ +// create_test_rhs: create a right-hand-side vector +//------------------------------------------------------------------------------ + +void create_test_rhs (SPEX_matrix *b_handle, int64_t n); + +void create_test_rhs (SPEX_matrix *b_handle, int64_t n) +{ + OK (SPEX_matrix_allocate (b_handle, SPEX_DENSE, SPEX_MPZ, n, 1, n, false, + true, NULL)); + SPEX_matrix b = *(b_handle); + // b(0)=0 + OK (SPEX_mpz_set_ui (b->x.mpz [0], 0)); + for (int64_t k = 1 ; k < n ; k++) + { + // b(k) = 1 + OK (SPEX_mpz_set_ui (b->x.mpz [k], 1)); + } +} + +//------------------------------------------------------------------------------ +// spex_test_chol_backslash: test SPEX_cholesky_backslash +//------------------------------------------------------------------------------ + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL \ +{ \ + OK (SPEX_matrix_free (&x, option)); \ +} + +SPEX_info spex_test_chol_backslash (SPEX_matrix A, SPEX_matrix b, + SPEX_options option); + +SPEX_info spex_test_chol_backslash (SPEX_matrix A, SPEX_matrix b, + SPEX_options option) +{ + SPEX_matrix x = NULL ; + // solve Ax=b + OK2 (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option)); + // disable memory testing when checking the solution + int64_t save = malloc_count ; malloc_count = INT64_MAX ; + OK (spex_demo_check_solution (A, x, b, option)); + // re-enable memory testing + malloc_count = save ; + SPEX_FREE_ALL; + return (SPEX_OK) ; +} + +//------------------------------------------------------------------------------ +// spex_test_cdiv_qr: test SPEX_cdiv_qr +//------------------------------------------------------------------------------ + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL \ +{ \ + SPEX_MPZ_CLEAR(q1); \ + SPEX_MPZ_CLEAR(r1); \ +} + +SPEX_info spex_test_cdiv_qr (mpz_t n, mpz_t d) ; + +SPEX_info spex_test_cdiv_qr (mpz_t n, mpz_t d) +{ + //SPEX_info info ; + mpz_t q1, r1; + SPEX_MPZ_SET_NULL(q1); + SPEX_MPZ_SET_NULL(r1); + OK2 (SPEX_mpz_init2(q1,1)); + OK2 (SPEX_mpz_init2(r1,1)); + + OK2 (SPEX_mpz_cdiv_qr(q1,r1,n,d)); + + SPEX_FREE_ALL ; + return (SPEX_OK) ; +} + +// BRUTAL ( spex_test_cdiv_qr ()) ; + + +//------------------------------------------------------------------------------ +// spex_test_chol_afs: test SPEX_cholesky_[analyze,factorize,solve] +//------------------------------------------------------------------------------ + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL \ +{ \ + OK (SPEX_symbolic_analysis_free (&S, option)); \ + OK (SPEX_factorization_free (&F, option)); \ + OK (SPEX_matrix_free (&x, option)); \ +} + +SPEX_info spex_test_chol_afs +( + SPEX_matrix A, + SPEX_matrix b, + SPEX_options option +) ; + +SPEX_info spex_test_chol_afs (SPEX_matrix A, SPEX_matrix b, SPEX_options option) +{ + SPEX_symbolic_analysis S = NULL ; + SPEX_factorization F = NULL ; + SPEX_matrix x = NULL ; + // solve Ax=b + OK2 (SPEX_cholesky_analyze (&S, A, option)); + OK2 (SPEX_cholesky_factorize (&F, A, S, option)); + OK2 (SPEX_cholesky_solve (&x, F, b, option)); + // disable memory testing when checking the solution + int64_t save = malloc_count ; malloc_count = INT64_MAX ; + OK (spex_demo_check_solution (A, x, b, option)); + // re-enable memory testing + malloc_count = save ; + SPEX_FREE_ALL; + return (SPEX_OK); +} + +//------------------------------------------------------------------------------ +// tcov_for_cholesky: main program +//------------------------------------------------------------------------------ + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL \ +{ \ + OK (SPEX_symbolic_analysis_free (&S, option)); \ + OK (SPEX_factorization_free (&F, option)); \ + OK (SPEX_matrix_free (&x, option)); \ + OK (SPEX_matrix_free (&A, option)); \ + OK (SPEX_matrix_free (&b, option)); \ + SPEX_FREE (option); \ +} + +int main (int argc, char *argv []) +{ + + //-------------------------------------------------------------------------- + // start SPEX + //-------------------------------------------------------------------------- + + SPEX_matrix A = NULL, b = NULL, x = NULL ; + SPEX_symbolic_analysis S = NULL ; + SPEX_factorization F = NULL, F2 = NULL ; + SPEX_options option = NULL ; + + if (argc < 2) + { + printf ("usage: tcov_for_cholesky matrixfilename\n"); + TEST_ABORT (SPEX_INCORRECT_INPUT); + } + + SPEX_info info ; + OK (SPEX_initialize_expert (tcov_malloc, tcov_calloc, tcov_realloc, + tcov_free)); + + // disable malloc testing for the first part of the test + spex_set_gmp_ntrials (INT64_MAX) ; + malloc_count = INT64_MAX ; + + OK (SPEX_create_default_options (&option)); + + //-------------------------------------------------------------------------- + // test a few small invalid matrices + //-------------------------------------------------------------------------- + + // unsymmetric matrix (row counts != col counts) + printf ("Cholesky: error handling for unsymmetric matrix (1)\n"); + read_test_matrix (&A, "../ExampleMats/test1.mat.txt"); + create_test_rhs (&b, A->n); + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), SPEX_NOTSPD); + OK (SPEX_matrix_free (&A, option)); + OK (SPEX_matrix_free (&b, option)); + + // unsymmetric matrix (unsymmetric pattern) + printf ("Cholesky: error handling for unsymmetric matrix (2)\n"); + read_test_matrix (&A, "../ExampleMats/test2.mat.txt"); + create_test_rhs (&b, A->n); + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), SPEX_NOTSPD); + OK (SPEX_matrix_free (&A, option)); + OK (SPEX_matrix_free (&b, option)); + + // unsymmetric matrix (unsymmetric values) + printf ("Cholesky: error handling for unsymmetric matrix (3)\n"); + read_test_matrix (&A, "../ExampleMats/test3.mat.txt"); + create_test_rhs (&b, A->n); + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), SPEX_NOTSPD); + OK (SPEX_matrix_free (&A, option)); + OK (SPEX_matrix_free (&b, option)); + + // symmetric indefinite matrix + printf ("Cholesky: error handling for symmetric indefinite matrix (4)\n"); + read_test_matrix (&A, "../ExampleMats/test4.mat.txt"); + create_test_rhs (&b, A->n); + option->algo = SPEX_CHOL_UP ; + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), SPEX_NOTSPD); + option->algo = SPEX_CHOL_LEFT ; + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), SPEX_NOTSPD); + option->algo = SPEX_CHOL_UP ; + OK (SPEX_matrix_free (&A, option)); + OK (SPEX_matrix_free (&b, option)); + + //-------------------------------------------------------------------------- + // symetry check + //-------------------------------------------------------------------------- + read_test_matrix (&A, "../ExampleMats/test5.mat.txt"); + SPEX_cholesky_analyze( &S, A, option); + OK (SPEX_matrix_free (&A, option)); + OK (SPEX_matrix_free (&b, option)); + + //-------------------------------------------------------------------------- + // load the test matrix and create the right-hand-side + //-------------------------------------------------------------------------- + + read_test_matrix (&A, argv [1]); + int64_t n = A->n ; + int64_t m = A->m ; + int64_t anz = -1 ; + OK (SPEX_matrix_nnz (&anz, A, option)); + printf ("\nInput matrix: %ld-by-%ld with %ld entries\n", n, m, anz); + OK ((n != m) ? SPEX_PANIC : SPEX_OK); + create_test_rhs (&b, A->n); + + //-------------------------------------------------------------------------- + // test SPEX_transpose + //-------------------------------------------------------------------------- + + printf("\n Test SPEX_transpose \n"); + SPEX_matrix A_mpq = NULL, A_mpfr = NULL, A_int = NULL, A_fp = NULL; + SPEX_matrix T_mpq = NULL, T_mpfr = NULL, T_int = NULL, T_fp = NULL; + // T = A' + OK ( SPEX_matrix_copy(&A_mpq, SPEX_CSC, SPEX_MPQ, A, option)); + OK ( SPEX_transpose(&T_mpq, A_mpq, option) ); + + OK ( SPEX_matrix_copy(&A_mpfr, SPEX_CSC, SPEX_MPFR, A, option)); + OK ( SPEX_transpose(&T_mpfr, A_mpfr, option) ); + + OK ( SPEX_matrix_copy(&A_int, SPEX_CSC, SPEX_INT64, A, option)); + OK ( SPEX_transpose(&T_int, A_int, option) ); + + OK ( SPEX_matrix_copy(&A_fp, SPEX_CSC, SPEX_FP64, A, option)); + OK ( SPEX_transpose(&T_fp, A_fp, option)); + + SPEX_matrix_free(&A_mpq,option); + SPEX_matrix_free(&A_mpfr,option); + SPEX_matrix_free(&A_int,option); + SPEX_matrix_free(&A_fp,option); + SPEX_matrix_free(&T_mpq,option); + SPEX_matrix_free(&T_mpfr,option); + SPEX_matrix_free(&T_int,option); + SPEX_matrix_free(&T_fp,option); + + //-------------------------------------------------------------------------- + // test spex_expand_mpfr_array + //-------------------------------------------------------------------------- + //create mpfr array where all elements are multiples of 220 + mpfr_rnd_t round = SPEX_OPTION_ROUND (option); + mpfr_t* x_mpfr = spex_create_mpfr_array (3, option); + mpz_t* x_mpz = spex_create_mpz_array (3); + mpq_t x_scale; + OK (spex_create_mpq (x_scale)); + SPEX_MPQ_SET_UI (x_scale, 1, 10); + for (int64_t k = 0 ; k < 3 ; k++) + { + SPEX_MPFR_SET_SI( x_mpfr[k],(k+2)*220, round); + } + + OK ( spex_expand_mpfr_array (x_mpz, x_mpfr, x_scale, 3, option)); + + //-------------------------------------------------------------------------- + // missing gmp coverage + //-------------------------------------------------------------------------- + mpz_t gmp_x, gmp_y, gmp_0; + mpq_t gmp_a, gmp_b, gmp_c; + mpfr_t gmp_e, gmp_f, gmp_g, gmp_h ; + uint64_t num1=2; + uint64_t num2=3; + int r; + + //Initialization + SPEX_MPZ_INIT(gmp_x); + SPEX_MPZ_INIT(gmp_y); + SPEX_MPZ_INIT(gmp_0); + + SPEX_MPQ_INIT(gmp_a); + SPEX_MPQ_INIT(gmp_b); + SPEX_MPQ_INIT(gmp_c); + + SPEX_MPFR_INIT2(gmp_e, 128); + SPEX_MPFR_INIT2(gmp_f, 128); + SPEX_MPFR_INIT2(gmp_g, 128); + SPEX_MPFR_INIT2(gmp_h, 128); + + //set values + SPEX_MPZ_SET_SI(gmp_y, -4); + SPEX_MPQ_SET_UI(gmp_b, 2, 7); + SPEX_MPFR_SET_SI(gmp_f, 10, round); + SPEX_MPFR_SET_SI(gmp_g, 7, round); + + SPEX_MPZ_SET_SI(gmp_0, 0); + + //Test + FILE *fil = fopen ("../ExampleMats/test4.mat.txt", "r"); + SPEX_gmp_fscanf(fil,"c"); + fclose (fil); + + SPEX_MPZ_ABS(gmp_x,gmp_y); + + SPEX_MPQ_SET_NUM(gmp_c,gmp_x); + + SPEX_MPQ_ABS(gmp_a,gmp_b); + + SPEX_MPQ_CMP(&r,gmp_b,gmp_a); + + SPEX_MPFR_MUL(gmp_e,gmp_f,gmp_g,round); + + SPEX_MPFR_UI_POW_UI(gmp_h,num1,num2,round); + + SPEX_MPQ_NEG(gmp_a,gmp_b); + + printf("Brutal test of SPEX_cdiv_qr: \n"); + mpz_t gmp_n,gmp_d,tmpz; + SPEX_MPZ_INIT2(gmp_n,1); + SPEX_MPZ_INIT(gmp_d); + SPEX_MPZ_INIT(tmpz); + SPEX_MPZ_SET_SI(tmpz, 1); //tmpz=1 + SPEX_MPZ_SET_SI(gmp_n, INT64_MAX); + for (int ii = 0; ii<3;ii++){ + SPEX_MPZ_MUL(gmp_n, gmp_n, gmp_n); + }// gmp_n = INT64_MAX^8 + SPEX_MPZ_SET(gmp_d, gmp_n); //gmp_d = gmp_n = INT64_MAX^8 + SPEX_MPZ_MUL(gmp_n, gmp_n, gmp_n); + SPEX_MPZ_SUB(gmp_n, gmp_n, tmpz);// gmp_n = (INT64_MAX^8)^2-1 + // we should get q = r = INT64_MAX^8-1 + BRUTAL(spex_test_cdiv_qr (gmp_n,gmp_d)); + + ERR(SPEX_mpz_cdiv_qr(gmp_x,gmp_y,gmp_n,gmp_0),SPEX_PANIC); + ERR(SPEX_mpz_divexact(gmp_x,gmp_y,gmp_0),SPEX_PANIC); + + //Free + SPEX_MPZ_CLEAR(gmp_x); + SPEX_MPZ_CLEAR(gmp_y); + SPEX_MPQ_CLEAR(gmp_a); + SPEX_MPQ_CLEAR(gmp_b); + SPEX_MPQ_CLEAR(gmp_c); + SPEX_MPFR_CLEAR(gmp_e); + SPEX_MPFR_CLEAR(gmp_f); + SPEX_MPFR_CLEAR(gmp_g); + SPEX_MPFR_CLEAR(gmp_h); + SPEX_MPZ_CLEAR(gmp_n); + SPEX_MPZ_CLEAR(gmp_d); + SPEX_MPZ_CLEAR(tmpz); + + //-------------------------------------------------------------------------- + // error handling + //-------------------------------------------------------------------------- + + // inputs cannot be NULL + ERR (SPEX_matrix_nnz (NULL, NULL, NULL), + SPEX_INCORRECT_INPUT); + ERR (SPEX_matrix_nnz (NULL, A, NULL), + SPEX_INCORRECT_INPUT); + ERR (SPEX_matrix_nnz (&anz, NULL, NULL), + SPEX_INCORRECT_INPUT); + ERR (SPEX_cholesky_analyze (NULL, NULL, NULL), + SPEX_INCORRECT_INPUT); + ERR (SPEX_cholesky_backslash (NULL, SPEX_MPQ, NULL, NULL, NULL), + SPEX_INCORRECT_INPUT); + ERR (SPEX_cholesky_factorize (NULL, NULL, NULL, NULL), + SPEX_INCORRECT_INPUT); + ERR (SPEX_determine_symmetry (NULL, NULL, NULL ), + SPEX_INCORRECT_INPUT); + + // type cannot be int64 + ERR (SPEX_cholesky_backslash (&x, SPEX_INT64, A, b, option), + SPEX_INCORRECT_INPUT); + + // mangle the matrix: invalid dimensions + A->n = 0 ; + A->m = 0 ; + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), + SPEX_INCORRECT_INPUT); + A->n = n ; + A->m = n ; + + // mangle the matrix: invalid type + A->type = SPEX_INT64 ; + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), + SPEX_INCORRECT_INPUT); + bool is_symmetric ; + ERR (SPEX_determine_symmetry (&is_symmetric, A, option), + SPEX_INCORRECT_INPUT); + A->type = SPEX_MPZ ; + + // valid analysis, but break the factorization + OK (SPEX_cholesky_analyze (&S, A, option)); + A->type = SPEX_INT64 ; + ERR (SPEX_cholesky_factorize (&F, A, S, option), + SPEX_INCORRECT_INPUT); + A->type = SPEX_MPZ ; + OK (SPEX_symbolic_analysis_free (&S, option)); + + // valid analysis and factorization, but break the solve + OK (SPEX_cholesky_analyze (&S, A, option)); + OK (SPEX_cholesky_factorize (&F, A, S, option)); + b->type = SPEX_INT64 ; + ERR (SPEX_cholesky_solve (&x, F, b, option), + SPEX_INCORRECT_INPUT); + b->type = SPEX_MPZ ; + OK (SPEX_symbolic_analysis_free (&S, option)); + OK (SPEX_factorization_free (&F, option)); + + // invalid algorithm + option->algo = 99 ; + ERR (SPEX_cholesky_backslash (&x, SPEX_MPQ, A, b, option), + SPEX_INCORRECT_ALGORITHM); + option->algo = SPEX_CHOL_UP ; + + //-------------------------------------------------------------------------- + // solve Ax=b with SPEX_cholesky_backslash and check the solution + //-------------------------------------------------------------------------- + + option->order = SPEX_AMD ; + option->algo = SPEX_CHOL_UP ; + option->print_level = 3 ; + printf ("Cholesky backslash, up-looking, no malloc testing:\n"); + OK (spex_test_chol_backslash (A, b, option)); + option->print_level = 0 ; + + printf ("Cholesky backslash, up-looking, no malloc testing, colamd:\n"); + option->order = SPEX_COLAMD ; + option->print_level = 3 ; + OK (spex_test_chol_backslash (A, b, option)); + option->order = SPEX_AMD ; + option->print_level = 0 ; + + printf ("Cholesky backslash, no malloc testing, natural ordering:\n"); + option->order = SPEX_NO_ORDERING ; + OK (spex_test_chol_backslash (A, b, option)); + + printf ("Cholesky backslash, no malloc testing, return x as MPFR:\n"); + OK (SPEX_cholesky_backslash (&x, SPEX_MPFR, A, b, option)); + //NOTE: mpfr solution can't be checked because mpfr->mpz isn't guaranteed + // to be exact + OK (SPEX_matrix_free (&x, option)); + + printf ("Cholesky backslash, up-looking with malloc testing, colamd:\n"); + option->order = SPEX_COLAMD ; + BRUTAL (spex_test_chol_backslash (A, b, option)); + + printf ("Cholesky backslash, up-looking with malloc testing, amd:\n"); + option->order = SPEX_AMD ; + BRUTAL (spex_test_chol_backslash (A, b, option)); + + printf ("Cholesky backslash, up-looking with malloc testing, " + " no ordering:\n"); + option->order = SPEX_NO_ORDERING ; + BRUTAL (spex_test_chol_backslash (A, b, option)); + + printf ("Cholesky backslash, left-looking with malloc testing:\n"); + option->algo = SPEX_CHOL_LEFT ; + BRUTAL (spex_test_chol_backslash (A, b, option)); + + //-------------------------------------------------------------------------- + // solve Ax=b with SPEX_cholesky_[analyze,factorize,solve]; check solution + //-------------------------------------------------------------------------- + + option->algo = SPEX_CHOL_UP ; + + printf ("Cholesky analyze/factorize/solve, no malloc testing:\n"); + spex_set_gmp_ntrials (INT64_MAX) ; + malloc_count = INT64_MAX ; + OK (spex_test_chol_afs (A, b, option)); + + printf ("Cholesky analyze/factorize/solve, with malloc testing:\n"); + // also check a different RHS, with b(0) = 0 + OK (SPEX_mpz_set_ui (b->x.mpz [0], 0)); + BRUTAL (spex_test_chol_afs (A, b, option)); + + //-------------------------------------------------------------------------- + // error handling + //-------------------------------------------------------------------------- + + // SPEX not initialized + spex_set_initialized (false); + ERR (SPEX_cholesky_factorize (&F2, A, S, option), SPEX_PANIC); + ERR (SPEX_cholesky_analyze (NULL, NULL, NULL), SPEX_PANIC); + ERR (SPEX_cholesky_solve (NULL, NULL, NULL, NULL), SPEX_PANIC); + ERR (SPEX_cholesky_backslash (NULL, SPEX_MPQ, NULL, NULL, NULL), + SPEX_PANIC); + spex_set_initialized (true); + SPEX_FREE_ALL; + + printf ("%s: all tests passed\n\n", __FILE__); + fprintf (stderr, "%s: all tests passed\n\n", __FILE__); + return 0; +} + diff --git a/SPEX/SPEX_Left_LU/Tcov/tcov_test.c b/SPEX/Tcov/tcov_for_lu.c similarity index 74% rename from SPEX/SPEX_Left_LU/Tcov/tcov_test.c rename to SPEX/Tcov/tcov_for_lu.c index ff8cf6d1ec..d967ac744d 100644 --- a/SPEX/SPEX_Left_LU/Tcov/tcov_test.c +++ b/SPEX/Tcov/tcov_for_lu.c @@ -1,12 +1,13 @@ -//------------------------------------------------------------------------------ -// SPEX/SPEX/SPEX_Left_LU/Tcov/tcov_test.c: test coverage for SPEX_Left_LU -//------------------------------------------------------------------------------ +// ---------------------------------------------------------------------------- +// SPEX/Tcov/tcov_for_lu.c: test coverage for SPEX_LU +// ---------------------------------------------------------------------------- -// SPEX_Left_LU: (c) 2019-2022, Chris Lourenco (US Naval Academy), Jinhao Chen, -// Erick Moreno-Centeno, Timothy A. Davis, Texas A&M. All Rights Reserved. +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. // SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later -//------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- /* * When the test is run without input argument, brutal test is used and simple @@ -18,8 +19,8 @@ * int64, 4 double. For Ab_type >= 5, it corresponds to 15 type of original * matrix A (i.e., (csc, triplet, dense) x (mpz, mpq, mpfr, int64, double)), * specifically, A->type=(Ab_type-5)%5, and A->kind=(Ab_type-5)/5. - * N and list1 specify the test list for spex_gmp_ntrials (in SPEX_gmp.h) - * M and list2 specify the test list for malloc_count (in tcov_malloc_test.h) + * N and list1 specify the test list for spex_gmp_ntrials (in SPEX_gmp.c) + * M and list2 specify the test list for malloc_count (in tcov_utilities.h) * N, list1, M, list2 are optional, but N and list1 are required when M and * list2 is wanted * @@ -36,70 +37,25 @@ */ // #define SPEX_TCOV_SHOW_LIST -/* This program will exactly solve the sparse linear system Ax = b by performing - * the SPEX Left LU factorization. Refer to README.txt for information on how - * to properly use this code. +/* This program will exactly solve the sparse linear system A*x = b by + * performing the SPEX Left LU factorization. Refer to README.txt for + * information on how to properly use this code. */ -#define SPEX_FREE_ALL \ -{ \ - /*SPEX_MPZ_CLEAR(mpz1);*/ \ - /*SPEX_MPZ_CLEAR(mpz2);*/ \ - /*SPEX_MPZ_CLEAR(mpz3);*/ \ - TEST_OK (SPEX_matrix_free(&A,option)) ; \ - TEST_OK (SPEX_matrix_free(&b, option)); \ - TEST_OK (SPEX_matrix_free(&B, option)); \ - TEST_OK (SPEX_matrix_free(&Ax, option)); \ - TEST_OK (SPEX_matrix_free(&sol, option)); \ - SPEX_FREE(option); \ - TEST_OK (SPEX_finalize()) ; \ +#define SPEX_FREE_ALL \ +{ \ + OK (SPEX_matrix_free (&A, option)); \ + OK (SPEX_matrix_free (&b, option)); \ + OK (SPEX_matrix_free (&B, option)); \ + OK (SPEX_matrix_free (&Ax, option)); \ + OK (SPEX_matrix_free (&sol, option)); \ + OK (SPEX_matrix_free (&sol_doub, option)); \ + OK (SPEX_symbolic_analysis_free (&S, option)); \ + SPEX_FREE (option); \ + OK (SPEX_finalize ()); \ } -#include "tcov_malloc_test.h" - -#define TEST_OK(method) \ -if (!pretend_to_fail) \ -{ \ - info = (method) ; assert (info == SPEX_OK) ; \ -} - -#define TEST_CHECK(method) \ -if (!pretend_to_fail) \ -{ \ - info = (method) ; \ - if (info == SPEX_OUT_OF_MEMORY) \ - { \ - SPEX_FREE_ALL; \ - pretend_to_fail = true ; \ - } \ - else if (info != SPEX_OK) \ - { \ - SPEX_PRINT_INFO (info) ; \ - printf ("test failure at line %d\n", __LINE__) ; \ - abort ( ) ; \ - } \ -} - -#define TEST_CHECK_FAILURE(method,expected_error) \ -if (!pretend_to_fail) \ -{ \ - info = (method) ; \ - if (info == SPEX_OUT_OF_MEMORY) \ - { \ - SPEX_FREE_ALL; \ - pretend_to_fail = true ; \ - } \ - else if (info != expected_error) \ - { \ - printf ("SPEX method was expected to fail, but succeeded!\n") ; \ - printf ("this error was expected:\n") ; \ - SPEX_PRINT_INFO (expected_error) ; \ - printf ("but this error was obtained:\n") ; \ - SPEX_PRINT_INFO (info) ; \ - printf ("test failure at line %d (wrong error)\n", __LINE__) ; \ - abort ( ) ; \ - } \ -} +#include "tcov_utilities.h" #define MAX_MALLOC_COUNT 1000 @@ -114,35 +70,51 @@ int64_t Axden3[11] = {3, 3, 6, 1, 7, 1, 1, 1, 5, 1, 1}; // Denominator of x int64_t bxnum3[4] = {17, 182, 61, 67}; // Numerator of b int64_t bxden3[4] = {15, 3, 6, 7}; // Denominator of b -#include -#include - -int main( int argc, char* argv[]) +int main ( int argc, char *argv[]) { - bool IS_SIMPLE_TEST = true; + bool is_simple_test = true; int Ab_type = 0; int64_t malloc_count_list[20]= { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; - int64_t NUM_OF_TRIALS = 0 ; - int64_t NUM_OF_MALLOC_T = 0; + int64_t num_of_trials = 0 ; + int64_t num_of_malloc_t = 0; int64_t *gmp_ntrial_list=NULL; // only used in simple test int64_t *malloc_trials_list=NULL; // only used in simple test bool pretend_to_fail = false ; + //------------------------------------------------------------------ + // Define variables + //------------------------------------------------------------------ + + // used in as source in different Ab_type for A and b + SPEX_matrix B = NULL ; + SPEX_matrix Ax = NULL ; + + // matrix A, b and solution + SPEX_matrix A = NULL ; + SPEX_matrix b = NULL ; + SPEX_matrix sol = NULL ; + SPEX_matrix sol_doub = NULL ; + + // Column permutation + SPEX_symbolic_analysis S = NULL ; + + SPEX_options option = NULL ; + //-------------------------------------------------------------------------- // parse input arguments //-------------------------------------------------------------------------- if (argc == 1) // brutal test { - IS_SIMPLE_TEST = false; - NUM_OF_TRIALS = 20; + is_simple_test = false; + num_of_trials = 20; } else // simple test { - IS_SIMPLE_TEST = true; + is_simple_test = true; int64_t arg_count = 0; // type of Matrix A and vector b: @@ -150,16 +122,16 @@ int main( int argc, char* argv[]) Ab_type = atoi(argv[++arg_count]); if (!argv[++arg_count]) { - NUM_OF_TRIALS=1; - gmp_ntrial_list= malloc (NUM_OF_TRIALS* sizeof(int64_t)); + num_of_trials=1; + gmp_ntrial_list= malloc (num_of_trials* sizeof(int64_t)); gmp_ntrial_list[0]=-1; arg_count--; } else { - NUM_OF_TRIALS=atoi(argv[arg_count]); - gmp_ntrial_list= malloc (NUM_OF_TRIALS* sizeof(int64_t)); - for (int64_t k=0; k0 at the end of inner loop. - for (int64_t k=0; kprint_level = 3; @@ -325,12 +300,16 @@ int main( int argc, char* argv[]) // Solve A*x=b where A and b are created from mpz entries //-------------------------------------------------------------- + TEST_ASSERT (B == NULL); + TEST_ASSERT (Ax == NULL); TEST_CHECK(SPEX_matrix_allocate(&B, SPEX_DENSE, (SPEX_type) Ab_type, n, numRHS, n*numRHS, false, true, option)); if (pretend_to_fail) continue ; + TEST_CHECK(SPEX_matrix_allocate(&Ax, SPEX_CSC, (SPEX_type) Ab_type, n, n, nz, false, true, option)); + if (pretend_to_fail) continue ; // fill Ax->i and Ax->p @@ -348,36 +327,40 @@ int main( int argc, char* argv[]) { // create empty A and b using uninitialized double mat/array // to trigger all-zero array condition + TEST_ASSERT (A == NULL); + TEST_ASSERT (b == NULL); + TEST_ASSERT (sol == NULL); TEST_CHECK(SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, Ax, option)); if (pretend_to_fail) continue ; TEST_CHECK(SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, B, option)); if (pretend_to_fail) continue ; - // to trigger SPEX_SINGULAR - TEST_CHECK_FAILURE(SPEX_Left_LU_backslash(&sol, SPEX_MPQ, A, + // to trigger SPEX_SINGULAR + TEST_CHECK_FAILURE(SPEX_lu_backslash(&sol, SPEX_MPQ, A, b, option), SPEX_SINGULAR); if (pretend_to_fail) continue ; option->pivot = SPEX_LARGEST; - TEST_CHECK_FAILURE(SPEX_Left_LU_backslash(&sol, SPEX_MPQ, A, + TEST_CHECK_FAILURE(SPEX_lu_backslash(&sol, SPEX_MPQ, A, b, option), SPEX_SINGULAR); if (pretend_to_fail) continue ; option->pivot = SPEX_FIRST_NONZERO; - TEST_CHECK_FAILURE(SPEX_Left_LU_backslash(&sol, SPEX_MPQ, A, + TEST_CHECK_FAILURE(SPEX_lu_backslash(&sol, SPEX_MPQ, A, b, option), SPEX_SINGULAR); if (pretend_to_fail) continue ; //free the memory alloc'd - TEST_OK (SPEX_matrix_free (&A, option)) ; - if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&b, option)) ; - if (pretend_to_fail) continue ; + OK (SPEX_matrix_free (&A, option)); + OK (SPEX_matrix_free (&b, option)); + TEST_ASSERT (A == NULL); + TEST_ASSERT (b == NULL); + TEST_ASSERT (sol == NULL); // trigger gcd == 1 int32_t prec = option->prec; option->prec = 17; double pow2_17 = pow(2,17); - assert (B != NULL) ; + TEST_ASSERT (B != NULL); for (j = 0; j < n && !pretend_to_fail; j++) // Get B { TEST_CHECK(SPEX_mpfr_set_d(SPEX_2D(B,j,0,mpfr), @@ -387,8 +370,8 @@ int main( int argc, char* argv[]) TEST_CHECK(SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ,B, option)); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&b, option)) ; - if (pretend_to_fail) continue ; + OK (SPEX_matrix_free (&b, option)); + TEST_ASSERT (b == NULL); // restore default precision option->prec = prec; @@ -400,23 +383,26 @@ int main( int argc, char* argv[]) { // create empty A using uninitialized double mat/array // to trigger all-zero array condition - assert (Ax!= NULL) ; + TEST_ASSERT (Ax != NULL); + TEST_ASSERT (A == NULL); TEST_CHECK(SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, Ax, option)); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&A, option)) ; - if (pretend_to_fail) continue ; + OK (SPEX_matrix_free (&A, option)); + TEST_ASSERT (A == NULL); // trigger gcd == 1 - assert (B != NULL) ; + TEST_ASSERT (B != NULL); for (j = 0; j < n; j++) // Get b { SPEX_2D(B,j,0,fp64) = bxnum[j]/1e17; } + TEST_ASSERT (b == NULL); TEST_CHECK(SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ, B, option)); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&b, option)) ; + OK (SPEX_matrix_free (&b, option)); + TEST_ASSERT (b == NULL); if (pretend_to_fail) continue ; // use smallest entry as pivot @@ -426,7 +412,7 @@ int main( int argc, char* argv[]) // fill Ax->x and b->x for (j = 0; j < n && !pretend_to_fail; j++) // Get b { - assert (B != NULL) ; + TEST_ASSERT (B != NULL); if (Ab_type == 0) //MPZ { TEST_CHECK(SPEX_mpz_set_ui(SPEX_2D(B, j, 0, mpz), @@ -461,7 +447,7 @@ int main( int argc, char* argv[]) for (j = 0; j < nz; j++) // Get Ax { - assert (Ax!= NULL) ; + TEST_ASSERT (Ax != NULL); if (Ab_type == 0) { TEST_CHECK(SPEX_mpz_set_ui(Ax->x.mpz[j],Axnum3[j])); @@ -494,13 +480,16 @@ int main( int argc, char* argv[]) if (pretend_to_fail) continue ; // successful case + TEST_ASSERT (A == NULL); + TEST_ASSERT (b == NULL); TEST_CHECK(SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, Ax,option)); if (pretend_to_fail) continue ; TEST_CHECK(SPEX_matrix_copy(&b, SPEX_DENSE, SPEX_MPZ,B,option)); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free(&B, option)); - if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free(&Ax, option)); + OK (SPEX_matrix_free(&B, option)); + OK (SPEX_matrix_free(&Ax, option)); + TEST_ASSERT (Ax == NULL); + TEST_ASSERT (B == NULL); if (pretend_to_fail) continue ; } else // 5 =< Ab_type < 20 @@ -530,7 +519,7 @@ int main( int argc, char* argv[]) double x_doub2[11] = {1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4}; int64_t x_int64[11] = {1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4}; - + // find the type and kind of the source matrix to copy from Ab_type = Ab_type > 19 ? 19:Ab_type; int tk = Ab_type-5; @@ -548,6 +537,7 @@ int main( int argc, char* argv[]) n1 = 1; nz1 = nz1; } + TEST_ASSERT (Ax == NULL); TEST_CHECK(SPEX_matrix_allocate(&Ax, (SPEX_kind) kind, (SPEX_type)type, m1, n1, nz1, false, true, option)); if (pretend_to_fail) continue ; @@ -565,7 +555,7 @@ int main( int argc, char* argv[]) // fill Ax->i and Ax->j for (j = 0; j < nz && !pretend_to_fail ; j++) { - assert(Ax != NULL); + TEST_ASSERT(Ax != NULL); if (kind != 2) {Ax->i[j] = I[j];} // triplet if (kind == 1){ Ax->j[j] = J[j];} @@ -617,11 +607,6 @@ int main( int argc, char* argv[]) TEST_CHECK (SPEX_matrix_check (Ax, option)); if (pretend_to_fail) continue ; - /*if (kind == 0) // CSC - { - TEST_CHECK (SPEX_determine_symmetry(Ax, true)); - }*/ - // convert to all different type of matrix for (int tk1 = 0; tk1 < 15 && !pretend_to_fail; tk1++) { @@ -635,8 +620,9 @@ int main( int argc, char* argv[]) "double",type, kind1 < 1 ? "CSC" : kind1 < 2 ? "Triplet" : "Dense", kind1,type1 < 1 ? "MPZ" : type1 < 2 ? "MPQ" : type1 < 3 ? "MPFR" : type1 < 4 - ? "int64" : "double",type1) ; + ? "int64" : "double",type1); + TEST_ASSERT (A == NULL); TEST_CHECK(SPEX_matrix_copy(&A, (SPEX_kind)kind1, (SPEX_type) type1, Ax, option)); if (pretend_to_fail) break ; @@ -647,30 +633,31 @@ int main( int argc, char* argv[]) // just perform once to try some failure cases if (tk == 0 && tk1 == 0) { - // fail SPEX_Left_LU_solve + // fail SPEX_lu_solve + TEST_ASSERT (b == NULL); TEST_CHECK(SPEX_matrix_allocate(&b, SPEX_DENSE, SPEX_MPZ, 1, 1, 1, true, true, option)); if (pretend_to_fail) break ; - TEST_CHECK_FAILURE(SPEX_Left_LU_solve(NULL, b, A, A, A, - b, NULL, NULL, option), SPEX_INCORRECT_INPUT); - if (pretend_to_fail) break ; - TEST_OK (SPEX_matrix_free (&b, option)) ; - if (pretend_to_fail) break ; + TEST_CHECK_FAILURE(SPEX_lu_solve(NULL, NULL, + b, option), SPEX_INCORRECT_INPUT); + OK (SPEX_matrix_free (&b, option)); + TEST_ASSERT (b == NULL); } else if (tk == 0 && (tk1 == 1 || tk1 == 2 || tk1 == 4)) { // test SPEX_matrix_copy with scale - TEST_OK (SPEX_matrix_free (&A, option)) ; + OK (SPEX_matrix_free (&A, option)); + TEST_ASSERT (A == NULL); if (pretend_to_fail) break ; - TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 2, 5)) ; + TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 2, 5)); if (pretend_to_fail) break ; TEST_CHECK(SPEX_matrix_copy(&A, (SPEX_kind)kind1, (SPEX_type) type1, Ax, option)); if (pretend_to_fail) break ; - TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 1, 1)) ; + TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 1, 1)); if (pretend_to_fail) break ; } - else if (tk == 0 && tk1 == 3)//A = CSC int64 + else if (tk == 0 && tk1 == 3) //A is CSC int64 { // test SPEX_matrix_check A->i[0] = -1; @@ -707,34 +694,34 @@ int main( int argc, char* argv[]) if (pretend_to_fail) break ; // Incorrect calling with NULL pointer(s) - TEST_CHECK_FAILURE(SPEX_LU_analyze(NULL,A,NULL), + TEST_CHECK_FAILURE(SPEX_lu_analyze(NULL,A,NULL), SPEX_INCORRECT_INPUT); if (pretend_to_fail) break ; // test SPEX_matrix_copy with scale - TEST_OK (SPEX_matrix_free (&A, option)) ; + OK (SPEX_matrix_free (&A, option)); if (pretend_to_fail) break ; - TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 5, 2)) ; + TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 5, 2)); if (pretend_to_fail) break ; TEST_CHECK(SPEX_matrix_copy(&A, (SPEX_kind)kind1, (SPEX_type) type1, Ax, option)); if (pretend_to_fail) break ; - TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 1, 1)) ; + TEST_CHECK (SPEX_mpq_set_ui (Ax->scale, 1, 1)); if (pretend_to_fail) break ; } else if (tk == 0 && tk1 == 8) // A= Triplet int64 { // test SPEX_matrix_check A->i[0] = -1; - TEST_CHECK_FAILURE(SPEX_matrix_check(A, option), + TEST_CHECK_FAILURE(SPEX_matrix_check(A, option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) break ; SPEX_FREE(A->x.int64); - TEST_CHECK_FAILURE(SPEX_matrix_check(A, option), + TEST_CHECK_FAILURE(SPEX_matrix_check(A, option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) break ; A->n = -1; - TEST_CHECK_FAILURE(SPEX_matrix_check(A, option), + TEST_CHECK_FAILURE(SPEX_matrix_check(A, option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) break ; } @@ -748,7 +735,7 @@ int main( int argc, char* argv[]) else if (tk == 4 && tk1 == 3)// converting double to int64 { // test spex_cast_array - TEST_OK (SPEX_matrix_free (&A, option)) ; + OK (SPEX_matrix_free (&A, option)); if (pretend_to_fail) break ; Ax->x.fp64[0] = 0.0/0.0;//NAN Ax->x.fp64[1] = DBL_MAX; //a value > INT64_MAX; @@ -761,7 +748,7 @@ int main( int argc, char* argv[]) Ax->x.fp64[1] = x_doub2[1]; Ax->x.fp64[2] = x_doub2[2]; } - TEST_OK (SPEX_matrix_free (&A, option)) ; + OK (SPEX_matrix_free (&A, option)); if (pretend_to_fail) break ; } if (pretend_to_fail) continue; @@ -769,11 +756,13 @@ int main( int argc, char* argv[]) if (tk == 3) { // fail SPEX_matrix_copy + TEST_ASSERT (A == NULL); TEST_CHECK_FAILURE(SPEX_matrix_copy(&A, 7, (SPEX_type) type, Ax, option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; // failure case: Ax->x = NULL SPEX_FREE(Ax->x.int64); + TEST_ASSERT (A == NULL); TEST_CHECK_FAILURE(SPEX_matrix_copy(&A, SPEX_CSC, SPEX_MPZ, Ax,option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; @@ -783,21 +772,24 @@ int main( int argc, char* argv[]) SPEX_DENSE, SPEX_MPZ, 1, 1, 1, true, true, option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; + TEST_ASSERT (b == NULL); TEST_CHECK_FAILURE(SPEX_matrix_allocate(&b, SPEX_DENSE, SPEX_MPZ, -1, 1, 1, true, true, option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; // test SPEX_matrix_allocate + TEST_ASSERT (b == NULL); TEST_CHECK(SPEX_matrix_allocate(&b, SPEX_DENSE, SPEX_MPQ, 1, 1, 1, false, false, option)); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&b, option)) ; - if (pretend_to_fail) continue ; + OK (SPEX_matrix_free (&b, option)); + TEST_ASSERT (b == NULL); TEST_CHECK(SPEX_matrix_allocate(&b, SPEX_DENSE, SPEX_MPFR, 1, 1, 1, false, false, option)); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&b, option)) ; + OK (SPEX_matrix_free (&b, option)); + TEST_ASSERT (b == NULL); if (pretend_to_fail) continue ; //test coverage for spex_gmp_reallocate() @@ -812,46 +804,47 @@ int main( int argc, char* argv[]) // test SPEX_matrix_check on a triplet matrix with bad triplets //-------------------------------------------------------------- - printf ("\n[ SPEX_matrix_check -------------------------\n") ; - TEST_OK (SPEX_matrix_free (&A, option)) ; - if (pretend_to_fail) continue ; +// printf ("\n[ SPEX_matrix_check -------------------------\n"); + OK (SPEX_matrix_free (&A, option)); int64_t I2 [4] = { 1, 2, 1, 1 } ; int64_t J2 [4] = { 1, 0, 0, 1 } ; + TEST_ASSERT (A == NULL); TEST_CHECK (SPEX_matrix_allocate (&A, SPEX_TRIPLET, - SPEX_INT64, 3, 3, 4, true, false, option)) ; + SPEX_INT64, 3, 3, 4, true, false, option)); if (pretend_to_fail) continue ; A->i = I2 ; A->j = J2 ; A->x.int64 = I2 ; A->nz = 4 ; - printf ("invalid triplet matrix expected:\n") ; +// printf ("invalid triplet matrix expected:\n"); TEST_CHECK_FAILURE (SPEX_matrix_check (A, option), - SPEX_INCORRECT_INPUT) ; - if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&A, option)) ; + SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; + OK (SPEX_matrix_free (&A, option)); + TEST_ASSERT (A == NULL); TEST_CHECK (SPEX_matrix_allocate (&A, SPEX_CSC, - SPEX_INT64, 3, 3, 4, true, false, option)) ; + SPEX_INT64, 3, 3, 4, true, false, option)); if (pretend_to_fail) continue ; int64_t P3 [4] = { 0, 2, 4, 4 } ; int64_t I3 [4] = { 0, 0, 0, 0 } ; A->p = P3 ; A->i = I3 ; A->x.int64 = I3 ; - printf ("invalid CSC matrix expected:\n") ; +// printf ("invalid CSC matrix expected:\n"); TEST_CHECK_FAILURE (SPEX_matrix_check (A, option), - SPEX_INCORRECT_INPUT) ; + SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free (&A, option)) ; - printf ("-----------------------------------------------]\n") ; + OK (SPEX_matrix_free (&A, option)); + TEST_ASSERT (A == NULL); +// printf ("-----------------------------------------------]\n"); //-------------------------------------------------------------- SPEX_FREE_ALL; // for miscellaneous test, continue to next loop directly - if (!IS_SIMPLE_TEST) + if (!is_simple_test) { if (malloc_count > 0) { @@ -868,23 +861,23 @@ int main( int argc, char* argv[]) if (Ab_type%2 == 0) { + //-------------------------------------------------------------- // SPEX Left LU backslash // solve Ax=b in full precision rational arithmetic //-------------------------------------------------------------- - TEST_CHECK(SPEX_Left_LU_backslash(&sol, SPEX_MPQ, A, b,option)); + + TEST_ASSERT (sol == NULL); + TEST_CHECK(SPEX_lu_backslash(&sol, SPEX_MPQ, A, b,option)); if (pretend_to_fail) continue ; - if (Ab_type == 4) - { - // This would return SPEX_INCORRECT since sol has been - // scaled down so that sol->scale = 1. Therefore sol is - // solution for original unscaled Ax=b, while this is - // checking if x is the solution for scaled Ax=b - TEST_CHECK_FAILURE(SPEX_check_solution(A, sol, b, option), - SPEX_INCORRECT); - if (pretend_to_fail) continue ; - } + // perform solution check if user wish to do so + bool Is_correct; + TEST_CHECK(spex_check_solution(&Is_correct, A, sol, b, option)); + if (pretend_to_fail) continue ; + OK (SPEX_matrix_free(&sol, option)); + TEST_ASSERT (sol == NULL); + if (pretend_to_fail) continue ; } else @@ -893,24 +886,27 @@ int main( int argc, char* argv[]) // SPEX Left LU backslash // solve Ax=b in double precision //-------------------------------------------------------------- - SPEX_matrix *sol_doub; - TEST_CHECK(SPEX_Left_LU_backslash(&sol_doub, SPEX_FP64, A, b, + + TEST_ASSERT (sol_doub == NULL); + TEST_CHECK(SPEX_lu_backslash(&sol_doub, SPEX_FP64, A, b, option)); if (pretend_to_fail) continue ; - TEST_OK (SPEX_matrix_free(&sol_doub, option)); + OK (SPEX_matrix_free(&sol_doub, option)); + TEST_ASSERT (sol_doub == NULL); // failure case if (Ab_type == 1) { - TEST_CHECK_FAILURE(SPEX_Left_LU_factorize(NULL, NULL, - NULL, NULL, A, NULL, NULL), SPEX_INCORRECT_INPUT); + TEST_CHECK_FAILURE(SPEX_lu_factorize(NULL, + A, NULL, NULL), SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; // incorrect solution type - TEST_CHECK_FAILURE(SPEX_Left_LU_backslash(&sol, SPEX_MPZ, + TEST_CHECK_FAILURE(SPEX_lu_backslash(&sol, SPEX_MPZ, A, b, option), SPEX_INCORRECT_INPUT); + TEST_ASSERT (sol == NULL); if (pretend_to_fail) continue ; // NULL solution pointer - TEST_CHECK_FAILURE(SPEX_Left_LU_backslash(NULL, SPEX_MPZ, + TEST_CHECK_FAILURE(SPEX_lu_backslash(NULL, SPEX_MPZ, A, b, option), SPEX_INCORRECT_INPUT); if (pretend_to_fail) continue ; // invalid kind @@ -923,14 +919,51 @@ int main( int argc, char* argv[]) } } + //------------------------------------------------------------------ + // test SPEX_lu_analyze + //------------------------------------------------------------------ + if (A != NULL && option != NULL) + { + SPEX_preorder saved_order = option->order; + option->order = SPEX_NO_ORDERING; + TEST_ASSERT (S == NULL); + TEST_CHECK(SPEX_lu_analyze(&S, A, option)); + if (pretend_to_fail) continue ; + if (option != NULL) option->order = saved_order; + } + + //------------------------------------------------------------------ + // test spex_amd and spex_colamd + //------------------------------------------------------------------ + + int64_t *ignore = NULL, nnz = 0 ; + + if (A != NULL) + { + int64_t nsave = A->n ; + A->n = -1 ; + TEST_CHECK_FAILURE (spex_amd (&ignore, &nnz, A, NULL), + SPEX_INCORRECT_INPUT); + if (pretend_to_fail) continue ; + if (A != NULL) A->n = nsave ; + } + + if (A != NULL) + { + A->p [0] = 1 ; + TEST_CHECK_FAILURE (spex_colamd (&ignore, &nnz, A, NULL), + SPEX_INCORRECT_INPUT); + if (pretend_to_fail) continue ; + if (A != NULL) A->p [0] = 0 ; + } + //------------------------------------------------------------------ // Free Memory //------------------------------------------------------------------ SPEX_FREE_ALL; - if(!IS_SIMPLE_TEST) + if(!is_simple_test) { - printf("im here %ld\n",malloc_count); if (malloc_count > 0) { malloc_count_list[k] = kk; @@ -945,11 +978,11 @@ int main( int argc, char* argv[]) // wrapup //-------------------------------------------------------------------------- - if (IS_SIMPLE_TEST) + if (is_simple_test) { free(gmp_ntrial_list); free(malloc_trials_list); - printf ("tests finished\n") ; + printf ("\nSPEX LU tests finished, tests passed\n"); } else { @@ -958,9 +991,11 @@ int main( int argc, char* argv[]) { printf("%ld ", malloc_count_list[i]); } - printf("\nbrutal tests finished\n"); + printf("\nSPEX LU: brutal tests finished, tests passed\n"); } + printf ("%s: all tests passed\n\n", __FILE__); + fprintf (stderr, "%s: all tests passed\n\n", __FILE__); return 0; } diff --git a/SPEX/Tcov/tcov_for_lu2.c b/SPEX/Tcov/tcov_for_lu2.c new file mode 100644 index 0000000000..673aeb366b --- /dev/null +++ b/SPEX/Tcov/tcov_for_lu2.c @@ -0,0 +1,183 @@ +// ---------------------------------------------------------------------------- +// SPEX/Tcov/tcov_for_lu2.c: test coverage for SPEX_Cholesky +// ---------------------------------------------------------------------------- + +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//----------------------------------------------------------------------------- + +/* This program will cover what isn't covered by tcov_for_lu + */ + +#include "tcov_utilities.h" +#include "spex_demos.h" + +// test wrapper for SPEX_* function when expected error would produce +#define ERR(method,expected_error) \ +{ \ + SPEX_info info5 = (method) ; \ + if (info5 != expected_error) \ + { \ + printf ("SPEX method was expected to fail, but succeeded!\n") ; \ + printf ("this error was expected:\n") ; \ + SPEX_PRINT_INFO (expected_error) ; \ + printf ("but this error was obtained:\n") ; \ + TEST_ABORT (info5) ; \ + } \ +} +//------------------------------------------------------------------------------ +// read_test_matrix: read in a matrix from a file +//------------------------------------------------------------------------------ + +void read_test_matrix (SPEX_matrix *A_handle, char *filename); + +void read_test_matrix (SPEX_matrix *A_handle, char *filename) +{ + FILE *f = fopen (filename, "r"); + OK (f == NULL ? SPEX_PANIC : SPEX_OK); + OK (spex_demo_tripread (A_handle, f, SPEX_FP64, NULL)); + fclose (f); +} + +//------------------------------------------------------------------------------ +// create_test_rhs: create a right-hand-side vector +//------------------------------------------------------------------------------ + +void create_test_rhs (SPEX_matrix *b_handle, int64_t n); + +void create_test_rhs (SPEX_matrix *b_handle, int64_t n) +{ + OK (SPEX_matrix_allocate (b_handle, SPEX_DENSE, SPEX_MPZ, n, 1, n, false, + true, NULL)); + SPEX_matrix b = *(b_handle); + // b(0)=0 + OK (SPEX_mpz_set_ui (b->x.mpz [0], 0)); + for (int64_t k = 1 ; k < n ; k++) + { + // b(k) = 1 + OK (SPEX_mpz_set_ui (b->x.mpz [k], 1)); + } +} + + +//------------------------------------------------------------------------------ +// spex_test_lu_backslash: test SPEX_lu_backslash +//------------------------------------------------------------------------------ + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL \ +{ \ + OK (SPEX_matrix_free (&x, option)); \ +} + +SPEX_info spex_test_lu_backslash (SPEX_matrix A, SPEX_matrix b, + SPEX_options option); + +SPEX_info spex_test_lu_backslash (SPEX_matrix A, SPEX_matrix b, + SPEX_options option) +{ + SPEX_matrix x = NULL ; + // solve Ax=b + OK2 (SPEX_lu_backslash (&x, SPEX_MPQ, A, b, option)); + // disable memory testing when checking the solution + int64_t save = malloc_count ; malloc_count = INT64_MAX ; + OK (spex_demo_check_solution (A, x, b, option)); + // re-enable memory testing + malloc_count = save ; + SPEX_FREE_ALL; + return (SPEX_OK) ; +} + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL \ +{ \ + OK (SPEX_matrix_free (&A, option)); \ + OK (SPEX_matrix_free (&b, option)); \ + OK (SPEX_matrix_free (&x, option)); \ + OK (SPEX_symbolic_analysis_free(&S, option)) \ +} + + +int main (int argc, char *argv []) +{ + + //-------------------------------------------------------------------------- + // start SPEX + //-------------------------------------------------------------------------- + + SPEX_matrix A = NULL, b = NULL, x = NULL ; + SPEX_symbolic_analysis S = NULL ; + //SPEX_factorization F = NULL, F2 = NULL ; + SPEX_options option = NULL ; + + if (argc < 2) + { + printf ("usage: tcov_for_cholesky matrixfilename\n"); + TEST_ABORT (SPEX_INCORRECT_INPUT); + } + + OK (SPEX_initialize_expert (tcov_malloc, tcov_calloc, tcov_realloc, + tcov_free)); + + // disable malloc testing for the first part of the test + spex_set_gmp_ntrials (INT64_MAX) ; + malloc_count = INT64_MAX ; + + OK (SPEX_create_default_options (&option)); + + + //-------------------------------------------------------------------------- + // load the test matrix and create the right-hand-side + //-------------------------------------------------------------------------- + + read_test_matrix (&A, argv [1]); + int64_t n = A->n ; + int64_t m = A->m ; + int64_t anz = -1 ; + OK (SPEX_matrix_nnz (&anz, A, option)); + printf ("\nInput matrix: %ld-by-%ld with %ld entries\n", n, m, anz); + OK ((n != m) ? SPEX_PANIC : SPEX_OK); + create_test_rhs (&b, A->n); + + + //TESTS + option->pivot = SPEX_TOL_LARGEST; + option->order = SPEX_AMD ; + option->print_level = 3 ; + printf ("LU backslash, AMD ordering, no malloc testing:\n"); + OK (spex_test_lu_backslash (A, b, option)); + option->print_level = 0 ; + + option->pivot = SPEX_FIRST_NONZERO ; + option->order = SPEX_COLAMD ; + option->print_level = 3 ; + printf ("LU backslash, AMD ordering, no malloc testing:\n"); + OK (spex_test_lu_backslash (A, b, option)); + option->print_level = 0 ; + + option->pivot = SPEX_TOL_SMALLEST ; + option->tol = 0; + option->order = SPEX_COLAMD ; + option->print_level = 3 ; + printf ("LU backslash, AMD ordering, no malloc testing:\n"); + OK (spex_test_lu_backslash (A, b, option)); + option->print_level = 0 ; + + OK (SPEX_matrix_free (&A, option)); + OK (SPEX_matrix_free (&b, option)); + + option->order = SPEX_AMD ; + read_test_matrix (&A, "../ExampleMats/test1.mat.txt"); + OK (SPEX_lu_analyze( &S, A, option)); + OK (SPEX_symbolic_analysis_free(&S, option)); + OK (SPEX_matrix_free (&A, option)); + + read_test_matrix (&A, "../ExampleMats/test5.mat.txt"); + SPEX_lu_analyze( &S, A, option); + + SPEX_FREE_ALL; + +} diff --git a/SPEX/Tcov/tcov_utilities.c b/SPEX/Tcov/tcov_utilities.c new file mode 100644 index 0000000000..6c3ee5f16d --- /dev/null +++ b/SPEX/Tcov/tcov_utilities.c @@ -0,0 +1,245 @@ +// ---------------------------------------------------------------------------- +// SPEX/Tcov/tcov_utilities.c: utility functions for tcov tests +// ---------------------------------------------------------------------------- + +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//----------------------------------------------------------------------------- + +#include "tcov_utilities.h" + +//----------------------------------------------------------------------------- +// tcov malloc/calloc/realloc/free wrappers +//----------------------------------------------------------------------------- + +int64_t malloc_count = INT64_MAX ; + +// Note that only the ANSI C memory manager is used here +// (malloc, calloc, realloc, free) + +// wrapper for malloc +void *tcov_malloc +( + size_t size // Size to alloc +) +{ + if (--malloc_count < 0) + { + /* pretend to fail */ + return (NULL); + } + return (malloc (size)); +} + +// wrapper for calloc +void *tcov_calloc +( + size_t n, // Size of array + size_t size // Size to alloc +) +{ + if (--malloc_count < 0) + { + /* pretend to fail */ + return (NULL); + } + // ensure at least one byte is calloc'd + return (calloc (n, size)); +} + +// wrapper for realloc +void *tcov_realloc +( + void *p, // Pointer to be realloced + size_t new_size // Size to alloc +) +{ + if (--malloc_count < 0) + { + /* pretend to fail */ + return (NULL); + } + return (realloc (p, new_size)); +} + +// wrapper for free +void tcov_free +( + void *p // Pointer to be free +) +{ + // This not really needed, but placed here anyway in case the Tcov tests + // want to do something different that free(p) in the future. + free (p); +} + +//----------------------------------------------------------------------------- +// test for spex_gmp_realloc +//----------------------------------------------------------------------------- + +int spex_gmp_realloc_test +( + void **p_new, + void * p_old, + size_t old_size, + size_t new_size +) +{ + TEST_ASSERT (spex_initialized ( )); + + // get the spex_gmp object for this thread + spex_gmp_t *spex_gmp = spex_gmp_get ( ); + TEST_ASSERT (spex_gmp != NULL); + int status = setjmp (spex_gmp->environment); + if (status != 0) + { + return (SPEX_OUT_OF_MEMORY); + } + *p_new = spex_gmp_reallocate (p_old, old_size, new_size); + return (SPEX_OK); +} + +//------------------------------------------------------------------------------ +// spex_check_solution: check solution to Ax=b +//------------------------------------------------------------------------------ + +/* Purpose: Given a solution vector x, check the solution of the linear system + * Ax = b. This is done by computing a rational-arthmetic A*x == b. This + * function is provided here only used for debugging purposes, as the routines + * within SPEX are gauranteed to be exact. + */ + +#undef SPEX_FREE_ALL +#define SPEX_FREE_ALL \ + SPEX_MPQ_CLEAR(temp); \ + SPEX_MPQ_CLEAR(scale); \ + SPEX_matrix_free(&b2, NULL); + +SPEX_info spex_check_solution +( + // output + bool *Is_correct, // true, if the solution is correct + // input + const SPEX_matrix A, // Input matrix of CSC MPZ + const SPEX_matrix x, // Solution vectors + const SPEX_matrix b, // Right hand side vectors + const SPEX_options option // Command options +) +{ + if (!spex_initialized ( )) return (SPEX_PANIC); + + //-------------------------------------------------------------------------- + // check inputs. Input are also checked by the two callers + //-------------------------------------------------------------------------- + + SPEX_info info ; + SPEX_REQUIRE (A, SPEX_CSC, SPEX_MPZ); + SPEX_REQUIRE (x, SPEX_DENSE, SPEX_MPQ); + SPEX_REQUIRE (b, SPEX_DENSE, SPEX_MPZ); + + //-------------------------------------------------------------------------- + // Declare vars + //-------------------------------------------------------------------------- + + int64_t p, j, i ; + SPEX_matrix b2 = NULL; // b2 stores the solution of A*x + mpq_t temp; SPEX_MPQ_SET_NULL(temp); + mpq_t scale; SPEX_MPQ_SET_NULL(scale); + + SPEX_MPQ_INIT(temp); + SPEX_MPQ_INIT(scale); + SPEX_CHECK (SPEX_matrix_allocate(&b2, SPEX_DENSE, SPEX_MPQ, b->m, b->n, + b->nzmax, false, true, option)); + + //-------------------------------------------------------------------------- + // perform SPEX_mpq_addmul in loops to compute b2 = A'*x, where A' is the + // scaled matrix with all entries in integer + //-------------------------------------------------------------------------- + + for (j = 0; j < b->n; j++) + { + for (i = 0; i < b->m; i++) + { + for (p = A->p[i]; p < A->p[i + 1]; p++) + { + // temp = A[p][i] (note this must be done seperately since A is + // mpz and temp is mpq) + SPEX_MPQ_SET_Z(temp, A->x.mpz[p]); + + // temp = temp*x[i] + SPEX_MPQ_MUL(temp, temp, + SPEX_2D(x, i, j, mpq)); + + // b2[p] = b2[p]-temp + SPEX_MPQ_ADD(SPEX_2D(b2, A->i[p], j, mpq), + SPEX_2D(b2, A->i[p], j, mpq),temp); + } + } + } + + //-------------------------------------------------------------------------- + // Apply scales of A and b to b2 before comparing the b2 with scaled b' + //-------------------------------------------------------------------------- + + SPEX_MPQ_DIV(scale, b->scale, A->scale); + + // Apply scaling factor, but ONLY if it is not 1 + int r; + SPEX_MPQ_CMP_UI(&r, scale, 1, 1); + if (r != 0) + { + for (i = 0; i < b2->m*b2->n; i++) + { + SPEX_MPQ_MUL(b2->x.mpq[i], b2->x.mpq[i], scale); + } + } + + //-------------------------------------------------------------------------- + // check if b==b2 + //-------------------------------------------------------------------------- + *Is_correct = true; + for (j = 0; j < b->n; j++) + { + for (i = 0; i < b->m; i++) + { + // temp = b[i] (correct b) + SPEX_MPQ_SET_Z(temp, SPEX_2D(b, i, j, mpz)); + + // set check false if b!=b2 + SPEX_MPQ_EQUAL(&r, temp, SPEX_2D(b2, i, j, mpq)); + if (r == 0) + { + *Is_correct = false; + j = b->n; + break; + } + } + } + + //-------------------------------------------------------------------------- + // Print info + //-------------------------------------------------------------------------- + + int pr = SPEX_OPTION_PRINT_LEVEL (option); + if (*Is_correct) + { + SPEX_PR1 ("Solution is verified to be exact.\n"); + } + else + { + // This can never happen. + SPEX_PR1 ("ERROR! Solution is wrong. This is a bug; please " + "contact the authors of SPEX.\n"); + } + + //-------------------------------------------------------------------------- + // Free memory + //-------------------------------------------------------------------------- + + SPEX_FREE_ALL; + return SPEX_OK; +} + diff --git a/SPEX/Tcov/tcov_utilities.h b/SPEX/Tcov/tcov_utilities.h new file mode 100644 index 0000000000..c1615b42f4 --- /dev/null +++ b/SPEX/Tcov/tcov_utilities.h @@ -0,0 +1,164 @@ +// ---------------------------------------------------------------------------- +// SPEX/Tcov/tcov_utilities.h: utilities for tcov tests +// ---------------------------------------------------------------------------- + +// SPEX: (c) 2019-2023, Chris Lourenco, Jinhao Chen, +// Lorena Mejia Domenzain, Timothy A. Davis, and Erick Moreno-Centeno. +// All Rights Reserved. +// SPDX-License-Identifier: GPL-2.0-or-later or LGPL-3.0-or-later + +//----------------------------------------------------------------------------- + +#ifndef TCOV_UTILITIES_H +#define TCOV_UTILITIES_H + +#include "spex_lu_internal.h" +#include +#include + +extern int64_t malloc_count ; + +#define SPEX_PRINT_INFO(info) \ +{ \ + switch(info) \ + { \ + case SPEX_OK: printf("SPEX_OK\n"); break; \ + case SPEX_OUT_OF_MEMORY: printf("OUT OF MEMORY\n"); break; \ + case SPEX_SINGULAR: printf("Matrix is SINGULAR\n"); break; \ + case SPEX_INCORRECT_INPUT: printf("INCORRECT INPUT\n"); break; \ + case SPEX_NOTSPD: printf("Matrix is not SPD\n"); break; \ + case SPEX_PANIC: printf("SPEX_PANIC\n"); break; \ + default: printf("unknown!\n"); \ + } \ +} + +// abort the test if a test failure occurs +#define TEST_ABORT(info) \ +{ \ + SPEX_PRINT_INFO (info) ; \ + printf ("test failure: %s at line %d\n", __FILE__,__LINE__) ; \ + fprintf (stderr, "test failure: %s at line %d\n", __FILE__, __LINE__) ; \ + fflush (stdout) ; \ + fflush (stderr) ; \ + abort ( ) ; \ +} + +// assert something that should be true +#define TEST_ASSERT(ok) \ +{ \ + if (!(ok)) TEST_ABORT (SPEX_PANIC) ; \ +} + +// OK: call a method and assert that it succeeds +// The method must return a SPEX_info value. +#define OK(method) \ +{ \ + SPEX_info info3 = (method) ; \ + if (info3 != SPEX_OK) TEST_ABORT (info3) ; \ +} + +// OK2: call a method and assert that it succeeds or runs out of memory. +// If the method runs out of memory, all workspace is freed and control is +// returned to the caller. The method must return a SPEX_info value. +#define OK2(method) \ +{ \ + SPEX_info info4 = (method) ; \ + if (info4 == SPEX_OUT_OF_MEMORY) \ + { \ + SPEX_FREE_ALL; \ + return (info4) ; \ + } \ + if (info4 != SPEX_OK) TEST_ABORT (info4) ; \ +} + +// test wrapper for SPEX_initialize*, SPEX_finalize, and SPEX_*_free methods +#define TEST_OK(method) \ +if (!pretend_to_fail) \ +{ \ + OK (method) ; \ +} + +// test wrapper for all other SPEX_* functions +#define TEST_CHECK(method) \ +if (!pretend_to_fail) \ +{ \ + info = (method) ; \ + if (info == SPEX_OUT_OF_MEMORY) \ + { \ + SPEX_FREE_ALL; \ + pretend_to_fail = true ; \ + } \ + else if (info != SPEX_OK) \ + { \ + TEST_ABORT (info) ; \ + } \ +} + +// test wrapper for SPEX_* function when expected error would produce +#define TEST_CHECK_FAILURE(method,expected_error) \ +if (!pretend_to_fail) \ +{ \ + info = (method) ; \ + if (info == SPEX_OUT_OF_MEMORY) \ + { \ + SPEX_FREE_ALL; \ + pretend_to_fail = true ; \ + } \ + else if (info != expected_error) \ + { \ + printf ("SPEX method was expected to fail, but succeeded!\n") ; \ + printf ("this error was expected:\n") ; \ + SPEX_PRINT_INFO (expected_error) ; \ + printf ("but this error was obtained:\n") ; \ + TEST_ABORT (info) ; \ + } \ +} + +// malloc function for test coverage +void *tcov_malloc +( + size_t size // Size to alloc +) ; + +// calloc function for test coverage +void *tcov_calloc +( + size_t n, // Size of array (# of entries) + size_t size // Size of each entry to alloc +) ; + +// realloc function for test coverage +void *tcov_realloc +( + void *p, // Pointer to be realloced + size_t new_size // Size to alloc +) ; + +// free function for test coverage +void tcov_free +( + void *p // Pointer to be freed +) ; + +// used to test spex_gmp_reallocate +int spex_gmp_realloc_test +( + void **p_new, + void * p_old, + size_t old_size, + size_t new_size +) ; + +SPEX_info spex_check_solution +( + // output + bool *Is_correct, // true, if the solution is correct + // input + const SPEX_matrix A, // Input matrix of CSC MPZ + const SPEX_matrix x, // Solution vectors + const SPEX_matrix b, // Right hand side vectors + const SPEX_options option // Command options +) ; + +#endif + diff --git a/SPEX/cmake_modules/FindGMP.cmake b/SPEX/cmake_modules/FindGMP.cmake index f51365269a..2fa7773c0e 100644 --- a/SPEX/cmake_modules/FindGMP.cmake +++ b/SPEX/cmake_modules/FindGMP.cmake @@ -4,7 +4,7 @@ # The following copyright and license applies to just this file only, not to # the library itself: -# FindGMP.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. +# FindGMP.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. # SPDX-License-Identifier: BSD-3-clause #------------------------------------------------------------------------------- @@ -27,123 +27,72 @@ if ( DEFINED ENV{CMAKE_PREFIX_PATH} ) # import CMAKE_PREFIX_PATH, typically created by spack - list ( PREPEND CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH} ) + set ( CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH} ) endif ( ) -# Try to get information from pkg-config file first. -find_package ( PkgConfig ) -if ( PKG_CONFIG_FOUND ) - set ( GMP_PC_OPTIONS "" ) - if ( GMP_FIND_VERSION ) - set ( GMP_PC_OPTIONS "gmp>=${GMP_FIND_VERSION}" ) - else ( ) - set ( GMP_PC_OPTIONS "gmp" ) - endif ( ) - if ( GMP_FIND_REQUIRED ) - # FIXME: Are there installations without pkg-config file? - # list ( APPEND GMP_PC_OPTIONS REQUIRED ) - endif ( ) - pkg_check_modules ( GMP ${GMP_PC_OPTIONS} ) - - if ( GMP_FOUND ) - # assume first is the actual library - # FIXME: Would it be possible to return all libraries in that variable? - list ( GET GMP_LINK_LIBRARIES 0 GMP_LIBRARY ) - set ( GMP_INCLUDE_DIR ${GMP_INCLUDEDIR} ) - endif ( ) - if (GMP_STATIC_FOUND) - # assume first is the actual library - list ( GET GMP_STATIC_LINK_LIBRARIES 0 GMP_STATIC ) - set ( GMP_INCLUDE_DIR ${GMP_INCLUDEDIR} ) - endif ( ) -endif ( ) - -if ( NOT GMP_FOUND ) - # Manual search if pkg-config couldn't be used. - - # include files for gmp - find_path ( GMP_INCLUDE_DIR - NAMES gmp.h - PATH_SUFFIXES include Include - ) - - # dynamic gmp library (or possibly static if no GMP dynamic library exists) - find_library ( GMP_LIBRARY - NAMES gmp - PATH_SUFFIXES lib build - ) - - # check if found - if ( GMP_LIBRARY MATCHES ".*NOTFOUND" OR GMP_INCLUDE_DIR MATCHES ".*NOTFOUND" ) - set ( FOUND_IT false ) - else ( ) - set ( FOUND_IT true ) - endif ( ) - - # static gmp library - if ( NOT MSVC ) - set ( save_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - endif ( ) - - find_library ( GMP_STATIC - NAMES gmp - PATH_SUFFIXES lib build - ) +# include files for gmp +find_path ( GMP_INCLUDE_DIR + NAMES gmp.h + PATH_SUFFIXES include Include +) - if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save_CMAKE_FIND_LIBRARY_SUFFIXES} ) - endif ( ) +# dynamic gmp library +find_library ( GMP_LIBRARY + NAMES gmp + PATH_SUFFIXES lib build +) - # get version of the library from the filename - if ( GMP_LIBRARY ) - get_filename_component ( GMP_LIBRARY ${GMP_LIBRARY} REALPATH ) - endif ( ) +if ( MSVC ) + set ( STATIC_SUFFIX .lib ) +else ( ) + set ( STATIC_SUFFIX .a ) +endif ( ) - # look in the middle for 6.2.1 (/spackstuff/gmp-6.2.1-morestuff/libgmp.10.4.1) - string ( REGEX MATCH "gmp-[0-9]+.[0-9]+.[0-9]+" GMP_VERSION1 ${GMP_LIBRARY} ) - - if ( NOT FOUND_IT ) - # gmp has not been found - set ( GMP_VERSION 0.0.0 ) - message ( WARNING "GMP not found") - elseif ( GMP_VERSION1 STREQUAL "" ) - # gmp has been found, but not as a spack library. Hunt for the version - # number in gmp.h. The gmp.h file includes the following lines: - # #define __GNU_MP_VERSION 6 - # #define __GNU_MP_VERSION_MINOR 2 - # #define __GNU_MP_VERSION_PATCHLEVEL 0 - file ( STRINGS ${GMP_INCLUDE_DIR}/gmp.h GMP_VER_MAJOR_STRING - REGEX "define __GNU_MP_VERSION " ) - file ( STRINGS ${GMP_INCLUDE_DIR}/gmp.h GMP_VER_MINOR_STRING - REGEX "define __GNU_MP_VERSION_MINOR " ) - file ( STRINGS ${GMP_INCLUDE_DIR}/gmp.h GMP_VER_PATCH_STRING - REGEX "define __GNU_MP_VERSION_PATCHLEVEL " ) - message ( STATUS "major: ${GMP_VER_MAJOR_STRING}" ) - message ( STATUS "minor: ${GMP_VER_MINOR_STRING}" ) - message ( STATUS "patch: ${GMP_VER_PATCH_STRING}" ) - if ( GMP_VER_MAJOR_STRING STREQUAL "") - # look at the end of the filename for the version number - string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - GMP_VERSION ${GMP_LIBRARY} ) - else ( ) - # get the version number from inside the gmp.h file itself - string ( REGEX MATCH "[0-9]+" GMP_VER_MAJOR ${GMP_VER_MAJOR_STRING} ) - string ( REGEX MATCH "[0-9]+" GMP_VER_MINOR ${GMP_VER_MINOR_STRING} ) - string ( REGEX MATCH "[0-9]+" GMP_VER_PATCH ${GMP_VER_PATCH_STRING} ) - set ( GMP_VERSION "${GMP_VER_MAJOR}.${GMP_VER_MINOR}.${GMP_VER_PATCH}") - endif ( ) +# static gmp library +set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${STATIC_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +find_library ( GMP_STATIC + NAMES gmp + PATH_SUFFIXES lib build +) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) + +# get version of the library from the filename +get_filename_component ( GMP_LIBRARY ${GMP_LIBRARY} REALPATH ) + +# look in the middle for 6.2.1 (/spackstuff/gmp-6.2.1-morestuff/libgmp.10.4.1) +string ( REGEX MATCH "gmp-[0-9]+.[0-9]+.[0-9]+" GMP_VERSION1 ${GMP_LIBRARY} ) + +if ( GMP_VERSION1 STREQUAL "" ) + # gmp has been found, but not as a spack library. Hunt for the version + # number in gmp.h. The gmp.h file includes the following lines: + # #define __GNU_MP_VERSION 6 + # #define __GNU_MP_VERSION_MINOR 2 + # #define __GNU_MP_VERSION_PATCHLEVEL 0 + file ( STRINGS ${GMP_INCLUDE_DIR}/gmp.h GMP_VER_MAJOR_STRING + REGEX "define __GNU_MP_VERSION " ) + file ( STRINGS ${GMP_INCLUDE_DIR}/gmp.h GMP_VER_MINOR_STRING + REGEX "define __GNU_MP_VERSION_MINOR" ) + file ( STRINGS ${GMP_INCLUDE_DIR}/gmp.h GMP_VER_PATCH_STRING + REGEX "define __GNU_MP_VERSION_PATCH" ) + message ( STATUS "major from gmp.h: ${GMP_VER_MAJOR_STRING}" ) + message ( STATUS "minor from gmp.h: ${GMP_VER_MINOR_STRING}" ) + message ( STATUS "patch from gmp.h: ${GMP_VER_PATCH_STRING}" ) + if ( GMP_VER_MAJOR_STRING STREQUAL "") + # look at the end of the filename for the version number + string ( + REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" + GMP_VERSION ${GMP_LIBRARY} ) else ( ) - # look at gmp-6.2.1 for the version number (spack library) - string ( REGEX MATCH "[0-9]+.[0-9]+.[0-9]" GMP_VERSION ${GMP_VERSION1} ) + # get the version number from inside the gmp.h file itself + string ( REGEX MATCH "[0-9]+" GMP_VER_MAJOR ${GMP_VER_MAJOR_STRING} ) + string ( REGEX MATCH "[0-9]+" GMP_VER_MINOR ${GMP_VER_MINOR_STRING} ) + string ( REGEX MATCH "[0-9]+" GMP_VER_PATCH ${GMP_VER_PATCH_STRING} ) + set ( GMP_VERSION "${GMP_VER_MAJOR}.${GMP_VER_MINOR}.${GMP_VER_PATCH}") endif ( ) -endif ( ) - -if ( NOT GMP_STATIC ) - set ( GMP_STATIC ${GMP_LIBRARY} ) +else ( ) + # look at gmp-6.2.1 for the version number (spack library) + string ( REGEX MATCH "[0-9]+.[0-9]+.[0-9]" GMP_VERSION ${GMP_VERSION1} ) endif ( ) set ( GMP_LIBRARIES ${GMP_LIBRARY} ) @@ -151,7 +100,7 @@ set ( GMP_LIBRARIES ${GMP_LIBRARY} ) include (FindPackageHandleStandardArgs) find_package_handle_standard_args ( GMP - REQUIRED_VARS GMP_LIBRARY GMP_INCLUDE_DIR + REQUIRED_VARS GMP_LIBRARIES GMP_INCLUDE_DIR VERSION_VAR GMP_VERSION ) @@ -169,9 +118,5 @@ if ( GMP_FOUND ) message ( STATUS "gmp static: ${GMP_STATIC}" ) else ( ) message ( STATUS "gmp not found" ) - set ( GMP_INCLUDE_DIR "" ) - set ( GMP_LIBRARIES "" ) - set ( GMP_LIBRARY "" ) - set ( GMP_STATIC "" ) endif ( ) diff --git a/SPEX/cmake_modules/FindMPFR.cmake b/SPEX/cmake_modules/FindMPFR.cmake index d2d2ecb835..fae9cb258d 100644 --- a/SPEX/cmake_modules/FindMPFR.cmake +++ b/SPEX/cmake_modules/FindMPFR.cmake @@ -4,7 +4,7 @@ # The following copyright and license applies to just this file only, not to # the library itself: -# FindMPFR.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. +# FindMPFR.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. # SPDX-License-Identifier: BSD-3-clause #------------------------------------------------------------------------------- @@ -27,108 +27,61 @@ if ( DEFINED ENV{CMAKE_PREFIX_PATH} ) # import CMAKE_PREFIX_PATH, typically created by spack - list ( PREPEND CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH} ) + set ( CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH} ) endif ( ) -# Try to get information from pkg-config file first. -find_package ( PkgConfig ) -if ( PKG_CONFIG_FOUND ) - set ( MPFR_PC_OPTIONS "" ) - if ( MPFR_FIND_VERSION ) - set ( MPFR_PC_OPTIONS "mpfr>=${MPFR_FIND_VERSION}" ) - else ( ) - set ( MPFR_PC_OPTIONS "mpfr" ) - endif ( ) - if ( MPFR_FIND_REQUIRED ) - # FIXME: Are there installations without pkg-config file? - # list ( APPEND MPFR_PC_OPTIONS REQUIRED ) - endif ( ) - pkg_check_modules ( MPFR ${MPFR_PC_OPTIONS} ) - - if ( MPFR_FOUND ) - # assume first is the actual library - list ( GET MPFR_LINK_LIBRARIES 0 MPFR_LIBRARY ) - set ( MPFR_INCLUDE_DIR ${MPFR_INCLUDEDIR} ) - endif ( ) - if (MPFR_STATIC_FOUND) - # assume first is the actual library - list ( GET MPFR_STATIC_LINK_LIBRARIES 0 MPFR_STATIC ) - set ( MPFR_INCLUDE_DIR ${MPFR_INCLUDEDIR} ) - endif ( ) -endif ( ) - -if ( NOT MPFR_FOUND ) - # Manual search if pkg-config couldn't be used. - # include files for mpfr - find_path ( MPFR_INCLUDE_DIR - NAMES mpfr.h - PATH_SUFFIXES include Include - ) - - # dynamic mpfr library (or possibly static if no mpfr dynamic library exists) - find_library ( MPFR_LIBRARY - NAMES mpfr - PATH_SUFFIXES lib build - ) - - # check if found - if ( MPFR_LIBRARY MATCHES ".*NOTFOUND" OR MPFR_INCLUDE_DIR MATCHES ".*NOTFOUND" ) - set ( FOUND_IT false ) - else ( ) - set ( FOUND_IT true ) - endif ( ) - - # static mpfr library - if ( NOT MSVC ) - set ( save_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - endif ( ) +# include files for mpfr +find_path ( MPFR_INCLUDE_DIR + NAMES mpfr.h + PATH_SUFFIXES include Include +) - find_library ( MPFR_STATIC - NAMES mpfr - PATH_SUFFIXES lib build - ) +# dynamic mpfr library +find_library ( MPFR_LIBRARY + NAMES mpfr + PATH_SUFFIXES lib build +) - if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save_CMAKE_FIND_LIBRARY_SUFFIXES} ) - endif ( ) +if ( MSVC ) + set ( STATIC_SUFFIX .lib ) +else ( ) + set ( STATIC_SUFFIX .a ) +endif ( ) - # get version of the library from the filename - get_filename_component ( MPFR_LIBRARY ${MPFR_LIBRARY} REALPATH ) - - # look in the middle for 4.1.0 (/spackstuff/mpfr-4.1.0-morestuff/libmpfr.10.4.1) - string ( REGEX MATCH "mpfr-[0-9]+.[0-9]+.[0-9]+" MPFR_VERSION1 ${MPFR_LIBRARY} ) - - if ( NOT FOUND_IT ) - # mpfr has not been found - set ( MPFR_VERSION 0.0.0 ) - message ( WARNING "MPFR not found") - elseif ( MPFR_VERSION1 STREQUAL "" ) - # mpfr has been found, but not a spack library. Hunt for the version - # number in mpfr.h. The mpfr.h file includes the following line: - # #define MPFR_VERSION_STRING "4.0.2" - file ( STRINGS ${MPFR_INCLUDE_DIR}/mpfr.h MPFR_VER_STRING - REGEX "MPFR_VERSION_STRING" ) - message ( STATUS "major/minor/patch: ${MPFR_VER_STRING}" ) - if ( MPFR_VER_STRING STREQUAL "") - # look at the end of the filename for the version number - string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - MPFR_VERSION ${MPFR_LIBRARY} ) - else ( ) - # get the version number from inside the mpfr.h file itself - string ( REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" MPFR_VERSION ${MPFR_VER_STRING} ) - endif ( ) +# static mpfr library +set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${STATIC_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) +find_library ( MPFR_STATIC + NAMES mpfr + PATH_SUFFIXES lib build +) +set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) + +# get version of the library from the filename +get_filename_component ( MPFR_LIBRARY ${MPFR_LIBRARY} REALPATH ) + +# look in the middle for 4.1.0 (/spackstuff/mpfr-4.1.0-morestuff/libmpfr.10.4.1) +string ( REGEX MATCH "mpfr-[0-9]+.[0-9]+.[0-9]+" MPFR_VERSION1 ${MPFR_LIBRARY} ) + +if ( MPFR_VERSION1 STREQUAL "" ) + # mpfr has been found, but not a spack library. Hunt for the version + # number in mpfr.h. The mpfr.h file includes the following line: + # #define MPFR_VERSION_STRING "4.0.2" + file ( STRINGS ${MPFR_INCLUDE_DIR}/mpfr.h MPFR_VER_STRING + REGEX "MPFR_VERSION_STRING" ) + message ( STATUS "from mpfr.h file: ${MPFR_VER_STRING}" ) + if ( MPFR_VER_STRING STREQUAL "") + # look at the end of the filename for the version number + string ( + REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" + MPFR_VERSION ${MPFR_LIBRARY} ) else ( ) - # look at mpfr-4.1.0 for the version number (spack library) - string ( REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" MPFR_VERSION ${MPFR_VERSION1} ) + # get the version number from inside the mpfr.h file itself + string ( REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" MPFR_VERSION ${MPFR_VER_STRING} ) endif ( ) -endif ( ) - -if ( NOT MPFR_STATIC ) - set ( MPFR_STATIC ${MPFR_LIBRARY} ) +else ( ) + # look at mpfr-4.1.0 for the version number (spack library) + string ( REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" MPFR_VERSION ${MPFR_VERSION1} ) endif ( ) set ( MPFR_LIBRARIES ${MPFR_LIBRARY} ) @@ -136,7 +89,7 @@ set ( MPFR_LIBRARIES ${MPFR_LIBRARY} ) include (FindPackageHandleStandardArgs) find_package_handle_standard_args ( MPFR - REQUIRED_VARS MPFR_LIBRARY MPFR_INCLUDE_DIR + REQUIRED_VARS MPFR_LIBRARIES MPFR_INCLUDE_DIR VERSION_VAR MPFR_VERSION ) @@ -154,9 +107,5 @@ if ( MPFR_FOUND ) message ( STATUS "mpfr static: ${MPFR_STATIC}" ) else ( ) message ( STATUS "mpfr not found" ) - set ( MPFR_INCLUDE_DIR "" ) - set ( MPFR_LIBRARIES "" ) - set ( MPFR_LIBRARY "" ) - set ( MPFR_STATIC "" ) endif ( ) diff --git a/SuiteSparse_config/CMakeLists.txt b/SuiteSparse_config/CMakeLists.txt index 8e5c119b54..cc7beefbd6 100644 --- a/SuiteSparse_config/CMakeLists.txt +++ b/SuiteSparse_config/CMakeLists.txt @@ -15,9 +15,9 @@ cmake_minimum_required ( VERSION 3.22 ) # version of both SuiteSparse and SuiteSparse_config -set ( SUITESPARSE_DATE "Jan 20, 2024" ) +set ( SUITESPARSE_DATE "Feb XX, 2024" ) # FIXME for 7.7.0 set ( SUITESPARSE_VERSION_MAJOR 7 ) -set ( SUITESPARSE_VERSION_MINOR 6 ) +set ( SUITESPARSE_VERSION_MINOR 7 ) set ( SUITESPARSE_VERSION_SUB 0 ) set ( SUITESPARSE_CONFIG_VERSION_MAJOR ${SUITESPARSE_VERSION_MAJOR} CACHE STRING "" FORCE ) set ( SUITESPARSE_CONFIG_VERSION_MINOR ${SUITESPARSE_VERSION_MINOR} CACHE STRING "" FORCE ) diff --git a/SuiteSparse_config/SuiteSparse_config.h b/SuiteSparse_config/SuiteSparse_config.h index 01ce98c5c8..bcea44c1fe 100644 --- a/SuiteSparse_config/SuiteSparse_config.h +++ b/SuiteSparse_config/SuiteSparse_config.h @@ -420,19 +420,19 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_HAS_VERSION_FUNCTION -#define SUITESPARSE_DATE "Jan 20, 2024" +#define SUITESPARSE_DATE "Feb XX, 2024" #define SUITESPARSE_MAIN_VERSION 7 -#define SUITESPARSE_SUB_VERSION 6 +#define SUITESPARSE_SUB_VERSION 7 #define SUITESPARSE_SUBSUB_VERSION 0 // version format x.y #define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_VERSION SUITESPARSE_VER_CODE(7, 6) +#define SUITESPARSE_VERSION SUITESPARSE_VER_CODE(7, 7) // version format x.y.z #define SUITESPARSE__VERCODE(main,sub,patch) \ (((main)*1000ULL + (sub))*1000ULL + (patch)) -#define SUITESPARSE__VERSION SUITESPARSE__VERCODE(7,6,0) +#define SUITESPARSE__VERSION SUITESPARSE__VERCODE(7,7,0) //============================================================================== // SuiteSparse interface to the BLAS and LAPACK libraries