diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c92b375b..28c83aca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,11 @@ jobs: - name: Choose environment run: | - cp spack-repo/environments/spack_cpu_gcc.yaml spack.yaml + # gprat_cpu_gcc_dist (rather than gprat_cpu_gcc) builds HPX with networking=tcp instead + # of networking=none, which --hpx:localities (used by the distributed multi-locality + # tests, see test/CMakeLists.txt) requires. It has no MKL variant, so the rest of this + # job uses OpenBLAS (-DGPRAT_ENABLE_MKL=OFF / -DUSE_MKL=OFF below) instead. + cp spack-repo/environments/spack_cpu_gcc_dist.yaml spack.yaml cat spack-repo/environments/ci_env_settings.yaml.tpl >> spack.yaml - name: Concretize @@ -61,17 +65,17 @@ jobs: shell: spack-bash {0} run: | spack env activate . - cmake "--preset=ci-${{ matrix.os }}" + cmake "--preset=ci-${{ matrix.os }}" -DGPRAT_ENABLE_MKL=OFF -DGPRAT_WITH_DISTRIBUTED=ON -DGPRAT_TEST_MULTI_LOCALITY=ON - name: Build - run: cmake --build build --config Release -j 2 + run: cmake --build build --config Release - name: Install run: cmake --install build --config Release --prefix prefix - name: Test working-directory: build - run: ctest --output-on-failure --no-tests=ignore -C Release -j 2 + run: ctest --output-on-failure --no-tests=ignore -C Release - name: Upload uses: actions/upload-artifact@v4 @@ -87,10 +91,10 @@ jobs: shell: spack-bash {0} run: | spack env activate . - cmake -G "Unix Makefiles" -S examples/gprat_cpp -B build_examples -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$PWD/prefix -DUSE_MKL=ON + cmake -G "Unix Makefiles" -S examples/gprat_cpp -B build_examples -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$PWD/prefix -DUSE_MKL=OFF - name: Build example project - run: cmake --build build_examples --config Release -j 2 + run: cmake --build build_examples --config Release # See: https://github.com/spack/setup-spack?tab=readme-ov-file#example-caching-your-own-binaries-for-public-repositories - name: Push packages and update index diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ff35d191..c1aee584 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -3,7 +3,6 @@ name: Code linting on: push: branches: - - main pull_request: jobs: diff --git a/.gitignore b/.gitignore index 64c941d3..002eaf98 100644 --- a/.gitignore +++ b/.gitignore @@ -195,7 +195,17 @@ examples/*/output.csv examples/gprat_*/include/ examples/gpflow_reference/GPflow /.vscode +benchmark_results_* # Editor related files ltex* compile_commands.json + +# Build files +build* + +# CTest output +Testing/ + +# Ignore folder +ignore \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 794a66f9..b1b011a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,7 @@ +# Top-level CMakeLists.txt + +# CMake initialization +# ############################################################################## cmake_minimum_required(VERSION 3.23) project( @@ -9,21 +13,30 @@ project( include(CMakeDependentOption) -# What to build? +# Build options +# ############################################################################## option(GPRAT_BUILD_CORE "Build the core library" ON) + cmake_dependent_option(GPRAT_BUILD_BINDINGS "Build the Python bindings" ON "GPRAT_BUILD_CORE" OFF) + cmake_dependent_option( GPRAT_ENABLE_EXAMPLES "Build example applications as well?" ${PROJECT_IS_TOP_LEVEL} "GPRAT_BUILD_CORE" OFF) + cmake_dependent_option(GPRAT_ENABLE_TESTS "Build unit and integration tests" ${PROJECT_IS_TOP_LEVEL} "GPRAT_BUILD_CORE" OFF) + cmake_dependent_option(GPRAT_ENABLE_MKL "Enable support for Intel oneMKL" ${PROJECT_IS_TOP_LEVEL} "GPRAT_BUILD_CORE" OFF) +option(GPRAT_ENABLE_BENCHMARK_CACHE_EVICTIONS + "Evict data from caches before running BLAS operations" ON) option(GPRAT_ENABLE_FORMAT_TARGETS "Enable clang-format / cmake-format targets" ${PROJECT_IS_TOP_LEVEL}) +# Format settings +# ############################################################################## if(GPRAT_ENABLE_FORMAT_TARGETS) set(CMAKE_FORMAT_EXCLUDE "^external_ports/") @@ -39,6 +52,8 @@ if(GPRAT_ENABLE_FORMAT_TARGETS) endif() endif() +# GNU install dirs +# ############################################################################## if(NOT CMAKE_SKIP_INSTALL_RULES) # Our installs follow the standard GNU directory layout. This include needs to # come first since we need the CMAKE_INSTALL_* in the CMakeLists.txt of each @@ -46,22 +61,24 @@ if(NOT CMAKE_SKIP_INSTALL_RULES) include(GNUInstallDirs) endif() +# Building the GPRAT core +# ############################################################################## if(GPRAT_BUILD_CORE) + + # MKL backend if(GPRAT_ENABLE_MKL) - # Try to find Intel oneMKL set(MKL_INTERFACE_FULL "intel_lp64") set(MKL_THREADING "sequential") find_package(MKL CONFIG REQUIRED) - if(MKL_FOUND) message(STATUS "Intel oneMKL Library found") else() - message(FATAL_ERROR "No BLAS Library found") + message(FATAL_ERROR "Intel oneMKL Library NOT found") endif() + + # OpenBLAS backend else() - # Try to find OpenBLAS find_library(OpenBLAS_LIB NAMES openblas REQUIRED) - if(OpenBLAS_LIB) message(STATUS "OpenBLAS Library found at ${OpenBLAS_LIB}") else() @@ -69,14 +86,22 @@ if(GPRAT_BUILD_CORE) endif() endif() + # HPX find_package(HPX REQUIRED) + include(cmake/hpx-apex-compat.cmake) + # Add core subdirectiory add_subdirectory(core) + + # Bindings subdirectory if(GPRAT_BUILD_BINDINGS) add_subdirectory(bindings) endif() + endif() +# Installation +# ############################################################################## if(NOT CMAKE_SKIP_INSTALL_RULES AND GPRAT_BUILD_CORE) include(CMakePackageConfigHelpers) @@ -100,6 +125,11 @@ if(NOT CMAKE_SKIP_INSTALL_RULES AND GPRAT_BUILD_CORE) RENAME "${package}Config.cmake" COMPONENT Development) + install( + FILES cmake/hpx-apex-compat.cmake + DESTINATION "${GPRat_INSTALL_CMAKEDIR}" + COMPONENT Development) + install( FILES "${PROJECT_BINARY_DIR}/${package}ConfigVersion.cmake" DESTINATION "${GPRat_INSTALL_CMAKEDIR}" @@ -116,11 +146,21 @@ if(NOT CMAKE_SKIP_INSTALL_RULES AND GPRAT_BUILD_CORE) endif() endif() +# Examples +# ############################################################################## if(GPRAT_ENABLE_EXAMPLES) add_subdirectory(examples/gprat_cpp) + if(GPRAT_WITH_DISTRIBUTED) + add_subdirectory(examples/gprat_distributed) + endif() endif() +# Tests +# ############################################################################## if(GPRAT_ENABLE_TESTS) enable_testing() add_subdirectory(test) endif() + +# End of file +# ############################################################################## diff --git a/CMakePresets.json b/CMakePresets.json index 695681a5..b94a7c11 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -192,8 +192,8 @@ } }, { - "name": "dev-linux-gpu", - "binaryDir": "${sourceDir}/build/dev-linux-gpu", + "name": "dev-linux-cuda", + "binaryDir": "${sourceDir}/build/dev-linux-cuda", "inherits": ["dev-linux"], "cacheVariables": { "GPRAT_WITH_CUDA": "ON", @@ -202,15 +202,31 @@ } }, { - "name": "release-linux-gpu", - "binaryDir": "${sourceDir}/build/release-linux-gpu", + "name": "release-linux-cuda", + "binaryDir": "${sourceDir}/build/release-linux-cuda", "inherits": ["release-linux"], "cacheVariables": { "GPRAT_WITH_CUDA": "ON", "GPRAT_APEX_STEPS": "OFF", "GPRAT_APEX_CHOLESKY": "OFF" } + }, + { + "name": "dev-linux-sycl", + "binaryDir": "${sourceDir}/build/dev-linux-sycl", + "inherits": ["dev-linux"], + "cacheVariables": { + "GPRAT_WITH_SYCL": "ON" + } + }, + { + "name": "release-linux-sycl", + "binaryDir": "${sourceDir}/build/release-linux-sycl", + "inherits": ["release-linux"], + "cacheVariables": { + "GPRAT_WITH_SYCL": "ON" } + } ], "buildPresets": [ { @@ -224,13 +240,23 @@ "configuration": "Release" }, { - "name": "dev-linux-gpu", - "configurePreset": "dev-linux-gpu", + "name": "dev-linux-cuda", + "configurePreset": "dev-linux-cuda", + "configuration": "Debug" + }, + { + "name": "release-linux-cuda", + "configurePreset": "release-linux-cuda", + "configuration": "Release" + }, + { + "name": "dev-linux-sycl", + "configurePreset": "dev-linux-sycl", "configuration": "Debug" }, { - "name": "release-linux-gpu", - "configurePreset": "release-linux-gpu", + "name": "release-linux-sycl", + "configurePreset": "release-linux-sycl", "configuration": "Release" } ], @@ -258,8 +284,8 @@ } }, { - "name": "dev-linux-gpu", - "configurePreset": "dev-linux-gpu", + "name": "dev-linux-cuda", + "configurePreset": "dev-linux-cuda", "configuration": "Debug", "output": { "outputOnFailure": true @@ -269,8 +295,8 @@ } }, { - "name": "release-linux-gpu", - "configurePreset": "release-linux-gpu", + "name": "release-linux-cuda", + "configurePreset": "release-linux-cuda", "configuration": "Release", "output": { "outputOnFailure": true diff --git a/README.md b/README.md index 5e60398c..73655dd1 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,17 @@ Leveraging the asynchronous many-task runtime HPX, we aim to combine the perform with the ease of use of commonly available Python libraries. Thus, GPRat can be conveniently integrated into Python projects without binding overheads or used directly with pure C++ code. +Computations run on CPUs as well as NVIDIA GPUs (CUDA) and Intel/AMD GPUs (SYCL), in single (fp32) and double (fp64) +precision. +GPRat further provides a NUMA-aware allocator for tile data, performance counters, and optional distributed execution +via HPX actions. ## Dependencies GPRat depends on [HPX](https://hpx-docs.stellar-group.org/latest/html/index.html) for asynchronous task-based parallelization. Furthermore, for CPU-only BLAS computation GPRat requires [OpenBLAS](http://www.openmathlib.org/OpenBLAS/) or [MKL](https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl.html). -A [CUDA](https://developer.nvidia.com/cuda-toolkit) installation is required for GPU-only BLAS computations. +A [CUDA](https://developer.nvidia.com/cuda-toolkit) installation is required for GPU-only BLAS computations on NVIDIA hardware. +For GPU computations on Intel and AMD hardware, GPRat supports [SYCL](https://www.khronos.org/sycl/) via [oneMath](https://github.com/uxlfoundation/oneMath). ### Install dependencies @@ -20,6 +25,9 @@ A script to install and setup spack for `GPRat` is provided in [`spack-repo`](sp Spack environment configurations and setup scripts for CPU and GPU use are provided in [`spack-repo/environments`](spack-repo/environments). +Since Spack is not available on Windows, we also support dependency installation using vcpkg. +For now, vcpkg builds are only tested on Windows. + ## How To Compile GPRat makes use of [CMake presets][1] to simplify the process of configuring the project. @@ -34,8 +42,9 @@ ctest --preset=dev-linux As a developer, you may create a `CMakeUserPresets.json` file at the root of the project that contains additional presets local to your machine. -In addition to the build configuration `dev-linux`, there are `release-linux`, `dev-linux-gpu`, and `release-linux-gpu`. -The configurations suffixed with `-gpu` build the library with CUDA. +In addition to the build configuration `dev-linux`, there are `release-linux`, `dev-linux-cuda`, `release-linux-cuda`, `dev-linux-sycl`, and `release-linux-sycl`. +For Windows, we have similar presets called `dev-windows` and `release-windows`. +The configurations suffixed with `-cuda` build the library with CUDA for NVIDIA GPUs, and those suffixed with `-sycl` build it with SYCL support for Intel and AMD GPUs. GPRat can be build with or without Python bindings. The following options can be set to include / exclude parts of the project: @@ -44,13 +53,31 @@ The following options can be set to include / exclude parts of the project: |--------------------------------|--------------------------------------------------------------------------------------|-----------------| | GPRAT_BUILD_CORE | Enable/Disable building of the core library | ON | | GPRAT_BUILD_BINDINGS | Enable/Disable building of the Python bindings | ON | -| GPRAT_ENABLE_FORMAT_TARGETS | Enable/Disable code formatting helper targets | ON if top-level | | GPRAT_ENABLE_EXAMPLES | Enable/Disable example projects | ON if top-level | -| GPRAT_USE_MKL | Enable/Disable usage of MKL library | OFF | -| GPRAT_WITH_CUDA | Enable/disable compilation with CUDA support | OFF | +| GPRAT_ENABLE_TESTS | Enable/Disable building of unit and integration tests | ON if top-level | +| GPRAT_ENABLE_FORMAT_TARGETS | Enable/Disable code formatting helper targets | ON if top-level | +| GPRAT_ENABLE_MKL | Enable/Disable support for Intel oneMKL | OFF | +| GPRAT_WITH_CUDA | Enable/disable compilation with CUDA support (NVIDIA GPUs) | OFF | +| GPRAT_WITH_SYCL | Enable/disable compilation with SYCL support (Intel and AMD GPUs via oneMath) | OFF | +| GPRAT_WITH_DISTRIBUTED | Enable/disable distributed GP support via HPX actions | OFF | | GPRAT_APEX_STEPS | Enable/disable compilation for steps duration measurement with APEX | OFF | | GPRAT_APEX_CHOLESKY | Enable/disable compilation for measuring cholesky assembly and computation with APEX | OFF | +A convenience script `compile_gprat.sh` is provided to configure, build, and install GPRat with a single command. +It takes five parameters: + +```sh +./compile_gprat.sh [python/cpp] [cpu/cuda/sycl] [release/dev] [mkl/none] [steps/cholesky/none] +``` + +- `$1`: build the Python bindings (`python`) or the C++ library (`cpp`) +- `$2`: backend, CPU (`cpu`), CUDA for NVIDIA GPUs (`cuda`), or SYCL for Intel and AMD GPUs (`sycl`) +- `$3`: build in `release` or `dev` mode +- `$4`: enable Intel oneMKL (`mkl`) or use OpenBLAS (`none`) +- `$5`: APEX profiling, measure step durations (`steps`), cholesky assembly and computation (`cholesky`), or disable profiling (`none`) + +Computations are supported in both single (fp32) and double (fp64) precision. + Respective scripts can be found in this directory. We also provide a spack package for GPRat in [`spack-repo/packages`](spack-repo/packages) for portable and convenient compilation. When the repository is added to spack, GPRat can be installed with `spack install gprat~cuda~bindings~examples blas={mkl,openblas}` @@ -66,15 +93,53 @@ implementations based on TensorFlow ([GPflow](https://github.com/GPflow/GPflow)) - Go to [`examples/gprat_cpp`](examples/gprat_cpp/) - Set parameters in [`execute.cpp`](examples/gprat_cpp/src/execute.cpp) - The example is built as part of the main project. - - Go to `build/` and execute `./gprat_cpp [--use_gpu]` to run the example. + - Go to `build/` and execute `./gprat_cpp [--use-gpu]` to run the example. - If you want to use an installed GPRat version: - Run `./run_gprat_cpp.sh [cpu/gpu] [x86/arm/riscv]` to build and run the example. + Run `./run_gprat_cpp.sh [cpu/cuda/sycl] [nvidia/amd/intel]` to build and run the example. + The second parameter selects the SYCL device and is only required when GPRat was compiled with the SYCL backend. ### To run GPRat with Python - Go to [`examples/gprat_python`](examples/gprat_python/) - Set parameters in [`config.json`](examples/gprat_python/config.json) -- Run `./run_gprat_python.sh [cpu/gpu]` to run the example +- Run `./run_gprat_python.sh [cpu/cuda/sycl] [nvidia/amd/intel]` to run the example. + The second parameter selects the SYCL device and is only required when GPRat was compiled with the SYCL backend. + +### To run the distributed GPRat benchmark + +- Configure the main project with `-DGPRAT_WITH_DISTRIBUTED=ON` to build [`examples/gprat_distributed`](examples/gprat_distributed/). +- The example is a CLI-driven scaling benchmark (no `config.json`) rather than a single "run one example" tool, + since it sweeps over training-set sizes rather than running one fixed configuration. +- Go to `build/` and execute `./gprat_distributed [options]`, or run `./run_gprat_distributed.sh [options]` to + build and run it. Useful options: + - `--start`/`--end`/`--step`: training-set sizes to sweep over (e.g. `--start 128 --end 4096 --step 2`) + - `--tiles`, `--regressors`, `--n_test`, `--opt_iter`, `--loop`: problem size and repetition count + - `--enabled`: bitmask to select which of cholesky/optimize/predict/predict_with_uncertainty/predict_with_full_cov to run + - `--train_x_path`/`--train_y_path`/`--test_path`: point at a larger dataset (e.g. one generated via + [`data/generators`](data/generators/)) for a real scaling study; the defaults point at the small `data/data_1024` + correctness fixture + - `--output_csv`: where per-run timings are appended (defaults to `examples/gprat_distributed/output.csv`, + matching the other examples) +- By default (`GPRAT_DIST_MULTI_LOCALITY=1`, on unless you set it to `0` before running + `run_gprat_distributed.sh`) the script runs across multiple localities on one node: it builds a + networking-enabled binary and, for each locality count in `GPRAT_DIST_LOCALITIES` (default `"1 2 4"`), + launches that many processes itself with `--hpx:localities=N --hpx:node=0..N-1` (node `0` is the console + process that receives your CLI options; the others just join), waiting for each round to finish before + moving to the next. All arguments you pass are forwarded to node `0`. Set `GPRAT_DIST_MULTI_LOCALITY=0` to + opt back into a single-locality run against the default `gprat_cpu_gcc` build. + **Important:** HPX's TCP parcelport zero-copy path (`hpx.parcel.zero_copy_serialization_threshold`, + 8192 bytes by default) reliably hangs once tile sizes exceed it in a multi-locality run, so the script + always raises it (`--hpx:ini=hpx.parcel.zero_copy_serialization_threshold=999999999`) for these runs. + Running across multiple actual nodes additionally requires cluster-specific network configuration + (AGAS bootstrap addresses, hostfile/job-scheduler integration) not set up here. + - The default Spack environment (`gprat_cpu_gcc`) builds HPX with `networking=none`, which rejects + `--hpx:localities` outright. `GPRAT_DIST_MULTI_LOCALITY=1` instead uses the `gprat_cpu_gcc_dist` + Spack environment (`networking=tcp`, OpenBLAS-only — see + `spack-repo/environments/setup_gprat_cpu_gcc_dist.sh`) and builds into a separate + `build/release-linux-dist` directory to avoid mixing the two toolchains. + - Enable `-DGPRAT_TEST_MULTI_LOCALITY=ON` (in addition to `-DGPRAT_WITH_DISTRIBUTED=ON`) to register + CTest smoke tests (`GPRat_test_distributed_multi_locality_{1,2,4}`) that launch `gprat_distributed` + across 1/2/4 localities; off by default since it needs the same networking-enabled HPX build. ### To run GPflow reference @@ -82,7 +147,7 @@ implementations based on TensorFlow ([GPflow](https://github.com/GPflow/GPflow)) - Set parameters in [`config.json`](examples/gpflow_reference/config.json) - Run `./run_gpflow.sh [cpu/gpu/arm]` to run example -### To run GPflow reference +### To run GPyTorch reference - Go to [`examples/gpytorch_reference`](examples/gpytorch_reference/) - Set parameters in [`config.json`](examples/gpytorch_reference/config.json) @@ -103,7 +168,13 @@ We specifically thank the follow contributors: [Optimization, Python bindings and reference implementations](https://doi.org/10.48550/arXiv.2505.00136). - [Henrik Möllmann](https://www.linkedin.com/in/moellh/): - [Accelerator Support](tbd.). + [CUDA backend via cuBLAS/cuSOLVER](tbd.). + +- [Marcel Graf](https://github.com/MarcelGraf0710): + [SYCL backend via oneMath](tbd.). + +- [Tim Niederhausen](https://github.com/timniederhausen): + [Distributed GP via HPX actions](tbd.). ## How To Cite diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index dd3765f1..ff0eba65 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -1,5 +1,5 @@ # try finding pybind11 -set(GPRat_pybind11_VERSION 2.10.3) +set(GPRat_pybind11_VERSION 2.13.6) find_package(pybind11 ${GPRat_pybind11_VERSION} QUIET) if(pybind11_FOUND) message(STATUS "Found package pybind11.") @@ -20,8 +20,11 @@ endif() # Option for GPU support with CUDA, cuSolver, cuBLAS option(GPRAT_WITH_CUDA "Enable GPU support with CUDA, cuSolver, cuBLAS" OFF) +option(GPRAT_WITH_SYCL "Enable SYCL support with oneMath" OFF) + # Pass variable to C++ code -add_compile_definitions(GPRAT_WITH_CUDA=$) +add_compile_definitions(GPRAT_WITH_CUDA=$ + GPRAT_WITH_SYCL=$) # Option for steps duration measurement with APEX option(GPRAT_APEX_STEPS "Enable measuring duration of steps with APEX" OFF) diff --git a/bindings/gprat_py.cpp b/bindings/gprat_py.cpp index b18d2279..6daf207d 100644 --- a/bindings/gprat_py.cpp +++ b/bindings/gprat_py.cpp @@ -1,4 +1,5 @@ -#include "gprat_c.hpp" +#include "gprat/gprat.hpp" + #include #include @@ -31,19 +32,19 @@ void init_gprat(py::module &m) // Set hyperparameters to default values in `AdamParams` class, unless // specified. Python object has full access to each hyperparameter and a // string representation `__repr__`. - py::class_(m, "AdamParams") + py::class_(m, "AdamParams") .def(py::init(), py::arg("learning_rate") = 0.001, py::arg("beta1") = 0.9, py::arg("beta2") = 0.999, py::arg("epsilon") = 1e-8, py::arg("opt_iter") = 0) - .def_readwrite("learning_rate", &gprat_hyper::AdamParams::learning_rate) - .def_readwrite("beta1", &gprat_hyper::AdamParams::beta1) - .def_readwrite("beta2", &gprat_hyper::AdamParams::beta2) - .def_readwrite("epsilon", &gprat_hyper::AdamParams::epsilon) - .def_readwrite("opt_iter", &gprat_hyper::AdamParams::opt_iter) - .def("__repr__", &gprat_hyper::AdamParams::repr); + .def_readwrite("learning_rate", &gprat::AdamParams::learning_rate) + .def_readwrite("beta1", &gprat::AdamParams::beta1) + .def_readwrite("beta2", &gprat::AdamParams::beta2) + .def_readwrite("epsilon", &gprat::AdamParams::epsilon) + .def_readwrite("opt_iter", &gprat::AdamParams::opt_iter) + .def("__repr__", &gprat::AdamParams::repr); // Initializes Gaussian Process with `GP` class. Sets default parameters for // squared exponential kernel, number of regressors and trainable, unless @@ -79,7 +80,7 @@ n_streams to a value enables computations on the GPU. trainable (list): List of booleans for trainable hyperparameters. Default is {true, true, true}. gpu_id (int): ID of the GPU to use. Default is 0. - n_streams (int): Number of streams for GPU computation. Default is 1. + n_units (int): Number of streams/queues for GPU computation. Default is 1. )pbdoc") // GPU constructor @@ -100,11 +101,11 @@ n_streams to a value enables computations on the GPU. py::arg("kernel_params") = std::vector{ 1.0, 1.0, 0.1 }, py::arg("trainable") = std::vector{ true, true, true }, py::arg("gpu_id") = 0, - py::arg("n_streams") = 1, + py::arg("n_units") = 1, R"pbdoc( Create Gaussian Process including its data, hyperparameters, and target. By default, the calculations are performed on the CPU. Setting at least gpu_id or -n_streams to a value enables computations on the GPU. +n_units to a value enables computations on the GPU. Parameters: input_data (list): Input data for the GP. @@ -117,7 +118,7 @@ n_streams to a value enables computations on the GPU. trainable (list): List of booleans for trainable hyperparameters. Default is {true, true, true}. gpu_id (int): ID of the GPU to use. Default is 0. - n_streams (int): Number of streams for GPU computation. Default is 1. + n_units (int): Number of streams/queues for GPU computation. Default is 1. )pbdoc") .def_readwrite("n_reg", &gprat::GP::n_reg) @@ -136,6 +137,8 @@ n_streams to a value enables computations on the GPU. py::arg("test_data"), py::arg("m_tiles"), py::arg("m_tile_size")) + .def( + "cholesky", &gprat::GP::cholesky, "Compute and return the Cholesky decomposition of the covariance matrix.") .def("optimize", &gprat::GP::optimize, py::arg("AdamParams")) .def("optimize_step", &gprat::GP::optimize_step, py::arg("AdamParams"), py::arg("iter")) .def("compute_loss", &gprat::GP::calculate_loss); diff --git a/bindings/utils_py.cpp b/bindings/utils_py.cpp index 277e40ef..4e694c0d 100644 --- a/bindings/utils_py.cpp +++ b/bindings/utils_py.cpp @@ -1,5 +1,6 @@ -#include "target.hpp" -#include "utils_c.hpp" +#include "gprat/target.hpp" +#include "gprat/utils.hpp" + #include #include @@ -32,7 +33,7 @@ void start_hpx_wrapper(std::vector args, std::size_t n_cores) } argv.push_back(nullptr); int argc = static_cast(args.size()); - utils::start_hpx_runtime(argc, argv.data()); + gprat::start_hpx_runtime(argc, argv.data()); } /** @@ -43,7 +44,7 @@ void start_hpx_wrapper(std::vector args, std::size_t n_cores) void init_utils(py::module &m) { m.def("compute_train_tiles", - &utils::compute_train_tiles, + &gprat::compute_train_tiles, py::arg("n_samples"), py::arg("n_tile_size"), R"pbdoc( @@ -58,7 +59,7 @@ void init_utils(py::module &m) )pbdoc"); m.def("compute_train_tile_size", - &utils::compute_train_tile_size, + &gprat::compute_train_tile_size, py::arg("n_samples"), py::arg("n_tiles"), R"pbdoc( @@ -73,7 +74,7 @@ void init_utils(py::module &m) )pbdoc"); m.def("compute_test_tiles", - &utils::compute_test_tiles, + &gprat::compute_test_tiles, py::arg("m_samples"), py::arg("n_tiles"), py::arg("n_tile_size"), @@ -90,7 +91,7 @@ void init_utils(py::module &m) )pbdoc"); m.def("print_vector", - &utils::print_vector, + &gprat::print_vector, py::arg("vec"), py::arg("start") = 0, py::arg("end") = -1, @@ -98,11 +99,12 @@ void init_utils(py::module &m) "Print elements of a vector with optional start, end, and separator parameters"); m.def("start_hpx", &start_hpx_wrapper, py::arg("args"), py::arg("n_cores")); // Using the wrapper function - m.def("resume_hpx", &utils::resume_hpx_runtime); - m.def("suspend_hpx", &utils::suspend_hpx_runtime); - m.def("stop_hpx", &utils::stop_hpx_runtime); + m.def("resume_hpx", &gprat::resume_hpx_runtime); + m.def("suspend_hpx", &gprat::suspend_hpx_runtime); + m.def("stop_hpx", &gprat::stop_hpx_runtime); - m.def("compiled_with_cuda", &utils::compiled_with_cuda, "Check if the code was compiled with CUDA support"); + m.def("compiled_with_cuda", &gprat::compiled_with_cuda, "Check if the code was compiled with CUDA support"); + m.def("compiled_with_sycl", &gprat::compiled_with_sycl, "Check if the code was compiled with SYCL support"); m.def("print_available_gpus", &gprat::print_available_gpus, "Print available GPUs with their properties"); m.def("gpu_count", &gprat::gpu_count, "Return the number of available GPUs"); diff --git a/boilerplate-benchmark.sh b/boilerplate-benchmark.sh new file mode 100755 index 00000000..a544dce3 --- /dev/null +++ b/boilerplate-benchmark.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +#SBATCH --job-name=gprat +#SBATCH --output=output_gprat.txt +#SBATCH --time=48:00:00 + +source ~/Setup_Scripts/setup_breyerml.sh + +if [[ "$HOSTNAME" == "simcl1n1" || "$HOSTNAME" == "simcl1n2" ]]; then + + ./execute-benchmark.sh yes yes yes yes gpu nvidia cuda + ./execute-benchmark.sh no no yes yes gpu nvidia sycl + +elif [[ "$HOSTNAME" == "simcl1n3" ]]; +then + + ./execute-benchmark.sh yes yes yes yes gpu amd + +elif [[ "$HOSTNAME" == "simcl1n4" ]]; +then + + ./execute-benchmark.sh yes yes yes yes cpu cpu + +fi \ No newline at end of file diff --git a/cmake/hpx-apex-compat.cmake b/cmake/hpx-apex-compat.cmake new file mode 100644 index 00000000..a863872e --- /dev/null +++ b/cmake/hpx-apex-compat.cmake @@ -0,0 +1,32 @@ +# HPX built with +static and instrumentation=apex embeds APEX's private +# zlib/rapidjson/otf2 dependencies into HPXTargets.cmake by bare name instead of +# as proper (exported) targets. Since no target with those names exists in a +# consuming project, CMake falls back to raw "-l" linker flags, which +# fail: "-lzlib" has no matching library file (real zlib produces libz, not +# libzlib) and "-lrapidjson" is header-only and never produces a library file at +# all. Defining targets with these exact names satisfies +# target_link_libraries()'s lookup before it degrades to a linker flag. This is +# purely additive: targets are only created when the real dependency can be +# found, so builds that don't hit this HPX export bug are unaffected. +if(NOT TARGET zlib) + find_package(ZLIB QUIET) + if(ZLIB_FOUND) + add_library(zlib INTERFACE IMPORTED) + target_link_libraries(zlib INTERFACE ZLIB::ZLIB) + endif() +endif() + +if(NOT TARGET rapidjson) + add_library(rapidjson INTERFACE IMPORTED) +endif() + +if(NOT TARGET otf2) + find_library( + GPRat_OTF2_LIBRARY + NAMES otf2 + HINTS "${Otf2_ROOT}/lib") + if(GPRat_OTF2_LIBRARY) + add_library(otf2 INTERFACE IMPORTED) + target_link_libraries(otf2 INTERFACE "${GPRat_OTF2_LIBRARY}") + endif() +endif() diff --git a/cmake/install-config.cmake b/cmake/install-config.cmake index 80345522..269fdc5f 100644 --- a/cmake/install-config.cmake +++ b/cmake/install-config.cmake @@ -10,5 +10,6 @@ else() endif() find_package(HPX REQUIRED) +include("${CMAKE_CURRENT_LIST_DIR}/hpx-apex-compat.cmake") include("${CMAKE_CURRENT_LIST_DIR}/GPRatTargets.cmake") diff --git a/compile_gprat.sh b/compile_gprat.sh index 1c63530a..dc2d1c4f 100755 --- a/compile_gprat.sh +++ b/compile_gprat.sh @@ -1,144 +1,533 @@ #!/bin/bash + +set -e # Exit immediately if a command exits with a non-zero status. + +################################################################################################### +# Parameters +################################################################################################### # $1: python/cpp -# $2: cpu/gpu -# $3: mkl -################################################################################ -set -e # Exit immediately if a command exits with a non-zero status. - -################################################################################ -# Configurations -################################################################################ +# $2: cpu/cuda/sycl +# $3: release/dev +# $4: mkl/none +# $5: apex profiling options: steps/cholesky/none + +################################################################################################### # Bindings -if [[ "$1" == "python" ]] -then - BINDINGS=ON - INSTALL_DIR=$(pwd)/examples/gprat_python -elif [[ "$1" == "cpp" ]] -then - BINDINGS=OFF - INSTALL_DIR=$(pwd)/examples/gprat_cpp +################################################################################################### +if [[ "$1" == "python" ]]; then + BINDINGS=ON + INSTALL_DIR=$(pwd)/examples/gprat_python +elif [[ "$1" == "cpp" ]]; then + BINDINGS=OFF + INSTALL_DIR=$(pwd)/examples/gprat_cpp else - echo "Please specify input parameter: python/cpp" - exit 1 + echo "Please specify input parameter: python/cpp" + exit 1 fi -# Select CMake preset +################################################################################################### +# CMake Presets +################################################################################################### if [[ "$2" == "cpu" ]]; then - # Release: + if [[ "$3" == "release" ]]; then PRESET=release-linux - # Debug: - #PRESET=dev-linux -elif [[ "$2" == "gpu" ]]; then - # Release: - PRESET=release-linux-gpu - # Debug: - #PRESET=dev-linux-gpu -elif [[ "$2" != "cpu" ]]; then - echo "Input parameter is missing. Using default: Run computations on CPU in Release mode" + elif [[ "$3" == "dev" ]]; then + PRESET=dev-linux + else + echo "Input parameter for release or dev mode is missing. Using default: Build in Release mode" PRESET=release-linux + fi +elif [[ "$2" == "cuda" ]]; then + if [[ "$3" == "release" ]]; then + PRESET=release-linux-cuda + elif [[ "$3" == "dev" ]]; then + PRESET=dev-linux-cuda + else + echo "Input parameter for release or dev mode is missing. Using default: Build in Release mode" + PRESET=release-linux-cuda + fi +elif [[ "$2" == "sycl" ]]; then + if [[ "$3" == "release" ]]; then + PRESET=release-linux-sycl + elif [[ "$3" == "dev" ]]; then + PRESET=dev-linux-sycl + else + echo "Input parameter for release or dev mode is missing. Using default: Build in Release mode" + PRESET=release-linux-sycl + fi +else + echo "Input parameter is not any of {cpu,cuda,sycl}. Using default: CPU in release mode." + PRESET=release-linux fi +################################################################################################### # Select BLAS library -if [[ "$3" == "mkl" ]] -then - USE_MKL=ON +################################################################################################### +if [[ "$4" == "mkl" ]]; then + USE_MKL=ON else - USE_MKL=OFF + USE_MKL=OFF fi # Select APEX profiling option -if [[ "$4" == "steps" ]]; then - GPRAT_APEX_STEPS=ON - GPRAT_APEX_CHOLESKY=OFF -elif [[ "$4" == "cholesky" ]]; then - GPRAT_APEX_STEPS=OFF - GPRAT_APEX_CHOLESKY=ON +if [[ "$5" == "steps" ]]; then + GPRAT_APEX_STEPS=ON + GPRAT_APEX_CHOLESKY=OFF +elif [[ "$5" == "cholesky" ]]; then + GPRAT_APEX_STEPS=OFF + GPRAT_APEX_CHOLESKY=ON else - GPRAT_APEX_STEPS=OFF - GPRAT_APEX_CHOLESKY=OFF + GPRAT_APEX_STEPS=OFF + GPRAT_APEX_CHOLESKY=OFF +fi + +################################################################################################### +# SYCL target defaults (overridden per host below) +################################################################################################### +GPRAT_SYCL_NVIDIA=${GPRAT_SYCL_NVIDIA:-OFF} +GPRAT_SYCL_AMD=${GPRAT_SYCL_AMD:-OFF} +GPRAT_SYCL_INTEL=${GPRAT_SYCL_INTEL:-OFF} +HIP_TARGETS=${HIP_TARGETS:-} + +################################################################################################### +# Pick Spack installation depending on the host +################################################################################################### + +# Set Spack if on simcl1n1, simcl1n2, simcl1n3, or simcl1n4 +if [[ \ + "$HOSTNAME" == "simcl1n1" || \ + "$HOSTNAME" == "simcl1n2" || \ + "$HOSTNAME" == "simcl1n3" || \ + "$HOSTNAME" == "simcl1n4" ]]; +then + + spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" + source $spack_destination/spack/share/spack/setup-env.sh + +fi + +# Set Spack if on psgs04 +# SITE-SPECIFIC: spack_destination is hardcoded for the pcsgs04 cluster. +# Adjust this path to match your local Spack installation before running on a different machine. +if [[ "$HOSTNAME" == "pcsgs04" ]]; then + + spack_destination="/scratch/grafml/gprat-spack/spack/" + source $spack_destination/share/spack/setup-env.sh + fi -if command -v spack &> /dev/null; then - echo "Spack command found, checking for environments..." - - # Get current hostname - HOSTNAME=$(hostname -s) - - if [[ "$HOSTNAME" == "ipvs-epyc1" ]]; then - # Check if the gprat_cpu_gcc environment exists - if spack env list | grep -q "gprat_cpu_gcc"; then - echo "Found gprat_cpu_gcc environment, activating it." - module load gcc/14.2.0 - export CXX=g++ - export CC=gcc - spack env activate gprat_cpu_gcc - GPRAT_WITH_CUDA=OFF # whether GPRAT_WITH_CUDA is ON of OFF is irrelevant for this example - fi - elif [[ "$HOSTNAME" == "sven0" || "$HOSTNAME" == "sven1" ]]; then - #module load gcc/13.2.1 - spack load openblas arch=linux-fedora38-riscv64 - HPX_CMAKE=$HOME/git_workspace/build-scripts/build/hpx/lib64/cmake/HPX - USE_MKL=OFF - elif [[ $(uname -i) == "aarch64" ]]; then - spack load gcc@14.2.0 - # Check if the gprat_cpu_arm environment exists - if spack env list | grep -q "gprat_cpu_arm"; then - echo "Found gprat_cpu_arm environment, activating it." - spack env activate gprat_cpu_arm - fi - USE_MKL=OFF - elif [[ "$HOSTNAME" == "simcl1n1" || "$HOSTNAME" == "simcl1n2" ]]; then - # Check if the gprat_gpu_clang environment exists - if spack env list | grep -q "gprat_gpu_clang"; then - echo "Found gprat_gpu_clang environment, activating it." - module load clang/17.0.1 - export CXX=clang++ - export CC=clang - module load cuda/12.0.1 - spack env activate gprat_gpu_clang - GPRAT_WITH_CUDA=ON - fi +################################################################################################### +# Setup Compilation Requirements +################################################################################################### + +# Assuming Spack is found ######################################################################### +if command -v spack &>/dev/null; then + + echo "Spack command found, checking for environments..." + + HOSTNAME=$(hostname -s) + + # ipvs-epyc1 #################################################################################### + if [[ "$HOSTNAME" == "ipvs-epyc1" ]]; then + + # Check whether the gprat_cpu_gcc environment exists + if spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.2.0 + export CXX=g++ + export CC=gcc + fi + + # sven0 and sven1 ############################################################################### + elif [[ "$HOSTNAME" == "sven0" || "$HOSTNAME" == "sven1" ]]; then + + # module load gcc/13.2.1 + spack load openblas arch=linux-fedora38-riscv64 + HPX_CMAKE=$HOME/git_workspace/build-scripts/build/hpx/lib64/cmake/HPX + USE_MKL=OFF + + # aarch64 ####################################################################################### + elif [[ $(uname -i) == "aarch64" ]]; then + + spack load gcc@14.2.0 + # Check if the gprat_cpu_arm environment exists + if spack env list | grep -q "gprat_cpu_arm"; then + echo "Found gprat_cpu_arm environment, activating it." + spack env activate gprat_cpu_arm + fi + USE_MKL=OFF + + # simcl1n1 and simcl1n2 with NVIDIA GPUs ######################################################## + elif [[ "$HOSTNAME" == "simcl1n1" || "$HOSTNAME" == "simcl1n2" ]]; then + + if [[ "$2" == "cpu" ]]; then # CPU build + + # Check if the gprat_cpu_gcc environment exists + if spack env list | grep -q "gprat_cpu_gcc"; then + + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + + # Load GCC 14.1.0 + module load gcc/14.1.0 + + # Set default compiler to GCC + export CXX=g++ + export CC=gcc + + else + + echo "Cannot find Spack environment gprat_cpu_gcc. Please run spack-repo/environments/setup_gprat_cpu_gcc.sh" 1>&2 + exit -1 + + fi + + else # GPU build + + if spack env list | grep -q "gprat_gpu_clang"; then + + echo "Found gprat_gpu_clang environment, activating it." + spack env activate gprat_gpu_clang + + CUDA_ARCH=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader | awk -F '.' '{print $1$2}') + + if [[ "$2" == "cuda" ]]; then # GPRat on NVIDIA GPUs with CUDA + + # Load CUDA and Clang modules + module load cuda/12.0.1 + module load clang/17.0.1 + + # Set default compiler to clang + export CXX=clang++ + export CC=clang + + elif [[ "$2" == "sycl" ]]; then # GPRat on NVIDIA GPUs with SYCL + + # Source Intel oneAPI environment if icpx is not yet in PATH + ONEAPI_COMPILER_ROOT="" + if ! command -v icpx &>/dev/null; then + ONEAPI_SETVARS="/import/sgs.scratch-simcl1/breyerml/Programs/spack/opt/spack/linux-zen4/intel-oneapi-compilers-2025.1.1-5ynklzzqslh265azbglzqdtecdghl7ob/setvars.sh" + if [[ -f "$ONEAPI_SETVARS" ]]; then + # setvars.sh requires a login shell; source just the compiler bin directory instead + ONEAPI_COMPILER_ROOT="$(dirname $ONEAPI_SETVARS)/compiler/2025.1" + export PATH="$ONEAPI_COMPILER_ROOT/bin:$PATH" + export LD_LIBRARY_PATH="$ONEAPI_COMPILER_ROOT/lib:${LD_LIBRARY_PATH:-}" + fi + fi + if [[ -z "$ONEAPI_COMPILER_ROOT" ]] && command -v icpx &>/dev/null; then + # icpx was already in PATH; derive root from its location + ONEAPI_COMPILER_ROOT="$(dirname $(dirname $(which icpx)))" + fi + + if command -v icpx &>/dev/null; then + + # Set default compiler to icpx + export CXX=icpx + export CC=icx + + # Set GPRat build options for SYCL on NVIDIA GPUs + GPRAT_SYCL_NVIDIA=ON + + # Load CUDA so icpx can find libdevice for NVIDIA SYCL targets + module load cuda/12.0.1 + GPRAT_SYCL_CUDA_PATH=${CUDA_HOME} + # Detect GPU SM arch (e.g. sm_80 for A30); default to sm_80 if detection fails + GPRAT_SYCL_NVIDIA_ARCH=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader 2>/dev/null | head -1 | tr -d '.' | sed 's/^/sm_/') + GPRAT_SYCL_NVIDIA_ARCH=${GPRAT_SYCL_NVIDIA_ARCH:-sm_80} + + # Add oneMath installation to CMAKE_PREFIX_PATH + CMAKE_PREFIX_PATH="/scratch-simcl1/grafml/Programs/oneMath_nvidia/oneMath/install/lib/cmake/oneMath:${CMAKE_PREFIX_PATH:-}" + + else + + echo \ + "Intel oneAPI DPC++ compiler (icpx) not found. " \ + "Please make sure that icpx is available in your PATH." 1>&2 + exit -1 + + fi + + fi + + else + + echo \ + "Cannot find Spack environment gprat_gpu_clang." \ + "Please run spack-repo/environments/setup_gprat_gpu_clang.sh" 1>&2 + exit -1 + + fi + + fi + + # simcl1n3 with AMD GPU ######################################################################### + elif [[ "$HOSTNAME" == "simcl1n3" ]]; then + + if [[ "$2" == "cpu" ]]; then # CPU build + + # Check if the gprat_cpu_gcc environment exists + if spack env list | grep -q "gprat_cpu_gcc"; then + + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + + # Load GCC 14.1.0 + module load gcc/14.1.0 + + # Set default compiler to GCC + export CXX=g++ + export CC=gcc + + else + + echo "Cannot find Spack environment gprat_cpu_gcc. Please run spack-repo/environments/setup_gprat_cpu_gcc.sh" 1>&2 + exit -1 + + fi + + else # GPU build + + # Check whether the gprat_gpu_clang environment exists + if spack env list | grep -q "gprat_gpu_clang"; then + + echo "Found gprat_gpu_clang environment, activating it." + spack env activate gprat_gpu_clang + + if [[ "$2" == "sycl" ]]; then # GPRat on AMD GPUs with SYCL + + # Source Intel oneAPI environment if icpx is not yet in PATH + ONEAPI_COMPILER_ROOT="" + if ! command -v icpx &>/dev/null; then + ONEAPI_SETVARS="/import/sgs.scratch-simcl1/breyerml/Programs/spack/opt/spack/linux-zen4/intel-oneapi-compilers-2025.1.1-5ynklzzqslh265azbglzqdtecdghl7ob/setvars.sh" + if [[ -f "$ONEAPI_SETVARS" ]]; then + # setvars.sh requires a login shell; source just the compiler bin directory instead + ONEAPI_COMPILER_ROOT="$(dirname $ONEAPI_SETVARS)/compiler/2025.1" + export PATH="$ONEAPI_COMPILER_ROOT/bin:$PATH" + export LD_LIBRARY_PATH="$ONEAPI_COMPILER_ROOT/lib:${LD_LIBRARY_PATH:-}" + fi + fi + if [[ -z "$ONEAPI_COMPILER_ROOT" ]] && command -v icpx &>/dev/null; then + # icpx was already in PATH; derive root from its location + ONEAPI_COMPILER_ROOT="$(dirname $(dirname $(which icpx)))" + fi + + # Set up ROCm/HIP environment (required for AMD GPU device libraries at link time) + ROCM_PATH=${ROCM_PATH:-/opt/rocm-6.4.0} + if [[ -d "$ROCM_PATH" ]]; then + export PATH="$ROCM_PATH/bin:$PATH" + export LD_LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib64:$ROCM_PATH/hip/lib:${LD_LIBRARY_PATH:-}" + export LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib64:$ROCM_PATH/hip/lib:${LIBRARY_PATH:-}" + export ROCM_PATH + fi + # Compatibility shim: libamd_comgr.so.2 → libamd_comgr.so.3 for icpx HIP adapter + COMGR_COMPAT_DIR="/data/scratch-simcl1/breyerml/Programs/.modulefiles/icpx" + if [[ -d "$COMGR_COMPAT_DIR" ]]; then + export LD_LIBRARY_PATH="$COMGR_COMPAT_DIR:${LD_LIBRARY_PATH:-}" + fi + export HSA_XNACK=1 + + if command -v icpx &>/dev/null; then + + # Set default compiler to icpx + export CXX=icpx + export CC=icx + + # Set GPRat build options for SYCL on AMD GPUs + GPRAT_SYCL_AMD=ON + + # Set GPRat HIP target for AMD Instinct MI210 GPU (required by icpx) + HIP_TARGETS="gfx90a" + + # Add oneMath installation to CMAKE_PREFIX_PATH + CMAKE_PREFIX_PATH="/scratch-simcl1/grafml/Programs/oneMath_amd/oneMath/install/lib/cmake/oneMath:${CMAKE_PREFIX_PATH:-}" + + else + + echo "Intel oneAPI DPC++ compiler (icpx) not found. Please make sure that icpx is available in your PATH." 1>&2 + exit -1 + + fi + + fi + + else + + echo "Cannot find Spack environment gprat_gpu_clang. Please run spack-repo/environments/setup_gprat_gpu_clang.sh" 1>&2 + exit -1 + + fi + + fi + + # simcl1n4 without GPU ########################################################################## + elif [[ "$HOSTNAME" == "simcl1n4" ]]; then + + if [[ "$2" == "cuda" || "$2" == "sycl" ]]; then + + echo "Error: simcl1n4 does not have a GPU." 1>&2 + exit -1 + + fi + + # Check if the gprat_cpu_gcc environment exists + if spack env list | grep -q "gprat_cpu_gcc"; then + + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + + # Load GCC 14.1.0 + module load gcc/14.1.0 + + # Set default compiler to GCC + export CXX=g++ + export CC=gcc + else - echo "Hostname is $HOSTNAME — no action taken." + + echo "Cannot find Spack environment gprat_cpu_gcc. Please run spack-repo/environments/setup_gprat_cpu_gcc.sh" 1>&2 + exit -1 + fi + + # pcsgs04 with Intel GPU ######################################################################## + elif [[ "$HOSTNAME" == "pcsgs04" ]]; then + + echo "Caution: Intel GPU support couldn't be tested and is in an experimental state." + + # Check whether the gprat_gpu_clang environment exists + if spack env list | grep -q "gprat_gpu_clang"; then + + echo "Found gprat_gpu_clang environment, activating it." + spack env activate gprat_gpu_clang + + if [[ "$2" == "sycl" ]]; then # GPRat on Intel GPUs with SYCL + + if command -v icpx &>/dev/null; then + + # Set default compiler to icpx + export CXX=icpx + export CC=icx + + # Set GPRat build options for SYCL on Intel GPUs + GPRAT_SYCL_INTEL=ON + + # Add oneMath installation to CMAKE_PREFIX_PATH. + # SITE-SPECIFIC: update this path to your local oneMath install prefix, + # or set CMAKE_PREFIX_PATH before invoking this script to override it. + CMAKE_PREFIX_PATH="/scratch/grafml/oneMath_intel_v0.9/oneMath/install:${CMAKE_PREFIX_PATH:-}" + + else + + echo \ + "Intel oneAPI DPC++ compiler (icpx) not found. Please make sure that icpx is available in your PATH." 1>&2 + exit -1 + + fi + + fi + + else + + echo \ + "Cannot find Spack environment gprat_gpu_clang. Please run spack-repo/environments/setup_gprat_gpu_clang.sh" 1>&2 + exit -1 + + fi + + # invalid hostnames ############################################################################# + else + + echo "Caution: This script does not cover host $HOSTNAME." + + fi + +# Assuming Spack is not found else - echo "Spack command not found. Building example without Spack." - # Assuming that Spack is not required on given system + + echo "Spack command not found. Building example without Spack." + fi +################################################################################################### +# Set up CMake +################################################################################################### + +# CPU build if [[ $PRESET == "release-linux" || $PRESET == "dev-linux" ]]; then - cmake --preset $PRESET \ - -DGPRAT_BUILD_BINDINGS=$BINDINGS \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - -DHPX_IGNORE_BOOST_COMPATIBILITY=ON \ - -DHPX_DIR=$HPX_CMAKE \ - -DGPRAT_ENABLE_FORMAT_TARGETS=OFF \ - -DGPRAT_ENABLE_MKL=$USE_MKL \ - -DGPRAT_APEX_STEPS=${GPRAT_APEX_STEPS} \ - -DGPRAT_APEX_CHOLESKY=${GPRAT_APEX_CHOLESKY} -elif [[ $PRESET == "release-linux-gpu" || $PRESET == "dev-linux-gpu" ]]; then - CUDA_ARCH=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader | awk -F '.' '{print $1$2}') - - cmake --preset $PRESET \ - -DGPRAT_BUILD_BINDINGS=$BINDINGS \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - -DHPX_IGNORE_BOOST_COMPATIBILITY=ON \ - -DGPRAT_ENABLE_FORMAT_TARGETS=OFF \ - -DGPRAT_ENABLE_MKL=$USE_MKL \ - -DGPRAT_APEX_STEPS=${GPRAT_APEX_STEPS} \ - -DGPRAT_APEX_CHOLESKY=${GPRAT_APEX_CHOLESKY} \ - -DCMAKE_C_COMPILER=$(which clang) \ - -DCMAKE_CXX_COMPILER=$(which clang++) \ - -DCMAKE_CUDA_COMPILER=$(which clang++) \ - -DCMAKE_CUDA_FLAGS=--cuda-path=${CUDA_HOME} \ - -DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCH} + + cmake --preset $PRESET -Wno-dev \ + -DGPRAT_BUILD_BINDINGS=$BINDINGS \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ + -DHPX_IGNORE_BOOST_COMPATIBILITY=ON \ + -DHPX_DIR=$HPX_CMAKE \ + -DGPRAT_ENABLE_FORMAT_TARGETS=OFF \ + -DGPRAT_ENABLE_MKL=$USE_MKL \ + -DGPRAT_APEX_STEPS=${GPRAT_APEX_STEPS} \ + -DGPRAT_APEX_CHOLESKY=${GPRAT_APEX_CHOLESKY} \ + -DGPRAT_WITH_DISTRIBUTED=ON \ + -DGPRAT_ENABLE_TESTS=ON \ + -DGPRAT_ENABLE_EXAMPLES=ON \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + +# CUDA build +elif [[ $PRESET == "release-linux-cuda" || $PRESET == "dev-linux-cuda" ]]; then + + cmake --preset $PRESET -Wno-dev \ + -DGPRAT_BUILD_BINDINGS=$BINDINGS \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ + -DHPX_IGNORE_BOOST_COMPATIBILITY=ON \ + -DGPRAT_ENABLE_FORMAT_TARGETS=OFF \ + -DGPRAT_ENABLE_MKL=$USE_MKL \ + -DGPRAT_APEX_STEPS=${GPRAT_APEX_STEPS} \ + -DGPRAT_APEX_CHOLESKY=${GPRAT_APEX_CHOLESKY} \ + -DGPRAT_WITH_DISTRIBUTED=ON \ + -DCMAKE_C_COMPILER=$(which clang) \ + -DCMAKE_CXX_COMPILER=$(which clang++) \ + -DCMAKE_CUDA_COMPILER=$(which clang++) \ + -DCMAKE_CUDA_FLAGS=--cuda-path=${CUDA_HOME} \ + -DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCH} \ + -DCMAKE_EXE_LINKER_FLAGS="-L${CUDA_HOME}/targets/x86_64-linux/lib" \ + -DGPRAT_ENABLE_TESTS=ON \ + -DGPRAT_ENABLE_EXAMPLES=ON \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + +# SYCL build +elif [[ $PRESET == "release-linux-sycl" || $PRESET == "dev-linux-sycl" ]]; then + + cmake --preset $PRESET -Wno-dev \ + -DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH \ + -DGPRAT_BUILD_BINDINGS=$BINDINGS \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ + -DHPX_IGNORE_BOOST_COMPATIBILITY=ON \ + -DGPRAT_ENABLE_FORMAT_TARGETS=OFF \ + -DGPRAT_ENABLE_MKL=$USE_MKL \ + -DGPRAT_APEX_STEPS=${GPRAT_APEX_STEPS} \ + -DGPRAT_APEX_CHOLESKY=${GPRAT_APEX_CHOLESKY} \ + -DGPRAT_WITH_DISTRIBUTED=ON \ + -DCMAKE_C_COMPILER=$(which icx) \ + -DCMAKE_CXX_COMPILER=$(which icpx) \ + -DGPRAT_WITH_SYCL=ON \ + -DGPRAT_SYCL_NVIDIA=$GPRAT_SYCL_NVIDIA \ + -DGPRAT_SYCL_AMD=$GPRAT_SYCL_AMD \ + -DGPRAT_SYCL_INTEL=$GPRAT_SYCL_INTEL \ + -DHIP_TARGETS=$HIP_TARGETS \ + -DGPRAT_SYCL_CUDA_PATH=${GPRAT_SYCL_CUDA_PATH:-} \ + -DGPRAT_SYCL_NVIDIA_ARCH=${GPRAT_SYCL_NVIDIA_ARCH:-} \ + -DCMAKE_BUILD_RPATH="${GPRAT_SYCL_CUDA_PATH:-}/lib64;${ONEAPI_COMPILER_ROOT}/lib" \ + -DGPRAT_ENABLE_TESTS=ON \ + -DGPRAT_ENABLE_EXAMPLES=ON \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON fi -################################################################################ +################################################################################################### # Compile code -################################################################################ +################################################################################################### cmake --build --preset $PRESET -- -j cmake --install build/$PRESET +################################################################################################### +# Run tests +################################################################################################### cd build/$PRESET ctest --output-on-failure --no-tests=ignore -C Release -j 2 diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 43e19b03..2eb310d3 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,11 +1,42 @@ +# Inner CMakeLists.txt + +# Options +# ############################################################################## + +# CUDA and SYCL are mutually exclusive, catch this error case +if(GPRAT_WITH_CUDA AND GPRAT_WITH_SYCL) + message( + FATAL_ERROR + "GPRAT_WITH_CUDA and GPRAT_WITH_SYCL cannot be enabled at the same time.") +endif() + +# SYCL +option(GPRAT_WITH_SYCL "Enable SYCL support with oneMath" OFF) + +option(GPRAT_SYCL_NVIDIA "Enable NVIDIA GPU support with oneMath SYCL backend" + OFF) +option(GPRAT_SYCL_AMD "Enable AMD GPU support with oneMath SYCL backend" OFF) +option(GPRAT_SYCL_INTEL "Enable Intel GPU support with oneMath SYCL backend" + OFF) + +set(HIP_TARGETS + "" + CACHE STRING "Target HIP architectures") + +# CUDA +option(GPRAT_WITH_CUDA "Enable GPU support with CUDA, cuSolver, cuBLAS" OFF) + +add_compile_definitions(GPRAT_WITH_CUDA=$ + GPRAT_WITH_SYCL=$) + if(GPRAT_WITH_CUDA) + set(CMAKE_CUDA_STANDARD 20) + set(CMAKE_CUDA_EXTENSIONS OFF) enable_language(CUDA) endif() -# Option for GPU support with CUDA, cuSolver, cuBLAS -option(GPRAT_WITH_CUDA "Enable GPU support with CUDA, cuSolver, cuBLAS" OFF) -# Pass variable to C++ code -add_compile_definitions(GPRAT_WITH_CUDA=$) +# Source files +# ############################################################################## # Option for steps duration measurement with APEX option(GPRAT_APEX_STEPS "Enable measuring duration of steps with APEX" OFF) @@ -25,12 +56,15 @@ option( # Pass variable to C++ code add_compile_definitions(GPRAT_APEX_CHOLESKY=$) +# Set general GPRAT source files set(SOURCE_FILES - src/gprat_c.cpp - src/utils_c.cpp + src/gprat.cpp + src/utils.cpp + src/performance_counters.cpp src/target.cpp - src/gp_kernels.cpp - src/gp_hyperparameters.cpp + src/tile_data.cpp + src/kernels.cpp + src/hyperparameters.cpp src/cpu/gp_functions.cpp src/cpu/gp_algorithms.cpp src/cpu/gp_uncertainty.cpp @@ -39,40 +73,185 @@ set(SOURCE_FILES src/cpu/adapter_cblas_fp32.cpp src/cpu/adapter_cblas_fp64.cpp) +# Add SYCL-specific source files if enabled +if(GPRAT_WITH_SYCL) + list( + APPEND + SOURCE_FILES + src/gpu/sycl/adapter_onemath.cpp + src/gpu/sycl/sycl_gp_algorithms.cpp + src/gpu/sycl/sycl_gp_functions.cpp + src/gpu/sycl/sycl_gp_optimizer.cpp + src/gpu/sycl/sycl_gp_uncertainty.cpp + src/gpu/sycl/sycl_tiled_algorithms.cpp) +endif() + +# Distributed HPX sources (HPX actions, tile cache, tiled dataset) +option(GPRAT_WITH_DISTRIBUTED "Enable distributed GP support via HPX actions" + OFF) +add_compile_definitions( + GPRAT_WITH_DISTRIBUTED=$) + +if(GPRAT_WITH_DISTRIBUTED) + list( + APPEND + SOURCE_FILES + src/cpu/adapter_cblas_fp64_actions.cpp + src/cpu/gp_algorithms_actions.cpp + src/cpu/gp_uncertainty_actions.cpp + src/cpu/gp_optimizer_actions.cpp + src/tile_cache.cpp + src/tiled_dataset.cpp) + + # HPX registration macros create static factory objects that icpx sees as + # unused + set_source_files_properties( + src/cpu/adapter_cblas_fp64_actions.cpp src/cpu/gp_algorithms_actions.cpp + src/cpu/gp_uncertainty_actions.cpp src/cpu/gp_optimizer_actions.cpp + src/tiled_dataset.cpp PROPERTIES COMPILE_OPTIONS "-Wno-unused-variable") +endif() + if(GPRAT_WITH_CUDA) list( APPEND SOURCE_FILES - src/gpu/gp_functions.cu - src/gpu/gp_algorithms.cu - src/gpu/gp_uncertainty.cu - src/gpu/gp_optimizer.cu - src/gpu/tiled_algorithms.cu - src/gpu/adapter_cublas.cu - src/gpu/cuda_kernels.cu) + src/gpu/cuda/gp_functions.cu + src/gpu/cuda/gp_algorithms.cu + src/gpu/cuda/gp_uncertainty.cu + src/gpu/cuda/gp_optimizer.cu + src/gpu/cuda/tiled_algorithms.cu + src/gpu/cuda/adapter_cublas.cu + src/gpu/cuda/cuda_kernels.cu) endif() +# Add GPRat core library +# ############################################################################## + +# Add GPRAT core library add_library(gprat_core STATIC ${SOURCE_FILES}) # We'd like to consume it just as core under the GPRat namespace set_property(TARGET gprat_core PROPERTY EXPORT_NAME core) add_library(GPRat::core ALIAS gprat_core) +# Headers +# ############################################################################## + # Add them as PRIVATE sources here so they show up in project files Can't use -# PUBLIC etc., see: https://stackoverflow.com/a/62465051 +# PUBLIC etc. see: https://stackoverflow.com/a/62465051 + file(GLOB_RECURSE header_files CONFIGURE_DEPENDS include/*.hpp include/cpu/*.hpp) + +if(GPRAT_WITH_SYCL) + file(GLOB_RECURSE sycl_headers CONFIGURE_DEPENDS include/sycl/*.hpp) + list(APPEND header_files ${sycl_headers}) +endif() + if(GPRAT_WITH_CUDA) file(GLOB_RECURSE cuda_headers CONFIGURE_DEPENDS include/gpu/*.cuh) list(APPEND header_files ${cuda_headers}) endif() + target_sources(gprat_core PRIVATE ${header_files}) +# Linking +# ############################################################################## + # Link HPX libraries target_link_libraries(gprat_core PUBLIC HPX::hpx) +# Link CUDA libaries if enabled if(GPRAT_WITH_CUDA) + find_package(CUDAToolkit MODULE REQUIRED) target_link_libraries(gprat_core PUBLIC CUDA::cusolver CUDA::cublas) + # Flag not working for CLANG CUDA + target_compile_features(gprat_core PUBLIC cuda_std_${CMAKE_CUDA_STANDARD}) +endif() + +# SYCL / oneMath linking +if(GPRAT_WITH_SYCL) + + find_package(oneMath REQUIRED) + + # Select SYCL backend architecture + set(GPRAT_SYCL_CUDA_PATH + "" + CACHE PATH "CUDA installation path for icpx NVIDIA SYCL target.") + + set(GPRAT_SYCL_NVIDIA_ARCH + "" + CACHE + STRING + "NVIDIA GPU SM arch for SYCL (e.g. sm_80). Derived from GPRAT_SYCL_CUDA_PATH if empty." + ) + + set(SYCL_FLAGS ${SYCL_FLAGS} -Wno-unused-command-line-argument) + + if(GPRAT_SYCL_NVIDIA) + + set(SYCL_FLAGS ${SYCL_FLAGS} -fsycl -fsycl-targets=nvptx64-nvidia-cuda) + if(GPRAT_SYCL_CUDA_PATH) + list(APPEND SYCL_FLAGS + "SHELL:-Xsycl-target-backend --cuda-path=${GPRAT_SYCL_CUDA_PATH}") + endif() + if(GPRAT_SYCL_NVIDIA_ARCH) + list( + APPEND SYCL_FLAGS + "SHELL:-Xsycl-target-backend --cuda-gpu-arch=${GPRAT_SYCL_NVIDIA_ARCH}") + endif() + + elseif(GPRAT_SYCL_AMD) + + set(SYCL_FLAGS ${SYCL_FLAGS} -fsycl -fsycl-targets=amdgcn-amd-amdhsa + -Xsycl-target-backend --offload-arch=${HIP_TARGETS}) + + elseif(GPRAT_SYCL_INTEL) + + set(SYCL_FLAGS ${SYCL_FLAGS} -fsycl -fsycl-targets=spir64) + + else() + + message( + FATAL_ERROR + "No SYCL backend specified. Please enable one of GPRAT_SYCL_NVIDIA, GPRAT_SYCL_AMD, or GPRAT_SYCL_INTEL." + ) + + endif() + + target_compile_options(gprat_core PUBLIC ${SYCL_FLAGS}) + + target_link_options(gprat_core PUBLIC ${SYCL_FLAGS}) + + # Set link libraries based on SYCL backend + if(GPRAT_SYCL_NVIDIA) + + target_link_libraries(gprat_core PUBLIC ONEMATH::onemath_blas_cublas + ONEMATH::onemath_lapack_cusolver) + + elseif(GPRAT_SYCL_AMD) + + target_link_libraries(gprat_core PUBLIC ONEMATH::onemath_blas_rocblas + ONEMATH::onemath_lapack_rocsolver) + + elseif(GPRAT_SYCL_INTEL) + + target_link_libraries(gprat_core PUBLIC ONEMATH::onemath_blas_mklgpu + ONEMATH::onemath_lapack_mklgpu) + + else() + + message( + FATAL_ERROR + "No SYCL backend specified. Please enable one of GPRAT_SYCL_NVIDIA, GPRAT_SYCL_AMD, or GPRAT_SYCL_INTEL." + ) + + endif() + + if(TARGET ONEMATH::onemath) + target_link_libraries(gprat_core PUBLIC ONEMATH::onemath) + endif() + endif() # Include directories @@ -90,10 +269,19 @@ else() target_link_libraries(gprat_core PUBLIC ${OpenBLAS_LIB}) endif() +target_compile_definitions(gprat_core + PUBLIC GPRAT_WITH_CUDA=$) +if(GPRAT_ENABLE_BENCHMARK_CACHE_EVICTIONS) + target_compile_definitions(gprat_core + PUBLIC GPRAT_ENABLE_BENCHMARK_CACHE_EVICTIONS) +endif() target_compile_features(gprat_core PUBLIC cxx_std_20) set_property(TARGET gprat_core PROPERTY POSITION_INDEPENDENT_CODE ON) +# Installation +# ############################################################################## + if(NOT CMAKE_SKIP_INSTALL_RULES) # We need to manually install those into CMAKE_INSTALL_INCLUDEDIR. Below # install(TARGETS ...) only setups the paths for the exported targets. @@ -111,3 +299,6 @@ if(NOT CMAKE_SKIP_INSTALL_RULES) INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") endif() + +# End of file +# ############################################################################## diff --git a/core/include/cpu/adapter_cblas_fp32.hpp b/core/include/cpu/adapter_cblas_fp32.hpp deleted file mode 100644 index aec6613b..00000000 --- a/core/include/cpu/adapter_cblas_fp32.hpp +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef CPU_ADAPTER_CBLAS_FP32_H -#define CPU_ADAPTER_CBLAS_FP32_H - -#include -#include -using vector_future = hpx::shared_future>; -using vector = std::vector; - -// Constants that are compatible with CBLAS -typedef enum BLAS_TRANSPOSE { Blas_no_trans = 111, Blas_trans = 112 } BLAS_TRANSPOSE; - -typedef enum BLAS_SIDE { Blas_left = 141, Blas_right = 142 } BLAS_SIDE; - -typedef enum BLAS_ALPHA { Blas_add = 1, Blas_substract = -1 } BLAS_ALPHA; - -// typedef enum BLAS_UPLO { Blas_upper = 121, -// Blas_lower = 122 } BLAS_UPLO; - -// typedef enum BLAS_ORDERING { Blas_row_major = 101, -// Blas_col_major = 102 } BLAS_ORDERING; - -// BLAS level 3 operations - -/** - * @brief FP32 In-place Cholesky decomposition of A - * @param f_A matrix to be factorized - * @param N matrix dimension - * @return factorized, lower triangular matrix L - */ -vector potrf(vector_future f_A, const int N); - -/** - * @brief FP32 In-place solve L(^T) * X = A or X * L(^T) = A where L lower triangular - * @param f_L Cholesky factor matrix - * @param f_A right hand side matrix - * @param N first dimension - * @param M second dimension - * @return solution matrix X - */ -vector trsm(vector_future f_L, - vector_future f_A, - const int N, - const int M, - const BLAS_TRANSPOSE transpose_L, - const BLAS_SIDE side_L); - -/** - * @brief FP32 Symmetric rank-k update: A = A - B * B^T - * @param f_A Base matrix - * @param f_B Symmetric update matrix - * @param N matrix dimension - * @return updated matrix A - */ -vector syrk(vector_future f_A, vector_future f_B, const int N); - -/** - * @brief FP32 General matrix-matrix multiplication: C = C - A(^T) * B(^T) - * @param f_C Base matrix - * @param f_B Right update matrix - * @param f_A Left update matrix - * @param N first matrix dimension - * @param M second matrix dimension - * @param K third matrix dimension - * @param transpose_A transpose left matrix - * @param transpose_B transpose right matrix - * @return updated matrix X - */ -vector gemm(vector_future f_A, - vector_future f_B, - vector_future f_C, - const int N, - const int M, - const int K, - const BLAS_TRANSPOSE transpose_A, - const BLAS_TRANSPOSE transpose_B); - -// BLAS level 2 operations - -/** - * @brief FP32 In-place solve L(^T) * x = a where L lower triangular - * @param f_L Cholesky factor matrix - * @param f_a right hand side vector - * @param N matrix dimension - * @param transpose_L transpose Cholesky factor - * @return solution vector x - */ -vector trsv(vector_future f_L, vector_future f_a, const int N, const BLAS_TRANSPOSE transpose_L); - -/** - * @brief FP32 General matrix-vector multiplication: b = b - A(^T) * a - * @param f_A update matrix - * @param f_a update vector - * @param f_b base vector - * @param N matrix dimension - * @param alpha add or substract update to base vector - * @param transpose_A transpose update matrix - * @return updated vector b - */ -vector gemv(vector_future f_A, - vector_future f_a, - vector_future f_b, - const int N, - const int M, - const BLAS_ALPHA alpha, - const BLAS_TRANSPOSE transpose_A); - -/** - * @brief FP32 Vector update with diagonal SYRK: r = r + diag(A^T * A) - * @param f_A update matrix - * @param f_r base vector - * @param N first matrix dimension - * @param M second matrix dimension - * @return updated vector r - */ -vector dot_diag_syrk(vector_future f_A, vector_future f_r, const int N, const int M); - -/** - * @brief FP32 Vector update with diagonal GEMM: r = r + diag(A * B) - * @param f_A first update matrix - * @param f_B second update matrix - * @param f_r base vector - * @param N first matrix dimension - * @param M second matrix dimension - * @return updated vector r - */ -vector dot_diag_gemm(vector_future f_A, vector_future f_B, vector_future f_r, const int N, const int M); - -// BLAS level 1 operations - -/** - * @brief FP32 AXPY: y - x - * @param f_y left vector - * @param f_x right vector - * @param N vector length - * @return y - x - */ -vector axpy(vector_future f_y, vector_future f_x, const int N); - -/** - * @brief FP32 Dot product: a * b - * @param f_a left vector - * @param f_b right vector - * @param N vector length - * @return a * b - */ -float dot(std::vector a, std::vector b, const int N); - -#endif // end of CPU_ADAPTER_CBLAS_FP32_H diff --git a/core/include/cpu/adapter_cblas_fp64.hpp b/core/include/cpu/adapter_cblas_fp64.hpp deleted file mode 100644 index b8bbcdad..00000000 --- a/core/include/cpu/adapter_cblas_fp64.hpp +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef CPU_ADAPTER_CBLAS_FP64_H -#define CPU_ADAPTER_CBLAS_FP64_H - -#include -#include - -using vector_future = hpx::shared_future>; -using vector = std::vector; - -// Constants that are compatible with CBLAS - -typedef enum BLAS_TRANSPOSE { Blas_no_trans = 111, Blas_trans = 112 } BLAS_TRANSPOSE; - -typedef enum BLAS_SIDE { Blas_left = 141, Blas_right = 142 } BLAS_SIDE; - -typedef enum BLAS_ALPHA { Blas_add = 1, Blas_substract = -1 } BLAS_ALPHA; - -// typedef enum BLAS_UPLO { Blas_upper = 121, -// Blas_lower = 122 } BLAS_UPLO; - -// typedef enum BLAS_ORDERING { Blas_row_major = 101, -// Blas_col_major = 102 } BLAS_ORDERING; - -// BLAS level 3 operations - -/** - * @brief FP64 In-place Cholesky decomposition of A - * @param f_A matrix to be factorized - * @param N matrix dimension - * @return factorized, lower triangular matrix L - */ -vector potrf(vector_future f_A, const int N); - -/** - * @brief FP64 In-place solve L(^T) * X = A or X * L(^T) = A where L lower triangular - * @param f_L Cholesky factor matrix - * @param f_A right hand side matrix - * @param N first dimension - * @param M second dimension - * @return solution matrix X - */ -vector trsm(vector_future f_L, - vector_future f_A, - const int N, - const int M, - const BLAS_TRANSPOSE transpose_L, - const BLAS_SIDE side_L); - -/** - * @brief FP64 Symmetric rank-k update: A = A - B * B^T - * @param f_A Base matrix - * @param f_B Symmetric update matrix - * @param N matrix dimension - * @return updated matrix A - */ -vector syrk(vector_future f_A, vector_future f_B, const int N); - -/** - * @brief FP64 General matrix-matrix multiplication: C = C - A(^T) * B(^T) - * @param f_C Base matrix - * @param f_B Right update matrix - * @param f_A Left update matrix - * @param N first matrix dimension - * @param M second matrix dimension - * @param K third matrix dimension - * @param transpose_A transpose left matrix - * @param transpose_B transpose right matrix - * @return updated matrix X - */ -vector gemm(vector_future f_A, - vector_future f_B, - vector_future f_C, - const int N, - const int M, - const int K, - const BLAS_TRANSPOSE transpose_A, - const BLAS_TRANSPOSE transpose_B); - -// BLAS level 2 operations - -/** - * @brief FP64 In-place solve L(^T) * x = a where L lower triangular - * @param f_L Cholesky factor matrix - * @param f_a right hand side vector - * @param N matrix dimension - * @param transpose_L transpose Cholesky factor - * @return solution vector x - */ -vector trsv(vector_future f_L, vector_future f_a, const int N, const BLAS_TRANSPOSE transpose_L); - -/** - * @brief FP64 General matrix-vector multiplication: b = b - A(^T) * a - * @param f_A update matrix - * @param f_a update vector - * @param f_b base vector - * @param N matrix dimension - * @param alpha add or substract update to base vector - * @param transpose_A transpose update matrix - * @return updated vector b - */ -vector gemv(vector_future f_A, - vector_future f_a, - vector_future f_b, - const int N, - const int M, - const BLAS_ALPHA alpha, - const BLAS_TRANSPOSE transpose_A); - -/** - * @brief FP64 Vector update with diagonal SYRK: r = r + diag(A^T * A) - * @param f_A update matrix - * @param f_r base vector - * @param N first matrix dimension - * @param M second matrix dimension - * @return updated vector r - */ -vector dot_diag_syrk(vector_future f_A, vector_future f_r, const int N, const int M); - -/** - * @brief FP64 Vector update with diagonal GEMM: r = r + diag(A * B) - * @param f_A first update matrix - * @param f_B second update matrix - * @param f_r base vector - * @param N first matrix dimension - * @param M second matrix dimension - * @return updated vector r - */ -vector dot_diag_gemm(vector_future f_A, vector_future f_B, vector_future f_r, const int N, const int M); - -// BLAS level 1 operations - -/** - * @brief FP64 AXPY: y - x - * @param f_y left vector - * @param f_x right vector - * @param N vector length - * @return y - x - */ -vector axpy(vector_future f_y, vector_future f_x, const int N); - -/** - * @brief FP64 Dot product: a * b - * @param a left vector - * @param b right vector - * @param N vector length - * @return a * b - */ -double dot(std::vector a, std::vector b, const int N); - -#endif // end of CPU_ADAPTER_CBLAS_FP64_H diff --git a/core/include/cpu/gp_uncertainty.hpp b/core/include/cpu/gp_uncertainty.hpp deleted file mode 100644 index 28089584..00000000 --- a/core/include/cpu/gp_uncertainty.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CPU_GP_UNCERTAINTY_H -#define CPU_GP_UNCERTAINTY_H - -#include -#include - -namespace cpu -{ - -/** - * @brief Extract diagonal elements of the matrix A. - * - * @param A The matrix - * @param M The rumber of rows in the matrix - * - * @return Diagonal element vector of the matrix A of size M - */ -// std::vector get_matrix_diagonal(const std::vector &A, std::size_t M); -hpx::shared_future> get_matrix_diagonal(hpx::shared_future> f_A, std::size_t M); - -} // end of namespace cpu - -#endif // end of CPU_GP_UNCERTAINTY_H diff --git a/core/include/cpu/tiled_algorithms.hpp b/core/include/cpu/tiled_algorithms.hpp deleted file mode 100644 index 28c25c05..00000000 --- a/core/include/cpu/tiled_algorithms.hpp +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef CPU_TILED_ALGORITHMS_H -#define CPU_TILED_ALGORITHMS_H - -#include "gp_hyperparameters.hpp" -#include "gp_kernels.hpp" -#include - -using Tiled_matrix = std::vector>>; -using Tiled_vector = std::vector>>; - -namespace cpu -{ - -// Tiled Cholesky Algorithm - -/** - * @brief Perform right-looking tiled Cholesky decomposition. - * - * @param ft_tiles Tiled matrix represented as a vector of futurized tiles, containing the - * covariance matrix, afterwards the Cholesky decomposition. - * @param N Tile size per dimension. - * @param n_tiles Number of tiles per dimension. - */ -void right_looking_cholesky_tiled(Tiled_matrix &ft_tiles, int N, std::size_t n_tiles); - -// Tiled Triangular Solve Algorithms - -/** - * @brief Perform tiled forward triangular matrix-vector solve. - * - * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. - * @param ft_rhs Tiled right-hand side vector, afterwards containing the tiled solution vector - * @param N Tile size per dimension. - * @param n_tiles Number of tiles per dimension. - */ -void forward_solve_tiled(Tiled_matrix &ft_tiles, Tiled_vector &ft_rhs, int N, std::size_t n_tiles); - -/** - * @brief Perform tiled backward triangular matrix-vector solve. - * - * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. - * @param ft_rhs Tiled right-hand side vector, afterwards containing the tiled solution vector - * @param N Tile size per dimension. - * @param n_tiles Number of tiles per dimension. - */ -void backward_solve_tiled(Tiled_matrix &ft_tiles, Tiled_vector &ft_rhs, int N, std::size_t n_tiles); - -/** - * @brief Perform tiled forward triangular matrix-matrix solve. - * - * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. - * @param ft_rhs Tiled right-hand side matrix, afterwards containing the tiled solution matrix. - * @param N Tile size of first dimension. - * @param M Tile size of second dimension. - * @param n_tiles Number of tiles in first dimension. - * @param m_tiles Number of tiles in second dimension. - */ -void forward_solve_tiled_matrix( - Tiled_matrix &ft_tiles, Tiled_matrix &ft_rhs, int N, int M, std::size_t n_tiles, std::size_t m_tiles); - -/** - * @brief Perform tiled backward triangular matrix-matrix solve. - * - * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. - * @param ft_rhs Tiled right-hand side matrix, afterwards containing the tiled solution matrix. - * @param N Tile size of first dimension. - * @param M Tile size of second dimension. - * @param n_tiles Number of tiles in first dimension. - * @param m_tiles Number of tiles in second dimension. - */ -void backward_solve_tiled_matrix( - Tiled_matrix &ft_tiles, Tiled_matrix &ft_rhs, int N, int M, std::size_t n_tiles, std::size_t m_tiles); - -/** - * @brief Perform tiled matrix-vector multiplication - * - * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. - * @param ft_vector Tiled vector represented as a vector of futurized tiles. - * @param ft_rhsTiled solution represented as a vector of futurized tiles. - * @param N_row Tile size of first dimension. - * @param N_col Tile size of second dimension. - * @param n_tiles Number of tiles in first dimension. - * @param m_tiles Number of tiles in second dimension. - */ -void matrix_vector_tiled(Tiled_matrix &ft_tiles, - Tiled_vector &ft_vector, - Tiled_vector &ft_rhs, - int N_row, - int N_col, - std::size_t n_tiles, - std::size_t m_tiles); - -/** - * @brief Perform tiled symmetric k-rank update on diagonal tiles - * - * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. - * @param ft_vector Tiled vector holding the diagonal tile results - * @param N Tile size of first dimension. - * @param M Tile size of second dimension. - * @param n_tiles Number of tiles in first dimension. - * @param m_tiles Number of tiles in second dimension. - */ -void symmetric_matrix_matrix_diagonal_tiled( - Tiled_matrix &ft_tiles, Tiled_vector &ft_vector, int N, int M, std::size_t n_tiles, std::size_t m_tiles); - -/** - * @brief Perform tiled symmetric k-rank update (ft_tiles^T * ft_tiles) - * - * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. - * @param ft_result Tiled matrix holding the result of the computationi. - * @param N Tile size of first dimension. - * @param M Tile size of second dimension. - * @param n_tiles Number of tiles in first dimension. - * @param m_tiles Number of tiles in second dimension. - */ -void symmetric_matrix_matrix_tiled( - Tiled_matrix &ft_tiles, Tiled_matrix &ft_result, int N, int M, std::size_t n_tiles, std::size_t m_tiles); - -/** - * @brief Compute the difference between two tiled vectors - * @param ft_minuend Tiled vector that is being subtracted from. - * @param ft_subtrahend Tiled vector that is being subtracted. - * @param ft_difference Tiled vector that contains the result of the substraction. - * @param M Tile size dimension. - * @param m_tiles Number of tiles. - */ -void vector_difference_tiled(Tiled_vector &ft_minuend, Tiled_vector &ft_substrahend, int M, std::size_t m_tiles); - -/** - * @brief Extract the tiled diagonals of a tiled matrix - * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. - * @param ft_vector Tiled vector containing the diagonals of the matrix tiles - * @param M Tile size per dimension. - * @param m_tiles Number of tiles per dimension. - */ -void matrix_diagonal_tiled(Tiled_matrix &ft_tiles, Tiled_vector &ft_vector, int M, std::size_t m_tiles); - -/** - * @brief Compute the negative log likelihood loss with a tiled covariance matrix K. - * - * Computes l = 0.5 * ( log(det(K)) + y^T * K^-1 * y) + const.) - * - * @param ft_tiles Tiled Cholesky factor matrix represented as a vector of futurized tiles. - * @param ft_alpha Tiled vector containing the solution of K^-1 * y - * @param ft_y Tiled vector containing the the training output y - * @param loss The loss value to be computed - * @param N Tile size per dimension. - * @param n_tiles Number of tiles per dimension. - */ -void compute_loss_tiled(Tiled_matrix &ft_tiles, - Tiled_vector &ft_alpha, - Tiled_vector &ft_y, - hpx::shared_future &loss, - int N, - std::size_t n_tiles); - -/** - * @brief Updates a hyperparameter of the SEK kernel using Adam - * - * @param ft_invK Tiled inverse of the covariance matrix K represented as a vector of futurized tiles. - * @param ft_grad_param Tiled covariance matrix gradient w.r.t. a hyperparameter. - * @param ft_alpha Tiled vector containing the precomputed inv(K) * y where y is the training output. - * @param adam_params Hyperparameter of the Adam optimizer - * @param sek_params Hyperparameters of the SEK kernel - * @param N Tile size per dimension. - * @param n_tiles Number of tiles per dimension. - * @param iter Current iteration. - * @param param_idx Index of the hyperparameter to optimize. - */ -void update_hyperparameter_tiled( - const Tiled_matrix &ft_invK, - const Tiled_matrix &ft_gradK_param, - const Tiled_vector &ft_alpha, - const gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, - int N, - std::size_t n_tiles, - std::size_t iter, - std::size_t param_idx); - -} // end of namespace cpu - -#endif // end of CPU_TILED_ALGORITHMS_H diff --git a/core/include/gprat/cpu/adapter_cblas_fp32.hpp b/core/include/gprat/cpu/adapter_cblas_fp32.hpp new file mode 100644 index 00000000..6101d040 --- /dev/null +++ b/core/include/gprat/cpu/adapter_cblas_fp32.hpp @@ -0,0 +1,154 @@ +#ifndef GPRAT_CPU_ADAPTER_CBLAS_FP32_HPP +#define GPRAT_CPU_ADAPTER_CBLAS_FP32_HPP + +#pragma once + +#include "gprat/cpu/blas_enums.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/tile_data.hpp" + +#include + +GPRAT_NS_BEGIN + +// typedef enum BLAS_UPLO { Blas_upper = 121, +// Blas_lower = 122 } BLAS_UPLO; + +// typedef enum BLAS_ORDERING { Blas_row_major = 101, +// Blas_col_major = 102 } BLAS_ORDERING; + +// BLAS level 3 operations + +/** + * @brief FP32 In-place Cholesky decomposition of A + * @param A matrix to be factorized + * @param N matrix dimension + * @return factorized, lower triangular matrix L + */ +mutable_tile_data potrf(const mutable_tile_data &A, int N); + +/** + * @brief FP32 In-place solve L(^T) * X = A or X * L(^T) = A where L lower triangular + * @param L Cholesky factor matrix + * @param A right hand side matrix + * @param N first dimension + * @param M second dimension + * @return solution matrix X + */ +mutable_tile_data +trsm(const const_tile_data &L, + const mutable_tile_data &A, + int N, + int M, + BLAS_TRANSPOSE transpose_L, + BLAS_SIDE side_L); + +/** + * @brief FP32 Symmetric rank-k update: A = A - B * B^T + * @param A Base matrix + * @param B Symmetric update matrix + * @param N matrix dimension + * @return updated matrix A + */ +mutable_tile_data syrk(const mutable_tile_data &A, const const_tile_data &B, int N); + +/** + * @brief FP32 General matrix-matrix multiplication: C = C - A(^T) * B(^T) + * @param C Base matrix + * @param B Right update matrix + * @param A Left update matrix + * @param N first matrix dimension + * @param M second matrix dimension + * @param K third matrix dimension + * @param transpose_A transpose left matrix + * @param transpose_B transpose right matrix + * @return updated matrix X + */ +mutable_tile_data +gemm(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &C, + int N, + int M, + int K, + BLAS_TRANSPOSE transpose_A, + BLAS_TRANSPOSE transpose_B); + +// BLAS level 2 operations + +/** + * @brief FP32 In-place solve L(^T) * x = a where L lower triangular + * @param L Cholesky factor matrix + * @param a right hand side vector + * @param N matrix dimension + * @param transpose_L transpose Cholesky factor + * @return solution vector x + */ +mutable_tile_data +trsv(const const_tile_data &L, const mutable_tile_data &a, int N, BLAS_TRANSPOSE transpose_L); + +/** + * @brief FP32 General matrix-vector multiplication: b = b - A(^T) * a + * @param A update matrix + * @param a update vector + * @param b base vector + * @param N matrix dimension + * @param alpha add or subtract update to base vector + * @param transpose_A transpose update matrix + * @return updated vector b + */ +mutable_tile_data +gemv(const const_tile_data &A, + const const_tile_data &a, + const mutable_tile_data &b, + int N, + int M, + BLAS_ALPHA alpha, + BLAS_TRANSPOSE transpose_A); + +/** + * @brief FP32 Vector update with diagonal SYRK: r = r + diag(A^T * A) + * @param A update matrix + * @param r base vector + * @param N first matrix dimension + * @param M second matrix dimension + * @return updated vector r + */ +mutable_tile_data +dot_diag_syrk(const const_tile_data &A, const mutable_tile_data &r, int N, int M); + +/** + * @brief FP32 Vector update with diagonal GEMM: r = r + diag(A * B) + * @param A first update matrix + * @param B second update matrix + * @param r base vector + * @param N first matrix dimension + * @param M second matrix dimension + * @return updated vector r + */ +mutable_tile_data dot_diag_gemm( + const const_tile_data &A, const const_tile_data &B, const mutable_tile_data &r, int N, int M); + +// BLAS level 1 operations + +/** + * @brief FP32 AXPY: y - x + * @param y left vector + * @param x right vector + * @param N vector length + * @return y - x + */ +mutable_tile_data axpy(const mutable_tile_data &y, const const_tile_data &x, int N); + +/** + * @brief FP32 Dot product: a * b + * @param a left vector + * @param b right vector + * @param N vector length + * @return a * b + */ +float dot(std::span a, std::span b, int N); + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/cpu/adapter_cblas_fp64.hpp b/core/include/gprat/cpu/adapter_cblas_fp64.hpp new file mode 100644 index 00000000..459eff5e --- /dev/null +++ b/core/include/gprat/cpu/adapter_cblas_fp64.hpp @@ -0,0 +1,158 @@ +#ifndef GPRAT_CPU_ADAPTER_CBLAS_FP64_HPP +#define GPRAT_CPU_ADAPTER_CBLAS_FP64_HPP + +#pragma once + +#include "gprat/cpu/blas_enums.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/tile_data.hpp" + +#include + +GPRAT_NS_BEGIN + +// typedef enum BLAS_UPLO { Blas_upper = 121, +// Blas_lower = 122 } BLAS_UPLO; + +// typedef enum BLAS_ORDERING { Blas_row_major = 101, +// Blas_col_major = 102 } BLAS_ORDERING; + +// BLAS level 3 operations + +/** + * @brief FP64 In-place Cholesky decomposition of A + * @param A matrix to be factorized + * @param N matrix dimension + * @return factorized, lower triangular matrix L + */ +mutable_tile_data potrf(const mutable_tile_data &A, int N); + +/** + * @brief FP64 In-place solve L(^T) * X = A or X * L(^T) = A where L lower triangular + * @param L Cholesky factor matrix + * @param A right hand side matrix + * @param N first dimension + * @param M second dimension + * @return solution matrix X + */ +mutable_tile_data +trsm(const const_tile_data &L, + const mutable_tile_data &A, + int N, + int M, + BLAS_TRANSPOSE transpose_L, + BLAS_SIDE side_L); + +/** + * @brief FP64 Symmetric rank-k update: A = A - B * B^T + * @param A Base matrix + * @param B Symmetric update matrix + * @param N matrix dimension + * @return updated matrix A + */ +mutable_tile_data syrk(const mutable_tile_data &A, const const_tile_data &B, int N); + +/** + * @brief FP64 General matrix-matrix multiplication: C = C - A(^T) * B(^T) + * @param C Base matrix + * @param B Right update matrix + * @param A Left update matrix + * @param N first matrix dimension + * @param M second matrix dimension + * @param K third matrix dimension + * @param transpose_A transpose left matrix + * @param transpose_B transpose right matrix + * @return updated matrix X + */ +mutable_tile_data +gemm(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &C, + int N, + int M, + int K, + BLAS_TRANSPOSE transpose_A, + BLAS_TRANSPOSE transpose_B); + +// BLAS level 2 operations + +/** + * @brief FP64 In-place solve L(^T) * x = a where L lower triangular + * @param L Cholesky factor matrix + * @param a right hand side vector + * @param N matrix dimension + * @param transpose_L transpose Cholesky factor + * @return solution vector x + */ +mutable_tile_data +trsv(const const_tile_data &L, const mutable_tile_data &a, int N, BLAS_TRANSPOSE transpose_L); + +/** + * @brief FP64 General matrix-vector multiplication: b = b - A(^T) * a + * @param A update matrix + * @param a update vector + * @param b base vector + * @param N matrix dimension + * @param alpha add or substract update to base vector + * @param transpose_A transpose update matrix + * @return updated vector b + */ +mutable_tile_data +gemv(const const_tile_data &A, + const const_tile_data &a, + const mutable_tile_data &b, + int N, + int M, + BLAS_ALPHA alpha, + BLAS_TRANSPOSE transpose_A); + +/** + * @brief FP64 Vector update with diagonal SYRK: r = r + diag(A^T * A) + * @param A update matrix + * @param r base vector + * @param N first matrix dimension + * @param M second matrix dimension + * @return updated vector r + */ +mutable_tile_data +dot_diag_syrk(const const_tile_data &A, const mutable_tile_data &r, int N, int M); + +/** + * @brief FP64 Vector update with diagonal GEMM: r = r + diag(A * B) + * @param A first update matrix + * @param B second update matrix + * @param r base vector + * @param N first matrix dimension + * @param M second matrix dimension + * @return updated vector r + */ +mutable_tile_data +dot_diag_gemm(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &r, + int N, + int M); + +// BLAS level 1 operations + +/** + * @brief FP64 AXPY: y - x + * @param f_y left vector + * @param f_x right vector + * @param N vector length + * @return y - x + */ +mutable_tile_data axpy(const mutable_tile_data &y, const const_tile_data &x, int N); + +/** + * @brief FP64 Dot product: a * b + * @param a left vector + * @param b right vector + * @param N vector length + * @return a * b + */ +double dot(std::span a, std::span b, int N); + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/cpu/adapter_cblas_fp64_actions.hpp b/core/include/gprat/cpu/adapter_cblas_fp64_actions.hpp new file mode 100644 index 00000000..442bd929 --- /dev/null +++ b/core/include/gprat/cpu/adapter_cblas_fp64_actions.hpp @@ -0,0 +1,83 @@ +#ifndef GPRAT_CPU_ADAPTER_CBLAS_FP64_ACTIONS_HPP +#define GPRAT_CPU_ADAPTER_CBLAS_FP64_ACTIONS_HPP + +#pragma once + +#include "gprat/cpu/adapter_cblas_fp64.hpp" +#include "gprat/detail/actions.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/tiled_dataset.hpp" + +#include + +GPRAT_NS_BEGIN + +namespace cpu +{ + +hpx::future> potrf_distributed(const tile_handle &A, int N); +hpx::future> trsm_distributed( + const tile_handle &L, + const tile_handle &A, + int N, + int M, + BLAS_TRANSPOSE transpose_L, + BLAS_SIDE side_L); +hpx::future> syrk_distributed(const tile_handle &A, const tile_handle &B, int N); +hpx::future> gemm_distributed( + const tile_handle &A, + const tile_handle &B, + const tile_handle &C, + int N, + int M, + int K, + BLAS_TRANSPOSE transpose_A, + BLAS_TRANSPOSE transpose_B); + +hpx::future> +trsv_distributed(const tile_handle &L, const tile_handle &a, int N, BLAS_TRANSPOSE transpose_L); +hpx::future> gemv_distributed( + const tile_handle &A, + const tile_handle &a, + const tile_handle &b, + int N, + int M, + BLAS_ALPHA alpha, + BLAS_TRANSPOSE transpose_A); + +hpx::future> +dot_diag_syrk_distributed(const tile_handle &A, const tile_handle &r, int N, int M); +hpx::future> dot_diag_gemm_distributed( + const tile_handle &A, const tile_handle &B, const tile_handle &r, int N, int M); +hpx::future> axpy_distributed(const tile_handle &y, const tile_handle &x, int N); + +// This just gives us the action type (that we want in the correct namespace) +HPX_DEFINE_PLAIN_DIRECT_ACTION(potrf_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(trsm_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(syrk_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gemm_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(trsv_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gemv_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(dot_diag_syrk_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(dot_diag_gemm_distributed); +HPX_DEFINE_PLAIN_DIRECT_ACTION(axpy_distributed); + +} // namespace cpu + +GPRAT_NS_END + +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::potrf, GPRAT_NS::cpu::potrf_distributed_action, "POTRF"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::trsm, GPRAT_NS::cpu::trsm_distributed_action, "TRSM"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::syrk, GPRAT_NS::cpu::syrk_distributed_action, "SYRK"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::gemm, GPRAT_NS::cpu::gemm_distributed_action, "GEMM"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::trsv, GPRAT_NS::cpu::trsv_distributed_action, "TRSV"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::gemv, GPRAT_NS::cpu::gemv_distributed_action, "GEMV"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::dot_diag_syrk, + GPRAT_NS::cpu::dot_diag_syrk_distributed_action, + "dot diag(SYRK)"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::dot_diag_gemm, + GPRAT_NS::cpu::dot_diag_gemm_distributed_action, + "dot diag(GEMM)"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::axpy, GPRAT_NS::cpu::axpy_distributed_action, "axpy"); + +#endif diff --git a/core/include/gprat/cpu/blas_enums.hpp b/core/include/gprat/cpu/blas_enums.hpp new file mode 100644 index 00000000..48c9ee0a --- /dev/null +++ b/core/include/gprat/cpu/blas_enums.hpp @@ -0,0 +1,19 @@ +#ifndef GPRAT_CPU_BLAS_ENUMS_HPP +#define GPRAT_CPU_BLAS_ENUMS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +GPRAT_NS_BEGIN + +// Constants that are compatible with CBLAS +typedef enum BLAS_TRANSPOSE { Blas_no_trans = 111, Blas_trans = 112 } BLAS_TRANSPOSE; + +typedef enum BLAS_SIDE { Blas_left = 141, Blas_right = 142 } BLAS_SIDE; + +typedef enum BLAS_ALPHA { Blas_add = 1, Blas_substract = -1 } BLAS_ALPHA; + +GPRAT_NS_END + +#endif diff --git a/core/include/cpu/gp_algorithms.hpp b/core/include/gprat/cpu/gp_algorithms.hpp similarity index 71% rename from core/include/cpu/gp_algorithms.hpp rename to core/include/gprat/cpu/gp_algorithms.hpp index b8a6f043..210810fd 100644 --- a/core/include/cpu/gp_algorithms.hpp +++ b/core/include/gprat/cpu/gp_algorithms.hpp @@ -1,30 +1,34 @@ -#ifndef CPU_GP_ALGORITHMS_H -#define CPU_GP_ALGORITHMS_H +#ifndef GPRAT_CPU_GP_ALGORITHMS_HPP +#define GPRAT_CPU_GP_ALGORITHMS_HPP -#include "gp_kernels.hpp" +#pragma once + +#include "gprat/detail/config.hpp" +#include "gprat/kernels.hpp" +#include "gprat/tile_data.hpp" + +#include #include +GPRAT_NS_BEGIN + namespace cpu { /** * @brief Compute the squared exponential kernel of two feature vectors * - * @param i_global The global index of the first feature vector - * @param j_global The global index of the second feature vector * @param n_regressors The number of regressors - * @param hyperparameters The kernel hyperparameters + * @param sek_params The kernel hyperparameters * @param i_input The first feature vector * @param j_input The second feature vector * - * @return The entry of a covariance function at position i_global,j_global + * @return The entry of a covariance function */ -double compute_covariance_function(std::size_t i_global, - std::size_t j_global, - std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &i_input, - const std::vector &j_input); +double compute_covariance_function(std::size_t n_regressors, + const SEKParams &sek_params, + std::span i_input, + std::span j_input); /** * @brief Generate a tile of the covariance matrix @@ -39,13 +43,13 @@ double compute_covariance_function(std::size_t i_global, * @return A quadratic tile of the covariance matrix of size N x N * @note Does apply noise variance on the diagonal */ -std::vector gen_tile_covariance( +mutable_tile_data gen_tile_covariance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &input); + const SEKParams &sek_params, + std::span input); /** * @brief Generate a tile of the prior covariance matrix @@ -61,13 +65,13 @@ std::vector gen_tile_covariance( * @note Does NOT apply noise variance on the diagonal */ // NAME: gen_tile_priot_covariance -std::vector gen_tile_full_prior_covariance( +mutable_tile_data gen_tile_full_prior_covariance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &input); + const SEKParams &sek_params, + std::span input); /** * @brief Generate the diagonal of a diagonal tile in the prior covariance matrix @@ -83,13 +87,13 @@ std::vector gen_tile_full_prior_covariance( * @note Does NOT apply noise variance */ // NAME: gen_tile_diag_prior_covariance -std::vector gen_tile_prior_covariance( +mutable_tile_data gen_tile_prior_covariance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &input); + const SEKParams &sek_params, + std::span input); /** * @brief Generate a tile of the cross-covariance matrix @@ -105,15 +109,15 @@ std::vector gen_tile_prior_covariance( * @return A tile of the cross covariance matrix of size N_row x N_col * @note Does NOT apply noise variance */ -std::vector gen_tile_cross_covariance( +mutable_tile_data gen_tile_cross_covariance( std::size_t row, std::size_t col, std::size_t N_row, std::size_t N_col, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &row_input, - const std::vector &col_input); + const SEKParams &sek_params, + std::span row_input, + std::span col_input); /** * @brief Transpose a tile of size N_row x N_col @@ -124,7 +128,7 @@ std::vector gen_tile_cross_covariance( * * @return The transposed tile of size N_col x N_row */ -std::vector gen_tile_transpose(std::size_t N_row, std::size_t N_col, const std::vector &tile); +mutable_tile_data gen_tile_transpose(std::size_t N_row, std::size_t N_col, std::span tile); /** * @brief Generate a tile of the output data @@ -135,7 +139,7 @@ std::vector gen_tile_transpose(std::size_t N_row, std::size_t N_col, con * * @return A tile of the output data of size N */ -std::vector gen_tile_output(std::size_t row, std::size_t N, const std::vector &output); +mutable_tile_data gen_tile_output(std::size_t row, std::size_t N, std::span output); /** * @brief Compute the L2-error norm over all tiles and elements @@ -158,7 +162,7 @@ double compute_error_norm(std::size_t n_tiles, * * @return A tile filled with zeros of size N */ -std::vector gen_tile_zeros(std::size_t N); +mutable_tile_data gen_tile_zeros(std::size_t N); /** * @brief Generate an identity tile (i==j?1:0) @@ -166,8 +170,10 @@ std::vector gen_tile_zeros(std::size_t N); * @param N The dimension of the quadratic tile * @return A NxN identity tile */ -std::vector gen_tile_identity(std::size_t N); +mutable_tile_data gen_tile_identity(std::size_t N); } // end of namespace cpu -#endif // end of CPU_GP_ALGORITHMS_H +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/cpu/gp_algorithms_actions.hpp b/core/include/gprat/cpu/gp_algorithms_actions.hpp new file mode 100644 index 00000000..2305bbae --- /dev/null +++ b/core/include/gprat/cpu/gp_algorithms_actions.hpp @@ -0,0 +1,104 @@ +#ifndef GPRAT_CPU_GP_ALGORITHMS_ACTIONS_HPP +#define GPRAT_CPU_GP_ALGORITHMS_ACTIONS_HPP + +#pragma once + +#include "gprat/cpu/gp_algorithms.hpp" +#include "gprat/detail/actions.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/tiled_dataset.hpp" + +GPRAT_NS_BEGIN + +namespace cpu +{ + +hpx::future> gen_tile_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &input); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_covariance_distributed); + +hpx::future> gen_tile_prior_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &input); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_prior_covariance_distributed); + +hpx::future> gen_tile_full_prior_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &input); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_full_prior_covariance_distributed); + +hpx::future> gen_tile_cross_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N_row, + std::size_t N_col, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &row_input, + const std::vector &col_input); + +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_cross_covariance_distributed); + +hpx::future> gen_tile_transpose_distributed( + const tile_handle &tile, std::size_t N_row, std::size_t N_col, const tile_handle &src); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_transpose_distributed); + +hpx::future> gen_tile_output_distributed( + const tile_handle &tile, std::size_t row, std::size_t N, const std::vector &output); + +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_output_distributed); + +hpx::future> gen_tile_zeros_distributed(const tile_handle &tile, std::size_t N); + +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_zeros_distributed); + +hpx::future> gen_tile_identity_distributed(const tile_handle &tile, std::size_t N); + +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_identity_distributed); +} // namespace cpu + +GPRAT_NS_END + +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_covariance, + GPRAT_NS::cpu::gen_tile_covariance_distributed_action, + "cpu::gen_tile_covariance"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_prior_covariance, + GPRAT_NS::cpu::gen_tile_prior_covariance_distributed_action, + "gen_tile_prior_covariance"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_full_prior_covariance, + GPRAT_NS::cpu::gen_tile_full_prior_covariance_distributed_action, + "gen_tile_full_prior_covariance"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_cross_covariance, + GPRAT_NS::cpu::gen_tile_cross_covariance_distributed_action, + "gen_tile_cross_covariance"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_transpose, + GPRAT_NS::cpu::gen_tile_transpose_distributed_action, + "gen_tile_transpose"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_output, + GPRAT_NS::cpu::gen_tile_output_distributed_action, + "gen_tile_output"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_zeros, + GPRAT_NS::cpu::gen_tile_zeros_distributed_action, + "gen_tile_zeros"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_identity, + GPRAT_NS::cpu::gen_tile_identity_distributed_action, + "gen_tile_identity"); + +#endif diff --git a/core/include/gprat/cpu/gp_functions.hpp b/core/include/gprat/cpu/gp_functions.hpp new file mode 100644 index 00000000..58a62619 --- /dev/null +++ b/core/include/gprat/cpu/gp_functions.hpp @@ -0,0 +1,1157 @@ +#ifndef GPRAT_CPU_GP_FUNCTIONS_HPP +#define GPRAT_CPU_GP_FUNCTIONS_HPP + +#pragma once + +#include "gprat/cpu/gp_algorithms.hpp" +#include "gprat/cpu/tiled_algorithms.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/scheduler.hpp" +#include "gprat/tile_data.hpp" + +#include + +GPRAT_NS_BEGIN + +namespace cpu +{ + +/** + * @brief Perform Cholesky decomposition (+Assembly) + * + * @param training_input The training input data + * @param sek_params The kernel hyperparameters + * + * @param n_tiles The number of training tiles + * @param n_tile_size The size of each training tile + * @param n_regressors The number of regressors + * + * @return The tiled Cholesky factor + */ +template +std::vector> +cholesky(Scheduler &sched, + const std::vector &training_input, + const SEKParams &sek_params, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors) +{ + // Tiled covariance matrix K_NxN + auto K_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + + for (std::size_t row = 0; row < n_tiles; row++) + { + for (std::size_t col = 0; col <= row; col++) + { + K_tiles[row * n_tiles + col] = detail::named_make_tile( + sched, + covariance_tile_on(sched, n_tiles, row, col), + "assemble_tiled_K", + K_tiles[row * n_tiles + col], + row, + col, + n_tile_size, + n_regressors, + sek_params, + training_input); + } + } + + // Launch asynchronous Cholesky decomposition: K = L * L^T + right_looking_cholesky_tiled(sched, K_tiles, n_tile_size, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Synchronize + std::vector> result(n_tiles * n_tiles); + for (std::size_t i = 0; i < n_tiles; i++) + { + for (std::size_t j = 0; j <= i; j++) + { + result[i * n_tiles + j] = K_tiles[i * n_tiles + j].get(); + } + } + return result; +} + +/** + * @brief Compute the predictions without uncertainties. + * + * @param training_input The training input data + * @param training_output The raining output data + * @param test_input The test input data + * @param hyperparameters The kernel hyperparameters + * @param n_tiles The number of training tiles + * @param n_tile_size The size of each training tile + * @param m_tiles The number of test tiles + * @param m_tile_size The size of each test tile + * @param n_regressors The number of regressors + * + * @return A vector containing the predictions + */ +template +std::vector +predict(Scheduler &sched, + const std::vector &training_input, + const std::vector &training_output, + const std::vector &test_input, + const SEKParams &sek_params, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t m_tiles, + std::size_t m_tile_size, + std::size_t n_regressors) +{ + /* + * Prediction: hat(y)_M = cross(K)_MxN * K^-1_NxN * y_N + * - Covariance matrix K_NxN + * - Cross-covariance cross(K)_MxN + * - Training output y_N + * - Prediction output hat(y)_M + * + * Algorithm: + * 1: Compute lower triangular part of covariance matrix K + * 2: Compute Cholesky factor L of K + * 3: Compute prediction hat(y): + * - triangular solve L * beta = y + * - triangular solve L^T * alpha = beta + * - compute hat(y) = cross(K) * alpha + */ + + /////////////////////////////////////////////////////////////////////////// + // Cholesky + + // Tiled covariance matrix K_NxN + auto K_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + + for (std::size_t row = 0; row < n_tiles; row++) + { + for (std::size_t col = 0; col <= row; col++) + { + K_tiles[row * n_tiles + col] = detail::named_make_tile( + sched, + covariance_tile_on(sched, n_tiles, row, col), + "assemble_tiled_K", + K_tiles[row * n_tiles + col], + row, + col, + n_tile_size, + n_regressors, + sek_params, + training_input); + } + } + + // Launch asynchronous Cholesky decomposition: K = L * L^T + right_looking_cholesky_tiled(sched, K_tiles, n_tile_size, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Prediction + + // Tiled cross_covariance matrix K_NxM + auto cross_covariance_tiles = make_tiled_dataset( + sched, + m_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + // Tiled solution + auto prediction_tiles = make_tiled_dataset( + sched, m_tiles, [&](std::size_t tile_index) { return prediction_tile_on(sched, m_tiles, tile_index); }); + // Tiled intermediate solution + auto alpha_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return alpha_tile_on(sched, n_tiles, tile_index); }); + + for (std::size_t i = 0; i < n_tiles; i++) + { + alpha_tiles[i] = detail::named_make_tile( + sched, + alpha_tile_on(sched, n_tiles, i), + "assemble_tiled_alpha", + alpha_tiles[i], + i, + n_tile_size, + training_output); + } + + for (std::size_t i = 0; i < m_tiles; i++) + { + for (std::size_t j = 0; j < n_tiles; j++) + { + cross_covariance_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + cross_covariance_tile_on(sched, n_tiles, i, j), + "assemble_pred", + cross_covariance_tiles[i * n_tiles + j], + i, + j, + m_tile_size, + n_tile_size, + n_regressors, + sek_params, + test_input, + training_input); + } + } + + for (std::size_t i = 0; i < m_tiles; i++) + { + prediction_tiles[i] = detail::named_make_tile( + sched, prediction_tile_on(sched, m_tiles, i), "assemble_tiled", prediction_tiles[i], m_tile_size); + } + + // Launch asynchronous triangular solve L * (L^T * alpha) = y + forward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + backward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + + // Launch asynchronous prediction computation solve: \hat{y} = K_cross_cov * alpha + matrix_vector_tiled( + sched, cross_covariance_tiles, alpha_tiles, prediction_tiles, m_tile_size, n_tile_size, n_tiles, m_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Synchronize prediction + // Preallocate memory + std::vector prediction_result; + prediction_result.reserve(test_input.size()); + for (std::size_t i = 0; i < m_tiles; i++) + { + mutable_tile_data tile = prediction_tiles[i].get(); + std::copy_n(tile.data(), tile.size(), std::back_inserter(prediction_result)); + } + return prediction_result; +} + +/** + * @brief Compute the predictions with uncertainties. + * + * @param training_input The training input data + * @param training_output The raining output data + * @param test_input The test input data + * @param hyperparameters The kernel hyperparameters + * @param n_tiles The number of training tiles + * @param n_tile_size The size of each training tile + * @param m_tiles The number of test tiles + * @param m_tile_size The size of each test tile + * @param n_regressors The number of regressors + * + * @return A vector containing the prediction vector and the uncertainty vector + */ +template +std::vector> predict_with_uncertainty( + Scheduler &sched, + const std::vector &training_input, + const std::vector &training_output, + const std::vector &test_input, + const SEKParams &sek_params, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t m_tiles, + std::size_t m_tile_size, + std::size_t n_regressors) +{ + /* + * Prediction: hat(y) = cross(K) * K^-1 * y + * Uncertainty: diag(Sigma) = diag(prior(K)) * diag(cross(K)^T * K^-1 * cross(K)) + * - Covariance matrix K_NxN + * - Cross-covariance cross(K)_MxN + * - Prior covariance prior(K)_MxM + * - Training output y_N + * - Prediction output hat(y)_M + * - Posterior covariance matrix Sigma_MxM + * + * Algorithm: + * 1: Compute lower triangular part of covariance matrix K + * 2: Compute Cholesky factor L of K + * 3: Compute prediction hat(y): + * - triangular solve L * beta = y + * - triangular solve L^T * alpha = beta + * - compute hat(y) = cross(K) * alpha + * 4: Compute uncertainty diag(Sigma): + * - triangular solve L * V = cross(K)^T + * - compute diag(W) = diag(V^T * V) + * - compute diag(Sigma) = diag(prior(K)) - diag(W) + */ + + /////////////////////////////////////////////////////////////////////////// + // Cholesky + + // Tiled covariance matrix K_NxN + auto K_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + + for (std::size_t row = 0; row < n_tiles; row++) + { + for (std::size_t col = 0; col <= row; col++) + { + K_tiles[row * n_tiles + col] = detail::named_make_tile( + sched, + covariance_tile_on(sched, n_tiles, row, col), + "assemble_tiled_K", + K_tiles[row * n_tiles + col], + row, + col, + n_tile_size, + n_regressors, + sek_params, + training_input); + } + } + + // Launch asynchronous Cholesky decomposition: K = L * L^T + right_looking_cholesky_tiled(sched, K_tiles, n_tile_size, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Prediction + + // Tiled intermediate solution + auto alpha_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return alpha_tile_on(sched, n_tiles, tile_index); }); + for (std::size_t i = 0; i < n_tiles; i++) + { + alpha_tiles[i] = detail::named_make_tile( + sched, + alpha_tile_on(sched, n_tiles, i), + "assemble_tiled_alpha", + alpha_tiles[i], + i, + n_tile_size, + training_output); + } + + // Tiled cross_covariance matrix K_NxM + auto cross_covariance_tiles = make_tiled_dataset( + sched, + m_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + for (std::size_t j = 0; j < n_tiles; j++) + { + cross_covariance_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + cross_covariance_tile_on(sched, n_tiles, i, j), + "assemble_pred", + cross_covariance_tiles[i * n_tiles + j], + i, + j, + m_tile_size, + n_tile_size, + n_regressors, + sek_params, + test_input, + training_input); + } + } + + // Tiled solution + auto prediction_tiles = make_tiled_dataset( + sched, m_tiles, [&](std::size_t tile_index) { return prediction_tile_on(sched, m_tiles, tile_index); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + prediction_tiles[i] = detail::named_make_tile( + sched, prediction_tile_on(sched, m_tiles, i), "assemble_tiled", prediction_tiles[i], m_tile_size); + } + + // Launch asynchronous triangular solve L * (L^T * alpha) = y + forward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + backward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + + // Launch asynchronous prediction computation solve: \hat{y} = K_cross_cov * alpha + matrix_vector_tiled( + sched, cross_covariance_tiles, alpha_tiles, prediction_tiles, m_tile_size, n_tile_size, n_tiles, m_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Uncertainty + + // Tiled transposed cross_covariance matrix K_MxN + auto t_cross_covariance_tiles = make_tiled_dataset( + sched, + n_tiles * m_tiles, + [&](std::size_t tile_index) + { return t_cross_covariance_tile_on(sched, m_tiles, tile_index / m_tiles, tile_index % m_tiles); }); + for (std::size_t j = 0; j < n_tiles; j++) + { + for (std::size_t i = 0; i < m_tiles; i++) + { + t_cross_covariance_tiles[j * m_tiles + i] = detail::named_make_tile( + sched, + t_cross_covariance_tile_on(sched, m_tiles, j, i), + "assemble_pred", + t_cross_covariance_tiles[j * m_tiles + i], + m_tile_size, + n_tile_size, + cross_covariance_tiles[i * n_tiles + j]); + } + } + + // Tiled prior covariance matrix diagonal diag(K_MxM) + auto prior_K_tiles = make_tiled_dataset( + sched, m_tiles, [&](std::size_t tile_index) { return prior_K_tile_on(sched, n_tiles, 0, tile_index); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + prior_K_tiles[i] = detail::named_make_tile( + sched, + prior_K_tile_on(sched, m_tiles, 0, i), + "assemble_tiled", + prior_K_tiles[i], + i, + i, + m_tile_size, + n_regressors, + sek_params, + test_input); + } + + // Tiled uncertainty solution + auto uncertainty_tiles = make_tiled_dataset( + sched, m_tiles, [&](std::size_t tile_index) { return uncertainty_tile_on(sched, m_tiles, tile_index); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + uncertainty_tiles[i] = detail::named_make_tile( + sched, uncertainty_tile_on(sched, m_tiles, i), "assemble_prior_inter", uncertainty_tiles[i], m_tile_size); + } + + // Launch asynchronous triangular solve L * V = cross(K)^T + forward_solve_tiled_matrix(sched, K_tiles, t_cross_covariance_tiles, n_tile_size, m_tile_size, n_tiles, m_tiles); + + // Launch asynchronous computation diag(W) = diag(V^T * V) + symmetric_matrix_matrix_diagonal_tiled( + sched, t_cross_covariance_tiles, uncertainty_tiles, n_tile_size, m_tile_size, n_tiles, m_tiles); + + // Launch asynchronous computation diag(Sigma) = diag(prior(K)) - diag(W) + vector_difference_tiled(sched, prior_K_tiles, uncertainty_tiles, m_tile_size, m_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Preallocate memory + std::vector prediction_result; + std::vector uncertainty_result; + prediction_result.reserve(test_input.size()); + uncertainty_result.reserve(test_input.size()); + + // Synchronize prediction + for (std::size_t i = 0; i < m_tiles; i++) + { + mutable_tile_data tile = prediction_tiles[i].get(); + std::copy_n(tile.begin(), tile.size(), std::back_inserter(prediction_result)); + } + + // Synchronize uncertainty + for (std::size_t i = 0; i < m_tiles; i++) + { + mutable_tile_data tile = uncertainty_tiles[i].get(); + std::copy_n(tile.begin(), tile.size(), std::back_inserter(uncertainty_result)); + } + + return std::vector>{ std::move(prediction_result), std::move(uncertainty_result) }; +} + +/** + * @brief Compute the predictions with full covariance matrix. + * + * @param training_input The training input data + * @param training_output The raining output data + * @param test_input The test input data + * @param sek_params The kernel hyperparameters + * @param n_tiles The number of training tiles + * @param n_tile_size The size of each training tile + * @param m_tiles The number of test tiles + * @param m_tile_size The size of each test tile + * @param n_regressors The number of regressors + * + * @return A vector containing the prediction vector and the full posterior covariance matrix + */ +template +std::vector> predict_with_full_cov( + Scheduler &sched, + const std::vector &training_input, + const std::vector &training_output, + const std::vector &test_input, + const SEKParams &sek_params, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t m_tiles, + std::size_t m_tile_size, + std::size_t n_regressors) +{ + /* + * Prediction: hat(y)_M = cross(K) * K^-1 * y + * Full covariance: Sigma = prior(K) - cross(K)^T * K^-1 * cross(K) + * - Covariance matrix K_NxN + * - Cross-covariance cross(K)_MxN + * - Prior covariance prior(K)_MxM + * - Training output y_N + * - Prediction output hat(y)_M + * - Posterior covariance matrix Sigma_MxM + * + * Algorithm: + * 1: Compute lower triangular part of covariance matrix K + * 2: Compute Cholesky factor L of K + * 3: Compute prediction hat(y): + * - triangular solve L * beta = y + * - triangular solve L^T * alpha = beta + * - compute hat(y) = cross(K) * alpha + * 4: Compute full covariance matrix Sigma: + * - triangular solve L * V = cross(K)^T + * - compute W = V^T * V + * - compute Sigma = prior(K) - W + * 5: Compute diag(Sigma) + */ + + /////////////////////////////////////////////////////////////////////////// + // Cholesky + + // Tiled covariance matrix K_NxN + auto K_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + for (std::size_t row = 0; row < n_tiles; row++) + { + for (std::size_t col = 0; col <= row; col++) + { + K_tiles[row * n_tiles + col] = detail::named_make_tile( + sched, + covariance_tile_on(sched, n_tiles, row, col), + "assemble_tiled_K", + K_tiles[row * n_tiles + col], + row, + col, + n_tile_size, + n_regressors, + sek_params, + training_input); + } + } + + // Launch asynchronous Cholesky decomposition: K = L * L^T + right_looking_cholesky_tiled(sched, K_tiles, n_tile_size, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Prediction + + // Tiled intermediate solution + auto alpha_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return alpha_tile_on(sched, n_tiles, tile_index); }); + for (std::size_t i = 0; i < n_tiles; i++) + { + alpha_tiles[i] = detail::named_make_tile( + sched, + alpha_tile_on(sched, n_tiles, i), + "assemble_tiled_alpha", + alpha_tiles[i], + i, + n_tile_size, + training_output); + } + + // Tiled cross_covariance matrix K_NxM + auto cross_covariance_tiles = make_tiled_dataset( + sched, + m_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + for (std::size_t j = 0; j < n_tiles; j++) + { + cross_covariance_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + cross_covariance_tile_on(sched, n_tiles, i, j), + "assemble_pred", + cross_covariance_tiles[i * n_tiles + j], + i, + j, + m_tile_size, + n_tile_size, + n_regressors, + sek_params, + test_input, + training_input); + } + } + + // Tiled solution + auto prediction_tiles = make_tiled_dataset( + sched, m_tiles, [&](std::size_t tile_index) { return prediction_tile_on(sched, n_tiles, tile_index); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + prediction_tiles[i] = detail::named_make_tile( + sched, prediction_tile_on(sched, m_tiles, i), "assemble_tiled", prediction_tiles[i], m_tile_size); + } + + // Launch asynchronous triangular solve L * (L^T * alpha) = y + forward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + backward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + + // Launch asynchronous prediction computation solve: \hat{y} = K_cross_cov * alpha + matrix_vector_tiled( + sched, cross_covariance_tiles, alpha_tiles, prediction_tiles, m_tile_size, n_tile_size, n_tiles, m_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Uncertainty + + // Tiled transposed cross_covariance matrix K_MxN + auto t_cross_covariance_tiles = make_tiled_dataset( + sched, + n_tiles * m_tiles, + [&](std::size_t tile_index) + { return t_cross_covariance_tile_on(sched, m_tiles, tile_index / m_tiles, tile_index % m_tiles); }); + for (std::size_t j = 0; j < n_tiles; j++) + { + for (std::size_t i = 0; i < m_tiles; i++) + { + t_cross_covariance_tiles[j * m_tiles + i] = detail::named_make_tile( + sched, + t_cross_covariance_tile_on(sched, m_tiles, j, i), + "assemble_pred", + t_cross_covariance_tiles[j * m_tiles + i], + m_tile_size, + n_tile_size, + cross_covariance_tiles[i * n_tiles + j]); + } + } + + // Tiled prior covariance matrix K_MxM + auto prior_K_tiles = make_tiled_dataset( + sched, + m_tiles * m_tiles, + [&](std::size_t tile_index) + { return prior_K_tile_on(sched, n_tiles, tile_index / m_tiles, tile_index % m_tiles); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + for (std::size_t j = 0; j <= i; j++) + { + prior_K_tiles[i * m_tiles + j] = detail::named_make_tile( + sched, + prior_K_tile_on(sched, m_tiles, i, j), + "assemble_prior_tiled", + prior_K_tiles[i * m_tiles + j], + i, + j, + m_tile_size, + n_regressors, + sek_params, + test_input); + + if (i != j) + { + prior_K_tiles[j * m_tiles + i] = detail::named_make_tile( + sched, + prior_K_tile_on(sched, m_tiles, j, i), + "assemble_prior_tiled", + prior_K_tiles[j * m_tiles + i], + m_tile_size, + m_tile_size, + prior_K_tiles[i * m_tiles + j]); + } + } + } + + // Tiled uncertainty solution + auto uncertainty_tiles = make_tiled_dataset( + sched, m_tiles, [&](std::size_t tile_index) { return uncertainty_tile_on(sched, m_tiles, tile_index); }); + for (std::size_t i = 0; i < m_tiles; i++) + { + uncertainty_tiles[i] = detail::named_make_tile( + sched, uncertainty_tile_on(sched, m_tiles, i), "assemble_prior_inter", uncertainty_tiles[i], m_tile_size); + } + + // Launch asynchronous triangular solve L * V = cross(K)^T + forward_solve_tiled_matrix(sched, K_tiles, t_cross_covariance_tiles, n_tile_size, m_tile_size, n_tiles, m_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous computation of full covariance Sigma = prior(K) - V^T * V + symmetric_matrix_matrix_tiled( + sched, t_cross_covariance_tiles, prior_K_tiles, n_tile_size, m_tile_size, n_tiles, m_tiles); + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous computation of uncertainty diag(Sigma) + matrix_diagonal_tiled(sched, prior_K_tiles, uncertainty_tiles, m_tile_size, m_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Preallocate memory + std::vector prediction_result; + std::vector uncertainty_result; + prediction_result.reserve(test_input.size()); + uncertainty_result.reserve(test_input.size()); + + // Synchronize prediction + for (std::size_t i = 0; i < m_tiles; i++) + { + mutable_tile_data tile = prediction_tiles[i].get(); + std::copy_n(tile.begin(), tile.size(), std::back_inserter(prediction_result)); + } + + // Synchronize uncertainty + for (std::size_t i = 0; i < m_tiles; i++) + { + mutable_tile_data tile = uncertainty_tiles[i].get(); + std::copy_n(tile.begin(), tile.size(), std::back_inserter(uncertainty_result)); + } + + return std::vector>{ std::move(prediction_result), std::move(uncertainty_result) }; +} + +/////////////////////////////////////////////////////////////////////////// +// OPTIMIZATION + +/** + * @brief Compute loss for given data and Gaussian process model + * + * @param training_input The training input data + * @param training_output The raining output data + * @param sek_params The kernel hyperparameters + * @param n_tiles The number of training tiles + * @param n_tile_size The size of each training tile + * @param n_regressors The number of regressors + * + * @return The loss + */ +template +double calculate_loss(Scheduler &sched, + const std::vector &training_input, + const std::vector &training_output, + const SEKParams &sek_params, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors) +{ + /* + * Negative log likelihood loss: + * loss(theta) = 0.5 * ( log(det(K)) - y^T * K^-1 * y - N * log(2 * pi) ) + * - Covariance matrix K(theta)_NxN + * - Training output y_N + * - Hyperparameters theta ={ v, l, v_n } + * + * Algorithm: + * 1: Compute lower triangular part of covariance matrix K + * 2: Compute Cholesky factor L of K + * 3: Compute prediction alpha = K^-1 * y: + * - triangular solve L * beta = y + * - triangular solve L^T * alpha = beta + * 5: Compute beta = K^-1 * y + * 6: Compute negative log likelihood loss + * - Calculate sum_i^N log(L_ii^2) + * - Calculate y^T * beta + * - Add constant N * log (2 * pi) + */ + + // Tiled covariance matrix K_NxN + auto K_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + for (std::size_t row = 0; row < n_tiles; row++) + { + for (std::size_t col = 0; col <= row; col++) + { + K_tiles[row * n_tiles + col] = detail::named_make_tile( + sched, + covariance_tile_on(sched, n_tiles, row, col), + "assemble_tiled_K", + K_tiles[row * n_tiles + col], + row, + col, + n_tile_size, + n_regressors, + sek_params, + training_input); + } + } + + // Tiled intermediate solution + auto alpha_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return alpha_tile_on(sched, n_tiles, tile_index); }); + for (std::size_t i = 0; i < n_tiles; i++) + { + alpha_tiles[i] = detail::named_make_tile( + sched, + alpha_tile_on(sched, n_tiles, i), + "assemble_tiled_alpha", + alpha_tiles[i], + i, + n_tile_size, + training_output); + } + + // Tiled output + auto y_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return prediction_tile_on(sched, n_tiles, tile_index); }); + for (std::size_t i = 0; i < n_tiles; i++) + { + y_tiles[i] = detail::named_make_tile( + sched, + prediction_tile_on(sched, n_tiles, i), + "assemble_tiled_alpha", + y_tiles[i], + i, + n_tile_size, + training_output); + } + + // Launch asynchronous Cholesky decomposition: K = L * L^T + right_looking_cholesky_tiled(sched, K_tiles, n_tile_size, n_tiles); + + // Launch asynchronous triangular solve L * (L^T * alpha) = y + forward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + backward_solve_tiled(sched, K_tiles, alpha_tiles, n_tile_size, n_tiles); + + // Launch asynchronous loss computation + return compute_loss_tiled(sched, K_tiles, alpha_tiles, y_tiles, n_tile_size, n_tiles).get(); +} + +/** + * @brief Perform optimization for a given number of iterations + * + * @param training_input The training input data + * @param training_output The raining output data + * + * @param n_tiles The number of training tiles + * @param n_tile_size The size of each training tile + * @param n_regressors The number of regressors + * + * @param adam_params The Adam optimizer hyperparameters + * @param sek_params The kernel hyperparameters + * @param trainable_params The vector containing a bool whether to train a hyperparameter + * + * @return A vector containing the loss values of each iteration + */ +template +std::vector +optimize(Scheduler &sched, + const std::vector &training_input, + const std::vector &training_output, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + const AdamParams &adam_params, + SEKParams &sek_params, + std::vector trainable_params, + std::size_t start_iter = 0) +{ + /* + * - Hyperparameters theta={v, l, v_n} + * - Covariance matrix K(theta) + * - Training ouput y + * + * Algorithm: + * for opt_iter: + * 1: Compute distance for entries of covariance matrix K + * 2: Compute lower triangular part of K with distance + * 3: Compute lower triangular gradients for delta(K)/delta(v), and delta(K)/delta(l) with distance + * + * 4: Compute Cholesky factor L of K + * 5: Compute K^-1: + * - triangular solve L * {} = I + * - triangular solve L^T * K^-1 = {} + * 6: Compute beta = K^-1 * y + * + * 7: Compute negative log likelihood loss + * - Calculate 0.5 sum_i^N log(L_ii^2) + * - Calculate 0.5 y^T * beta + * - Add constant N / 2 * log (2 * pi) + * + * 8: Compute delta(loss)/delta(param_i) + * - Compute trace(K^-1 * delta(K)/delta(theta_i)) + * - Compute beta^T * delta(K)/delta(theta_i) * beta + * 9: Update hyperparameters theta with Adam optimizer + * - m_T = beta1 * m_T-1 + (1 - beta1) * g_T + * - w_T = beta2 + w_T-1 + (1 - beta2) * g_T^2 + * - nu_T = nu * sqrt(1 - beta2_T) / (1 - beta1_T) + * - theta_T = theta_T-1 - nu_T * m_T / (sqrt(w_T) + epsilon) + * endfor + */ + + // data holder for computed loss values + std::vector losses; + losses.reserve(static_cast(adam_params.opt_iter)); + + // Tiled output + auto y_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return prediction_tile_on(sched, n_tiles, tile_index); }); + // Launch asynchronous assembly of output y + for (std::size_t i = 0; i < n_tiles; i++) + { + y_tiles[i] = detail::named_make_tile( + sched, prediction_tile_on(sched, n_tiles, i), "assemble_y", y_tiles[i], i, n_tile_size, training_output); + } + + ////////////////////////////////////////////////////////////////////////////// + // per-loop tiles + + // Tiled covariance matrix K_NxN + auto K_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return covariance_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + + // Tiled inverse covariance matrix K^-1_NxN + auto K_inv_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return K_inv_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + + // Tiled intermediate solution + auto alpha_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return alpha_tile_on(sched, n_tiles, tile_index); }); + + // Tiled future data structures for gradients + + // Tiled covariance with gradient v + auto grad_v_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return K_grad_v_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + + // Tiled covariance with gradient l + auto grad_l_tiles = make_tiled_dataset( + sched, + n_tiles * n_tiles, + [&](std::size_t tile_index) + { return K_grad_l_tile_on(sched, n_tiles, tile_index / n_tiles, tile_index % n_tiles); }); + + auto inter_alpha = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return inter_alpha_tile_on(sched, n_tiles, tile_index); }); + + auto diag_tiles = make_tiled_dataset( + sched, n_tiles, [&](std::size_t tile_index) { return diag_tile_on(sched, n_tiles, tile_index); }); + + ////////////////////////////////////////////////////////////////////////////// + // Perform optimization + for (std::size_t iter = start_iter; iter < static_cast(adam_params.opt_iter); iter++) + { + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous assembly of tiled covariance matrix, derivative of covariance matrix + // vector w.r.t. to vertical lengthscale and derivative of covariance + // matrix vector w.r.t. to lengthscale + for (std::size_t i = 0; i < n_tiles; i++) + { + for (std::size_t j = 0; j <= i; j++) + { + // Compute the distance (z_i - z_j) of K entries to reuse + hpx::shared_future> cov_dists = detail::named_async( + "assemble_cov_dist", i, j, n_tile_size, n_regressors, sek_params, training_input); + + K_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + covariance_tile_on(sched, n_tiles, i, j), + "assemble_K", + K_tiles[i * n_tiles + j], + i, + j, + n_tile_size, + sek_params, + cov_dists); + if (trainable_params[0]) + { + grad_l_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + K_grad_l_tile_on(sched, n_tiles, i, j), + "assemble_gradl", + grad_l_tiles[i * n_tiles + j], + n_tile_size, + sek_params, + cov_dists); + if (i != j) + { + grad_l_tiles[j * n_tiles + i] = detail::named_make_tile( + sched, + K_grad_l_tile_on(sched, n_tiles, j, i), + "assemble_gradl_t", + grad_l_tiles[j * n_tiles + i], + n_tile_size, + n_tile_size, + grad_l_tiles[i * n_tiles + j]); + } + } + + if (trainable_params[1]) + { + grad_v_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + K_grad_v_tile_on(sched, n_tiles, i, j), + "assemble_gradv", + grad_v_tiles[i * n_tiles + j], + n_tile_size, + sek_params, + cov_dists); + if (i != j) + { + grad_v_tiles[j * n_tiles + i] = detail::named_make_tile( + sched, + K_grad_v_tile_on(sched, n_tiles, j, i), + "assemble_gradv_t", + grad_v_tiles[j * n_tiles + i], + n_tile_size, + n_tile_size, + grad_v_tiles[i * n_tiles + j]); + } + } + } + } + + // Assembly with reallocation -> optimize to only set existing values + for (std::size_t i = 0; i < n_tiles; i++) + { + alpha_tiles[i] = detail::named_make_tile( + sched, alpha_tile_on(sched, n_tiles, i), "assemble_tiled_alpha", alpha_tiles[i], n_tile_size); + } + + for (std::size_t i = 0; i < n_tiles; i++) + { + for (std::size_t j = 0; j < n_tiles; j++) + { + if (i == j) + { + K_inv_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + K_inv_tile_on(sched, n_tiles, i, j), + "assemble_identity_matrix", + K_inv_tiles[i * n_tiles + j], + n_tile_size); + } + else + { + K_inv_tiles[i * n_tiles + j] = detail::named_make_tile( + sched, + K_inv_tile_on(sched, n_tiles, i, j), + "assemble_identity_matrix", + K_inv_tiles[i * n_tiles + j], + n_tile_size * n_tile_size); + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous Cholesky decomposition: K = L * L^T + right_looking_cholesky_tiled(sched, K_tiles, n_tile_size, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous compute K^-1 through L* (L^T * X) = I + forward_solve_tiled_matrix(sched, K_tiles, K_inv_tiles, n_tile_size, n_tile_size, n_tiles, n_tiles); + backward_solve_tiled_matrix(sched, K_tiles, K_inv_tiles, n_tile_size, n_tile_size, n_tiles, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous compute beta = inv(K) * y + matrix_vector_tiled(sched, K_inv_tiles, y_tiles, alpha_tiles, n_tile_size, n_tile_size, n_tiles, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous loss computation where + // loss(theta) = 0.5 * ( log(det(K)) - y^T * K^-1 * y - N * log(2 * pi) ) + auto loss_value = compute_loss_tiled(sched, K_tiles, alpha_tiles, y_tiles, n_tile_size, n_tiles); + + /////////////////////////////////////////////////////////////////////////// + // Launch asynchronous update of the hyperparameters + if (trainable_params[0]) + { // lengthscale + update_hyperparameter_tiled_lengthscale( + sched, + K_inv_tiles, + grad_l_tiles, + alpha_tiles, + adam_params, + diag_tiles, + inter_alpha, + sek_params, + n_tile_size, + n_tiles, + iter, + 0); + } + if (trainable_params[1]) + { // vertical_lengthscale + update_hyperparameter_tiled_lengthscale( + sched, + K_inv_tiles, + grad_v_tiles, + alpha_tiles, + adam_params, + diag_tiles, + inter_alpha, + sek_params, + n_tile_size, + n_tiles, + iter, + 1); + } + if (trainable_params[2]) + { // noise_variance + update_hyperparameter_tiled_noise_variance( + sched, K_inv_tiles, alpha_tiles, adam_params, sek_params, n_tile_size, n_tiles, iter, 2); + } + // Synchronize after iteration + losses.push_back(loss_value.get()); + } + return losses; +} + +/** + * @brief Perform a single optimization step + * + * @param training_input The training input data + * @param training_output The raining output data + * + * @param n_tiles The number of training tiles + * @param n_tile_size The size of each training tile + * @param n_regressors The number of regressors + * + * @param adam_params The Adam optimizer hyperparameters + * @param sek_params The kernel hyperparameters + * @param trainable_params The vector containing a bool whether to train a hyperparameter + * + * @param iter The current optimization iteration + * + * @return The loss value + */ +template +double optimize_step(Scheduler &sched, + const std::vector &training_input, + const std::vector &training_output, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + AdamParams &adam_params, + SEKParams &sek_params, + std::vector trainable_params, + std::size_t iter) +{ + // No point in copy&pasting everything for this function + const auto old_opt_iter = adam_params.opt_iter; + adam_params.opt_iter = iter + 1; + const auto r = optimize( + sched, + training_input, + training_output, + n_tiles, + n_tile_size, + n_regressors, + adam_params, + sek_params, + trainable_params, + iter); + adam_params.opt_iter = old_opt_iter; + return r[0]; +} + +} // end of namespace cpu + +GPRAT_NS_END + +#endif diff --git a/core/include/cpu/gp_optimizer.hpp b/core/include/gprat/cpu/gp_optimizer.hpp similarity index 80% rename from core/include/cpu/gp_optimizer.hpp rename to core/include/gprat/cpu/gp_optimizer.hpp index c632e87b..1712597d 100644 --- a/core/include/cpu/gp_optimizer.hpp +++ b/core/include/gprat/cpu/gp_optimizer.hpp @@ -1,10 +1,17 @@ -#ifndef CPU_GP_OPTIMIZER_H -#define CPU_GP_OPTIMIZER_H +#ifndef GPRAT_CPU_GP_OPTIMIZER_H +#define GPRAT_CPU_GP_OPTIMIZER_H + +#pragma once + +#include "gprat/detail/config.hpp" +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/tile_data.hpp" -#include "gp_hyperparameters.hpp" -#include "gp_kernels.hpp" #include +GPRAT_NS_BEGIN + namespace cpu { @@ -54,7 +61,7 @@ double compute_sigmoid(double parameter); double compute_covariance_distance(std::size_t i_global, std::size_t j_global, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, const std::vector &i_input, const std::vector &j_input); @@ -70,12 +77,12 @@ double compute_covariance_distance(std::size_t i_global, * * @return A quadratic tile containing the distance between the features of size N x N */ -std::vector gen_tile_distance( +mutable_tile_data gen_tile_distance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, const std::vector &input); /** @@ -89,12 +96,12 @@ std::vector gen_tile_distance( * * @return A quadratic tile of the covariance matrix of size N x N */ -std::vector gen_tile_covariance_with_distance( +mutable_tile_data gen_tile_covariance_with_distance( std::size_t row, std::size_t col, std::size_t N, - const gprat_hyper::SEKParams &sek_params, - const std::vector &distance); + const SEKParams &sek_params, + const const_tile_data &distance); /** * @brief Generate a derivative tile w.r.t. vertical_lengthscale v @@ -105,8 +112,8 @@ std::vector gen_tile_covariance_with_distance( * * @return A quadratic tile of the derivative of v of size N x N */ -std::vector -gen_tile_grad_v(std::size_t N, const gprat_hyper::SEKParams &sek_params, const std::vector &distance); +mutable_tile_data +gen_tile_grad_v(std::size_t N, const SEKParams &sek_params, const const_tile_data &distance); /** * @brief Generate a derivative tile w.r.t. lengthscale l @@ -117,8 +124,8 @@ gen_tile_grad_v(std::size_t N, const gprat_hyper::SEKParams &sek_params, const s * * @return A quadratic tile of the derivative of l of size N x N */ -std::vector -gen_tile_grad_l(std::size_t N, const gprat_hyper::SEKParams &sek_params, const std::vector &distance); +mutable_tile_data +gen_tile_grad_l(std::size_t N, const SEKParams &sek_params, const const_tile_data &distance); /** * @brief Update biased first raw moment estimate: m_T+1 = beta_1 * m_T + (1 - beta_1) * g_T. @@ -153,11 +160,8 @@ double update_second_moment(double gradient, double v_T, double beta_2); * * @return The updated hyperparameter */ -double adam_step(const double unconstrained_hyperparam, - const gprat_hyper::AdamParams &adam_params, - double m_T, - double v_T, - std::size_t iter); +double +adam_step(double unconstrained_hyperparam, const AdamParams &adam_params, double m_T, double v_T, std::size_t iter); /** * @brief Compute negative-log likelihood on one tile. @@ -168,9 +172,9 @@ double adam_step(const double unconstrained_hyperparam, * * @return Return l = y^T * alpha + \sum_i^N log(L_ii^2) */ -double compute_loss(const std::vector &K_diag_tile, - const std::vector &alpha_tile, - const std::vector &y_tile, +double compute_loss(std::span K_diag_tile, + std::span alpha_tile, + std::span y_tile, std::size_t N); /** @@ -182,7 +186,7 @@ double compute_loss(const std::vector &K_diag_tile, * * @return The added up loss plus the constant factor */ -double add_losses(const std::vector &losses, std::size_t N, std::size_t n); +double add_losses(std::span losses, std::size_t N, std::size_t n); /** * @brief Compute the loss gradient. @@ -204,7 +208,7 @@ double compute_gradient(double trace, double dot, std::size_t N, std::size_t n_t * * @return The updated global trace */ -double compute_trace(const std::vector &diagonal, double trace); +double compute_trace(std::span diagonal, double trace); /** * @brief Add the dot product of a vector to a global result. @@ -215,7 +219,7 @@ double compute_trace(const std::vector &diagonal, double trace); * * @return The updated global result */ -double compute_dot(const std::vector &vector_T, const std::vector &vector, double result); +double compute_dot(std::span vector_T, std::span vector, double result); /** * @brief Add the local trace of a matrix tile to the global trace @@ -226,8 +230,10 @@ double compute_dot(const std::vector &vector_T, const std::vector &tile, double trace, std::size_t N); +double compute_trace_diag(std::span tile, double trace, std::size_t N); } // end of namespace cpu -#endif // end of CPU_GP_OPTIMIZER_H +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/cpu/gp_optimizer_actions.hpp b/core/include/gprat/cpu/gp_optimizer_actions.hpp new file mode 100644 index 00000000..ade9de4e --- /dev/null +++ b/core/include/gprat/cpu/gp_optimizer_actions.hpp @@ -0,0 +1,80 @@ +#ifndef GPRAT_CPU_GP_OPTIMIZER_ACTIONS_HPP +#define GPRAT_CPU_GP_OPTIMIZER_ACTIONS_HPP + +#pragma once + +#include "gprat/cpu/gp_optimizer.hpp" +#include "gprat/detail/actions.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/tiled_dataset.hpp" + +GPRAT_NS_BEGIN + +namespace cpu +{ +hpx::future> gen_tile_covariance_with_distance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + const SEKParams &sek_params, + const const_tile_data &distance); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_covariance_with_distance_distributed); + +hpx::future> gen_tile_grad_l_distributed( + const tile_handle &tile, + std::size_t N, + const SEKParams &sek_params, + const const_tile_data &distance); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_grad_l_distributed); + +hpx::future> gen_tile_grad_v_distributed( + const tile_handle &tile, + std::size_t N, + const SEKParams &sek_params, + const const_tile_data &distance); +HPX_DEFINE_PLAIN_DIRECT_ACTION(gen_tile_grad_v_distributed); + +hpx::future compute_loss_distributed(const tile_handle &K_diag_tile, + const tile_handle &alpha_tile, + const tile_handle &y_tile, + std::size_t N); +HPX_DEFINE_PLAIN_DIRECT_ACTION(compute_loss_distributed); + +hpx::future compute_trace_distributed(const tile_handle &diagonal, double trace); +HPX_DEFINE_PLAIN_DIRECT_ACTION(compute_trace_distributed); + +hpx::future +compute_dot_distributed(const tile_handle &vector_T, const tile_handle &vector, double result); +HPX_DEFINE_PLAIN_DIRECT_ACTION(compute_dot_distributed); + +hpx::future compute_trace_diag_distributed(const tile_handle &tile, double trace, std::size_t N); +HPX_DEFINE_PLAIN_DIRECT_ACTION(compute_trace_diag_distributed); + +} // namespace cpu + +GPRAT_NS_END + +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_covariance_with_distance, + GPRAT_NS::cpu::gen_tile_covariance_with_distance_distributed_action, + "gen_tile_covariance_with_distance"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_grad_l, + GPRAT_NS::cpu::gen_tile_grad_l_distributed_action, + "gen_tile_grad_l"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_grad_v, + GPRAT_NS::cpu::gen_tile_grad_v_distributed_action, + "gen_tile_grad_v"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_loss, + GPRAT_NS::cpu::compute_loss_distributed_action, + "compute_loss"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_trace, + GPRAT_NS::cpu::compute_trace_distributed_action, + "compute_trace"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_dot, + GPRAT_NS::cpu::compute_dot_distributed_action, + "compute_dot"); +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_trace_diag, + GPRAT_NS::cpu::compute_trace_diag_distributed_action, + "compute_trace_diag"); + +#endif diff --git a/core/include/gprat/cpu/gp_uncertainty.hpp b/core/include/gprat/cpu/gp_uncertainty.hpp new file mode 100644 index 00000000..cb402119 --- /dev/null +++ b/core/include/gprat/cpu/gp_uncertainty.hpp @@ -0,0 +1,28 @@ +#ifndef GPRAT_CPU_GP_UNCERTAINTY_HPP +#define GPRAT_CPU_GP_UNCERTAINTY_HPP + +#pragma once + +#include "gprat/detail/config.hpp" +#include "gprat/tile_data.hpp" + +GPRAT_NS_BEGIN + +namespace cpu +{ + +/** + * @brief Extract diagonal elements of the matrix A. + * + * @param A The matrix + * @param M The rumber of rows in the matrix + * + * @return Diagonal element vector of the matrix A of size M + */ +mutable_tile_data get_matrix_diagonal(const const_tile_data &A, std::size_t M); + +} // end of namespace cpu + +GPRAT_NS_END + +#endif // end of CPU_GP_UNCERTAINTY_H diff --git a/core/include/gprat/cpu/gp_uncertainty_actions.hpp b/core/include/gprat/cpu/gp_uncertainty_actions.hpp new file mode 100644 index 00000000..31e47d88 --- /dev/null +++ b/core/include/gprat/cpu/gp_uncertainty_actions.hpp @@ -0,0 +1,25 @@ +#ifndef GPRAT_CPU_GP_UNCERTAINTY_ACTIONS_HPP +#define GPRAT_CPU_GP_UNCERTAINTY_ACTIONS_HPP + +#pragma once + +#include "gprat/cpu/gp_uncertainty.hpp" +#include "gprat/detail/actions.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/tiled_dataset.hpp" + +GPRAT_NS_BEGIN + +namespace cpu +{ +hpx::future> get_matrix_diagonal_distributed(const tile_handle &A, std::size_t M); +HPX_DEFINE_PLAIN_DIRECT_ACTION(get_matrix_diagonal_distributed); +} // namespace cpu + +GPRAT_NS_END + +GPRAT_DECLARE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::get_matrix_diagonal, + GPRAT_NS::cpu::get_matrix_diagonal_distributed_action, + "get_matrix_diagonal"); + +#endif diff --git a/core/include/gprat/cpu/tiled_algorithms.hpp b/core/include/gprat/cpu/tiled_algorithms.hpp new file mode 100644 index 00000000..2438fab6 --- /dev/null +++ b/core/include/gprat/cpu/tiled_algorithms.hpp @@ -0,0 +1,657 @@ +#ifndef GPRAT_CPU_TILED_ALGORITHMS_H +#define GPRAT_CPU_TILED_ALGORITHMS_H + +#pragma once + +#include "gprat/cpu/adapter_cblas_fp64.hpp" +#include "gprat/cpu/gp_algorithms.hpp" +#include "gprat/cpu/gp_optimizer.hpp" +#include "gprat/cpu/gp_uncertainty.hpp" +#include "gprat/detail/async_helpers.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/scheduler.hpp" + +#include + +GPRAT_NS_BEGIN + +namespace cpu +{ + +namespace impl +{ +void update_parameters( + const AdamParams &adam_params, + SEKParams &sek_params, + std::size_t N, + std::size_t n_tiles, + std::size_t iter, + std::size_t param_idx, + double trace, + double dot, + bool jitter, + double factor); +} + +// Tiled Cholesky Algorithm + +/** + * @brief Perform right-looking tiled Cholesky decomposition. + * + * @param tiles Tiled matrix represented as a vector of futurized tiles, containing the + * covariance matrix, afterwards the Cholesky decomposition. + * @param N Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + */ +template +void right_looking_cholesky_tiled(Scheduler &sched, Tiles &tiles, std::size_t N, std::size_t n_tiles) +{ + for (std::size_t k = 0; k < n_tiles; k++) + { + // POTRF: Compute Cholesky factor L + tiles[k * n_tiles + k] = detail::named_dataflow( + sched, cholesky_potrf_on(sched, n_tiles, k), "cholesky_tiled", tiles[k * n_tiles + k], N); + for (std::size_t m = k + 1; m < n_tiles; m++) + { + // TRSM: Solve X * L^T = A + tiles[m * n_tiles + k] = detail::named_dataflow( + sched, + cholesky_trsm_on(sched, n_tiles, k, m), + "cholesky_tiled", + tiles[k * n_tiles + k], + tiles[m * n_tiles + k], + N, + N, + Blas_trans, + Blas_right); + } + for (std::size_t m = k + 1; m < n_tiles; m++) + { + // SYRK: A = A - B * B^T + tiles[m * n_tiles + m] = detail::named_dataflow( + sched, + cholesky_syrk_on(sched, n_tiles, m), + "cholesky_tiled", + tiles[m * n_tiles + m], + tiles[m * n_tiles + k], + N); + for (std::size_t n = k + 1; n < m; n++) + { + // GEMM: C = C - A * B^T + tiles[m * n_tiles + n] = detail::named_dataflow( + sched, + cholesky_gemm_on(sched, n_tiles, k, m, n), + "cholesky_tiled", + tiles[m * n_tiles + k], + tiles[n * n_tiles + k], + tiles[m * n_tiles + n], + N, + N, + N, + Blas_no_trans, + Blas_trans); + } + } + } +} + +// Tiled Triangular Solve Algorithms + +/** + * @brief Perform tiled forward triangular matrix-vector solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side vector, afterwards containing the tiled solution vector + * @param N Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + */ +template +void forward_solve_tiled(Scheduler &sched, Tiles &ft_tiles, Tiles &ft_rhs, std::size_t N, std::size_t n_tiles) +{ + for (std::size_t k = 0; k < n_tiles; k++) + { + // TRSM: Solve L * x = a + ft_rhs[k] = detail::named_dataflow( + sched, + solve_trsv_on(sched, n_tiles, k), + "triangular_solve_tiled", + ft_tiles[k * n_tiles + k], + ft_rhs[k], + N, + Blas_no_trans); + for (std::size_t m = k + 1; m < n_tiles; m++) + { + // GEMV: b = b - A * a + ft_rhs[m] = detail::named_dataflow( + sched, + solve_gemv_on(sched, n_tiles, k, m), + "triangular_solve_tiled", + ft_tiles[m * n_tiles + k], + ft_rhs[k], + ft_rhs[m], + N, + N, + Blas_substract, + Blas_no_trans); + } + } +} + +/** + * @brief Perform tiled backward triangular matrix-vector solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side vector, afterwards containing the tiled solution vector + * @param N Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + */ +template +void backward_solve_tiled(Scheduler &sched, Tiles &ft_tiles, Tiles &ft_rhs, std::size_t N, std::size_t n_tiles) +{ + for (int k_ = static_cast(n_tiles) - 1; k_ >= 0; k_--) // int instead of std::size_t for last comparison + { + std::size_t k = static_cast(k_); + // TRSM: Solve L^T * x = a + ft_rhs[k] = detail::named_dataflow( + sched, + solve_trsm_on(sched, n_tiles, k), + "triangular_solve_tiled", + ft_tiles[k * n_tiles + k], + ft_rhs[k], + N, + Blas_trans); + for (int m_ = k_ - 1; m_ >= 0; m_--) // int instead of std::size_t for last comparison + { + std::size_t m = static_cast(m_); + // GEMV:b = b - A^T * a + ft_rhs[m] = detail::named_dataflow( + sched, + solve_gemv_on(sched, n_tiles, k, m), + "triangular_solve_tiled", + ft_tiles[k * n_tiles + m], + ft_rhs[k], + ft_rhs[m], + N, + N, + Blas_substract, + Blas_trans); + } + } +} + +/** + * @brief Perform tiled forward triangular matrix-matrix solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side matrix, afterwards containing the tiled solution matrix. + * @param N Tile size of first dimension. + * @param M Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + */ +template +void forward_solve_tiled_matrix( + Scheduler &sched, + Tiles &ft_tiles, + Tiles &ft_rhs, + std::size_t N, + std::size_t M, + std::size_t n_tiles, + std::size_t m_tiles) +{ + for (std::size_t c = 0; c < m_tiles; c++) + { + for (std::size_t k = 0; k < n_tiles; k++) + { + // TRSM: solve L * X = A + ft_rhs[k * m_tiles + c] = detail::named_dataflow( + sched, + solve_matrix_trsm_on(sched, m_tiles, c, k), + "triangular_solve_tiled_matrix", + ft_tiles[k * n_tiles + k], + ft_rhs[k * m_tiles + c], + N, + M, + Blas_no_trans, + Blas_left); + for (std::size_t m = k + 1; m < n_tiles; m++) + { + // GEMM: C = C - A * B + ft_rhs[m * m_tiles + c] = detail::named_dataflow( + sched, + solve_matrix_gemm_on(sched, m_tiles, c, k, m), + "triangular_solve_tiled_matrix", + ft_tiles[m * n_tiles + k], + ft_rhs[k * m_tiles + c], + ft_rhs[m * m_tiles + c], + N, + M, + N, + Blas_no_trans, + Blas_no_trans); + } + } + } +} + +/** + * @brief Perform tiled backward triangular matrix-matrix solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side matrix, afterwards containing the tiled solution matrix. + * @param N Tile size of first dimension. + * @param M Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + */ +template +void backward_solve_tiled_matrix( + Scheduler &sched, + Tiles &ft_tiles, + Tiles &ft_rhs, + std::size_t N, + std::size_t M, + std::size_t n_tiles, + std::size_t m_tiles) +{ + for (std::size_t c = 0; c < m_tiles; c++) + { + for (int k_ = static_cast(n_tiles) - 1; k_ >= 0; k_--) // int instead of std::size_t for last comparison + { + std::size_t k = static_cast(k_); + // TRSM: solve L^T * X = A + ft_rhs[k * m_tiles + c] = detail::named_dataflow( + sched, + solve_matrix_trsm_on(sched, m_tiles, c, k), + "triangular_solve_tiled_matrix", + ft_tiles[k * n_tiles + k], + ft_rhs[k * m_tiles + c], + N, + M, + Blas_trans, + Blas_left); + for (int m_ = k_ - 1; m_ >= 0; m_--) // int instead of std::size_t for last comparison + { + std::size_t m = static_cast(m_); + // GEMM: C = C - A^T * B + ft_rhs[m * m_tiles + c] = detail::named_dataflow( + sched, + solve_matrix_gemm_on(sched, m_tiles, c, k, m), + "triangular_solve_tiled_matrix", + ft_tiles[k * n_tiles + m], + ft_rhs[k * m_tiles + c], + ft_rhs[m * m_tiles + c], + N, + M, + N, + Blas_trans, + Blas_no_trans); + } + } + } +} + +/** + * @brief Perform tiled matrix-vector multiplication + * + * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. + * @param ft_vector Tiled vector represented as a vector of futurized tiles. + * @param ft_rhs Tiled solution represented as a vector of futurized tiles. + * @param N_row Tile size of first dimension. + * @param N_col Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + */ +template +void matrix_vector_tiled(Scheduler &sched, + Tiles &ft_tiles, + Tiles &ft_vector, + Tiles &ft_rhs, + std::size_t N_row, + std::size_t N_col, + std::size_t n_tiles, + std::size_t m_tiles) +{ + for (std::size_t k = 0; k < m_tiles; k++) + { + for (std::size_t m = 0; m < n_tiles; m++) + { + ft_rhs[k] = detail::named_dataflow( + sched, + multiply_gemv_on(sched, n_tiles, k, m), + "prediction_tiled", + ft_tiles[k * n_tiles + m], + ft_vector[m], + ft_rhs[k], + N_row, + N_col, + Blas_add, + Blas_no_trans); + } + } +} + +/** + * @brief Perform tiled symmetric k-rank update on diagonal tiles + * + * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. + * @param ft_vector Tiled vector holding the diagonal tile results + * @param N Tile size of first dimension. + * @param M Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + */ +template +void symmetric_matrix_matrix_diagonal_tiled( + Scheduler &sched, + Tiles &ft_tiles, + Tiles &ft_vector, + std::size_t N, + std::size_t M, + std::size_t n_tiles, + std::size_t m_tiles) +{ + for (std::size_t i = 0; i < m_tiles; ++i) + { + for (std::size_t n = 0; n < n_tiles; ++n) + { + // Compute inner product to obtain diagonal elements of + // V^T * V <=> cross(K) * K^-1 * cross(K)^T + ft_vector[i] = detail::named_dataflow( + sched, + k_rank_dot_diag_syrk_on(sched, m_tiles, i), + "posterior_tiled", + ft_tiles[n * m_tiles + i], + ft_vector[i], + N, + M); + } + } +} + +/** + * @brief Perform tiled symmetric k-rank update (ft_tiles^T * ft_tiles) + * + * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. + * @param ft_result Tiled matrix holding the result of the computationi. + * @param N Tile size of first dimension. + * @param M Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + */ +template +void symmetric_matrix_matrix_tiled( + Scheduler &sched, + Tiles &ft_tiles, + Tiles &ft_result, + std::size_t N, + std::size_t M, + std::size_t n_tiles, + std::size_t m_tiles) +{ + for (std::size_t c = 0; c < m_tiles; c++) + { + for (std::size_t k = 0; k < m_tiles; k++) + { + for (std::size_t m = 0; m < n_tiles; m++) + { + // (SYRK for (c == k) possible) + // GEMM: C = C - A^T * B + ft_result[c * m_tiles + k] = detail::named_dataflow( + sched, + k_rank_gemm_on(sched, m_tiles, c, k, m), + "triangular_solve_tiled_matrix", + ft_tiles[m * m_tiles + c], + ft_tiles[m * m_tiles + k], + ft_result[c * m_tiles + k], + N, + M, + M, + Blas_trans, + Blas_no_trans); + } + } + } +} + +/** + * @brief Compute the difference between two tiled vectors + * @param ft_minuend Tiled vector that is being subtracted from. + * @param ft_subtrahend Tiled vector that is being subtracted. + * @param M Tile size dimension. + * @param m_tiles Number of tiles. + */ +template +void vector_difference_tiled( + Scheduler &sched, Tiles &ft_minuend, Tiles &ft_subtrahend, std::size_t M, std::size_t m_tiles) +{ + for (std::size_t i = 0; i < m_tiles; i++) + { + ft_subtrahend[i] = detail::named_dataflow( + sched, vector_axpy_on(sched, m_tiles, i), "uncertainty_tiled", ft_minuend[i], ft_subtrahend[i], M); + } +} + +/** + * @brief Extract the tiled diagonals of a tiled matrix + * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. + * @param ft_vector Tiled vector containing the diagonals of the matrix tiles + * @param M Tile size per dimension. + * @param m_tiles Number of tiles per dimension. + */ +template +void matrix_diagonal_tiled(Scheduler &sched, Tiles &ft_tiles, Tiles &ft_vector, std::size_t M, std::size_t m_tiles) +{ + for (std::size_t i = 0; i < m_tiles; i++) + { + ft_vector[i] = detail::named_dataflow( + sched, get_diagonal_on(sched, m_tiles, i), "uncertainty_tiled", ft_tiles[i * m_tiles + i], M); + } +} + +/** + * @brief Compute the negative log likelihood loss with a tiled covariance matrix K. + * + * Computes l = 0.5 * ( log(det(K)) + y^T * K^-1 * y) + const.) + * + * @param ft_tiles Tiled Cholesky factor matrix represented as a vector of futurized tiles. + * @param ft_alpha Tiled vector containing the solution of K^-1 * y + * @param ft_y Tiled vector containing the training output y + * @param N Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @return The loss value to be computed + */ +template +hpx::future +compute_loss_tiled(Scheduler &sched, Tiles &ft_tiles, Tiles &ft_alpha, Tiles &ft_y, std::size_t N, std::size_t n_tiles) +{ + std::vector> loss_tiled; + loss_tiled.reserve(n_tiles); + for (std::size_t k = 0; k < n_tiles; k++) + { + loss_tiled.push_back(detail::named_dataflow( + sched, + compute_loss_on(sched, n_tiles, k), + "loss_tiled", + ft_tiles[k * n_tiles + k], + ft_alpha[k], + ft_y[k], + N)); + } + return detail::named_dataflow("loss_tiled", loss_tiled, N, n_tiles); +} + +/** + * @brief Updates a hyperparameter of the SEK kernel using Adam + * + * @param ft_invK Tiled inverse of the covariance matrix K represented as a vector of futurized tiles. + * @param ft_gradK_param Tiled covariance matrix gradient w.r.t. a hyperparameter. + * @param ft_alpha Tiled vector containing the precomputed inv(K) * y where y is the training output. + * @param adam_params Hyperparameter of the Adam optimizer + * @param sek_params Hyperparameters of the SEK kernel + * @param N Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @param iter Current iteration. + * @param param_idx Index of the hyperparameter to optimize. + */ +template +void update_hyperparameter_tiled_lengthscale( + Scheduler &sched, + const Tiles &ft_invK, + const Tiles &ft_gradK_param, + const Tiles &ft_alpha, + const AdamParams &adam_params, + Tiles &diag_tiles, // Diagonal tiles + Tiles &inter_alpha, // Intermediate result + SEKParams &sek_params, + std::size_t N, + std::size_t n_tiles, + std::size_t iter, + std::size_t param_idx) +{ + /* + * PART 1: + * Compute gradient = 0.5 * ( trace(inv(K) * grad(K)_param) + y^T * inv(K) * grad(K)_param * inv(K) * y ) + * + * 1: Compute trace(inv(K) * grad(K)_param) + * 2: Compute y^T * inv(K) * grad(K)_param * inv(K) * y + * + * Update parameter: + * 3: Update moments + * - m_T = beta1 * m_T-1 + (1 - beta1) * g_T + * - w_T = beta2 + w_T-1 + (1 - beta2) * g_T^2 + * 4: Adam step: + * - nu_T = nu * sqrt(1 - beta2_T) / (1 - beta1_T) + * - theta_T = theta_T-1 - nu_T * m_T / (sqrt(w_T) + epsilon) + */ + hpx::shared_future trace = hpx::make_ready_future(0.0); + hpx::shared_future dot = hpx::make_ready_future(0.0); + bool jitter = false; + double factor = 1.0; + + // Reset our helper tiles + for (std::size_t d = 0; d < n_tiles; d++) + { + diag_tiles[d] = detail::named_make_tile( + sched, diag_tile_on(sched, n_tiles, d), "assemble", diag_tiles[d], N); + inter_alpha[d] = detail::named_make_tile( + sched, inter_alpha_tile_on(sched, n_tiles, d), "assemble", inter_alpha[d], N); + } + + //////////////////////////////////// + // PART 1: Compute gradient + // Step 1: Compute trace(inv(K)*grad_K_param) + // Compute diagonal tiles of inv(K) * grad(K)_param + for (std::size_t i = 0; i < n_tiles; ++i) + { + for (std::size_t j = 0; j < n_tiles; ++j) + { + diag_tiles[i] = detail::named_dataflow( + sched, + diag_tile_on(sched, n_tiles, i), + "trace", + ft_invK[i * n_tiles + j], + ft_gradK_param[j * n_tiles + i], + diag_tiles[i], + N, + N); + } + } + // Compute the trace of the diagonal tiles + for (std::size_t j = 0; j < n_tiles; ++j) + { + trace = detail::named_dataflow( + sched, diag_tile_on(sched, n_tiles, j), "trace", diag_tiles[j], trace); + } + // Not sure if can be done this way + // Step 2: Compute alpha^T * grad(K)_param * alpha (with alpha = inv(K) * y) + // Compute inter_alpha = grad(K)_param * alpha + for (std::size_t k = 0; k < n_tiles; k++) + { + for (std::size_t m = 0; m < n_tiles; m++) + { + inter_alpha[k] = detail::named_dataflow( + sched, + inter_alpha_tile_on(sched, n_tiles, k), + "gemv", + ft_gradK_param[k * n_tiles + m], + ft_alpha[m], + inter_alpha[k], + N, + N, + Blas_add, + Blas_no_trans); + } + } + // Compute alpha^T * inter_alpha + for (std::size_t j = 0; j < n_tiles; ++j) + { + dot = detail::named_dataflow( + sched, inter_alpha_tile_on(sched, n_tiles, j), "grad_right_tiled", inter_alpha[j], ft_alpha[j], dot); + } + + impl::update_parameters( + adam_params, sek_params, N, n_tiles, iter, param_idx, trace.get(), dot.get(), jitter, factor); +} + +template +void update_hyperparameter_tiled_noise_variance( + Scheduler &sched, + const Tiles &ft_invK, + const Tiles &ft_alpha, + const AdamParams &adam_params, + SEKParams &sek_params, + std::size_t N, + std::size_t n_tiles, + std::size_t iter, + std::size_t param_idx) +{ + /* + * PART 1: + * Compute gradient = 0.5 * ( trace(inv(K) * grad(K)_param) + y^T * inv(K) * grad(K)_param * inv(K) * y ) + * + * 1: Compute trace(inv(K) * grad(K)_param) + * 2: Compute y^T * inv(K) * grad(K)_param * inv(K) * y + * + * Update parameter: + * 3: Update moments + * - m_T = beta1 * m_T-1 + (1 - beta1) * g_T + * - w_T = beta2 + w_T-1 + (1 - beta2) * g_T^2 + * 4: Adam step: + * - nu_T = nu * sqrt(1 - beta2_T) / (1 - beta1_T) + * - theta_T = theta_T-1 - nu_T * m_T / (sqrt(w_T) + epsilon) + */ + hpx::shared_future trace = hpx::make_ready_future(0.0); + hpx::shared_future dot = hpx::make_ready_future(0.0); + bool jitter = true; + double factor = 1.0; + + //////////////////////////////////// + // PART 1: Compute gradient + // Step 1: Compute the trace of inv(K) * noise_variance + for (std::size_t j = 0; j < n_tiles; ++j) + { + trace = detail::named_dataflow( + sched, K_inv_tile_on(sched, n_tiles, j, j), "grad_left_tiled", ft_invK[j * n_tiles + j], trace, N); + } + //////////////////////////////////// + // Step 2: Compute the alpha^T * alpha * noise_variance + for (std::size_t j = 0; j < n_tiles; ++j) + { + dot = detail::named_dataflow( + sched, alpha_tile_on(sched, n_tiles, j), "grad_right_tiled", ft_alpha[j], ft_alpha[j], dot); + } + + factor = compute_sigmoid(to_unconstrained(sek_params.noise_variance, true)); + + impl::update_parameters( + adam_params, sek_params, N, n_tiles, iter, param_idx, trace.get(), dot.get(), jitter, factor); +} + +} // end of namespace cpu + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/detail/actions.hpp b/core/include/gprat/detail/actions.hpp new file mode 100644 index 00000000..4a78e0b6 --- /dev/null +++ b/core/include/gprat/detail/actions.hpp @@ -0,0 +1,120 @@ +#ifndef GPRAT_DETAIL_ACTIONS_HPP +#define GPRAT_DETAIL_ACTIONS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +#include +#include +#include + +GPRAT_NS_BEGIN + +/// @brief This template provides access to a function F's associated HPX action and related metadata. +/// +/// Users can use this template to access the previously declared HPX plain (and optionally direct) action. +/// This way we get singleton-like semantics for free, there is always only one plain action associated with +/// a Callable value F. +template +struct plain_action_for; + +#define GPRAT_DECLARE_PLAIN_ACTION_FOR(local_function, action, friendly_name) \ + HPX_REGISTER_ACTION_DECLARATION(action) \ + template <> \ + struct GPRAT_NS::plain_action_for \ + { \ + using action_type = action; \ + constexpr static std::string_view name = friendly_name; \ + } + +#define GPRAT_DEFINE_PLAIN_ACTION_FOR(local_function, action) HPX_REGISTER_ACTION(action) + +// ============================================================= +// distributed action-based scheduling + +struct tiled_scheduler_distributed +{ + /// @brief Create a new scheduler that targets all localities. + tiled_scheduler_distributed() : + localities_(hpx::find_all_localities()) + { + // ctor + } + + /// @brief Create a new scheduler that targets the given localities. + explicit tiled_scheduler_distributed(std::vector in_localities) : + localities_(std::move(in_localities)) + { + // ctor + } + + std::vector localities_; +}; + +namespace detail +{ +// HPX does not auto-collapse future chains in their async(), dataflow(), ... functions. +// This usually works fine, but we require shared_futures most of the time. +// Unfortunately, C++ will not do two-step conversions for us (future> -> future -> shared_future). +// see: https://github.com/STEllAR-GROUP/hpx/issues/3758 +template +hpx::future collapse(hpx::future> &&fut) +{ + return { std::move(fut) }; +} + +template +hpx::future collapse(hpx::future &&fut) +{ + return std::move(fut); +} + +template +decltype(auto) +named_make_tile(const tiled_scheduler_distributed &sched, std::size_t on, const char *name, Args &&...args) +{ + hpx::threads::thread_schedule_hint hint; + hint.sharing_mode(hpx::threads::thread_sharing_hint::do_not_combine_tasks + | hpx::threads::thread_sharing_hint::do_not_share_function); + decltype(auto) policy = hpx::execution::experimental::with_hint(hpx::launch::async, hint) | hpx::launch::deferred; + return collapse(hpx::dataflow( + policy, + hpx::annotated_function(hpx::unwrapping(typename plain_action_for::action_type{}), name), + sched.localities_[on], + std::forward(args)...)); +} + +template +decltype(auto) +named_dataflow(const tiled_scheduler_distributed &sched, std::size_t on, const char *name, Args &&...args) +{ + hpx::threads::thread_schedule_hint hint; + hint.sharing_mode(hpx::threads::thread_sharing_hint::do_not_combine_tasks + | hpx::threads::thread_sharing_hint::do_not_share_function); + decltype(auto) policy = hpx::execution::experimental::with_hint(hpx::launch::async, hint) | hpx::launch::deferred; + return collapse(hpx::dataflow( + policy, + hpx::annotated_function(hpx::unwrapping(typename plain_action_for::action_type{}), name), + sched.localities_[on], + std::forward(args)...)); +} + +template +decltype(auto) named_async(const tiled_scheduler_distributed &sched, std::size_t on, const char *name, Args &&...args) +{ + hpx::threads::thread_schedule_hint hint; + hint.sharing_mode(hpx::threads::thread_sharing_hint::do_not_combine_tasks + | hpx::threads::thread_sharing_hint::do_not_share_function); + decltype(auto) policy = hpx::execution::experimental::with_hint(hpx::launch::async, hint) | hpx::launch::deferred; + return hpx::async(policy, + hpx::annotated_function(typename plain_action_for::action_type{}, name), + sched.localities_[on], + std::forward(args)...); +} + +} // namespace detail + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/detail/async_helpers.hpp b/core/include/gprat/detail/async_helpers.hpp new file mode 100644 index 00000000..05a24a91 --- /dev/null +++ b/core/include/gprat/detail/async_helpers.hpp @@ -0,0 +1,74 @@ +#ifndef GPRAT_DETAIL_DATAFLOW_HELPERS_HPP +#define GPRAT_DETAIL_DATAFLOW_HELPERS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +#include +#include +#include +#include + +GPRAT_NS_BEGIN + +/// @brief Empty type representing local scheduling (always on this locality) +struct basic_local_scheduler +{ }; + +namespace detail +{ + +// Functions prefixed with named_* allow the user to specify a custom name for this entry in the +// execution graph. Much like wrapping your function with hpx::annotated_function would. + +// ============================================================= +// non-scheduler aware + +template +decltype(auto) named_dataflow(const char *name, Args &&...args) +{ + return hpx::dataflow(hpx::annotated_function(hpx::unwrapping(F), name), std::forward(args)...); +} + +template +decltype(auto) named_async(const char *name, Args &&...args) +{ + return hpx::async(hpx::annotated_function(F, name), std::forward(args)...); +} + +// ============================================================= +// local shared-memory scheduling +// (no-op, same as above) + +template +decltype(auto) named_make_tile(const basic_local_scheduler & /*sched*/, + std::size_t /*on*/, + const char *name, + TileReference & /*target*/, + Args &&...args) +{ + // This method basically ignores the reference to the target tile as the non-action factories don't need it. + // (They always create the tile_data locally and return that - only the HPX action wrappers need a reference) + return hpx::dataflow(hpx::annotated_function(hpx::unwrapping(F), name), std::forward(args)...); +} + +template +decltype(auto) +named_dataflow(const basic_local_scheduler & /*sched*/, std::size_t /*on*/, const char *name, Args &&...args) +{ + return hpx::dataflow(hpx::annotated_function(hpx::unwrapping(F), name), std::forward(args)...); +} + +template +decltype(auto) +named_async(const basic_local_scheduler & /*sched*/, std::size_t /*on*/, const char *name, Args &&...args) +{ + return hpx::async(hpx::annotated_function(F, name), std::forward(args)...); +} + +} // namespace detail + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/detail/config.hpp b/core/include/gprat/detail/config.hpp new file mode 100644 index 00000000..427d998d --- /dev/null +++ b/core/include/gprat/detail/config.hpp @@ -0,0 +1,36 @@ +#ifndef GPRAT_DETAIL_CONFIG_HPP +#define GPRAT_DETAIL_CONFIG_HPP + +#pragma once + +#ifndef GPRAT_WITH_CUDA +#define GPRAT_WITH_CUDA 0 +#endif +#ifndef GPRAT_WITH_SYCL +#define GPRAT_WITH_SYCL 0 +#endif +#ifndef GPRAT_WITH_DISTRIBUTED +#define GPRAT_WITH_DISTRIBUTED 0 +#endif + +// clang-format off +#define GPRAT_NS gprat::v1 +#define GPRAT_NS_BEGIN namespace gprat { inline namespace v1 { +#define GPRAT_NS_END } } +// clang-format on + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#if defined(GPRAT_DYN_LINK) +#if defined(GPRAT_SOURCE) +#define GPRAT_DECL __declspec(dllexport) +#else +#define GPRAT_DECL __declspec(dllimport) +#endif +#endif +#endif + +#if !defined(GPRAT_DECL) +#define GPRAT_DECL +#endif + +#endif diff --git a/core/include/gprat_c.hpp b/core/include/gprat/gprat.hpp similarity index 69% rename from core/include/gprat_c.hpp rename to core/include/gprat/gprat.hpp index 6781d286..4316cafc 100644 --- a/core/include/gprat_c.hpp +++ b/core/include/gprat/gprat.hpp @@ -1,16 +1,21 @@ -#ifndef GPRAT_C_H -#define GPRAT_C_H +#ifndef GPRAT_C_HPP +#define GPRAT_C_HPP -#include "gp_hyperparameters.hpp" -#include "gp_kernels.hpp" -#include "target.hpp" +#pragma once + +#include "gprat/detail/config.hpp" +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" + +#include "tile_data.hpp" #include #include #include -// namespace for GPRat library entities -namespace gprat -{ +GPRAT_NS_BEGIN + +// GP_data //////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * @brief Data structure for Gaussian Process data @@ -24,10 +29,10 @@ struct GP_data std::string file_path; /** @brief Number of samples in the data */ - int n_samples; + std::size_t n_samples; /** @brief Number of GP regressors */ - int n_regressors; + std::size_t n_regressors; /** @brief Vector containing the data */ std::vector data; @@ -38,12 +43,15 @@ struct GP_data * * The file specified by `f_path` must contain `n` samples. * - * @param f_path Path to the file + * @param file_path Path to the file * @param n Number of samples + * @param n_reg Number of regressors */ - GP_data(const std::string &file_path, int n, int n_reg); + GP_data(const std::string &file_path, std::size_t n, std::size_t n_reg); }; +// GP ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** * @brief Gaussian Process class for regression tasks * @@ -61,10 +69,10 @@ class GP std::vector training_output_; /** @brief Number of tiles */ - int n_tiles_; + std::size_t n_tiles_; /** @brief Size of each tile in each dimension */ - int n_tile_size_; + std::size_t n_tile_size_; /** * @brief List of bools indicating trainable parameters: lengthscale, @@ -78,13 +86,19 @@ class GP std::shared_ptr target_; public: + /// Variables + /// ///////////////////////////////////////////////////////////////////////////////////////////////////////// + /** @brief Number of regressors */ - int n_reg; + std::size_t n_reg; /** * @brief Hyperarameters of the squared exponential kernel */ - gprat_hyper::SEKParams kernel_params; + SEKParams kernel_params; + + /// Generic constructor + /// /////////////////////////////////////////////////////////////////////////////////////////////// /** * @brief Constructs a Gaussian Process (GP) @@ -102,13 +116,16 @@ class GP */ GP(std::vector input, std::vector output, - int n_tiles, - int n_tile_size, - int n_regressors, - std::vector kernel_hyperparams, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + const std::vector &kernel_hyperparams, std::vector trainable_bool, std::shared_ptr target); + /// CPU constructor + /// /////////////////////////////////////////////////////////////////////////////////////////////////// + /** * @brief Constructs a Gaussian Process (GP) for CPU computations * @@ -124,14 +141,17 @@ class GP */ GP(std::vector input, std::vector output, - int n_tiles, - int n_tile_size, - int n_regressors, - std::vector kernel_hyperparams, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + const std::vector &kernel_hyperparams, std::vector trainable_bool); + /// GPU constructor + /// /////////////////////////////////////////////////////////////////////////////////////////////////// + /** - * @brief Constructs a Gaussian Process (GP) for GPU computations + * @brief Constructs a Gaussian Process (GP) for GPU computations using CUDA or SYCL * * @param input Input data for training of the GP * @param output Expected output data for training of the GP @@ -143,17 +163,20 @@ class GP * parameter of squared exponential kernel * @param trainable_bool Vector indicating which parameters are trainable * @param gpu_id GPU identifier - * @param n_streams Number of CUDA streams for GPU computations + * @param n_units Number of CUDA streams / SYCL queues for GPU computations */ GP(std::vector input, std::vector output, - int n_tiles, - int n_tile_size, - int n_regressors, - std::vector kernel_hyperparams, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + const std::vector &kernel_hyperparams, std::vector trainable_bool, int gpu_id, - int n_streams); + int n_units); + + /// Class methods + /// ///////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns Gaussian Process attributes as string. @@ -173,27 +196,27 @@ class GP /** * @brief Predict output for test input */ - std::vector predict(const std::vector &test_data, int m_tiles, int m_tile_size); + std::vector predict(const std::vector &test_data, std::size_t m_tiles, std::size_t m_tile_size); /** * @brief Predict output for test input and additionally provide * uncertainty for the predictions. */ std::vector> - predict_with_uncertainty(const std::vector &test_data, int m_tiles, int m_tile_size); + predict_with_uncertainty(const std::vector &test_data, std::size_t m_tiles, std::size_t m_tile_size); /** * @brief Predict output for test input and additionally compute full * posterior covariance matrix. * - * @param test_input Test input data + * @param test_data Test input data * @param m_tiles Number of tiles * @param m_tile_size Size of each tile * * @return Full covariance matrix */ std::vector> - predict_with_full_cov(const std::vector &test_data, int m_tiles, int m_tile_size); + predict_with_full_cov(const std::vector &test_data, std::size_t m_tiles, std::size_t m_tile_size); /** * @brief Optimize hyperparameters @@ -203,18 +226,18 @@ class GP * * @return losses */ - std::vector optimize(const gprat_hyper::AdamParams &adam_params); + std::vector optimize(const AdamParams &adam_params); /** * @brief Perform a single optimization step * - * @param hyperparams Hyperparameters of squared exponential kernel: + * @param adam_params Hyperparameters of squared exponential kernel: * lengthscale, vertical_lengthscale, noise_variance * @param iter number of iterations * * @return loss */ - double optimize_step(gprat_hyper::AdamParams &adam_params, int iter); + double optimize_step(AdamParams &adam_params, std::size_t iter); /** * @brief Calculate loss for given data and Gaussian process model @@ -224,8 +247,9 @@ class GP /** * @brief Computes & returns cholesky decomposition */ - std::vector> cholesky(); + std::vector> cholesky(); }; -} // namespace gprat -#endif // end of GPRAT_C_H +GPRAT_NS_END + +#endif diff --git a/core/include/gpu/adapter_cublas.cuh b/core/include/gprat/gpu/adapter_cublas.cuh similarity index 97% rename from core/include/gpu/adapter_cublas.cuh rename to core/include/gprat/gpu/adapter_cublas.cuh index 1a69cb58..738cf35e 100644 --- a/core/include/gpu/adapter_cublas.cuh +++ b/core/include/gprat/gpu/adapter_cublas.cuh @@ -1,10 +1,18 @@ -#ifndef ADAPTER_CUBLAS_H -#define ADAPTER_CUBLAS_H +#ifndef GPRAT_GPU_ADAPTER_CUBLAS_HPP +#define GPRAT_GPU_ADAPTER_CUBLAS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +#include "gprat/target.hpp" -#include #include #include -#include + +#include + +GPRAT_NS_BEGIN // Constants, compatible with cuBLAS @@ -262,4 +270,6 @@ inline cublasSideMode_t opposite(cublasSideMode_t side) return (side == CUBLAS_SIDE_LEFT) ? CUBLAS_SIDE_RIGHT : CUBLAS_SIDE_LEFT; } -#endif // end of ADAPTER_CUBLAS_H +GPRAT_NS_END + +#endif diff --git a/core/include/gpu/cuda_kernels.cuh b/core/include/gprat/gpu/cuda_kernels.cuh similarity index 71% rename from core/include/gpu/cuda_kernels.cuh rename to core/include/gprat/gpu/cuda_kernels.cuh index 4daef473..69a48d8f 100644 --- a/core/include/gpu/cuda_kernels.cuh +++ b/core/include/gprat/gpu/cuda_kernels.cuh @@ -1,5 +1,11 @@ -#ifndef CUDA_KERNELS_H -#define CUDA_KERNELS_H +#ifndef GPRAT_CUDA_KERNELS_HPP +#define GPRAT_CUDA_KERNELS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +GPRAT_NS_BEGIN /** * @brief Kernel to transpose a matrix. @@ -11,4 +17,6 @@ */ __global__ void transpose(double *transposed, double *original, std::size_t width, std::size_t height); -#endif // CUDA_KERNELS_H +GPRAT_NS_END + +#endif diff --git a/core/include/gpu/cuda_utils.cuh b/core/include/gprat/gpu/cuda_utils.cuh similarity index 90% rename from core/include/gpu/cuda_utils.cuh rename to core/include/gprat/gpu/cuda_utils.cuh index 0c51ea76..52b5fc16 100644 --- a/core/include/gpu/cuda_utils.cuh +++ b/core/include/gprat/gpu/cuda_utils.cuh @@ -1,14 +1,19 @@ -#ifndef CUDA_UTILS_H -#define CUDA_UTILS_H +#ifndef GPRAT_CUDA_UTILS_HPP +#define GPRAT_CUDA_UTILS_HPP +#pragma once + +#include "gprat/detail/config.hpp" +#include "gprat/target.hpp" #include #include #include #include #include -#include #include +GPRAT_NS_BEGIN + #define BLOCK_SIZE 16 using hpx::cuda::experimental::check_cuda_error; @@ -25,7 +30,7 @@ using hpx::cuda::experimental::check_cuda_error; * * @return A pointer to the copied vector on the device */ -inline double *copy_to_device(const std::vector &h_vector, gprat::CUDA_GPU &gpu) +inline double *copy_to_device(const std::vector &h_vector, CUDA_GPU &gpu) { double *d_vector; check_cuda_error(cudaMalloc(&d_vector, h_vector.size() * sizeof(double))); @@ -66,4 +71,6 @@ inline void free(std::vector> &vector) } } -#endif // end of CUDA_UTILS_H +GPRAT_NS_END + +#endif diff --git a/core/include/gpu/gp_algorithms.cuh b/core/include/gprat/gpu/gp_algorithms.cuh similarity index 89% rename from core/include/gpu/gp_algorithms.cuh rename to core/include/gprat/gpu/gp_algorithms.cuh index 51cbc355..8da8a956 100644 --- a/core/include/gpu/gp_algorithms.cuh +++ b/core/include/gprat/gpu/gp_algorithms.cuh @@ -1,11 +1,18 @@ -#ifndef GPU_GP_ALGORITHMS_H -#define GPU_GP_ALGORITHMS_H +#ifndef GPRAT_GPU_GP_ALGORITHMS_HPP +#define GPRAT_GPU_GP_ALGORITHMS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" +#include "gprat/tile_data.hpp" -#include "gp_kernels.hpp" -#include "target.hpp" #include #include +GPRAT_NS_BEGIN + namespace gpu { @@ -28,8 +35,8 @@ double *gen_tile_covariance(const double *d_input, const std::size_t tile_column, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu); + const SEKParams sek_params, + CUDA_GPU &gpu); /** * @brief Generate the diagonal of a diagonal tile in the prior covariance matrix @@ -51,8 +58,8 @@ double *gen_tile_prior_covariance( const std::size_t tile_column, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu); + const SEKParams sek_params, + CUDA_GPU &gpu); /** * @brief Generate a tile of the cross-covariance matrix @@ -77,8 +84,8 @@ double *gen_tile_cross_covariance( const std::size_t n_row_tile_size, const std::size_t n_column_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu); + const SEKParams sek_params, + CUDA_GPU &gpu); /** * @brief Transpose a tile of size n_row_tile_size x n_column_tile_size @@ -92,7 +99,7 @@ double *gen_tile_cross_covariance( hpx::shared_future gen_tile_transpose(std::size_t n_row_tile_size, std::size_t n_column_tile_size, const hpx::shared_future f_tile, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Generate a tile of the output data @@ -104,7 +111,7 @@ hpx::shared_future gen_tile_transpose(std::size_t n_row_tile_size, * @return A tile of the output data of size n_tile_size */ double * -gen_tile_output(const std::size_t row, const std::size_t n_tile_size, const double *d_output, gprat::CUDA_GPU &gpu); +gen_tile_output(const std::size_t row, const std::size_t n_tile_size, const double *d_output, CUDA_GPU &gpu); /** * @brief Compute the L2-error norm over all tiles and elements @@ -126,7 +133,7 @@ double compute_error_norm(const std::size_t n_tiles, * * @return A tile filled with zeros of size N */ -double *gen_tile_zeros(std::size_t n_tile_size, gprat::CUDA_GPU &gpu); +double *gen_tile_zeros(std::size_t n_tile_size, CUDA_GPU &gpu); /** * @brief Allocates the tiled covariance matrix on the device given the training @@ -144,8 +151,8 @@ std::vector> assemble_tiled_covariance_matrix( const std::size_t n_tiles, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu); + const SEKParams sek_params, + CUDA_GPU &gpu); /** * @brief Allocates the tiled alpha vector on the device given the training @@ -159,7 +166,7 @@ std::vector> assemble_tiled_covariance_matrix( * @return A tiled alpha vector of size n_tiles x n_tile_size */ std::vector> assemble_alpha_tiles( - const double *d_output, const std::size_t n_tiles, const std::size_t n_tile_size, gprat::CUDA_GPU &gpu); + const double *d_output, const std::size_t n_tiles, const std::size_t n_tile_size, CUDA_GPU &gpu); /** * @brief Allocates the tiled cross covariance matrix on the device given the @@ -185,8 +192,8 @@ std::vector> assemble_cross_covariance_tiles( const std::size_t m_tile_size, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu); + const SEKParams sek_params, + CUDA_GPU &gpu); /** * @brief Allocates a tiled vector on the device and initializes it with zeros. @@ -198,7 +205,7 @@ std::vector> assemble_cross_covariance_tiles( * @return A tiled vector of size n_tiles x n_tile_size with zeros */ std::vector> -assemble_tiles_with_zeros(std::size_t n_tile_size, std::size_t n_tiles, gprat::CUDA_GPU &gpu); +assemble_tiles_with_zeros(std::size_t n_tile_size, std::size_t n_tiles, CUDA_GPU &gpu); /** * @brief Allocates the tiled prior covariance matrix on the device given the @@ -218,8 +225,8 @@ std::vector> assemble_prior_K_tiles( const std::size_t m_tiles, const std::size_t m_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu); + const SEKParams sek_params, + CUDA_GPU &gpu); /** * @brief Allocates the posterior covariance matrix. @@ -238,8 +245,8 @@ std::vector> assemble_prior_K_tiles_full( const std::size_t m_tiles, const std::size_t m_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu); + const SEKParams sek_params, + CUDA_GPU &gpu); /** * @brief Allocates the tiled transpose cross covariance matrix on the device @@ -261,7 +268,7 @@ std::vector> assemble_t_cross_covariance_tiles( const std::size_t m_tiles, const std::size_t n_tile_size, const std::size_t m_tile_size, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Allocates the output vector on the device given the training output @@ -272,7 +279,7 @@ std::vector> assemble_t_cross_covariance_tiles( * @param gpu GPU target for computations */ std::vector> assemble_y_tiles( - const double *d_training_output, const std::size_t n_tiles, const std::size_t n_tile_size, gprat::CUDA_GPU &gpu); + const double *d_training_output, const std::size_t n_tiles, const std::size_t n_tile_size, CUDA_GPU &gpu); /** * @brief Allocates the tiled covariance matrix on the device given the training @@ -286,7 +293,7 @@ std::vector> assemble_y_tiles( std::vector copy_tiled_vector_to_host_vector(std::vector> &d_tiles, std::size_t n_tile_size, std::size_t n_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Moves lower triangular tiles of the covariance matrix to the host. @@ -298,11 +305,11 @@ std::vector copy_tiled_vector_to_host_vector(std::vector> move_lower_tiled_matrix_to_host( +std::vector> move_lower_tiled_matrix_to_host( const std::vector> &d_tiles, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Frees the device memory of the lower triangular tiles of the covariance matrix. @@ -314,4 +321,6 @@ void free_lower_tiled_matrix(const std::vector> &d_ } // end of namespace gpu -#endif // end of GPU_GP_ALGORITHMS_H +GPRAT_NS_END + +#endif diff --git a/core/include/gpu/gp_functions.cuh b/core/include/gprat/gpu/gp_functions.cuh similarity index 87% rename from core/include/gpu/gp_functions.cuh rename to core/include/gprat/gpu/gp_functions.cuh index 6ea5bd0a..d8746d33 100644 --- a/core/include/gpu/gp_functions.cuh +++ b/core/include/gprat/gpu/gp_functions.cuh @@ -1,9 +1,15 @@ #ifndef GPU_GP_FUNCTIONS_H #define GPU_GP_FUNCTIONS_H -#include "gp_hyperparameters.hpp" -#include "gp_kernels.hpp" -#include "target.hpp" +#pragma once + +#include "gprat/detail/config.hpp" +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" +#include "gprat/tile_data.hpp" + +GPRAT_NS_BEGIN namespace gpu { @@ -28,13 +34,13 @@ std::vector predict(const std::vector &training_input, const std::vector &training_output, const std::vector &test_input, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Compute the predictions with uncertainties. @@ -56,13 +62,13 @@ std::vector> predict_with_uncertainty( const std::vector &training_input, const std::vector &training_output, const std::vector &test_input, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Compute the predictions with full covariance matrix. @@ -84,13 +90,13 @@ std::vector> predict_with_full_cov( const std::vector &training_input, const std::vector &training_output, const std::vector &test_data, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Compute loss for given data and Gaussian process model @@ -107,11 +113,11 @@ std::vector> predict_with_full_cov( */ double compute_loss(const std::vector &training_input, const std::vector &training_output, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform optimization for a given number of iterations @@ -137,10 +143,10 @@ optimize(const std::vector &training_input, int n_tiles, int n_tile_size, int n_regressors, - const gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, + const AdamParams &adam_params, + SEKParams &sek_params, std::vector trainable_params, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform a single optimization step @@ -166,11 +172,11 @@ double optimize_step(const std::vector &training_input, int n_tiles, int n_tile_size, int n_regressors, - gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, + AdamParams &adam_params, + SEKParams &sek_params, std::vector trainable_params, int iter, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform Cholesky decompositon (+ Assembly) @@ -186,14 +192,16 @@ double optimize_step(const std::vector &training_input, * * @return The tiled Cholesky factor */ -std::vector> +std::vector> cholesky(const std::vector &training_input, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); } // end of namespace gpu +GPRAT_NS_END + #endif diff --git a/core/include/gpu/gp_optimizer.cuh b/core/include/gprat/gpu/gp_optimizer.cuh similarity index 93% rename from core/include/gpu/gp_optimizer.cuh rename to core/include/gprat/gpu/gp_optimizer.cuh index d0c5dd3a..61495de0 100644 --- a/core/include/gpu/gp_optimizer.cuh +++ b/core/include/gprat/gpu/gp_optimizer.cuh @@ -1,12 +1,19 @@ -#ifndef GPU_GP_OPTIMIZER_H -#define GPU_GP_OPTIMIZER_H +#ifndef GPRAT_GPU_GP_OPTIMIZER_HPP +#define GPRAT_GPU_GP_OPTIMIZER_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" -#include "gp_hyperparameters.hpp" -#include "gp_kernels.hpp" -#include "target.hpp" #include #include +GPRAT_NS_BEGIN + namespace gpu { @@ -56,7 +63,7 @@ double compute_sigmoid(const double parameter); double compute_covariance_distance(std::size_t i_global, std::size_t j_global, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &i_input, const std::vector &j_input); @@ -77,7 +84,7 @@ std::vector gen_tile_distance( std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &input); /** @@ -96,7 +103,7 @@ std::vector gen_tile_covariance_with_distance( std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &cov_dists); /** @@ -116,7 +123,7 @@ gen_tile_grad_v(std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &cov_dists); /** @@ -136,7 +143,7 @@ gen_tile_grad_l(std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &cov_dists); /** @@ -159,7 +166,7 @@ std::vector gen_tile_grad_v_trans(std::size_t N, const std::vector -gen_tile_grad_l_trans(std::size_t N, const hpx::shared_future f_grad_l_tile, gprat::CUDA_GPU &gpu); +gen_tile_grad_l_trans(std::size_t N, const hpx::shared_future f_grad_l_tile, CUDA_GPU &gpu); /** * @brief Compute hyper-parameter beta_1 or beta_2 to power t. @@ -187,7 +194,7 @@ compute_loss(const hpx::shared_future &K_diag_tile, const hpx::shared_future &alpha_tile, const hpx::shared_future &y_tile, std::size_t N, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Add up negative-log likelihood loss for all tiles. @@ -260,8 +267,8 @@ double update_second_moment(const double &gradient, double v_T, const double &be */ hpx::shared_future update_param(const double unconstrained_hyperparam, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, double m_T, double v_T, const std::vector beta1_T, @@ -319,7 +326,7 @@ sum_gradright(const std::vector &inter_alpha, const std::vector */ double sum_noise_gradleft(const std::vector &ft_invK, double grad, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, std::size_t N, std::size_t n_tiles); @@ -334,8 +341,10 @@ double sum_noise_gradleft(const std::vector &ft_invK, * @return The sum of the noise gradient */ double -sum_noise_gradright(const std::vector &alpha, double grad, gprat_hyper::SEKParams sek_params, std::size_t N); +sum_noise_gradright(const std::vector &alpha, double grad, SEKParams sek_params, std::size_t N); } // end of namespace gpu -#endif // end of GPU_GP_OPTIMIZER_H +GPRAT_NS_END + +#endif diff --git a/core/include/gpu/gp_uncertainty.cuh b/core/include/gprat/gpu/gp_uncertainty.cuh similarity index 71% rename from core/include/gpu/gp_uncertainty.cuh rename to core/include/gprat/gpu/gp_uncertainty.cuh index 8c2dce18..4a93eccb 100644 --- a/core/include/gpu/gp_uncertainty.cuh +++ b/core/include/gprat/gpu/gp_uncertainty.cuh @@ -1,7 +1,13 @@ -#ifndef GPU_GP_UNCERTAINTY_H -#define GPU_GP_UNCERTAINTY_H +#ifndef GPRAT_GPU_GP_UNCERTAINTY_HPP +#define GPRAT_GPU_GP_UNCERTAINTY_HPP -#include "target.hpp" +#pragma once + +#include "gprat/detail/config.hpp" + +#include "gprat/target.hpp" + +GPRAT_NS_BEGIN namespace gpu { @@ -16,7 +22,7 @@ namespace gpu * @return Diagonal elements of posterior covariance matrix */ hpx::shared_future diag_posterior( - const hpx::shared_future A, const hpx::shared_future B, std::size_t M, gprat::CUDA_GPU &gpu); + const hpx::shared_future A, const hpx::shared_future B, std::size_t M, CUDA_GPU &gpu); /** * @brief Retrieve diagonal elements of posterior covariance matrix. @@ -26,8 +32,10 @@ hpx::shared_future diag_posterior( * * @return Diagonal elements of posterior covariance matrix */ -hpx::shared_future diag_tile(const hpx::shared_future A, std::size_t M, gprat::CUDA_GPU &gpu); +hpx::shared_future diag_tile(const hpx::shared_future A, std::size_t M, CUDA_GPU &gpu); } // end of namespace gpu -#endif // end of GPU_GP_UNCERTAINTY_H +GPRAT_NS_END + +#endif diff --git a/core/include/gpu/tiled_algorithms.cuh b/core/include/gprat/gpu/tiled_algorithms.cuh similarity index 92% rename from core/include/gpu/tiled_algorithms.cuh rename to core/include/gprat/gpu/tiled_algorithms.cuh index 78c6f5cb..38875e1e 100644 --- a/core/include/gpu/tiled_algorithms.cuh +++ b/core/include/gprat/gpu/tiled_algorithms.cuh @@ -1,12 +1,19 @@ -#ifndef GPU_TILED_ALGORITHMS_H -#define GPU_TILED_ALGORITHMS_H +#ifndef GPRAT_GPU_TILED_ALGORITHMS_HPP +#define GPRAT_GPU_TILED_ALGORITHMS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +#include "gprat/hyperparameters.hpp" +#include "gprat/target.hpp" +#include "gprat/kernels.hpp" -#include "gp_hyperparameters.hpp" -#include "target.hpp" #include -#include #include +GPRAT_NS_BEGIN + namespace gpu { @@ -26,7 +33,7 @@ namespace gpu void right_looking_cholesky_tiled(std::vector> &ft_tiles, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu, + CUDA_GPU &gpu, const cusolverDnHandle_t &cusolver); // Tiled Triangular Solve Algorithms @@ -44,7 +51,7 @@ void forward_solve_tiled(std::vector> &ft_tiles, std::vector> &ft_rhs, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform tiled backward triangular matrix-vector solve. @@ -59,7 +66,7 @@ void backward_solve_tiled(std::vector> &ft_tiles, std::vector> &ft_rhs, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform tiled forward triangular matrix-matrix solve. @@ -79,7 +86,7 @@ void forward_solve_tiled_matrix( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform tiled backward triangular matrix-matrix solve. @@ -99,7 +106,7 @@ void backward_solve_tiled_matrix( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform tiled matrix-vector multiplication @@ -120,7 +127,7 @@ void matrix_vector_tiled(std::vector> &ft_tiles, const std::size_t N_col, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Perform tiled symmetric k-rank update on diagonal tiles @@ -140,14 +147,14 @@ void symmetric_matrix_matrix_diagonal_tiled( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); void compute_gemm_of_invK_y(std::vector> &ft_invK, std::vector> &ft_y, std::vector> &ft_alpha, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); // Tiled Loss hpx::shared_future compute_loss_tiled( @@ -156,7 +163,7 @@ hpx::shared_future compute_loss_tiled( std::vector> &ft_y, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); // Tiled Diagonal of Posterior Covariance Matrix void symmetric_matrix_matrix_tiled( @@ -166,7 +173,7 @@ void symmetric_matrix_matrix_tiled( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Compute the difference between two tiled vectors @@ -183,14 +190,14 @@ void vector_difference_tiled(std::vector> &ft_prior std::vector> &ft_vector, const std::size_t m_tile_size, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); // Tiled Prediction Uncertainty void matrix_diagonal_tiled(std::vector> &ft_priorK, std::vector> &ft_vector, const std::size_t m_tile_size, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); // Compute I-y*y^T*inv(K) void update_grad_K_tiled_mkl(std::vector> &ft_tiles, @@ -198,7 +205,7 @@ void update_grad_K_tiled_mkl(std::vector> &ft_tiles const std::vector> &ft_v2, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Updates the lengthscale hyperparameter of the SEK kernel using Adam. @@ -223,8 +230,8 @@ double update_lengthscale( const std::vector> &ft_invK, const std::vector> &ft_gradparam, const std::vector> &ft_alpha, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, const std::size_t n_tile_size, const std::size_t n_tiles, std::vector> &m_T, @@ -232,7 +239,7 @@ double update_lengthscale( const std::vector> &beta1_T, const std::vector> &beta2_T, int iter, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Updates the vertical lengthscale hyperparameter of the SEK kernel @@ -258,8 +265,8 @@ double update_vertical_lengthscale( const std::vector> &ft_invK, const std::vector> &ft_gradparam, const std::vector> &ft_alpha, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, const std::size_t n_tile_size, const std::size_t n_tiles, std::vector> &m_T, @@ -267,7 +274,7 @@ double update_vertical_lengthscale( const std::vector> &beta1_T, const std::vector> &beta2_T, int iter, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); /** * @brief Updates a hyperparameter of the SEK kernel using Adam @@ -290,8 +297,8 @@ double update_vertical_lengthscale( double update_noise_variance( const std::vector> &ft_invK, const std::vector> &ft_alpha, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, const std::size_t n_tile_size, const std::size_t n_tiles, std::vector> &m_T, @@ -299,8 +306,10 @@ double update_noise_variance( const std::vector> &beta1_T, const std::vector> &beta2_T, int iter, - gprat::CUDA_GPU &gpu); + CUDA_GPU &gpu); } // end of namespace gpu -#endif // end of GPU_TILED_ALGORITHMS_H +GPRAT_NS_END + +#endif diff --git a/core/include/gp_hyperparameters.hpp b/core/include/gprat/hyperparameters.hpp similarity index 55% rename from core/include/gp_hyperparameters.hpp rename to core/include/gprat/hyperparameters.hpp index cd9cf5a8..fb719092 100644 --- a/core/include/gp_hyperparameters.hpp +++ b/core/include/gprat/hyperparameters.hpp @@ -1,10 +1,14 @@ -#ifndef GP_HYPERPARAMETERS_H -#define GP_HYPERPARAMETERS_H +#ifndef GPRAT_GPHYPERPARAMETERS_HPP +#define GPRAT_GPHYPERPARAMETERS_HPP +#pragma once + +#include "gprat/detail/config.hpp" + +#include #include -namespace gprat_hyper -{ +GPRAT_NS_BEGIN /** * @brief Hyperparameters for the Adam optimizer @@ -34,7 +38,7 @@ struct AdamParams /** * @brief Number of optimization iterations */ - int opt_iter; + std::size_t opt_iter; /** * @brief Initialize hyperparameters @@ -44,10 +48,8 @@ struct AdamParams * @param b2 beta2 * @param eps epsilon * @param opt_i number of optimization iterationsgp op - * @param M_T_init initial values for first moment vector - * @param V_T_init initial values for second moment vector */ - AdamParams(double lr = 0.001, double b1 = 0.9, double b2 = 0.999, double eps = 1e-8, int opt_i = 0); + AdamParams(double lr = 0.001, double b1 = 0.9, double b2 = 0.999, double eps = 1e-8, std::size_t opt_i = 0); /** * @brief Returns a string representation of the hyperparameters @@ -55,6 +57,30 @@ struct AdamParams std::string repr() const; }; -} // namespace gprat_hyper +template +void save_construct_data(Archive &ar, const AdamParams *v, const unsigned int) +{ + ar << v->learning_rate; + ar << v->beta1; + ar << v->beta2; + ar << v->epsilon; + ar << v->opt_iter; +} + +template +void load_construct_data(Archive &ar, AdamParams *v, const unsigned int) +{ + double learning_rate, beta1, beta2, epsilon; + std::size_t opt_iter; + ar >> learning_rate; + ar >> beta1; + ar >> beta2; + ar >> epsilon; + ar >> opt_iter; + + new (v) AdamParams(learning_rate, beta1, beta2, epsilon, opt_iter); +} + +GPRAT_NS_END -#endif // GP_HYPERPARAMETERS_H +#endif diff --git a/core/include/gp_kernels.hpp b/core/include/gprat/kernels.hpp similarity index 55% rename from core/include/gp_kernels.hpp rename to core/include/gprat/kernels.hpp index c1346f32..daa7798b 100644 --- a/core/include/gp_kernels.hpp +++ b/core/include/gprat/kernels.hpp @@ -1,12 +1,15 @@ -#ifndef GP_KERNELS_H -#define GP_KERNELS_H +#ifndef GPRAT_GPKERNELS_HPP +#define GPRAT_GPKERNELS_HPP -#include +#pragma once -// #include +#include "gprat/detail/config.hpp" -namespace gprat_hyper -{ +#include +#include +#include + +GPRAT_NS_BEGIN /** * @brief Squared Exponential Kernel Parameters @@ -41,12 +44,12 @@ struct SEKParams /** * @brief Construct a new SEKParams object * - * @param lengthscale Lengthscale: variance of training output - * @param vertical_lengthscale Vertical Lengthscale: standard deviation + * @param in_lengthscale Lengthscale: variance of training output + * @param in_vertical_lengthscale Vertical Lengthscale: standard deviation * of training input - * @param noise_variance Noise Variance: small value + * @param in_noise_variance Noise Variance: small value */ - SEKParams(double lengthscale_, double vertical_lengthscale_, double noise_variance_); + SEKParams(double in_lengthscale, double in_vertical_lengthscale, double in_noise_variance); /** * @brief Return the number of parameters @@ -77,6 +80,31 @@ struct SEKParams const double &get_param(std::size_t index) const; }; -} // namespace gprat_hyper +template +void save_construct_data(Archive &ar, const SEKParams *v, const unsigned int) +{ + ar << v->lengthscale; + ar << v->vertical_lengthscale; + ar << v->noise_variance; +} + +template +void load_construct_data(Archive &ar, SEKParams *v, const unsigned int) +{ + double lengthscale, vertical_lengthscale, noise_variance; + ar >> lengthscale; + ar >> vertical_lengthscale; + ar >> noise_variance; + + new (v) SEKParams(lengthscale, vertical_lengthscale, noise_variance); +} + +template +void serialize(Archive &ar, SEKParams &pt, const unsigned int) +{ + ar & pt.m_T & pt.w_T; +} + +GPRAT_NS_END -#endif // end of GP_KERNELS_H +#endif diff --git a/core/include/gprat/performance_counters.hpp b/core/include/gprat/performance_counters.hpp new file mode 100644 index 00000000..2310c6bc --- /dev/null +++ b/core/include/gprat/performance_counters.hpp @@ -0,0 +1,114 @@ +#ifndef GPRAT_PERFORMANCE_COUNTERS_HPP +#define GPRAT_PERFORMANCE_COUNTERS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +#include +#include +#include +#include +#include +#include +#include + +GPRAT_NS_BEGIN + +/// The following is a very simple way of defining per-function metrics by using the function itself as a template +/// parameter ensuring that each function receives exactly one instantiation. +template +struct function_performance_metrics +{ + /// Number of times the function was called + static std::atomic num_calls; + + /// Total wall-clock time elapsed inside the function + static std::atomic elapsed_ns; +}; + +template +/*static*/ std::atomic function_performance_metrics::num_calls(0); +template +/*static*/ std::atomic function_performance_metrics::elapsed_ns(0); + +/// @brief This RAII helper allows us to time a function's total wall-clock execution time with minimal code. +struct scoped_function_timer +{ + explicit scoped_function_timer(std::atomic &num_calls, std::atomic &in_total) : + total(in_total) + { + ++num_calls; + } + + ~scoped_function_timer() + { + const auto elapsed = timer.elapsed_nanoseconds(); + HPX_ASSERT(elapsed >= 0); + if (elapsed > 0) + { + total += static_cast(elapsed); + } + } + + std::atomic &total; + hpx::chrono::high_resolution_timer timer; +}; + +/// @brief Time the execution of the enclosing function from the current point to its end. +/// @param local_function The function key that we're collecting performance information for. Usually the enclosing +/// function. +#define GPRAT_TIME_FUNCTION(local_function) \ + scoped_function_timer _gprat_fn_timer(function_performance_metrics::num_calls, \ + function_performance_metrics::elapsed_ns) + +template +std::uint64_t get_and_reset_function_elapsed(bool reset) +{ + return hpx::util::get_and_reset_value(function_performance_metrics::elapsed_ns, reset); +} + +template +std::uint64_t get_and_reset_function_calls(bool reset) +{ + return hpx::util::get_and_reset_value(function_performance_metrics::num_calls, reset); +} + +void track_tile_data_allocation(std::size_t size); +void track_tile_data_deallocation(std::size_t size); + +void track_tile_server_allocation(std::size_t size); +void track_tile_server_deallocation(std::size_t size); + +void record_transmission_time(std::int64_t elapsed_ns); + +std::uint64_t get_tile_data_allocations(bool reset); +std::uint64_t get_tile_data_deallocations(bool reset); +std::uint64_t get_tile_server_allocations(bool reset); +std::uint64_t get_tile_server_deallocations(bool reset); +std::uint64_t get_tile_transmission_time(bool reset); +std::uint64_t get_tile_transmission_count(bool reset); + +void register_performance_counters(); + +void force_evict_memory(const void *start, std::size_t size); + +template +void force_evict_memory(std::span data) +{ + force_evict_memory(data.data(), data.size_bytes()); +} + +#ifdef GPRAT_ENABLE_BENCHMARK_CACHE_EVICTIONS +/// @brief Force-evict a memory span from the cache for benchmarking purposes. +/// @param data The memory region to evict +#define GPRAT_BENCHMARK_FORCE_EVICT(data) force_evict_memory(data) +#else +/// @brief Force-evict a memory span from the cache for benchmarking purposes. +/// @param data The memory region to evict +#define GPRAT_BENCHMARK_FORCE_EVICT(data) (void) data +#endif + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/scheduler.hpp b/core/include/gprat/scheduler.hpp new file mode 100644 index 00000000..80c026ca --- /dev/null +++ b/core/include/gprat/scheduler.hpp @@ -0,0 +1,208 @@ +#ifndef GPRAT_CPU_SCHEDULER_HPP +#define GPRAT_CPU_SCHEDULER_HPP + +#pragma once + +#include "gprat/detail/async_helpers.hpp" + +// TODO: move to separate header +#include "gprat/tile_data.hpp" + +#include +#include + +GPRAT_NS_BEGIN + +using tiled_scheduler_local = basic_local_scheduler; + +template +using tiled_dataset_local = std::vector>>; + +template +struct tile_dataset_type; + +template +struct tile_dataset_type +{ + using type = tiled_dataset_local; +}; + +template +tiled_dataset_local make_tiled_dataset(const tiled_scheduler_local &, std::size_t num_tiles, Mapper &&) +{ + return std::vector>>{ num_tiles }; +} + +// ============================================================= +// local scheduler + +constexpr std::size_t covariance_tile_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*row*/, std::size_t /*col*/) +{ + return 0; +} + +constexpr std::size_t cross_covariance_tile_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*row*/, std::size_t /*col*/) +{ + return 0; +} + +constexpr std::size_t alpha_tile_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*i*/) +{ + return 0; +} + +constexpr std::size_t +prediction_tile_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*i*/) +{ + return 0; +} + +constexpr std::size_t t_cross_covariance_tile_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*row*/, std::size_t /*col*/) +{ + return 0; +} + +constexpr std::size_t prior_K_tile_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*row*/, std::size_t /*col*/) +{ + return 0; +} + +constexpr std::size_t K_inv_tile_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*row*/, std::size_t /*col*/) +{ + return 0; +} + +constexpr std::size_t K_grad_v_tile_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*row*/, std::size_t /*col*/) +{ + return 0; +} + +constexpr std::size_t K_grad_l_tile_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*row*/, std::size_t /*col*/) +{ + return 0; +} + +constexpr std::size_t +uncertainty_tile_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*i*/) +{ + return 0; +} + +constexpr std::size_t +inter_alpha_tile_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*i*/) +{ + return 0; +} + +constexpr std::size_t diag_tile_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*i*/) +{ + return 0; +} + +constexpr std::size_t +cholesky_potrf_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/) +{ + return 0; +} + +constexpr std::size_t +cholesky_syrk_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*m*/) +{ + return 0; +} + +constexpr std::size_t +cholesky_trsm_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/, std::size_t /*m*/) +{ + return 0; +} + +constexpr std::size_t cholesky_gemm_on(const tiled_scheduler_local & /*sched*/, + std::size_t /*n_tiles*/, + std::size_t /*k*/, + std::size_t /*m*/, + std::size_t /*n*/) +{ + return 0; +} + +constexpr std::size_t solve_trsv_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/) +{ + return 0; +} + +constexpr std::size_t solve_trsm_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/) +{ + return 0; +} + +constexpr std::size_t +solve_gemv_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/, std::size_t /*m*/) +{ + return 0; +} + +constexpr std::size_t solve_matrix_trsm_on( + const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*c*/, std::size_t /*k*/) +{ + return 0; +} + +constexpr std::size_t solve_matrix_gemm_on(const tiled_scheduler_local & /*sched*/, + std::size_t /*n_tiles*/, + std::size_t /*c*/, + std::size_t /*k*/, + std::size_t /*m*/) +{ + return 0; +} + +constexpr std::size_t +multiply_gemv_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/, std::size_t /*m*/) +{ + return 0; +} + +constexpr std::size_t +k_rank_dot_diag_syrk_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/) +{ + return 0; +} + +constexpr std::size_t k_rank_gemm_on(const tiled_scheduler_local & /*sched*/, + std::size_t /*n_tiles*/, + std::size_t /*c*/, + std::size_t /*k*/, + std::size_t /*m*/) +{ + return 0; +} + +constexpr std::size_t +vector_axpy_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/) +{ + return 0; +} + +constexpr std::size_t +get_diagonal_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/) +{ + return 0; +} + +constexpr std::size_t +compute_loss_on(const tiled_scheduler_local & /*sched*/, std::size_t /*n_tiles*/, std::size_t /*k*/) +{ + return 0; +} + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/scheduler/cyclic.hpp b/core/include/gprat/scheduler/cyclic.hpp new file mode 100644 index 00000000..9afcf934 --- /dev/null +++ b/core/include/gprat/scheduler/cyclic.hpp @@ -0,0 +1,153 @@ +#ifndef GPRAT_SCHEDULER_CYCLIC_HPP +#define GPRAT_SCHEDULER_CYCLIC_HPP + +#pragma once + +#include "gprat/detail/actions.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/scheduler.hpp" + +GPRAT_NS_BEGIN + +struct tiled_scheduler_cyclic : tiled_scheduler_distributed +{ + using tiled_scheduler_distributed::tiled_scheduler_distributed; + + /// @brief Create a new scheduler that targets all localities. + explicit tiled_scheduler_cyclic(std::size_t in_width = 1) : + num_localities(localities_.size()), + width(in_width), + height(num_localities / width) + { + if (num_localities % width != 0) + { + throw std::invalid_argument("num_localities must be divisible by width"); + } + } + + /// @brief Create a new scheduler that targets the given localities. + explicit tiled_scheduler_cyclic(std::vector in_localities, std::size_t in_width = 1) : + tiled_scheduler_distributed(std::move(in_localities)), + num_localities(localities_.size()), + width(in_width), + height(num_localities / width) + { + if (num_localities % width != 0) + { + throw std::invalid_argument("num_localities must be divisible by width"); + } + } + + std::size_t num_localities; + std::size_t width; + std::size_t height; +}; + +constexpr std::size_t +covariance_tile_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row % sched.height) + (col % sched.width); +} + +constexpr std::size_t +cross_covariance_tile_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row % sched.height) + (col % sched.width); +} + +constexpr std::size_t alpha_tile_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t i) +{ + return (i % sched.height) + (i % sched.width); +} + +constexpr std::size_t prediction_tile_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t i) +{ + return (i % sched.height) + (i % sched.width); +} + +constexpr std::size_t cholesky_potrf_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (k % sched.height) + (k % sched.width); +} + +constexpr std::size_t cholesky_syrk_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t m) +{ + return (m % sched.height) + (m % sched.width); +} + +constexpr std::size_t +cholesky_trsm_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t k, std::size_t m) +{ + return (m % sched.height) + (k % sched.width); +} + +constexpr std::size_t cholesky_gemm_on( + const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t k, std::size_t m, std::size_t n) +{ + return (m % sched.height) + (n % sched.width); +} + +constexpr std::size_t solve_trsv_on(const tiled_scheduler_cyclic &sched, std::size_t n_tiles, std::size_t k) +{ + return (k % sched.height) + (k % sched.width); +} + +constexpr std::size_t solve_trsm_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (k % sched.height) + (k % sched.width); +} + +constexpr std::size_t +solve_gemv_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t k, std::size_t m) +{ + return (k % sched.height) + (m % sched.width); +} + +constexpr std::size_t +solve_matrix_trsm_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t c, std::size_t k) +{ + return (k % sched.height) + (c % sched.width); +} + +constexpr std::size_t solve_matrix_gemm_on( + const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t c, std::size_t k, std::size_t m) +{ + return (m % sched.height) + (c % sched.width); +} + +constexpr std::size_t +multiply_gemv_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t k, std::size_t m) +{ + return (k % sched.height) + (m % sched.width); +} + +constexpr std::size_t +k_rank_dot_diag_syrk_on(const tiled_scheduler_cyclic &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (k % sched.height) + (k % sched.width); +} + +constexpr std::size_t +k_rank_gemm_on(const tiled_scheduler_cyclic &sched, std::size_t n_tiles, std::size_t c, std::size_t k, std::size_t m) +{ + return (k * n_tiles + m) % sched.num_localities; +} + +constexpr std::size_t vector_axpy_on(const tiled_scheduler_cyclic &sched, std::size_t n_tiles, std::size_t k) +{ + return (k * n_tiles + k) % sched.num_localities; +} + +constexpr std::size_t get_diagonal_on(const tiled_scheduler_cyclic &sched, std::size_t n_tiles, std::size_t k) +{ + return (k * n_tiles + k) % sched.num_localities; +} + +constexpr std::size_t compute_loss_on(const tiled_scheduler_cyclic &sched, std::size_t n_tiles, std::size_t k) +{ + return (k * n_tiles + k) % sched.num_localities; +} + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/scheduler/sma.hpp b/core/include/gprat/scheduler/sma.hpp new file mode 100644 index 00000000..74730563 --- /dev/null +++ b/core/include/gprat/scheduler/sma.hpp @@ -0,0 +1,170 @@ +#ifndef GPRAT_SCHEDULER_SMA_HPP +#define GPRAT_SCHEDULER_SMA_HPP + +#pragma once + +#include "gprat/detail/actions.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/scheduler.hpp" + +GPRAT_NS_BEGIN + +struct tiled_scheduler_sma : tiled_scheduler_distributed +{ + using tiled_scheduler_distributed::tiled_scheduler_distributed; + + std::size_t num_localities = localities_.size(); +}; + +constexpr std::size_t +covariance_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row + col) % sched.num_localities; +} + +constexpr std::size_t +cross_covariance_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row + col) % sched.num_localities; +} + +constexpr std::size_t alpha_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t i) +{ + return (2 * i) % sched.num_localities; +} + +constexpr std::size_t prediction_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t i) +{ + return (2 * i) % sched.num_localities; +} + +constexpr std::size_t +t_cross_covariance_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row + col) % sched.num_localities; +} + +constexpr std::size_t +prior_K_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row + col) % sched.num_localities; +} + +constexpr std::size_t +K_inv_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row + col) % sched.num_localities; +} + +constexpr std::size_t +K_grad_v_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row + col) % sched.num_localities; +} + +constexpr std::size_t +K_grad_l_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t row, std::size_t col) +{ + return (row + col) % sched.num_localities; +} + +constexpr std::size_t uncertainty_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t i) +{ + return (2 * i) % sched.num_localities; +} + +constexpr std::size_t inter_alpha_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t i) +{ + return (2 * i) % sched.num_localities; +} + +constexpr std::size_t diag_tile_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t i) +{ + return i % sched.num_localities; +} + +constexpr std::size_t cholesky_potrf_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (2 * k) % sched.num_localities; +} + +constexpr std::size_t cholesky_syrk_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t m) +{ + return (2 * m) % sched.num_localities; +} + +constexpr std::size_t +cholesky_trsm_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k, std::size_t m) +{ + return (k + m) % sched.num_localities; +} + +constexpr std::size_t cholesky_gemm_on( + const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t /*k*/, std::size_t m, std::size_t n) +{ + return (m + n) % sched.num_localities; +} + +constexpr std::size_t solve_trsv_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (2 * k) % sched.num_localities; +} + +constexpr std::size_t solve_trsm_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (2 * k) % sched.num_localities; +} + +constexpr std::size_t +solve_gemv_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k, std::size_t m) +{ + return (k + m) % sched.num_localities; +} + +constexpr std::size_t +solve_matrix_trsm_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t c, std::size_t k) +{ + return (k + c) % sched.num_localities; +} + +constexpr std::size_t solve_matrix_gemm_on( + const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t c, std::size_t /*k*/, std::size_t m) +{ + return (c + m) % sched.num_localities; +} + +constexpr std::size_t +multiply_gemv_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k, std::size_t m) +{ + return (k + m) % sched.num_localities; +} + +constexpr std::size_t k_rank_dot_diag_syrk_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (2 * k) % sched.num_localities; +} + +constexpr std::size_t k_rank_gemm_on( + const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t /*c*/, std::size_t k, std::size_t m) +{ + return (k + m) % sched.num_localities; +} + +constexpr std::size_t vector_axpy_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (2 * k) % sched.num_localities; +} + +constexpr std::size_t get_diagonal_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (2 * k) % sched.num_localities; +} + +constexpr std::size_t compute_loss_on(const tiled_scheduler_sma &sched, std::size_t /*n_tiles*/, std::size_t k) +{ + return (2 * k) % sched.num_localities; +} + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/target.hpp b/core/include/gprat/target.hpp new file mode 100644 index 00000000..59c0cca9 --- /dev/null +++ b/core/include/gprat/target.hpp @@ -0,0 +1,392 @@ +#ifndef GPRAT_TARGET_H +#define GPRAT_TARGET_H + +#pragma once + +#include "gprat/detail/config.hpp" + +#include +#include + +#if GPRAT_WITH_CUDA +#include +#include +#endif + +#if GPRAT_WITH_SYCL +#include +#endif + +GPRAT_NS_BEGIN + +struct DeviceParameters +{ + std::size_t id; + std::size_t n_queues; +}; + +/** + * @brief This class represents the target on which to perform the Gaussian + * Process computations: either CPU or GPU. + * + * The respective subclasses implement specific targets: CPU, CUDA_GPU, SYCL_DEVICE. + * They may also set additional attributes or function that are required when + * using this target. + */ +struct Target +{ + /** + * @brief Returns true if target is CPU. + * + * Implemented by subclasses. + */ + virtual bool is_cpu() = 0; + + /** + * @brief Returns true if target is a CUDA GPU. + * + * Implemented by subclasses. + */ + virtual bool is_gpu() = 0; + + /** + * @brief Returns true if target is a SYCL device. + * + * Implemented by subclasses. + */ + virtual bool is_sycl() = 0; + + /** + * @brief Returns string representation of the target. + * + * Implemented by subclasses. + */ + virtual std::string repr() const = 0; + + virtual ~Target() { } + + protected: + Target() = default; +}; + +// CPU //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +struct CPU : public Target +{ + public: + /** + * @brief Returns CPU target. + */ + CPU(); + + /** + * @brief Returns true because target is CPU. + */ + bool is_cpu() override; + + /** + * @brief Returns false because CPU target is not a CUDA GPU. + */ + bool is_gpu() override; + + /** + * @brief Returns false because CPU target is not a SYCL device. + */ + bool is_sycl() override; + + /** + * @brief Returns string representation of the CPU target. + */ + std::string repr() const override; +}; + +/** + * @brief Creates and returns handle for CPU target. + * + * @return CPU target + */ +CPU get_cpu(); + +// CUDA GPU /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if GPRAT_WITH_CUDA +struct CUDA_GPU : public Target +{ + /** + * @brief Identifier of GPU device. + * + * Can be set to a value between 0 and gpu_count(). + */ + int id; + + /** + * @brief Number of CUDA streams used asynchronous computation and data + * transfer. + */ + int n_streams; + + /** + * @brief Index of next CUDA stream assigned on next_stream() or + * next_cublas_handle(). + */ + std::atomic i_stream; + + /** @brief Default amount of CUDA shared memory used by CUDA kernels. */ + int shared_memory_size; + + /** + * @brief Returns GPU target that uses CUDA. + */ + CUDA_GPU(int id, int n_streams); + + CUDA_GPU(const CUDA_GPU &o) : + id(o.id), + n_streams(o.n_streams), + i_stream(o.i_stream.load()), + shared_memory_size(o.shared_memory_size), + streams(o.streams), + cublas_handles(o.cublas_handles) + { } + + CUDA_GPU &operator=(const CUDA_GPU &o) + { + id = o.id; + n_streams = o.n_streams; + i_stream.store(o.i_stream.load()); + shared_memory_size = o.shared_memory_size; + streams = o.streams; + cublas_handles = o.cublas_handles; + return *this; + } + + /** + * @brief Returns false because target is not CPU. + */ + bool is_cpu() override; + + /** + * @brief Returns true because target is a CUDA GPU. + */ + bool is_gpu() override; + + /** + * @brief Returns false because target is not a SYCL device. + */ + bool is_sycl() override; + + /** + * @brief Returns string representation of the GPU target. + */ + std::string repr() const override; + + /** + * @brief Creates n_streams CUDA streams and cublas handles. + * + * WARNING: Call destroy() to free both resources after using them. + */ + void create(); + + /** + * @brief Destroys the CUDA streams and cublas handles previously created + * with create(). + */ + void destroy(); + + /** + * @brief Returns the next CUDA streams. + * + * It regards the collection of CUDA streams as a cyclic list and returns + * the next CUDA stream in the cycle. The returned stream was already + * created when calling create() and will be destroyed by using destroy(). + * + * @return CUDA stream + */ + cudaStream_t next_stream(); + + /** + * @brief Synchronizes the collection of CUDA streams. + * + * The streams must have be retrieved by next_stream(). Thus, it can use the + * cyclic ordering to sync each stream in subset_of_streams only once. + * + * @param subset_of_streams Vector of CUDA streams, previously retrieved + * with next_stream(). + */ + void sync_streams(std::vector &subset_of_streams); + + /** + * @brief Returns the next cuBLAS handle. + * + * It regards the collection of cuBLAS handles as a cyclic list and returns + * the next handle in the cycle. The returned handle was already + * created when calling create() and will be destroyed by using destroy(). + * + * @return cuBLAS handle + */ + std::pair next_cublas_handle(); + + private: + std::vector streams; + std::vector cublas_handles; +}; + +/** + * @brief Creates and returns handle for GPU target. + * + * @param id ID of GPU. + * @param n_streams Number of streams to be created on GPU. + * + * @return GPU target + */ +CUDA_GPU get_gpu(int id, int n_streams); + +/** + * @brief Returns handle for GPU target with ID 0. + * + * Uses only one stream, so single-threaded GPU execution. + */ +CUDA_GPU get_gpu(); +#endif + +// SYCL /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if GPRAT_WITH_SYCL +struct SYCL_DEVICE : public Target +{ + /** + * @brief Identifier of SYCL device. + * + * Can be set to a value between 0 and device_count(). + */ + std::size_t id; + + /** + * @brief Number of SYCL queues used asynchronous computation and data transfer. + */ + std::size_t n_queues; + + /** + * @brief Index of next SYCL queue assigned on next_queue(). + */ + std::atomic i_queue; + + /** @brief Default amount of SYCL local memory used by kernels. */ + std::size_t local_memory_size; + + /** + * @brief Returns GPU target that uses SYCL. + */ + SYCL_DEVICE(int gpu_id, int n_queues); + + SYCL_DEVICE(const SYCL_DEVICE &o) : + id(o.id), + n_queues(o.n_queues), + i_queue(o.i_queue.load()), + local_memory_size(o.local_memory_size), + selected_device_(o.selected_device_), + queues(o.queues) + { } + + SYCL_DEVICE &operator=(const SYCL_DEVICE &o) + { + id = o.id; + n_queues = o.n_queues; + i_queue.store(o.i_queue.load()); + local_memory_size = o.local_memory_size; + selected_device_ = o.selected_device_; + queues = o.queues; + return *this; + } + + /** + * @brief Returns false because target is not CPU. + */ + bool is_cpu() override; + + /** + * @brief Returns false because target is not a CUDA GPU. + */ + bool is_gpu() override; + + /** + * @brief Returns true because target is a SYCL device. + */ + bool is_sycl() override; + + /** + * @brief Returns string representation of the SYCL target. + */ + std::string repr() const override; + + /** + * @brief Creates n_queues SYCL queues. + * + * WARNING: Call destroy() to free both resources after using them. + */ + void create(); + + /** + * @brief Destroys the SYCL queues previously created with create(). + */ + void destroy(); + + /** + * @brief Returns the next SYCL queue. + * + * It regards the collection of SYCL queues as a cyclic list and returns + * the next SYCL queue in the cycle. The returned queue was already + * created when calling create() and will be destroyed by using destroy(). + * + * @return SYCL queue + */ + sycl::queue next_queue(); + + /** + * @brief Synchronizes the collection of SYCL queues. + * + * The queue must be retrieved by next_queue(). Thus, it can use the + * cyclic ordering to sync each queue in subset_of_queues only once. + * + * @param subset_of_queue Vector of SYCL queues, previously retrieved + * with next_queue(). + */ + void sync_queues(std::vector &subset_of_queues); + + private: + sycl::device selected_device_; + std::vector queues; +}; + +/** + * @brief Creates and returns handle for SYCL target. + * + * @param id ID of SYCL device. + * @param n_queues Number of queues to be created on SYCL device. + * + * @return SYCL target + */ +SYCL_DEVICE get_sycl_device(int id, int n_queues); + +/** + * @brief Returns handle for SYCL target with ID 0. + * + * Uses only one queue, so single-threaded GPU execution. + */ +SYCL_DEVICE get_sycl_device(); +#endif + +// General //////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Lists available GPUs with their properties. + */ +void print_available_gpus(); + +/** + * @brief Returns number of available GPUs. + */ +int gpu_count(); + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/tile_cache.hpp b/core/include/gprat/tile_cache.hpp new file mode 100644 index 00000000..6410b0b5 --- /dev/null +++ b/core/include/gprat/tile_cache.hpp @@ -0,0 +1,97 @@ +#ifndef GPRAT_TILECACHE_HPP +#define GPRAT_TILECACHE_HPP + +#pragma once + +#include "gprat/tile_data.hpp" + +#include +#include + +GPRAT_NS_BEGIN + +namespace detail +{ +hpx::util::cache::statistics::local_full_statistics &get_global_statistics(); + +/// @brief Statistics implementation that uses counters shared between all tile_cache instances +class global_full_statistics +{ + public: + using update_on_exit = hpx::util::cache::statistics::local_full_statistics::update_on_exit; + + // ReSharper disable once CppNonExplicitConversionOperator + operator hpx::util::cache::statistics::local_full_statistics &() const { return get_global_statistics(); } + + void got_hit() noexcept { get_global_statistics().got_hit(); } + + void got_miss() noexcept { get_global_statistics().got_miss(); } + + void got_insertion() noexcept { get_global_statistics().got_insertion(); } + + void got_eviction() noexcept { get_global_statistics().got_eviction(); } + + void clear() noexcept { get_global_statistics().clear(); } +}; +} // namespace detail + +/** + * @brief LRU cache for mutable_tile_data objects with versioning support + * @tparam T Tile data type. + */ +template +class tile_cache +{ + friend struct tile_cache_counters; + + public: + explicit tile_cache(std::size_t max_size = 16) : + cache_(max_size) + { } + + bool try_get(const hpx::naming::gid_type &key, std::size_t generation, mutable_tile_data &cached_data) + { + std::lock_guard g(mutex_); + + entry e; + { + hpx::naming::gid_type unused; + if (!cache_.get_entry(key, unused, e)) + { + return false; + } + } + + if (e.generation == generation) + { + cached_data = e.data; + return true; + } + + // Erase the obsolete entry + cache_.erase([&](const auto &p) { return p.first == key; }); + return false; + } + + void insert(const hpx::naming::gid_type &key, std::size_t generation, const mutable_tile_data &data) + { + std::lock_guard g(mutex_); + cache_.insert(key, entry{ data, generation }); + } + + void clear() { cache_.clear(); } + + private: + struct entry + { + mutable_tile_data data; + std::size_t generation = 0; + }; + + hpx::mutex mutex_; // lru_cache is not thread-safe! + hpx::util::cache::lru_cache cache_; +}; + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/tile_data.hpp b/core/include/gprat/tile_data.hpp new file mode 100644 index 00000000..c4b2c086 --- /dev/null +++ b/core/include/gprat/tile_data.hpp @@ -0,0 +1,184 @@ +#ifndef GPRAT_TILE_DATA_HPP +#define GPRAT_TILE_DATA_HPP + +#pragma once + +#include "gprat/detail/config.hpp" + +#include +#include + +GPRAT_NS_BEGIN + +namespace detail +{ +void *allocate_tile_data(std::size_t num_bytes); +void deallocate_tile_data(void *p, std::size_t num_bytes); + +template +struct tile_data_allocator +{ + typedef T value_type; + + tile_data_allocator() = default; + + template + constexpr tile_data_allocator(const tile_data_allocator &) noexcept + { } + + [[nodiscard]] T *allocate(std::size_t n) + { + if (n > (std::numeric_limits::max)() / sizeof(T)) + { + throw std::bad_array_new_length(); + } + + if (auto p = static_cast(allocate_tile_data(n * sizeof(T)))) + { + return p; + } + + throw std::bad_alloc(); + } + + void deallocate(T *p, std::size_t n) noexcept { deallocate_tile_data(p, n * sizeof(T)); } +}; + +template +bool operator==(const tile_data_allocator &, const tile_data_allocator &) +{ + return true; +} + +template +bool operator!=(const tile_data_allocator &, const tile_data_allocator &) +{ + return false; +} +} // namespace detail + +/** + * @brief Non-mutable reference-counted dynamic array of a given type T. + * This class represents a simple reference-counted non-resizeable buffer with elements of type T. + * It can be serialized by HPX and thus be used as a parameter for HPX actions. + * This type is intended to be used for parameters and attributes that do not require mutable data (i.e., only read + * access) + * + * @tparam T Element type of the tile. Usually some numeric type like double or float. This class currently only + * requires T to be serializable by HPX. + */ +template +class const_tile_data +{ + protected: + typedef hpx::serialization::serialize_buffer> cpu_buffer_type; + + struct hold_reference + { + explicit hold_reference(const cpu_buffer_type &data) : + data_(data) + { } + + void operator()(const T *) const { } // no deletion necessary + + cpu_buffer_type data_; + }; + + public: + const_tile_data() = default; + + // Create a new (uninitialized) tile_data of the given size. + explicit const_tile_data(std::size_t size) : + cpu_data_(size) + { } + + // Create a tile_data which acts as a proxy to a part of the embedded array. + // The proxy is assumed to refer to either the left or the right boundary + // element. + const_tile_data(const const_tile_data &base, std::size_t offset, std::size_t size) : + cpu_data_(base.cpu_data_.data() + offset, + size, + cpu_buffer_type::reference, + hold_reference(base.cpu_data_)) // keep referenced tile_data alive + { } + + [[nodiscard]] const T *data() const + { + if (!cpu_data_.data()) + { + throw std::runtime_error("no data"); + } + return cpu_data_.data(); + } + + [[nodiscard]] std::size_t size() const noexcept { return cpu_data_.size(); } + + [[nodiscard]] const T *begin() const noexcept { return cpu_data_.data(); } + + [[nodiscard]] const T *end() const noexcept { return cpu_data_.data() + cpu_data_.size(); } + + [[nodiscard]] const T &operator[](std::size_t idx) const { return cpu_data_[idx]; } + + [[nodiscard]] std::span as_span() const noexcept { return { cpu_data_.data(), cpu_data_.size() }; } + + // ReSharper disable once CppNonExplicitConversionOperator + operator std::span() const noexcept // NOLINT(*-explicit-constructor) + { + return { cpu_data_.data(), cpu_data_.size() }; + } + + friend bool operator==(const const_tile_data &a, const const_tile_data &b) noexcept + { + return a.cpu_data_ == b.cpu_data_; + } + + protected: + friend class hpx::serialization::access; + + template + void serialize(Archive &ar, const unsigned int) + { + // clang-format off + ar & cpu_data_; + // clang-format on + } + + cpu_buffer_type cpu_data_; +}; + +/** + * A mutable version of const_tile_data. + * + * @tparam T Element type of the tile. See @ref const_tile_data + */ +template +class mutable_tile_data : public const_tile_data +{ + public: + using const_tile_data::const_tile_data; + + [[nodiscard]] T *data() const + { + if (!this->cpu_data_.data()) + { + throw std::runtime_error("no data"); + } + return const_cast(this->cpu_data_.data()); + } + + [[nodiscard]] T *begin() const noexcept { return const_cast(this->cpu_data_.data()); } + + [[nodiscard]] T *end() const noexcept { return const_cast(this->cpu_data_.data()) + this->cpu_data_.size(); } + + [[nodiscard]] T &operator[](std::size_t idx) const { return this->cpu_data_[idx]; } + + // ReSharper disable once CppNonExplicitConversionOperator + operator std::span() noexcept // NOLINT(*-explicit-constructor) + { + return { this->cpu_data_.data(), this->cpu_data_.size() }; + } +}; + +GPRAT_NS_END + +#endif diff --git a/core/include/gprat/tiled_dataset.hpp b/core/include/gprat/tiled_dataset.hpp new file mode 100644 index 00000000..2aeba1b9 --- /dev/null +++ b/core/include/gprat/tiled_dataset.hpp @@ -0,0 +1,456 @@ +#ifndef GPRAT_COMPONENTS_TILED_DATASET_HPP +#define GPRAT_COMPONENTS_TILED_DATASET_HPP + +#pragma once + +#include "gprat/detail/actions.hpp" +#include "gprat/detail/config.hpp" +#include "gprat/performance_counters.hpp" +#include "gprat/tile_cache.hpp" +#include "gprat/tile_data.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GPRAT_NS_BEGIN + +namespace server +{ + +/** + * Server component owning a single tile's data. + * + * @tparam T Element type of the tile. Usually some numeric type like double or float. This class currently only + * requires T to be serializable by HPX. + */ +template +struct tile_holder : hpx::components::component_base> +{ + tile_holder() { track_tile_server_allocation(0); } + + explicit tile_holder(const mutable_tile_data &data) : + data_(data) + { + track_tile_server_allocation(data.size()); + } + + ~tile_holder() { track_tile_server_deallocation(data_.size()); } + + [[nodiscard]] mutable_tile_data get_data() const + { + std::shared_lock lock(mutex_); + return data_; + } + + void set_data(const mutable_tile_data &data) + { + std::unique_lock lock(mutex_); + data_ = data; + } + + // Every member function that has to be invoked remotely needs to be + // wrapped into a component action. + HPX_DEFINE_COMPONENT_DIRECT_ACTION(tile_holder, get_data) + HPX_DEFINE_COMPONENT_DIRECT_ACTION(tile_holder, set_data) + + private: + mutable hpx::shared_mutex mutex_; + mutable_tile_data data_; +}; + +template +struct tile_manager_shared_data +{ + struct tile_entry + { + tile_entry() : + locality_id(hpx::naming::invalid_locality_id) + { } + + tile_entry(hpx::id_type tile, std::uint32_t in_locality_id) : + id(std::move(tile)), + locality_id(in_locality_id) + { } + + hpx::id_type id; + std::uint32_t locality_id; + std::shared_ptr> local_data; + + private: + friend class hpx::serialization::access; + + template + void serialize(Archive &ar, unsigned) + { + ar & id & locality_id; + } + }; + + std::vector tiles; + + private: + friend class hpx::serialization::access; + + template + void serialize(Archive &ar, unsigned) + { + ar & tiles; + } +}; + +template +struct tile_manager : hpx::components::component_base> +{ + explicit tile_manager(tile_manager_shared_data &&data) : + data_(std::move(data)) + { + const auto here = hpx::get_locality_id(); + for (auto &tile : data_.tiles) + { + if (tile.locality_id == here) + { + tile.local_data = hpx::get_ptr>(hpx::launch::sync, tile.id); + } + } + } + + mutable_tile_data get_tile_data(std::size_t tile_index, std::size_t generation) + { + const auto &target_tile = data_.tiles[tile_index]; + + // Best is always to rely on local data + if (target_tile.local_data) + { + return target_tile.local_data->get_data(); + } + + // Next, try the tile cache - maybe we have current data + { + mutable_tile_data cached_data; + if (cache_.try_get(target_tile.id.get_gid(), generation, cached_data)) + { + return cached_data; + } + } + + hpx::chrono::high_resolution_timer timer; + auto data = hpx::async(typename tile_holder::get_data_action{}, target_tile.id).get(); + + record_transmission_time(timer.elapsed_nanoseconds()); + cache_.insert(target_tile.id.get_gid(), generation, data); + + return data; + } + + hpx::future> get_tile_data_async(std::size_t tile_index, std::size_t generation) + { + const auto &target_tile = data_.tiles[tile_index]; + + // Best is always to rely on local data + if (target_tile.local_data) + { + return hpx::make_ready_future(target_tile.local_data->get_data()); + } + + // Next, try the tile cache - maybe we have current data + { + mutable_tile_data cached_data; + if (cache_.try_get(target_tile.id.get_gid(), generation, cached_data)) + { + return hpx::make_ready_future(cached_data); + } + } + + return hpx::async(typename tile_holder::get_data_action{}, target_tile.id) + .then( + [this, + self = this->get_id(), + generation, + gid = target_tile.id.get_gid(), + timer = hpx::chrono::high_resolution_timer()](hpx::future> &&f) mutable + { + record_transmission_time(timer.elapsed_nanoseconds()); + auto data = f.get(); + cache_.insert(gid, generation, data); + self = {}; // release our reference + return data; + }); + } + + hpx::future + set_tile_data_async(std::size_t tile_index, std::size_t generation, const mutable_tile_data &data) + { + const auto &target_tile = data_.tiles[tile_index]; + + if (target_tile.local_data) + { + target_tile.local_data->set_data(data); + return hpx::make_ready_future(); + } + + // Insert into cache only after the remote write confirms success; inserting + // before the write would leave a stale cache entry if the remote call fails. + return hpx::async(typename tile_holder::set_data_action{}, target_tile.id, data) + .then( + [this, self = this->get_id(), gid = target_tile.id.get_gid(), generation, data]( + hpx::future &&f) mutable + { + f.get(); // rethrow any remote exception + cache_.insert(gid, generation, data); + self = {}; // release our reference + }); + } + + private: + tile_manager_shared_data data_; + tile_cache cache_; +}; + +} // namespace server + +// DECLARATION macros (use in a single header) + +#define GPRAT_REGISTER_TILE_HOLDER_DECLARATION_IMPL(type, name) \ + HPX_REGISTER_ACTION_DECLARATION(type::get_data_action, HPX_PP_CAT(_tile_holder_get_data_action_, name)) \ + HPX_REGISTER_ACTION_DECLARATION(type::set_data_action, HPX_PP_CAT(_tile_holder_set_data_action_, name)) \ + /**/ + +#define GPRAT_REGISTER_TILED_DATASET_DECLARATION(type, name) \ + typedef ::GPRAT_NS::server::tile_holder HPX_PP_CAT(_server_tile_holder_, HPX_PP_CAT(type, name)); \ + GPRAT_REGISTER_TILE_HOLDER_DECLARATION_IMPL(HPX_PP_CAT(_server_tile_holder_, HPX_PP_CAT(type, name)), name) + +// REGISTRATION macros (use in a single .cpp file) + +#define GPRAT_REGISTER_TILE_HOLDER_IMPL(type, name) \ + HPX_REGISTER_ACTION(type::get_data_action, HPX_PP_CAT(_tile_holder_get_data_action_, name)) \ + HPX_REGISTER_ACTION(type::set_data_action, HPX_PP_CAT(_tile_holder_set_data_action_, name)) \ + typedef ::hpx::components::component HPX_PP_CAT(_server_tile_holder_component_, name); \ + HPX_REGISTER_COMPONENT(HPX_PP_CAT(_server_tile_holder_component_, name)) \ + /**/ + +#define GPRAT_REGISTER_TILE_MANAGER_IMPL(type, name) \ + typedef ::hpx::components::component HPX_PP_CAT(_server_tile_manager_component_, name); \ + HPX_REGISTER_COMPONENT(HPX_PP_CAT(_server_tile_manager_component_, name)) \ + /**/ + +#define GPRAT_REGISTER_TILED_DATASET(type, name) \ + typedef ::GPRAT_NS::server::tile_holder HPX_PP_CAT(_server_tile_holder_, HPX_PP_CAT(type, name)); \ + GPRAT_REGISTER_TILE_HOLDER_IMPL(HPX_PP_CAT(_server_tile_holder_, HPX_PP_CAT(type, name)), name) \ + typedef ::GPRAT_NS::server::tile_manager HPX_PP_CAT(_server_tile_manager_, HPX_PP_CAT(type, name)); \ + GPRAT_REGISTER_TILE_MANAGER_IMPL(HPX_PP_CAT(_server_tile_manager_, HPX_PP_CAT(type, name)), name) + +template +class tile_handle +{ + public: + tile_handle() = default; + + tile_handle(std::vector managers, std::size_t tile_index, std::size_t generation) : + managers_(std::make_shared>(std::move(managers))), + tile_index_(tile_index), + generation_(generation) + { } + + tile_handle(std::shared_ptr> managers, std::size_t tile_index, std::size_t generation) : + managers_(std::move(managers)), + tile_index_(tile_index), + generation_(generation) + { } + + // ReSharper disable once CppNonExplicitConversionOperator + operator mutable_tile_data() const { return get(); } // NOLINT(*-explicit-constructor) + + mutable_tile_data get() const { return local_manager()->get_tile_data(tile_index_, generation_); } + + hpx::future> get_async() const + { + return local_manager()->get_tile_data_async(tile_index_, generation_); + } + + // Returns a new tile_handle with the incremented generation once the write completes. + // Callers MUST use the returned handle for subsequent reads; the original handle's + // generation_ is not updated. + [[nodiscard]] hpx::future set_async(const mutable_tile_data &data) const + { + return local_manager() + ->set_tile_data_async(tile_index_, generation_ + 1, data) + .then( + [self = *this](hpx::future &&) mutable + { + ++self.generation_; + return self; + }); + } + + private: + friend class hpx::serialization::access; + + template + void serialize(Archive &ar, unsigned) + { + // Serialize the vector contents, not the shared_ptr itself. + // cached_manager_ is a runtime cache and is not serialized. + ar &*managers_ &tile_index_ & generation_; + } + + std::shared_ptr> local_manager() const + { + if (cached_manager_) + { + return cached_manager_; + } + const auto here = hpx::get_locality_id(); + for (const auto &id : *managers_) + { + if (here == hpx::naming::get_locality_id_from_id(id)) + { + cached_manager_ = hpx::get_ptr>(hpx::launch::sync, id); + return cached_manager_; + } + } + throw std::runtime_error("This locality is not known"); + } + + std::shared_ptr> managers_ = std::make_shared>(); + std::size_t tile_index_ = 0; + std::size_t generation_ = 0; + mutable std::shared_ptr> cached_manager_; +}; + +template +class tiled_dataset +{ + public: + using value_type = hpx::shared_future>; + + tiled_dataset() = default; + + explicit tiled_dataset(std::size_t size) : + data_(std::make_unique(size)), + size_(size) + { } + + [[nodiscard]] std::size_t size() const noexcept { return size_; } + + const value_type *data() const noexcept { return data_.get(); } + + const value_type *begin() const noexcept { return data_.get(); } + + const value_type *end() const noexcept { return data_.get() + size_; } + + value_type &operator[](std::size_t i) + { + if (i >= size_) + { + throw std::out_of_range("tiled_dataset::operator[]"); + } + return data_[i]; + } + + const value_type &operator[](std::size_t i) const + { + if (i >= size_) + { + throw std::out_of_range("tiled_dataset::operator[]"); + } + return data_[i]; + } + + private: + std::unique_ptr data_; + std::size_t size_ = 0; +}; + +template +tiled_dataset +create_tiled_dataset(std::span> targets, std::size_t num_tiles) +{ + // First, create the actual tile data holders + std::vector>> holders; + holders.reserve(targets.size()); + for (const auto &target : targets) + { +#if (HPX_VERSION_FULL >= 0x011100) + holders.emplace_back( + hpx::components::bulk_create_async>(target.first, target.second)); +#else + holders.emplace_back(hpx::components::bulk_create_async>(target.first, target.second)); +#endif + } + + // Next, we prepare our shared data for the manager components + server::tile_manager_shared_data manager_data; + manager_data.tiles.reserve(num_tiles); + + for (std::size_t i = 0; i < targets.size() && manager_data.tiles.size() < num_tiles; ++i) + { + const auto locality = hpx::naming::get_locality_id_from_id(targets[i].first); + for (hpx::id_type &id : holders[i].get()) + { + manager_data.tiles.emplace_back(std::move(id), locality); + if (manager_data.tiles.size() == num_tiles) + { + break; + } + } + } + + if (manager_data.tiles.size() != num_tiles) + { + throw std::runtime_error( + "create_tiled_dataset: targets provided fewer slots (" + std::to_string(manager_data.tiles.size()) + + ") than num_tiles (" + std::to_string(num_tiles) + ")"); + } + + // Now we move on to the manager components + std::vector managers; + managers.reserve(targets.size()); + for (const auto &target : targets) + { + managers.emplace_back(hpx::components::create>(target.first, manager_data)); + } + + // Finally, we create our fat tile_handles — all sharing one managers vector. + auto shared_managers = std::make_shared>(std::move(managers)); + tiled_dataset tiles(num_tiles); + for (std::size_t i = 0; i < num_tiles; ++i) + { + tiles[i] = hpx::make_ready_future(tile_handle{ shared_managers, i, 0 }); + } + return tiles; +} + +template +tiled_dataset make_tiled_dataset(const tiled_scheduler_distributed &sched, std::size_t num_tiles, Mapper &&mapper) +{ + const auto num_localities = sched.localities_.size(); + std::vector> targets; + targets.reserve(num_localities); + + for (std::size_t i = 0; i < num_localities; ++i) + { + targets.emplace_back(sched.localities_[i], 0); + } + + for (std::size_t i = 0; i < num_tiles; i++) + { + ++targets[mapper(i) % num_localities].second; + } + + return create_tiled_dataset(targets, num_tiles); +} + +GPRAT_NS_END + +// Register the double version by default +// Users can register custom types in the same way +GPRAT_REGISTER_TILED_DATASET_DECLARATION(double, double) + +#endif diff --git a/core/include/utils_c.hpp b/core/include/gprat/utils.hpp similarity index 57% rename from core/include/utils_c.hpp rename to core/include/gprat/utils.hpp index 591bb7ee..704859e9 100644 --- a/core/include/utils_c.hpp +++ b/core/include/gprat/utils.hpp @@ -1,5 +1,9 @@ -#ifndef UTILS_C_H -#define UTILS_C_H +#ifndef GPRAT_UTILS_HPP +#define GPRAT_UTILS_HPP + +#pragma once + +#include "gprat/detail/config.hpp" #include #include @@ -7,8 +11,8 @@ #include #include -namespace utils -{ +GPRAT_NS_BEGIN + /** * @brief Compute the number of tiles for training data, given the number of * samples and the size of each tile. @@ -16,16 +20,16 @@ namespace utils * @param n_samples Number of samples * @param n_tile_size Size of each tile */ -int compute_train_tiles(int n_samples, int n_tile_size); +std::size_t compute_train_tiles(std::size_t n_samples, std::size_t n_tile_size); /** * @brief Compute the number of tiles for training data, given the number of * samples and the size of each tile. * * @param n_samples Number of samples - * @param n_tile_size Size of each tile + * @param n_tiles Size of each tile */ -int compute_train_tile_size(int n_samples, int n_tiles); +std::size_t compute_train_tile_size(std::size_t n_samples, std::size_t n_tiles); /** * @brief Compute the number of test tiles and the size of a test tile. @@ -37,7 +41,18 @@ int compute_train_tile_size(int n_samples, int n_tiles); * @param n_tiles Number of tiles * @param n_tile_size Size of each tile */ -std::pair compute_test_tiles(int n_test, int n_tiles, int n_tile_size); +std::pair +compute_test_tiles(std::size_t n_test, std::size_t n_tiles, std::size_t n_tile_size); + +/** + * @brief Computes a good-enough guess for the number of tiles per dimension. + * + * This guess is based on experiments ran on a single dual-socket 64 core machine. + * It might not be appropriate for distributed scenarios. + * + * @param n Number of samples + */ +std::size_t guess_good_tile_count_per_dimension(std::size_t n); /** * @brief Load data from file @@ -45,7 +60,7 @@ std::pair compute_test_tiles(int n_test, int n_tiles, int n_tile_size) * @param file_path Path to the file * @param n_samples Number of samples to load */ -std::vector load_data(const std::string &file_path, int n_samples, int offset); +std::vector load_data(const std::string &file_path, std::size_t n_samples, std::size_t offset); /** * @brief Print a vector @@ -85,6 +100,19 @@ void stop_hpx_runtime(); */ bool compiled_with_cuda(); -} // namespace utils +/** + * @brief Returns whether the code was compiled with SYCL support. + */ +bool compiled_with_sycl(); + +/** + * @brief Returns whether the SYCL GPU compute backend is functional at runtime. + * + * Returns false if required runtime libraries (e.g. oneMath LAPACK) are + * ABI-incompatible with the current SYCL runtime, even if compiled_with_sycl() is true. + */ +bool sycl_gpu_functional(); + +GPRAT_NS_END #endif diff --git a/core/include/gpu/sycl/adapter_onemath.hpp b/core/include/gpu/sycl/adapter_onemath.hpp new file mode 100644 index 00000000..b3d9a306 --- /dev/null +++ b/core/include/gpu/sycl/adapter_onemath.hpp @@ -0,0 +1,256 @@ +#ifndef ADAPTER_ONEMATH_H +#define ADAPTER_ONEMATH_H + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// GRPat +#include "gprat/target.hpp" + +#include "sycl_utils.hpp" + +// SYCL +#include + +// oneMath +#include + +// BLAS LEVEL 3 OPERATIONS //////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief In-place Cholesky decomposition of f_A + * + * @param queue SYCL queue + * @param f_A matrix to be factorized + * @param N matrix dimension + * + * @return factorized, lower triangular matrix f_L, in-place update of f_A + */ +double *potrf(sycl::queue queue, double *f_A, const std::size_t N); + +/** + * @brief In-place solve A(^T) * X = B or X * A(^T) = B for lower triangular A + * + * @param queue SYCL queue + * @param f_A lower triangular matrix + * @param f_B right hand side matrix + * @param M number of rows + * @param N number of columns + * @param is_A_transposed whether to transpose A + * @param is_right whether to use A on the left or right side + * + * @return solution matrix f_X, in-place update of f_B + */ +double *trsm(sycl::queue queue, + double *f_A, + double *f_B, + const std::size_t M, + const std::size_t N, + const oneapi::math::transpose is_transposed, + const oneapi::math::side is_right); + +/** + * @brief Symmetric rank-k update: C = C - A * A^T + * + * @param queue SYCL queue + * @param f_A matrix + * @param f_C Symmetric matrix + * @param N matrix dimension + * + * @return updated matrix f_A, in-place update + */ +double *syrk(sycl::queue queue, double *f_A, double *f_C, const std::size_t N); + +/** + * @brief General matrix-matrix multiplication: C = C - A(^T) * B(^T) + * + * @param queue SYCL queue + * @param f_A Left update matrix + * @param f_B Right update matrix + * @param f_C Base matrix + * @param M Number of rows of matrix A + * @param N Number of columns of matrix B + * @param K Number of columns of matrix A / rows of matrix B + * @param is_A_transposed whether to transpose left matrix A + * @param is_B_transposed whether to transpose right matrix B + * + * @return updated matrix f_C, in-place update + */ +double *gemm(sycl::queue queue, + double *f_A, + double *f_B, + double *f_C, + const std::size_t M, + const std::size_t N, + const std::size_t K, + const oneapi::math::transpose is_A_transposed, + const oneapi::math::transpose is_B_transposed); + +// BLAS LEVEL 2 OPERATIONS //////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief In-place solve A(^T) * x = b where A lower triangular + * + * @param queue SYCL queue + * @param f_A lower triangular matrix + * @param f_a right hand side vector + * @param N matrix dimension + * @param is_A_transposed whether to transpose A + * + * @return solution vector f_x, in-place update of b + */ +double * +trsv(sycl::queue queue, double *f_A, double *f_b, const std::size_t N, const oneapi::math::transpose is_A_transposed); + +/** + * @brief General matrix-vector multiplication: y = y - A(^T) * x + * + * @param queue SYCL queue + * @param f_A update matrix + * @param f_x update vector + * @param f_y base vector + * @param N matrix dimension + * @param alpha add or substract update to base vector + * @param is_A_transposed transpose update matrix + * + * @return updated vector f_y, in-place update + */ +double *gemv(sycl::queue queue, + double *f_A, + double *f_x, + double *f_y, + const std::size_t M, + const std::size_t N, + const double alpha, + const oneapi::math::transpose is_A_transposed); + +/** + * @brief General matrix rank-1 update: A = A - x*y^T + * + * @param queue SYCL queue + * @param f_A base matrix + * @param f_x first update vector + * @param f_y second update vector + * @param N matrix dimension + * + * @return vector f_b, in-place update + */ +double *ger(sycl::queue queue, double *f_A, double *f_x, double *f_y, const std::size_t N); + +/** + * @brief Vector update with diagonal SYRK: r = r + diag(A^T * A) + * + * @param queue SYCL queue + * @param f_A update matrix + * @param f_r base vector + * @param M number of rows of A + * @param N number of columns of A + * + * @return vector f_r, in-place update + */ +double *dot_diag_syrk(sycl::queue queue, double *f_A, double *f_r, const std::size_t M, const std::size_t N); + +/** + * @brief Kernel class for vector update with diagonal SYRK + */ +class DotDiagSyrkKernel +{ + private: + double *d_A; + double *d_r; + std::size_t M; + std::size_t N; + + public: + /** + * @brief Constructor for DotDiagSyrkKernel for vector update with diagonal SYRK + * + * @param A update matrix + * @param r base vector + * @param M number of rows of A + * @param N number of columns of A + */ + explicit DotDiagSyrkKernel(double *A, double *r, const std::size_t M, const std::size_t N); + + /** + * @brief The operator() of DotDiagSyrkKernel implements the actual kernel + * + * @param id global SYCL id of the kernel + */ + void operator()(const sycl::id<1> &id) const; +}; + +/** + * @brief Vector update with diagonal GEMM: r = r + diag(A * B) + * + * @param queue SYCL queue + * @param f_A first update matrix, of size NxN + * @param f_B second update matrix, of size NxM + * @param f_r base vector + * @param M first matrix dimension + * @param N second matrix dimension + * + * @return updated vector f_r, in-place update + */ +double * +dot_diag_gemm(sycl::queue queue, double *f_A, double *f_B, double *f_r, const std::size_t M, const std::size_t N); + +/** + * @brief Kernel class for vector update with diagonal GEMM + */ +class DotDiagGemmKernel +{ + private: + double *A; + double *B; + double *r; + std::size_t M; + std::size_t N; + + public: + /** + * @brief Constructor for DotDiagGemmKernel for vector update with diagonal GEMM + * + * @param A first update matrix, of size NxN + * @param B second update matrix, of size NxM + * @param r base vector + * @param M first matrix dimension + * @param N second matrix dimension + */ + explicit DotDiagGemmKernel(double *A, double *B, double *r, const std::size_t M, const std::size_t N); + + /** + * @brief The operator() of DotDiagGemmKernel implements the actual kernel + * + * @param id global SYCL id of the kernel + */ + void operator()(const sycl::id<1> &id) const; +}; + +// BLAS LEVEL 1 OPERATIONS //////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Dot product: a * b + * + * @param queue SYCL queue + * @param f_a left vector + * @param f_b right vector + * @param N vector length + * @return f_a * f_b + */ +double *dot(sycl::queue queue, double *f_a, double *f_b, const std::size_t N); + +// HELPER FUNCTIONS /////////////////////////////////////////////////////////////////////////////////////////////////// + +inline oneapi::math::transpose invert_transpose_operator(oneapi::math::transpose op) +{ + return (op == oneapi::math::transpose::nontrans) + ? oneapi::math::transpose::trans + : oneapi::math::transpose::nontrans; +} + +inline oneapi::math::side invert_side_operator(oneapi::math::side op) +{ + return (op == oneapi::math::side::left) ? oneapi::math::side::right : oneapi::math::side::left; +} + +#endif // end of ADAPTER_ONEMATH_H diff --git a/core/include/gpu/sycl/sycl_gp_algorithms.hpp b/core/include/gpu/sycl/sycl_gp_algorithms.hpp new file mode 100644 index 00000000..5dfc4bd1 --- /dev/null +++ b/core/include/gpu/sycl/sycl_gp_algorithms.hpp @@ -0,0 +1,330 @@ +#ifndef SYCL_GP_ALGORITHMS_H +#define SYCL_GP_ALGORITHMS_H + +// GPRat +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" + +// HPX +#include + +// STD library +#include + +namespace gprat::sycl_backend +{ + +/** + * @brief Generate a tile of the covariance matrix + * + * @param d_input The input data vector + * @param tile_row The row index of the tile in the tiled matrix + * @param tile_column The column index of the tile in the tiled matrix + * @param n_tile_size The dimension of the quadratic tile (N*N elements) + * @param n_regressors The number of regressors + * @param sek_params The kernel hyperparameters + * @param sycl_device SYCL target for computations + * + * @return A quadratic tile of the covariance matrix of size N x N + * @note Does apply noise variance on the diagonal + */ +double *gen_tile_covariance(const double *d_input, + const std::size_t tile_row, + const std::size_t tile_column, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Generate the diagonal of a diagonal tile in the prior covariance matrix + * + * @param d_input The input data vector + * @param tile_row The row index of the tile in the tiled matrix + * @param tile_column The column index of the tile in the tiled matrix + * @param n_tile_size The dimension of the quadratic tile (N*N elements) + * @param n_regressors The number of regressors + * @param sek_params The kernel hyperparameters + * @param sycl_device SYCL target for computations + * + * @return The diagonal of size N of a tile of the prior covariance matrix of size N x N + * @note Does NOT apply noise variance + */ +double *gen_tile_prior_covariance( + const double *d_input, + const std::size_t tile_row, + const std::size_t tile_column, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Generate a tile of the cross-covariance matrix + * + * @param d_row_input input data for row, allocated on device + * @param d_col_input input data for column, allocated on device + * @param tile_row The row index of the tile in the tiled matrix + * @param tile_column The column index of the tile in the tiled matrix + * @param n_row_tile_size The row-wise dimension of the tile + * @param n_column_tile_size The column-wise dimension of the tile + * @param n_regressors The number of regressors + * @param sek_params The kernel hyperparameters + * @param sycl_device SYCL target for computations + * @return A tile of the cross covariance matrix of size N_row x N_col + * @note Does NOT apply noise variance + */ +double *gen_tile_cross_covariance( + const double *d_row_input, + const double *d_col_input, + const std::size_t tile_row, + const std::size_t tile_column, + const std::size_t n_row_tile_size, + const std::size_t n_column_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Transpose a tile of size n_row_tile_size x n_column_tile_size + * + * @param n_row_tile_size The row-wise dimension of the tile + * @param n_column_tile_size The column-wise dimension of the tile + * @param f_tile The tile to transpose + * @param sycl_device SYCL target for computations + * + * @return The transposed tile of size n_row_tile_size x n_column_tile_size + */ +hpx::shared_future gen_tile_transpose(std::size_t n_row_tile_size, + std::size_t n_column_tile_size, + const hpx::shared_future f_tile, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Generate a tile of the output data + * + * @param row The row index of the tile in relation to the tiled matrix + * @param n_tile_size The size of the tile + * @param d_output The output data vector + * @param sycl_device SYCL target for computations + * @return A tile of the output data of size n_tile_size + */ +double *gen_tile_output( + const std::size_t row, const std::size_t n_tile_size, const double *d_output, gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Compute the L2-error norm over all tiles and elements + * + * @param n_tiles The number of tiles per dimension + * @param n_tile_size The number of elements per tile + * @param b The ground truth + * @param tiles The tiled matrix + */ +double compute_error_norm(const std::size_t n_tiles, + const std::size_t n_tile_size, + const std::vector &b, + const std::vector> &tiles); + +/** + * @brief Generate a tile initialized with zero + * + * @param n_tile_size The size of the tile + * @param sycl_device SYCL target for computations + * + * @return A tile filled with zeros of size N + */ +double *gen_tile_zeros(std::size_t n_tile_size, gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the tiled covariance matrix on the device given the training + * data. + * + * @param d_training_input The training input data + * @param n_tiles The number of tiles per dimension + * @param n_tile_size The size of the tile + * @param n_regressors The number of regressors + * @param sek_params The kernel hyperparameters + * @param sycl_device SYCL target for computations + */ +std::vector> assemble_tiled_covariance_matrix( + const double *d_training_input, + const std::size_t n_tiles, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the tiled alpha vector on the device given the training + * output. + * + * @param d_output The training output data + * @param n_tiles The number of tiles per dimension + * @param n_tile_size The size of the tile + * @param sycl_device SYCL target for computations + * + * @return A tiled alpha vector of size n_tiles x n_tile_size + */ +std::vector> assemble_alpha_tiles( + const double *d_output, const std::size_t n_tiles, const std::size_t n_tile_size, gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the tiled cross covariance matrix on the device given the + * training and test data. + * + * @param d_test_input The test input data + * @param d_training_input The training input data + * @param m_tiles The number of tiles per dimension for the test data + * @param n_tiles The number of tiles per dimension for the training data + * @param m_tile_size The size of the tile for the test data + * @param n_tile_size The size of the tile for the training data + * @param n_regressors The number of regressors + * @param sek_params The kernel hyperparameters + * @param sycl_device SYCL target for computations + * + * @return A tiled cross covariance matrix with m_tiles x n_tiles tiles + */ +std::vector> assemble_cross_covariance_tiles( + const double *d_test_input, + const double *d_training_input, + const std::size_t m_tiles, + const std::size_t n_tiles, + const std::size_t m_tile_size, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates a tiled vector on the device and initializes it with zeros. + * + * @param n_tile_size The size of the tile + * @param n_tiles The number of tiles per dimensionl + * @param sycl_device SYCL target for computations + * + * @return A tiled vector of size n_tiles x n_tile_size with zeros + */ +std::vector> +assemble_tiles_with_zeros(std::size_t n_tile_size, std::size_t n_tiles, gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the tiled prior covariance matrix on the device given the + * test input data. + * + * @param d_test_input The test input data + * @param m_tiles The number of tiles per dimension for the test data + * @param m_tile_size The size of the tile for the test data + * @param n_regressors The number of regressors + * @param sek_params The kernel hyperparameters + * @param sycl_device SYCL target for computations + * + * @return A tiled prior covariance matrix with m_tiles x m_tiles tiles + */ +std::vector> assemble_prior_K_tiles( + const double *d_test_input, + const std::size_t m_tiles, + const std::size_t m_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the posterior covariance matrix. + * + * @param d_test_input The test input data + * @param m_tiles The number of tiles per dimension for the test data + * @param m_tile_size The size of the tile for the test data + * @param n_regressors The number of regressors + * @param sek_params The kernel hyperparameters + * @param sycl_device SYCL target for computations + * + * @return A tiled posterior covariance matrix with m_tiles x m_tiles tiles + */ +std::vector> assemble_prior_K_tiles_full( + const double *d_test_input, + const std::size_t m_tiles, + const std::size_t m_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the tiled transpose cross covariance matrix on the device + * given the cross covariance matrix. + * + * Allocates device memory and copies the tranposed cross covariance matrix to + * it. + * + * @param d_cross_covariance_tiles The cross covariance matrix + * @param n_tiles The number of tiles per dimension for the training data + * @param m_tiles The number of tiles per dimension for the test data + * @param n_tile_size The size of the tile for the training data + * @param m_tile_size The size of the tile for the test data + * @param sycl_device SYCL target for computations + */ +std::vector> assemble_t_cross_covariance_tiles( + const std::vector> &d_cross_covariance_tiles, + const std::size_t n_tiles, + const std::size_t m_tiles, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the output vector on the device given the training output + * + * @param d_training_input The training input data + * @param n_tiles The number of tiles per dimension + * @param n_tile_size The size of the tile + * @param sycl_device SYCL target for computations + */ +std::vector> +assemble_y_tiles(const double *d_training_output, + const std::size_t n_tiles, + const std::size_t n_tile_size, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Allocates the tiled covariance matrix on the device given the training + * data. + * + * @param d_tiles The training input data + * @param n_tile_size The size of the tile + * @param n_tiles The number of tiles per dimension + * @param sycl_device SYCL target for computations + */ +std::vector copy_tiled_vector_to_host_vector(std::vector> &d_tiles, + std::size_t n_tile_size, + std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Moves lower triangular tiles of the covariance matrix to the host. + * + * Allocates host memory for the tiles on the host and free the device memory. + * + * @param d_tiles The tiles on the device + * @param n_tile_size The size of the tile + * @param n_tiles The number of tiles + * @param sycl_device SYCL target for computations + */ +std::vector> move_lower_tiled_matrix_to_host( + const std::vector> &d_tiles, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Frees the device memory of the lower triangular tiles of the covariance matrix. + * + * @param d_tiles The tiles on the device + * @param n_tiles The number of tiles + * @param sycl_device SYCL target for computations + */ +void free_lower_tiled_matrix(const std::vector> &d_tiles, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +} // end of namespace gprat::sycl_backend + +#endif // end of SYCL_GP_ALGORITHMS_H diff --git a/core/include/cpu/gp_functions.hpp b/core/include/gpu/sycl/sycl_gp_functions.hpp similarity index 53% rename from core/include/cpu/gp_functions.hpp rename to core/include/gpu/sycl/sycl_gp_functions.hpp index 7079bab6..ca20c5c8 100644 --- a/core/include/cpu/gp_functions.hpp +++ b/core/include/gpu/sycl/sycl_gp_functions.hpp @@ -1,44 +1,26 @@ -#ifndef CPU_GP_FUNCTIONS_H -#define CPU_GP_FUNCTIONS_H +#ifndef SYCL_GP_FUNCTIONS_H +#define SYCL_GP_FUNCTIONS_H -#include "gp_hyperparameters.hpp" -#include "gp_kernels.hpp" -#include +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" -namespace cpu +namespace gprat::sycl_backend { -/** - * @brief Perform Cholesky decompositon (+Assebmly) - * - * @param training_input The training input data - * @param hyperparameters The kernel hyperparameters - * - * @param n_tiles The number of training tiles - * @param n_tile_size The size of each training tile - * @param n_regressors The number of regressors - * - * @return The tiled Cholesky factor - */ -std::vector> -cholesky(const std::vector &training_input, - const gprat_hyper::SEKParams &sek_params, - int n_tiles, - int n_tile_size, - int n_regressors); - /** * @brief Compute the predictions without uncertainties. * * @param training_input The training input data * @param training_output The raining output data * @param test_input The test input data - * @param hyperparameters The kernel hyperparameters + * @param sek_params The kernel hyperparameters * @param n_tiles The number of training tiles * @param n_tile_size The size of each training tile * @param m_tiles The number of test tiles * @param m_tile_size The size of each test tile * @param n_regressors The number of regressors + * @param sycl_device SYCL target for computations * * @return A vector containing the predictions */ @@ -46,12 +28,13 @@ std::vector predict(const std::vector &training_input, const std::vector &training_output, const std::vector &test_input, - const gprat_hyper::SEKParams &sek_params, + const gprat::SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, - int n_regressors); + int n_regressors, + gprat::SYCL_DEVICE &sycl_device); /** * @brief Compute the predictions with uncertainties. @@ -59,12 +42,13 @@ predict(const std::vector &training_input, * @param training_input The training input data * @param training_output The raining output data * @param test_input The test input data - * @param hyperparameters The kernel hyperparameters + * @param sek_params The kernel hyperparameters * @param n_tiles The number of training tiles * @param n_tile_size The size of each training tile * @param m_tiles The number of test tiles * @param m_tile_size The size of each test tile * @param n_regressors The number of regressors + * @param sycl_device SYCL target for computations * * @return A vector containing the prediction vector and the uncertainty vector */ @@ -72,25 +56,27 @@ std::vector> predict_with_uncertainty( const std::vector &training_input, const std::vector &training_output, const std::vector &test_input, - const gprat_hyper::SEKParams &sek_params, + const gprat::SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, - int n_regressors); + int n_regressors, + gprat::SYCL_DEVICE &sycl_device); /** * @brief Compute the predictions with full covariance matrix. * * @param training_input The training input data * @param training_output The raining output data - * @param test_input The test input data - * @param hyperparameters The kernel hyperparameters + * @param test_data The test input data + * @param sek_params The kernel hyperparameters * @param n_tiles The number of training tiles * @param n_tile_size The size of each training tile * @param m_tiles The number of test tiles * @param m_tile_size The size of each test tile * @param n_regressors The number of regressors + * @param sycl_device SYCL target for computations * * @return A vector containing the prediction vector and the full posterior covariance matrix */ @@ -98,86 +84,55 @@ std::vector> predict_with_full_cov( const std::vector &training_input, const std::vector &training_output, const std::vector &test_data, - const gprat_hyper::SEKParams &sek_params, + const gprat::SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, - int n_regressors); + int n_regressors, + gprat::SYCL_DEVICE &sycl_device); /** * @brief Compute loss for given data and Gaussian process model * * @param training_input The training input data * @param training_output The raining output data - * @param hyperparameters The kernel hyperparameters + * @param sek_params The kernel hyperparameters * @param n_tiles The number of training tiles * @param n_tile_size The size of each training tile * @param n_regressors The number of regressors + * @param sycl_device SYCL target for computations * * @return The loss */ double compute_loss(const std::vector &training_input, const std::vector &training_output, - const gprat_hyper::SEKParams &sek_params, + const gprat::SEKParams &sek_params, int n_tiles, int n_tile_size, - int n_regressors); + int n_regressors, + gprat::SYCL_DEVICE &sycl_device); /** - * @brief Perform optimization for a given number of iterations + * @brief Perform Cholesky decompositon (+ Assembly) * * @param training_input The training input data - * @param training_output The raining output data - * + * @param sek_params The kernel hyperparameters * @param n_tiles The number of training tiles * @param n_tile_size The size of each training tile * @param n_regressors The number of regressors + * @param sycl_device SYCL target for computations * - * @param hyperparams The Adam optimizer hyperparameters - * @param hyperparameters The kernel hyperparameters - * @param trainable_params The vector containing a bool wheather to train a hyperparameter - * - * @return A vector containing the loss values of each iteration + * @return The tiled Cholesky factor */ -std::vector -optimize(const std::vector &training_input, - const std::vector &training_output, +std::vector> +cholesky(const std::vector &training_input, + const gprat::SEKParams &sek_params, int n_tiles, int n_tile_size, int n_regressors, - const gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, - std::vector trainable_params); - -/** - * @brief Perform a single optimization step - * - * @param training_input The training input data - * @param training_output The raining output data - * - * @param n_tiles The number of training tiles - * @param n_tile_size The size of each training tile - * @param n_regressors The number of regressors - * - * @param hyperparams The Adam optimizer hyperparameters - * @param hyperparameters The kernel hyperparameters - * @param trainable_params The vector containing a bool wheather to train a hyperparameter - * - * @param iter The current optimization iteration - * - * @return The loss value - */ -double optimize_step(const std::vector &training_input, - const std::vector &training_output, - int n_tiles, - int n_tile_size, - int n_regressors, - gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, - std::vector trainable_params, - int iter); + gprat::SYCL_DEVICE &sycl_device); -} // end of namespace cpu +} // namespace gprat::sycl_backend -#endif // end of CPU_GP_FUNCTIONS_H +#endif // ! SYCL_GP_FUNCTIONS_H diff --git a/core/include/gpu/sycl/sycl_gp_optimizer.hpp b/core/include/gpu/sycl/sycl_gp_optimizer.hpp new file mode 100644 index 00000000..fa78a722 --- /dev/null +++ b/core/include/gpu/sycl/sycl_gp_optimizer.hpp @@ -0,0 +1,71 @@ +#ifndef SYCL_GP_OPTIMIZER_H +#define SYCL_GP_OPTIMIZER_H + +// GPRat +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" + +// HPX +#include + +// STD library +#include + +namespace gprat::sycl_backend +{ + +/** + * @brief Generate a derivative tile w.r.t. lengthscale. + * + * @param N The dimension of the quadratic tile (N*N elements) + * @param grad_l_tile The gradient of the left side + * + * @return A quadratic tile of the derivative of l of size N x N + */ +std::vector gen_tile_grad_v_trans(std::size_t N, const std::vector &grad_l_tile); + +/** + * @brief Generate a derivative tile w.r.t. lengthscale. + * + * @param N The dimension of the quadratic tile (N*N elements) + * @param f_grad_l_tile The gradient of the left side + * @param sycl_device The SYCL target for computations + * + * @return A quadratic tile of the derivative of l of size N x N + */ +hpx::shared_future +gen_tile_grad_l_trans(std::size_t N, const hpx::shared_future f_grad_l_tile, gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Compute negative-log likelihood on one tile. + * + * @param K_diag_tile The Cholesky factor L (in a diagonal tile) + * @param alpha_tile The tiled solution of K * alpha = y + * @param y_tile The output tile + * @param N The dimension of the quadratic tile (N*N elements) + * @param sycl_device The SYCL target for computations + * + * @return Return l = y^T * alpha + \sum_i^N log(L_ii^2) + */ +double compute_loss(const hpx::shared_future &K_diag_tile, + const hpx::shared_future &alpha_tile, + const hpx::shared_future &y_tile, + std::size_t N, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Add up negative-log likelihood loss for all tiles. + * + * @param losses A vector contianing the loss per tile + * @param n_tile_size The size of a tile + * @param n_tiles The number of tiles + * + * @return The added up loss plus the constant factor + */ +hpx::shared_future +add_losses(const std::vector> &losses, std::size_t n_tile_size, std::size_t n_tiles); + +} // namespace gprat::sycl_backend + +#endif // end of SYCL_GP_OPTIMIZER_H diff --git a/core/include/gpu/sycl/sycl_gp_uncertainty.hpp b/core/include/gpu/sycl/sycl_gp_uncertainty.hpp new file mode 100644 index 00000000..f1d6d528 --- /dev/null +++ b/core/include/gpu/sycl/sycl_gp_uncertainty.hpp @@ -0,0 +1,32 @@ +#ifndef SYCL_GP_UNCERTAINTY_H +#define SYCL_GP_UNCERTAINTY_H + +#include + +namespace gprat::sycl_backend +{ + +/** + * @brief Retrieve diagonal elements of posterior covariance matrix. + * + * @param A Diagonal elements matrix A + * @param B Diagonal elements matrix B + * @param M Number of rows in the matrix + * + * @return Diagonal elements of posterior covariance matrix + */ +double *diag_posterior(double *A, double *B, std::size_t M); + +/** + * @brief Retrieve diagonal elements of posterior covariance matrix. + * + * @param A Posterior covariance matrix + * @param M Number of rows in the matrix + * + * @return Diagonal elements of posterior covariance matrix + */ +double *diag_tile(double *A, std::size_t M); + +} // end of namespace gprat::sycl_backend + +#endif // end of SYCL_GP_UNCERTAINTY_H diff --git a/core/include/gpu/sycl/sycl_kernels.hpp b/core/include/gpu/sycl/sycl_kernels.hpp new file mode 100644 index 00000000..bb3eb36c --- /dev/null +++ b/core/include/gpu/sycl/sycl_kernels.hpp @@ -0,0 +1,399 @@ +#ifndef GPRAT_SYCL_KERNELS_H +#define GPRAT_SYCL_KERNELS_H + +// Includes /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// GPRat +#include "gprat/kernels.hpp" + +#include "sycl_utils.hpp" + +// Transpose kernel /////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Kernel to transpose a matrix. + */ +class TransposeKernel +{ + private: + double *transposed; + double *original; + std::size_t width; + std::size_t height; + sycl::local_accessor local; + + public: + /** + * @brief Construct a TransposeKernel object + * + * @param transposed Pointer to the transposed output matrix. + * @param original Pointer to the original input matrix. + * @param width Width of the original matrix. + * @param height Height of the original matrix. + * @param cgh SYCL command group handler for local memory + */ + explicit TransposeKernel( + double *transposed, double *original, std::size_t width, std::size_t height, sycl::handler &cgh) : + transposed(transposed), + original(original), + width(width), + height(height), + local(sycl::local_accessor(sycl::range<2>(WORK_GROUP_SIZE, WORK_GROUP_SIZE + 1), cgh)) + { } + + /** + * @brief The operator() implements the actual kernel functionality. + * + * @param nd_item The SYCL nd_item representing the current thread. + */ + void operator()(const sycl::nd_item<2> &nd_item) const + { + const std::size_t local_x = nd_item.get_local_id(1); + const std::size_t local_y = nd_item.get_local_id(0); + + const std::size_t group_x = nd_item.get_group(1); + const std::size_t group_y = nd_item.get_group(0); + + std::size_t xIndex = group_x * WORK_GROUP_SIZE + local_x; + std::size_t yIndex = group_y * WORK_GROUP_SIZE + local_y; + + // Load tile into local memory + if (xIndex < width && yIndex < height) + { + local[local_y][local_x] = original[yIndex * width + xIndex]; + } + else + { + local[local_y][local_x] = 0.0; // padding + } + + nd_item.barrier(sycl::access::fence_space::local_space); + + // Compute swapped indices for transpose write-back + std::size_t x_index_out = group_y * WORK_GROUP_SIZE + local_x; + std::size_t y_index_out = group_x * WORK_GROUP_SIZE + local_y; + + if (x_index_out < height && y_index_out < width) + { + transposed[y_index_out * height + x_index_out] = local[local_x][local_y]; + } + } +}; + +// GenTileCovarianceKernel //////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Class for the kernel function to compute covariance + */ +class GenTileCovarianceKernel +{ + private: + double *d_tile; + const double *d_input; + std::size_t n_tile_size; + std::size_t n_regressors; + std::size_t tile_row; + std::size_t tile_column; + double lengthscale_; + double vertical_lengthscale_; + double noise_variance_; + + public: + /** + * @brief Constructor of the kernel to generate a tile of the covariance matrix + */ + explicit GenTileCovarianceKernel( + double *d_tile, + const double *d_input_input, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const std::size_t tile_row, + const std::size_t tile_column, + const gprat::SEKParams sek_params) : + d_tile(d_tile), + d_input(d_input_input), + n_tile_size(n_tile_size), + n_regressors(n_regressors), + tile_row(tile_row), + tile_column(tile_column), + lengthscale_(sek_params.lengthscale), + vertical_lengthscale_(sek_params.vertical_lengthscale), + noise_variance_(sek_params.noise_variance) + { } + + /** + * @brief The operator() implements the actual kernel functionality. + * + * @param item The SYCL item representing the current thread. + */ + void operator()(const sycl::item<2> &item) const + { + const std::size_t i = item.get_id(0); + const std::size_t j = item.get_id(1); + + const std::size_t i_global = n_tile_size * tile_row + i; + const std::size_t j_global = n_tile_size * tile_column + j; + + double distance = 0.0; + double z_ik_minus_z_jk = 0.0; + + for (std::size_t k = 0; k < n_regressors; ++k) + { + z_ik_minus_z_jk = d_input[i_global + k] - d_input[j_global + k]; + distance += z_ik_minus_z_jk * z_ik_minus_z_jk; + } + + double covariance = vertical_lengthscale_ * sycl::exp(-0.5 * distance / (lengthscale_ * lengthscale_)); + + if (i_global == j_global) + { + covariance += noise_variance_; + } + + d_tile[i * n_tile_size + j] = covariance; + } +}; + +// GenTileFullPriorCovarianceKernel /////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Class for the kernel to generate a tile of the prior covariance matrix + * + */ +class GenTileFullPriorCovarianceKernel +{ + private: + double *d_tile; + const double *d_input; + std::size_t n_tile_size; + std::size_t n_regressors; + std::size_t tile_row; + std::size_t tile_column; + double lengthscale_; + double vertical_lengthscale_; + + public: + /** + * @brief Constructor of the kernel to generate a tile of the prior covariance matrix + */ + explicit GenTileFullPriorCovarianceKernel( + double *d_tile, + const double *d_input_input, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const std::size_t tile_row, + const std::size_t tile_column, + const gprat::SEKParams sek_params) : + d_tile(d_tile), + d_input(d_input_input), + n_tile_size(n_tile_size), + n_regressors(n_regressors), + tile_row(tile_row), + tile_column(tile_column), + lengthscale_(sek_params.lengthscale), + vertical_lengthscale_(sek_params.vertical_lengthscale) + { } + + /** + * @brief The operator() implements the actual kernel functionality. + * + * @param item The SYCL item representing the current thread. + */ + void operator()(const sycl::item<2> &item) const + { + const std::size_t i = item.get_id(0); + const std::size_t j = item.get_id(1); + + const std::size_t i_global = n_tile_size * tile_row + i; + const std::size_t j_global = n_tile_size * tile_column + j; + + double distance = 0.0; + double z_ik_minus_z_jk = 0.0; + + for (std::size_t k = 0; k < n_regressors; ++k) + { + z_ik_minus_z_jk = d_input[i_global + k] - d_input[j_global + k]; + distance += z_ik_minus_z_jk * z_ik_minus_z_jk; + } + + const double covariance = vertical_lengthscale_ * sycl::exp(-0.5 * distance / (lengthscale_ * lengthscale_)); + + d_tile[i * n_tile_size + j] = covariance; + } +}; + +// GenTilePriorCovarianceKernel /////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Class for the kernel to generate the diagonal of a diagonal tile in the prior covariance matrix + * + */ +class GenTilePriorCovarianceKernel +{ + private: + double *d_tile; + const double *d_input; + std::size_t n_tile_size; + std::size_t n_regressors; + std::size_t tile_row; + std::size_t tile_column; + double lengthscale_; + double vertical_lengthscale_; + + public: + /** + * @brief Constructor of the kernel to generate the diagonal of a diagonal tile in the prior covariance matrix + */ + explicit GenTilePriorCovarianceKernel( + double *d_tile, + const double *d_input_input, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const std::size_t tile_row, + const std::size_t tile_column, + const gprat::SEKParams sek_params) : + d_tile(d_tile), + d_input(d_input_input), + n_tile_size(n_tile_size), + n_regressors(n_regressors), + tile_row(tile_row), + tile_column(tile_column), + lengthscale_(sek_params.lengthscale), + vertical_lengthscale_(sek_params.vertical_lengthscale) + { } + + /** + * @brief The operator() implements the actual kernel functionality. + * + * @param id The SYCL id representing the current thread. + */ + void operator()(const sycl::id<1> &id) const + { + std::size_t i_global = n_tile_size * tile_row + id; + std::size_t j_global = n_tile_size * tile_column + id; + + double distance = 0.0; + double z_ik_minus_z_jk = 0.0; + + for (std::size_t k = 0; k < n_regressors; ++k) + { + z_ik_minus_z_jk = d_input[i_global + k] - d_input[j_global + k]; + distance += z_ik_minus_z_jk * z_ik_minus_z_jk; + } + + double covariance = vertical_lengthscale_ * exp(-0.5 * distance / (lengthscale_ * lengthscale_)); + + d_tile[id] = covariance; + } +}; + +// GenTileCrossCovarianceKernel /////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Class for the kernel to generate a tile of the cross-covariance matrix + */ +class GenTileCrossCovarianceKernel +{ + private: + double *d_tile; + const double *d_row_input; + const double *d_col_input; + std::size_t n_row_tile_size; + std::size_t n_column_tile_size; + std::size_t tile_row; + std::size_t tile_column; + std::size_t n_regressors; + double lengthscale_; + double vertical_lengthscale_; + + public: + /** + * @brief Constructor of the kernel to generate a tile of the cross-covariance matrix + */ + explicit GenTileCrossCovarianceKernel( + double *d_tile, + const double *d_row_input, + const double *d_col_input, + const std::size_t n_row_tile_size, + const std::size_t n_column_tile_size, + const std::size_t tile_row, + const std::size_t tile_column, + const std::size_t n_regressors, + const gprat::SEKParams sek_params) : + d_tile(d_tile), + d_row_input(d_row_input), + d_col_input(d_col_input), + n_row_tile_size(n_row_tile_size), + n_column_tile_size(n_column_tile_size), + tile_row(tile_row), + tile_column(tile_column), + n_regressors(n_regressors), + lengthscale_(sek_params.lengthscale), + vertical_lengthscale_(sek_params.vertical_lengthscale) + { } + + /** + * @brief The operator() implements the actual kernel functionality. + * + * @param item The SYCL item representing the current thread. + */ + void operator()(const sycl::item<2> &item) const + { + const std::size_t i = item.get_id(0); + const std::size_t j = item.get_id(1); + + const std::size_t i_global = n_row_tile_size * tile_row + i; + const std::size_t j_global = n_column_tile_size * tile_column + j; + + double distance = 0.0; + double z_ik_minus_z_jk = 0.0; + + for (std::size_t k = 0; k < n_regressors; ++k) + { + z_ik_minus_z_jk = d_row_input[i_global + k] - d_col_input[j_global + k]; + distance += z_ik_minus_z_jk * z_ik_minus_z_jk; + } + + const double covariance = vertical_lengthscale_ * sycl::exp(-0.5 * distance / (lengthscale_ * lengthscale_)); + + d_tile[i * n_column_tile_size + j] = covariance; + } +}; + +// GenTileOutputKernel //////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Class for the kernel to generate a tile of the output data + */ +class GenTileOutputKernel +{ + private: + double *tile; + const double *output; + std::size_t row; + std::size_t n_tile_size; + + public: + /** + * @brief Constructor of the kernel to generate a tile of the output data + */ + explicit GenTileOutputKernel(double *tile, const double *output, std::size_t row, std::size_t n_tile_size) : + tile(tile), + output(output), + row(row), + n_tile_size(n_tile_size) + { } + + /** + * @brief The operator() implements the actual kernel functionality. + * + * @param id The SYCL id representing the current thread. + */ + void operator()(const sycl::id<1> &id) const + { + std::size_t i_global = n_tile_size * row + id; + tile[id] = output[i_global]; + } +}; + +#endif // end of GPRAT_SYCL_KERNELS_H diff --git a/core/include/gpu/sycl/sycl_tiled_algorithms.hpp b/core/include/gpu/sycl/sycl_tiled_algorithms.hpp new file mode 100644 index 00000000..9aa53126 --- /dev/null +++ b/core/include/gpu/sycl/sycl_tiled_algorithms.hpp @@ -0,0 +1,313 @@ +#ifndef SYCL_TILED_ALGORITHMS_H +#define SYCL_TILED_ALGORITHMS_H + +// GPRat +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" + +// HPX +#include + +namespace gprat::sycl_backend +{ + +// Tiled Cholesky Algorithm + +/** + * @brief Perform right-looking Cholesky decomposition. + * + * @param ft_tiles Matrix represented as a vector of tiles, containing the + * covariance matrix, afterwards the Cholesky decomposition. + * @param n_tile_size Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @param sycl_device The SYCL target for computations + */ +void right_looking_cholesky_tiled(std::vector> &ft_tiles, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +// Tiled Triangular Solve Algorithms + +/** + * @brief Perform tiled forward triangular matrix-vector solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side vector, afterwards containing the tiled solution vector + * @param n_tile_size Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @param sycl_device The SYCL target for computations + */ +void forward_solve_tiled(std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Perform tiled backward triangular matrix-vector solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side vector, afterwards containing the tiled solution vector + * @param n_tile_size Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @param sycl_device The SYCL target for computations + */ +void backward_solve_tiled(std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Perform tiled forward triangular matrix-matrix solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side matrix, afterwards containing the tiled solution matrix. + * @param n_tile_size Tile size of first dimension. + * @param m_tile_size Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + * @param sycl_device The SYCL target for computations + */ +void forward_solve_tiled_matrix( + std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Perform tiled backward triangular matrix-matrix solve. + * + * @param ft_tiles Tiled triangular matrix represented as a vector of futurized tiles. + * @param ft_rhs Tiled right-hand side matrix, afterwards containing the tiled solution matrix. + * @param n_tile_size Tile size of first dimension. + * @param m_tile_size Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + * @param sycl_device The SYCL target for computations + */ +void backward_solve_tiled_matrix( + std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Perform tiled matrix-vector multiplication + * + * @param ft_tiles Tiled matrix represented as a vector of futurized tiles. + * @param ft_vector Tiled vector represented as a vector of futurized tiles. + * @param ft_rhs Tiled solution represented as a vector of futurized tiles. + * @param N_row Tile size of first dimension. + * @param N_col Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + * @param sycl_device The SYCL target for computations + */ +void matrix_vector_tiled(std::vector> &ft_tiles, + std::vector> &ft_vector, + std::vector> &ft_rhs, + const std::size_t N_row, + const std::size_t N_col, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Perform tiled symmetric k-rank update on diagonal tiles + * + * @param ft_tCC_tiles Tiled matrix represented as a vector of futurized tiles. + * @param ft_inter_tiles Tiled vector holding the diagonal tile results + * @param n_tile_size Tile size of first dimension. + * @param m_tile_size Tile size of second dimension. + * @param n_tiles Number of tiles in first dimension. + * @param m_tiles Number of tiles in second dimension. + * @param sycl_device The SYCL target for computations + */ +void symmetric_matrix_matrix_diagonal_tiled( + std::vector> &ft_tCC_tiles, + std::vector> &ft_inter_tiles, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Compute the tiled matrix-vector product alpha = invK * y + * + * @param ft_invK Futures holding the tiles of the inverse kernel matrix + * invK + * @param ft_y Futures holding the tiles of the input vector y + * @param ft_alpha Futures holding the tiles of the output vector alpha + * @param n_tile_size The number of elements per tile dimension + * @param n_tiles The number of tiles per matrix dimension + * @param sycl_device The SYCL device used to launch GEMV operations + */ +void compute_gemm_of_invK_y(std::vector> &ft_invK, + std::vector> &ft_y, + std::vector> &ft_alpha, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +// Tiled Loss +hpx::shared_future compute_loss_tiled( + std::vector> &ft_tiles, + std::vector> &ft_alpha, + std::vector> &ft_y, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +// Tiled Diagonal of Posterior Covariance Matrix +void symmetric_matrix_matrix_tiled( + std::vector> &ft_tCC_tiles, + std::vector> &ft_priorK, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Compute the difference between two tiled vectors + * + * @param ft_priorK Tiled vector that is being subtracted from. + * @param ft_inter Tiled vector that is being subtracted. + * @param ft_vector Tiled vector that is the result of the subtraction. + * @param m_tile_size Tile size dimension. + * @param m_tiles Number of tiles. + */ +void vector_difference_tiled(std::vector> &ft_priorK, + std::vector> &ft_inter, + std::vector> &ft_vector, + const std::size_t m_tile_size, + const std::size_t m_tiles); + +// Tiled Prediction Uncertainty +void matrix_diagonal_tiled(std::vector> &ft_priorK, + std::vector> &ft_vector, + const std::size_t m_tile_size, + const std::size_t m_tiles); + +// Compute I-y*y^T*inv(K) +void update_grad_K_tiled_mkl(std::vector> &ft_tiles, + const std::vector> &ft_v1, + const std::vector> &ft_v2, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Updates the lengthscale hyperparameter of the SEK kernel using Adam. + * + * @param ft_invK Tiled inverse of the covariance matrix K represented as a vector of futurized tiles. + * @param ft_gradparam Tiled gradient of the hyperparameter represented as a vector of futurized tiles. + * @param ft_alpha Tiled vector containing the precomputed inv(K) * y where y is the training output. + * @param sek_params Hyperparameters of the SEK kernel + * @param adam_params Hyperparameter of the Adam optimizer + * @param n_tile_size Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @param m_T Tiled vector containing the first moment of the Adam optimizer. + * @param v_T Tiled vector containing the second moment of the Adam optimizer. + * @param beta1_T Tiled vector containing the first moment of the Adam optimizer. + * @param beta2_T Tiled vector containing the second moment of the Adam optimizer. + * @param iter Current iteration. + * @param sycl_device The SYCL target for computations + * + * @return The updated hyperparameter + */ +double update_lengthscale( + const std::vector> &ft_invK, + const std::vector> &ft_gradparam, + const std::vector> &ft_alpha, + gprat::SEKParams sek_params, + gprat::AdamParams adam_params, + const std::size_t n_tile_size, + const std::size_t n_tiles, + std::vector> &m_T, + std::vector> &v_T, + const std::vector> &beta1_T, + const std::vector> &beta2_T, + int iter, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Updates the vertical lengthscale hyperparameter of the SEK kernel + * using Adam. + * + * @param ft_invK Tiled inverse of the covariance matrix K represented as a vector of futurized tiles. + * @param ft_gradparam Tiled gradient of the hyperparameter represented as a vector of futurized tiles. + * @param ft_alpha Tiled vector containing the precomputed inv(K) * y where y is the training output. + * @param sek_params Hyperparameters of the SEK kernel + * @param adam_params Hyperparameter of the Adam optimizer + * @param n_tile_size Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @param m_T Tiled vector containing the first moment of the Adam optimizer. + * @param v_T Tiled vector containing the second moment of the Adam optimizer. + * @param beta1_T Tiled vector containing the first moment of the Adam optimizer. + * @param beta2_T Tiled vector containing the second moment of the Adam optimizer. + * @param iter Current iteration. + * @param sycl_device The SYCL target for computations + * + * @return The updated hyperparameter + */ +double update_vertical_lengthscale( + const std::vector> &ft_invK, + const std::vector> &ft_gradparam, + const std::vector> &ft_alpha, + gprat::SEKParams sek_params, + gprat::AdamParams adam_params, + const std::size_t n_tile_size, + const std::size_t n_tiles, + std::vector> &m_T, + std::vector> &v_T, + const std::vector> &beta1_T, + const std::vector> &beta2_T, + int iter, + gprat::SYCL_DEVICE &sycl_device); + +/** + * @brief Updates a hyperparameter of the SEK kernel using Adam + * + * @param ft_invK Tiled inverse of the covariance matrix K represented as a vector of futurized tiles. + * @param ft_alpha Tiled vector containing the precomputed inv(K) * y where y is the training output. + * @param sek_params Hyperparameters of the SEK kernel + * @param adam_params Hyperparameter of the Adam optimizer + * @param n_tile_size Tile size per dimension. + * @param n_tiles Number of tiles per dimension. + * @param m_T Tiled vector containing the first moment of the Adam optimizer. + * @param v_T Tiled vector containing the second moment of the Adam optimizer. + * @param beta1_T Tiled vector containing the first moment of the Adam optimizer. + * @param beta2_T Tiled vector containing the second moment of the Adam optimizer. + * @param iter Current iteration. + * @param sycl_device The SYCL target for computations + * + @return The updated hyperparameter + */ +double update_noise_variance( + const std::vector> &ft_invK, + const std::vector> &ft_alpha, + gprat::SEKParams sek_params, + gprat::AdamParams adam_params, + const std::size_t n_tile_size, + const std::size_t n_tiles, + std::vector> &m_T, + std::vector> &v_T, + const std::vector> &beta1_T, + const std::vector> &beta2_T, + int iter, + gprat::SYCL_DEVICE &sycl_device); + +} // namespace gprat::sycl_backend + +#endif // end of SYCL_TILED_ALGORITHMS_H diff --git a/core/include/gpu/sycl/sycl_utils.hpp b/core/include/gpu/sycl/sycl_utils.hpp new file mode 100644 index 00000000..5f89aada --- /dev/null +++ b/core/include/gpu/sycl/sycl_utils.hpp @@ -0,0 +1,70 @@ +#ifndef SYCL_UTILS_HPP +#define SYCL_UTILS_HPP + +#define WORK_GROUP_SIZE 16 + +// GPRat +#include "gprat/target.hpp" + +// HPX +#include + +// SYCL +#include + +namespace gprat::sycl_backend +{ + +/** + * @brief Copies a vector from the host to the device using the next SYCL queue of sycl_device. + * + * Allocates device memory for the vector and synchronizes the stream after + * copying the data. + * + * @param h_vector The vector to copy from the host + * @param sycl_device The SYCL target + * + * @return A pointer to the copied vector on the device + */ +inline double *copy_to_device(const std::vector &h_vector, gprat::SYCL_DEVICE &sycl_device) +{ + double *d_vector; + sycl::queue queue = sycl_device.next_queue(); + + try + { + d_vector = sycl::malloc_device(h_vector.size(), queue); + auto copy_process = queue.memcpy(d_vector, h_vector.data(), h_vector.size() * sizeof(double)); + copy_process.wait(); + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + } + return d_vector; +} + +/** + * @brief Frees the device memory allocated in a vector of shared futures. + * + * @param vector The vector of shared futures to free + * @param queue The SYCL queue to use for freeing the memory + */ +inline void free(std::vector> &vector, const sycl::queue &queue) +{ + try + { + for (auto &ptr : vector) + { + sycl::free(ptr.get(), queue); + } + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + } +} + +} // end of namespace gprat::sycl_backend + +#endif // end of SYCL_UTILS_HPP diff --git a/core/include/target.hpp b/core/include/target.hpp deleted file mode 100644 index 8b66cb0b..00000000 --- a/core/include/target.hpp +++ /dev/null @@ -1,208 +0,0 @@ -#ifndef TARGET_H -#define TARGET_H - -#include - -#if GPRAT_WITH_CUDA -#include -#include -#endif - -namespace gprat -{ - -/** - * @brief This class represents the target on which to perform the Gaussian - * Process computations: either CPU or GPU. - * - * The respective subclasses implement specific targets: CPU, CUDA_GPU. - * They may also set additional attributes or function that are required when - * using this target. - */ -struct Target -{ - /** - * @brief Returns true if target is CPU. - * - * Implemented by subclasses. - */ - virtual bool is_cpu() = 0; - - /** - * @brief Returns true if target is GPU. - * - * Implemented by subclasses. - */ - virtual bool is_gpu() = 0; - - /** - * @brief Returns string representation of the target. - * - * Implemented by subclasses. - */ - virtual std::string repr() const = 0; - - virtual ~Target() { } - - protected: - Target() = default; -}; - -struct CPU : public Target -{ - public: - /** - * @brief Returns CPU target. - */ - CPU(); - - /** - * @brief Returns true because target is CPU. - */ - bool is_cpu() override; - - /** - * @brief Returns false because CPU target is not GPU. - */ - bool is_gpu() override; - - /** - * @brief Returns string representation of the CPU target. - */ - std::string repr() const override; -}; - -/** - * @brief Creates and returns handle for CPU target. - * - * @return CPU target - */ -CPU get_cpu(); - -#if GPRAT_WITH_CUDA -struct CUDA_GPU : public Target -{ - /** - * @brief Identifier of GPU device. - * - * Can be set to a value between 0 and gpu_count(). - */ - int id; - - /** - * @brief Number of CUDA streams used asynchronous computation and data - * transfer. - */ - int n_streams; - - /** - * @brief Index of next CUDA stream assigned on next_stream() or - * next_cublas_handle(). - */ - int i_stream; - - /** @brief Default amount of CUDA shared memory used by CUDA kernels. */ - int shared_memory_size; - - /** - * @brief Returns GPU target that uses CUDA. - */ - CUDA_GPU(int id, int n_streams); - - /** - * @brief Returns false because target is not CPU. - */ - bool is_cpu() override; - - /** - * @brief Returns true because target is GPU. - */ - bool is_gpu() override; - - /** - * @brief Returns string representation of the GPU target. - */ - std::string repr() const override; - - /** - * @brief Creates n_streams CUDA streams and cublas handles. - * - * WARNING: Call destroy() to free both resources after using them. - */ - void create(); - - /** - * @brief Destroys the CUDA streams and cublas handles previously created - * with create(). - */ - void destroy(); - - /** - * @brief Returns the next CUDA streams. - * - * It regards the collection of CUDA streams as a cyclic list and returns - * the next CUDA stream in the cycle. The returned stream was already - * created when calling create() and will be destroyed by using destroy(). - * - * @return CUDA stream - */ - cudaStream_t next_stream(); - - /** - * @brief Synchronizes the collection of CUDA streams. - * - * The streams must have be retrieved by next_stream(). Thus, it can use the - * cyclic ordering to sync each stream in subset_of_streams only once. - * - * @param subset_of_streams Vector of CUDA streams, previously retrieved - * with next_stream(). - */ - void sync_streams(std::vector &subset_of_streams); - - /** - * @brief Returns the next cuBLAS handle. - * - * It regards the collection of cuBLAS handles as a cyclic list and returns - * the next handle in the cycle. The returned handle was already - * created when calling create() and will be destroyed by using destroy(). - * - * @return cuBLAS handle - */ - std::pair next_cublas_handle(); - - private: - std::vector streams; - std::vector cublas_handles; -}; - -/** - * @brief Creates and returns handle for GPU target. - * - * @param id ID of GPU. - * @param n_streams Number of streams to be created on GPU. - * - * @return GPU target - */ -CUDA_GPU get_gpu(int id, int n_streams); - -/** - * @brief Returns handle for GPU target with ID 0. - * - * Uses only one stream, so single-threaded GPU execution. - */ -CUDA_GPU get_gpu(); -#endif - -/** - * @brief Lists available GPUs with their properties. - */ -void print_available_gpus(); - -/** - * @brief Returns number of available GPUs. - */ -int gpu_count(); - -} // namespace gprat - -#endif // end of TARGET_H diff --git a/core/src/cpu/adapter_cblas_fp32.cpp b/core/src/cpu/adapter_cblas_fp32.cpp index 54e09bd5..357ce8fc 100644 --- a/core/src/cpu/adapter_cblas_fp32.cpp +++ b/core/src/cpu/adapter_cblas_fp32.cpp @@ -1,194 +1,118 @@ -#include "cpu/adapter_cblas_fp32.hpp" - -#ifdef GPRAT_ENABLE_MKL -// MKL CBLAS and LAPACKE -#include "mkl_cblas.h" -#include "mkl_lapacke.h" -#else -#include "cblas.h" -#include "lapacke.h" +#include "gprat/cpu/adapter_cblas_fp32.hpp" + +#include "adapter_cblas_impl.hpp" + +#ifdef HPX_HAVE_MODULE_PERFORMANCE_COUNTERS +#include #endif -// BLAS level 3 operations +GPRAT_NS_BEGIN + +mutable_tile_data potrf(const mutable_tile_data &A, const int N) { return detail::potrf_impl(A, N); } -vector potrf(vector_future f_A, const int N) +mutable_tile_data +trsm(const const_tile_data &L, + const mutable_tile_data &A, + const int N, + const int M, + const BLAS_TRANSPOSE transpose_L, + const BLAS_SIDE side_L) { - vector A = f_A.get(); - // POTRF: in-place Cholesky decomposition of A - // use spotrf2 recursive version for better stability - LAPACKE_spotrf2(LAPACK_ROW_MAJOR, 'L', N, A.data(), N); - // return factorized matrix L - return A; + return detail::trsm_impl(L, A, N, M, transpose_L, side_L); } -vector trsm(vector_future f_L, - vector_future f_A, - const int N, - const int M, - const BLAS_TRANSPOSE transpose_L, - const BLAS_SIDE side_L) - +mutable_tile_data syrk(const mutable_tile_data &A, const const_tile_data &B, const int N) { - const vector &L = f_L.get(); - vector A = f_A.get(); - // TRSM constants - const float alpha = 1.0; - // TRSM: in-place solve L(^T) * X = A or X * L(^T) = A where L lower triangular - cblas_strsm( - CblasRowMajor, - static_cast(side_L), - CblasLower, - static_cast(transpose_L), - CblasNonUnit, - N, - M, - alpha, - L.data(), - N, - A.data(), - M); - // return vector - return A; + return detail::syrk_impl(A, B, N); } -vector syrk(vector_future f_A, vector_future f_B, const int N) +mutable_tile_data +gemm(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &C, + const int N, + const int M, + const int K, + const BLAS_TRANSPOSE transpose_A, + const BLAS_TRANSPOSE transpose_B) { - const vector &B = f_B.get(); - vector A = f_A.get(); - // SYRK constants - const float alpha = -1.0; - const float beta = 1.0; - // SYRK:A = A - B * B^T - cblas_ssyrk(CblasRowMajor, CblasLower, CblasNoTrans, N, N, alpha, B.data(), N, beta, A.data(), N); - // return updated matrix A - return A; + return detail::gemm_impl(A, B, C, N, M, K, transpose_A, transpose_B); } -vector gemm(vector_future f_A, - vector_future f_B, - vector_future f_C, - const int N, - const int M, - const int K, - const BLAS_TRANSPOSE transpose_A, - const BLAS_TRANSPOSE transpose_B) +mutable_tile_data +trsv(const const_tile_data &L, const mutable_tile_data &a, const int N, const BLAS_TRANSPOSE transpose_L) { - vector C = f_C.get(); - const vector &B = f_B.get(); - const vector &A = f_A.get(); - // GEMM constants - const float alpha = -1.0; - const float beta = 1.0; - // GEMM: C = C - A(^T) * B(^T) - cblas_sgemm( - CblasRowMajor, - static_cast(transpose_A), - static_cast(transpose_B), - K, - M, - N, - alpha, - A.data(), - K, - B.data(), - M, - beta, - C.data(), - M); - // return updated matrix C - return C; + return detail::trsv_impl(L, a, N, transpose_L); } -// BLAS level 2 operations - -vector trsv(vector_future f_L, vector_future f_a, const int N, const BLAS_TRANSPOSE transpose_L) +mutable_tile_data +gemv(const const_tile_data &A, + const const_tile_data &a, + const mutable_tile_data &b, + const int N, + const int M, + const BLAS_ALPHA alpha, + const BLAS_TRANSPOSE transpose_A) { - const vector &L = f_L.get(); - vector a = f_a.get(); - // TRSV: In-place solve L(^T) * x = a where L lower triangular - cblas_strsv(CblasRowMajor, - CblasLower, - static_cast(transpose_L), - CblasNonUnit, - N, - L.data(), - N, - a.data(), - 1); - // return solution vector x - return a; + return detail::gemv_impl(A, a, b, N, M, alpha, transpose_A); } -vector gemv(vector_future f_A, - vector_future f_a, - vector_future f_b, - const int N, - const int M, - const BLAS_ALPHA alpha, - const BLAS_TRANSPOSE transpose_A) +mutable_tile_data +dot_diag_syrk(const const_tile_data &A, const mutable_tile_data &r, const int N, const int M) { - const vector &A = f_A.get(); - const vector &a = f_a.get(); - vector b = f_b.get(); - // GEMV constants - // const float alpha = -1.0; - const float beta = 1.0; - // GEMV: b{N} = b{N} - A(^T){NxM} * a{M} - cblas_sgemv( - CblasRowMajor, - static_cast(transpose_A), - N, - M, - alpha, - A.data(), - M, - a.data(), - 1, - beta, - b.data(), - 1); - // return updated vector b - return b; + return detail::dot_diag_syrk_impl(A, r, N, M); } -vector dot_diag_syrk(vector_future f_A, vector_future f_r, const int N, const int M) +mutable_tile_data +dot_diag_gemm(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &r, + const int N, + const int M) { - const vector &A = f_A.get(); - vector r = f_r.get(); - // r = r + diag(A^T * A) - for (std::size_t j = 0; j < static_cast(M); ++j) - { - // Extract the j-th column and compute the dot product with itself - r[j] += cblas_sdot(N, &A[j], M, &A[j], M); - } - return r; + return detail::dot_diag_gemm_impl(A, B, r, N, M); } -vector dot_diag_gemm(vector_future f_A, vector_future f_B, vector_future f_r, const int N, const int M) +mutable_tile_data axpy(const mutable_tile_data &y, const const_tile_data &x, const int N) { - const vector &A = f_A.get(); - const vector &B = f_B.get(); - vector r = f_r.get(); - // r = r + diag(A * B) - for (std::size_t i = 0; i < static_cast(N); ++i) - { - r[i] += cblas_sdot(M, &A[i * static_cast(M)], 1, &B[i], N); - } - return r; + return detail::axpy_impl(y, x, N); } -// BLAS level 1 operations +float dot(std::span a, std::span b, const int N) { return detail::dot_impl(a, b, N); } -vector axpy(vector_future f_y, vector_future f_x, const int N) +#ifdef HPX_HAVE_MODULE_PERFORMANCE_COUNTERS +namespace detail { - vector y = f_y.get(); - const vector &x = f_x.get(); - cblas_saxpy(N, -1.0, x.data(), 1, y.data(), 1); - return y; -} - -float dot(vector a, vector b, const int N) +void register_fp32_performance_counters() { - // DOT: a * b - return cblas_sdot(N, a.data(), 1, b.data(), 1); +#define GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(name, fn_expr) \ + hpx::performance_counters::install_counter_type( \ + name "/time", \ + get_and_reset_function_elapsed, \ + #fn_expr, \ + "", \ + hpx::performance_counters::counter_type::monotonically_increasing); \ + hpx::performance_counters::install_counter_type( \ + name "/calls", \ + get_and_reset_function_calls, \ + #fn_expr, \ + "", \ + hpx::performance_counters::counter_type::monotonically_increasing) + + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/potrf32", &potrf); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/trsm32", &trsm); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/syrk32", &syrk); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/gemm32", &gemm); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/trsv32", &trsv); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/gemv32", &gemv); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/dot_diag_syrk32", &dot_diag_syrk); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/dot_diag_gemm32", &dot_diag_gemm); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/axpy32", &axpy); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/dot32", &dot); + +#undef GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR } +} // namespace detail +#endif + +GPRAT_NS_END diff --git a/core/src/cpu/adapter_cblas_fp64.cpp b/core/src/cpu/adapter_cblas_fp64.cpp index dac3a515..d96f28d4 100644 --- a/core/src/cpu/adapter_cblas_fp64.cpp +++ b/core/src/cpu/adapter_cblas_fp64.cpp @@ -1,194 +1,118 @@ -#include "cpu/adapter_cblas_fp64.hpp" - -#ifdef GPRAT_ENABLE_MKL -// MKL CBLAS and LAPACKE -#include "mkl_cblas.h" -#include "mkl_lapacke.h" -#else -#include "cblas.h" -#include "lapacke.h" +#include "gprat/cpu/adapter_cblas_fp64.hpp" + +#include "adapter_cblas_impl.hpp" + +#ifdef HPX_HAVE_MODULE_PERFORMANCE_COUNTERS +#include #endif -// BLAS level 3 operations +GPRAT_NS_BEGIN + +mutable_tile_data potrf(const mutable_tile_data &A, const int N) { return detail::potrf_impl(A, N); } -vector potrf(vector_future f_A, const int N) +mutable_tile_data +trsm(const const_tile_data &L, + const mutable_tile_data &A, + const int N, + const int M, + const BLAS_TRANSPOSE transpose_L, + const BLAS_SIDE side_L) { - vector A = f_A.get(); - // POTRF: in-place Cholesky decomposition of A - // use dpotrf2 recursive version for better stability - LAPACKE_dpotrf2(LAPACK_ROW_MAJOR, 'L', N, A.data(), N); - // return factorized matrix L - return A; + return detail::trsm_impl(L, A, N, M, transpose_L, side_L); } -vector trsm(vector_future f_L, - vector_future f_A, - const int N, - const int M, - const BLAS_TRANSPOSE transpose_L, - const BLAS_SIDE side_L) - +mutable_tile_data syrk(const mutable_tile_data &A, const const_tile_data &B, const int N) { - const vector &L = f_L.get(); - vector A = f_A.get(); - // TRSM constants - const double alpha = 1.0; - // TRSM: in-place solve L(^T) * X = A or X * L(^T) = A where L lower triangular - cblas_dtrsm( - CblasRowMajor, - static_cast(side_L), - CblasLower, - static_cast(transpose_L), - CblasNonUnit, - N, - M, - alpha, - L.data(), - N, - A.data(), - M); - // return vector - return A; + return detail::syrk_impl(A, B, N); } -vector syrk(vector_future f_A, vector_future f_B, const int N) +mutable_tile_data +gemm(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &C, + const int N, + const int M, + const int K, + const BLAS_TRANSPOSE transpose_A, + const BLAS_TRANSPOSE transpose_B) { - const vector &B = f_B.get(); - vector A = f_A.get(); - // SYRK constants - const double alpha = -1.0; - const double beta = 1.0; - // SYRK:A = A - B * B^T - cblas_dsyrk(CblasRowMajor, CblasLower, CblasNoTrans, N, N, alpha, B.data(), N, beta, A.data(), N); - // return updated matrix A - return A; + return detail::gemm_impl(A, B, C, N, M, K, transpose_A, transpose_B); } -vector gemm(vector_future f_A, - vector_future f_B, - vector_future f_C, - const int N, - const int M, - const int K, - const BLAS_TRANSPOSE transpose_A, - const BLAS_TRANSPOSE transpose_B) +mutable_tile_data trsv( + const const_tile_data &L, const mutable_tile_data &a, const int N, const BLAS_TRANSPOSE transpose_L) { - vector C = f_C.get(); - const vector &B = f_B.get(); - const vector &A = f_A.get(); - // GEMM constants - const double alpha = -1.0; - const double beta = 1.0; - // GEMM: C = C - A(^T) * B(^T) - cblas_dgemm( - CblasRowMajor, - static_cast(transpose_A), - static_cast(transpose_B), - K, - M, - N, - alpha, - A.data(), - K, - B.data(), - M, - beta, - C.data(), - M); - // return updated matrix C - return C; + return detail::trsv_impl(L, a, N, transpose_L); } -// BLAS level 2 operations - -vector trsv(vector_future f_L, vector_future f_a, const int N, const BLAS_TRANSPOSE transpose_L) +mutable_tile_data +gemv(const const_tile_data &A, + const const_tile_data &a, + const mutable_tile_data &b, + const int N, + const int M, + const BLAS_ALPHA alpha, + const BLAS_TRANSPOSE transpose_A) { - const vector &L = f_L.get(); - vector a = f_a.get(); - // TRSV: In-place solve L(^T) * x = a where L lower triangular - cblas_dtrsv(CblasRowMajor, - CblasLower, - static_cast(transpose_L), - CblasNonUnit, - N, - L.data(), - N, - a.data(), - 1); - // return solution vector x - return a; + return detail::gemv_impl(A, a, b, N, M, alpha, transpose_A); } -vector gemv(vector_future f_A, - vector_future f_a, - vector_future f_b, - const int N, - const int M, - const BLAS_ALPHA alpha, - const BLAS_TRANSPOSE transpose_A) +mutable_tile_data +dot_diag_syrk(const const_tile_data &A, const mutable_tile_data &r, const int N, const int M) { - const vector &A = f_A.get(); - const vector &a = f_a.get(); - vector b = f_b.get(); - // GEMV constants - // const double alpha = -1.0; - const double beta = 1.0; - // GEMV: b{N} = b{N} - A(^T){NxM} * a{M} - cblas_dgemv( - CblasRowMajor, - static_cast(transpose_A), - N, - M, - alpha, - A.data(), - M, - a.data(), - 1, - beta, - b.data(), - 1); - // return updated vector b - return b; + return detail::dot_diag_syrk_impl(A, r, N, M); } -vector dot_diag_syrk(vector_future f_A, vector_future f_r, const int N, const int M) +mutable_tile_data +dot_diag_gemm(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &r, + const int N, + const int M) { - const vector &A = f_A.get(); - vector r = f_r.get(); - // r = r + diag(A^T * A) - for (std::size_t j = 0; j < static_cast(M); ++j) - { - // Extract the j-th column and compute the dot product with itself - r[j] += cblas_ddot(N, &A[j], M, &A[j], M); - } - return r; + return detail::dot_diag_gemm_impl(A, B, r, N, M); } -vector dot_diag_gemm(vector_future f_A, vector_future f_B, vector_future f_r, const int N, const int M) +mutable_tile_data axpy(const mutable_tile_data &y, const const_tile_data &x, const int N) { - const vector &A = f_A.get(); - const vector &B = f_B.get(); - vector r = f_r.get(); - // r = r + diag(A * B) - for (std::size_t i = 0; i < static_cast(N); ++i) - { - r[i] += cblas_ddot(M, &A[i * static_cast(M)], 1, &B[i], N); - } - return r; + return detail::axpy_impl(y, x, N); } -// BLAS level 1 operations +double dot(std::span a, std::span b, const int N) { return detail::dot_impl(a, b, N); } -vector axpy(vector_future f_y, vector_future f_x, const int N) +#ifdef HPX_HAVE_MODULE_PERFORMANCE_COUNTERS +namespace detail { - vector y = f_y.get(); - const vector &x = f_x.get(); - cblas_daxpy(N, -1.0, x.data(), 1, y.data(), 1); - return y; -} - -double dot(std::vector a, std::vector b, const int N) +void register_fp64_performance_counters() { - // DOT: a * b - return cblas_ddot(N, a.data(), 1, b.data(), 1); +#define GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(name, fn_expr) \ + hpx::performance_counters::install_counter_type( \ + name "/time", \ + get_and_reset_function_elapsed, \ + #fn_expr, \ + "", \ + hpx::performance_counters::counter_type::monotonically_increasing); \ + hpx::performance_counters::install_counter_type( \ + name "/calls", \ + get_and_reset_function_calls, \ + #fn_expr, \ + "", \ + hpx::performance_counters::counter_type::monotonically_increasing) + + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/potrf64", &potrf); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/trsm64", &trsm); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/syrk64", &syrk); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/gemm64", &gemm); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/trsv64", &trsv); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/gemv64", &gemv); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/dot_diag_syrk64", &dot_diag_syrk); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/dot_diag_gemm64", &dot_diag_gemm); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/axpy64", &axpy); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/dot64", &dot); + +#undef GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR } +} // namespace detail +#endif + +GPRAT_NS_END diff --git a/core/src/cpu/adapter_cblas_fp64_actions.cpp b/core/src/cpu/adapter_cblas_fp64_actions.cpp new file mode 100644 index 00000000..173f8f2c --- /dev/null +++ b/core/src/cpu/adapter_cblas_fp64_actions.cpp @@ -0,0 +1,142 @@ +#include "gprat/cpu/adapter_cblas_fp64_actions.hpp" + +#include + +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::potrf, GPRAT_NS::cpu::potrf_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::trsm, GPRAT_NS::cpu::trsm_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::syrk, GPRAT_NS::cpu::syrk_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::gemm, GPRAT_NS::cpu::gemm_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::trsv, GPRAT_NS::cpu::trsv_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::gemv, GPRAT_NS::cpu::gemv_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::dot_diag_syrk, GPRAT_NS::cpu::dot_diag_syrk_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::dot_diag_gemm, GPRAT_NS::cpu::dot_diag_gemm_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::axpy, GPRAT_NS::cpu::axpy_distributed_action) + +GPRAT_NS_BEGIN + +namespace cpu +{ +hpx::future> potrf_distributed(const tile_handle &A, int N) +{ + return hpx::dataflow( + hpx::launch::async, + [A, N](hpx::future> &&tile) { return A.set_async(potrf(tile.get(), N)); }, + A.get_async()); +} + +hpx::future> trsm_distributed( + const tile_handle &L, + const tile_handle &A, + int N, + int M, + BLAS_TRANSPOSE transpose_L, + BLAS_SIDE side_L) +{ + return hpx::dataflow( + hpx::launch::async, + [A, N, M, transpose_L, side_L]( + hpx::future> &&Ld, hpx::future> &&Ad) + { return A.set_async(trsm(Ld.get(), Ad.get(), N, M, transpose_L, side_L)); }, + L.get_async(), + A.get_async()); +} + +hpx::future> syrk_distributed(const tile_handle &A, const tile_handle &B, int N) +{ + return hpx::dataflow( + hpx::launch::async, + [A, N](hpx::future> &&Ad, hpx::future> &&Bd) + { return A.set_async(syrk(Ad.get(), Bd.get(), N)); }, + A.get_async(), + B.get_async()); +} + +hpx::future> gemm_distributed( + const tile_handle &A, + const tile_handle &B, + const tile_handle &C, + int N, + int M, + int K, + BLAS_TRANSPOSE transpose_A, + BLAS_TRANSPOSE transpose_B) +{ + return hpx::dataflow( + hpx::launch::async, + [C, N, M, K, transpose_A, transpose_B](hpx::future> &&Ad, + hpx::future> &&Bd, + hpx::future> &&Cd) + { return C.set_async(gemm(Ad.get(), Bd.get(), Cd.get(), N, M, K, transpose_A, transpose_B)); }, + A.get_async(), + B.get_async(), + C.get_async()); +} + +hpx::future> +trsv_distributed(const tile_handle &L, const tile_handle &a, int N, BLAS_TRANSPOSE transpose_L) +{ + return hpx::dataflow( + hpx::launch::async, + [a, N, transpose_L](hpx::future> &&Ld, hpx::future> &&ad) + { return a.set_async(trsv(Ld.get(), ad.get(), N, transpose_L)); }, + L.get_async(), + a.get_async()); +} + +hpx::future> gemv_distributed( + const tile_handle &A, + const tile_handle &a, + const tile_handle &b, + int N, + int M, + BLAS_ALPHA alpha, + BLAS_TRANSPOSE transpose_A) +{ + return hpx::dataflow( + hpx::launch::async, + [b, N, M, alpha, transpose_A](hpx::future> &&Ad, + hpx::future> &&ad, + hpx::future> &&bd) + { return b.set_async(gemv(Ad.get(), ad.get(), bd.get(), N, M, alpha, transpose_A)); }, + A.get_async(), + a.get_async(), + b.get_async()); +} + +hpx::future> +dot_diag_syrk_distributed(const tile_handle &A, const tile_handle &r, int N, int M) +{ + return hpx::dataflow( + hpx::launch::async, + [r, N, M](hpx::future> &&Ad, hpx::future> &&rd) + { return r.set_async(dot_diag_syrk(Ad.get(), rd.get(), N, M)); }, + A.get_async(), + r.get_async()); +} + +hpx::future> dot_diag_gemm_distributed( + const tile_handle &A, const tile_handle &B, const tile_handle &r, int N, int M) +{ + return hpx::dataflow( + hpx::launch::async, + [r, N, M](hpx::future> &&Ad, + hpx::future> &&Bd, + hpx::future> &&rd) + { return r.set_async(dot_diag_gemm(Ad.get(), Bd.get(), rd.get(), N, M)); }, + A.get_async(), + B.get_async(), + r.get_async()); +} + +hpx::future> axpy_distributed(const tile_handle &y, const tile_handle &x, int N) +{ + return hpx::dataflow( + hpx::launch::async, + [y, N](hpx::future> &&yd, hpx::future> &&xd) + { return y.set_async(axpy(yd.get(), xd.get(), N)); }, + y.get_async(), + x.get_async()); +} +} // namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/adapter_cblas_impl.hpp b/core/src/cpu/adapter_cblas_impl.hpp new file mode 100644 index 00000000..d8e08d04 --- /dev/null +++ b/core/src/cpu/adapter_cblas_impl.hpp @@ -0,0 +1,342 @@ +// Shared templated implementation for fp32 and fp64 CBLAS adapters. +// Included directly by adapter_cblas_fp32.cpp and adapter_cblas_fp64.cpp. +// Not a public header — do not include from elsewhere. + +#pragma once + +#include "gprat/performance_counters.hpp" +#include "gprat/tile_data.hpp" + +#ifdef HPX_HAVE_MODULE_PERFORMANCE_COUNTERS +#include +#endif + +#ifdef GPRAT_ENABLE_MKL +#include "mkl_cblas.h" +#include "mkl_lapacke.h" +#else +#include "cblas.h" +#include "lapacke.h" +#endif + +#include +#include + +GPRAT_NS_BEGIN + +namespace detail +{ + +// BLAS level 3 /////////////////////////////////////////////////////////////// + +template +mutable_tile_data potrf_impl(const mutable_tile_data &A, const int N) +{ + GPRAT_BENCHMARK_FORCE_EVICT(A.as_span()); + GPRAT_TIME_FUNCTION(&potrf); + if constexpr (std::is_same_v) + { + LAPACKE_spotrf2(LAPACK_ROW_MAJOR, 'L', N, A.data(), N); + } + else + { + LAPACKE_dpotrf2(LAPACK_ROW_MAJOR, 'L', N, A.data(), N); + } + return A; +} + +template +mutable_tile_data +trsm_impl(const const_tile_data &L, + const mutable_tile_data &A, + const int N, + const int M, + const BLAS_TRANSPOSE transpose_L, + const BLAS_SIDE side_L) +{ + GPRAT_BENCHMARK_FORCE_EVICT(L.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(A.as_span()); + GPRAT_TIME_FUNCTION(&trsm); + const T alpha = T(1); + if constexpr (std::is_same_v) + { + cblas_strsm( + CblasRowMajor, + static_cast(side_L), + CblasLower, + static_cast(transpose_L), + CblasNonUnit, + N, + M, + alpha, + L.data(), + N, + A.data(), + M); + } + else + { + cblas_dtrsm( + CblasRowMajor, + static_cast(side_L), + CblasLower, + static_cast(transpose_L), + CblasNonUnit, + N, + M, + alpha, + L.data(), + N, + A.data(), + M); + } + return A; +} + +template +mutable_tile_data syrk_impl(const mutable_tile_data &A, const const_tile_data &B, const int N) +{ + GPRAT_BENCHMARK_FORCE_EVICT(A.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(B.as_span()); + GPRAT_TIME_FUNCTION(&syrk); + const T alpha = T(-1); + const T beta = T(1); + if constexpr (std::is_same_v) + { + cblas_ssyrk(CblasRowMajor, CblasLower, CblasNoTrans, N, N, alpha, B.data(), N, beta, A.data(), N); + } + else + { + cblas_dsyrk(CblasRowMajor, CblasLower, CblasNoTrans, N, N, alpha, B.data(), N, beta, A.data(), N); + } + return A; +} + +template +mutable_tile_data +gemm_impl(const const_tile_data &A, + const const_tile_data &B, + const mutable_tile_data &C, + const int N, + const int M, + const int K, + const BLAS_TRANSPOSE transpose_A, + const BLAS_TRANSPOSE transpose_B) +{ + GPRAT_BENCHMARK_FORCE_EVICT(A.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(B.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(C.as_span()); + GPRAT_TIME_FUNCTION(&gemm); + const T alpha = T(-1); + const T beta = T(1); + if constexpr (std::is_same_v) + { + cblas_sgemm( + CblasRowMajor, + static_cast(transpose_A), + static_cast(transpose_B), + K, + M, + N, + alpha, + A.data(), + K, + B.data(), + M, + beta, + C.data(), + M); + } + else + { + cblas_dgemm( + CblasRowMajor, + static_cast(transpose_A), + static_cast(transpose_B), + K, + M, + N, + alpha, + A.data(), + K, + B.data(), + M, + beta, + C.data(), + M); + } + return C; +} + +// BLAS level 2 /////////////////////////////////////////////////////////////// + +template +mutable_tile_data +trsv_impl(const const_tile_data &L, const mutable_tile_data &a, const int N, const BLAS_TRANSPOSE transpose_L) +{ + GPRAT_BENCHMARK_FORCE_EVICT(L.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(a.as_span()); + GPRAT_TIME_FUNCTION(&trsv); + if constexpr (std::is_same_v) + { + cblas_strsv(CblasRowMajor, + CblasLower, + static_cast(transpose_L), + CblasNonUnit, + N, + L.data(), + N, + a.data(), + 1); + } + else + { + cblas_dtrsv(CblasRowMajor, + CblasLower, + static_cast(transpose_L), + CblasNonUnit, + N, + L.data(), + N, + a.data(), + 1); + } + return a; +} + +template +mutable_tile_data +gemv_impl(const const_tile_data &A, + const const_tile_data &a, + const mutable_tile_data &b, + const int N, + const int M, + const BLAS_ALPHA alpha, + const BLAS_TRANSPOSE transpose_A) +{ + GPRAT_BENCHMARK_FORCE_EVICT(A.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(a.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(b.as_span()); + GPRAT_TIME_FUNCTION(&gemv); + const T beta = T(1); + if constexpr (std::is_same_v) + { + cblas_sgemv( + CblasRowMajor, + static_cast(transpose_A), + N, + M, + alpha, + A.data(), + M, + a.data(), + 1, + beta, + b.data(), + 1); + } + else + { + cblas_dgemv( + CblasRowMajor, + static_cast(transpose_A), + N, + M, + alpha, + A.data(), + M, + a.data(), + 1, + beta, + b.data(), + 1); + } + return b; +} + +template +mutable_tile_data +dot_diag_syrk_impl(const const_tile_data &A, const mutable_tile_data &r, const int N, const int M) +{ + GPRAT_BENCHMARK_FORCE_EVICT(A.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(r.as_span()); + GPRAT_TIME_FUNCTION(&dot_diag_syrk); + auto r_p = r.data(); + auto A_p = A.data(); + for (std::size_t j = 0; j < static_cast(M); ++j) + { + if constexpr (std::is_same_v) + { + r_p[j] += cblas_sdot(N, &A_p[j], M, &A_p[j], M); + } + else + { + r_p[j] += cblas_ddot(N, &A_p[j], M, &A_p[j], M); + } + } + return r; +} + +template +mutable_tile_data dot_diag_gemm_impl( + const const_tile_data &A, const const_tile_data &B, const mutable_tile_data &r, const int N, const int M) +{ + GPRAT_BENCHMARK_FORCE_EVICT(A.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(B.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(r.as_span()); + GPRAT_TIME_FUNCTION(&dot_diag_gemm); + auto r_p = r.data(); + auto A_p = A.data(); + auto B_p = B.data(); + for (std::size_t i = 0; i < static_cast(N); ++i) + { + if constexpr (std::is_same_v) + { + r_p[i] += cblas_sdot(M, &A_p[i * static_cast(M)], 1, &B_p[i], N); + } + else + { + r_p[i] += cblas_ddot(M, &A_p[i * static_cast(M)], 1, &B_p[i], N); + } + } + return r; +} + +// BLAS level 1 /////////////////////////////////////////////////////////////// + +template +mutable_tile_data axpy_impl(const mutable_tile_data &y, const const_tile_data &x, const int N) +{ + GPRAT_BENCHMARK_FORCE_EVICT(y.as_span()); + GPRAT_BENCHMARK_FORCE_EVICT(x.as_span()); + GPRAT_TIME_FUNCTION(&axpy); + if constexpr (std::is_same_v) + { + cblas_saxpy(N, T(-1), x.data(), 1, y.data(), 1); + } + else + { + cblas_daxpy(N, T(-1), x.data(), 1, y.data(), 1); + } + return y; +} + +template +T dot_impl(std::span a, std::span b, const int N) +{ + GPRAT_BENCHMARK_FORCE_EVICT(a); + GPRAT_BENCHMARK_FORCE_EVICT(b); + GPRAT_TIME_FUNCTION(&dot); + if constexpr (std::is_same_v) + { + return cblas_sdot(N, a.data(), 1, b.data(), 1); + } + else + { + return cblas_ddot(N, a.data(), 1, b.data(), 1); + } +} + +} // namespace detail + +GPRAT_NS_END diff --git a/core/src/cpu/gp_algorithms.cpp b/core/src/cpu/gp_algorithms.cpp index 92193b6d..ab3ed77b 100644 --- a/core/src/cpu/gp_algorithms.cpp +++ b/core/src/cpu/gp_algorithms.cpp @@ -1,183 +1,182 @@ -#include "cpu/gp_algorithms.hpp" +#include "gprat/cpu/gp_algorithms.hpp" + +#include "gprat/performance_counters.hpp" +#include "gprat/tile_data.hpp" #include -#include + +GPRAT_NS_BEGIN namespace cpu { // Tile generation -double compute_covariance_function(std::size_t i_global, - std::size_t j_global, - std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &i_input, - const std::vector &j_input) +double compute_covariance_function(std::size_t n_regressors, + const SEKParams &sek_params, + std::span i_input, + std::span j_input) { + GPRAT_TIME_FUNCTION(&compute_covariance_function); // k(z_i,z_j) = vertical_lengthscale * exp(-0.5 / lengthscale^2 * (z_i - z_j)^2) double distance = 0.0; - double z_ik_minus_z_jk; - for (std::size_t k = 0; k < n_regressors; k++) { - z_ik_minus_z_jk = i_input[i_global + k] - j_input[j_global + k]; + const double z_ik_minus_z_jk = i_input[k] - j_input[k]; distance += z_ik_minus_z_jk * z_ik_minus_z_jk; } + return sek_params.vertical_lengthscale * exp(-0.5 / (sek_params.lengthscale * sek_params.lengthscale) * distance); } -std::vector gen_tile_covariance( +mutable_tile_data gen_tile_covariance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &input) + const SEKParams &sek_params, + std::span input) { - std::size_t i_global, j_global; - double covariance_function; - // Preallocate required memory - std::vector tile; - tile.reserve(N * N); - // Compute entries + GPRAT_TIME_FUNCTION(&gen_tile_covariance); + mutable_tile_data tile(N * N); for (std::size_t i = 0; i < N; i++) { - i_global = N * row + i; + const std::size_t i_global = N * row + i; for (std::size_t j = 0; j < N; j++) { - j_global = N * col + j; + const std::size_t j_global = N * col + j; + // compute covariance function - covariance_function = - compute_covariance_function(i_global, j_global, n_regressors, sek_params, input, input); + auto covariance_function = compute_covariance_function( + n_regressors, sek_params, input.subspan(i_global, n_regressors), input.subspan(j_global, n_regressors)); if (i_global == j_global) { // noise variance on diagonal covariance_function += sek_params.noise_variance; } - tile.push_back(covariance_function); + + tile.data()[i * N + j] = covariance_function; } } return tile; } -std::vector gen_tile_full_prior_covariance( +mutable_tile_data gen_tile_full_prior_covariance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &input) + const SEKParams &sek_params, + std::span input) { - std::size_t i_global, j_global; - // Preallocate required memory - std::vector tile; - tile.reserve(N * N); - // Compute entries + GPRAT_TIME_FUNCTION(&gen_tile_full_prior_covariance); + mutable_tile_data tile(N * N); for (std::size_t i = 0; i < N; i++) { - i_global = N * row + i; + const std::size_t i_global = N * row + i; for (std::size_t j = 0; j < N; j++) { - j_global = N * col + j; + const std::size_t j_global = N * col + j; // compute covariance function - tile.push_back(compute_covariance_function(i_global, j_global, n_regressors, sek_params, input, input)); + tile.data()[i * N + j] = compute_covariance_function( + n_regressors, sek_params, input.subspan(i_global, n_regressors), input.subspan(j_global, n_regressors)); } } return tile; } -std::vector gen_tile_prior_covariance( +mutable_tile_data gen_tile_prior_covariance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &input) + const SEKParams &sek_params, + std::span input) { - std::size_t i_global, j_global; - // Preallocate required memory - std::vector tile; - tile.reserve(N); - // Compute entries + GPRAT_TIME_FUNCTION(&gen_tile_prior_covariance); + mutable_tile_data tile(N); for (std::size_t i = 0; i < N; i++) { - i_global = N * row + i; - j_global = N * col + i; + const std::size_t i_global = N * row + i; + const std::size_t j_global = N * col + i; // compute covariance function - tile.push_back(compute_covariance_function(i_global, j_global, n_regressors, sek_params, input, input)); + tile.data()[i] = compute_covariance_function( + n_regressors, sek_params, input.subspan(i_global, n_regressors), input.subspan(j_global, n_regressors)); } return tile; } -std::vector gen_tile_cross_covariance( +mutable_tile_data gen_tile_cross_covariance( std::size_t row, std::size_t col, std::size_t N_row, std::size_t N_col, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, - const std::vector &row_input, - const std::vector &col_input) + const SEKParams &sek_params, + std::span row_input, + std::span col_input) { - std::size_t i_global, j_global; - // Preallocate required memory - std::vector tile; - tile.reserve(N_row * N_col); - // Compute entries + GPRAT_TIME_FUNCTION(&gen_tile_cross_covariance); + mutable_tile_data tile(N_row * N_col); for (std::size_t i = 0; i < N_row; i++) { - i_global = N_row * row + i; + std::size_t i_global = N_row * row + i; for (std::size_t j = 0; j < N_col; j++) { - j_global = N_col * col + j; + std::size_t j_global = N_col * col + j; // compute covariance function - tile.push_back( - compute_covariance_function(i_global, j_global, n_regressors, sek_params, row_input, col_input)); + tile.data()[i * N_col + j] = compute_covariance_function( + n_regressors, + sek_params, + row_input.subspan(i_global, n_regressors), + col_input.subspan(j_global, n_regressors)); } } return tile; } -std::vector gen_tile_transpose(std::size_t N_row, std::size_t N_col, const std::vector &tile) +mutable_tile_data gen_tile_transpose(std::size_t N_row, std::size_t N_col, std::span tile) { - // Preallocate required memory - std::vector transposed; - transposed.reserve(N_row * N_col); + GPRAT_TIME_FUNCTION(&gen_tile_transpose); + mutable_tile_data transposed(N_row * N_col); // Transpose entries for (std::size_t j = 0; j < N_col; j++) { for (std::size_t i = 0; i < N_row; ++i) { // Mapping (i, j) in the original tile to (j, i) in the transposed tile - transposed.push_back(tile[i * N_col + j]); + transposed.data()[j * N_row + i] = tile[i * N_col + j]; } } return transposed; } -std::vector gen_tile_output(std::size_t row, std::size_t N, const std::vector &output) +mutable_tile_data gen_tile_output(std::size_t row, std::size_t N, std::span output) { - // Preallocate required memory - std::vector tile; - tile.reserve(N); - // Copy entries - std::copy(output.begin() + static_cast(N * row), - output.begin() + static_cast(N * (row + 1)), - std::back_inserter(tile)); + GPRAT_TIME_FUNCTION(&gen_tile_output); + mutable_tile_data tile(N); + std::copy(output.data() + (N * row), output.data() + (N * (row + 1)), tile.data()); return tile; } -std::vector gen_tile_zeros(std::size_t N) { return std::vector(N, 0.0); } +mutable_tile_data gen_tile_zeros(std::size_t N) +{ + GPRAT_TIME_FUNCTION(&gen_tile_zeros); + mutable_tile_data tile(N); + std::fill_n(tile.data(), N, 0.0); + return tile; +} -std::vector gen_tile_identity(std::size_t N) +mutable_tile_data gen_tile_identity(std::size_t N) { + GPRAT_TIME_FUNCTION(&gen_tile_identity); + mutable_tile_data tile(N * N); // Initialize zero tile - std::vector tile(N * N, 0.0); + std::fill_n(tile.data(), N * N, 0.0); // Fill diagonal with ones for (std::size_t i = 0; i < N; i++) { - tile[i * N + i] = 1.0; + tile.data()[i * N + i] = 1.0; } return tile; } @@ -189,6 +188,7 @@ double compute_error_norm(std::size_t n_tiles, const std::vector &b, const std::vector> &tiles) { + GPRAT_TIME_FUNCTION(&compute_error_norm); double error = 0.0; for (std::size_t k = 0; k < n_tiles; k++) { @@ -204,3 +204,5 @@ double compute_error_norm(std::size_t n_tiles, } } // end of namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/gp_algorithms_actions.cpp b/core/src/cpu/gp_algorithms_actions.cpp new file mode 100644 index 00000000..3bfd3fe0 --- /dev/null +++ b/core/src/cpu/gp_algorithms_actions.cpp @@ -0,0 +1,100 @@ +#include "gprat/cpu/gp_algorithms_actions.hpp" + +#include + +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_covariance, + GPRAT_NS::cpu::gen_tile_covariance_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_prior_covariance, + GPRAT_NS::cpu::gen_tile_prior_covariance_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_prior_covariance, + GPRAT_NS::cpu::gen_tile_full_prior_covariance_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_cross_covariance, + GPRAT_NS::cpu::gen_tile_cross_covariance_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_transpose, GPRAT_NS::cpu::gen_tile_transpose_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_output, GPRAT_NS::cpu::gen_tile_output_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_zeros, GPRAT_NS::cpu::gen_tile_zeros_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_identity, GPRAT_NS::cpu::gen_tile_identity_distributed_action) + +GPRAT_NS_BEGIN + +namespace cpu +{ +hpx::future> gen_tile_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &input) +{ + return tile.set_async(cpu::gen_tile_covariance(row, col, N, n_regressors, sek_params, input)); +} + +hpx::future> gen_tile_prior_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &input) +{ + return tile.set_async(cpu::gen_tile_prior_covariance(row, col, N, n_regressors, sek_params, input)); +} + +hpx::future> gen_tile_full_prior_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &input) +{ + return tile.set_async(cpu::gen_tile_full_prior_covariance(row, col, N, n_regressors, sek_params, input)); +} + +hpx::future> gen_tile_cross_covariance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N_row, + std::size_t N_col, + std::size_t n_regressors, + const SEKParams &sek_params, + const std::vector &row_input, + const std::vector &col_input) +{ + return tile.set_async( + cpu::gen_tile_cross_covariance(row, col, N_row, N_col, n_regressors, sek_params, row_input, col_input)); +} + +hpx::future> gen_tile_transpose_distributed( + const tile_handle &tile, std::size_t N_row, std::size_t N_col, const tile_handle &src) +{ + return hpx::dataflow( + hpx::launch::async, + [=](hpx::future> &&tiled) + { return tile.set_async(cpu::gen_tile_transpose(N_row, N_col, tiled.get().as_span())); }, + src.get_async()); +} + +hpx::future> gen_tile_output_distributed( + const tile_handle &tile, std::size_t row, std::size_t N, const std::vector &output) +{ + return tile.set_async(cpu::gen_tile_output(row, N, output)); +} + +hpx::future> gen_tile_zeros_distributed(const tile_handle &tile, std::size_t N) +{ + return tile.set_async(cpu::gen_tile_zeros(N)); +} + +hpx::future> gen_tile_identity_distributed(const tile_handle &tile, std::size_t N) +{ + return tile.set_async(cpu::gen_tile_identity(N)); +} +} // namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/gp_functions.cpp b/core/src/cpu/gp_functions.cpp index eee692fd..097f4867 100644 --- a/core/src/cpu/gp_functions.cpp +++ b/core/src/cpu/gp_functions.cpp @@ -1,1271 +1,20 @@ -#include "cpu/gp_functions.hpp" +#include "gprat/cpu/gp_functions.hpp" + +#include "gprat/cpu/gp_algorithms.hpp" +#include "gprat/cpu/gp_optimizer.hpp" +#include "gprat/cpu/tiled_algorithms.hpp" +#include "gprat/detail/async_helpers.hpp" -#include "apex_utils.hpp" -#include "cpu/gp_algorithms.hpp" -#include "cpu/gp_optimizer.hpp" -#include "cpu/tiled_algorithms.hpp" #include -using Tiled_matrix = std::vector>>; -using Tiled_vector = std::vector>>; +GPRAT_NS_BEGIN namespace cpu { /////////////////////////////////////////////////////////////////////////// // PREDICT -std::vector> -cholesky(const std::vector &training_input, - const gprat_hyper::SEKParams &sek_params, - int n_tiles, - int n_tile_size, - int n_regressors) -{ - std::vector> result; - -#if GPRAT_APEX_CHOLESKY - GPRAT_START_TIMER(assembly_cholesky_timer); -#endif - GPRAT_START_STEP(assembly_timer); - - // Tiled future data structures - Tiled_matrix K_tiles; // Tiled covariance matrix - - // Preallocate memory - result.resize(static_cast(n_tiles * n_tiles)); - K_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - K_tiles[i * static_cast(n_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_covariance, "assemble_tiled_K"), - i, - j, - n_tile_size, - n_regressors, - sek_params, - training_input); - } - } - - GPRAT_END_STEP(assembly_timer, "cholesky_step assembly", K_tiles); - GPRAT_START_STEP(cholesky_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous Cholesky decomposition: K = L * L^T - right_looking_cholesky_tiled(K_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(cholesky_timer, "cholesky_step cholesky", K_tiles); -#if GPRAT_APEX_CHOLESKY - GPRAT_STOP_TIMER(assembly_cholesky_timer, "cholesky", K_tiles); -#endif - - /////////////////////////////////////////////////////////////////////////// - // Synchronize - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - result[i * static_cast(n_tiles) + j] = - K_tiles[i * static_cast(n_tiles) + j].get(); - } - } - return result; -} - -std::vector -predict(const std::vector &training_input, - const std::vector &training_output, - const std::vector &test_input, - const gprat_hyper::SEKParams &sek_params, - int n_tiles, - int n_tile_size, - int m_tiles, - int m_tile_size, - int n_regressors) -{ - /* - * Prediction: hat(y)_M = cross(K)_MxN * K^-1_NxN * y_N - * - Covariance matrix K_NxN - * - Cross-covariance cross(K)_MxN - * - Training ouput y_N - * - Prediction output hat(y)_M - * - * Algorithm: - * 1: Compute lower triangular part of covariance matrix K - * 2: Compute Cholesky factor L of K - * 3: Compute prediction hat(y): - * - triangular solve L * beta = y - * - triangular solve L^T * alpha = beta - * - compute hat(y) = cross(K) * alpha - */ - - GPRAT_START_STEP(assembly_timer); - - std::vector prediction_result; - // Tiled future data structures - Tiled_matrix K_tiles; // Tiled covariance matrix - Tiled_matrix cross_covariance_tiles; // Tiled cross_covariance matrix - Tiled_vector prediction_tiles; // Tiled solution - Tiled_vector alpha_tiles; // Tiled intermediate solution - - // Preallocate memory - prediction_result.reserve(test_input.size()); - - K_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - alpha_tiles.reserve(static_cast(n_tiles)); - cross_covariance_tiles.reserve(static_cast(m_tiles) * static_cast(n_tiles)); - prediction_tiles.reserve(static_cast(m_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - K_tiles[i * static_cast(n_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_covariance, "assemble_tiled_K"), - i, - j, - n_tile_size, - n_regressors, - sek_params, - training_input); - } - } - - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - alpha_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_output, "assemble_tiled_alpha"), i, n_tile_size, training_output)); - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - for (std::size_t j = 0; j < static_cast(n_tiles); j++) - { - cross_covariance_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_cross_covariance, "assemble_pred"), - i, - j, - m_tile_size, - n_tile_size, - n_regressors, - sek_params, - test_input, - training_input)); - } - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - prediction_tiles.push_back(hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble_tiled"), m_tile_size)); - } - - GPRAT_END_STEP( - assembly_timer, "predict_step assembly", K_tiles, alpha_tiles, cross_covariance_tiles, prediction_tiles); - GPRAT_START_STEP(cholesky_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous Cholesky decomposition: K = L * L^T - right_looking_cholesky_tiled(K_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(cholesky_timer, "predict_step cholesky", K_tiles); - GPRAT_START_STEP(forward_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous triangular solve L * (L^T * alpha) = y - // First, forward solve L * beta = y - forward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(forward_timer, "predict_step forward", alpha_tiles); - GPRAT_START_STEP(backward_timer); - - // Second, backward solve L^T * alpha = beta - backward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(backward_timer, "predict_step backward", alpha_tiles); - GPRAT_START_STEP(prediction_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous prediction computation solve: \hat{y} = K_cross_cov * alpha - matrix_vector_tiled( - cross_covariance_tiles, - alpha_tiles, - prediction_tiles, - m_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(m_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Synchronize prediction - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - auto tile = prediction_tiles[i].get(); - std::copy(tile.begin(), tile.end(), std::back_inserter(prediction_result)); - } - - GPRAT_END_STEP(prediction_timer, "predict_step prediction"); - - return prediction_result; -} - -std::vector> predict_with_uncertainty( - const std::vector &training_input, - const std::vector &training_output, - const std::vector &test_input, - const gprat_hyper::SEKParams &sek_params, - int n_tiles, - int n_tile_size, - int m_tiles, - int m_tile_size, - int n_regressors) -{ - /* - * Prediction: hat(y) = cross(K) * K^-1 * y - * Uncertainty: diag(Sigma) = diag(prior(K)) * diag(cross(K)^T * K^-1 * cross(K)) - * - Covariance matrix K_NxN - * - Cross-covariance cross(K)_MxN - * - Prior covariance prior(K)_MxM - * - Training ouput y_N - * - Prediction output hat(y)_M - * - Posterior covariance matrix Sigma_MxM - * - * Algorithm: - * 1: Compute lower triangular part of covariance matrix K - * 2: Compute Cholesky factor L of K - * 3: Compute prediction hat(y): - * - triangular solve L * beta = y - * - triangular solve L^T * alpha = beta - * - compute hat(y) = cross(K) * alpha - * 4: Compute uncertainty diag(Sigma): - * - triangular solve L * V = cross(K)^T - * - compute diag(W) = diag(V^T * V) - * - compute diag(Sigma) = diag(prior(K)) - diag(W) - */ - - GPRAT_START_STEP(assembly_timer); - - std::vector prediction_result; - std::vector uncertainty_result; - // Tiled future data structures for prediction - Tiled_matrix K_tiles; // Tiled covariance matrix K_NxN - Tiled_matrix cross_covariance_tiles; // Tiled cross_covariance matrix K_NxM - Tiled_vector prediction_tiles; // Tiled solution - Tiled_vector alpha_tiles; // Tiled intermediate solution - // Tiled future data structures for uncertainty - Tiled_matrix t_cross_covariance_tiles; // Tiled transposed cross_covariance matrix K_MxN - Tiled_vector prior_K_tiles; // Tiled prior covariance matrix diagonal diag(K_MxM) - Tiled_vector uncertainty_tiles; // Tiled uncertainty solution - - // Preallocate memory - prediction_result.reserve(test_input.size()); - uncertainty_result.reserve(test_input.size()); - - K_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - cross_covariance_tiles.reserve(static_cast(m_tiles) * static_cast(n_tiles)); - prediction_tiles.reserve(static_cast(m_tiles)); - alpha_tiles.reserve(static_cast(n_tiles)); - - t_cross_covariance_tiles.reserve(static_cast(n_tiles) * static_cast(m_tiles)); - prior_K_tiles.reserve(static_cast(m_tiles)); - uncertainty_tiles.reserve(static_cast(m_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - K_tiles[i * static_cast(n_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_covariance, "assemble_tiled_K"), - i, - j, - n_tile_size, - n_regressors, - sek_params, - training_input); - } - } - - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - alpha_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_output, "assemble_tiled_alpha"), i, n_tile_size, training_output)); - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - for (std::size_t j = 0; j < static_cast(n_tiles); j++) - { - cross_covariance_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_cross_covariance, "assemble_pred"), - i, - j, - m_tile_size, - n_tile_size, - n_regressors, - sek_params, - test_input, - training_input)); - } - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - prediction_tiles.push_back(hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble_tiled"), m_tile_size)); - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - prior_K_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_prior_covariance, "assemble_tiled"), - i, - i, - m_tile_size, - n_regressors, - sek_params, - test_input)); - } - - for (std::size_t j = 0; j < static_cast(n_tiles); j++) - { - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - t_cross_covariance_tiles.push_back(hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_transpose), "assemble_pred"), - m_tile_size, - n_tile_size, - cross_covariance_tiles[i * static_cast(n_tiles) + j])); - } - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - uncertainty_tiles.push_back( - hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble_prior_inter"), m_tile_size)); - } - - GPRAT_END_STEP( - assembly_timer, - "predict_uncer_step assembly", - K_tiles, - alpha_tiles, - cross_covariance_tiles, - prediction_tiles, - prior_K_tiles, - uncertainty_tiles, - t_cross_covariance_tiles); - GPRAT_START_STEP(cholesky_timer); - - // Prediction - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous Cholesky decomposition: K = L * L^T - right_looking_cholesky_tiled(K_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(cholesky_timer, "predict_uncer_step cholesky", K_tiles); - GPRAT_START_STEP(forward_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous triangular solve L * (L^T * alpha) = y - // First, forward solve L * beta = y - forward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(forward_timer, "predict_uncer_step forward", alpha_tiles); - GPRAT_START_STEP(backward_timer); - - // Second, backward solve L^T * alpha = beta - backward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(backward_timer, "predict_uncer_step backward", alpha_tiles); - GPRAT_START_STEP(prediction_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous prediction computation solve: hat(y) = cross(K) * alpha - matrix_vector_tiled( - cross_covariance_tiles, - alpha_tiles, - prediction_tiles, - m_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(m_tiles)); - - GPRAT_END_STEP(prediction_timer, "predict_uncer_step prediction", prediction_tiles); - GPRAT_START_STEP(uncertainty_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous triangular solve L * V = cross(K)^T - forward_solve_tiled_matrix( - K_tiles, - t_cross_covariance_tiles, - n_tile_size, - m_tile_size, - static_cast(n_tiles), - static_cast(m_tiles)); - - GPRAT_END_STEP(uncertainty_timer, "predict_uncer_step forward KcK", t_cross_covariance_tiles); - GPRAT_START_STEP(posterior_covariance_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous computation diag(W) = diag(V^T * V) - symmetric_matrix_matrix_diagonal_tiled( - t_cross_covariance_tiles, - uncertainty_tiles, - n_tile_size, - m_tile_size, - static_cast(n_tiles), - static_cast(m_tiles)); - - GPRAT_END_STEP(posterior_covariance_timer, "predict_uncer_step posterior covariance", uncertainty_tiles); - GPRAT_START_STEP(prediction_uncertainty_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous computation diag(Sigma) = diag(prior(K)) - diag(W) - vector_difference_tiled(prior_K_tiles, uncertainty_tiles, m_tile_size, static_cast(m_tiles)); - - GPRAT_END_STEP(prediction_uncertainty_timer, "predict_uncer_step prediction uncertainty", uncertainty_tiles); - - /////////////////////////////////////////////////////////////////////////// - // Synchronize prediction - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - auto tile = prediction_tiles[i].get(); - std::copy(tile.begin(), tile.end(), std::back_inserter(prediction_result)); - } - - // Synchronize uncertainty - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - auto tile = uncertainty_tiles[i].get(); - std::copy(tile.begin(), tile.end(), std::back_inserter(uncertainty_result)); - } - - return std::vector>{ std::move(prediction_result), std::move(uncertainty_result) }; -} - -std::vector> predict_with_full_cov( - const std::vector &training_input, - const std::vector &training_output, - const std::vector &test_input, - const gprat_hyper::SEKParams &sek_params, - int n_tiles, - int n_tile_size, - int m_tiles, - int m_tile_size, - int n_regressors) -{ - /* - * Prediction: hat(y)_M = cross(K) * K^-1 * y - * Full covariance: Sigma = prior(K) - cross(K)^T * K^-1 * cross(K) - * - Covariance matrix K_NxN - * - Cross-covariance cross(K)_MxN - * - Prior covariance prior(K)_MxM - * - Training ouput y_N - * - Prediction output hat(y)_M - * - Posterior covariance matrix Sigma_MxM - * - * Algorithm: - * 1: Compute lower triangular part of covariance matrix K - * 2: Compute Cholesky factor L of K - * 3: Compute intermediate solutions (alpha and V): - * - triangular solve L * beta = y - * - triangular solve L^T * alpha = beta - * - triangular solve L * V = cross(K)^T - * 4: Compute prediction hat(y): - * - compute hat(y) = cross(K) * alpha - * 5: Compute full covariance matrix Sigma: - * - compute W = V^T * V - * - compute Sigma = prior(K) - W - * 6: Compute diag(Sigma) - */ - - GPRAT_START_STEP(assembly_timer); - - std::vector prediction_result; - std::vector uncertainty_result; - // Tiled future data structures for prediction - Tiled_matrix K_tiles; // Tiled covariance matrix K_NxN - Tiled_matrix cross_covariance_tiles; // Tiled cross_covariance matrix K_NxM - Tiled_vector prediction_tiles; // Tiled solution - Tiled_vector alpha_tiles; // Tiled intermediate solution - // Tiled future data structures for uncertainty - Tiled_matrix t_cross_covariance_tiles; // Tiled transposed cross_covariance matrix K_MxN - Tiled_matrix prior_K_tiles; // Tiled prior covariance matrix K_MxM - Tiled_vector uncertainty_tiles; // Tiled uncertainty solution - - // Preallocate memory - prediction_result.reserve(test_input.size()); - uncertainty_result.reserve(test_input.size()); - - K_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - cross_covariance_tiles.reserve(static_cast(m_tiles) * static_cast(n_tiles)); - prediction_tiles.reserve(static_cast(m_tiles)); - alpha_tiles.reserve(static_cast(n_tiles)); - - t_cross_covariance_tiles.reserve(static_cast(n_tiles) * static_cast(m_tiles)); - prior_K_tiles.resize(static_cast(m_tiles * m_tiles)); - uncertainty_tiles.reserve(static_cast(m_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - K_tiles[i * static_cast(n_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_covariance, "assemble_tiled_K"), - i, - j, - n_tile_size, - n_regressors, - sek_params, - training_input); - } - } - - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - alpha_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_output, "assemble_tiled_alpha"), i, n_tile_size, training_output)); - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - for (std::size_t j = 0; j < static_cast(n_tiles); j++) - { - cross_covariance_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_cross_covariance, "assemble_pred"), - i, - j, - m_tile_size, - n_tile_size, - n_regressors, - sek_params, - test_input, - training_input)); - } - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - prediction_tiles.push_back(hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble_tiled"), m_tile_size)); - } - - // Assemble prior covariance matrix vector - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - prior_K_tiles[i * static_cast(m_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_full_prior_covariance, "assemble_prior_tiled"), - i, - j, - m_tile_size, - n_regressors, - sek_params, - test_input); - - if (i != j) - { - prior_K_tiles[j * static_cast(m_tiles) + i] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_transpose), "assemble_prior_tiled"), - m_tile_size, - m_tile_size, - prior_K_tiles[i * static_cast(m_tiles) + j]); - } - } - } - - for (std::size_t j = 0; j < static_cast(n_tiles); j++) - { - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - t_cross_covariance_tiles.push_back(hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_transpose), "assemble_pred"), - m_tile_size, - n_tile_size, - cross_covariance_tiles[i * static_cast(n_tiles) + j])); - } - } - - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - uncertainty_tiles.push_back(hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble_tiled"), m_tile_size)); - } - - GPRAT_END_STEP( - assembly_timer, - "predict_full_cov_step assembly", - K_tiles, - alpha_tiles, - cross_covariance_tiles, - prediction_tiles, - prior_K_tiles, - uncertainty_tiles, - t_cross_covariance_tiles); - GPRAT_START_STEP(cholesky_timer); - - // Prediction - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous Cholesky decomposition: K = L * L^T - right_looking_cholesky_tiled(K_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(cholesky_timer, "predict_full_cov_step cholesky", K_tiles); - GPRAT_START_STEP(forward_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous triangular solve L * (L^T * alpha) = y - forward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(forward_timer, "predict_full_cov_step forward", alpha_tiles); - GPRAT_START_STEP(backward_timer); - - backward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - - GPRAT_END_STEP(backward_timer, "predict_full_cov_step backward", alpha_tiles); - GPRAT_START_STEP(forward_KcK_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous triangular solve L * V = cross(K)^T - forward_solve_tiled_matrix( - K_tiles, - t_cross_covariance_tiles, - n_tile_size, - m_tile_size, - static_cast(n_tiles), - static_cast(m_tiles)); - - GPRAT_END_STEP(forward_KcK_timer, "predict_full_cov_step forward KcK", t_cross_covariance_tiles); - GPRAT_START_STEP(prediction_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous prediction computation solve: hat(y) = K_cross_cov * alpha - matrix_vector_tiled( - cross_covariance_tiles, - alpha_tiles, - prediction_tiles, - m_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(m_tiles)); - - GPRAT_END_STEP(prediction_timer, "predict_full_cov_step prediction", prediction_tiles); - GPRAT_START_STEP(full_cov_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous computation of full covariance Sigma = prior(K) - V^T * V - symmetric_matrix_matrix_tiled( - t_cross_covariance_tiles, - prior_K_tiles, - n_tile_size, - m_tile_size, - static_cast(n_tiles), - static_cast(m_tiles)); - - GPRAT_END_STEP(full_cov_timer, "predict_full_cov_step full cov", prior_K_tiles); - GPRAT_START_STEP(prediction_uncertainty_timer); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous computation of uncertainty diag(Sigma) - matrix_diagonal_tiled(prior_K_tiles, uncertainty_tiles, m_tile_size, static_cast(m_tiles)); - - GPRAT_END_STEP(prediction_uncertainty_timer, "predict_full_cov_step pred uncer", uncertainty_tiles); - - /////////////////////////////////////////////////////////////////////////// - // Synchronize prediction - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - auto tile = prediction_tiles[i].get(); - std::copy(tile.begin(), tile.end(), std::back_inserter(prediction_result)); - } - - // Synchronize uncertainty - for (std::size_t i = 0; i < static_cast(m_tiles); i++) - { - auto tile = uncertainty_tiles[i].get(); - std::copy(tile.begin(), tile.end(), std::back_inserter(uncertainty_result)); - } - - return std::vector>{ std::move(prediction_result), std::move(uncertainty_result) }; -} - -/////////////////////////////////////////////////////////////////////////// -// OPTIMIZATION -double compute_loss(const std::vector &training_input, - const std::vector &training_output, - const gprat_hyper::SEKParams &sek_params, - int n_tiles, - int n_tile_size, - int n_regressors) -{ - /* - * Negative log likelihood loss: - * loss(theta) = 0.5 * ( log(det(K)) - y^T * K^-1 * y - N * log(2 * pi) ) - * - Covariance matrix K(theta)_NxN - * - Training ouput y_N - * - Hyperparameters theta ={ v, l, v_n } - * - * Algorithm: - * 1: Compute lower triangular part of covariance matrix K - * 2: Compute Cholesky factor L of K - * 3: Compute prediction alpha = K^-1 * y: - * - triangular solve L * beta = y - * - triangular solve L^T * alpha = beta - * 5: Compute beta = K^-1 * y - * 6: Compute negative log likelihood loss - * - Calculate sum_i^N log(L_ii^2) - * - Calculate y^T * beta - * - Add constant N * log (2 * pi) - */ - - hpx::shared_future loss_value; - // Tiled future data structures - Tiled_matrix K_tiles; // Tiled covariance matrix K_NxN - Tiled_vector y_tiles; // Tiled output - Tiled_vector alpha_tiles; // Tiled intermediate solution - - // Preallocate memory - K_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - y_tiles.reserve(static_cast(n_tiles)); - alpha_tiles.reserve(static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - K_tiles[i * static_cast(n_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_covariance, "assemble_tiled_K"), - i, - j, - n_tile_size, - n_regressors, - sek_params, - training_input); - } - } - - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - y_tiles.push_back( - hpx::async(hpx::annotated_function(gen_tile_output, "assemble_tiled_y"), i, n_tile_size, training_output)); - } - - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - alpha_tiles.push_back(hpx::async( - hpx::annotated_function(gen_tile_output, "assemble_tiled_alpha"), i, n_tile_size, training_output)); - } - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous Cholesky decomposition: K = L * L^T - right_looking_cholesky_tiled(K_tiles, n_tile_size, static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous triangular solve L * (L^T * alpha) = y - forward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - backward_solve_tiled(K_tiles, alpha_tiles, n_tile_size, static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous loss computation - compute_loss_tiled(K_tiles, alpha_tiles, y_tiles, loss_value, n_tile_size, static_cast(n_tiles)); - - return loss_value.get(); -} - -std::vector -optimize(const std::vector &training_input, - const std::vector &training_output, - int n_tiles, - int n_tile_size, - int n_regressors, - const gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, - std::vector trainable_params) -{ - /* - * - Hyperparameters theta={v, l, v_n} - * - Covariance matrix K(theta) - * - Training ouput y - * - * Algorithm: - * for opt_iter: - * 1: Compute distance for entries of covariance matrix K - * 2: Compute lower triangular part of K with distance - * 3: Compute lower triangular gradients for delta(K)/delta(v), and delta(K)/delta(l) with distance - * - * 4: Compute Cholesky factor L of K - * 5: Compute K^-1: - * - triangular solve L * {} = I - * - triangular solve L^T * K^-1 = {} - * 6: Compute beta = K^-1 * y - * - * 7: Compute negative log likelihood loss - * - Calculate 0.5 sum_i^N log(L_ii^2) - * - Calculate 0.5 y^T * beta - * - Add constant N / 2 * log (2 * pi) - * - * 8: Compute delta(loss)/delta(param_i) - * - Compute trace(K^-1 * delta(K)/delta(theta_i)) - * - Compute beta^T * delta(K)/delta(theta_i) * beta - * 9: Update hyperparameters theta with Adam optimizer - * - m_T = beta1 * m_T-1 + (1 - beta1) * g_T - * - w_T = beta2 + w_T-1 + (1 - beta2) * g_T^2 - * - nu_T = nu * sqrt(1 - beta2_T) / (1 - beta1_T) - * - theta_T = theta_T-1 - nu_T * m_T / (sqrt(w_T) + epsilon) - * endfor - */ - - // data holder for loss - hpx::shared_future loss_value; - // data holder for computed loss values - std::vector losses; - - // Tiled future data structures - Tiled_matrix K_tiles; // Tiled covariance matrix K_NxN - Tiled_vector y_tiles; // Tiled output - Tiled_vector alpha_tiles; // Tiled intermediate solution - Tiled_matrix K_inv_tiles; // Tiled inversed covariance matrix K^-1_NxN - // Tiled future data structures for gradients - Tiled_matrix grad_v_tiles; // Tiled covariance with gradient v - Tiled_matrix grad_l_tiles; // Tiled covariance with gradient l - - // Preallocate memory - losses.reserve(static_cast(adam_params.opt_iter)); - y_tiles.reserve(static_cast(n_tiles)); - - alpha_tiles.resize(static_cast(n_tiles)); // for now resize since reset in loop - K_inv_tiles.resize(static_cast(n_tiles * n_tiles)); // for now resize since reset in loop - - K_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - grad_v_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - grad_l_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly of output y - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - y_tiles.push_back( - hpx::async(hpx::annotated_function(gen_tile_output, "assemble_y"), i, n_tile_size, training_output)); - } - - ////////////////////////////////////////////////////////////////////////////// - // Perform optimization - for (std::size_t iter = 0; iter < static_cast(adam_params.opt_iter); iter++) - { - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly of tiled covariance matrix, derivative of covariance matrix - // vector w.r.t. to vertical lengthscale and derivative of covariance - // matrix vector w.r.t. to lengthscale - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - // Compute the distance (z_i - z_j) of K entries to reuse - hpx::shared_future> cov_dists = hpx::async( - hpx::annotated_function(gen_tile_distance, "assemble_cov_dist"), - i, - j, - n_tile_size, - n_regressors, - sek_params, - training_input); - - K_tiles[i * static_cast(n_tiles) + j] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_covariance_with_distance), "assemble_K"), - i, - j, - n_tile_size, - sek_params, - cov_dists); - if (trainable_params[0]) - { - grad_l_tiles[i * static_cast(n_tiles) + j] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_grad_l), "assemble_gradl"), - n_tile_size, - sek_params, - cov_dists); - if (i != j) - { - grad_l_tiles[j * static_cast(n_tiles) + i] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_transpose), "assemble_gradl_t"), - n_tile_size, - n_tile_size, - grad_l_tiles[i * static_cast(n_tiles) + j]); - } - } - - if (trainable_params[1]) - { - grad_v_tiles[i * static_cast(n_tiles) + j] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_grad_v), "assemble_gradv"), - n_tile_size, - sek_params, - cov_dists); - if (i != j) - { - grad_v_tiles[j * static_cast(n_tiles) + i] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_transpose), "assemble_gradv_t"), - n_tile_size, - n_tile_size, - grad_v_tiles[i * static_cast(n_tiles) + j]); - } - } - } - } - - // Assembly with reallocation -> optimize to only set existing values - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - alpha_tiles[i] = hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble_tiled"), n_tile_size); - } - - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j < static_cast(n_tiles); j++) - { - if (i == j) - { - K_inv_tiles[i * static_cast(n_tiles) + j] = - hpx::async(hpx::annotated_function(gen_tile_identity, "assemble_identity_matrix"), n_tile_size); - } - else - { - K_inv_tiles[i * static_cast(n_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_zeros, "assemble_identity_matrix"), n_tile_size * n_tile_size); - } - } - } - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous Cholesky decomposition: K = L * L^T - right_looking_cholesky_tiled(K_tiles, n_tile_size, static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous compute K^-1 through L* (L^T * X) = I - forward_solve_tiled_matrix( - K_tiles, - K_inv_tiles, - n_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(n_tiles)); - backward_solve_tiled_matrix( - K_tiles, - K_inv_tiles, - n_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous compute beta = inv(K) * y - matrix_vector_tiled( - K_inv_tiles, - y_tiles, - alpha_tiles, - n_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous loss computation where - // loss(theta) = 0.5 * ( log(det(K)) - y^T * K^-1 * y - N * log(2 * pi) ) - compute_loss_tiled(K_tiles, alpha_tiles, y_tiles, loss_value, n_tile_size, static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous update of the hyperparameters - if (trainable_params[0]) - { // lengthscale - update_hyperparameter_tiled( - K_inv_tiles, - grad_l_tiles, - alpha_tiles, - adam_params, - sek_params, - n_tile_size, - static_cast(n_tiles), - iter, - 0); - } - if (trainable_params[1]) - { // vertical_lengthscale - update_hyperparameter_tiled( - K_inv_tiles, - grad_v_tiles, - alpha_tiles, - adam_params, - sek_params, - n_tile_size, - static_cast(n_tiles), - iter, - 1); - } - if (trainable_params[2]) - { // noise_variance - update_hyperparameter_tiled( - K_inv_tiles, - Tiled_matrix{}, // no tiled gradient matrix required - alpha_tiles, - adam_params, - sek_params, - n_tile_size, - static_cast(n_tiles), - iter, - 2); - } - // Synchronize after iteration - losses.push_back(loss_value.get()); - } - // Return losses - return losses; -} - -double optimize_step(const std::vector &training_input, - const std::vector &training_output, - int n_tiles, - int n_tile_size, - int n_regressors, - gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, - std::vector trainable_params, - int iter) -{ - /* - * - Hyperparameters theta={v, l, v_n} - * - Covariance matrix K(theta) - * - Training ouput y - * - * Algorithm: - * 1: Compute distance for entries of covariance matrix K - * 2: Compute lower triangular part of K with distance - * 3: Compute lower triangular gradients for delta(K)/delta(v), and delta(K)/delta(l) with distance - * - * 4: Compute Cholesky factor L of K - * 5: Compute K^-1: - * - triangular solve L * {} = I - * - triangular solve L^T * K^-1 = {} - * 6: Compute beta = K^-1 * y - * - * 7: Compute negative log likelihood loss - * - Calculate 0.5 sum_i^N log(L_ii^2) - * - Calculate 0.5 y^T * beta - * - Add constant N / 2 * log (2 * pi) - * - * 8: Compute delta(loss)/delta(param_i) - * - Compute trace(K^-1 * delta(K)/delta(theta_i)) - * - Compute beta^T * delta(K)/delta(theta_i) * beta - * 9: Update hyperparameters theta with Adam optimizer - * - m_T = beta1 * m_T-1 + (1 - beta1) * g_T - * - w_T = beta2 + w_T-1 + (1 - beta2) * g_T^2 - * - nu_T = nu * sqrt(1 - beta2_T) / (1 - beta1_T) - * - theta_T = theta_T-1 - nu_T * m_T / (sqrt(w_T) + epsilon) - */ - - // data holder for loss - hpx::shared_future loss_value; - - // Tiled future data structures - Tiled_matrix K_tiles; // Tiled covariance matrix K_NxN - Tiled_vector y_tiles; // Tiled output - Tiled_vector alpha_tiles; // Tiled intermediate solution - Tiled_matrix K_inv_tiles; // Tiled inversed covariance matrix K^-1_NxN - // Tiled future data structures for gradients - Tiled_matrix grad_v_tiles; // Tiled covariance with gradient v - Tiled_matrix grad_l_tiles; // Tiled covariance with gradient l - - // Preallocate memory - y_tiles.reserve(static_cast(n_tiles)); - - alpha_tiles.resize(static_cast(n_tiles)); // for now resize since reset in loop - K_inv_tiles.resize(static_cast(n_tiles * n_tiles)); // for now resize since reset in loop - - K_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - grad_v_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - grad_l_tiles.resize(static_cast(n_tiles * n_tiles)); // No reserve because of triangular structure - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly of output y - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - y_tiles.push_back( - hpx::async(hpx::annotated_function(gen_tile_output, "assemble_y"), i, n_tile_size, training_output)); - } - - ////////////////////////////////////////////////////////////////////////////// - // Perform one optimization step - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous assembly of tiled covariance matrix, derivative of covariance matrix - // vector w.r.t. to vertical lengthscale and derivative of covariance - // matrix vector w.r.t. to lengthscale - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j <= i; j++) - { - // Compute the distance (z_i - z_j) of K entries to reuse - hpx::shared_future> cov_dists = hpx::async( - hpx::annotated_function(gen_tile_distance, "assemble_cov_dist"), - i, - j, - n_tile_size, - n_regressors, - sek_params, - training_input); - - K_tiles[i * static_cast(n_tiles) + j] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_covariance_with_distance), "assemble_K"), - i, - j, - n_tile_size, - sek_params, - cov_dists); - - if (trainable_params[0]) - { - grad_l_tiles[i * static_cast(n_tiles) + j] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_grad_l), "assemble_gradl"), - n_tile_size, - sek_params, - cov_dists); - if (i != j) - { - grad_l_tiles[j * static_cast(n_tiles) + i] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_transpose), "assemble_gradl_t"), - n_tile_size, - n_tile_size, - grad_l_tiles[i * static_cast(n_tiles) + j]); - } - } - - if (trainable_params[1]) - { - grad_v_tiles[i * static_cast(n_tiles) + j] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_grad_v), "assemble_gradv"), - n_tile_size, - sek_params, - cov_dists); - if (i != j) - { - grad_v_tiles[j * static_cast(n_tiles) + i] = hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&gen_tile_transpose), "assemble_gradv_t"), - n_tile_size, - n_tile_size, - grad_v_tiles[i * static_cast(n_tiles) + j]); - } - } - } - } - - // Assembly with reallocation -> optimize to only set existing values - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - alpha_tiles[i] = hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble_tiled"), n_tile_size); - } - - for (std::size_t i = 0; i < static_cast(n_tiles); i++) - { - for (std::size_t j = 0; j < static_cast(n_tiles); j++) - { - if (i == j) - { - K_inv_tiles[i * static_cast(n_tiles) + j] = - hpx::async(hpx::annotated_function(gen_tile_identity, "assemble_identity_matrix"), n_tile_size); - } - else - { - K_inv_tiles[i * static_cast(n_tiles) + j] = hpx::async( - hpx::annotated_function(gen_tile_zeros, "assemble_identity_matrix"), n_tile_size * n_tile_size); - } - } - } - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous Cholesky decomposition: K = L * L^T - right_looking_cholesky_tiled(K_tiles, n_tile_size, static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous compute K^-1 through L* (L^T * X) = I - forward_solve_tiled_matrix( - K_tiles, - K_inv_tiles, - n_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(n_tiles)); - backward_solve_tiled_matrix( - K_tiles, - K_inv_tiles, - n_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous compute beta = inv(K) * y - matrix_vector_tiled( - K_inv_tiles, - y_tiles, - alpha_tiles, - n_tile_size, - n_tile_size, - static_cast(n_tiles), - static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous loss computation where - // loss(theta) = 0.5 * ( log(det(K)) - y^T * K^-1 * y - N * log(2 * pi) ) - compute_loss_tiled(K_tiles, alpha_tiles, y_tiles, loss_value, n_tile_size, static_cast(n_tiles)); - - /////////////////////////////////////////////////////////////////////////// - // Launch asynchronous update of the hyperparameters - if (trainable_params[0]) - { // lengthscale - update_hyperparameter_tiled( - K_inv_tiles, - grad_l_tiles, - alpha_tiles, - adam_params, - sek_params, - n_tile_size, - static_cast(n_tiles), - static_cast(iter), - 0); - } - if (trainable_params[1]) - { // vertical_lengthscale - update_hyperparameter_tiled( - K_inv_tiles, - grad_v_tiles, - alpha_tiles, - adam_params, - sek_params, - n_tile_size, - static_cast(n_tiles), - static_cast(iter), - 1); - } - if (trainable_params[2]) - { // noise_variance - update_hyperparameter_tiled( - K_inv_tiles, - Tiled_matrix{}, // no tiled gradient matrix required - alpha_tiles, - adam_params, - sek_params, - n_tile_size, - static_cast(n_tiles), - static_cast(iter), - 2); - } - return loss_value.get(); -} } // end of namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/gp_optimizer.cpp b/core/src/cpu/gp_optimizer.cpp index d33b1889..7c1c76f7 100644 --- a/core/src/cpu/gp_optimizer.cpp +++ b/core/src/cpu/gp_optimizer.cpp @@ -1,9 +1,13 @@ -#include "cpu/gp_optimizer.hpp" +#include "gprat/cpu/gp_optimizer.hpp" -#include "cpu/adapter_cblas_fp64.hpp" +#include "gprat/cpu/adapter_cblas_fp64.hpp" + +#include #include #include +GPRAT_NS_BEGIN + namespace cpu { @@ -40,110 +44,103 @@ double compute_sigmoid(double parameter) { return 1.0 / (1.0 + exp(-parameter)); double compute_covariance_distance(std::size_t i_global, std::size_t j_global, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, const std::vector &i_input, const std::vector &j_input) { // -0.5*lengthscale^2*(z_i-z_j)^2 double distance = 0.0; - double z_ik_minus_z_jk; - for (std::size_t k = 0; k < n_regressors; k++) { - z_ik_minus_z_jk = i_input[i_global + k] - j_input[j_global + k]; + const double z_ik_minus_z_jk = i_input[i_global + k] - j_input[j_global + k]; distance += z_ik_minus_z_jk * z_ik_minus_z_jk; } return -0.5 / (sek_params.lengthscale * sek_params.lengthscale) * distance; } -std::vector gen_tile_distance( +mutable_tile_data gen_tile_distance( std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, const std::vector &input) { - std::size_t i_global, j_global; // Preallocate memory - std::vector tile; - tile.reserve(N * N); + mutable_tile_data tile(N * N); for (std::size_t i = 0; i < N; i++) { - i_global = N * row + i; + const std::size_t i_global = N * row + i; for (std::size_t j = 0; j < N; j++) { - j_global = N * col + j; + const std::size_t j_global = N * col + j; // compute covariance function - tile.push_back(compute_covariance_distance(i_global, j_global, n_regressors, sek_params, input, input)); + tile.data()[i * N + j] = + compute_covariance_distance(i_global, j_global, n_regressors, sek_params, input, input); } } return tile; } -std::vector gen_tile_covariance_with_distance( +mutable_tile_data gen_tile_covariance_with_distance( std::size_t row, std::size_t col, std::size_t N, - const gprat_hyper::SEKParams &sek_params, - const std::vector &distance) + const SEKParams &sek_params, + const const_tile_data &distance) { - std::size_t i_global, j_global; - double covariance; // Preallocate required memory - std::vector tile; - tile.reserve(N * N); + mutable_tile_data tile(N * N); for (std::size_t i = 0; i < N; i++) { - i_global = N * row + i; + const std::size_t i_global = N * row + i; for (std::size_t j = 0; j < N; j++) { - j_global = N * col + j; + const std::size_t j_global = N * col + j; // compute covariance function - covariance = sek_params.vertical_lengthscale * exp(distance[i * N + j]); + double covariance = sek_params.vertical_lengthscale * exp(distance.data()[i * N + j]); if (i_global == j_global) { // noise variance on diagonal covariance += sek_params.noise_variance; } - tile.push_back(covariance); + tile.data()[i * N + j] = covariance; } } return tile; } -std::vector -gen_tile_grad_v(std::size_t N, const gprat_hyper::SEKParams &sek_params, const std::vector &distance) +mutable_tile_data +gen_tile_grad_v(std::size_t N, const SEKParams &sek_params, const const_tile_data &distance) { // Preallocate required memory - std::vector tile; - tile.reserve(N * N); + mutable_tile_data tile(N * N); double hyperparam_der = compute_sigmoid(to_unconstrained(sek_params.vertical_lengthscale, false)); for (std::size_t i = 0; i < N; i++) { for (std::size_t j = 0; j < N; j++) { // compute derivative - tile.push_back(exp(distance[i * N + j]) * hyperparam_der); + tile.data()[i * N + j] = exp(distance.data()[i * N + j]) * hyperparam_der; } } return tile; } -std::vector -gen_tile_grad_l(std::size_t N, const gprat_hyper::SEKParams &sek_params, const std::vector &distance) +mutable_tile_data +gen_tile_grad_l(std::size_t N, const SEKParams &sek_params, const const_tile_data &distance) { // Preallocate required memory - std::vector tile; - tile.reserve(N * N); - double hyperparam_der = compute_sigmoid(to_unconstrained(sek_params.lengthscale, false)); - double factor = -2.0 * sek_params.vertical_lengthscale / sek_params.lengthscale; + mutable_tile_data tile(N * N); + const double hyperparam_der = compute_sigmoid(to_unconstrained(sek_params.lengthscale, false)); + const double factor = -2.0 * sek_params.vertical_lengthscale / sek_params.lengthscale; for (std::size_t i = 0; i < N; i++) { for (std::size_t j = 0; j < N; j++) { // compute derivative - tile.push_back(factor * distance[i * N + j] * exp(distance[i * N + j]) * hyperparam_der); + tile.data()[i * N + j] = + factor * distance.data()[i * N + j] * exp(distance.data()[i * N + j]) * hyperparam_der; } } return tile; @@ -161,11 +158,8 @@ double update_second_moment(double gradient, double v_T, double beta_2) return beta_2 * v_T + (1.0 - beta_2) * gradient * gradient; } -double adam_step(const double unconstrained_hyperparam, - const gprat_hyper::AdamParams &adam_params, - double m_T, - double v_T, - std::size_t iter) +double adam_step( + const double unconstrained_hyperparam, const AdamParams &adam_params, double m_T, double v_T, std::size_t iter) { // Compute decay rate double beta1_T = pow(adam_params.beta1, static_cast(iter + 1)); @@ -184,9 +178,9 @@ double adam_step(const double unconstrained_hyperparam, ///////////////////////////////////////////////////////////////////////// // Loss -double compute_loss(const std::vector &K_diag_tile, - const std::vector &alpha_tile, - const std::vector &y_tile, +double compute_loss(std::span K_diag_tile, + std::span alpha_tile, + std::span y_tile, std::size_t N) { // l = y^T * alpha + \sum_i^N log(L_ii^2) @@ -202,7 +196,7 @@ double compute_loss(const std::vector &K_diag_tile, return l; } -double add_losses(const std::vector &losses, std::size_t N, std::size_t n_tiles) +double add_losses(std::span losses, std::size_t N, std::size_t n_tiles) { // 0.5 * \sum losses + const double l = 0.0; @@ -224,17 +218,17 @@ double compute_gradient(double trace, double dot, std::size_t N, std::size_t n_t return 0.5 / static_cast(N * n_tiles) * (trace - dot); } -double compute_trace(const std::vector &diagonal, double trace) +double compute_trace(std::span diagonal, double trace) { return trace + std::reduce(diagonal.begin(), diagonal.end()); } -double compute_dot(const std::vector &vector_T, const std::vector &vector, double result) +double compute_dot(std::span vector_T, std::span vector, double result) { return result + dot(vector_T, vector, static_cast(vector.size())); } -double compute_trace_diag(const std::vector &tile, double trace, std::size_t N) +double compute_trace_diag(std::span tile, double trace, std::size_t N) { double local_trace = 0.0; for (std::size_t i = 0; i < N; ++i) @@ -245,3 +239,5 @@ double compute_trace_diag(const std::vector &tile, double trace, std::si } } // end of namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/gp_optimizer_actions.cpp b/core/src/cpu/gp_optimizer_actions.cpp new file mode 100644 index 00000000..222c23d0 --- /dev/null +++ b/core/src/cpu/gp_optimizer_actions.cpp @@ -0,0 +1,97 @@ +#include "gprat/cpu/gp_optimizer_actions.hpp" + +#include + +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_covariance_with_distance, + GPRAT_NS::cpu::gen_tile_covariance_with_distance_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_grad_l, GPRAT_NS::cpu::gen_tile_grad_l_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::gen_tile_grad_v, GPRAT_NS::cpu::gen_tile_grad_v_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_loss, GPRAT_NS::cpu::compute_loss_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_trace, GPRAT_NS::cpu::compute_trace_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_dot, GPRAT_NS::cpu::compute_dot_distributed_action) +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::compute_trace_diag, GPRAT_NS::cpu::compute_trace_diag_distributed_action) + +GPRAT_NS_BEGIN + +namespace cpu +{ + +hpx::future> gen_tile_covariance_with_distance_distributed( + const tile_handle &tile, + std::size_t row, + std::size_t col, + std::size_t N, + const SEKParams &sek_params, + const const_tile_data &distance) +{ + return tile.set_async(cpu::gen_tile_covariance_with_distance(row, col, N, sek_params, distance)); +} + +hpx::future> gen_tile_grad_l_distributed( + const tile_handle &tile, + std::size_t N, + const SEKParams &sek_params, + const const_tile_data &distance) +{ + return tile.set_async(cpu::gen_tile_grad_l(N, sek_params, distance)); +} + +hpx::future> gen_tile_grad_v_distributed( + const tile_handle &tile, + std::size_t N, + const SEKParams &sek_params, + const const_tile_data &distance) +{ + return tile.set_async(cpu::gen_tile_grad_v(N, sek_params, distance)); +} + +hpx::future compute_loss_distributed(const tile_handle &K_diag_tile, + const tile_handle &alpha_tile, + const tile_handle &y_tile, + std::size_t N) +{ + return hpx::dataflow( + hpx::launch::async, + [=](hpx::future> &&K_diag_tiled, + hpx::future> &&alpha_tiled, + hpx::future> &&y_tiled) { + return cpu::compute_loss( + K_diag_tiled.get().as_span(), alpha_tiled.get().as_span(), y_tiled.get().as_span(), N); + }, + K_diag_tile.get_async(), + alpha_tile.get_async(), + y_tile.get_async()); +} + +hpx::future compute_trace_distributed(const tile_handle &diagonal, double trace) +{ + return hpx::dataflow( + hpx::launch::async, + [=](hpx::future> &&diagonald) + { return cpu::compute_trace(diagonald.get().as_span(), trace); }, + diagonal.get_async()); +} + +hpx::future +compute_dot_distributed(const tile_handle &vector_T, const tile_handle &vector, double result) +{ + return hpx::dataflow( + hpx::launch::async, + [=](hpx::future> &&vector_Td, hpx::future> &&vectord) + { return cpu::compute_dot(vector_Td.get().as_span(), vectord.get().as_span(), result); }, + vector_T.get_async(), + vector.get_async()); +} + +hpx::future compute_trace_diag_distributed(const tile_handle &tile, double trace, std::size_t N) +{ + return hpx::dataflow( + hpx::launch::async, + [=](hpx::future> &&tiled) + { return cpu::compute_trace_diag(tiled.get().as_span(), trace, N); }, + tile.get_async()); +} + +} // namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/gp_uncertainty.cpp b/core/src/cpu/gp_uncertainty.cpp index 3ea6a7a9..5f03366f 100644 --- a/core/src/cpu/gp_uncertainty.cpp +++ b/core/src/cpu/gp_uncertainty.cpp @@ -1,21 +1,22 @@ -#include "cpu/gp_uncertainty.hpp" +#include "gprat/cpu/gp_uncertainty.hpp" + +#include "gprat/tile_data.hpp" + +GPRAT_NS_BEGIN namespace cpu { -hpx::shared_future> get_matrix_diagonal(hpx::shared_future> f_A, std::size_t M) +mutable_tile_data get_matrix_diagonal(const const_tile_data &A, std::size_t M) { - auto A = f_A.get(); - // Preallocate memory - std::vector tile; - tile.reserve(M); - // Add elements + mutable_tile_data tile(M); for (std::size_t i = 0; i < M; ++i) { - tile.push_back(A[i * M + i]); + tile.data()[i] = A.data()[i * M + i]; } - - return hpx::make_ready_future(std::move(tile)); + return tile; } } // end of namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/gp_uncertainty_actions.cpp b/core/src/cpu/gp_uncertainty_actions.cpp new file mode 100644 index 00000000..d760f5c4 --- /dev/null +++ b/core/src/cpu/gp_uncertainty_actions.cpp @@ -0,0 +1,23 @@ +#include "gprat/cpu/gp_uncertainty_actions.hpp" + +#include + +GPRAT_DEFINE_PLAIN_ACTION_FOR(&GPRAT_NS::cpu::get_matrix_diagonal, + GPRAT_NS::cpu::get_matrix_diagonal_distributed_action) + +GPRAT_NS_BEGIN + +namespace cpu +{ +hpx::future> get_matrix_diagonal_distributed(const tile_handle &A, std::size_t M) +{ + return hpx::dataflow( + hpx::launch::async, + [A, M](hpx::future> &&Ad) + { return A.set_async(cpu::get_matrix_diagonal(Ad.get(), M)); }, + A.get_async()); +} + +} // namespace cpu + +GPRAT_NS_END diff --git a/core/src/cpu/tiled_algorithms.cpp b/core/src/cpu/tiled_algorithms.cpp index 5c5b2573..d035b89d 100644 --- a/core/src/cpu/tiled_algorithms.cpp +++ b/core/src/cpu/tiled_algorithms.cpp @@ -1,429 +1,31 @@ -#include "cpu/tiled_algorithms.hpp" +#include "gprat/cpu/tiled_algorithms.hpp" -#include "cpu/adapter_cblas_fp64.hpp" -#include "cpu/gp_algorithms.hpp" -#include "cpu/gp_optimizer.hpp" -#include "cpu/gp_uncertainty.hpp" -#include +#include "gprat/cpu/adapter_cblas_fp64.hpp" +#include "gprat/cpu/gp_algorithms.hpp" +#include "gprat/cpu/gp_optimizer.hpp" -namespace cpu -{ - -// Tiled Cholesky Algorithm - -void right_looking_cholesky_tiled(Tiled_matrix &ft_tiles, int N, std::size_t n_tiles) -{ - for (std::size_t k = 0; k < n_tiles; k++) - { - // POTRF: Compute Cholesky factor L - ft_tiles[k * n_tiles + k] = - hpx::dataflow(hpx::annotated_function(potrf, "cholesky_tiled"), ft_tiles[k * n_tiles + k], N); - for (std::size_t m = k + 1; m < n_tiles; m++) - { - // TRSM: Solve X * L^T = A - ft_tiles[m * n_tiles + k] = hpx::dataflow( - hpx::annotated_function(trsm, "cholesky_tiled"), - ft_tiles[k * n_tiles + k], - ft_tiles[m * n_tiles + k], - N, - N, - Blas_trans, - Blas_right); - } - for (std::size_t m = k + 1; m < n_tiles; m++) - { - // SYRK: A = A - B * B^T - ft_tiles[m * n_tiles + m] = hpx::dataflow( - hpx::annotated_function(syrk, "cholesky_tiled"), - ft_tiles[m * n_tiles + m], - ft_tiles[m * n_tiles + k], - N); - for (std::size_t n = k + 1; n < m; n++) - { - // GEMM: C = C - A * B^T - ft_tiles[m * n_tiles + n] = hpx::dataflow( - hpx::annotated_function(gemm, "cholesky_tiled"), - ft_tiles[m * n_tiles + k], - ft_tiles[n * n_tiles + k], - ft_tiles[m * n_tiles + n], - N, - N, - N, - Blas_no_trans, - Blas_trans); - } - } - } -} - -// Tiled Triangular Solve Algorithms - -void forward_solve_tiled(Tiled_matrix &ft_tiles, Tiled_vector &ft_rhs, int N, std::size_t n_tiles) -{ - for (std::size_t k = 0; k < n_tiles; k++) - { - // TRSM: Solve L * x = a - ft_rhs[k] = hpx::dataflow( - hpx::annotated_function(trsv, "triangular_solve_tiled"), - ft_tiles[k * n_tiles + k], - ft_rhs[k], - N, - Blas_no_trans); - for (std::size_t m = k + 1; m < n_tiles; m++) - { - // GEMV: b = b - A * a - ft_rhs[m] = hpx::dataflow( - hpx::annotated_function(gemv, "triangular_solve_tiled"), - ft_tiles[m * n_tiles + k], - ft_rhs[k], - ft_rhs[m], - N, - N, - Blas_substract, - Blas_no_trans); - } - } -} - -void backward_solve_tiled(Tiled_matrix &ft_tiles, Tiled_vector &ft_rhs, int N, std::size_t n_tiles) -{ - for (int k_ = static_cast(n_tiles) - 1; k_ >= 0; k_--) // int instead of std::size_t for last comparison - { - std::size_t k = static_cast(k_); - // TRSM: Solve L^T * x = a - ft_rhs[k] = hpx::dataflow( - hpx::annotated_function(trsv, "triangular_solve_tiled"), - ft_tiles[k * n_tiles + k], - ft_rhs[k], - N, - Blas_trans); - for (int m_ = k_ - 1; m_ >= 0; m_--) // int instead of std::size_t for last comparison - { - std::size_t m = static_cast(m_); - // GEMV:b = b - A^T * a - ft_rhs[m] = hpx::dataflow( - hpx::annotated_function(gemv, "triangular_solve_tiled"), - ft_tiles[k * n_tiles + m], - ft_rhs[k], - ft_rhs[m], - N, - N, - Blas_substract, - Blas_trans); - } - } -} - -void forward_solve_tiled_matrix( - Tiled_matrix &ft_tiles, Tiled_matrix &ft_rhs, int N, int M, std::size_t n_tiles, std::size_t m_tiles) -{ - for (std::size_t c = 0; c < m_tiles; c++) - { - for (std::size_t k = 0; k < n_tiles; k++) - { - // TRSM: solve L * X = A - ft_rhs[k * m_tiles + c] = hpx::dataflow( - hpx::annotated_function(trsm, "triangular_solve_tiled_matrix"), - ft_tiles[k * n_tiles + k], - ft_rhs[k * m_tiles + c], - N, - M, - Blas_no_trans, - Blas_left); - for (std::size_t m = k + 1; m < n_tiles; m++) - { - // GEMM: C = C - A * B - ft_rhs[m * m_tiles + c] = hpx::dataflow( - hpx::annotated_function(gemm, "triangular_solve_tiled_matrix"), - ft_tiles[m * n_tiles + k], - ft_rhs[k * m_tiles + c], - ft_rhs[m * m_tiles + c], - N, - M, - N, - Blas_no_trans, - Blas_no_trans); - } - } - } -} - -void backward_solve_tiled_matrix( - Tiled_matrix &ft_tiles, Tiled_matrix &ft_rhs, int N, int M, std::size_t n_tiles, std::size_t m_tiles) -{ - for (std::size_t c = 0; c < m_tiles; c++) - { - for (int k_ = static_cast(n_tiles) - 1; k_ >= 0; k_--) // int instead of std::size_t for last comparison - { - std::size_t k = static_cast(k_); - // TRSM: solve L^T * X = A - ft_rhs[k * m_tiles + c] = hpx::dataflow( - hpx::annotated_function(trsm, "triangular_solve_tiled_matrix"), - ft_tiles[k * n_tiles + k], - ft_rhs[k * m_tiles + c], - N, - M, - Blas_trans, - Blas_left); - for (int m_ = k_ - 1; m_ >= 0; m_--) // int instead of std::size_t for last comparison - { - std::size_t m = static_cast(m_); - // GEMM: C = C - A^T * B - ft_rhs[m * m_tiles + c] = hpx::dataflow( - hpx::annotated_function(gemm, "triangular_solve_tiled_matrix"), - ft_tiles[k * n_tiles + m], - ft_rhs[k * m_tiles + c], - ft_rhs[m * m_tiles + c], - N, - M, - N, - Blas_trans, - Blas_no_trans); - } - } - } -} - -void matrix_vector_tiled(Tiled_matrix &ft_tiles, - Tiled_vector &ft_vector, - Tiled_vector &ft_rhs, - int N_row, - int N_col, - std::size_t n_tiles, - std::size_t m_tiles) -{ - for (std::size_t k = 0; k < m_tiles; k++) - { - for (std::size_t m = 0; m < n_tiles; m++) - { - ft_rhs[k] = hpx::dataflow( - hpx::annotated_function(gemv, "prediction_tiled"), - ft_tiles[k * n_tiles + m], - ft_vector[m], - ft_rhs[k], - N_row, - N_col, - Blas_add, - Blas_no_trans); - } - } -} - -void symmetric_matrix_matrix_diagonal_tiled( - Tiled_matrix &ft_tiles, Tiled_vector &ft_vector, int N, int M, std::size_t n_tiles, std::size_t m_tiles) -{ - for (std::size_t i = 0; i < m_tiles; ++i) - { - for (std::size_t n = 0; n < n_tiles; ++n) - { // Compute inner product to obtain diagonal elements of - // V^T * V <=> cross(K) * K^-1 * cross(K)^T - ft_vector[i] = hpx::dataflow( - hpx::annotated_function(dot_diag_syrk, "posterior_tiled"), - ft_tiles[n * m_tiles + i], - ft_vector[i], - N, - M); - } - } -} - -void symmetric_matrix_matrix_tiled( - Tiled_matrix &ft_tiles, Tiled_matrix &ft_result, int N, int M, std::size_t n_tiles, std::size_t m_tiles) -{ - for (std::size_t c = 0; c < m_tiles; c++) - { - for (std::size_t k = 0; k < m_tiles; k++) - { - for (std::size_t m = 0; m < n_tiles; m++) - { - // (SYRK for (c == k) possible) - // GEMM: C = C - A^T * B - ft_result[c * m_tiles + k] = hpx::dataflow( - hpx::annotated_function(&gemm, "triangular_solve_tiled_matrix"), - ft_tiles[m * m_tiles + c], - ft_tiles[m * m_tiles + k], - ft_result[c * m_tiles + k], - N, - M, - M, - Blas_trans, - Blas_no_trans); - } - } - } -} - -void vector_difference_tiled(Tiled_vector &ft_minuend, Tiled_vector &ft_subtrahend, int M, std::size_t m_tiles) -{ - for (std::size_t i = 0; i < m_tiles; i++) - { - ft_subtrahend[i] = - hpx::dataflow(hpx::annotated_function(&axpy, "uncertainty_tiled"), ft_minuend[i], ft_subtrahend[i], M); - } -} +GPRAT_NS_BEGIN -void matrix_diagonal_tiled(Tiled_matrix &ft_tiles, Tiled_vector &ft_vector, int M, std::size_t m_tiles) +namespace cpu { - for (std::size_t i = 0; i < m_tiles; i++) - { - ft_vector[i] = hpx::dataflow( - hpx::annotated_function(get_matrix_diagonal, "uncertainty_tiled"), ft_tiles[i * m_tiles + i], M); - } -} -void compute_loss_tiled(Tiled_matrix &ft_tiles, - Tiled_vector &ft_alpha, - Tiled_vector &ft_y, - hpx::shared_future &loss, - int N, - std::size_t n_tiles) +namespace impl { - std::vector> loss_tiled; - loss_tiled.reserve(n_tiles); - for (std::size_t k = 0; k < n_tiles; k++) - { - loss_tiled.push_back(hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&compute_loss), "loss_tiled"), - ft_tiles[k * n_tiles + k], - ft_alpha[k], - ft_y[k], - N)); - } - - loss = hpx::dataflow(hpx::annotated_function(hpx::unwrapping(&add_losses), "loss_tiled"), loss_tiled, N, n_tiles); -} -void update_hyperparameter_tiled( - const Tiled_matrix &ft_invK, - const Tiled_matrix &ft_gradK_param, - const Tiled_vector &ft_alpha, - const gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, - int N, +void update_parameters( + const AdamParams &adam_params, + SEKParams &sek_params, + std::size_t N, std::size_t n_tiles, std::size_t iter, - std::size_t param_idx) + std::size_t param_idx, + double trace, + double dot, + bool jitter, + double factor) { - /* - * PART 1: - * Compute gradient = 0.5 * ( trace(inv(K) * grad(K)_param) + y^T * inv(K) * grad(K)_param * inv(K) * y ) - * - * 1: Compute trace(inv(K) * grad(K)_param) - * 2: Compute y^T * inv(K) * grad(K)_param * inv(K) * y - * - * Update parameter: - * 3: Update moments - * - m_T = beta1 * m_T-1 + (1 - beta1) * g_T - * - w_T = beta2 + w_T-1 + (1 - beta2) * g_T^2 - * 4: Adam step: - * - nu_T = nu * sqrt(1 - beta2_T) / (1 - beta1_T) - * - theta_T = theta_T-1 - nu_T * m_T / (sqrt(w_T) + epsilon) - */ - hpx::shared_future trace = hpx::make_ready_future(0.0); - hpx::shared_future dot = hpx::make_ready_future(0.0); - bool jitter = false; - double factor = 1.0; - if (param_idx == 0 || param_idx == 1) // 0: lengthscale; 1: vertical_lengthscale - { - Tiled_vector diag_tiles; // Diagonal tiles - Tiled_vector inter_alpha; // Intermediate result - // Preallocate memory - inter_alpha.reserve(n_tiles); - diag_tiles.reserve(n_tiles); - // Asynchrnonous initialization - for (std::size_t d = 0; d < n_tiles; d++) - { - diag_tiles.push_back(hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble"), N)); - inter_alpha.push_back(hpx::async(hpx::annotated_function(gen_tile_zeros, "assemble"), N)); - } - - //////////////////////////////////// - // PART 1: Compute gradient - // Step 1: Compute trace(inv(K)*grad_K_param) - // Compute diagonal tiles of inv(K) * grad(K)_param - for (std::size_t i = 0; i < n_tiles; ++i) - { - for (std::size_t j = 0; j < n_tiles; ++j) - { - diag_tiles[i] = hpx::dataflow( - hpx::annotated_function(dot_diag_gemm, "trace"), - ft_invK[i * n_tiles + j], - ft_gradK_param[j * n_tiles + i], - diag_tiles[i], - N, - N); - } - } - // Compute the trace of the diagonal tiles - for (std::size_t j = 0; j < n_tiles; ++j) - { - trace = - hpx::dataflow(hpx::annotated_function(hpx::unwrapping(&compute_trace), "trace"), diag_tiles[j], trace); - } - // Not sure if can be done this way - // Step 2: Compute alpha^T * grad(K)_param * alpha (with alpha = inv(K) * y) - // Compute inter_alpha = grad(K)_param * alpha - for (std::size_t k = 0; k < n_tiles; k++) - { - for (std::size_t m = 0; m < n_tiles; m++) - { - inter_alpha[k] = hpx::dataflow( - hpx::annotated_function(gemv, "gemv"), - ft_gradK_param[k * n_tiles + m], - ft_alpha[m], - inter_alpha[k], - N, - N, - Blas_add, - Blas_no_trans); - } - } - // Compute alpha^T * inter_alpha - for (std::size_t j = 0; j < n_tiles; ++j) - { - dot = hpx::dataflow(hpx::annotated_function(hpx::unwrapping(&compute_dot), "grad_right_tiled"), - inter_alpha[j], - ft_alpha[j], - dot); - } - } - else if (param_idx == 2) // @2: noise_variance - { - jitter = true; - //////////////////////////////////// - // PART 1: Compute gradient - // Step 1: Compute the trace of inv(K) * noise_variance - for (std::size_t j = 0; j < n_tiles; ++j) - { - trace = hpx::dataflow(hpx::annotated_function(hpx::unwrapping(&compute_trace_diag), "grad_left_tiled"), - ft_invK[j * n_tiles + j], - trace, - N); - } - //////////////////////////////////// - // Step 2: Compute the alpha^T * alpha * noise_variance - for (std::size_t j = 0; j < n_tiles; ++j) - { - dot = hpx::dataflow(hpx::annotated_function(hpx::unwrapping(&compute_dot), "grad_right_tiled"), - ft_alpha[j], - ft_alpha[j], - dot); - } - - factor = compute_sigmoid(to_unconstrained(sek_params.noise_variance, true)); - } - else - { - // Throw an exception for invalid param_idx - throw std::invalid_argument("Invalid param_idx"); - } - // Compute gradient = trace + dot - double gradient = - factor - * hpx::dataflow( - hpx::annotated_function(hpx::unwrapping(&compute_gradient), "update_hyperparam"), trace, dot, N, n_tiles) - .get(); + double gradient = factor * compute_gradient(trace, dot, N, n_tiles); //////////////////////////////////// // PART 2: Update parameter @@ -437,14 +39,14 @@ void update_hyperparameter_tiled( double unconstrained_param = to_unconstrained(sek_params.get_param(param_idx), jitter); // Adam step update with unconstrained parameter // compute beta_t inside - double updated_param = adam_step( - unconstrained_param, - adam_params, - sek_params.m_T[param_idx], - sek_params.w_T[param_idx], - static_cast(iter)); + double updated_param = + adam_step(unconstrained_param, adam_params, sek_params.m_T[param_idx], sek_params.w_T[param_idx], iter); // Transform hyperparameter back to constrained form sek_params.set_param(param_idx, to_constrained(updated_param, jitter)); } +} // namespace impl + } // end of namespace cpu + +GPRAT_NS_END diff --git a/core/src/gprat.cpp b/core/src/gprat.cpp new file mode 100644 index 00000000..4a5fbf47 --- /dev/null +++ b/core/src/gprat.cpp @@ -0,0 +1,395 @@ +#include "gprat/gprat.hpp" + +#include "gprat/cpu/gp_functions.hpp" +#include "gprat/utils.hpp" + +#if GPRAT_WITH_DISTRIBUTED +#include "gprat/tiled_dataset.hpp" +#endif + +#if GPRAT_WITH_CUDA +#include "gprat/gpu/gp_functions.cuh" +#endif + +#if GPRAT_WITH_SYCL +#include "gprat/target.hpp" + +#include "gpu/sycl/sycl_gp_functions.hpp" +#endif + +GPRAT_NS_BEGIN + +GP_data::GP_data(const std::string &f_path, std::size_t n, std::size_t n_reg) : + file_path(f_path), + n_samples(n), + n_regressors(n_reg) +{ + data = load_data(f_path, n, n_reg - 1); +} + +// Generic type constructor of class GP /////////////////////////////////////////////////////////////////////////////// +GP::GP(std::vector input, + std::vector output, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + const std::vector &kernel_hyperparams, + std::vector trainable_bool, + std::shared_ptr target) : + training_input_(std::move(input)), + training_output_(std::move(output)), + n_tiles_(n_tiles), + n_tile_size_(n_tile_size), + trainable_params_(std::move(trainable_bool)), + target_(std::move(target)), + n_reg(n_regressors), + kernel_params(kernel_hyperparams[0], kernel_hyperparams[1], kernel_hyperparams[2]) +{ } + +// CPU-type constructor of class GP /////////////////////////////////////////////////////////////////////////////////// +GP::GP(std::vector input, + std::vector output, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + const std::vector &kernel_hyperparams, + std::vector trainable_bool) : + training_input_(std::move(input)), + training_output_(std::move(output)), + n_tiles_(n_tiles), + n_tile_size_(n_tile_size), + trainable_params_(std::move(trainable_bool)), + target_(std::make_shared()), + n_reg(n_regressors), + kernel_params(kernel_hyperparams[0], kernel_hyperparams[1], kernel_hyperparams[2]) +{ } + +/// GPU constructor /////////////////////////////////////////////////////////////////////////////////////////////////// +GP::GP(std::vector input, + std::vector output, + std::size_t n_tiles, + std::size_t n_tile_size, + std::size_t n_regressors, + const std::vector &kernel_hyperparams, + std::vector trainable_bool, + int gpu_id, + int n_streams) : + training_input_(std::move(input)), + training_output_(std::move(output)), + n_tiles_(n_tiles), + n_tile_size_(n_tile_size), + trainable_params_(std::move(trainable_bool)), +#if GPRAT_WITH_CUDA + target_(std::make_shared(CUDA_GPU(gpu_id, n_streams))), + +#elif GPRAT_WITH_SYCL + target_(std::make_shared(SYCL_DEVICE(gpu_id, n_streams))), + +#else + target_(std::make_shared()), + +#endif + n_reg(n_regressors), + kernel_params(kernel_hyperparams[0], kernel_hyperparams[1], kernel_hyperparams[2]) +{ +#if !GPRAT_WITH_CUDA && !GPRAT_WITH_SYCL + throw std::runtime_error( + "Cannot create GP object using CUDA or SYCL for computation. " + "CUDA and SYCL are not available because GPRat has been compiled without CUDA and SYCL support. " + "Remove arguments gpu_id (" + + std::to_string(gpu_id) + ") and n_streams (" + std::to_string(n_streams) + + ") to perform computations on the CPU."); +#endif +} + +std::string GP::repr() const +{ + std::ostringstream oss; + oss << std::fixed << std::setprecision(12); + oss << "Kernel_Params: [lengthscale=" << kernel_params.lengthscale << ", vertical_lengthscale=" + << kernel_params.vertical_lengthscale << ", noise_variance=" << kernel_params.noise_variance + << ", n_regressors=" << n_reg << "], Trainable_Params: [trainable_params l=" << trainable_params_[0] + << ", trainable_params v=" << trainable_params_[1] << ", trainable_params n=" << trainable_params_[2] + << "], Target: [" << target_->repr() << "], n_tiles=" << n_tiles_ << ", n_tile_size=" << n_tile_size_; + return oss.str(); +} + +std::vector GP::get_training_input() const { return training_input_; } + +std::vector GP::get_training_output() const { return training_output_; } + +std::vector GP::predict(const std::vector &test_input, std::size_t m_tiles, std::size_t m_tile_size) +{ +#if GPRAT_WITH_CUDA + if (target_->is_gpu()) + { + return gpu::predict( + training_input_, + training_output_, + test_input, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif +#if GPRAT_WITH_SYCL + if (target_->is_sycl()) + { + return sycl_backend::predict( + training_input_, + training_output_, + test_input, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif + + tiled_scheduler_local scheduler; + return cpu::predict( + scheduler, + training_input_, + training_output_, + test_input, + kernel_params, + n_tiles_, + n_tile_size_, + m_tiles, + m_tile_size, + n_reg); +} + +// predict_with_uncertainty /////////////////////////////////////////////////////////////////////////////////////////// +std::vector> +GP::predict_with_uncertainty(const std::vector &test_input, std::size_t m_tiles, std::size_t m_tile_size) +{ +#if GPRAT_WITH_CUDA + if (target_->is_gpu()) + { + return gpu::predict_with_uncertainty( + training_input_, + training_output_, + test_input, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif +#if GPRAT_WITH_SYCL + if (target_->is_sycl()) + { + return sycl_backend::predict_with_uncertainty( + training_input_, + training_output_, + test_input, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif + tiled_scheduler_local scheduler; + return cpu::predict_with_uncertainty( + scheduler, + training_input_, + training_output_, + test_input, + kernel_params, + n_tiles_, + n_tile_size_, + m_tiles, + m_tile_size, + n_reg); +} + +// predict_with_full_cov ////////////////////////////////////////////////////////////////////////////////////////////// +std::vector> +GP::predict_with_full_cov(const std::vector &test_input, std::size_t m_tiles, std::size_t m_tile_size) +{ +#if GPRAT_WITH_CUDA + if (target_->is_gpu()) + { + return gpu::predict_with_full_cov( + training_input_, + training_output_, + test_input, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif +#if GPRAT_WITH_SYCL + if (target_->is_sycl()) + { + return sycl_backend::predict_with_full_cov( + training_input_, + training_output_, + test_input, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif + tiled_scheduler_local scheduler; + return cpu::predict_with_full_cov( + scheduler, + training_input_, + training_output_, + test_input, + kernel_params, + n_tiles_, + n_tile_size_, + m_tiles, + m_tile_size, + n_reg); +} + +std::vector GP::optimize(const AdamParams &adam_params) +{ +#if GPRAT_WITH_CUDA || GPRAT_WITH_SYCL + if (target_->is_gpu() || target_->is_sycl()) + { + std::cerr << "GP::optimize is not implemented for GPU targets.\n" + << "Falling back to the CPU implementation." << std::endl; + } +#endif + tiled_scheduler_local scheduler; + return cpu::optimize( + scheduler, + training_input_, + training_output_, + n_tiles_, + n_tile_size_, + n_reg, + adam_params, + kernel_params, + trainable_params_); +} + +double GP::optimize_step(AdamParams &adam_params, std::size_t iter) +{ +#if GPRAT_WITH_CUDA || GPRAT_WITH_SYCL + if (target_->is_gpu() || target_->is_sycl()) + { + std::cerr << "GP::optimize_step is not implemented for GPU targets.\n" + << "Falling back to the CPU implementation." << std::endl; + } +#endif + tiled_scheduler_local scheduler; + return cpu::optimize_step( + scheduler, + training_input_, + training_output_, + n_tiles_, + n_tile_size_, + n_reg, + adam_params, + kernel_params, + trainable_params_, + iter); +} + +// calculate_loss ///////////////////////////////////////////////////////////////////////////////////////////////////// +double GP::calculate_loss() +{ +#if GPRAT_WITH_CUDA + if (target_->is_gpu()) + { + return gpu::compute_loss( + training_input_, + training_output_, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif +#if GPRAT_WITH_SYCL + if (target_->is_sycl()) + { + return sycl_backend::compute_loss( + training_input_, + training_output_, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif + tiled_scheduler_local scheduler; + return cpu::calculate_loss( + scheduler, training_input_, training_output_, kernel_params, n_tiles_, n_tile_size_, n_reg); +} + +std::vector> GP::cholesky() +{ +#if GPRAT_WITH_CUDA + if (target_->is_gpu()) + { + return gpu::cholesky( + training_input_, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + } +#endif +#if GPRAT_WITH_SYCL + if (target_->is_sycl()) + { + auto raw = sycl_backend::cholesky( + training_input_, + kernel_params, + static_cast(n_tiles_), + static_cast(n_tile_size_), + static_cast(n_reg), + *std::dynamic_pointer_cast(target_)); + std::vector> result; + result.reserve(raw.size()); + for (auto &tile : raw) + { + if (tile.empty()) + { + result.emplace_back(); + } + else + { + mutable_tile_data t(tile.size()); + std::copy(tile.begin(), tile.end(), t.begin()); + result.push_back(std::move(t)); + } + } + return result; + } +#endif + tiled_scheduler_local sched; + return cpu::cholesky(sched, training_input_, kernel_params, n_tiles_, n_tile_size_, n_reg); +} + +GPRAT_NS_END diff --git a/core/src/gprat_c.cpp b/core/src/gprat_c.cpp deleted file mode 100644 index c93e792c..00000000 --- a/core/src/gprat_c.cpp +++ /dev/null @@ -1,363 +0,0 @@ -#include "gprat_c.hpp" - -#include "cpu/gp_functions.hpp" -#include "utils_c.hpp" -#include - -#if GPRAT_WITH_CUDA -#include "gpu/gp_functions.cuh" -#endif - -// namespace for GPRat library entities -namespace gprat -{ - -GP_data::GP_data(const std::string &f_path, int n, int n_reg) : - file_path(f_path), - n_samples(n), - n_regressors(n_reg) -{ - data = utils::load_data(f_path, n, n_reg - 1); -} - -GP::GP(std::vector input, - std::vector output, - int n_tiles, - int n_tile_size, - int n_regressors, - std::vector kernel_hyperparams, - std::vector trainable_bool, - std::shared_ptr target) : - training_input_(input), - training_output_(output), - n_tiles_(n_tiles), - n_tile_size_(n_tile_size), - trainable_params_(trainable_bool), - target_(target), - n_reg(n_regressors), - kernel_params(kernel_hyperparams[0], kernel_hyperparams[1], kernel_hyperparams[2]) -{ } - -GP::GP(std::vector input, - std::vector output, - int n_tiles, - int n_tile_size, - int n_regressors, - std::vector kernel_hyperparams, - std::vector trainable_bool) : - training_input_(input), - training_output_(output), - n_tiles_(n_tiles), - n_tile_size_(n_tile_size), - trainable_params_(trainable_bool), - target_(std::make_shared()), - n_reg(n_regressors), - kernel_params(kernel_hyperparams[0], kernel_hyperparams[1], kernel_hyperparams[2]) -{ } - -GP::GP(std::vector input, - std::vector output, - int n_tiles, - int n_tile_size, - int n_regressors, - std::vector kernel_hyperparams, - std::vector trainable_bool, - int gpu_id, - int n_streams) : - training_input_(input), - training_output_(output), - n_tiles_(n_tiles), - n_tile_size_(n_tile_size), - trainable_params_(trainable_bool), -#if GPRAT_WITH_CUDA - target_(std::make_shared(CUDA_GPU(gpu_id, n_streams))), -#else - target_(std::make_shared()), -#endif - n_reg(n_regressors), - kernel_params(kernel_hyperparams[0], kernel_hyperparams[1], kernel_hyperparams[2]) -{ -#if !GPRAT_WITH_CUDA - throw std::runtime_error( - "Cannot create GP object using CUDA for computation. " - "CUDA is not available because GPRat has been compiled without CUDA. " - "Remove arguments gpu_id (" - + std::to_string(gpu_id) + ") and n_streams (" + std::to_string(n_streams) - + ") to perform computations on the CPU."); -#endif -} - -std::string GP::repr() const -{ - std::ostringstream oss; - oss << std::fixed << std::setprecision(12); - oss << "Kernel_Params: [lengthscale=" << kernel_params.lengthscale << ", vertical_lengthscale=" - << kernel_params.vertical_lengthscale << ", noise_variance=" << kernel_params.noise_variance - << ", n_regressors=" << n_reg << "], Trainable_Params: [trainable_params l=" << trainable_params_[0] - << ", trainable_params v=" << trainable_params_[1] << ", trainable_params n=" << trainable_params_[2] - << "], Target: [" << target_->repr() << "], n_tiles=" << n_tiles_ << ", n_tile_size=" << n_tile_size_; - return oss.str(); -} - -std::vector GP::get_training_input() const { return training_input_; } - -std::vector GP::get_training_output() const { return training_output_; } - -std::vector GP::predict(const std::vector &test_input, int m_tiles, int m_tile_size) -{ - return hpx::async( - [this, &test_input, m_tiles, m_tile_size]() - { -#if GPRAT_WITH_CUDA - if (target_->is_gpu()) - { - return gpu::predict( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg, - *std::dynamic_pointer_cast(target_)); - } - else - { - return cpu::predict( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg); - } -#else - return cpu::predict( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg); -#endif - }) - .get(); -} - -std::vector> -GP::predict_with_uncertainty(const std::vector &test_input, int m_tiles, int m_tile_size) -{ - return hpx::async( - [this, &test_input, m_tiles, m_tile_size]() - { -#if GPRAT_WITH_CUDA - if (target_->is_gpu()) - { - return gpu::predict_with_uncertainty( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg, - *std::dynamic_pointer_cast(target_)); - } - else - { - return cpu::predict_with_uncertainty( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg); - } -#else - return cpu::predict_with_uncertainty( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg); -#endif - }) - .get(); -} - -std::vector> -GP::predict_with_full_cov(const std::vector &test_input, int m_tiles, int m_tile_size) -{ - return hpx::async( - [this, &test_input, m_tiles, m_tile_size]() - { -#if GPRAT_WITH_CUDA - if (target_->is_gpu()) - { - return gpu::predict_with_full_cov( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg, - *std::dynamic_pointer_cast(target_)); - } - else - { - return cpu::predict_with_full_cov( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg); - } -#else - return cpu::predict_with_full_cov( - training_input_, - training_output_, - test_input, - kernel_params, - n_tiles_, - n_tile_size_, - m_tiles, - m_tile_size, - n_reg); -#endif - }) - .get(); -} - -std::vector GP::optimize(const gprat_hyper::AdamParams &adam_params) -{ - return hpx::async( - [this, &adam_params]() - { -#if GPRAT_WITH_CUDA - if (target_->is_gpu()) - { - std::cerr << "GP::optimze_step has not been implemented for the GPU.\n" - << "Instead, this operation executes the CPU implementation." << std::endl; - } -#endif - return cpu::optimize( - training_input_, - training_output_, - n_tiles_, - n_tile_size_, - n_reg, - adam_params, - kernel_params, - trainable_params_); - }) - .get(); -} - -double GP::optimize_step(gprat_hyper::AdamParams &adam_params, int iter) -{ - return hpx::async( - [this, &adam_params, iter]() - { -#if GPRAT_WITH_CUDA - if (target_->is_gpu()) - { - std::cerr << "GP::optimze_step has not been implemented for the GPU.\n" - << "Instead, this operation executes the CPU implementation." << std::endl; - } -#endif - return cpu::optimize_step( - training_input_, - training_output_, - n_tiles_, - n_tile_size_, - n_reg, - adam_params, - kernel_params, - trainable_params_, - iter); - }) - .get(); -} - -double GP::calculate_loss() -{ - return hpx::async( - [this]() - { -#if GPRAT_WITH_CUDA - if (target_->is_gpu()) - { - return gpu::compute_loss( - training_input_, - training_output_, - kernel_params, - n_tiles_, - n_tile_size_, - n_reg, - *std::dynamic_pointer_cast(target_)); - } - else - { - return cpu::compute_loss( - training_input_, training_output_, kernel_params, n_tiles_, n_tile_size_, n_reg); - } -#else - return cpu::compute_loss( - training_input_, training_output_, kernel_params, n_tiles_, n_tile_size_, n_reg); -#endif - }) - .get(); -} - -std::vector> GP::cholesky() -{ - return hpx::async( - [this]() - { -#if GPRAT_WITH_CUDA - if (target_->is_gpu()) - { - return gpu::cholesky( - training_input_, - kernel_params, - n_tiles_, - n_tile_size_, - n_reg, - *std::dynamic_pointer_cast(target_)); - } - else - { - return cpu::cholesky(training_input_, kernel_params, n_tiles_, n_tile_size_, n_reg); - } -#else - return cpu::cholesky(training_input_, kernel_params, n_tiles_, n_tile_size_, n_reg); -#endif - }) - .get(); -} - -} // namespace gprat diff --git a/core/src/gpu/adapter_cublas.cu b/core/src/gpu/cuda/adapter_cublas.cu similarity index 92% rename from core/src/gpu/adapter_cublas.cu rename to core/src/gpu/cuda/adapter_cublas.cu index 61227e8d..d7b26511 100644 --- a/core/src/gpu/adapter_cublas.cu +++ b/core/src/gpu/cuda/adapter_cublas.cu @@ -1,4 +1,6 @@ -#include "gpu/adapter_cublas.cuh" +#include "gprat/gpu/adapter_cublas.cuh" + +GPRAT_NS_BEGIN // frequently used names using hpx::cuda::experimental::check_cuda_error; @@ -40,6 +42,9 @@ potrf(cusolverDnHandle_t cusolver, cudaStream_t stream, hpx::shared_future(malloc(workspaceInBytesOnHost)); if (h_work == nullptr) { + check_cuda_error(cudaFree(d_work)); + check_cuda_error(cudaFree(d_info)); + cusolverDnDestroyParams(params); throw std::runtime_error("Error: h_work not allocated."); } } @@ -51,21 +56,35 @@ potrf(cusolverDnHandle_t cusolver, cudaStream_t stream, hpx::shared_future #include #include +GPRAT_NS_BEGIN + namespace gpu { @@ -20,7 +24,7 @@ __global__ void gen_tile_covariance_kernel( const std::size_t n_regressors, const std::size_t tile_row, const std::size_t tile_column, - const gprat_hyper::SEKParams sek_params) + const SEKParams sek_params) { // Compute the global indices of the thread unsigned int i = blockIdx.y * blockDim.y + threadIdx.y; @@ -59,8 +63,8 @@ double *gen_tile_covariance(const double *d_input, const std::size_t tile_column, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { double *d_tile; @@ -85,7 +89,7 @@ __global__ void gen_tile_full_prior_covariance_kernel( const std::size_t n_regressors, const std::size_t tile_row, const std::size_t tile_column, - const gprat_hyper::SEKParams sek_params) + const SEKParams sek_params) { unsigned int i = blockIdx.y * blockDim.y + threadIdx.y; unsigned int j = blockIdx.x * blockDim.x + threadIdx.x; @@ -117,8 +121,8 @@ double *gen_tile_full_prior_covariance( const std::size_t tile_colums, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { double *d_tile; @@ -143,7 +147,7 @@ __global__ void gen_tile_prior_covariance_kernel( const std::size_t n_regressors, const std::size_t tile_row, const std::size_t tile_column, - const gprat_hyper::SEKParams sek_params) + const SEKParams sek_params) { unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; @@ -174,8 +178,8 @@ double *gen_tile_prior_covariance( const std::size_t tile_column, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { double *d_tile; @@ -202,7 +206,7 @@ __global__ void gen_tile_cross_covariance_kernel( const std::size_t tile_row, const std::size_t tile_column, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params) + const SEKParams sek_params) { unsigned int i = blockIdx.y * blockDim.y + threadIdx.y; unsigned int j = blockIdx.x * blockDim.x + threadIdx.x; @@ -235,8 +239,8 @@ double *gen_tile_cross_covariance( const std::size_t n_row_tile_size, const std::size_t n_column_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { double *d_tile; @@ -265,7 +269,7 @@ double *gen_tile_cross_covariance( hpx::shared_future gen_tile_cross_cov_T(std::size_t n_row_tile_size, std::size_t n_column_tile_size, const hpx::shared_future f_cross_covariance_tile, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { double *transposed; check_cuda_error(cudaMalloc(&transposed, n_row_tile_size * n_column_tile_size * sizeof(double))); @@ -293,8 +297,7 @@ __global__ void gen_tile_output_kernel(double *tile, const double *output, std:: } } -double * -gen_tile_output(const std::size_t row, const std::size_t n_tile_size, const double *d_output, gprat::CUDA_GPU &gpu) +double *gen_tile_output(const std::size_t row, const std::size_t n_tile_size, const double *d_output, CUDA_GPU &gpu) { dim3 threads_per_block(256); dim3 n_blocks((n_tile_size + 255) / 256); @@ -311,7 +314,7 @@ gen_tile_output(const std::size_t row, const std::size_t n_tile_size, const doub return d_tile; } -double *gen_tile_zeros(std::size_t n_tile_size, gprat::CUDA_GPU &gpu) +double *gen_tile_zeros(std::size_t n_tile_size, CUDA_GPU &gpu) { double *d_tile; cudaStream_t stream = gpu.next_stream(); @@ -345,8 +348,8 @@ std::vector> assemble_tiled_covariance_matrix( const std::size_t n_tiles, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { std::vector> d_tiles(n_tiles * n_tiles); @@ -369,8 +372,8 @@ std::vector> assemble_tiled_covariance_matrix( return d_tiles; } -std::vector> assemble_alpha_tiles( - const double *d_output, const std::size_t n_tiles, const std::size_t n_tile_size, gprat::CUDA_GPU &gpu) +std::vector> +assemble_alpha_tiles(const double *d_output, const std::size_t n_tiles, const std::size_t n_tile_size, CUDA_GPU &gpu) { std::vector> alpha_tiles(n_tiles); for (std::size_t i = 0; i < n_tiles; i++) @@ -390,8 +393,8 @@ std::vector> assemble_cross_covariance_tiles( const std::size_t m_tile_size, const std::size_t n_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { std::vector> cross_covariance_tiles; cross_covariance_tiles.resize(m_tiles * n_tiles); @@ -416,7 +419,7 @@ std::vector> assemble_cross_covariance_tiles( } std::vector> -assemble_tiles_with_zeros(std::size_t n_tile_size, std::size_t n_tiles, gprat::CUDA_GPU &gpu) +assemble_tiles_with_zeros(std::size_t n_tile_size, std::size_t n_tiles, CUDA_GPU &gpu) { std::vector> tiles(n_tiles); for (std::size_t i = 0; i < n_tiles; i++) @@ -431,8 +434,8 @@ std::vector> assemble_prior_K_tiles( const std::size_t m_tiles, const std::size_t m_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { std::vector> d_prior_K_tiles; d_prior_K_tiles.resize(m_tiles); @@ -449,8 +452,8 @@ std::vector> assemble_prior_K_tiles_full( const std::size_t m_tiles, const std::size_t m_tile_size, const std::size_t n_regressors, - const gprat_hyper::SEKParams sek_params, - gprat::CUDA_GPU &gpu) + const SEKParams sek_params, + CUDA_GPU &gpu) { std::vector> d_prior_K_tiles(m_tiles * m_tiles); for (std::size_t i = 0; i < m_tiles; i++) @@ -483,7 +486,7 @@ std::vector> assemble_t_cross_covariance_tiles( const std::size_t m_tiles, const std::size_t n_tile_size, const std::size_t m_tile_size, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { std::vector> d_t_cross_covariance_tiles(m_tiles * n_tiles); for (std::size_t i = 0; i < m_tiles; i++) @@ -502,7 +505,7 @@ std::vector> assemble_t_cross_covariance_tiles( } std::vector> assemble_y_tiles( - const double *d_training_output, const std::size_t n_tiles, const std::size_t n_tile_size, gprat::CUDA_GPU &gpu) + const double *d_training_output, const std::size_t n_tiles, const std::size_t n_tile_size, CUDA_GPU &gpu) { std::vector> d_y_tiles(n_tiles); for (std::size_t i = 0; i < n_tiles; i++) @@ -512,10 +515,8 @@ std::vector> assemble_y_tiles( return d_y_tiles; } -std::vector copy_tiled_vector_to_host_vector(std::vector> &d_tiles, - std::size_t n_tile_size, - std::size_t n_tiles, - gprat::CUDA_GPU &gpu) +std::vector copy_tiled_vector_to_host_vector( + std::vector> &d_tiles, std::size_t n_tile_size, std::size_t n_tiles, CUDA_GPU &gpu) { std::vector h_vector(n_tiles * n_tile_size); std::vector streams(n_tiles); @@ -533,13 +534,13 @@ std::vector copy_tiled_vector_to_host_vector(std::vector> move_lower_tiled_matrix_to_host( +std::vector> move_lower_tiled_matrix_to_host( const std::vector> &d_tiles, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { - std::vector> h_tiles(n_tiles * n_tiles); + std::vector> h_tiles(n_tiles * n_tiles); std::vector streams(n_tiles * (n_tiles + 1) / 2); for (std::size_t i = 0; i < n_tiles; ++i) @@ -547,7 +548,7 @@ std::vector> move_lower_tiled_matrix_to_host( for (std::size_t j = 0; j <= i; ++j) { streams[i] = gpu.next_stream(); - h_tiles[i * n_tiles + j].resize(n_tile_size * n_tile_size); + h_tiles[i * n_tiles + j] = mutable_tile_data(n_tile_size * n_tile_size); check_cuda_error(cudaMemcpyAsync( h_tiles[i * n_tiles + j].data(), d_tiles[i * n_tiles + j].get(), @@ -574,3 +575,5 @@ void free_lower_tiled_matrix(const std::vector> &d_ } } // end of namespace gpu + +GPRAT_NS_END diff --git a/core/src/gpu/gp_functions.cu b/core/src/gpu/cuda/gp_functions.cu similarity index 93% rename from core/src/gpu/gp_functions.cu rename to core/src/gpu/cuda/gp_functions.cu index cbc54666..a1300866 100644 --- a/core/src/gpu/gp_functions.cu +++ b/core/src/gpu/cuda/gp_functions.cu @@ -1,15 +1,19 @@ -#include "gpu/gp_functions.cuh" +#include "gprat/gpu/gp_functions.cuh" + +#include "gprat/gpu/cuda_utils.cuh" +#include "gprat/gpu/gp_algorithms.cuh" +#include "gprat/gpu/tiled_algorithms.cuh" +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" +#include "gprat/tile_data.hpp" #include "apex_utils.hpp" -#include "gp_kernels.hpp" -#include "gpu/cuda_utils.cuh" -#include "gpu/gp_algorithms.cuh" -#include "gpu/tiled_algorithms.cuh" -#include "target.hpp" #include #include #include +GPRAT_NS_BEGIN + namespace gpu { @@ -17,13 +21,13 @@ std::vector predict(const std::vector &h_training_input, const std::vector &h_training_output, const std::vector &h_test_input, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { GPRAT_START_STEP(alloc_timer); @@ -84,6 +88,10 @@ predict(const std::vector &h_training_input, free(prediction_tiles); destroy(cusolver); + check_cuda_error(cudaFree(d_training_input)); + check_cuda_error(cudaFree(d_training_output)); + check_cuda_error(cudaFree(d_test_input)); + gpu.destroy(); GPRAT_END_STEP(destroy_timer, "predict_step ressource destroy"); @@ -95,13 +103,13 @@ std::vector> predict_with_uncertainty( const std::vector &h_training_input, const std::vector &h_training_output, const std::vector &h_test_input, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { GPRAT_START_STEP(alloc_timer); @@ -226,13 +234,13 @@ std::vector> predict_with_full_cov( const std::vector &h_training_input, const std::vector &h_training_output, const std::vector &h_test_input, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int m_tiles, int m_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { GPRAT_START_STEP(alloc_timer); @@ -348,11 +356,11 @@ std::vector> predict_with_full_cov( double compute_loss(const std::vector &h_training_input, const std::vector &h_training_output, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { gpu.create(); @@ -398,10 +406,10 @@ optimize(const std::vector &training_input, int n_tiles, int n_tile_size, int n_regressors, - const gprat_hyper::AdamParams &adam_params, - const gprat_hyper::SEKParams &sek_params, + const AdamParams &adam_params, + const SEKParams &sek_params, std::vector trainable_params, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { throw std::logic_error("Function not implemented for GPU"); // return std::vector>(); @@ -412,23 +420,23 @@ double optimize_step(const std::vector &training_input, int n_tiles, int n_tile_size, int n_regressors, - gprat_hyper::AdamParams &adam_params, - gprat_hyper::SEKParams &sek_params, + AdamParams &adam_params, + SEKParams &sek_params, std::vector trainable_params, int iter, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { throw std::logic_error("Function not implemented for GPU"); // return 0.0; } -std::vector> +std::vector> cholesky(const std::vector &h_training_input, - const gprat_hyper::SEKParams &sek_params, + const SEKParams &sek_params, int n_tiles, int n_tile_size, int n_regressors, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { gpu.create(); @@ -457,7 +465,7 @@ cholesky(const std::vector &h_training_input, #endif // Copy tiled matrix to host - std::vector> h_tiles = move_lower_tiled_matrix_to_host(d_tiles, n_tile_size, n_tiles, gpu); + auto h_tiles = move_lower_tiled_matrix_to_host(d_tiles, n_tile_size, n_tiles, gpu); cudaFree(d_training_input); destroy(cusolver); @@ -467,3 +475,5 @@ cholesky(const std::vector &h_training_input, } } // end of namespace gpu + +GPRAT_NS_END diff --git a/core/src/gpu/gp_optimizer.cu b/core/src/gpu/cuda/gp_optimizer.cu similarity index 91% rename from core/src/gpu/gp_optimizer.cu rename to core/src/gpu/cuda/gp_optimizer.cu index 53cca8bb..ea465261 100644 --- a/core/src/gpu/gp_optimizer.cu +++ b/core/src/gpu/cuda/gp_optimizer.cu @@ -1,8 +1,12 @@ -#include "gpu/gp_optimizer.cuh" +#include "gprat/gpu/gp_optimizer.cuh" -#include "gpu/adapter_cublas.cuh" -#include "gpu/cuda_kernels.cuh" -#include "gpu/cuda_utils.cuh" +#include "gprat/gpu/adapter_cublas.cuh" +#include "gprat/gpu/cuda_kernels.cuh" +#include "gprat/gpu/cuda_utils.cuh" + +#include + +GPRAT_NS_BEGIN namespace gpu { @@ -36,7 +40,7 @@ double compute_sigmoid(const double parameter) { return 1.0 / (1.0 + exp(-parame double compute_covariance_distance(std::size_t i_global, std::size_t j_global, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &i_input, const std::vector &j_input) { @@ -58,7 +62,7 @@ std::vector gen_tile_distance( std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &input) { std::size_t i_global, j_global; @@ -85,7 +89,7 @@ std::vector gen_tile_covariance_with_distance( std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &cov_dists) { std::size_t i_global, j_global; @@ -117,7 +121,7 @@ gen_tile_grad_v(std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &cov_dists) { // Initialize tile @@ -140,7 +144,7 @@ gen_tile_grad_l(std::size_t row, std::size_t col, std::size_t N, std::size_t n_regressors, - gprat_hyper::SEKParams sek_params, + SEKParams sek_params, const std::vector &cov_dists) { // Initialize tile @@ -176,7 +180,7 @@ std::vector gen_tile_grad_v_trans(std::size_t N, const std::vector -gen_tile_grad_l_trans(std::size_t N, const hpx::shared_future f_grad_l_tile, gprat::CUDA_GPU &gpu) +gen_tile_grad_l_trans(std::size_t N, const hpx::shared_future f_grad_l_tile, CUDA_GPU &gpu) { double *transposed; check_cuda_error(cudaMalloc(&transposed, N * N * sizeof(double))); @@ -209,7 +213,7 @@ compute_loss(const hpx::shared_future &K_diag_tile, const hpx::shared_future &alpha_tile, const hpx::shared_future &y_tile, std::size_t N, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { auto [cublas, stream] = gpu.next_cublas_handle(); @@ -233,7 +237,7 @@ add_losses(const std::vector> &losses, std::size_t n_ { l += losses[i].get(); } - l += n_tile_size * n_tiles * log(2.0 * M_PI); + l += n_tile_size * n_tiles * log(2.0 * std::numbers::pi); return hpx::make_ready_future(0.5 * l / (n_tile_size * n_tiles)); } @@ -276,8 +280,8 @@ double update_second_moment(const double &gradient, double v_T, const double &be hpx::shared_future update_param(const double unconstrained_hyperparam, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, double m_T, double v_T, const std::vector beta1_T, @@ -339,11 +343,8 @@ sum_gradright(const std::vector &inter_alpha, const std::vector return 0.0; } -double sum_noise_gradleft(const std::vector &ft_invK, - double grad, - gprat_hyper::SEKParams sek_params, - std::size_t N, - std::size_t n_tiles) +double sum_noise_gradleft( + const std::vector &ft_invK, double grad, SEKParams sek_params, std::size_t N, std::size_t n_tiles) { double noise_der = compute_sigmoid(to_unconstrained(sek_params.noise_variance, true)); for (std::size_t i = 0; i < N; ++i) @@ -353,8 +354,7 @@ double sum_noise_gradleft(const std::vector &ft_invK, return std::move(grad); } -double -sum_noise_gradright(const std::vector &alpha, double grad, gprat_hyper::SEKParams sek_params, std::size_t N) +double sum_noise_gradright(const std::vector &alpha, double grad, SEKParams sek_params, std::size_t N) { // double noise_der = // compute_sigmoid(to_unconstrained(sek_params.noise_variance, true)); @@ -364,3 +364,5 @@ sum_noise_gradright(const std::vector &alpha, double grad, gprat_hyper:: } } // end of namespace gpu + +GPRAT_NS_END diff --git a/core/src/gpu/gp_uncertainty.cu b/core/src/gpu/cuda/gp_uncertainty.cu similarity index 74% rename from core/src/gpu/gp_uncertainty.cu rename to core/src/gpu/cuda/gp_uncertainty.cu index a7919457..6cc7f50b 100644 --- a/core/src/gpu/gp_uncertainty.cu +++ b/core/src/gpu/cuda/gp_uncertainty.cu @@ -1,16 +1,19 @@ -#include "gpu/gp_uncertainty.cuh" +#include "gprat/gpu/gp_uncertainty.cuh" + +#include "gprat/gpu/cuda_utils.cuh" +#include "gprat/target.hpp" -#include "gpu/cuda_utils.cuh" -#include "target.hpp" #include +GPRAT_NS_BEGIN + using hpx::cuda::experimental::check_cuda_error; namespace gpu { -hpx::shared_future diag_posterior( - const hpx::shared_future A, const hpx::shared_future B, std::size_t M, gprat::CUDA_GPU &gpu) +hpx::shared_future +diag_posterior(const hpx::shared_future A, const hpx::shared_future B, std::size_t M, CUDA_GPU &gpu) { auto [cublas, stream] = gpu.next_cublas_handle(); @@ -27,7 +30,7 @@ hpx::shared_future diag_posterior( return hpx::make_ready_future(tile); } -hpx::shared_future diag_tile(const hpx::shared_future A, std::size_t M, gprat::CUDA_GPU &gpu) +hpx::shared_future diag_tile(const hpx::shared_future A, std::size_t M, CUDA_GPU &gpu) { double *diag_tile; check_cuda_error(cudaMalloc(&diag_tile, M * sizeof(double))); @@ -41,3 +44,5 @@ hpx::shared_future diag_tile(const hpx::shared_future A, std } } // end of namespace gpu + +GPRAT_NS_END diff --git a/core/src/gpu/tiled_algorithms.cu b/core/src/gpu/cuda/tiled_algorithms.cu similarity index 93% rename from core/src/gpu/tiled_algorithms.cu rename to core/src/gpu/cuda/tiled_algorithms.cu index 1ffdd866..3c479ffd 100644 --- a/core/src/gpu/tiled_algorithms.cu +++ b/core/src/gpu/cuda/tiled_algorithms.cu @@ -1,10 +1,13 @@ -#include "gpu/tiled_algorithms.cuh" +#include "gprat/gpu/tiled_algorithms.cuh" + +#include "gprat/gpu/adapter_cublas.cuh" +#include "gprat/gpu/gp_optimizer.cuh" +#include "gprat/gpu/gp_uncertainty.cuh" -#include "gpu/adapter_cublas.cuh" -#include "gpu/gp_optimizer.cuh" -#include "gpu/gp_uncertainty.cuh" #include +GPRAT_NS_BEGIN + namespace gpu { @@ -13,7 +16,7 @@ namespace gpu void right_looking_cholesky_tiled(std::vector> &ft_tiles, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu, + CUDA_GPU &gpu, const cusolverDnHandle_t &cusolver) { for (std::size_t k = 0; k < n_tiles; ++k) @@ -86,7 +89,7 @@ void forward_solve_tiled(std::vector> &ft_tiles, std::vector> &ft_rhs, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t k = 0; k < n_tiles; ++k) { @@ -120,7 +123,7 @@ void backward_solve_tiled(std::vector> &ft_tiles, std::vector> &ft_rhs, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { // NOTE: The loops traverse backwards. Its last comparisons require the // usage negative numbers. Therefore they use signed int instead of the @@ -160,7 +163,7 @@ void forward_solve_tiled_matrix( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t c = 0; c < m_tiles; ++c) { @@ -209,7 +212,7 @@ void backward_solve_tiled_matrix( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t c = 0; c < m_tiles; ++c) { @@ -258,7 +261,7 @@ void matrix_vector_tiled(std::vector> &ft_tiles, const std::size_t N_col, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t k = 0; k < m_tiles; ++k) { @@ -288,7 +291,7 @@ void symmetric_matrix_matrix_diagonal_tiled( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t i = 0; i < m_tiles; ++i) { @@ -315,7 +318,7 @@ void compute_gemm_of_invK_y(std::vector> &ft_invK, std::vector> &ft_alpha, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t i = 0; i < n_tiles; ++i) { @@ -344,7 +347,7 @@ hpx::shared_future compute_loss_tiled( std::vector> &ft_y, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { std::vector> loss_tiled(n_tiles); @@ -364,7 +367,7 @@ void symmetric_matrix_matrix_tiled( const std::size_t m_tile_size, const std::size_t n_tiles, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t c = 0; c < m_tiles; ++c) { @@ -397,7 +400,7 @@ void vector_difference_tiled(std::vector> &ft_prior std::vector> &ft_vector, const std::size_t m_tile_size, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t i = 0; i < m_tiles; i++) { @@ -409,7 +412,7 @@ void matrix_diagonal_tiled(std::vector> &ft_priorK, std::vector> &ft_vector, const std::size_t m_tile_size, const std::size_t m_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t i = 0; i < m_tiles; i++) { @@ -422,7 +425,7 @@ void update_grad_K_tiled_mkl(std::vector> &ft_tiles const std::vector> &ft_v2, const std::size_t n_tile_size, const std::size_t n_tiles, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { for (std::size_t i = 0; i < n_tiles; ++i) { @@ -441,8 +444,8 @@ static double update_hyperparameter( const std::vector> &ft_gradparam, const std::vector> &ft_alpha, double &hyperparameter, // lengthscale or vertical-lengthscale - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, const std::size_t n_tile_size, const std::size_t n_tiles, std::vector> &m_T, @@ -451,7 +454,7 @@ static double update_hyperparameter( const std::vector> &beta2_T, int iter, int param_idx, // 0 for lengthscale, 1 for vertical-lengthscale - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { throw std::logic_error("Function not implemented for GPU"); // return 0; @@ -461,8 +464,8 @@ double update_lengthscale( const std::vector> &ft_invK, const std::vector> &ft_gradparam, const std::vector> &ft_alpha, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, const std::size_t n_tile_size, const std::size_t n_tiles, std::vector> &m_T, @@ -470,7 +473,7 @@ double update_lengthscale( const std::vector> &beta1_T, const std::vector> &beta2_T, int iter, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { return update_hyperparameter( ft_invK, @@ -494,8 +497,8 @@ double update_vertical_lengthscale( const std::vector> &ft_invK, const std::vector> &ft_gradparam, const std::vector> &ft_alpha, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, const std::size_t n_tile_size, const std::size_t n_tiles, std::vector> &m_T, @@ -503,7 +506,7 @@ double update_vertical_lengthscale( const std::vector> &beta1_T, const std::vector> &beta2_T, int iter, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { return update_hyperparameter( ft_invK, @@ -526,8 +529,8 @@ double update_vertical_lengthscale( double update_noise_variance( const std::vector> &ft_invK, const std::vector> &ft_alpha, - gprat_hyper::SEKParams sek_params, - gprat_hyper::AdamParams adam_params, + SEKParams sek_params, + AdamParams adam_params, const std::size_t n_tile_size, const std::size_t n_tiles, std::vector> &m_T, @@ -535,10 +538,12 @@ double update_noise_variance( const std::vector> &beta1_T, const std::vector> &beta2_T, int iter, - gprat::CUDA_GPU &gpu) + CUDA_GPU &gpu) { throw std::logic_error("Function not implemented for GPU"); // return 0; } } // end of namespace gpu + +GPRAT_NS_END diff --git a/core/src/gpu/sycl/adapter_onemath.cpp b/core/src/gpu/sycl/adapter_onemath.cpp new file mode 100644 index 00000000..9c818b5e --- /dev/null +++ b/core/src/gpu/sycl/adapter_onemath.cpp @@ -0,0 +1,351 @@ +#include "gpu/sycl/adapter_onemath.hpp" + +// BLAS LEVEL 3 OPERATIONS //////////////////////////////////////////////////////////////////////////////////////////// + +double *potrf(sycl::queue queue, double *f_A, const std::size_t N) +{ + std::int64_t scratchpad_size = oneapi::math::lapack::potrf_scratchpad_size( + queue, oneapi::math::uplo::upper, static_cast(N), static_cast(N)); + + double *scratchpad = sycl::malloc_device(static_cast(scratchpad_size), queue); + + // row-major POTRF + // A = potrf(A) + // for LOWER part of symmetric positive semi-definite matrix A + + // column-major cuBLAS POTRF for row-major stored A + // for UPPER part of symmetric positive semi-definite matrix A + + try + { + oneapi::math::lapack::potrf( + queue, + oneapi::math::uplo::upper, + static_cast(N), + f_A, + static_cast(N), + scratchpad, + scratchpad_size); + + queue.wait(); + } + catch (...) + { + sycl::free(scratchpad, queue); + throw; + } + + sycl::free(scratchpad, queue); + + return f_A; +} + +double *trsm(sycl::queue queue, + double *f_A, + double *f_B, + const std::size_t M, + const std::size_t N, + const oneapi::math::transpose is_transposed, + const oneapi::math::side is_right) +{ + // TRSM constants + const double alpha = 1.0; + + // row-major TRSM solves for X + // + // for side_A == Blas_right: + // op(A) * X = alpha * B + // A^T * X = B + // + // for side_A == Blas_left: + // X * op(A) = alpha * B + // X * A^T = B + // + // for op: transpose_A + + // column-major cuBLAS TRSM for row-major stored A & B + // for X on opposite side (opposite of side_A) + + oneapi::math::blas::column_major::trsm( + queue, + invert_side_operator(is_right), + oneapi::math::uplo::upper, + is_transposed, + oneapi::math::diag::nonunit, + static_cast(M), + static_cast(N), + alpha, + f_A, + static_cast(M), + f_B, + static_cast(N)); + + queue.wait(); + + return f_B; +} + +double *syrk(sycl::queue queue, double *f_A, double *f_C, const std::size_t N) +{ + // SYRK constants + const double alpha = -1.0; + const double beta = 1.0; + + // row-major SYRK + // C = alpha * op(A) * op(A)^T + beta * C + // C = - A * A^T + C + // for LOWER part of symmetric matrix C + // for op: NO transpose: + + // column-major cuBLAS SYRK for row-major stored A & C + // C = - op(A) * op(A)^T + fm(C) + // = - A^T * A - C + // for UPPER part of symmetric matrix C + // for op: TRANSPOSE + + oneapi::math::blas::column_major::syrk( + queue, + oneapi::math::uplo::upper, + oneapi::math::transpose::trans, + static_cast(N), + static_cast(N), + alpha, + f_A, + static_cast(N), + beta, + f_C, + static_cast(N)); + + queue.wait(); + + return f_C; +} + +double *gemm(sycl::queue queue, + double *f_A, + double *f_B, + double *f_C, + const std::size_t M, + const std::size_t N, + const std::size_t K, + const oneapi::math::transpose is_A_transposed, + const oneapi::math::transpose is_B_transposed) +{ + // row-major GEMM + // C = alpha * op(A) * op(B) + beta * C + // = op(A) * op(B) - C + // for op(A): transpose_A + // for op(B): transpose_B + + // column-major cuBLAS GEMM for row-major stored A, B, C + // C = alpha * op(B) * op(A) + beta * C + // = op(B) * op(A) - C + // for inverted ordering of matrices A, B + + oneapi::math::blas::column_major::gemm( + queue, + is_B_transposed, + is_A_transposed, + static_cast(N), + static_cast(M), + static_cast(K), + -1.0, + f_B, + static_cast(N), + f_A, + static_cast(K), + 1.0, + f_C, + static_cast(N)); + + queue.wait(); + + return f_C; +} + +// BLAS LEVEL 2 OPERATIONS //////////////////////////////////////////////////////////////////////////////////////////// + +double * +trsv(sycl::queue queue, double *f_A, double *f_b, const std::size_t N, const oneapi::math::transpose is_A_transposed) +{ + // row-major TRSV solves for x + // op(A) * x = b + // for op: transpose_A + // for LOWER part of lower triangular matrix A + + // column-major cuBLAS TRSV for row-major stored A + // for op: opposite of transpose_A + // for UPPER part of lower triangular matrix A + + oneapi::math::blas::column_major::trsv( + queue, + oneapi::math::uplo::upper, + invert_transpose_operator(is_A_transposed), + oneapi::math::diag::nonunit, + static_cast(N), + f_A, + static_cast(N), + f_b, + 1); + + queue.wait(); + + return f_b; +} + +double *gemv(sycl::queue queue, + double *f_A, + double *f_x, + double *f_y, + const std::size_t M, + const std::size_t N, + const double alpha, + const oneapi::math::transpose is_A_transposed) +{ + // GEMV constants + // const double alpha_value = alpha; + // const double beta = 1.0; + + // row-major GEMV + // y = alpha * op(A) * x + beta * y + // = alpha * op(A) * x + y + // for MxN matrix A + // for vector x + // for vector y + + // column-major cuBLAS GEMV for row-major stored A (and x,y) + // for op: opposite of transpose_A + + oneapi::math::blas::column_major::gemv( + queue, + invert_transpose_operator(is_A_transposed), + static_cast(N), + static_cast(M), + alpha, + f_A, + static_cast(N), + f_x, + 1, + 1.0, + f_y, + 1); + + queue.wait(); + + return f_y; +} + +double *ger(sycl::queue queue, double *f_A, double *f_x, double *f_y, const std::size_t N) +{ + // GER constants + const double alpha = -1.0; + + // row-major GER + // A = alpha * x*y^T + A + // = -x*y^T + A + + // column-major cuBLAS GER for row-major stored A (and x,y) + // A = alpha * y*x^T + A + // = -y*x^T + A + // for opposite order of x,y + + oneapi::math::blas::column_major::ger( + queue, + static_cast(N), + static_cast(N), + alpha, + f_y, + 1, + f_x, + 1, + f_A, + static_cast(N)); + + queue.wait(); + + return f_A; +} + +DotDiagSyrkKernel::DotDiagSyrkKernel(double *d_A, double *d_r, const std::size_t M, const std::size_t N) : + d_A(d_A), + d_r(d_r), + M(M), + N(N) +{ } + +void DotDiagSyrkKernel::operator()(const sycl::id<1> &id) const +{ + double dot_product = 0.0; + + for (std::size_t i = 0; i < M; ++i) + { + dot_product += d_A[i * N + id] * d_A[i * N + id]; + } + + d_r[id] += dot_product; +} + +double *dot_diag_syrk(sycl::queue queue, double *f_A, double *f_r, const std::size_t M, const std::size_t N) +{ + // r = r + diag(A^T * A) + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = DotDiagSyrkKernel(f_A, f_r, M, N); + cgh.parallel_for(sycl::range<1>(N), kernel); + }); + event.wait(); + + return f_r; +} + +DotDiagGemmKernel::DotDiagGemmKernel(double *A, double *B, double *r, const std::size_t M, const std::size_t N) : + A(A), + B(B), + r(r), + M(M), + N(N) +{ } + +void DotDiagGemmKernel::operator()(const sycl::id<1> &id) const +{ + double dot_product = 0.0; + + for (std::size_t i = 0; i < M; ++i) + { + dot_product += A[i * N + id] * B[id * M + i]; + } + + r[id] += dot_product; +} + +double * +dot_diag_gemm(sycl::queue queue, double *f_A, double *f_B, double *f_r, const std::size_t M, const std::size_t N) +{ + // r = r + diag(A * B) + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = DotDiagGemmKernel(f_A, f_B, f_r, M, N); + cgh.parallel_for(sycl::range<1>(N), kernel); + }); + event.wait(); + + return f_r; +} + +// BLAS LEVEL 1 OPERATIONS //////////////////////////////////////////////////////////////////////////////////////////// + +double *dot(sycl::queue queue, double *f_a, double *f_b, const std::size_t N) +{ + // Use shared USM so the result is readable from the host without an explicit copy. + double *result = sycl::malloc_shared(1, queue); + *result = 0.0; + + oneapi::math::blas::column_major::dot(queue, static_cast(N), f_a, 1, f_b, 1, result); + + queue.wait(); + + return result; +} diff --git a/core/src/gpu/sycl/sycl_gp_algorithms.cpp b/core/src/gpu/sycl/sycl_gp_algorithms.cpp new file mode 100644 index 00000000..464ef876 --- /dev/null +++ b/core/src/gpu/sycl/sycl_gp_algorithms.cpp @@ -0,0 +1,544 @@ +#include "gpu/sycl/sycl_gp_algorithms.hpp" + +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" + +#include "gpu/sycl/sycl_gp_optimizer.hpp" +#include "gpu/sycl/sycl_kernels.hpp" +#include "gpu/sycl/sycl_utils.hpp" +#include + +namespace gprat::sycl_backend +{ + +// SYCL boilerplate code ////////////////////////////////////////////////////////////////////////////////////////////// + +double *gen_tile_covariance(const double *d_input, + const std::size_t tile_row, + const std::size_t tile_column, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + double *d_tile; + + sycl::queue queue = sycl_device.next_queue(); + + d_tile = sycl::malloc_device(n_tile_size * n_tile_size, queue); + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = GenTileCovarianceKernel( + d_tile, d_input, n_tile_size, n_regressors, tile_row, tile_column, sek_params); + cgh.parallel_for(sycl::range<2>(n_tile_size, n_tile_size), kernel); + }); + + event.wait(); + + return d_tile; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return nullptr; + } +} + +double *gen_tile_full_prior_covariance( + const double *d_input, + const std::size_t tile_row, + const std::size_t tile_columns, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + double *d_tile; + + sycl::queue queue = sycl_device.next_queue(); + + d_tile = sycl::malloc_device(n_tile_size * n_tile_size, queue); + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = GenTileFullPriorCovarianceKernel( + d_tile, d_input, n_tile_size, n_regressors, tile_row, tile_columns, sek_params); + cgh.parallel_for(sycl::range<2>(n_tile_size, n_tile_size), kernel); + }); + + event.wait(); + return d_tile; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return nullptr; + } +} + +double *gen_tile_prior_covariance( + const double *d_input, + const std::size_t tile_row, + const std::size_t tile_column, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + double *d_tile; + + sycl::queue queue = sycl_device.next_queue(); + + d_tile = sycl::malloc_device(n_tile_size, queue); + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = GenTilePriorCovarianceKernel( + d_tile, d_input, n_tile_size, n_regressors, tile_row, tile_column, sek_params); + cgh.parallel_for(sycl::range<1>(n_tile_size), kernel); + }); + + event.wait(); + return d_tile; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return nullptr; + } +} + +double *gen_tile_cross_covariance( + const double *d_row_input, + const double *d_col_input, + const std::size_t tile_row, + const std::size_t tile_column, + const std::size_t n_row_tile_size, + const std::size_t n_column_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + double *d_tile; + + sycl::queue queue = sycl_device.next_queue(); + + d_tile = sycl::malloc_device(n_row_tile_size * n_column_tile_size, queue); + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = GenTileCrossCovarianceKernel( + d_tile, + d_row_input, + d_col_input, + n_row_tile_size, + n_column_tile_size, + tile_row, + tile_column, + n_regressors, + sek_params); + cgh.parallel_for(sycl::range<2>(n_row_tile_size, n_column_tile_size), kernel); + }); + + event.wait(); + return d_tile; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return nullptr; + } +} + +hpx::shared_future gen_tile_cross_cov_T(std::size_t n_row_tile_size, + std::size_t n_column_tile_size, + const hpx::shared_future f_cross_covariance_tile, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + double *transposed; + + sycl::queue queue = sycl_device.next_queue(); + + transposed = sycl::malloc_device(n_row_tile_size * n_column_tile_size, queue); + + double *d_cross_covariance_tile = f_cross_covariance_tile.get(); + + sycl::range<2> global_range(((n_row_tile_size + WORK_GROUP_SIZE - 1) / WORK_GROUP_SIZE) * WORK_GROUP_SIZE, + ((n_column_tile_size + WORK_GROUP_SIZE - 1) / WORK_GROUP_SIZE) * WORK_GROUP_SIZE); + + sycl::range<2> local_range(WORK_GROUP_SIZE, WORK_GROUP_SIZE); + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = + TransposeKernel(transposed, d_cross_covariance_tile, n_row_tile_size, n_column_tile_size, cgh); + cgh.parallel_for(sycl::nd_range<2>(global_range, local_range), kernel); + }); + + event.wait(); + return hpx::make_ready_future(transposed); + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return hpx::make_ready_future(nullptr); + } +} + +double *gen_tile_output( + const std::size_t row, const std::size_t n_tile_size, const double *d_output, gprat::SYCL_DEVICE &sycl_device) +{ + try + { + double *d_tile; + + sycl::queue queue = sycl_device.next_queue(); + + d_tile = sycl::malloc_device(n_tile_size, queue); + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + auto kernel = GenTileOutputKernel(d_tile, d_output, row, n_tile_size); + cgh.parallel_for(sycl::range<1>(n_tile_size), kernel); + }); + + event.wait(); + return d_tile; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return nullptr; + } +} + +double *gen_tile_zeros(std::size_t n_tile_size, gprat::SYCL_DEVICE &sycl_device) +{ + try + { + sycl::queue queue = sycl_device.next_queue(); + + double *d_tile; + d_tile = sycl::malloc_device(n_tile_size, queue); + queue.fill(d_tile, 0.0, n_tile_size).wait(); + return d_tile; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return nullptr; + } +} + +// Standard C++ code ////////////////////////////////////////////////////////////////////////////////////////////////// + +double compute_error_norm(std::size_t n_tiles, + std::size_t n_tile_size, + const std::vector &b, + const std::vector> &tiles) +{ + double error = 0.0; + for (std::size_t k = 0; k < n_tiles; k++) + { + auto a = tiles[k]; + for (std::size_t i = 0; i < n_tile_size; i++) + { + std::size_t i_global = n_tile_size * k + i; + // ||a - b||_2 + error += (b[i_global] - a[i]) * (b[i_global] - a[i]); + } + } + return sqrt(error); +} + +// HPX boilerplate code /////////////////////////////////////////////////////////////////////////////////////////////// + +std::vector> assemble_tiled_covariance_matrix( + const double *d_training_input, + const std::size_t n_tiles, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> d_tiles(n_tiles * n_tiles); + + for (std::size_t tile_row = 0; tile_row < n_tiles; ++tile_row) + { + for (std::size_t tile_column = 0; tile_column < tile_row + 1; ++tile_column) + { + double *result = gen_tile_covariance( + d_training_input, tile_row, tile_column, n_tile_size, n_regressors, sek_params, std::ref(sycl_device)); + + d_tiles[tile_row * n_tiles + tile_column] = hpx::make_ready_future(result); + } + } + + return d_tiles; +} + +std::vector> assemble_alpha_tiles( + const double *d_output, const std::size_t n_tiles, const std::size_t n_tile_size, gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> alpha_tiles(n_tiles); + for (std::size_t i = 0; i < n_tiles; i++) + { + alpha_tiles[i] = hpx::async( + hpx::annotated_function(&gen_tile_output, "assemble_tiled_alpha"), + i, + n_tile_size, + d_output, + std::ref(sycl_device)); + } + + return alpha_tiles; +} + +std::vector> assemble_cross_covariance_tiles( + const double *d_test_input, + const double *d_training_input, + const std::size_t m_tiles, + const std::size_t n_tiles, + const std::size_t m_tile_size, + const std::size_t n_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> cross_covariance_tiles; + cross_covariance_tiles.resize(m_tiles * n_tiles); + for (std::size_t i = 0; i < m_tiles; i++) + { + for (std::size_t j = 0; j < n_tiles; j++) + { + cross_covariance_tiles[i * n_tiles + j] = hpx::async( + [=, &sycl_device]() + { + return gen_tile_cross_covariance( + d_test_input, + d_training_input, + i, + j, + m_tile_size, + n_tile_size, + n_regressors, + sek_params, + std::ref(sycl_device)); + }); + } + } + return cross_covariance_tiles; +} + +std::vector> +assemble_tiles_with_zeros(std::size_t n_tile_size, std::size_t n_tiles, gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> tiles(n_tiles); + for (std::size_t i = 0; i < n_tiles; i++) + { + tiles[i] = hpx::async(&gen_tile_zeros, n_tile_size, std::ref(sycl_device)); + } + return tiles; +} + +std::vector> assemble_prior_K_tiles( + const double *d_test_input, + const std::size_t m_tiles, + const std::size_t m_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> d_prior_K_tiles; + d_prior_K_tiles.resize(m_tiles); + for (std::size_t i = 0; i < m_tiles; i++) + { + d_prior_K_tiles[i] = hpx::async( + [=, &sycl_device]() + { + return gen_tile_prior_covariance( + d_test_input, i, i, m_tile_size, n_regressors, sek_params, std::ref(sycl_device)); + }); + } + return d_prior_K_tiles; +} + +std::vector> assemble_prior_K_tiles_full( + const double *d_test_input, + const std::size_t m_tiles, + const std::size_t m_tile_size, + const std::size_t n_regressors, + const gprat::SEKParams sek_params, + gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> d_prior_K_tiles(m_tiles * m_tiles); + for (std::size_t i = 0; i < m_tiles; i++) + { + for (std::size_t j = 0; j <= i; j++) + { + d_prior_K_tiles[i * m_tiles + j] = hpx::async( + &gen_tile_full_prior_covariance, + d_test_input, + i, + j, + m_tile_size, + n_regressors, + sek_params, + std::ref(sycl_device)); + + if (i != j) + { + d_prior_K_tiles[j * m_tiles + i] = hpx::dataflow( + &gen_tile_grad_l_trans, m_tile_size, d_prior_K_tiles[i * m_tiles + j], std::ref(sycl_device)); + } + } + } + return d_prior_K_tiles; +} + +std::vector> assemble_t_cross_covariance_tiles( + const std::vector> &d_cross_covariance_tiles, + const std::size_t n_tiles, + const std::size_t m_tiles, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> d_t_cross_covariance_tiles(m_tiles * n_tiles); + for (std::size_t i = 0; i < m_tiles; i++) + { + for (std::size_t j = 0; j < n_tiles; j++) + { + d_t_cross_covariance_tiles[j * m_tiles + i] = hpx::dataflow( + &gen_tile_cross_cov_T, + m_tile_size, + n_tile_size, + d_cross_covariance_tiles[i * n_tiles + j], + std::ref(sycl_device)); + } + } + return d_t_cross_covariance_tiles; +} + +std::vector> +assemble_y_tiles(const double *d_training_output, + const std::size_t n_tiles, + const std::size_t n_tile_size, + gprat::SYCL_DEVICE &sycl_device) +{ + std::vector> d_y_tiles(n_tiles); + for (std::size_t i = 0; i < n_tiles; i++) + { + d_y_tiles[i] = hpx::async(&gen_tile_output, i, n_tile_size, d_training_output, std::ref(sycl_device)); + } + return d_y_tiles; +} + +std::vector copy_tiled_vector_to_host_vector(std::vector> &d_tiles, + std::size_t n_tile_size, + std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + std::vector h_vector(n_tiles * n_tile_size); + sycl::queue queue = sycl_device.next_queue(); + + for (std::size_t i = 0; i < n_tiles; i++) + { + queue.memcpy(h_vector.data() + i * n_tile_size, d_tiles[i].get(), n_tile_size * sizeof(double)); + } + + queue.wait(); + return h_vector; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return {}; + } +} + +std::vector> move_lower_tiled_matrix_to_host( + const std::vector> &d_tiles, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + std::vector> h_tiles(n_tiles * n_tiles); + sycl::queue queue = sycl_device.next_queue(); + + for (std::size_t i = 0; i < n_tiles; ++i) + { + for (std::size_t j = 0; j <= i; ++j) + { + h_tiles[i * n_tiles + j].resize(n_tile_size * n_tile_size); + queue.memcpy(h_tiles[i * n_tiles + j].data(), + d_tiles[i * n_tiles + j].get(), + n_tile_size * n_tile_size * sizeof(double)); + } + } + + queue.wait(); + + for (std::size_t i = 0; i < n_tiles; ++i) + { + for (std::size_t j = 0; j <= i; ++j) + { + sycl::free(d_tiles[i * n_tiles + j].get(), queue); + } + } + + return h_tiles; + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return {}; + } +} + +void free_lower_tiled_matrix(const std::vector> &d_tiles, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + try + { + sycl::queue queue = sycl_device.next_queue(); + + for (std::size_t i = 0; i < n_tiles; ++i) + { + for (std::size_t j = 0; j <= i; ++j) + { + sycl::free(d_tiles[i * n_tiles + j].get(), queue); + } + } + + queue.wait(); + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + } +} + +} // namespace gprat::sycl_backend diff --git a/core/src/gpu/sycl/sycl_gp_functions.cpp b/core/src/gpu/sycl/sycl_gp_functions.cpp new file mode 100644 index 00000000..014fe610 --- /dev/null +++ b/core/src/gpu/sycl/sycl_gp_functions.cpp @@ -0,0 +1,512 @@ +#include "gpu/sycl/sycl_gp_functions.hpp" + +#include "gprat/kernels.hpp" +#include "gprat/target.hpp" + +#include "gpu/sycl/sycl_gp_algorithms.hpp" +#include "gpu/sycl/sycl_tiled_algorithms.hpp" +#include "gpu/sycl/sycl_utils.hpp" +#include + +namespace gprat::sycl_backend +{ + +// predict //////////////////////////////////////////////////////////////////////////////////////////////////////////// + +std::vector +predict(const std::vector &h_training_input, + const std::vector &h_training_output, + const std::vector &h_test_input, + const gprat::SEKParams &sek_params, + int n_tiles, + int n_tile_size, + int m_tiles, + int m_tile_size, + int n_regressors, + gprat::SYCL_DEVICE &sycl_device) +{ + sycl_device.create(); + + double *d_training_input = copy_to_device(h_training_input, sycl_device); + double *d_training_output = copy_to_device(h_training_output, sycl_device); + double *d_test_input = copy_to_device(h_test_input, sycl_device); + + auto d_tiles = assemble_tiled_covariance_matrix( + d_training_input, + static_cast(n_tiles), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto alpha_tiles = assemble_alpha_tiles( + d_training_output, static_cast(n_tiles), static_cast(n_tile_size), sycl_device); + + auto cross_covariance_tiles = assemble_cross_covariance_tiles( + d_test_input, + d_training_input, + static_cast(m_tiles), + static_cast(n_tiles), + static_cast(m_tile_size), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto prediction_tiles = assemble_tiles_with_zeros( + static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + + right_looking_cholesky_tiled( + d_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + // Triangular solve K_NxN * alpha = y + + forward_solve_tiled( + d_tiles, alpha_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + backward_solve_tiled( + d_tiles, alpha_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + matrix_vector_tiled( + cross_covariance_tiles, + alpha_tiles, + prediction_tiles, + static_cast(m_tile_size), + static_cast(n_tile_size), + static_cast(n_tiles), + static_cast(m_tiles), + sycl_device); + + std::vector prediction = copy_tiled_vector_to_host_vector( + prediction_tiles, static_cast(m_tile_size), std::size_t(m_tiles), sycl_device); + + gprat::sycl_backend::free_lower_tiled_matrix(d_tiles, static_cast(n_tiles), sycl_device); + + sycl::queue queue = sycl_device.next_queue(); + + gprat::sycl_backend::free(alpha_tiles, queue); + gprat::sycl_backend::free(cross_covariance_tiles, queue); + gprat::sycl_backend::free(prediction_tiles, queue); + + sycl::free(d_training_input, queue); + sycl::free(d_training_output, queue); + sycl::free(d_test_input, queue); + + sycl_device.destroy(); + + return prediction; +} + +// predict_with_uncertainty /////////////////////////////////////////////////////////////////////////////////////////// + +std::vector> predict_with_uncertainty( + const std::vector &h_training_input, + const std::vector &h_training_output, + const std::vector &h_test_input, + const gprat::SEKParams &sek_params, + int n_tiles, + int n_tile_size, + int m_tiles, + int m_tile_size, + int n_regressors, + gprat::SYCL_DEVICE &sycl_device) +{ + sycl_device.create(); + + double *d_training_input = copy_to_device(h_training_input, sycl_device); + double *d_training_output = copy_to_device(h_training_output, sycl_device); + double *d_test_input = copy_to_device(h_test_input, sycl_device); + + // Assemble tiled covariance matrix on GPU. + auto d_K_tiles = assemble_tiled_covariance_matrix( + d_training_input, + static_cast(n_tiles), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto d_alpha_tiles = assemble_alpha_tiles( + d_training_output, static_cast(n_tiles), static_cast(n_tile_size), sycl_device); + + auto d_prior_K_tiles = assemble_prior_K_tiles( + d_test_input, + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto d_cross_covariance_tiles = assemble_cross_covariance_tiles( + d_test_input, + d_training_input, + static_cast(m_tiles), + static_cast(n_tiles), + static_cast(m_tile_size), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto d_t_cross_covariance_tiles = assemble_t_cross_covariance_tiles( + d_cross_covariance_tiles, + static_cast(n_tiles), + static_cast(m_tiles), + static_cast(n_tile_size), + static_cast(m_tile_size), + sycl_device); + + // Assemble placeholder matrix for diag(K_MxN * (K^-1_NxN * K_NxM)) + auto d_prior_inter_tiles = assemble_tiles_with_zeros( + static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + + auto d_prediction_tiles = assemble_tiles_with_zeros( + static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + + // Assemble placeholder for uncertainty + auto d_prediction_uncertainty_tiles = assemble_tiles_with_zeros( + static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + + right_looking_cholesky_tiled( + d_K_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + // Triangular solve K_NxN * alpha = y + forward_solve_tiled(d_K_tiles, + d_alpha_tiles, + static_cast(n_tile_size), + static_cast(n_tiles), + sycl_device); + backward_solve_tiled(d_K_tiles, + d_alpha_tiles, + static_cast(n_tile_size), + static_cast(n_tiles), + sycl_device); + + // Triangular solve A_M,N * K_NxN = K_MxN -> A_MxN = K_MxN * K^-1_NxN + forward_solve_tiled_matrix( + d_K_tiles, + d_t_cross_covariance_tiles, + static_cast(n_tile_size), + static_cast(m_tile_size), + static_cast(n_tiles), + static_cast(m_tiles), + sycl_device); + + // Compute predictions + matrix_vector_tiled( + d_cross_covariance_tiles, + d_alpha_tiles, + d_prediction_tiles, + static_cast(m_tile_size), + static_cast(n_tile_size), + static_cast(n_tiles), + static_cast(m_tiles), + sycl_device); + + // posterior covariance matrix - (K_MxN * K^-1_NxN) * K_NxM + symmetric_matrix_matrix_diagonal_tiled( + d_t_cross_covariance_tiles, + d_prior_inter_tiles, + static_cast(n_tile_size), + static_cast(m_tile_size), + static_cast(n_tiles), + static_cast(m_tiles), + sycl_device); + + // Compute predicition uncertainty + vector_difference_tiled( + d_prior_K_tiles, + d_prior_inter_tiles, + d_prediction_uncertainty_tiles, + static_cast(m_tile_size), + static_cast(m_tiles)); + + // Get predictions and uncertainty to return them + std::vector prediction = copy_tiled_vector_to_host_vector( + d_prediction_tiles, static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + + std::vector pred_var_full = copy_tiled_vector_to_host_vector( + d_prediction_uncertainty_tiles, + static_cast(m_tile_size), + static_cast(m_tiles), + sycl_device); + + sycl::queue queue = sycl_device.next_queue(); + sycl::free(d_training_input, queue); + sycl::free(d_training_output, queue); + sycl::free(d_test_input, queue); + + gprat::sycl_backend::free_lower_tiled_matrix(d_K_tiles, static_cast(n_tiles), sycl_device); + + gprat::sycl_backend::free(d_alpha_tiles, queue); + gprat::sycl_backend::free(d_prior_K_tiles, queue); + gprat::sycl_backend::free(d_cross_covariance_tiles, queue); + gprat::sycl_backend::free(d_t_cross_covariance_tiles, queue); + gprat::sycl_backend::free(d_prior_inter_tiles, queue); + gprat::sycl_backend::free(d_prediction_tiles, queue); + gprat::sycl_backend::free(d_prediction_uncertainty_tiles, queue); + + sycl_device.destroy(); + + return std::vector>{ prediction, pred_var_full }; +} + +// predict_with_full_cov ////////////////////////////////////////////////////////////////////////////////////////////// + +std::vector> predict_with_full_cov( + const std::vector &h_training_input, + const std::vector &h_training_output, + const std::vector &h_test_input, + const gprat::SEKParams &sek_params, + int n_tiles, + int n_tile_size, + int m_tiles, + int m_tile_size, + int n_regressors, + gprat::SYCL_DEVICE &sycl_device) +{ + sycl_device.create(); + + double *d_training_input = copy_to_device(h_training_input, sycl_device); + double *d_training_output = copy_to_device(h_training_output, sycl_device); + double *d_test_input = copy_to_device(h_test_input, sycl_device); + + // Assemble tiled covariance matrix on GPU. + auto d_K_tiles = assemble_tiled_covariance_matrix( + d_training_input, + static_cast(n_tiles), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto d_alpha_tiles = assemble_alpha_tiles( + d_training_output, static_cast(n_tiles), static_cast(n_tile_size), sycl_device); + + auto d_prior_K_tiles = assemble_prior_K_tiles_full( + d_test_input, + static_cast(m_tiles), + static_cast(m_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto d_cross_covariance_tiles = assemble_cross_covariance_tiles( + d_test_input, + d_training_input, + static_cast(m_tiles), + static_cast(n_tiles), + static_cast(m_tile_size), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto d_t_cross_covariance_tiles = assemble_t_cross_covariance_tiles( + d_cross_covariance_tiles, + static_cast(n_tiles), + static_cast(m_tiles), + static_cast(n_tile_size), + static_cast(m_tile_size), + sycl_device); + + auto d_prediction_tiles = assemble_tiles_with_zeros( + static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + + // Assemble placeholder for uncertainty + auto d_prediction_uncertainty_tiles = assemble_tiles_with_zeros( + static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + + right_looking_cholesky_tiled( + d_K_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + // Triangular solve K_NxN * alpha = y + forward_solve_tiled(d_K_tiles, + d_alpha_tiles, + static_cast(n_tile_size), + static_cast(n_tiles), + sycl_device); + backward_solve_tiled(d_K_tiles, + d_alpha_tiles, + static_cast(n_tile_size), + static_cast(n_tiles), + sycl_device); + + // Triangular solve A_M,N * K_NxN = K_MxN -> A_MxN = K_MxN * K^-1_NxN + forward_solve_tiled_matrix( + d_K_tiles, + d_t_cross_covariance_tiles, + static_cast(n_tile_size), + static_cast(m_tile_size), + static_cast(n_tiles), + static_cast(m_tiles), + sycl_device); + + // Compute predictions + matrix_vector_tiled( + d_cross_covariance_tiles, + d_alpha_tiles, + d_prediction_tiles, + static_cast(m_tile_size), + static_cast(n_tile_size), + static_cast(n_tiles), + static_cast(m_tiles), + sycl_device); + + // posterior covariance matrix - (K_MxN * K^-1_NxN) * K_NxM + symmetric_matrix_matrix_tiled( + d_t_cross_covariance_tiles, + d_prior_K_tiles, + static_cast(n_tile_size), + static_cast(m_tile_size), + static_cast(n_tiles), + static_cast(m_tiles), + sycl_device); + + // Compute predicition uncertainty + matrix_diagonal_tiled(d_prior_K_tiles, + d_prediction_uncertainty_tiles, + static_cast(m_tile_size), + static_cast(m_tiles)); + + // Get predictions and uncertainty to return them + std::vector prediction = copy_tiled_vector_to_host_vector( + d_prediction_tiles, static_cast(m_tile_size), static_cast(m_tiles), sycl_device); + std::vector pred_var_full = copy_tiled_vector_to_host_vector( + d_prediction_uncertainty_tiles, + static_cast(m_tile_size), + static_cast(m_tiles), + sycl_device); + + sycl::queue queue = sycl_device.next_queue(); + + sycl::free(d_training_input, queue); + sycl::free(d_training_output, queue); + sycl::free(d_test_input, queue); + + gprat::sycl_backend::free_lower_tiled_matrix(d_K_tiles, static_cast(n_tiles), sycl_device); + + gprat::sycl_backend::free(d_alpha_tiles, queue); + + gprat::sycl_backend::free_lower_tiled_matrix(d_prior_K_tiles, static_cast(m_tiles), sycl_device); + gprat::sycl_backend::free(d_cross_covariance_tiles, queue); + gprat::sycl_backend::free(d_t_cross_covariance_tiles, queue); + gprat::sycl_backend::free(d_prediction_tiles, queue); + gprat::sycl_backend::free(d_prediction_uncertainty_tiles, queue); + + sycl_device.destroy(); + + return std::vector>{ prediction, pred_var_full }; +} + +// compute_loss /////////////////////////////////////////////////////////////////////////////////////////////////////// + +double compute_loss(const std::vector &h_training_input, + const std::vector &h_training_output, + const gprat::SEKParams &sek_params, + int n_tiles, + int n_tile_size, + int n_regressors, + gprat::SYCL_DEVICE &sycl_device) +{ + sycl_device.create(); + + double *d_training_input = copy_to_device(h_training_input, sycl_device); + double *d_training_output = copy_to_device(h_training_output, sycl_device); + + // Assemble tiled covariance matrix on GPU. + auto d_K_tiles = assemble_tiled_covariance_matrix( + d_training_input, + static_cast(n_tiles), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + auto d_alpha_tiles = assemble_alpha_tiles( + d_training_output, static_cast(n_tiles), static_cast(n_tile_size), sycl_device); + + auto d_y_tiles = assemble_y_tiles( + d_training_output, static_cast(n_tiles), static_cast(n_tile_size), sycl_device); + + right_looking_cholesky_tiled( + d_K_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + // Triangular solve K_NxN * alpha = y + forward_solve_tiled(d_K_tiles, + d_alpha_tiles, + static_cast(n_tile_size), + static_cast(n_tiles), + sycl_device); + backward_solve_tiled(d_K_tiles, + d_alpha_tiles, + static_cast(n_tile_size), + static_cast(n_tiles), + sycl_device); + + // Compute loss + hpx::shared_future loss_value = compute_loss_tiled( + d_K_tiles, + d_alpha_tiles, + d_y_tiles, + static_cast(n_tile_size), + static_cast(n_tiles), + sycl_device); + + sycl::queue queue = sycl_device.next_queue(); + + sycl::free(d_training_input, queue); + sycl::free(d_training_output, queue); + + loss_value.get(); + + gprat::sycl_backend::free_lower_tiled_matrix(d_K_tiles, static_cast(n_tiles), sycl_device); + + gprat::sycl_backend::free(d_alpha_tiles, queue); + gprat::sycl_backend::free(d_y_tiles, queue); + + sycl_device.destroy(); + + return loss_value.get(); +} + +// cholesky /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +std::vector> +cholesky(const std::vector &h_training_input, + const gprat::SEKParams &sek_params, + int n_tiles, + int n_tile_size, + int n_regressors, + gprat::SYCL_DEVICE &sycl_device) +{ + sycl_device.create(); + + double *d_training_input = copy_to_device(h_training_input, sycl_device); + + // Assemble tiled covariance matrix on GPU. + std::vector> d_tiles = assemble_tiled_covariance_matrix( + d_training_input, + static_cast(n_tiles), + static_cast(n_tile_size), + static_cast(n_regressors), + sek_params, + sycl_device); + + // Compute Tiled Cholesky decomposition on device + right_looking_cholesky_tiled( + d_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + // Copy tiled matrix to host + std::vector> h_tiles = move_lower_tiled_matrix_to_host( + d_tiles, static_cast(n_tile_size), static_cast(n_tiles), sycl_device); + + sycl::queue queue = sycl_device.next_queue(); + sycl::free(d_training_input, queue); + + sycl_device.destroy(); + + return h_tiles; +} + +} // namespace gprat::sycl_backend diff --git a/core/src/gpu/sycl/sycl_gp_optimizer.cpp b/core/src/gpu/sycl/sycl_gp_optimizer.cpp new file mode 100644 index 00000000..2111a85f --- /dev/null +++ b/core/src/gpu/sycl/sycl_gp_optimizer.cpp @@ -0,0 +1,94 @@ +#include "gpu/sycl/sycl_gp_optimizer.hpp" + +#include "gpu/sycl/adapter_onemath.hpp" +#include "gpu/sycl/sycl_kernels.hpp" +#include "gpu/sycl/sycl_utils.hpp" + +namespace gprat::sycl_backend +{ + +// gen_tile_grad_l_trans ////////////////////////////////////////////////////////////////////////////////////////////// + +hpx::shared_future +gen_tile_grad_l_trans(std::size_t N, const hpx::shared_future f_grad_l_tile, gprat::SYCL_DEVICE &sycl_device) +{ + try + { + sycl::queue queue = sycl_device.next_queue(); + + double *transposed = sycl::malloc_device(N * N, queue); + double *d_grad_l_tile = f_grad_l_tile.get(); + + sycl::range<2> global_range(((N + WORK_GROUP_SIZE - 1) / WORK_GROUP_SIZE) * WORK_GROUP_SIZE, + ((N + WORK_GROUP_SIZE - 1) / WORK_GROUP_SIZE) * WORK_GROUP_SIZE); + sycl::range<2> local_range(WORK_GROUP_SIZE, WORK_GROUP_SIZE); + + auto event = queue.submit( + [&](sycl::handler &cgh) + { + cgh.parallel_for(sycl::nd_range<2>(global_range, local_range), + [=](sycl::nd_item<2> item) + { + std::size_t row = item.get_global_id(0); + std::size_t col = item.get_global_id(1); + + if (row < N && col < N) + { + transposed[row * N + col] = d_grad_l_tile[col * N + row]; + } + }); + }); + + event.wait(); + return hpx::make_ready_future(transposed); + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + return hpx::make_ready_future(static_cast(nullptr)); + } +} + +// compute_loss /////////////////////////////////////////////////////////////////////////////////////////////////////// + +double compute_loss(const hpx::shared_future &K_diag_tile, + const hpx::shared_future &alpha_tile, + const hpx::shared_future &y_tile, + std::size_t N, + gprat::SYCL_DEVICE &sycl_device) +{ + sycl::queue queue = sycl_device.next_queue(); + // l = y^T * alpha + \sum_i^N log(L_ii^2) + double l; + // Compute y^T * alpha (result in shared USM, readable from host) + double *d_dot = dot(queue, y_tile.get(), alpha_tile.get(), N); + l = *d_dot; + sycl::free(d_dot, queue); + // Copy diagonal tile to host so we can read it + std::vector h_diag(N * N); + queue.memcpy(h_diag.data(), K_diag_tile.get(), N * N * sizeof(double)).wait(); + // Compute \sum_i^N log(L_ii^2) + for (std::size_t i = 0; i < N; i++) + { + l += std::log(h_diag[i * N + i] * h_diag[i * N + i]); + } + return l; +} + +// add_losses ///////////////////////////////////////////////////////////////////////////////////////////////////////// + +hpx::shared_future +add_losses(const std::vector> &losses, std::size_t n_tile_size, std::size_t n_tiles) +{ + // Add the squared difference to the error + double l = 0.0; + for (std::size_t i = 0; i < n_tiles; i++) + { + l += losses[i].get(); + } + l += static_cast(n_tile_size) * static_cast(n_tiles) * log(2.0 * M_PI); + + return hpx::make_ready_future(0.5 * l / static_cast((n_tile_size * n_tiles))); +} + +} // end of namespace gprat::sycl_backend diff --git a/core/src/gpu/sycl/sycl_gp_uncertainty.cpp b/core/src/gpu/sycl/sycl_gp_uncertainty.cpp new file mode 100644 index 00000000..2fdd0d07 --- /dev/null +++ b/core/src/gpu/sycl/sycl_gp_uncertainty.cpp @@ -0,0 +1,63 @@ +// GPRat +#include "gpu/sycl/sycl_gp_uncertainty.hpp" + +#include "gprat/target.hpp" + +#include "gpu/sycl/sycl_utils.hpp" + +// oneMath +#include + +namespace gprat::sycl_backend +{ + +double *diag_posterior(double *A, double *B, std::size_t M) +{ + sycl::queue queue(sycl::gpu_selector_v); + + double *tile = sycl::malloc_device(M, queue); + + // tile = 1.0*A + (-1.0)*B + oneapi::math::blas::column_major::omatadd( + queue, + oneapi::math::transpose::nontrans, + oneapi::math::transpose::nontrans, + 1, + static_cast(M), + 1.0, + A, + 1, + -1.0, + B, + 1, + tile, + 1); + + queue.wait(); + + return tile; +} + +double *diag_tile(double *A, std::size_t M) +{ + sycl::queue queue(sycl::gpu_selector_v); + + double *diag_tile = sycl::malloc_device(M, queue); + + oneapi::math::blas::column_major::omatcopy( + queue, + oneapi::math::transpose::nontrans, + 1, + static_cast(M), + 1.0, + A, + static_cast(M) + 1, + diag_tile, + 1); + + queue.wait(); + + return diag_tile; +} + +} // end of namespace gprat::sycl_backend diff --git a/core/src/gpu/sycl/sycl_tiled_algorithms.cpp b/core/src/gpu/sycl/sycl_tiled_algorithms.cpp new file mode 100644 index 00000000..a18727b2 --- /dev/null +++ b/core/src/gpu/sycl/sycl_tiled_algorithms.cpp @@ -0,0 +1,522 @@ +#include "gpu/sycl/sycl_tiled_algorithms.hpp" + +#include "gpu/sycl/adapter_onemath.hpp" +#include "gpu/sycl/sycl_gp_optimizer.hpp" +#include "gpu/sycl/sycl_gp_uncertainty.hpp" +#include + +namespace gprat::sycl_backend +{ + +// Tiled Cholesky Algorithm + +void right_looking_cholesky_tiled(std::vector> &ft_tiles, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t k = 0; k < n_tiles; ++k) + { + result = potrf(sycl_device.next_queue(), ft_tiles[k * n_tiles + k].get(), n_tile_size); + ft_tiles[k * n_tiles + k] = hpx::make_ready_future(result); + + for (std::size_t m = k + 1; m < n_tiles; ++m) + { + result = trsm(sycl_device.next_queue(), + ft_tiles[k * n_tiles + k].get(), + ft_tiles[m * n_tiles + k].get(), + n_tile_size, + n_tile_size, + oneapi::math::transpose::trans, + oneapi::math::side::right); + + ft_tiles[m * n_tiles + k] = hpx::make_ready_future(result); + } + + for (std::size_t m = k + 1; m < n_tiles; ++m) + { + result = syrk(sycl_device.next_queue(), + ft_tiles[m * n_tiles + k].get(), + ft_tiles[m * n_tiles + m].get(), + n_tile_size); + + ft_tiles[m * n_tiles + m] = hpx::make_ready_future(result); + + for (std::size_t n = k + 1; n < m; ++n) + { + result = gemm( + sycl_device.next_queue(), + ft_tiles[m * n_tiles + k].get(), + ft_tiles[n * n_tiles + k].get(), + ft_tiles[m * n_tiles + n].get(), + n_tile_size, + n_tile_size, + n_tile_size, + oneapi::math::transpose::nontrans, + oneapi::math::transpose::trans); + + ft_tiles[m * n_tiles + n] = hpx::make_ready_future(result); + } + } + } +} + +// Tiled Triangular Solve Algorithms + +void forward_solve_tiled(std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t k = 0; k < n_tiles; ++k) + { + // TRSM: Solve L * x = a + result = trsv(sycl_device.next_queue(), + ft_tiles[k * n_tiles + k].get(), + ft_rhs[k].get(), + n_tile_size, + oneapi::math::transpose::nontrans); + + ft_rhs[k] = hpx::make_ready_future(result); + + double *x_k = result; + auto gemv_queue = sycl_device.next_queue(); + + for (std::size_t m = k + 1; m < n_tiles; ++m) + { + // GEMV: b = b - A * x_k + result = gemv(gemv_queue, + ft_tiles[m * n_tiles + k].get(), + x_k, + ft_rhs[m].get(), + n_tile_size, + n_tile_size, + -1, + oneapi::math::transpose::nontrans); + + ft_rhs[m] = hpx::make_ready_future(result); + } + } +} + +void backward_solve_tiled(std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + // NOTE: The loops traverse backwards. Its last comparisons require the + // usage negative numbers. Therefore they use signed int instead of the + // unsigned std::size_t. + + for (int k = static_cast(n_tiles) - 1; k >= 0; k--) + { + // TRSM: Solve L^T * x = a + result = trsv(sycl_device.next_queue(), + ft_tiles[static_cast(k) * n_tiles + static_cast(k)].get(), + ft_rhs[static_cast(k)].get(), + n_tile_size, + oneapi::math::transpose::trans); + + ft_rhs[static_cast(k)] = hpx::make_ready_future(result); + + for (int m = k - 1; m >= 0; m--) + { + // GEMV: b = b - A^T * a + result = gemv(sycl_device.next_queue(), + ft_tiles[static_cast(k) * n_tiles + static_cast(m)].get(), + ft_rhs[static_cast(k)].get(), + ft_rhs[static_cast(m)].get(), + n_tile_size, + n_tile_size, + -1, + oneapi::math::transpose::trans); + + ft_rhs[static_cast(m)] = hpx::make_ready_future(result); + } + } +} + +void forward_solve_tiled_matrix( + std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + double *result_gemm; + + for (std::size_t c = 0; c < m_tiles; ++c) + { + for (std::size_t k = 0; k < n_tiles; ++k) + { + // TRSM: solve L * X = A + result = trsm(sycl_device.next_queue(), + ft_tiles[static_cast(k) * n_tiles + static_cast(k)].get(), + ft_rhs[static_cast(k * m_tiles + c)].get(), + n_tile_size, + m_tile_size, + oneapi::math::transpose::nontrans, + oneapi::math::side::left); + + ft_rhs[static_cast(k * m_tiles + c)] = hpx::make_ready_future(result); + + for (std::size_t m = k + 1; m < n_tiles; ++m) + { + // GEMM: C = C - A * B + result_gemm = gemm( + sycl_device.next_queue(), + ft_tiles[m * n_tiles + k].get(), + ft_rhs[static_cast(k * m_tiles + c)].get(), + ft_rhs[m * m_tiles + c].get(), + n_tile_size, + m_tile_size, + n_tile_size, + oneapi::math::transpose::nontrans, + oneapi::math::transpose::nontrans); + + ft_rhs[m * m_tiles + c] = hpx::make_ready_future(result_gemm); + } + } + } +} + +void backward_solve_tiled_matrix( + std::vector> &ft_tiles, + std::vector> &ft_rhs, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t c = 0; c < m_tiles; ++c) + { + for (std::size_t k = 0; k < n_tiles; ++k) + { + // TRSM: solve L^T * X = A + result = trsm(sycl_device.next_queue(), + ft_tiles[static_cast(k) * n_tiles + static_cast(k)].get(), + ft_rhs[static_cast(k * m_tiles + c)].get(), + n_tile_size, + m_tile_size, + oneapi::math::transpose::trans, + oneapi::math::side::left); + + ft_rhs[static_cast(k * m_tiles + c)] = hpx::make_ready_future(result); + + for (std::size_t m = 0; m < k; ++m) + { + // GEMM: C = C - A^T * B + result = gemm( + sycl_device.next_queue(), + ft_tiles[k * n_tiles + m].get(), + ft_rhs[static_cast(k * m_tiles + c)].get(), + ft_rhs[m * m_tiles + c].get(), + n_tile_size, + m_tile_size, + n_tile_size, + oneapi::math::transpose::trans, + oneapi::math::transpose::nontrans); + + ft_rhs[m * m_tiles + c] = hpx::make_ready_future(result); + } + } + } +} + +void matrix_vector_tiled(std::vector> &ft_tiles, + std::vector> &ft_vector, + std::vector> &ft_rhs, + const std::size_t N_row, + const std::size_t N_col, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t k = 0; k < m_tiles; ++k) + { + for (std::size_t m = 0; m < n_tiles; ++m) + { + result = gemv(sycl_device.next_queue(), + ft_tiles[k * n_tiles + m].get(), + ft_vector[m].get(), + ft_rhs[k].get(), + N_row, + N_col, + 1, + oneapi::math::transpose::nontrans); + + ft_rhs[k] = hpx::make_ready_future(result); + } + } +} + +void symmetric_matrix_matrix_diagonal_tiled( + std::vector> &ft_tCC_tiles, + std::vector> &ft_inter_tiles, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t i = 0; i < m_tiles; ++i) + { + for (std::size_t n = 0; n < n_tiles; ++n) + { + // Compute inner product to obtain diagonal elements of + // (K_MxN * (K^-1_NxN * K_NxM)) + result = dot_diag_syrk(sycl_device.next_queue(), + ft_tCC_tiles[n * m_tiles + i].get(), + ft_inter_tiles[i].get(), + n_tile_size, + m_tile_size); + + ft_inter_tiles[i] = hpx::make_ready_future(result); + } + } +} + +void compute_gemm_of_invK_y(std::vector> &ft_invK, + std::vector> &ft_y, + std::vector> &ft_alpha, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t i = 0; i < n_tiles; ++i) + { + for (std::size_t j = 0; j < n_tiles; ++j) + { + result = gemv(sycl_device.next_queue(), + ft_invK[i * n_tiles + j].get(), + ft_y[j].get(), + ft_alpha[i].get(), + n_tile_size, + n_tile_size, + 1, + oneapi::math::transpose::nontrans); + + ft_alpha[i] = hpx::make_ready_future(result); + } + } +} + +hpx::shared_future compute_loss_tiled( + std::vector> &ft_tiles, + std::vector> &ft_alpha, + std::vector> &ft_y, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double total_loss = 0.0; + for (std::size_t k = 0; k < n_tiles; k++) + { + total_loss += compute_loss(ft_tiles[k * n_tiles + k], ft_alpha[k], ft_y[k], n_tile_size, sycl_device); + } + total_loss += static_cast(n_tile_size) * static_cast(n_tiles) * std::log(2.0 * M_PI); + return hpx::make_ready_future(0.5 * total_loss / static_cast(n_tile_size * n_tiles)); +} + +void symmetric_matrix_matrix_tiled( + std::vector> &ft_tCC_tiles, + std::vector> &ft_priorK, + const std::size_t n_tile_size, + const std::size_t m_tile_size, + const std::size_t n_tiles, + const std::size_t m_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t c = 0; c < m_tiles; ++c) + { + for (std::size_t k = 0; k < m_tiles; ++k) + { + for (std::size_t m = 0; m < n_tiles; ++m) + { + // GEMM: C = C - A^T * B + result = gemm( + sycl_device.next_queue(), + ft_tCC_tiles[m * m_tiles + c].get(), + ft_tCC_tiles[m * m_tiles + k].get(), + ft_priorK[c * m_tiles + k].get(), + n_tile_size, + m_tile_size, + m_tile_size, + oneapi::math::transpose::trans, + oneapi::math::transpose::nontrans); + + ft_priorK[c * m_tiles + k] = hpx::make_ready_future(result); + } + } + } +} + +void vector_difference_tiled(std::vector> &ft_priorK, + std::vector> &ft_inter, + std::vector> &ft_vector, + const std::size_t m_tile_size, + const std::size_t m_tiles) +{ + for (std::size_t i = 0; i < m_tiles; i++) + { + ft_vector[i] = hpx::dataflow(hpx::unwrapping(&diag_posterior), ft_priorK[i], ft_inter[i], m_tile_size); + } +} + +void matrix_diagonal_tiled(std::vector> &ft_priorK, + std::vector> &ft_vector, + const std::size_t m_tile_size, + const std::size_t m_tiles) +{ + for (std::size_t i = 0; i < m_tiles; i++) + { + ft_vector[i] = hpx::dataflow(hpx::unwrapping(&diag_tile), ft_priorK[i * m_tiles + i], m_tile_size); + } +} + +void update_grad_K_tiled_mkl(std::vector> &ft_tiles, + const std::vector> &ft_v1, + const std::vector> &ft_v2, + const std::size_t n_tile_size, + const std::size_t n_tiles, + gprat::SYCL_DEVICE &sycl_device) +{ + double *result; + + for (std::size_t i = 0; i < n_tiles; ++i) + { + for (std::size_t j = 0; j < n_tiles; ++j) + { + result = ger( + sycl_device.next_queue(), ft_tiles[i * n_tiles + j].get(), ft_v1[i].get(), ft_v2[j].get(), n_tile_size); + + ft_tiles[i * n_tiles + j] = hpx::make_ready_future(result); + } + } +} + +static double update_hyperparameter( + const std::vector> & /*ft_invK*/, + const std::vector> & /*ft_gradparam*/, + const std::vector> & /*ft_alpha*/, + double & /*hyperparameter*/, + gprat::SEKParams /*sek_params*/, + gprat::AdamParams /*adam_params*/, + const std::size_t /*n_tile_size*/, + const std::size_t /*n_tiles*/, + std::vector> & /*m_T*/, + std::vector> & /*v_T*/, + const std::vector> & /*beta1_T*/, + const std::vector> & /*beta2_T*/, + int /*iter*/, + int /*param_idx*/, + gprat::SYCL_DEVICE & /*sycl_device*/) +{ + throw std::logic_error("Function not implemented for GPU"); +} + +double update_lengthscale( + const std::vector> &ft_invK, + const std::vector> &ft_gradparam, + const std::vector> &ft_alpha, + gprat::SEKParams sek_params, + gprat::AdamParams adam_params, + const std::size_t n_tile_size, + const std::size_t n_tiles, + std::vector> &m_T, + std::vector> &v_T, + const std::vector> &beta1_T, + const std::vector> &beta2_T, + int iter, + gprat::SYCL_DEVICE &sycl_device) +{ + return update_hyperparameter( + ft_invK, + ft_gradparam, + ft_alpha, + sek_params.lengthscale, + sek_params, + adam_params, + n_tile_size, + n_tiles, + m_T, + v_T, + beta1_T, + beta2_T, + iter, + 0, + sycl_device); +} + +double update_vertical_lengthscale( + const std::vector> &ft_invK, + const std::vector> &ft_gradparam, + const std::vector> &ft_alpha, + gprat::SEKParams sek_params, + gprat::AdamParams adam_params, + const std::size_t n_tile_size, + const std::size_t n_tiles, + std::vector> &m_T, + std::vector> &v_T, + const std::vector> &beta1_T, + const std::vector> &beta2_T, + int iter, + gprat::SYCL_DEVICE &sycl_device) +{ + return update_hyperparameter( + ft_invK, + ft_gradparam, + ft_alpha, + sek_params.vertical_lengthscale, + sek_params, + adam_params, + n_tile_size, + n_tiles, + m_T, + v_T, + beta1_T, + beta2_T, + iter, + 1, + sycl_device); +} + +double update_noise_variance( + const std::vector> & /*ft_invK*/, + const std::vector> & /*ft_alpha*/, + gprat::SEKParams /*sek_params*/, + gprat::AdamParams /*adam_params*/, + const std::size_t /*n_tile_size*/, + const std::size_t /*n_tiles*/, + std::vector> & /*m_T*/, + std::vector> & /*v_T*/, + const std::vector> & /*beta1_T*/, + const std::vector> & /*beta2_T*/, + int /*iter*/, + gprat::SYCL_DEVICE & /*sycl_device*/) +{ + throw std::logic_error("Function not implemented for GPU"); +} + +} // namespace gprat::sycl_backend diff --git a/core/src/gp_hyperparameters.cpp b/core/src/hyperparameters.cpp similarity index 86% rename from core/src/gp_hyperparameters.cpp rename to core/src/hyperparameters.cpp index f0a8caab..2a4800ce 100644 --- a/core/src/gp_hyperparameters.cpp +++ b/core/src/hyperparameters.cpp @@ -1,12 +1,11 @@ -#include "gp_hyperparameters.hpp" +#include "gprat/hyperparameters.hpp" #include #include -namespace gprat_hyper -{ +GPRAT_NS_BEGIN -AdamParams::AdamParams(double lr, double b1, double b2, double eps, int opt_i) : +AdamParams::AdamParams(double lr, double b1, double b2, double eps, std::size_t opt_i) : learning_rate(lr), beta1(b1), beta2(b2), @@ -30,4 +29,4 @@ std::string AdamParams::repr() const return oss.str(); } -} // namespace gprat_hyper +GPRAT_NS_END diff --git a/core/src/gp_kernels.cpp b/core/src/kernels.cpp similarity index 73% rename from core/src/gp_kernels.cpp rename to core/src/kernels.cpp index 42952e7e..9fd0218e 100644 --- a/core/src/gp_kernels.cpp +++ b/core/src/kernels.cpp @@ -1,13 +1,13 @@ -#include "gp_kernels.hpp" +#include "gprat/kernels.hpp" #include -namespace gprat_hyper -{ -SEKParams::SEKParams(double lengthscale_, double vertical_lengthscale_, double noise_variance_) : - lengthscale(lengthscale_), - vertical_lengthscale(vertical_lengthscale_), - noise_variance(noise_variance_) +GPRAT_NS_BEGIN + +SEKParams::SEKParams(double in_lengthscale, double in_vertical_lengthscale, double in_noise_variance) : + lengthscale(in_lengthscale), + vertical_lengthscale(in_vertical_lengthscale), + noise_variance(in_noise_variance) { m_T.resize(this->size()); w_T.resize(this->size()); @@ -51,4 +51,5 @@ const double &SEKParams::get_param(std::size_t index) const } throw std::invalid_argument("Get Invalid param_idx"); } -} // namespace gprat_hyper + +GPRAT_NS_END diff --git a/core/src/performance_counters.cpp b/core/src/performance_counters.cpp new file mode 100644 index 00000000..f304063d --- /dev/null +++ b/core/src/performance_counters.cpp @@ -0,0 +1,131 @@ +#include "gprat/performance_counters.hpp" + +#include "gprat/detail/config.hpp" +#if GPRAT_WITH_DISTRIBUTED +#include "gprat/tile_cache.hpp" +#endif + +#include +#include +#include +#ifdef HPX_HAVE_MODULE_PERFORMANCE_COUNTERS +#include +#endif + +GPRAT_NS_BEGIN + +#define GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(name) \ + static std::atomic name(0); \ + std::uint64_t get_##name(bool reset) { return hpx::util::get_and_reset_value(name, reset); } + +GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(tile_data_allocations) +GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(tile_data_deallocations) +GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(tile_server_allocations) +GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(tile_server_deallocations) +GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(tile_transmission_time) +GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(tile_transmission_count) + +#undef GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR + +void track_tile_data_allocation(std::size_t /*size*/) { tile_data_allocations += 1; } + +void track_tile_data_deallocation(std::size_t /*size*/) { tile_data_deallocations += 1; } + +void track_tile_server_allocation(std::size_t /*size*/) { tile_server_allocations += 1; } + +void track_tile_server_deallocation(std::size_t /*size*/) { tile_server_deallocations += 1; } + +void record_transmission_time(std::int64_t elapsed_ns) +{ + HPX_ASSERT(elapsed_ns >= 0); + tile_transmission_count += 1; + if (elapsed_ns > 0) + { + tile_transmission_time += static_cast(elapsed_ns); + } +} + +#ifdef HPX_HAVE_MODULE_PERFORMANCE_COUNTERS +// These are non-public functions of their respective CUs. +namespace detail +{ +void register_fp32_performance_counters(); +void register_fp64_performance_counters(); +} // namespace detail + +void register_performance_counters() +{ + // XXX: you can do this with templates, but it's quite a bit more complicated +#define GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR(name, stats_expr) \ + hpx::performance_counters::install_counter_type( \ + name, \ + [](bool reset) { return hpx::util::get_and_reset_value(stats_expr, reset); }, \ + #stats_expr, \ + "", \ + hpx::performance_counters::counter_type::monotonically_increasing) + + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/tile_data/num_allocations", tile_data_allocations); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/tile_data/num_deallocations", tile_data_deallocations); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/tile_server/num_allocations", tile_server_allocations); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/tile_server/num_deallocations", tile_server_deallocations); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/tile_cache/transmission_time", tile_transmission_time); + GPRAT_MAKE_SIMPLE_COUNTER_ACCESSOR("/gprat/tile_cache/transmission_count", tile_transmission_count); + +#undef GPRAT_MAKE_STATISTICS_ACCESSOR + + // XXX: you can do this with templates, but it's quite a bit more complicated +#define GPRAT_MAKE_STATISTICS_ACCESSOR(name, stats_expr) \ + hpx::performance_counters::install_counter_type( \ + name, \ + [](bool reset) { return (stats_expr) (reset); }, \ + #stats_expr, \ + "", \ + hpx::performance_counters::counter_type::monotonically_increasing) + +#if GPRAT_WITH_DISTRIBUTED + GPRAT_MAKE_STATISTICS_ACCESSOR("/gprat/tile_cache/hits", detail::get_global_statistics().hits); + GPRAT_MAKE_STATISTICS_ACCESSOR("/gprat/tile_cache/misses", detail::get_global_statistics().misses); + GPRAT_MAKE_STATISTICS_ACCESSOR("/gprat/tile_cache/evictions", detail::get_global_statistics().evictions); + GPRAT_MAKE_STATISTICS_ACCESSOR("/gprat/tile_cache/insertions", detail::get_global_statistics().insertions); +#endif + +#undef GPRAT_MAKE_STATISTICS_ACCESSOR + + detail::register_fp32_performance_counters(); + detail::register_fp64_performance_counters(); +} + +#else +void register_performance_counters() +{ + // no-op for binary compatibility +} +#endif + +void force_evict_memory(const void *start, std::size_t size) +{ + // A cache line size of 64 seems to be a safe estimate. + // see: https://lemire.me/blog/2023/12/12/measuring-the-size-of-the-cache-line-empirically/ + constexpr std::size_t cache_line_size = 64; + + const char *p = static_cast(start); + const char *end = p + size; + + _mm_mfence(); + do { + // Intel recommends clflushopt over normal clflush due to higher performance, see: + // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf + _mm_clflush(p); + p += cache_line_size; + } while (p < end); + + // Make sure we don't miss a cache line at the end + if ((reinterpret_cast(p) & (cache_line_size - 1)) + != (reinterpret_cast(end - 1) & (cache_line_size - 1))) + { + _mm_clflush(end - 1); + } + _mm_mfence(); +} + +GPRAT_NS_END diff --git a/core/src/target.cpp b/core/src/target.cpp index 1b500702..0384102d 100644 --- a/core/src/target.cpp +++ b/core/src/target.cpp @@ -1,25 +1,32 @@ -#include "target.hpp" +#include "gprat/target.hpp" #include +#include #if GPRAT_WITH_CUDA -#include "gpu/cuda_utils.cuh" -using hpx::cuda::experimental::check_cuda_error; +#include "gprat/gpu/cuda_utils.cuh" #endif -namespace gprat -{ +#if GPRAT_WITH_SYCL +#include "gpu/sycl/sycl_utils.hpp" +#endif + +GPRAT_NS_BEGIN -CPU::CPU() { } +CPU::CPU() = default; bool CPU::is_cpu() { return true; } bool CPU::is_gpu() { return false; } +bool CPU::is_sycl() { return false; } + std::string CPU::repr() const { return "CPU"; } CPU get_cpu() { return CPU(); } +// CUDA /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #if GPRAT_WITH_CUDA CUDA_GPU::CUDA_GPU(int id, int n_streams) : id(id), @@ -28,22 +35,20 @@ CUDA_GPU::CUDA_GPU(int id, int n_streams) : shared_memory_size(0), streams() { -#if GPRAT_WITH_CUDA int deviceCount; cudaGetDeviceCount(&deviceCount); if (id >= deviceCount) { throw std::runtime_error("Requested GPU device is not available."); } -#else - throw std::runtime_error("CUDA is not available because GPRat has been compiled without CUDA."); -#endif } bool CUDA_GPU::is_cpu() { return false; } bool CUDA_GPU::is_gpu() { return true; } +bool CUDA_GPU::is_sycl() { return false; } + std::string CUDA_GPU::repr() const { std::ostringstream oss; @@ -107,8 +112,136 @@ std::pair CUDA_GPU::next_cublas_handle() CUDA_GPU get_gpu(int id, int n_streams) { return CUDA_GPU(id, n_streams); } CUDA_GPU get_gpu() { return CUDA_GPU(0, 1); } + +#endif + +// SYCL /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if GPRAT_WITH_SYCL + +SYCL_DEVICE::SYCL_DEVICE(int id, int n_queues) : + id(static_cast(id)), + n_queues(static_cast(n_queues)), + i_queue(0), + local_memory_size(0), + queues() +{ + try + { + std::vector all_gpus; + std::vector platforms = sycl::platform::get_platforms(); + + for (const auto &platform : platforms) + { + std::vector devices = platform.get_devices(); + for (const auto &device : devices) + { + if (device.get_info() == sycl::info::device_type::gpu) + { + all_gpus.push_back(device); + } + } + } + + const std::size_t device_count = all_gpus.size(); + if (static_cast(id) >= device_count) + { + throw std::runtime_error("Requested GPU device is not available."); + } + + // Store the selected device so create() can target it specifically. + selected_device_ = all_gpus[static_cast(id)]; + } + catch (const std::exception &e) + { + std::cout << "SYCL error during device selection: " << e.what() << "\n"; + throw; + } +} + +bool SYCL_DEVICE::is_cpu() { return false; } + +bool SYCL_DEVICE::is_gpu() { return false; } + +bool SYCL_DEVICE::is_sycl() { return true; } + +std::string SYCL_DEVICE::repr() const +{ + std::ostringstream oss; + oss << "SYCL DEVICE: [id=" << id << ", n_queues=" << n_queues << "]"; + return oss.str(); +} + +void SYCL_DEVICE::create() +{ + try + { + queues.resize(n_queues); + for (size_t i = 0; i < n_queues; ++i) + { + queues[i] = sycl::queue(selected_device_); + } + } + catch (const std::exception &e) + { + std::cout << "SYCL error during queue creation: " << e.what() << "\n"; + throw; + } +} + +void SYCL_DEVICE::destroy() +{ + try + { + queues.clear(); + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception during destruction: " << e.what() << "\n"; + } +} + +sycl::queue SYCL_DEVICE::next_queue() +{ + return queues[static_cast(i_queue++) % static_cast(n_queues)]; +} + +void SYCL_DEVICE::sync_queues(std::vector &subset_of_queues) +{ + try + { + if (subset_of_queues.size() < queues.size()) + { + for (sycl::queue &queue : subset_of_queues) + { + queue.wait(); + } + } + else + { + for (sycl::queue &queue : queues) + { + queue.wait(); + } + } + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + } +} + +SYCL_DEVICE get_sycl_device(const std::size_t id, const std::size_t n_queues) +{ + return SYCL_DEVICE(static_cast(id), static_cast(n_queues)); +} + +SYCL_DEVICE get_sycl_device() { return SYCL_DEVICE(0, 1); } + #endif +// General //////////////////////////////////////////////////////////////////////////////////////////////////////////// + void print_available_gpus() { #if GPRAT_WITH_CUDA @@ -133,8 +266,59 @@ void print_available_gpus() << " Memory Bus Width: " << deviceProp.memoryBusWidth << " bits" << std::endl; // clang-format on } +#elif GPRAT_WITH_SYCL + try + { + // Get all available platforms + std::vector platforms = sycl::platform::get_platforms(); + + // Loop over all platforms + for (const auto &platform : platforms) + { + std::cout << "Platform: " << platform.get_info() << "\n"; + + // Get all devices for each platform + std::vector devices = platform.get_devices(); + + for (size_t i = 0; i < devices.size(); ++i) + { + sycl::device device = devices[i]; + + // Check if the device is a GPU + if (device.get_info() == sycl::info::device_type::gpu) + { + std::cout << "Device " << i << ": " << device.get_info() << "\n"; + + // Query various device properties for GPUs + try + { + std::cout << " Total Global Memory: " << device.get_info() + << " bytes\n" + << " Max Compute Units: " << device.get_info() + << "\n" + << " Max Work Group Size: " + << device.get_info() << "\n" + << " Max Work Item Dimensions: " + << device.get_info() << "\n" + << " Max Clock Frequency: " + << device.get_info() << " MHz\n" + << " Max Memory Allocation Size: " + << device.get_info() << " bytes\n"; + } + catch (const sycl::exception &e) + { + std::cerr << "Error querying device properties: " << e.what() << std::endl; + } + } + } + } + } + catch (const sycl::exception &e) + { + std::cerr << "SYCL exception: " << e.what() << std::endl; + } #else - std::cout << "CUDA is not available - There are no GPUs available. You can only " + std::cout << "There are no GPUs available. You can only " "`get_cpu()` to utilize the CPU for computation." << std::endl; #endif @@ -143,15 +327,45 @@ void print_available_gpus() int gpu_count() { #if GPRAT_WITH_CUDA + int deviceCount; cudaGetDeviceCount(&deviceCount); return deviceCount; + +#elif GPRAT_WITH_SYCL + + try + { + std::vector all_gpus; + std::vector platforms = sycl::platform::get_platforms(); + + for (const auto &platform : platforms) + { + std::vector devices = platform.get_devices(); + for (const auto &device : devices) + { + if (device.get_info() == sycl::info::device_type::gpu) + { + all_gpus.push_back(device); + } + } + } + return static_cast(all_gpus.size()); + } + catch (const sycl::exception &e) + { + std::cout << "SYCL exception: " << e.what() << "\n"; + } + return 0; + #else - std::cout << "CUDA is not available - There are no GPUs available. You can only " + + std::cout << "GPRat has been compiled without GPU support. You can only " "use `get_cpu()` to utilize the CPU for computation." << std::endl; return 0; + #endif } -} // namespace gprat +GPRAT_NS_END diff --git a/core/src/tile_cache.cpp b/core/src/tile_cache.cpp new file mode 100644 index 00000000..6a1c658a --- /dev/null +++ b/core/src/tile_cache.cpp @@ -0,0 +1,15 @@ +#include "gprat/tile_cache.hpp" + +GPRAT_NS_BEGIN + +namespace detail +{ +hpx::util::cache::statistics::local_full_statistics &get_global_statistics() +{ + static hpx::util::cache::statistics::local_full_statistics stats; + return stats; +} + +} // namespace detail + +GPRAT_NS_END diff --git a/core/src/tile_data.cpp b/core/src/tile_data.cpp new file mode 100644 index 00000000..24ef9eb3 --- /dev/null +++ b/core/src/tile_data.cpp @@ -0,0 +1,34 @@ +#include "gprat/tile_data.hpp" + +#include "gprat/performance_counters.hpp" + +#include + +GPRAT_NS_BEGIN + +namespace detail +{ + +void *allocate_tile_data(std::size_t num_bytes) +{ + auto &topology = hpx::get_runtime().get_topology(); + const auto bitmap = topology.cpuset_to_nodeset(topology.get_machine_affinity_mask()); + + track_tile_data_allocation(num_bytes); + return topology.allocate_membind(num_bytes, bitmap, hpx::threads::hpx_hwloc_membind_policy::membind_firsttouch, 0); +} + +void deallocate_tile_data(void *p, std::size_t num_bytes) +{ + track_tile_data_deallocation(num_bytes); + + if (hpx::is_running()) + { + auto &topology = hpx::get_runtime().get_topology(); + topology.deallocate(p, num_bytes); + } +} + +} // namespace detail + +GPRAT_NS_END diff --git a/core/src/tiled_dataset.cpp b/core/src/tiled_dataset.cpp new file mode 100644 index 00000000..26c3c674 --- /dev/null +++ b/core/src/tiled_dataset.cpp @@ -0,0 +1,3 @@ +#include "gprat/tiled_dataset.hpp" + +GPRAT_REGISTER_TILED_DATASET(double, double) diff --git a/core/src/utils_c.cpp b/core/src/utils.cpp similarity index 56% rename from core/src/utils_c.cpp rename to core/src/utils.cpp index 896b7ad0..0dd8fff5 100644 --- a/core/src/utils_c.cpp +++ b/core/src/utils.cpp @@ -1,11 +1,13 @@ -#include "utils_c.hpp" +#include "gprat/utils.hpp" #include +#if GPRAT_WITH_SYCL +#include +#endif -namespace utils -{ +GPRAT_NS_BEGIN -int compute_train_tiles(int n_samples, int n_tile_size) +std::size_t compute_train_tiles(std::size_t n_samples, std::size_t n_tile_size) { if (n_tile_size > 0) { @@ -18,7 +20,7 @@ int compute_train_tiles(int n_samples, int n_tile_size) } } -int compute_train_tile_size(int n_samples, int n_tiles) +std::size_t compute_train_tile_size(std::size_t n_samples, std::size_t n_tiles) { if (n_tiles > 0) { @@ -31,10 +33,10 @@ int compute_train_tile_size(int n_samples, int n_tiles) } } -std::pair compute_test_tiles(int n_test, int n_tiles, int n_tile_size) +std::pair compute_test_tiles(std::size_t n_test, std::size_t n_tiles, std::size_t n_tile_size) { - int m_tiles; - int m_tile_size; + std::size_t m_tiles; + std::size_t m_tile_size; // if n_test is not divisible by (incl. smaller than) n_tile_size, use the same number of tiles if ((n_test % n_tile_size) > 0) @@ -51,10 +53,35 @@ std::pair compute_test_tiles(int n_test, int n_tiles, int n_tile_size) return { m_tiles, m_tile_size }; } -std::vector load_data(const std::string &file_path, int n_samples, int offset) +std::size_t guess_good_tile_count_per_dimension(std::size_t n) +{ + // These have been found through experimentation - they are only estimates that have been shown to perform + // better than fixed tile counts. + const auto hw_concurrency = hpx::threads::hardware_concurrency(); + + // For small datasets / few cores we shouldn't bother + if (n < (1 << 8) || hw_concurrency < 4) + { + return 1; + } + + if (n < (1 << 12) || hw_concurrency < 16) + { + return 4; + } + + if (n < (1 << 18) || hw_concurrency < 32) + { + return 16; + } + + return std::min(hw_concurrency, n / 256); +} + +std::vector load_data(const std::string &file_path, std::size_t n_samples, std::size_t offset) { std::vector _data; - _data.resize(static_cast(n_samples + offset), 0.0); + _data.resize(n_samples + offset, 0.0); FILE *input_file = fopen(file_path.c_str(), "r"); if (input_file == NULL) @@ -63,11 +90,14 @@ std::vector load_data(const std::string &file_path, int n_samples, int o } // load data - int scanned_elements = 0; - for (int i = 0; i < n_samples; i++) + std::size_t scanned_elements = 0; + for (std::size_t i = 0; i < n_samples; i++) { - scanned_elements += - fscanf(input_file, "%lf", &_data[static_cast(i + offset)]); // scanned_elements++; + const auto r = fscanf(input_file, "%lf", &_data[(i + offset)]); + if (r > 0) + { + scanned_elements += static_cast(r); + } } fclose(input_file); @@ -141,4 +171,27 @@ bool compiled_with_cuda() #endif } -} // namespace utils +bool compiled_with_sycl() +{ +#if GPRAT_WITH_SYCL + return true; +#else + return false; +#endif +} + +bool sycl_gpu_functional() +{ +#if GPRAT_WITH_SYCL + // libonemath_lapack_cusolver.so requires sycl::_V1::detail::SubmissionInfo::SubmissionInfo() + // which was introduced after oneAPI 2025.0. If the symbol is absent the LAPACK backend will + // crash with a dynamic linker error at the first call site. + dlerror(); // clear any previous error + void *sym = dlsym(RTLD_DEFAULT, "_ZN4sycl3_V16detail14SubmissionInfoC1Ev"); + return sym != nullptr; +#else + return false; +#endif +} + +GPRAT_NS_END diff --git a/create_python_package.sh b/create_python_package.sh index 6ea4d99b..883377b3 100755 --- a/create_python_package.sh +++ b/create_python_package.sh @@ -1,4 +1,8 @@ #!/bin/bash + +spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" +source $spack_destination/spack/share/spack/setup-env.sh + if command -v spack &> /dev/null; then echo "Spack command found, checking for environments..." diff --git a/data/data_1024/output.json b/data/data_1024/output.json index ba966b95..b9f63f79 100644 --- a/data/data_1024/output.json +++ b/data/data_1024/output.json @@ -1 +1 @@ -{"choleksy":[[1.0488088481701516E0,9.983462763853087E-1,9.971948660405838E-1,9.962569870514585E-1,9.95245691709372E-1,9.938758189144798E-1,9.918647654899141E-1,9.889340600584038E-1,9.863008018781477E-1,9.814239128903309E-1,9.743431484733321E-1,9.651141501135281E-1,9.538076846989525E-1,9.405086973725397E-1,9.253151964637757E-1,9.083369918799128E-1,8.896943106526867E-1,8.69516315057808E-1,8.479395498252674E-1,8.25106345430617E-1,8.011632043114504E-1,7.762591961174596E-1,7.505443868207682E-1,7.241683247435408E-1,6.972786043711611E-1,6.700195262889018E-1,6.425308687907773E-1,6.149467837463306E-1,5.873948262592331E-1,5.599951245923527E-1,5.328596938435468E-1,5.060918940034972E-1,9.518858256460321E-1,4.403559638907732E-1,9.982024329990548E-1,9.966205341159102E-1,9.949671086435963E-1,9.929574863900363E-1,9.903102838094936E-1,9.867489634733181E-1,9.834890046029382E-1,9.779977052614807E-1,9.703190338848883E-1,9.605126495014892E-1,9.48653093195914E-1,9.348287975810272E-1,9.191409335227059E-1,9.01702116097625E-1,8.826349939399145E-1,8.62070747707032E-1,8.40147524345694E-1,8.170088341615384E-1,7.928019374060763E-1,7.676762462234563E-1,7.417817663950553E-1,7.152676014426042E-1,6.882805393716632E-1,6.609637397357409E-1,6.33455535860819E-1,6.058883640759408E-1,5.783878287321358E-1,5.51071908739928E-1,5.240503083896528E-1,4.9742395240552356E-1,9.507879989574666E-1,2.1155796954346645E-1,3.8890282405904747E-1,9.980587374251528E-1,9.960471191073174E-1,9.936803925906429E-1,9.906774995724066E-1,9.867626287333733E-1,9.831518667663292E-1,9.773140046651455E-1,9.692953907509122E-1,9.591579723987234E-1,9.46978460221211E-1,9.328473125429653E-1,9.168675598300923E-1,8.991534914067097E-1,8.798292288909632E-1,8.590272122778778E-1,8.368866254647221E-1,8.135517882552219E-1,7.891705415090166E-1,7.638926511563258E-1,7.37868255324268E-1,7.112463768829415E-1,6.84173521388729E-1,6.567923777592151E-1,6.29240636142773E-1,6.016499344319168E-1,5.741449417970548E-1,5.468425845664778E-1,5.19851416823149E-1,4.9327113529487604E-1,9.498937664280961E-1,2.0989864919011159E-1,1.2986640585712897E-1,3.6983659391542584E-1,9.97915229073093E-1,9.954747771117294E-1,9.923971832954881E-1,9.88406321730185E-1,9.847204229679979E-1,9.788043654240689E-1,9.707050482509328E-1,9.604849800554243E-1,9.482214361638279E-1,9.340054362881847E-1,9.179405623782859E-1,9.001416391032782E-1,8.807333014969042E-1,8.598484757823092E-1,8.376268002461542E-1,8.14213013256669E-1,7.897553351337906E-1,7.644038696163304E-1,7.383090491810221E-1,7.116201465140736E-1,6.844838720903792E-1,6.570430751590493E-1,6.294355625508715E-1,6.017930466995246E-1,5.742402311881227E-1,5.468940390761758E-1,5.198629863031894E-1,4.932466996695792E-1,9.489295341527383E-1,2.082282132312769E-1,1.2795990439546354E-1,9.790395769217386E-2,3.6085291790768437E-1,9.977719472347261E-1,9.949036634421792E-1,9.911178223119708E-1,9.876356402881383E-1,9.819141158158929E-1,9.739988375597842E-1,9.639511085087087E-1,9.518471171854396E-1,9.377769272706643E-1,9.218433052368341E-1,9.041604082970758E-1,8.848523571174188E-1,8.640517192762011E-1,8.418979303612812E-1,8.185356798713186E-1,7.941132887480834E-1,7.687811044459943E-1,7.426899379917177E-1,7.159895655626723E-1,6.888273147910644E-1,6.613467533595486E-1,6.336864945802454E-1,6.059791316266061E-1,5.783503090022356E-1,5.509179367630067E-1,5.237915500332686E-1,4.9707181354014734E-1,9.476234116907833E-1,2.0648793296188736E-1,1.260141463612267E-1,9.633082159422765E-2,8.311298870330752E-2,3.567991619851197E-1,9.976289310613308E-1,9.943339325389622E-1,9.91339344464842E-1,9.86091742466748E-1,9.786334850376434E-1,9.690228308526938E-1,9.573331458635047E-1,9.436519248940329E-1,9.280796468081213E-1,9.107284851352506E-1,8.917208982988603E-1,8.711881252465042E-1,8.492686133082544E-1,8.261064055033798E-1,8.018495142884102E-1,7.766483079227584E-1,7.506539342674614E-1,7.240168049882169E-1,6.968851608765735E-1,6.694037364117976E-1,6.417125388445882E-1,6.139457540784692E-1,5.862307885406463E-1,5.586874531531141E-1,5.314272925128398E-1,5.045530595351031E-1,9.457059474854856E-1,2.0462127132961727E-1,1.2399594574630425E-1,9.470226369887053E-2,8.244135012699529E-2,7.736586042465483E-2,3.5587192967247533E-1,9.974862195407934E-1,9.952683661138827E-1,9.907814803640083E-1,9.840626987897277E-1,9.751653046898169E-1,9.641579945836999E-1,9.511239535782791E-1,9.361597578491718E-1,9.193741253791287E-1,9.0088653852732E-1,8.808257638409832E-1,8.59328295735186E-1,8.365367512460465E-1,8.12598243015398E-1,7.876627570163635E-1,7.618815603217042E-1,7.354056625064681E-1,7.083843521314696E-1,6.809638272514226E-1,6.532859361140233E-1,6.254870412497011E-1,5.976970170819167E-1,5.700383880977726E-1,5.426256115861873E-1,5.155645060464954E-1,9.429116294964417E-1,2.0257418051224285E-1,1.2187462288118832E-1,9.29950606719435E-2,8.169483546114234E-2,7.812113181859504E-2,7.761318585548678E-2,3.571821542883523E-1,9.988518900108769E-1,9.954190581196096E-1,9.897313559515383E-1,9.81835061591001E-1,9.71792230485948E-1,9.596798485192447E-1,9.455888040855486E-1,9.296226991893284E-1,9.118965222361909E-1,8.925352072699224E-1,8.716721058737622E-1,8.494473987878011E-1,8.260064744955974E-1,8.014983016210725E-1,7.760738209874848E-1,7.498843816748697E-1,7.230802434345562E-1,6.958091654530348E-1,6.682150987833664E-1,6.404369968653992E-1,6.126077555222567E-1,5.848532907341127E-1,5.572917594311539E-1,5.300329255892923E-1,9.404009163337426E-1,2.0059840030284964E-1,1.1980311832034857E-1,9.132606538936672E-2,8.09748518134158E-2,7.888977664191144E-2,8.035471974681917E-2,8.228929752966851E-2,3.5595537363197827E-1,9.988536933972448E-1,9.954268716203156E-1,9.897502304832465E-1,9.81870802250616E-1,9.718512887767433E-1,9.597691993983815E-1,9.457158107937641E-1,9.297949691077079E-1,9.12121757201779E-1,8.928210518676031E-1,8.720259972060331E-1,8.498764211100407E-1,8.265172218986714E-1,8.020967516550934E-1,7.767652217621105E-1,7.506731545564874E-1,7.239699030041512E-1,6.968022579062401E-1,6.693131594619738E-1,6.416405271227767E-1,6.13916218657903E-1,5.862651262977375E-1,5.588044148050514E-1,9.357509851319555E-1,1.9817968492805021E-1,1.1747589221408314E-1,8.946253075707929E-2,8.007369907144662E-2,7.946683500584431E-2,8.288427480587283E-2,8.713487322601209E-2,8.509593584780317E-2,3.5897129976724407E-1,9.988558100916567E-1,9.954359317213732E-1,9.897718883023335E-1,9.819114412252787E-1,9.719179058618361E-1,9.598692750590352E-1,9.458571676877856E-1,9.299856228021106E-1,9.123697624259818E-1,8.931343478615462E-1,8.724122556758167E-1,8.503429001608896E-1,8.270706290825097E-1,8.027431189579683E-1,7.775097949776758E-1,7.515202990599902E-1,7.249230274722614E-1,6.978637570375075E-1,6.704843762564766E-1,6.42921734792746E-1,6.153066217776846E-1,5.87762880373681E-1,9.289997411570858E-1,1.9533594478570854E-1,1.1490970803456522E-1,8.741785944135132E-2,7.899811837962627E-2,7.984887779160454E-2,8.518495196709994E-2,9.17167106710492E-2,9.487727963912801E-2,9.39215217185593E-2,3.631105877981804E-1,9.988582388761283E-1,9.954462332290304E-1,9.897963170824723E-1,9.819569556310943E-1,9.719920447573411E-1,9.599800209225353E-1,9.460127993201629E-1,9.301945610779254E-1,9.126404126541883E-1,8.934749423486132E-1,8.728307000090213E-1,8.508466265586875E-1,8.276664599004646E-1,8.034371431036945E-1,7.783072595897209E-1,7.524255183582494E-1,7.259393102069966E-1,6.989933534663272E-1,6.717284450794061E-1,6.44280329989664E-1,6.167786988334732E-1,9.202002364848036E-1,1.9208798011523934E-1,1.121228367774541E-1,8.520658770023318E-2,7.775605757089032E-2,8.003401885695097E-2,8.724186950285168E-2,9.600433681887907E-2,1.0429880176496036E-1,1.0707601700708445E-1,1.0304231627377945E-1,3.66416951023689E-1,9.988609783501585E-1,9.954577702270767E-1,9.89823502897527E-1,9.820073198002579E-1,9.720736642446255E-1,9.601013765057033E-1,9.461826225041332E-1,9.304216750594677E-1,9.129335709624108E-1,8.93842668782331E-1,8.732811333882342E-1,8.513873736092277E-1,8.283044593074766E-1,8.041785434126535E-1,7.791573132168064E-1,7.533884935101394E-1,7.270184220193645E-1,7.001907151665141E-1,6.730450394774814E-1,6.45716001117991E-1,9.094199446954067E-1,1.8845921274076977E-1,1.0913482694744828E-1,8.284420261576221E-2,7.635656768372633E-2,8.002192903313421E-2,8.904233306924039E-2,9.997014116132927E-2,1.1329788337182257E-1,1.1977225516088724E-1,1.1794063818924215E-1,1.0920484804454826E-1,3.680910481807598E-1,9.98864026931642E-1,9.954705360806387E-1,9.898534302302388E-1,9.820625052964183E-1,9.721627188936215E-1,9.602332754525789E-1,9.463665463531333E-1,9.306668462353024E-1,9.132490888048878E-1,8.942373470175393E-1,8.737633434873971E-1,8.519648973216633E-1,8.289843533467189E-1,8.049670188969767E-1,7.800596320313004E-1,7.544088832824833E-1,7.281600109015266E-1,7.01455487105761E-1,6.74433810157735E-1,8.967398578048209E-1,1.8447538879007783E-1,1.0596626283662326E-1,8.034695086447088E-2,7.48096869259535E-2,7.981382849020757E-2,9.057597191749864E-2,1.0358968804579946E-1,1.2181653258009509E-1,1.3192672512749448E-1,1.323078240072696E-1,1.2444318710080576E-1,1.1151294117428191E-1,3.681981515112831E-1,9.988673828579022E-1,9.954845234404425E-1,9.898860819819234E-1,9.821224809317344E-1,9.722591590885858E-1,9.603756455693387E-1,9.465644723241518E-1,9.309299465078708E-1,9.135868060661796E-1,8.946587833593667E-1,8.742771025102154E-1,8.525789364270628E-1,8.297058491372667E-1,8.058022482047306E-1,7.810138706461787E-1,7.554863239645916E-1,7.293637017536072E-1,7.02787290869096E-1,8.822534230886454E-1,1.801642579243263E-1,1.0263851548022593E-1,7.773164248998812E-2,7.312631426710936E-2,7.941245782749877E-2,9.18348391855569E-2,1.0684197687671246E-1,1.2980203864774345E-1,1.434620993832832E-1,1.4605049708771944E-1,1.3911790712968197E-1,1.2614728847632758E-1,1.1059800870976823E-1,3.6719297597085576E-1,9.98871044186844E-1,9.954997242475443E-1,9.899214394831746E-1,9.821872127856176E-1,9.723629310562987E-1,9.605284088624009E-1,9.467762942649272E-1,9.312108382474459E-1,9.139465511178199E-1,8.951067706166456E-1,8.74822167232482E-1,8.53229212399882E-1,8.304686348631618E-1,8.066838895634166E-1,7.820196619984708E-1,7.566204291761711E-1,7.306290960999915E-1,8.660653401853742E-1,1.7555523492588318E-1,9.917349069169581E-2,7.501545313948998E-2,7.131807498866959E-2,7.882202867139515E-2,9.281347497956867E-2,1.0970964627849411E-1,1.3720753415155584E-1,1.5430808998862247E-1,1.59082503225814E-1,1.5313464281088415E-1,1.4022579015606715E-1,1.2416286252607184E-1,1.0761909796023673E-1,3.655719413180943E-1,9.988750087982254E-1,9.955161297385232E-1,9.899594825055664E-1,9.822566642251502E-1,9.724739768966897E-1,9.606914815797104E-1,9.470018984649996E-1,9.315093743504493E-1,9.143281408795864E-1,8.955810881598869E-1,8.753982790485051E-1,8.539154294826323E-1,8.312723797642644E-1,8.076115807233076E-1,7.830766172300198E-1,7.57810789669436E-1,8.482902410719829E-1,1.7067904966147157E-1,9.559337849228777E-2,7.221572814241288E-2,6.93971806113453E-2,7.804815496239319E-2,9.350893176767738E-2,1.1217911957950884E-1,1.4399245672134833E-1,1.6440218040062834E-1,1.7132584423214192E-1,1.6640664498984276E-1,1.5365849925682853E-1,1.3721046127165154E-1,1.2000430200364434E-1,1.0364776354602073E-1,3.637257315213025E-1,9.988792743950471E-1,9.95533730451135E-1,9.90000189274349E-1,9.823307959271713E-1,9.725922346158846E-1,9.608647742552023E-1,9.472411637106224E-1,9.318253983021592E-1,9.147313808854632E-1,8.960815019839369E-1,8.760051640218398E-1,8.546372747140429E-1,8.321167341293065E-1,8.085849389011703E-1,7.841843255662585E-1,8.290512771463038E-1,1.6556739146562263E-1,9.19204080665371E-2,6.934979165031484E-2,6.737628565086648E-2,7.709776647717297E-2,9.392076241520908E-2,1.1424069029417347E-1,1.501229042290935E-1,1.7369022244628143E-1,1.8271146747983294E-1,1.7885570280186705E-1,1.663629061221123E-1,1.4965738206762974E-1,1.319299314490676E-1,1.1495124276805806E-1,9.946070650342467E-2,3.6191613821837704E-1,9.988838385050591E-1,9.955525162304208E-1,9.900435364821286E-1,9.824095659020176E-1,9.727176381616578E-1,9.610481917564327E-1,9.474939613435399E-1,9.321587442438397E-1,9.151560653543657E-1,8.966077647754507E-1,8.766425329405354E-1,8.553944179610274E-1,8.330013292915796E-1,8.09603560724951E-1,8.084786387001414E-1,1.602525538791924E-1,8.817661210172825E-2,6.643476382820561E-2,6.526834362899342E-2,7.597900645048308E-2,9.405097196918631E-2,1.1588854759636151E-1,1.5557187978964582E-1,1.8212689103678856E-1,1.9317990051831208E-1,1.9041291552010448E-1,1.7826480484242593E-1,1.6142706763408168E-1,1.433189163963001E-1,1.2586189678044818E-1,1.0987637915794825E-1,9.554601738797078E-2,3.6029906424408525E-1,9.988886984823842E-1,9.955724762352689E-1,9.900894993035262E-1,9.824929295189088E-1,9.728501174612797E-1,9.61241633335372E-1,9.477601553236399E-1,9.325092370443291E-1,9.156019772657028E-1,8.971596159853163E-1,8.773100813771157E-1,8.561865119547788E-1,8.33925777627709E-1,7.867080325172441E-1,1.5476708543772724E-1,8.438360401835868E-2,6.348738879904155E-2,6.308646468787789E-2,7.470111542837202E-2,9.390393502980111E-2,1.1712074305417024E-1,1.6031942540046168E-1,1.8967599247295144E-1,2.0268172348150112E-1,2.0101930395171858E-1,1.8929901403270671E-1,1.7245063007990113E-1,1.541002757470896E-1,1.3630763656140665E-1,1.1996777226688098E-1,1.0529460285744686E-1,9.217275065574995E-2,3.5895406756517473E-1,9.988938515092547E-1,9.955935989454241E-1,9.901380514108027E-1,9.825808395329648E-1,9.729895984617465E-1,9.614449926823518E-1,9.480396022954849E-1,9.328766923761163E-1,9.160688884398581E-1,8.97736781906174E-1,8.780074897535224E-1,8.57013192331332E-1,7.63879143191091E-1,1.4914345184645117E-1,8.056237118226527E-2,6.052387570486829E-2,6.0843777027524436E-2,7.327430369332122E-2,9.348628120841368E-2,1.1793910109975744E-1,1.6435264546449932E-1,1.9631062545585493E-1,2.1117787571287794E-1,2.1062625493638204E-1,1.9940994273643023E-1,1.8266752015329366E-1,1.6420987369354512E-1,1.4622162655036142E-1,1.2966597817574016E-1,1.147843712650352E-1,1.0146396580790043E-1,8.945843542878774E-2,3.579078319671605E-1,9.988992945978645E-1,9.956158721689399E-1,9.901891649904444E-1,9.826732461138415E-1,9.731360031723769E-1,9.616581579831577E-1,9.483321516587309E-1,9.332609167959439E-1,9.165565596236659E-1,8.983389757551751E-1,8.787344234112554E-1,7.40134103055855E-1,1.43413714417214E-1,7.673308672180451E-2,5.755975487162852E-2,5.8553294213573685E-2,7.170961474951758E-2,9.280675174994493E-2,1.1834907680716346E-1,1.6766562373734573E-1,2.0201319708582932E-1,2.1863979668440248E-1,2.1919579626700433E-1,2.0855199583378511E-1,1.9202605344435883E-1,1.7359105533013167E-1,1.5554301825671407E-1,1.3890654662038132E-1,1.239478290450957E-1,1.1055560216162309E-1,9.847209882933211E-2,8.741841237581299E-2,3.5715056537709716E-1,9.989050245923325E-1,9.956392830500693E-1,9.90242810760698E-1,9.827700968759707E-1,9.732892497097603E-1,9.618810119792548E-1,9.48637645642436E-1,9.336617078299709E-1,9.170647405809688E-1,8.989658977621333E-1,7.15615994401875E-1,1.376092290948305E-1,7.291494207021289E-2,5.460975066198998E-2,5.6227790192462095E-2,7.00187824411875E-2,9.187603087943008E-2,1.1835956551951889E-1,1.702592393572444E-1,2.0677529912052245E-1,2.2504940480011248E-1,2.2670070304786313E-1,2.1668981692895725E-1,2.0048378833950384E-1,1.8219515307693204E-1,1.6421757635207657E-1,1.4763022031310605E-1,1.3272124173895203E-1,1.1938008763903359E-1,1.0733727236350674E-1,9.629608881667351E-2,8.599935389214512E-2,3.566476263354939E-1,9.989110381707773E-1,9.956638180775891E-1,9.902989579900435E-1,9.828713369103884E-1,9.734492523450408E-1,9.621134320311392E-1,9.489559193832674E-1,9.340788540635304E-1,9.17593170188338E-1,6.904674059596193E-1,1.3176036978449934E-1,6.912600182932994E-2,5.168767218373334E-2,5.3879683610627255E-2,6.821408429902513E-2,9.070655580888894E-2,1.1798266968361112E-1,1.7214088950390494E-1,2.1059745249438452E-1,2.303989209561024E-1,2.3312444002963245E-1,2.2379837020461918E-1,2.0800775384878328E-1,1.899818586151428E-1,1.7219818862339717E-1,1.5578357438587342E-1,1.4104539221497817E-1,1.2787303939710967E-1,1.1598520116188187E-1,1.0506718821483328E-1,9.484200238094057E-2,8.510318557960882E-2,3.5634870410263697E-1,9.98917331847502E-1,9.956894630935506E-1,9.903575745165966E-1,9.82976908818138E-1,9.736159215535197E-1,9.623552901847997E-1,9.49286801007607E-1,9.345121352355193E-1,6.648290635492802E-1,1.2589627902786754E-1,6.538308202120047E-2,4.8806322602168384E-2,5.152093277154805E-2,6.630819367140865E-2,8.931230960604147E-2,1.1723342889891179E-1,1.7332412784724377E-1,2.1348873051306388E-1,2.346905466958455E-1,2.3846094772376641E-1,2.298628660658278E-1,2.1457452866864463E-1,1.969194580742814E-1,1.7944525392548086E-1,1.6331955035885462E-1,1.4886625132119113E-1,1.3597405905799545E-1,1.2434988928563653E-1,1.1366109572960029E-1,1.0361051521357793E-1,9.397266367486255E-2,8.460634007174693E-2,3.561959164658303E-1,9.989239019752856E-1,9.957162033024535E-1,9.904186267684248E-1,9.830867527452284E-1,9.73789164066557E-1,9.626064532412784E-1,9.496301117175631E-1,6.388385523805215E-1,1.2004464838269881E-1,6.170165227292862E-2,4.5977427394785435E-2,4.916294228714746E-2,6.431403310227413E-2,8.770860127898925E-2,1.1612951966059552E-1,1.738282292596811E-1,2.1546627317608769E-1,2.3793600938648768E-1,2.4271428302194936E-1,2.3487853846635978E-1,2.201701759171919E-1,2.0298493118853927E-1,1.859269450808475E-1,1.7019787788614266E-1,1.561355506831375E-1,1.4362744593211504E-1,1.3236893945761802E-1,1.2200966171580907E-1,1.1223215809485865E-1,1.0279131822381474E-1,9.352975328412873E-2,8.437677819025881E-2,3.5613115694206543E-1,9.98930744747783E-1,9.957440232808342E-1,9.90482079784771E-1,9.83200806419131E-1,9.739688829257528E-1,9.628667828293157E-1,6.126291458274744E-1,1.1423153015928568E-1,5.8095761980567526E-2,4.321158149519946E-2,4.6816482196317566E-2,6.224463127156261E-2,8.59118374725666E-2,1.14690931568097E-1,1.7367769225537036E-1,2.1655470671344032E-1,2.4015598899609825E-1,2.4589812756639837E-1,2.3885028454582183E-1,2.2479004080945614E-1,2.0816391797666928E-1,1.9161934645165382E-1,1.763853801906622E-1,1.6281124984916065E-1,1.5078281690328693E-1,1.3998431351249727E-1,1.3004808683691638E-1,1.2063649103228674E-1,1.1148440823570187E-1,1.024174196671833E-1,9.335298044432189E-2,8.428902018560853E-2,3.561023145166233E-1,9.989378562020277E-1,9.95772906987265E-1,9.905478972381655E-1,9.833190051867977E-1,9.741549775393874E-1,5.863287526790256E-1,1.084811814741481E-1,5.4577990031332076E-2,4.051821491017107E-2,4.4491620040706385E-2,6.0112985623633396E-2,8.393929010769421E-2,1.1293962688487165E-1,1.729016912781979E-1,2.1678548362420821E-1,2.4137944273856599E-1,2.480351791857619E-1,2.41792179547583E-1,2.2843842106019502E-1,2.124505591236807E-1,1.9650646857624993E-1,1.818561617583479E-1,1.688578925792515E-1,1.5739562411674912E-1,1.4714300124566038E-1,1.3771572823651354E-1,1.2875629397982669E-1,1.1997941726740673E-1,1.1119300253706225E-1,1.0230160615493071E-1,9.329648009924152E-2,8.42361638176644E-2,3.560677564067851E-1,9.989452322210387E-1,9.95802837772754E-1,9.906160414574179E-1,9.834412820541782E-1,5.600589919545932E-1,1.0281594091498139E-1,5.115941723970596E-2,3.790557606564619E-2,4.21976661134795E-2,5.79319325815248E-2,8.18088641327306E-2,1.1089919027869133E-1,1.715334912894976E-1,2.1619615927114766E-1,2.4164284505289374E-1,2.4915644329820869E-1,2.437268818930601E-1,2.3112812195821875E-1,2.1584721859143696E-1,2.005801447525304E-1,1.8659167944273022E-1,1.7424684969390436E-1,1.6342756421194868E-1,1.5379758785625564E-1,1.4495681362677454E-1,1.3652841210788458E-1,1.282070103359254E-1,1.197823942886237E-1,1.1114533827826736E-1,1.0227923373446213E-1,9.324124176249186E-2,8.413767756994776E-2,3.559986605388377E-1,9.989528685365284E-1,9.958337983915431E-1,9.906864734514724E-1,5.339344014587326E-1,9.725613748513984E-2,4.7849620279833735E-2,3.538073185113855E-2,3.994313183686925E-2,5.571402698851961E-2,7.953886930597033E-2,1.0859447535741892E-1,1.6960983711827687E-1,2.148296214203739E-1,2.4098936109438737E-1,2.4930044227359138E-1,2.4468494473024335E-1,2.3287990981039453E-1,2.1836409900871864E-1,2.0383981670127121E-1,1.905807005660578E-1,1.789564484697836E-1,1.688468754912058E-1,1.5990671284237684E-1,1.5172105275397296E-1,1.4389450698479564E-1,1.361019079518395E-1,1.2811469252545213E-1,1.1980913880617688E-1,1.1115970107182595E-1,1.0222088384012779E-1,9.310232474558892E-2,8.394239704311111E-2,3.5587920882429636E-1,9.989607607317095E-1,9.95865771012293E-1,5.080617833966817E-1,9.182003092374635E-2,4.465668557956558E-2,3.294958309054693E-2,3.773570098437202E-2,5.347143214162401E-2,7.714779960344435E-2,1.0605125425902925E-1,1.6717032975219243E-1,2.1273328903977523E-1,2.3946797214893564E-1,2.4851236134192073E-1,2.447040512426887E-1,2.3372187878095832E-1,2.200187620523452E-1,2.0629221840557893E-1,1.9381915383132087E-1,1.8297199101889122E-1,1.7362852203432655E-1,1.6543541593128103E-1,1.579641384584538E-1,1.508017026622964E-1,1.436036632738071E-1,1.361230904307706E-1,1.282212310064762E-1,1.1986264887463216E-1,1.1109796903388626E-1,1.0203882015788455E-1,9.283046374493284E-2,8.362711422068737E-2,3.5570506241865574E-1,9.989689042441995E-1,4.8253968765278027E-1,8.652378198885732E-2,4.1587241384208405E-2,3.0616893974183674E-2,3.558221324792104E-2,5.121582149273538E-2,7.465412345984257E-2,1.032958760761346E-1,1.6425680119503475E-1,2.0995829621352619E-1,2.3713257116436423E-1,2.4684314975258836E-1,2.4382819150363064E-1,2.3368874704290443E-1,2.2083556730534967E-1,2.0795096885953207E-1,1.9630988082994172E-1,1.8628566635452073E-1,1.7775426628458854E-1,1.7035536833294446E-1,1.6364813237144155E-1,1.5720311852073787E-1,1.5065733119621366E-1,1.4374566738335695E-1,1.3631399326882154E-1,1.283161665007761E-1,1.197977851007045E-1,1.1087114769163502E-1,1.0168705659397625E-1,9.24087888878468E-2,8.319193229943493E-2,3.554807706509569E-1],[],[],[],[4.574580308014191E-1,8.13814508534836E-2,3.864650600197933E-2,2.8386333842311314E-2,3.348865946262215E-2,4.8958292800652295E-2,7.207608761728121E-2,1.003549393160897E-1,1.609126987304168E-1,2.0655867623317054E-1,2.3404104596248082E-1,2.4434859555764948E-1,2.4210679870667315E-1,2.328210986172364E-1,2.208450439556598E-1,2.0883608574451865E-1,1.98062297602596E-1,1.8889636287680608E-1,1.8121263397725101E-1,1.7464499021448082E-1,1.6874173309827997E-1,1.6305828365747962E-1,1.5721402114253627E-1,1.5092606872137673E-1,1.4402475082096441E-1,1.3645255140749085E-1,1.2824898729298692E-1,1.1952573881214383E-1,1.1043777829841137E-1,1.0115611489510568E-1,9.184621027824069E-2,8.265389010256845E-2,4.3289784662289427E-1,7.640502140244285E-2,3.583835010792846E-2,2.626052961416736E-2,3.146018764402009E-2,4.670929522840551E-2,6.943153689166295E-2,9.725498294089883E-2,1.571824884506777E-1,2.0259055983498725E-1,2.302543666994424E-1,2.4108839165448462E-1,2.395938622299818E-1,2.3116458731970216E-1,2.2008321018108842E-1,2.0897343297280588E-1,1.9909197705736753E-1,1.9080938976045644E-1,1.8399877740112297E-1,1.7828945773667884E-1,1.7322042744749874E-1,1.6833343050594246E-1,1.6323132835179788E-1,1.5761406659034077E-1,1.512964545351374E-1,1.442090910731866E-1,1.3638446588066275E-1,1.279324062612948E-1,1.1901068437893753E-1,1.0979666727642261E-1,1.0046440445326174E-1,9.116928258386134E-2,4.0893116187097805E-1,7.160444893431243E-2,3.3165370906637966E-2,2.4241127106490522E-2,2.950111886666938E-2,4.4478569602550866E-2,6.673775168416617E-2,9.402219982017071E-2,1.5311108677600482E-1,1.9811140022095863E-1,2.2583569283511964E-1,2.37125209628465E-1,2.363470342362262E-1,2.2876911889165139E-1,2.1859085516804902E-1,2.083941155931682E-1,1.9942016405389995E-1,1.9203611716566543E-1,1.8611424483086655E-1,1.8128060521284028E-1,1.7706652780551824E-1,1.73001668171013E-1,1.686736414245532E-1,1.637659968838894E-1,1.5807823911594052E-1,1.5152873103469006E-1,1.4414210978437292E-1,1.3602518678977812E-1,1.273371869694584E-1,1.1826044199258517E-1,1.0897625202698183E-1,9.964834349705452E-2,3.856209893112823E-1,6.69877285670583E-2,3.0628975932736717E-2,2.232885947878242E-2,2.7614971918265965E-2,4.2275101790266605E-2,6.40113045798699E-2,9.068217568831886E-2,1.4874332744424615E-1,1.9317923598148748E-1,2.2084951331381497E-1,2.3252379654208657E-1,2.3242674542446162E-1,2.2568802669952043E-1,2.1641279845640857E-1,2.07133835753341E-1,1.990732356197039E-1,1.925935463008566E-1,1.8756666550827486E-1,1.836167298954364E-1,1.8026910106630473E-1,1.7704303858538697E-1,1.7351232675507444E-1,1.6934507030736634E-1,1.6432585605431077E-1,1.583606218096877E-1,1.5146545658657587E-1,1.4374308087776932E-1,1.3535286895864507E-1,1.2648072791187548E-1,1.173138443730891E-1,1.0802301477934588E-1,3.630214286352342E-1,6.256098151595686E-2,2.822947429737685E-2,2.052362107497679E-2,2.5804495600162004E-2,4.0107088911348204E-2,6.126793689952102E-2,8.725965594617092E-2,1.441234701389168E-1,1.8785200138794725E-1,2.1536083191093125E-1,2.273501081843139E-1,2.2789534418791813E-1,2.219772553914222E-1,2.1359714072480937E-1,2.0523222327864593E-1,1.9808211908165307E-1,1.9250382113463332E-1,1.8836936076234884E-1,1.8530230853152518E-1,1.8282379655354428E-1,1.8044446096842387E-1,1.7772579314377873E-1,1.7432155848109285E-1,1.7000197975732842E-1,1.646605405493962E-1,1.583042222219767E-1,1.5103068030121766E-1,1.429981970573856E-1,1.3439489131823448E-1,1.2541246775007395E-1,1.1622749738507802E-1,3.411778647593642E-1,5.832855635410884E-2,2.5966173262573927E-2,1.8824544998133377E-2,2.4071707511324425E-2,3.798191788957632E-2,5.852245561539043E-2,8.377834190745044E-2,1.3929475558192841E-1,1.8218689179685157E-1,2.0943440782519163E-1,2.216704904857805E-1,2.2281627185167405E-1,2.176945656498842E-1,2.1019451926975893E-1,2.0273215398415054E-1,1.9648168088806656E-1,1.9179369398733406E-1,1.8854089273014532E-1,1.863476361290428E-1,1.8473258208231214E-1,1.8319957215320068E-1,1.8129944229599737E-1,1.7867285867990731E-1,1.750763881392174E-1,1.7039118625784372E-1,1.6461470667080313E-1,1.5783867736800808E-1,1.502191252060152E-1,1.4194506210860708E-1,1.3321135934748637E-1,1.2419906309241886E-1,3.2012725224010663E-1,5.429314237349466E-2,2.3837478137321455E-2,1.7230082850992742E-2,2.2417938146581634E-2,3.5906155664357835E-2,5.578865061779953E-2,8.026071738031922E-2,1.3429901058608001E-1,1.7623979015681823E-1,2.0313405965396256E-1,2.1555091888440042E-1,2.172532849263037E-1,2.1289877173069122E-1,2.062573803333133E-1,1.9967906812466868E-1,1.9431009858943762E-1,1.904939573429216E-1,1.881045626739449E-1,1.8676839833115022E-1,1.860033986728376E-1,1.853084721012931E-1,1.8422551301985726E-1,1.8238344321666097E-1,1.7952602161390713E-1,1.755223502426951E-1,1.7036007490352317E-1,1.6412425258961363E-1,1.5696758261305702E-1,1.4907871357875396E-1,1.4065436831926578E-1,1.3187878477698745E-1,2.9989847405874603E-1,5.045589223121271E-2,2.1840993632845012E-2,1.5738085195273806E-2,2.0843879158757874E-2,3.388555023085052E-2,5.307923193318196E-2,7.672790580883235E-2,1.29176305273952E-1,1.7006475888225636E-1,1.9652203893676665E-1,2.0905630345195897E-1,2.1126973347691488E-1,2.0764902188389903E-1,2.0183927914671473E-1,1.9612030044359888E-1,1.91608227870642E-1,1.8863885403148736E-1,1.8708787109638464E-1,1.8658518940453253E-1,1.86649745438566E-1,1.867773853236999E-1,1.865028287007573E-1,1.8544470157178625E-1,1.8333492680517838E-1,1.8003096606025282E-1,1.755105150779761E-1,1.6985134038853528E-1,1.632018435596766E-1,1.557491304734302E-1,1.4769051409887435E-1,1.392121752063944E-1,2.8051276284081544E-1,4.681655118359473E-2,1.9973624982316827E-2,1.434588142092011E-2,1.9349634674919892E-2,3.192504155578732E-2,5.0405786153552755E-2,7.319955759147058E-2,1.2396466345354312E-1,1.637135996961654E-1,1.8965847754049664E-1,2.0224986562128755E-1,2.0492790282793175E-1,2.0200413006853593E-1,1.9699421713069074E-1,1.9210443215196712E-1,1.8841897572139948E-1,1.862654774707735E-1,1.8552195175426267E-1,1.858229881203377E-1,1.8669020682419496E-1,1.8761824995890874E-1,1.8813645902974746E-1,1.8785468511419295E-1,1.8649409334102587E-1,1.8390104552828615E-1,1.800432785050161E-1,1.7499077509787828E-1,1.6888677883389408E-1,1.6191576271196628E-1,1.542744369636078E-1,1.461497269548139E-1,2.6198417264481194E-1,4.3373590371920026E-2,1.823167731604851E-2,1.3050357867654077E-2,1.7934774616254062E-2,3.0028781326767298E-2,4.777875104512526E-2,6.969376665356669E-2,1.1869982602078959E-1,1.5723548248472127E-1,1.82600911334309E-1,1.9519259043593498E-1,1.9828842395482485E-1,1.9602196564895805E-1,1.9177602417661893E-1,1.876806738988046E-1,1.8478668983575539E-1,1.8341317295651796E-1,1.834409912916101E-1,1.8451060376331863E-1,1.861479346774498E-1,1.8784824692629315E-1,1.8913730798809827E-1,1.8961776562983132E-1,1.890011937926722E-1,1.8712350936230815E-1,1.8394260812428695E-1,1.795203219259441E-1,1.739939912078345E-1,1.6754446482038304E-1,1.603667384434286E-1,1.52647348609983E-1,2.443200897578164E-1,4.012434181900942E-2,1.6610951979979256E-2,1.1848033200064157E-2,1.6598389045500844E-2,2.8200160433889634E-2,4.520740706295805E-2,6.622701488425393E-2,1.1341506625369202E-1,1.5067664277791212E-1,1.7540388090061348E-1,1.8794275642360533E-1,1.9140975610153313E-1,1.8975890604609932E-1,1.862377923736515E-1,1.8289828742854713E-1,1.8075657318806462E-1,1.801229500952252E-1,1.808816455873254E-1,1.8268010417339856E-1,1.8505009762167934E-1,1.874892818867416E-1,1.8952164074328004E-1,1.907442198656764E-1,1.9086023813743808E-1,1.896959226148905E-1,1.8719956412856534E-1,1.8342459968696573E-1,1.7850183968246042E-1,1.7260762354174397E-1,1.6593421168283562E-1,1.586666949725505E-1,2.2752177143876331E-1,3.706513301755069E-2,1.5106838687231646E-2,1.0735130199224861E-2,1.5339142652091235E-2,2.6441843052504143E-2,4.269988430955878E-2,6.28141426604756E-2,1.081410549855653E-1,1.4408014619593423E-1,1.6811860848140323E-1,1.8055554350734856E-1,1.8434774344693128E-1,1.832693556537209E-1,1.804313659890825E-1,1.778060522046582E-1,1.7637413148557896E-1,1.7643691542018825E-1,1.778824630804322E-1,1.8036623713850566E-1,1.8342730988337835E-1,1.8656743272461054E-1,1.893105624060988E-1,1.912497529134246E-1,1.9208115506331505E-1,1.9162214634829638E-1,1.898117569173625E-1,1.86694903903109E-1,1.8239535925200004E-1,1.7708417830351103E-1,1.709499642013597E-1,1.6417539136227266E-1,2.115849022202602E-1,3.419141923043301E-2,1.3714402594043893E-2,9.707643294313832E-3,1.415532857966292E-2,2.4755806192278833E-2,4.026318333743828E-2,5.946834337190112E-2,1.0290577290418541E-1,1.3748571709603158E-1,1.6079274898914828E-1,1.7308271784330206E-1,1.7715524605881539E-1,1.7660533275516663E-1,1.7440689099222734E-1,1.7245178185212703E-1,1.7168465988819853E-1,1.723977330643824E-1,1.7448332433770272E-1,1.7760585565659254E-1,1.8131305115447416E-1,1.8511237494554197E-1,1.8852946155843736E-1,1.9115497351455882E-1,1.9267931299861313E-1,1.9291191784534947E-1,1.9178299873544227E-1,1.89328940339607E-1,1.8566608465158765E-1,1.8095954115172858E-1,1.7539343760825457E-1,1.6914715438880526E-1,1.965001581829894E-1,3.149791187303381E-2,1.2428465587800355E-2,8.76140131308587E-3,1.3044920900429488E-2,2.3143383597882792E-2,3.790320810657932E-2,5.620117963022153E-2,9.773446662283175E-2,1.309296277281175E-1,1.5347021173370734E-1,1.6557239113164066E-1,1.6988184394556588E-1,1.6981612472058155E-1,1.6821242597009667E-1,1.6688189387234753E-1,1.6673277405401332E-1,1.6804812012333492E-1,1.7072490600584328E-1,1.7443735660961393E-1,1.78743088273095E-1,1.8315679679965363E-1,1.8720743111731714E-1,1.904848342919487E-1,1.9267499396008095E-1,1.9358037217116283E-1,1.9312288615907014E-1,1.9133048013396775E-1,1.8831178792585743E-1,1.8422542438642062E-1,1.7925033066982207E-1,1.735618135681651E-1,1.8225377051938044E-1,2.8978701600242875E-2,1.12436812620696E-2,7.89212507737754E-3,1.20056251428895E-2,2.16053129273188E-2,3.562480936426188E-2,5.3022618691124825E-2,9.26496447075042E-2,1.2444464346289257E-1,1.4619104853930565E-1,1.5806885080171143E-1,1.6257361176274115E-1,1.629480104519215E-1,1.6189361494467838E-1,1.611410347447352E-1,1.6156198925119333E-1,1.634303820665612E-1,1.6664817608504975E-1,1.7090014128531208E-1,1.7575490853081813E-1,1.8073581512972114E-1,1.8537667849136538E-1,1.8926804953554854E-1,1.920928331942016E-1,1.9364751805831898E-1,1.938463260429578E-1,1.927089484228297E-1,1.9033614068486432E-1,1.8687958543202274E-1,1.8251243367516695E-1,1.7740523993148152E-1,1.688280806733429E-1,2.662737497093568E-2,1.0154603228310037E-2,7.095479606474643E-3,1.1034926381085306E-2,2.014178519196264E-2,3.343183671262918E-2,4.994108453236315E-2,8.767110951734454E-2,1.1806001909084132E-1,1.3899140315000078E-1,1.506124565295659E-1,1.5527296066610038E-1,1.5604404789053192E-1,1.5549342138921327E-1,1.5527176127778797E-1,1.5621435000469974E-1,1.5858599228386944E-1,1.622939262120386E-1,1.6703410498598434E-1,1.7238717330239878E-1,1.7788640195253638E-1,1.8307193615203884E-1,1.8753650252987206E-1,1.9096123717293031E-1,1.9313768092819872E-1,1.9397301765422703E-1,1.9347895876823656E-1,1.9174831259932493E-1,1.8892549944383658E-1,1.8517738328097358E-1,1.8066918925370729E-1,1.5620208035055458E-1,2.4437123804184755E-2,9.155746573656866E-3,6.367120815408856E-3,1.013013449266878E-2,1.875249551436229E-2,3.132719766388833E-2,4.696352401058657E-2,8.281602051461052E-2,1.1180154079736944E-1,1.3190351624392851E-1,1.4323959780617584E-1,1.480185429291516E-1,1.4914392342044575E-1,1.4905192167085216E-1,1.4931427793019872E-1,1.5073011154753846E-1,1.5355521861502044E-1,1.577023453853911E-1,1.6287916171721997E-1,1.686791994886015E-1,1.7464683065286693E-1,1.803298827282699E-1,1.8532465355118016E-1,1.893117918363579E-1,1.9207892541606603E-1,1.935269035249956E-1,1.9365980575978764E-1,1.9256251804239266E-1,1.9037197078995793E-1,1.8724834793201078E-1,1.8335106871065468E-1,1.443519307119633E-1,2.2400846570420824E-2,8.241642417220234E-3,5.7027367057087015E-3,9.288426287574874E-3,1.7436694342477146E-2,2.9312922048995962E-2,4.409548455572113E-2,7.809898461613501E-2,1.0569160818741292E-1,1.2495577998670324E-1,1.3598270673195517E-1,1.4084521426148766E-1,1.4228385919455241E-1,1.4260615523019513E-1,1.4330622880654878E-1,1.4514747324320312E-1,1.4837679853573174E-1,1.5291263833706015E-1,1.5847480869137864E-1,1.6467047500499654E-1,1.710561494469674E-1,1.771885835844523E-1,1.8266895862750862E-1,1.8717867209357938E-1,1.905024690767911E-1,1.9253560108690956E-1,1.9327492794900794E-1,1.9279752283129764E-1,1.9123269487066316E-1,1.8873365455553043E-1,1.854536366477063E-1,1.3325145606787653E-1,2.0511241373423507E-2,7.406885642528375E-3,5.09808314210478E-3,8.506884297536193E-3,1.6193238349105018E-2,2.7390230237644198E-2,4.134120094685935E-2,7.353216917776065E-2,9.974935064804993E-2,1.1817283583937203E-1,1.288703198574025E-1,1.3378404826799833E-1,1.3549657377983293E-1,1.3619002804947863E-1,1.372825421531556E-1,1.3950236315549802E-1,1.4308766358279773E-1,1.479626905797854E-1,1.5385973414389753E-1,1.6040021327761123E-1,1.671536884980278E-1,1.7368695860186506E-1,1.7960730798979274E-1,1.8459806254409242E-1,1.884420980545014E-1,1.9102982644862596E-1,1.9235135279166496E-1,1.924761227873554E-1,1.9152578176509488E-1,1.896463675274384E-1,1.8698464571709567E-1,1.2287260836076266E-1,1.8760890272900153E-2,6.646175990631032E-3,4.5490143899430645E-3,7.782532097840846E-3,1.5020640339800561E-2,2.555960373993097E-2,3.870368883965938E-2,6.912543331328642E-2,9.399077238369467E-2,1.1157570927986334E-1,1.2192718270659478E-1,1.2686239716820583E-1,1.2881129105655004E-1,1.298342653608488E-1,1.3127532444376164E-1,1.338282720762042E-1,1.377227126140128E-1,1.4288878106465716E-1,1.4907147077476168E-1,1.5590695045432654E-1,1.629786057778256E-1,1.6986428359458827E-1,1.7617849189137869E-1,1.8160759821004255E-1,1.859335944470568E-1,1.890428207826907E-1,1.909191345712003E-1,1.9162460535080963E-1,1.912732529556706E-1,1.9000383092672202E-1,1.879564399255028E-1,1.1318589964473773E-1,1.714233487066784E-2,5.9543527870752795E-3,4.0515086547101824E-3,7.1123661058094E-3,1.3917117588898513E-2,2.3820856888041104E-2,3.618484287394115E-2,6.488647343580166E-2,8.842892061763032E-2,1.0518197518037876E-1,1.1517439059274753E-1,1.2010399273571408E-1,1.222537920053518E-1,1.2356640909994106E-1,1.2531380055335745E-1,1.2815613458698194E-1,1.3231463262764892E-1,1.377253423848965E-1,1.4414609601692158E-1,1.5122818783874353E-1,1.585694755017022E-1,1.6575973049121537E-1,1.7242170017768804E-1,1.7824583281800635E-1,1.830141839289957E-1,1.8660978874467263E-1,1.890107953927526E-1,1.9027220479499002E-1,1.905005219066619E-1,1.898271848588103E-1,1.8838551614991622E-1,1.0416080062525368E-1,1.5648143235110337E-2,5.326423646971814E-3,3.6016889177107794E-3,6.493383864899515E-3,1.2880638118939842E-2,2.2173208434587928E-2,3.378553737355225E-2,6.082097915752971E-2,8.307407170752112E-2,9.900594778668739E-2,1.0862955944418477E-1,1.1352908140372153E-1,1.1584650386312927E-1,1.1741085531013316E-1,1.1942429606859348E-1,1.2251425413218871E-1,1.2689376511949596E-1,1.3250476757497356E-1,1.3911797931768674E-1,1.464000809256966E-1,1.539639217477729E-1,1.6141195013764456E-1,1.6837606068584138E-1,1.745517408785167E-1,1.7972201095676754E-1,1.837673571973652E-1,1.8666077831412842E-1,1.88450560721779E-1,1.8923586860077618E-1,1.891408661697427E-1,1.8829206045304805E-1,9.576610410375239E-2,1.4270968368303733E-2,4.7575875566363435E-3,3.195839401328878E-3,5.922608878954879E-3,1.1908964531790444E-2,2.061535204843255E-2,3.150572785105038E-2,5.693279598044095E-2,7.793393025265409E-2,9.305888954836397E-2,1.0230702058449984E-1,1.0715458759558305E-1,1.0960862110841031E-1,1.1138892653839728E-1,1.1363025746883136E-1,1.1692826861241216E-1,1.2148801533673431E-1,1.2725726178736751E-1,1.3401957571249673E-1,1.4145717538452363E-1,1.491982987309222E-1,1.5685870035360372E-1,1.64080220279419E-1,1.7056425851933468E-1,1.7609564760731472E-1,1.805530612972687E-1,1.8390492055853788E-1,1.8619318852740746E-1,1.875099173040975E-1,1.879721032257498E-1,1.8769946909024773E-1,8.797025287223563E-2,1.300359852825898E-2,4.243252769013095E-3,2.8304180244986053E-3,5.39711210789832E-3,1.0999695088324444E-2,1.9145524834678303E-2,2.9344551740408755E-2,5.322409154047441E-2,7.301383665904734E-2,8.734923343128664E-2,9.621803373198548E-2,1.0099429956042377E-1,1.0355625283350314E-1,1.0551897422171615E-1,1.079523057235927E-1,1.1142115266971352E-1,1.1612280129682452E-1,1.2201073648728056E-1,1.2888126418257675E-1,1.3643218941226723E-1,1.4430741815739584E-1,1.5213652073094475E-1,1.595719711053384E-1,1.6632186676747124E-1,1.7217364083120407E-1,1.7700486375747798E-1,1.807799535731554E-1,1.8353496944338107E-1,1.8535512587374492E-1,1.8635041363323068E-1,1.86633863480964E-1,8.074163221797745E-2,1.1838999805883835E-2,3.77904997470613E-3,2.502065225213968E-3,4.914030274369821E-3,1.0150301816372215E-2,1.776157314960739E-2,2.730042699546485E-2,4.96955225208582E-2,6.831697905820323E-2,8.188281378559283E-2,9.037101288018903E-2,9.505907230341112E-2,9.770259125624475E-2,9.981650612881574E-2,1.024083187787751E-1,1.0601325261699877E-1,1.1082103907246603E-1,1.1679074328890153E-1,1.237312286239991E-1,1.3135584107407383E-1,1.3932432315135437E-1,1.472804546145208E-1,1.5488792352190797E-1,1.618622197731196E-1,1.6799410166613585E-1,1.7316071186482881E-1,1.7732303549391118E-1,1.80511666619275E-1,1.8280529388141947E-1,1.843071128587339E-1,1.8512360765387412E-1,7.404882772774818E-2,1.0770351423681095E-2,3.3608412225120668E-3,2.207609533377842E-3,4.470581160861971E-3,9.358165502651472E-3,1.646101512053391E-2,2.53711474048149E-2,4.634639971346065E-2,6.384460593052355E-2,7.66631013253234E-2,8.47717601743041E-2,8.93570425794539E-2,9.205809640138073E-2,9.429433408009517E-2,9.701353843246927E-2,1.0072234985578302E-1,1.0560316059387187E-1,1.1162044416248469E-1,1.1859537871650103E-1,1.2625671856740645E-1,1.3428010743030466E-1,1.4232381777088313E-1,1.5006322610819786E-1,1.572218193489185E-1,1.635943387825185E-1,1.6905813562981312E-1,1.7357132038305878E-1,1.7715947255667286E-1,1.7989509573523108E-1,1.818748407129424E-1,1.8319883580077248E-1,6.786084952494173E-2,9.791074272348994E-3,2.9847250645200054E-3,1.9440702753958249E-3,4.064076099351172E-3,8.620607492922063E-3,1.5241099412454396E-2,2.3553973680602008E-2,4.3174849071494395E-2,5.959623625115781E-2,7.169143828334054E-2,7.942370338885892E-2,8.389385134958609E-2,8.663069232302266E-2,8.896273740317594E-2,9.178069721773854E-2,9.55637486171682E-2,1.0048716007820796E-1,1.0652061446361837E-1,1.13497307563658E-1,1.2116119079149167E-1,1.292037777170253E-1,1.3729801243544235E-1,1.4513133223854605E-1,1.524357361780954E-1,1.59010537641621E-1,1.647338893106316E-1,1.6956156745034634E-1,1.7351459205770964E-1,1.7665964387451608E-1,1.7908711162072213E-1,1.8089099662409946E-1,6.214732443481551E-2,8.894853234005835E-3,2.6470383927603134E-3,1.7086577829722451E-3,3.6919298709093416E-3,7.934918285191946E-3,1.4098859906070104E-2,2.1845719575405136E-2,4.017796695373886E-2,5.556986444198979E-2,6.696727032168584E-2,7.43281331242853E-2,7.867286956419545E-2,8.142597062867013E-2,8.382963787689365E-2,8.672016109992896E-2,9.055038393758387E-2,9.548866515241503E-2,1.01509675066389E-1,1.0845828267602478E-1,1.1609335517128609E-1,1.2412215681253812E-1,1.322323847399063E-1,1.4012381190098616E-1,1.4753737713777898E-1,1.5427748555528278E-1,1.602236374983193E-1,1.6532979237509274E-1,1.696128637442421E-1,1.7313408601707558E-1,1.759778935419458E-1,1.7823242016878332E-1,5.687865785708025E-2,8.075653858566794E-3,2.3443554186753377E-3,1.4987714638739027E-3,3.351668242046846E-3,7.2983829532930885E-3,1.3031166063829088E-2,2.024283246521835E-2,3.7351968102782455E-2,5.176215786812895E-2,6.2488372290333466E-2,6.94844363587551E-2,7.369542362115036E-2,7.644739748656751E-2,7.890078225769884E-2,8.18400840457438E-2,8.569294593049394E-2,9.062102877798567E-2,9.660374981057965E-2,1.0349726667779843E-1,1.1107501937067935E-1,1.190598243152522E-1,1.2715412295948206E-1,1.3507020675895778E-1,1.4255829739711717E-1,1.4942834205615038E-1,1.55561685993719E-1,1.6091096183415207E-1,1.6548942215724086E-1,1.693532393807596E-1,1.725812193629326E-1,1.7525591182037198E-1,5.2026167336912975E-2,7.3277339647235E-3,2.0734842248924176E-3,1.31199607321782E-3,3.0409333683171546E-3,6.708303482590946E-3,1.2034768861182337E-2,1.874146800511469E-2,3.469232522199229E-2,4.8168645052038356E-2,5.825106542522434E-2,6.489032350450084E-2,6.896101733615166E-2,7.169652073758484E-2,7.417992885533463E-2,7.714657081663288E-2,8.100001662462299E-2,8.589543820217575E-2,9.181674448834025E-2,9.863096402555199E-2,1.0612571332485092E-1,1.1403909165013068E-1,1.2208819358066977E-1,1.2999792590206613E-1,1.3752805528748785E-1,1.4449445322609522E-1,1.5078075686011488E-1,1.5633873142428145E-1,1.611784014784053E-1,1.6535126380274556E-1,1.689308335698167E-1,1.7199437715462587E-1,4.756218997152592E-2,6.645650730928642E-3,1.8314612923518434E-3,1.146096501252782E-3,2.7574872947946547E-3,6.162018136242008E-3,1.1106342248757893E-2,1.7337558616145634E-2,3.219389931383547E-2,4.478389318650963E-2,5.425042405058735E-2,6.0542046614057654E-2,6.446754774553723E-2,6.717317417797981E-2,6.966903501641292E-2,7.264384466701551E-2,7.647821589536499E-2,8.13210373369531E-2,8.716044368587784E-2,9.387389002363901E-2,1.0126272791686468E-1,1.0908000786061958E-1,1.1705731186974144E-1,1.2493217930080112E-1,1.324741074038066E-1,1.3950520799098828E-1,1.4591180630405284E-1,1.5164522635679786E-1,1.5671268104092925E-1,1.611613747571204E-1,1.65059876063096E-1,1.684804803616051E-1,4.346016587666661E-2,6.0242638265985285E-3,1.6155443760884137E-3,9.990113686823524E-4,2.499213778158954E-3,5.65691799963762E-3,1.024252018752529E-2,1.6026875696496058E-2,2.9851060212816603E-2,4.160167390402564E-2,5.048047029385396E-2,5.6434606852888744E-2,6.021151252849088E-2,6.28756765195094E-2,6.536844277371695E-2,6.833441697651789E-2,7.213235330661542E-2,7.690505919232121E-2,8.264462194838451E-2,8.923845849308852E-2,9.650117660775803E-2,1.0420039250532169E-1,1.1208194341106265E-1,1.1989594566595595E-1,1.2742174097831668E-1,1.3448793387167485E-1,1.4098388342384863E-1,1.4686086360347325E-1,1.5212367202293642E-1,1.5681559643713375E-1,1.6100060409285047E-1,1.6474633805877037E-1],[3.55216779472357E-1,9.989859262616928E-1,9.959675740347118E-1,9.909902545660512E-1,9.841113345123599E-1,9.753993603783353E-1,9.649330798426005E-1,9.528003785447788E-1,9.390971515503972E-1,9.239261289228025E-1,9.073956746327408E-1,8.896185774558119E-1,8.707108515832154E-1,8.507905634462458E-1,8.299766997788786E-1,8.083880902675622E-1,7.861423963162245E-1,7.633551755403274E-1,7.401390296474168E-1,7.166028414106114E-1,6.928511045391035E-1,6.689833484341212E-1,6.450936581222145E-1,6.21270288106452E-1,5.975953674901199E-1,5.741446925207114E-1,5.509876016824107E-1,5.281869276354986E-1,5.057990196588761E-1,4.8387382979063376E-1,4.6245505557117217E-1,4.4158033216076903E-1,8.204024429561232E-2,3.549265653819703E-1,9.989947949414174E-1,9.960034050509223E-1,9.910714961486673E-1,9.842565473545044E-1,9.756269763807625E-1,9.652611660273185E-1,9.532464102163196E-1,9.396777984592267E-1,9.246570577863565E-1,9.082913709096846E-1,8.906921887635387E-1,8.71974054613011E-1,8.522534556805386E-1,8.316477167656223E-1,8.102739486720684E-1,7.882480624633081E-1,7.656838586903967E-1,7.426921988281675E-1,7.193802642582896E-1,6.958509062948246E-1,6.722020889943537E-1,6.485264248592166E-1,6.249108020533014E-1,6.01436100423571E-1,5.781769924695939E-1,5.552018244347189E-1,5.325725719079057E-1,5.10344863721731E-1,4.885680675028397E-1,4.6728542996583444E-1,9.041412577851199E-2,8.138241295320048E-2,3.546242221026255E-1,9.99003895294351E-1,9.960401505464292E-1,9.911547652836205E-1,9.84405307414713E-1,9.758600401040223E-1,9.655969541388735E-1,9.537027238732698E-1,9.40271605301069E-1,9.25404294877589E-1,9.09206767391565E-1,8.917891105209315E-1,8.73264372724349E-1,8.537474398696892E-1,8.333539545286013E-1,8.121992902227412E-1,7.903975911426396E-1,7.680608860239484E-1,7.452982830049408E-1,7.222152504472352E-1,6.98912986917866E-1,6.754878818391122E-1,6.5203106674135E-1,6.286280556263585E-1,6.053584716808138E-1,5.822958564833935E-1,5.595075569298327E-1,5.370546843593708E-1,5.149921397999069E-1,4.9336869885060397E-1,9.87529704402439E-2,8.961946804661568E-2,8.071113662311367E-2,3.5432264514385287E-1,9.990132220769636E-1,9.960777894321033E-1,9.912400144781723E-1,9.84557530566469E-1,9.760984211571426E-1,9.659402587437738E-1,9.541690713432319E-1,9.408782547504295E-1,9.261674487544547E-1,9.101413951413475E-1,8.92908794601343E-1,8.745811786533383E-1,8.552718114402778E-1,8.350946347831237E-1,8.141632682568266E-1,7.925900743181611E-1,7.704852967200947E-1,7.479562786356323E-1,7.251067651273871E-1,7.020362928745675E-1,6.788396684387328E-1,6.556065348401967E-1,6.324210248493387E-1,6.093614981867687E-1,5.865003587832116E-1,5.639039473790419E-1,5.416325040447991E-1,5.197401946738617E-1,1.0699084930391005E-1,9.782415717379254E-2,8.88213373403465E-2,8.005304234419058E-2,3.5403232977438615E-1,9.990227699194839E-1,9.961163001217601E-1,9.913271951398261E-1,9.847131307617697E-1,9.763419861989981E-1,9.662908902332824E-1,9.546451988654446E-1,9.414974222982508E-1,9.269461190174801E-1,9.110947743130442E-1,8.940506798389276E-1,8.759238297852984E-1,8.56825847971617E-1,8.36868958712146E-1,8.161650127024398E-1,7.948245774745638E-1,7.72956100215832E-1,7.506651489839944E-1,7.280537366205784E-1,7.052197299986741E-1,6.82256345671968E-1,6.592517315431747E-1,6.362886328615605E-1,6.134441397050282E-1,5.907895121110208E-1,5.683900781962705E-1,5.463051999476987E-1,1.150639778318088E-1,1.0593252162583129E-1,9.69029070375544E-2,8.804950787858419E-2,7.942855372749263E-2,3.5376072380943563E-1,9.990325333294234E-1,9.96155660546167E-1,9.914162576072435E-1,9.848720200843769E-1,9.76590599017861E-1,9.666486549313983E-1,9.551308472271507E-1,9.421287764142049E-1,9.277398964929057E-1,9.120664143479086E-1,8.952141922273187E-1,8.772916683425969E-1,8.584088093567387E-1,8.386761070818327E-1,8.182036301277086E-1,7.971001395768001E-1,7.754722760506951E-1,7.534238238224129E-1,7.310550559528538E-1,7.084621628232993E-1,6.857367649266068E-1,6.629655093909776E-1,6.402297484597393E-1,6.176052970511368E-1,5.951622655813723E-1,5.729649634551685E-1,1.229115022568281E-1,1.1388262300883303E-1,1.0489365083750074E-1,9.602175471205356E-2,8.732555061439946E-2,7.885096508033056E-2,3.5351204383609525E-1,9.990425066951822E-1,9.961958481673617E-1,9.915071511818583E-1,9.850341088042932E-1,9.768441206128614E-1,9.67013355205586E-1,9.556257519037336E-1,9.427719787139621E-1,9.285483634222219E-1,9.130558141786669E-1,8.963987451282237E-1,8.786840215845215E-1,8.600199379777644E-1,8.405152403740564E-1,8.202782038095804E-1,7.994157730520942E-1,7.78032773736765E-1,7.562311991628148E-1,7.341095764174929E-1,7.117624139458001E-1,6.892797312346808E-1,6.667466699505387E-1,6.442431846752911E-1,6.218438103401721E-1,5.996175025647534E-1,1.3047620757063486E-1,1.2161530791110547E-1,1.1273326997519195E-1,1.0390912988022137E-1,9.520301717745479E-2,8.666221725390047E-2,7.832645177612657E-2,3.532874544659319E-1,9.990526842897305E-1,9.96236839993275E-1,9.915998241601646E-1,9.851993054334331E-1,9.771024092773161E-1,9.673847895802197E-1,9.561296432025946E-1,9.434266841314373E-1,9.293710936581497E-1,9.140624624419125E-1,8.976037394901668E-1,8.801002020195628E-1,8.616584588962227E-1,8.423854989366327E-1,8.223877938233723E-1,8.01770463795861E-1,7.806365126558381E-1,7.590861370179656E-1,7.372161131715008E-1,7.151192634289009E-1,6.928840024462246E-1,6.705939627281776E-1,6.483276973925517E-1,6.261584572748425E-1,1.3770513753553218E-1,1.2907489724487414E-1,1.2036410841591574E-1,1.1165276035206821E-1,1.0300163126052958E-1,9.445853424745836E-2,8.606385567729047E-2,7.785478461963838E-2,3.530855114886867E-1,9.990630602743644E-1,9.962786125926462E-1,9.916942238666614E-1,9.853675167824585E-1,9.773653206838883E-1,9.677627528526965E-1,9.566422464107381E-1,9.440925410960043E-1,9.302076528671053E-1,9.150858376987747E-1,8.988285640776007E-1,8.815395076304727E-1,8.633235800588619E-1,8.442860031520728E-1,8.245314371541301E-1,8.041631712029413E-1,7.832823819855558E-1,7.619874651954142E-1,7.403734428683505E-1,7.185314482414394E-1,6.965482884456154E-1,6.745060841276793E-1,6.52481984013452E-1,1.4455011954491837E-1,1.362097908734482E-1,1.277318268288078E-1,1.1919628459680873E-1,1.1066374862958198E-1,1.0218174369473436E-1,9.379052154342049E-2,8.552756508817068E-2,7.74305271067753E-2,3.5290277431110156E-1,9.99073628702534E-1,9.963211421102224E-1,9.917902966874304E-1,9.85538648018746E-1,9.776327079715353E-1,9.68147036212176E-1,9.571632819460291E-1,9.447691917146714E-1,9.310575987381802E-1,9.161254086639727E-1,9.000725957105976E-1,8.830012221124494E-1,8.650144925194938E-1,8.462158536256207E-1,8.267081478308421E-1,8.065928282255379E-1,7.859692406562829E-1,7.649339771263397E-1,7.435803033297631E-1,7.219976617421224E-1,7.002712504145631E-1,6.784816764581273E-1,1.509681896408474E-1,1.429729805173489E-1,1.3478599472634342E-1,1.2648651375502912E-1,1.1813412161311801E-1,1.0977526722689644E-1,1.0144928787575495E-1,9.31931854108768E-2,8.504482324951926E-2,7.7044509605401E-2,3.527344989761173E-1,9.990843835237396E-1,9.96364404282231E-1,9.918879881043283E-1,9.857126027254522E-1,9.779044218342023E-1,9.685374273609E-1,9.57692465512084E-1,9.454562719591968E-1,9.319204811986702E-1,9.171806344433467E-1,9.013351995153187E-1,8.844846151247854E-1,8.667303706773872E-1,8.481741313933198E-1,8.289169170845405E-1,8.09058341459226E-1,7.886959173405114E-1,7.679244317315481E-1,7.468353932593182E-1,7.255165532097051E-1,7.040515001458585E-1,1.5692191543493209E-1,1.4932246633887672E-1,1.414805938999562E-1,1.3347401340553597E-1,1.253605491338105E-1,1.1718482733698357E-1,1.0898452303806179E-1,1.007954033338969E-1,9.265478695345623E-2,8.460334412266209E-2,7.668539219005555E-2,3.5257533144754033E-1,9.990953185874948E-1,9.964083744521144E-1,9.919872427297708E-1,9.858892829616444E-1,9.781803106112164E-1,9.689337106380429E-1,9.582295082567514E-1,9.461534118581252E-1,9.327958426361662E-1,9.182509647799569E-1,9.026157291854461E-1,8.859889425563009E-1,8.684703725327083E-1,8.501598981508355E-1,8.311567135312957E-1,8.115585912583814E-1,7.914612104765395E-1,7.709575533268439E-1,7.50137372000674E-1,7.290867274230074E-1,1.6237961700631712E-1,1.5522157496494676E-1,1.4777442862276638E-1,1.401135991880393E-1,1.3229444930932205E-1,1.2435908698696E-1,1.1634282055175363E-1,1.082794618315812E-1,1.002050502312858E-1,9.215987967693451E-2,8.4188951859111E-2,7.634115138923381E-2,3.524199333196225E-1,9.991064276473531E-1,9.964530275865169E-1,9.920880043420852E-1,9.860685893234589E-1,9.784602203793363E-1,9.693356671460421E-1,9.587741169341369E-1,9.468602356937174E-1,9.336832181272232E-1,9.19335840308825E-1,9.039135272547489E-1,8.875134468048643E-1,8.70233639959488E-1,8.521721965037375E-1,8.334264833810815E-1,8.140924318823503E-1,7.942638883281551E-1,7.740320315699887E-1,7.534848593431651E-1,1.673154880114751E-1,1.606391789604754E-1,1.5363144038520438E-1,1.4636474182842465E-1,1.3889134802769287E-1,1.3125021334742948E-1,1.2347362811868627E-1,1.1559277222713271E-1,1.076417032847745E-1,9.965961896935072E-2,9.169148320502557E-2,8.378729064153712E-2,7.60003584691332E-2,3.5226348917048894E-1,9.991177043649948E-1,9.964983382915134E-1,9.921902159214114E-1,9.862504210062554E-1,9.787439950464102E-1,9.697430748793533E-1,9.593259940701192E-1,9.475763622037381E-1,9.345821356726076E-1,9.204346928203815E-1,9.052279253809417E-1,8.890573570712856E-1,8.720192989965719E-1,8.542100502399133E-1,8.357251506734654E-1,8.166586916736441E-1,7.971026890820146E-1,7.771465214514195E-1,1.7170962118885955E-1,1.6554981985506775E-1,1.5902092711772717E-1,1.5219187935239084E-1,1.4511127914310007E-1,1.3781435925207164E-1,1.3032980201241307E-1,1.226855317556627E-1,1.1491296423259675E-1,1.0704951039059044E-1,9.913938904979094E-2,9.123299937579483E-2,8.338523254354156E-2,7.565315801955007E-2,3.5210206522285364E-1,9.991291423143719E-1,9.965442808290683E-1,9.92293819686126E-1,9.864346758677257E-1,9.7903147644659E-1,9.701557088555738E-1,9.598848381313033E-1,9.483014047880626E-1,9.354921164391183E-1,9.215469455326734E-1,9.06558244640972E-1,8.906198896678473E-1,8.738264601569811E-1,8.562724646247611E-1,8.380516175410376E-1,8.192561732694129E-1,7.999763209843773E-1,1.755479441407478E-1,1.6993373870970568E-1,1.6391766888466958E-1,1.575646364061991E-1,1.5091909412802237E-1,1.440120581482175E-1,1.3686808063816805E-1,1.2951126750651326E-1,1.2196978383261992E-1,1.1427860275563466E-1,1.064805162355115E-1,9.862563291169148E-2,9.076973010017803E-2,8.297189666276795E-2,7.529190183055515E-2,3.5193281025261375E-1,9.991407349859083E-1,9.965908291337134E-1,9.923987571297666E-1,9.866212504919233E-1,9.793225044370552E-1,9.705733412488768E-1,9.604503436973518E-1,9.49034971720057E-1,9.364126750079658E-1,9.2267201337237E-1,9.079037958378654E-1,8.922002483417139E-1,8.756542187560903E-1,8.58358426719777E-1,8.404047645014598E-1,8.218836538474078E-1,1.7882207269969672E-1,1.7377681985294072E-1,1.6830196386149346E-1,1.62457952579656E-1,1.562846811007825E-1,1.4980853046976295E-1,1.430494732215613E-1,1.360273008082638E-1,1.2876637747725403E-1,1.2129863552783543E-1,1.136647936164426E-1,1.0591399585822014E-1,9.810222389262098E-2,9.028991724038195E-2,8.25392474544016E-2,7.491143831308579E-2,3.517540087985154E-1,9.991524757907513E-1,9.966379568294333E-1,9.925049690584343E-1,9.868100402541726E-1,9.796169169961902E-1,9.709957415256911E-1,9.610222016366298E-1,9.497766663626772E-1,9.373433196296859E-1,9.238093032645947E-1,9.092638798192283E-1,8.937976246134425E-1,8.77501655258998E-1,8.604669057251122E-1,8.427834507789742E-1,1.8152909032299877E-1,1.7707045479369612E-1,1.7215958000135975E-1,1.6685212340484668E-1,1.6118309507444123E-1,1.551739013938304E-1,1.4883956168569046E-1,1.4219512823827143E-1,1.352606788308263E-1,1.2806455719329965E-1,1.2064480607058206E-1,1.1304896167251331E-1,1.0533254450213081E-1,9.755667786116484E-2,8.978528748962869E-2,8.208229133125008E-2,7.450909578444048E-2,3.515650112033293E-1,9.991643580650731E-1,9.966856372467485E-1,9.926123956286471E-1,9.870009393868203E-1,9.79914550323164E-1,9.714226765825636E-1,9.616000992850943E-1,9.505260873892283E-1,9.382835524855512E-1,9.24958214431592E-1,9.106377878074999E-1,8.954111981307867E-1,8.793678356474309E-1,8.625968533466439E-1,1.8367126280051904E-1,1.7981133441606686E-1,1.7548162913279872E-1,1.7073275925288772E-1,1.655946030043529E-1,1.600833318212718E-1,1.5420871576308984E-1,1.479807174909023E-1,1.4141471155121707E-1,1.3453496649541824E-1,1.273762976057104E-1,1.1998402887574175E-1,1.124125799979485E-1,1.0472310312705109E-1,9.69806283648653E-2,8.9251141659733E-2,8.159893135647432E-2,7.408442431717624E-2,3.5136607355336424E-1,9.991763750744175E-1,9.967338434399817E-1,9.927209763856223E-1,9.871938410457877E-1,9.802152389388544E-1,9.718539108861364E-1,9.621837206283583E-1,9.512828290087165E-1,9.39232869955437E-1,9.261181387002325E-1,9.12024801742018E-1,8.970401370379658E-1,8.812518118064977E-1,1.8525569811383594E-1,1.8200117837628024E-1,1.7826437129536865E-1,1.7409066864823658E-1,1.6950464871704093E-1,1.6451706610525543E-1,1.5913222321775364E-1,1.5335471827385955E-1,1.4719487753855975E-1,1.4067247326208585E-1,1.338185986358208E-1,1.2667580743508325E-1,1.1929681304695802E-1,1.1174216276821587E-1,1.0407734937199592E-1,9.636979622587417E-2,8.868607055538363E-2,8.108956579091267E-2,7.36387738216182E-2,3.511581431832455E-1,9.991885200180904E-1,9.967825482046988E-1,9.928306503019604E-1,9.873886373778832E-1,9.805188157880613E-1,9.722892066151676E-1,9.627727464868476E-1,9.520464811957206E-1,9.401907628920849E-1,9.272884608183327E-1,9.134241946329446E-1,8.986835983605392E-1,1.8629396156007622E-1,1.8364641115766134E-1,1.805089579105958E-1,1.7692167355354044E-1,1.7290374406206685E-1,1.6846040151329936E-1,1.6359033868722964E-1,1.5829259017744787E-1,1.5257216203303983E-1,1.464439775016023E-1,1.3993497447002065E-1,1.3308443076759083E-1,1.2594278942411863E-1,1.1856938869736972E-1,1.1102955954677828E-1,1.0339153727212617E-1,9.572355863545402E-2,8.809140444975967E-2,8.055652628116387E-2,7.317478661416661E-2,3.50942623115443E-1,9.992007860335893E-1,9.968317240953098E-1,9.929413558167082E-1,9.875852195888334E-1,9.808251123429499E-1,9.727283238045232E-1,9.633668547039724E-1,9.528166299246997E-1,9.411567169016978E-1,9.284685587797599E-1,9.148352309270782E-1,1.8680165627178405E-1,1.847577945083971E-1,1.8222112290595768E-1,1.792263649445703E-1,1.757872936296741E-1,1.7190358562692518E-1,1.675682560687521E-1,1.6277465104325217E-1,1.575222576013459E-1,1.5182086726122657E-1,1.4569289393658044E-1,1.3917389072537556E-1,1.3231151376166364E-1,1.2516332487409285E-1,1.1779389411648288E-1,1.1027165715900138E-1,1.026659138582424E-1,9.50442459274559E-2,8.747050970794217E-2,8.000344756257571E-2,7.269587383381197E-2,3.5072114319449005E-1,9.992131662010709E-1,9.968813434428199E-1,9.930530308747723E-1,9.877834780119904E-1,9.811339587076628E-1,9.731710204910629E-1,9.639657203372233E-1,9.535928574086506E-1,9.421302126307872E-1,9.296578041582724E-1,1.867979790493767E-1,1.8535002600802516E-1,1.8341083117244675E-1,1.810098074993852E-1,1.7815536111814947E-1,1.748416488496068E-1,1.710560105488744E-1,1.6678605072160244E-1,1.6202561057533532E-1,1.5677913739707308E-1,1.5106421881644286E-1,1.4491229473411557E-1,1.3836777021104274E-1,1.314859061915455E-1,1.2432994533236714E-1,1.1696793404325266E-1,1.094696402682804E-1,1.0190386164327037E-1,9.433629678095273E-2,8.6828037321474E-2,7.943464662406842E-2,7.220573040809293E-2,3.504953584044152E-1,9.992256535478515E-1,9.969313783727167E-1,9.931656129666586E-1,9.879833021776715E-1,9.814451837240404E-1,9.736170528613418E-1,9.645690158521026E-1,9.54374742342015E-1,9.431107260591849E-1,1.8630526100441802E-1,1.854413133059379E-1,1.8409189375974103E-1,1.8228120248072613E-1,1.800123859210806E-1,1.772741799062844E-1,1.7404831730437767E-1,1.7031667623549215E-1,1.6606739481408736E-1,1.6129943286599613E-1,1.560253163479446E-1,1.502720459377735E-1,1.4408036743189584E-1,1.3750276436229233E-1,1.306006242576865E-1,1.2344104365661643E-1,1.1609368278274952E-1,1.086279799133424E-1,1.0111091421895184E-1,9.360538865453062E-2,8.616920895622981E-2,7.885456986377576E-2,7.17079263451474E-2,3.5026678730371213E-1,9.992382410529387E-1,9.969818008229836E-1,9.932790391685119E-1,9.881845808830876E-1,9.817586150783848E-1,9.740661754010463E-1,9.651764113187926E-1,9.551618601477355E-1,1.8534850192166075E-1,1.850529331769252E-1,1.8428155902072538E-1,1.8305351791409047E-1,1.8136685874882663E-1,1.7920505268241071E-1,1.7654435458262704E-1,1.733609952547854E-1,1.6963741873760152E-1,1.653670213984711E-1,1.6055709846053784E-1,1.5522994871894927E-1,1.494223089292728E-1,1.4318346044523583E-1,1.3657245177240548E-1,1.2965490409266717E-1,1.2249982020393453E-1,1.151767209085072E-1,1.0775331282512461E-1,1.0029377286299448E-1,9.285763574018234E-2,8.549920190401672E-2,7.82673458999544E-2,7.120559566129933E-2,3.5003669663169756E-1,9.992509216515899E-1,9.970325825622243E-1,9.933932461824267E-1,9.883872022628154E-1,9.82074079409204E-1,9.745181410460778E-1,9.657875746114588E-1,1.8395490651889473E-1,1.842087839753935E-1,1.8400008853632754E-1,1.8334309497885817E-1,1.8223096511826434E-1,1.8064211298003321E-1,1.7854749930896327E-1,1.7591784542917233E-1,1.7272997242087076E-1,1.6897170143393794E-1,1.646449925812964E-1,1.5976724329163086E-1,1.5437089120351968E-1,1.4850164518663805E-1,1.4221577864446622E-1,1.3557695212482643E-1,1.2865299337430597E-1,1.2151297142498343E-1,1.1422478296635641E-1,1.0685334951397962E-1,9.945942214377206E-2,9.209891774470987E-2,8.482266960635661E-2,7.76764623540825E-2,7.07012299800667E-2,3.4980603246881403E-1,9.992636882398962E-1,9.970836952078886E-1,9.935081703770057E-1,9.885910538597682E-1,9.82391402415869E-1,9.749727013351983E-1,1.821534299493428E-1,1.8293493937326533E-1,1.832703261117256E-1,1.8316923916275696E-1,1.826202053632672E-1,1.815968337808642E-1,1.8006502357998244E-1,1.7799017753883273E-1,1.753436221426499E-1,1.7210765199199637E-1,1.682788498233536E-1,1.6386957418475712E-1,1.589077334344409E-1,1.5343514971715022E-1,1.4750493597206643E-1,1.4117835109078122E-1,1.3452156723496275E-1,1.276026969747043E-1,1.2048931178515399E-1,1.132465632114265E-1,1.0593591382995698E-1,9.861440884347276E-2,9.133437435283151E-2,8.414341234801452E-2,7.708456884275604E-2,7.019657260620474E-2,3.495753940732294E-1,9.992765336793862E-1,9.971351102445852E-1,9.936237478281351E-1,9.887960226966188E-1,9.827104089681153E-1,1.7997433898415552E-1,1.8125921046881086E-1,1.8211726746697438E-1,1.82553804209679E-1,1.8255299946094025E-1,1.820839474240484E-1,1.8110776040301424E-1,1.795847606116206E-1,1.7748096016204132E-1,1.7477323171701026E-1,1.7145279710693578E-1,1.6752689834190926E-1,1.630187434778447E-1,1.579660103335824E-1,1.524183185964098E-1,1.4643413175747694E-1,1.4007752698504358E-1,1.334151901699088E-1,1.2651387991377705E-1,1.1943848401540165E-1,1.12250685834724E-1,1.0500817847975306E-1,9.776431649825222E-2,9.056807561329434E-2,8.346419502141637E-2,7.649339631973913E-2,6.969260088117656E-2,3.4934504364906444E-1,9.992894508016489E-1,9.971867990424697E-1,9.937399143599523E-1,9.89001995347628E-1,1.7744879436317573E-1,1.792107224857311E-1,1.805676374796001E-1,1.8152077624697432E-1,1.8205028446372862E-1,1.821210627548727E-1,1.81689746855917E-1,1.8071185714304752E-1,1.791483176619996E-1,1.7697073467897056E-1,1.741650402851461E-1,1.7073333925293718E-1,1.6669402580098508E-1,1.6208043208597533E-1,1.5693840520182398E-1,1.5132326880346159E-1,1.4529660984486234E-1,1.3892325574018605E-1,1.3226869685704395E-1,1.2539708952021342E-1,1.1836986697776823E-1,1.11244903541228E-1,1.0407612558712323E-1,9.691344089891049E-2,8.980285937556973E-2,8.278669609830971E-2,7.590377479871241E-2,6.918957965861272E-2,3.491149436889318E-1,9.993024324129702E-1,9.972387328756949E-1,9.938566055859762E-1,1.746084588387728E-1,1.7681951137329666E-1,1.7864948100380063E-1,1.8009586474092715E-1,1.8113511170377378E-1,1.817282748072659E-1,1.8182785249242092E-1,1.813848763625241E-1,1.8035544877032386E-1,1.7870611065410932E-1,1.76417625657614E-1,1.7348699401192885E-1,1.699277376232641E-1,1.6576869668147426E-1,1.6105171974885032E-1,1.558286966054066E-1,1.501583750780542E-1,1.441033337542328E-1,1.3772737550344097E-1,1.310934879306081E-1,1.242624080385926E-1,1.1729174367679558E-1,1.1023554978946676E-1,1.0314423229941815E-1,9.606465156692226E-2,8.904031365996148E-2,8.211156389651451E-2,7.531572695045284E-2,6.86871663951857E-2,3.488848129826916E-1,9.993154712989823E-1,9.972908829409115E-1,1.7148513448520247E-1,1.741161446960572E-1,1.7639177241875523E-1,1.783061061267523E-1,1.7983225022232072E-1,1.809277739757721E-1,1.8154140033348298E-1,1.8162001314069234E-1,1.8111519336752097E-1,1.7998865756322413E-1,1.7821616737012821E-1,1.7578970047288042E-1,1.7271789996522183E-1,1.690250208071843E-1,1.6474873962138636E-1,1.5993726888364596E-1,1.546462159134745E-1,1.4893556370401004E-1,1.4286704739015152E-1,1.3650208270103945E-1,1.2990029319428253E-1,1.2311859625556369E-1,1.1621075047909372E-1,1.0922723901039676E-1,1.0221536010059598E-1,9.521941067773328E-2,8.828087402129609E-2,8.1438552270362E-2,7.472861351485574E-2,6.818454815684051E-2,3.4865419268645076E-1,9.993285602293198E-1,1.6811043192650024E-1,1.7113137028965675E-1,1.7382404817305458E-1,1.7617948511956733E-1,1.7816780210144254E-1,1.7974346093965815E-1,1.808517871917069E-1,1.8143587965442745E-1,1.8144312604123153E-1,1.8083069353546202E-1,1.795695481357542E-1,1.7764677176434862E-1,1.7506617055292298E-1,1.7184737137061531E-1,1.680237564126276E-1,1.6363966744417058E-1,1.5874731781786283E-1,1.534037930330429E-1,1.4766842136931194E-1,1.416006804043229E-1,1.3525869537672527E-1,1.2869829677260947E-1,1.2197254458417676E-1,1.1513159592785616E-1,1.0822278696412542E-1,1.0129081282120043E-1,9.437791345556025E-2,8.752400271453167E-2,8.076670720233328E-2,7.414130726508454E-2,6.768059230588128E-2,3.484225147907412E-1],[],[],[3.969469997306232E-2,5.458735111189851E-3,1.4232040710716622E-3,8.688456942222264E-4,2.2641186470091753E-3,5.190460873009591E-3,9.439929363430162E-3,1.4805085566621379E-2,2.765779698788415E-2,3.8615116601142384E-2,4.6934355728817836E-2,5.256194979405294E-2,5.618820727821596E-2,5.880102295947698E-2,6.1277060315742767E-2,6.42192562040444E-2,6.796558299392175E-2,7.265296525263738E-2,7.827716593944659E-2,8.47350845870847E-2,9.185407639071894E-2,9.941589197998107E-2,1.0718033297338803E-1,1.149099712077426E-1,1.2239404026496375E-1,1.2946782928014594E-1,1.3602402736951613E-1,1.4201421358752167E-1,1.4744114405080463E-1,1.5234455433138702E-1,1.567841524986503E-1,1.6082324946781568E-1,3.624160434411349E-2,4.944525400508913E-3,1.2521143765000273E-3,7.538628721102438E-4,2.0503289063816383E-3,4.76018269817707E-3,8.695217740893057E-3,1.3667799257262832E-2,2.560781810088269E-2,3.5816848920312075E-2,4.3604529230634737E-2,4.891714749312381E-2,5.2391911264054174E-2,5.4945067698081905E-2,5.739253731684813E-2,6.0297953910720375E-2,6.397955904629833E-2,6.856858897205309E-2,7.406420450794744E-2,8.037229943435358E-2,8.733244456633105E-2,9.474005564138464E-2,1.0236855704001319E-1,1.0999279568233775E-1,1.1741188347527351E-1,1.2446792916010521E-1,1.3105720007544194E-1,1.3713189904103582E-1,1.4269308988209964E-1,1.4777730608817313E-1,1.524403317350732E-1,1.567414631702258E-1,3.307792337017654E-2,4.477388767084306E-3,1.1001425336971253E-3,6.524761703554119E-4,1.8560907798618026E-3,4.363706715758294E-3,8.00507915663554E-3,1.261061633144341E-2,2.3694641389568737E-2,3.319912425726206E-2,4.048289065287337E-2,4.549256666433579E-2,4.881606070434813E-2,5.130269611830419E-2,5.3711432536485276E-2,5.65688859505779E-2,6.017458917420714E-2,6.465428086820385E-2,7.0010243844943E-2,7.615687352038845E-2,8.294540801525631E-2,9.018442823119602E-2,9.76605963933882E-2,1.0516080209367232E-1,1.1249396670550044E-1,1.1950910058410111E-1,1.2610625145171603E-1,1.3223852828637606E-1,1.3790562588788027E-1,1.431412089307311E-1,1.4799746255762375E-1,1.525299799844622E-1,3.018194376834073E-2,4.053364806008119E-3,9.6533838001048E-4,5.632399341876477E-4,1.6797668687490467E-3,3.998750554509939E-3,7.366274187347715E-3,1.1629162997741783E-2,2.1911674096633003E-2,3.0753936389884048E-2,3.756093022153535E-2,4.228002260022085E-2,4.5453408910199354E-2,4.786798569037763E-2,5.022937244111475E-2,5.302936726570222E-2,5.654978477726109E-2,6.091105300275843E-2,6.611830520019675E-2,7.209394597442458E-2,7.870032186549722E-2,8.575865527245136E-2,9.306842526437664E-2,1.0042828647394447E-1,1.0765685127876896E-1,1.1461006482526334E-1,1.2119191374337826E-1,1.273566599375139E-1,1.331029257077012E-1,1.3846182145697586E-1,1.434822457361035E-1,1.4821639092769648E-1,2.753319156604665E-2,3.6687692605206264E-3,8.459234294538869E-4,4.8484065389119016E-4,1.519832592944612E-3,3.663131455475636E-3,6.775647547645046E-3,1.0719124823441846E-2,2.025228329145266E-2,2.8473121515705902E-2,3.4829853784243255E-2,3.927091875644598E-2,4.22961729616912E-2,4.463435497601378E-2,4.6941199920503565E-2,4.967579904120707E-2,5.3103205840665614E-2,5.733872094564856E-2,6.239006292399703E-2,6.818715720744474E-2,7.460289470257114E-2,8.14705983278797E-2,8.860211372880741E-2,9.580754428561673E-2,1.0291503098331975E-1,1.0978744240963345E-1,1.1633282167932954E-1,1.2250679585018882E-1,1.2830718420172382E-1,1.337628373264699E-1,1.3891966475181441E-1,1.438267487384084E-1,2.5112417918048965E-2,3.320183363777195E-3,7.402798607301854E-4,4.1608803231960723E-4,1.3748720630165077E-3,3.354769830992388E-3,6.2301422895761046E-3,9.876274393903865E-3,1.8709857130721427E-2,2.634844814125061E-2,3.228069425611449E-2,3.645637216180555E-2,3.933616684029321E-2,4.159470038548202E-2,4.384111245858517E-2,4.650380727091489E-2,4.983199938902256E-2,5.393604162020472E-2,5.882598089676096E-2,6.443878263421275E-2,7.065731774249939E-2,7.732645725642297E-2,8.426994024779613E-2,9.13089701587093E-2,9.828101580710025E-2,1.0505581771383549E-1,1.1154555502380348E-1,1.1770739906766113E-1,1.2353860866517051E-1,1.2906604809919398E-1,1.3433291911769069E-1,1.393854710416946E-1,2.290157554435244E-2,3.0044422155739575E-3,6.469395650583069E-4,3.5590616514290875E-4,1.2435735176319514E-3,3.0716913529509203E-3,5.726811082635891E-3,9.096494290089458E-3,1.7277857479787783E-2,2.437169539028096E-2,2.990440976930734E-2,3.3827325011952056E-2,3.656492116473264E-2,3.8741520583060005E-2,4.092278937636397E-2,4.35083720542248E-2,4.6732530505858835E-2,5.070084571367778E-2,5.5425445700106823E-2,6.084986550254659E-2,6.686639567042481E-2,7.333089687230507E-2,8.007851149268157E-2,8.694116788870292E-2,9.376542893817198E-2,1.0042781979087662E-1,1.0684470020216119E-1,1.1297493350172953E-1,1.1881543419208883E-1,1.243913323377286E-1,1.297433857310868E-1,1.3491527293337743E-1,2.08837874265035E-2,2.7186224759953546E-3,5.645733801602205E-4,3.033249264316827E-4,1.1247244455350406E-3,2.8120277566401762E-3,5.262824854812422E-3,8.375795771082556E-3,1.5949864470790037E-2,2.2534720391824963E-2,2.7691969163556925E-2,3.13746429666697E-2,3.3973789864095744E-2,3.606702864377457E-2,3.817950798992322E-2,4.0683947186666125E-2,4.380050518417496E-2,4.763016360755829E-2,5.218689516313073E-2,5.7420347139020805E-2,6.323167713400973E-2,6.948717569072987E-2,7.603288686040709E-2,8.27110678616409E-2,8.93771140087314E-2,9.591421627307917E-2,1.0224292778830334E-1,1.0832392214606394E-1,1.1415396006836541E-1,1.1975666800828547E-1,1.2517060552048306E-1,1.3043712653674308E-1,1.9043309255041437E-2,2.460029622567709E-3,4.919806129648816E-4,2.5747163364179333E-4,1.0172064967297312E-3,2.5740165365769866E-3,4.835479071630446E-3,7.7103335541192424E-3,1.4719613608932359E-2,2.082951547593527E-2,2.563442555325719E-2,2.908920079706129E-2,3.155404427340092E-2,3.356325223804067E-2,3.560424872077822E-2,3.802456982028512E-2,4.103108450555798E-2,4.472034403162779E-2,4.910794118218809E-2,5.414919319650879E-2,5.975358316378863E-2,6.57972747278816E-2,7.213670536185868E-2,7.862404933438247E-2,8.512324979754114E-2,9.152401740472833E-2,9.775108280244978E-2,1.0376702073021879E-1,1.0956860412818066E-1,1.1517816520753846E-1,1.2063229257185644E-1,1.2597024494037348E-1,1.736548697544571E-2,2.22618498396831E-3,4.280789321493977E-4,2.1756304944584454E-4,9.199902737054165E-4,2.355999699424555E-3,4.442197922370557E-3,7.096417082511476E-3,1.3581026056949273E-2,1.9248255948444936E-2,2.3722978776071973E-2,2.6961956124011262E-2,2.9296955255962587E-2,3.122212226260809E-2,3.318978935955923E-2,3.5523960155329194E-2,3.841898985194771E-2,4.1967164872669244E-2,4.6185485958363644E-2,5.103451475097479E-2,5.6431532066734666E-2,6.226202460362687E-2,6.83923128462971E-2,7.468406527064526E-2,8.100946986184711E-2,8.726458748804235E-2,9.337828496511907E-2,9.931510387766584E-2,1.050719721136011E-1,1.106701162919177E-1,1.1614436290924711E-1,1.2153208784957494E-1,1.5836710636419418E-2,2.014812731972734E-3,3.718946925419806E-4,1.8289776316040275E-4,8.321300805496371E-4,2.1564217268920465E-3,4.0805366714956656E-3,6.530518663266722E-3,1.2528232732360993E-2,1.77833392386425E-2,2.1949027572077288E-2,2.498401205599025E-2,2.7193864046402835E-2,2.9035550448440053E-2,3.0928788818873287E-2,3.317561128237567E-2,3.595859903473737E-2,3.93659357720193E-2,4.341583102167232E-2,4.807368333936071E-2,5.326405959997855E-2,5.8881229467570996E-2,6.480088780289177E-2,7.08937677099066E-2,7.70399848369066E-2,8.314176127540357E-2,8.913203627630445E-2,9.497736102003523E-2,1.0067493922400331E-1,1.0624506058445517E-1,1.1172098014821871E-1,1.1713838626915936E-1,1.4444365605143209E-2,1.8238269843277224E-3,3.225537366233944E-4,1.5284898167795545E-4,7.527586957320672E-4,1.973826888757813E-3,3.7481824196034658E-3,6.009278842431339E-3,1.1555592844836822E-2,1.6427416218828032E-2,2.0304212364409338E-2,2.314666957605942E-2,2.523624257126097E-2,2.6995496561332842E-2,2.881386081909709E-2,3.0972869425279784E-2,3.3644033380975324E-2,3.691159232517561E-2,4.0794778613510226E-2,4.5263439254853585E-2,5.024893347541761E-2,5.565378652841864E-2,6.1362564249991966E-2,6.72546319198868E-2,7.32177054117374E-2,7.915996310029548E-2,8.501833352935859E-2,9.076139953338026E-2,9.638674122123289E-2,1.0191386097222403E-1,1.0737461533146404E-1,1.1280318357339526E-1,1.317678208104246E-2,1.651319144736968E-3,2.792727037807534E-4,1.2685774873881717E-4,6.810822232756044E-4,1.8068560332080096E-3,3.4429535026296652E-3,5.529509368385958E-3,1.065770748402702E-2,1.5173415485035497E-2,1.878044951562761E-2,2.144147054815568E-2,2.3415744043933637E-2,2.5094025872006532E-2,2.683763803405121E-2,2.8909004941763402E-2,3.146923594689579E-2,3.459878185166239E-2,3.831772517828758E-2,4.259999261874568E-2,4.7383261470440384E-2,5.257780020947534E-2,5.80765504797183E-2,6.376707784883567E-2,6.954436425731582E-2,7.532232680200829E-2,8.104178361923736E-2,8.66733527923937E-2,9.221507265922131E-2,9.768578987603659E-2,1.0311611838409496E-1,1.0853889040132017E-1,1.2023183713997824E-2,1.4955455821863048E-3,2.413508654706258E-4,1.0442660197232212E-4,6.16375066984745E-4,1.6542429688068412E-3,3.16279774119822E-3,5.088194072522917E-3,9.829428843598751E-3,1.4014561366527772E-2,1.7369957921625087E-2,1.986023221465994E-2,2.172424465027883E-2,2.3323357611868947E-2,2.499282728438593E-2,2.6977274521991314E-2,2.94280411362378E-2,3.242194083501689E-2,3.5979746871534525E-2,4.007911692871806E-2,4.466359262350238E-2,4.965069017710702E-2,5.494124266630663E-2,6.043058764688362E-2,6.60206354430052E-2,7.163081475886865E-2,7.720571975773077E-2,8.271799107775962E-2,8.816619002533821E-2,9.35686222653133E-2,9.895479878380617E-2,1.0435635093409942E-1,1.097363601577118E-2,1.3549157303976288E-3,2.0816249389107373E-4,8.511366925771463E-5,5.579750633779422E-4,1.5148105398382335E-3,2.9057897344623527E-3,4.6824879738779634E-3,9.06586563672474E-3,1.2944386400494674E-2,1.6065278779859284E-2,1.839507404394245E-2,2.0153877143666184E-2,2.167590515150789E-2,2.327225640759084E-2,2.5170975088225037E-2,2.751423608641662E-2,3.037536424220059E-2,3.377567712560824E-2,3.76962349415809E-2,4.208601117501536E-2,4.6869292692413E-2,5.1954332568936355E-2,5.7243818262965776E-2,6.264625012433625E-2,6.80863345965474E-2,7.351231695841033E-2,7.889883351377315E-2,8.424501780810087E-2,8.956873359739746E-2,9.489851322048992E-2,1.0026491825786164E-1,1.0018995145333434E-2,1.227980669224019E-3,1.7914976298291017E-4,6.852719948046569E-5,5.052788009531584E-4,1.3874664846620498E-3,2.67012737498352E-3,4.309714890153747E-3,8.362385223552121E-3,1.1956738969964076E-2,1.4859289333619291E-2,1.703843776093198E-2,1.869705715643481E-2,2.0144308643926842E-2,2.1668913457322813E-2,2.348348994280128E-2,2.5721614251468388E-2,2.845326702040182E-2,3.170017642640302E-2,3.544649688468092E-2,3.9646223073728934E-2,4.422995491838764E-2,4.911290876190181E-2,5.420470834288418E-2,5.9420107517180076E-2,6.46888523779048E-2,6.996270539649141E-2,7.521825945260974E-2,8.045525573590176E-2,8.56912007755263E-2,9.09537582139354E-2,9.627253668314995E-2,9.150857550094696E-3,1.1134222331747527E-3,1.5381617341434918E-4,5.432051754306489E-5,4.577371463626238E-4,1.2711991552494147E-3,2.454127743516692E-3,3.967363812858637E-3,7.714612933625204E-3,1.104578675929686E-2,1.3745211351413232E-2,1.5783101358392074E-2,1.7346503011299405E-2,1.8721460866226294E-2,2.0175978893678108E-2,2.1908327739500348E-2,2.4044021658769118E-2,2.6649838138752064E-2,2.974779454645809E-2,3.332485110520608E-2,3.733963500682182E-2,4.172862197518753E-2,4.6413551006053676E-2,5.131057885339596E-2,5.634038038755176E-2,6.143750130583035E-2,6.655708047986729E-2,7.16776179536132E-2,7.679948565901182E-2,8.19399044374074E-2,8.712576586076559E-2,9.238582907419148E-2,8.361510855826582E-3,1.0100426778600071E-3,1.3172048747922197E-4,4.218738939335413E-5,4.1485099194196084E-4,1.1650731652982247E-3,2.256222525328219E-3,3.653084279550789E-3,7.118429027076327E-3,1.02060166345181E-2,1.2716615052494617E-2,1.4622187843887987E-2,1.609524978369086E-2,1.7400526974271868E-2,1.878685142247962E-2,2.043915486704879E-2,2.247539634885516E-2,2.495928759471469E-2,2.7913025553099925E-2,3.132610736165335E-2,3.516142602907752E-2,3.9360916675103684E-2,4.385241753520547E-2,4.855822703590254E-2,5.3404614481257766E-2,5.833068517837393E-2,6.329480868430984E-2,6.827733422715586E-2,7.327927676797422E-2,7.831763110201459E-2,8.34186010872576E-2,8.861018743165759E-2,7.643886318203873E-3,9.167549228146536E-4,1.1247115539002888E-4,3.1857779721919826E-5,3.7616723376117503E-4,1.0682250243518438E-3,2.074953073102607E-3,3.364680951898377E-3,6.569963698657819E-3,9.432231506667452E-3,1.1767419137925214E-2,1.3549169429481594E-2,1.4936658326528006E-2,1.6174958857120614E-2,1.7495168127788115E-2,1.906982183518398E-2,2.1009801526277416E-2,2.337588684171232E-2,2.6190355966425233E-2,2.9444993038196893E-2,3.310661196389767E-2,3.712221198717908E-2,4.142532516992978E-2,4.594401345116742E-2,5.060982149252514E-2,5.536617602476229E-2,6.017452840616883E-2,6.50170121202262E-2,6.98952880522549E-2,7.482617391174123E-2,7.983525898858872E-2,8.494986516629838E-2,6.991513078090022E-3,8.325733787373477E-4,9.572121111362696E-5,2.309398272320566E-5,3.412749848869257E-4,9.798588061833147E-4,1.9089652257840393E-3,3.100107584804047E-3,6.065590489217566E-3,8.719544686590398E-3,1.0891887532995507E-2,1.2557867819837405E-2,1.3864419924455067E-2,1.5038504743618727E-2,1.6294819519732894E-2,1.7794384245405102E-2,1.9641452956264693E-2,2.189400311780923E-2,2.4574306482788116E-2,2.7676202622222614E-2,3.1170102827861455E-2,3.5007696380189926E-2,3.912782228960288E-2,4.346394201374948E-2,4.7952565325401646E-2,5.254120552083118E-2,5.7194245268461195E-2,6.18955319129178E-2,6.664736710098793E-2,7.146643090723062E-2,7.637776103342232E-2,8.140806969339963E-2,6.3984744005346995E-3,7.566053584912006E-4,8.116361352596194E-5,1.5687104789297984E-5,3.098020247881482E-4,8.992418913887785E-4,1.757003977975969E-3,2.8574605494898664E-3,5.601918430701353E-3,8.063372190200783E-3,1.0084623392644867E-2,1.164245120121257E-2,1.287255719685243E-2,1.3985214674421367E-2,1.5179960091221176E-2,1.6607118912108608E-2,1.8364741138929358E-2,2.0508128166819743E-2,2.3059467706801447E-2,2.601444082954213E-2,2.9346753592635465E-2,3.301243227323805E-2,3.6955254792680775E-2,4.111373303222016E-2,4.5429041536373456E-2,4.9852549932800326E-2,5.435142148028435E-2,5.891114287016064E-2,6.353464453100448E-2,6.823849996048661E-2,7.304724910258252E-2,7.798705416573556E-2,5.85936602343809E-3,6.880430640844021E-4,6.852700710992755E-5,9.453877098852553E-6,2.814114827188884E-4,8.257008166421508E-4,1.617908080876906E-3,2.634972052394366E-3,5.175783213743703E-3,7.4594234050625735E-3,9.340560867847682E-3,1.0797428480066226E-2,1.1955421819393557E-2,1.3009442410300392E-2,1.414501494377765E-2,1.5502535676977203E-2,1.71742487815689E-2,1.921290184483952E-2,2.1640530350459576E-2,2.4454459792515062E-2,2.7631408644888788E-2,3.1131407886986595E-2,3.490282525634519E-2,3.8888889369720195E-2,4.303514996196006E-2,4.7296608469409515E-2,5.164305899483033E-2,5.6061550150604156E-2,6.0555623494770186E-2,6.51417696665E-2,6.98440765094058E-2,7.468820734264561E-2,5.369256695398857E-3,6.261561361135328E-4,5.757187555948719E-5,4.233775671585366E-6,2.557987503985832E-4,7.586172563864064E-4,1.4906046432095741E-3,2.431003172147268E-3,4.784237631780296E-3,6.903690482835187E-3,8.654955078657328E-3,1.0017641266826579E-2,1.110768958381128E-2,1.2105844303331625E-2,1.318468300614081E-2,1.4475385431781078E-2,1.6064764071916385E-2,1.8003131098567954E-2,2.0312310363551737E-2,2.2991090745199397E-2,2.6018940338167765E-2,2.9359582837196807E-2,3.296564557125469E-2,3.678475592027435E-2,4.076656063201988E-2,4.4869475034898174E-2,4.906577633814003E-2,5.334399581436241E-2,5.7708263871704864E-2,6.217500565334383E-2,6.676789531551962E-2,7.151214076272416E-2,4.923650942796997E-3,5.702847476437541E-4,4.808706136090093E-5,-1.1357351046257191E-7,2.3268861731718169E-4,6.974241568365243E-4,1.3741037892208716E-3,2.2440368188394585E-3,4.424541522675253E-3,6.392436778196407E-3,8.023370689419945E-3,9.29825404857514E-3,1.032435326586568E-2,1.1269375612542019E-2,1.2293937330539474E-2,1.3520664833528867E-2,1.5031290232419992E-2,1.687380478845273E-2,1.9069769456681644E-2,2.1619270648382642E-2,2.450428205211273E-2,2.7691927847348856E-2,3.1138783376766625E-2,3.479657266092683E-2,3.861877314930478E-2,4.256700347004642E-2,4.661587908976041E-2,5.075533379356477E-2,5.4990060880434725E-2,5.933643191486063E-2,6.381773940804066E-2,6.845877254572653E-2,4.51845407304539E-3,5.198332210659763E-4,3.9886624596587156E-5,-3.7107263452324585E-6,2.1183262045442982E-4,6.416020370102073E-4,1.2674934205829413E-3,2.072670703336306E-3,4.094151398292383E-3,5.922184613654882E-3,7.441669434105832E-3,8.634742944718967E-3,9.600713723087118E-3,1.0495284700782311E-2,1.1468022911872672E-2,1.2633618162347237E-2,1.4069051809094102E-2,1.5820104811048237E-2,1.790803146843688E-2,2.0334064197506347E-2,2.3082456185577187E-2,2.612345898038213E-2,2.9417302658244996E-2,3.291952158970352E-2,3.658716977985418E-2,4.0384866446694284E-2,4.4289424088513E-2,4.829209879491914E-2,5.239811796696936E-2,5.662380689842423E-2,6.0992102941894694E-2,6.552740729447859E-2,4.149939393554205E-3,4.7426414396138205E-4,3.280701476050331E-5,-6.664510811785026E-6,1.930065990603137E-4,5.906754670293861E-4,1.1699341198795348E-3,1.915610389489354E-3,3.790709924357057E-3,5.489702611427548E-3,6.905996895128722E-3,8.022883392625961E-3,8.932369597341118E-3,9.779105505744155E-3,1.0702452435195166E-2,1.1809736737593026E-2,1.3173498119316692E-2,1.4837413952303547E-2,1.6822395012952615E-2,1.9130681649557797E-2,2.1748597512706858E-2,2.4649266802589366E-2,2.7796298892552605E-2,3.1148767896213306E-2,3.4667062548532884E-2,3.8318608244112935E-2,4.208227751277364E-2,4.5950569192579935E-2,4.992921392518942E-2,5.40344941930031E-2,5.828901387384447E-2,6.271681169916199E-2,3.814717603677243E-3,4.330929582896486E-4,2.6704530207609466E-5,-9.06789608846299E-6,1.760084443405055E-4,5.442097301039467E-4,1.0806542252736545E-3,1.771662488753151E-3,3.5120353873877574E-3,5.091992798409355E-3,6.412768797670327E-3,7.4587370660610455E-3,8.315205953101762E-3,9.11664863575821E-3,9.993000317699298E-3,1.1044756272364419E-2,1.2340304252137542E-2,1.3921320877897157E-2,1.5808342824517926E-2,1.8004492892333815E-2,2.0497972326295997E-2,2.3264540896952127E-2,2.6270929142111467E-2,2.9479495736928964E-2,3.285373467094184E-2,3.6363691684719604E-2,3.9990167046225725E-2,4.372682404359634E-2,4.7579864292085494E-2,5.156552776030603E-2,5.570610242302071E-2,6.0025285564099494E-2,3.509708299163452E-3,3.9588299617071164E-4,2.1453040909454453E-5,-1.1001660161289927E-5,1.6065603337497923E-4,5.018076713598102E-4,9.98945098861282E-4,1.6397280448533697E-3,3.2561112624055486E-3,4.726277658246959E-3,5.958657043527301E-3,6.938638288305191E-3,7.74538214087336E-3,8.503991400750113E-3,9.335695373367347E-3,1.0334652511477048E-2,1.156536998304368E-2,1.3067622639189128E-2,1.486154819309377E-2,1.6951038162299013E-2,1.9325993782122276E-2,2.196459014017057E-2,2.4836437503493788E-2,2.790693900236378E-2,3.1142476678549795E-2,3.451553954335767E-2,3.8008728388333746E-2,4.161679441824065E-2,4.534637713190618E-2,4.9213671734883856E-2,5.3240664386659343E-2,5.7450728081081905E-2,3.2321135148613567E-3,3.622409350441694E-4,1.6941951394728044E-5,-1.2535874409792726E-5,1.4678533632524765E-4,4.6310673395339667E-4,9.241566050582568E-4,1.5187961457067368E-3,3.02107597448455E-3,4.389987275618015E-3,5.540575673890826E-3,6.459180164190825E-3,7.219319136685496E-3,7.937467050829152E-3,8.726812392079774E-3,9.675635463687196E-3,1.0844816933404867E-2,1.2272325044691994E-2,1.3977878859611298E-2,1.5966035796681034E-2,1.8228233842667155E-2,2.074485914862828E-2,2.3488176314794527E-2,2.642640746994729E-2,2.952861760968982E-2,3.276957077015026E-2,3.6133546405141465E-2,3.961630928483935E-2,4.3224903381822E-2,4.697547488856921E-2,5.0889719320017186E-2,5.4990699263797495E-2,2.97939322109848E-3,3.318126449637497E-4,1.3074382064715942E-5,-1.3731222508010661E-5,1.3424868591093418E-4,4.2777618067125415E-4,8.556928100723333E-4,1.407937790672129E-3,2.805212928890566E-3,4.080746691927984E-3,5.155666919213547E-3,6.017200620985069E-3,6.73368657312566E-3,7.413653459655106E-3,8.162862890549924E-3,9.064142505912809E-3,1.0174984273560618E-2,1.1531641217879533E-2,1.315339871353202E-2,1.5045387382414744E-2,1.7200432199775652E-2,1.9600941284754633E-2,2.2221623518327814E-2,2.503330873576179E-2,2.800755164645021E-2,3.1121231883186263E-2,3.436019124183448E-2,3.7721136224663984E-2,4.121148197807656E-2,4.484731991156184E-2,4.865006365685755E-2,5.2642476535538656E-2,2.7492426817994813E-3,3.042794011302682E-4,9.765548447328563E-6,-1.4640169798897243E-5,1.2291319822610932E-4,3.9551449739156367E-4,7.930079090041562E-4,1.3063000333234421E-3,2.6069408684375244E-3,3.796363568642527E-3,4.801287466328326E-3,5.609768517051308E-3,6.285389645012327E-3,6.92936145710835E-3,7.640585260231398E-3,8.496830605773832E-3,9.552423238165252E-3,1.0841988633229075E-2,1.238436760808462E-2,1.4185180639919984E-2,1.6238502534331557E-2,1.8528588597788158E-2,2.1032396562678666E-2,2.372316631171846E-2,2.6574760577784056E-2,2.9566023895373623E-2,3.268424973513266E-2,3.592701727826024E-2,3.930208001708708E-2,4.282546770792204E-2,4.6518318902408894E-2,5.0403106527854256E-2,2.5395715775743117E-3,2.793544354081905E-4,6.941319353604737E-6,-1.530799811520095E-5,1.1265933418430174E-4,3.6604697333674093E-4,7.356023833297734E-4,1.2131004131744729E-3,2.424804602631913E-3,3.5348162342169857E-3,4.4749950481125225E-3,5.234169949437319E-3,5.871556043513474E-3,6.481622985926124E-3,7.156934507463919E-3,7.970567879180102E-3,8.973890693337821E-3,1.019998489409526E-2,1.1667239581437063E-2,1.3381690354172589E-2,1.533853644778447E-2,1.7523719052754034E-2,1.991626321188574E-2,2.2491634263364417E-2,2.5225832463602153E-2,2.8099525140962308E-2,3.1101352472305638E-2,3.4229700241594385E-2,3.749262823179407E-2,4.090609693832729E-2,4.449097507531481E-2,4.8269452202022674E-2],[1.6451547326723E-1,1.6789579527837523E-1,1.709760657164614E-1,1.737445778600596E-1,1.7616883456399177E-1,1.7820057284995075E-1,1.79782109401023E-1,1.8085313634471614E-1,1.81357198074052E-1,1.812472157140803E-1,1.8048960049397092E-1,1.7906670534555472E-1,1.769775855911148E-1,1.7423724436945928E-1,1.7087469563316365E-1,1.6693026575399725E-1,1.624525682030686E-1,1.5749553444638648E-1,1.5211578918881766E-1,1.4637054445726003E-1,1.4031607724689799E-1,1.3400676544258242E-1,1.2749459448581874E-1,1.2082901391039015E-1,1.1405701475142133E-1,1.0722330975428472E-1,1.0037052139580097E-1,9.353931163123619E-2,8.676841681563836E-2,8.009457764037989E-2,7.355237479507636E-2,6.717399528915953E-2,1.6073062970702245E-1,1.6443959721735174E-1,1.678774913639239E-1,1.7103022020525582E-1,1.7386303288448202E-1,1.7632532550466654E-1,1.7835679929342224E-1,1.7989412804436758E-1,1.8087737878145518E-1,1.8125555245314048E-1,1.8099077547201856E-1,1.8006087355962053E-1,1.7846027732500314E-1,1.761994141470266E-1,1.7330290180910388E-1,1.6980695341021992E-1,1.657564231098772E-1,1.612018769259847E-1,1.5619698220563608E-1,1.5079639814216023E-1,1.4505424038802167E-1,1.3902310170372256E-1,1.3275354628222055E-1,1.2629395960743944E-1,1.1969062526769016E-1,1.1298790920044792E-1,1.0622845370258065E-1,9.94533118977731E-2,9.270198297071147E-2,8.601233544755016E-2,7.942042757277722E-2,7.296024910017886E-2,1.567852940923994E-1,1.6079226835181065E-1,1.6455761883653394E-1,1.680652036597862E-1,1.7127837733975085E-1,1.7414457544130982E-1,1.7660127700301204E-1,1.7858253044243763E-1,1.8002530187426452E-1,1.8087501499513411E-1,1.8108980505092326E-1,1.8064320228727673E-1,1.7952517407744922E-1,1.777416596833273E-1,1.7531289546330614E-1,1.722709277216776E-1,1.6865673670160647E-1,1.6451735579518348E-1,1.5990328399233694E-1,1.5486638101988173E-1,1.494583260791622E-1,1.4372962920492457E-1,1.3772911816196798E-1,1.3150378574303515E-1,1.2509886964076267E-1,1.1855804424205349E-1,1.1192362425041093E-1,1.0523670775146253E-1,9.853721592456871E-2,9.186381404929572E-2,8.525372105041033E-2,7.874243109103206E-2,1.52707688015259E-1,1.5698239328726993E-1,1.610451194830706E-1,1.6487800067228095E-1,1.6844284664196807E-1,1.71685505089259E-1,1.7454162140691856E-1,1.7694301131364085E-1,1.7882392182994256E-1,1.8012655409347622E-1,1.8080536429154573E-1,1.8082984384955253E-1,1.8018568909747523E-1,1.7887447433432624E-1,1.7691210835578428E-1,1.7432645863028928E-1,1.711545595358518E-1,1.6743978743778493E-1,1.6322930398230248E-1,1.5857196333224396E-1,1.5351677162256877E-1,1.481118945595857E-1,1.424041414285771E-1,1.3643881361716664E-1,1.3025979089652828E-1,1.2390973399680788E-1,1.1743030120920142E-1,1.1086230371255104E-1,1.0424575377105004E-1,9.761978776950574E-2,9.102246939124661E-2,8.449049545676439E-2,1.4852470251071984E-1,1.5303745974564378E-1,1.5736782451371045E-1,1.6149652030747363E-1,1.6538414955302239E-1,1.6897533336530193E-1,1.7220426325222232E-1,1.750009101950616E-1,1.7729718454109356E-1,1.7903242637369562E-1,1.8015773836674015E-1,1.8063884977371436E-1,1.804574041094435E-1,1.7961076508407756E-1,1.781106031193668E-1,1.7598063307362416E-1,1.732539115762202E-1,1.6997007439135564E-1,1.6617281753377558E-1,1.6190782334382595E-1,1.5722122666242805E-1,1.5215862371928435E-1,1.4676455738340324E-1,1.4108237033645676E-1,1.3515430077786078E-1,1.2902169869445132E-1,1.2272525851332687E-1,1.1630519009000304E-1,1.0980127918975682E-1,1.0325281671298288E-1,9.669839991429385E-2,9.01756269686361E-2,1.4426177093913067E-1,1.4898370154636867E-1,1.5355253898113166E-1,1.579478946567068E-1,1.621294856904577E-1,1.660410533778544E-1,1.6961570278470542E-1,1.7278193945766893E-1,1.754697157882351E-1,1.7761587453435873E-1,1.7916849909640967E-1,1.8008984844524556E-1,1.8035775293211595E-1,1.7996554693767142E-1,1.7892078308363996E-1,1.7724308464952881E-1,1.7496153577381895E-1,1.7211198651532614E-1,1.6873457788854435E-1,1.6487169278316768E-1,1.6056643425456338E-1,1.5586164024924384E-1,1.5079937380319786E-1,1.454207839067896E-1,1.3976621328896385E-1,1.3387543094936405E-1,1.2778788360420912E-1,1.2154288543484652E-1,1.1517969439221323E-1,1.0873745157721558E-1,1.02254984791099E-1,9.57704962827588E-2,1.3994277225673327E-1,1.4484597250042675E-1,1.4962488672741847E-1,1.542582957741578E-1,1.5870533590996064E-1,1.6290919824063507E-1,1.6680225350253464E-1,1.7031190901235657E-1,1.733665303746618E-1,1.759008247923547E-1,1.7786019491309837E-1,1.7920373204103562E-1,1.7990570996421926E-1,1.7995563757808805E-1,1.7935709765451235E-1,1.78125714106857E-1,1.762866378084137E-1,1.738719237975116E-1,1.7091810547103867E-1,1.674641756222476E-1,1.6355008163394186E-1,1.5921575008105227E-1,1.5450058514401413E-1,1.4944333981161567E-1,1.4408223802590842E-1,1.3845522568200863E-1,1.3260024325718858E-1,1.2655543708656264E-1,1.2035925473344837E-1,1.1405039824633041E-1,1.0766763415753502E-1,1.0124947877613198E-1,1.3558996258353903E-1,1.406476495373911E-1,1.4560918507907347E-1,1.5045278242691984E-1,1.5513728209394073E-1,1.5960563539332E-1,1.6378981301685067E-1,1.6761647622244502E-1,1.7101276407917737E-1,1.7391160429394162E-1,1.7625605751493548E-1,1.7800235649420584E-1,1.7912148772802558E-1,1.7959935685735048E-1,1.7943574812832067E-1,1.7864240577287124E-1,1.7724061724982962E-1,1.7525866612497604E-1,1.7272945983327098E-1,1.696885453937333E-1,1.6617262569038754E-1,1.6221859748437512E-1,1.5786306087004562E-1,1.531422030632481E-1,1.4809193680877036E-1,1.427481716805533E-1,1.3714710991706186E-1,1.31325481636797E-1,1.253206621903721E-1,1.1917064273320103E-1,1.1291385056909581E-1,1.0658883620911082E-1,1.3122393276052013E-1,1.3641056309828092E-1,1.4152834771615144E-1,1.4655517552521755E-1,1.51449855693464E-1,1.5615538929063477E-1,1.606036614196433E-1,1.647209219770563E-1,1.6843342993978058E-1,1.7167268055698107E-1,1.7437972780600988E-1,1.765082575964107E-1,1.780262470428974E-1,1.789162351105262E-1,1.7917439828732215E-1,1.7880874455671172E-1,1.7783679499981545E-1,1.76283115024199E-1,1.7417699931644595E-1,1.7155052610271027E-1,1.6843709811539606E-1,1.6487049704892484E-1,1.608844064525073E-1,1.5651230995612647E-1,1.5178764746406975E-1,1.4674410821370956E-1,1.4141595146609634E-1,1.3583826770597215E-1,1.300471205423016E-1,1.2407953772242204E-1,1.179733454568542E-1,1.1176686127267951E-1,1.268635894449837E-1,1.3215495261549923E-1,1.374038138620589E-1,1.425879607535975E-1,1.476664139627687E-1,1.525824918557552E-1,1.5726828704259474E-1,1.6164995331994092E-1,1.6565319978773826E-1,1.6920842439262834E-1,1.7225500309488034E-1,1.7474438571372866E-1,1.7664182278288654E-1,1.7792673368726697E-1,1.785918935654003E-1,1.7864173765735725E-1,1.7809014142107754E-1,1.7695803198873677E-1,1.7527113318803741E-1,1.730580615588006E-1,1.7034889503840484E-1,1.6717424641309028E-1,1.635648016201551E-1,1.5955123387894915E-1,1.5516437882384798E-1,1.5043555041009476E-1,1.453968877345141E-1,1.4008164389033714E-1,1.3452435461952375E-1,1.2876085255747216E-1,1.2282811888283333E-1,1.167639857615318E-1,1.225261572159424E-1,1.2789944475955428E-1,1.3325550173365575E-1,1.385722166521079E-1,1.438090424908776E-1,1.4890985969964654E-1,1.5380723904176297E-1,1.5842753253124606E-1,1.6269621141376833E-1,1.6654289718535695E-1,1.6990560693071438E-1,1.7273386098992083E-1,1.7499046757018746E-1,1.766519805047789E-1,1.777079920048741E-1,1.781595445705275E-1,1.7801700907059356E-1,1.7729777757695764E-1,1.760240706401774E-1,1.7422107765173112E-1,1.7191555574428447E-1,1.6913492432993432E-1,1.6590682038150154E-1,1.6225902956679686E-1,1.582196811179611E-1,1.5381758731416192E-1,1.4908261733985195E-1,1.440460150908858E-1,1.3874059641152195E-1,1.3320078900646712E-1,1.2746250444219057E-1,1.2156285371175674E-1,1.1822719914267864E-1,1.2366105205388839E-1,1.291017840512369E-1,1.345275661941516E-1,1.3989848237075253E-1,1.4515919678420885E-1,1.5024300586284636E-1,1.5507673212804168E-1,1.5958590127095268E-1,1.636996628950099E-1,1.673549824117964E-1,1.7049975034587675E-1,1.7309461518116245E-1,1.7511352285141407E-1,1.7654310966166495E-1,1.7738121844694474E-1,1.7763487344420384E-1,1.7731805499401362E-1,1.7644957061737687E-1,1.750512417342307E-1,1.7314653477017744E-1,1.7075967843897374E-1,1.679152371922276E-1,1.6463806010662665E-1,1.6095349594881553E-1,1.5688775662209728E-1,1.5246831861445403E-1,1.4772427068534638E-1,1.4268654114946955E-1,1.3738796553193952E-1,1.318631816127323E-1,1.2614836135014873E-1,1.1398065330153023E-1,1.1945518943672702E-1,1.2495948332852899E-1,1.3047214976949054E-1,1.3595408014902557E-1,1.4135092095115057E-1,1.4659691832935193E-1,1.5161961488381842E-1,1.5634486220489546E-1,1.6070162468785254E-1,1.646261093088371E-1,1.680648670642211E-1,1.709766649031128E-1,1.7333309912226E-1,1.751180825687954E-1,1.7632646131762744E-1,1.7696208462308027E-1,1.7703566138564963E-1,1.7656269599394225E-1,1.7556172287570307E-1,1.740529713341107E-1,1.720575068276191E-1,1.6959682342328694E-1,1.6669281086228477E-1,1.6336798996422375E-1,1.5964590010279717E-1,1.5555152845765832E-1,1.511116881563685E-1,1.4635527670184303E-1,1.413133730833321E-1,1.360191582099753E-1,1.3050766611877498E-1,1.0979888280026781E-1,1.1529570637476019E-1,1.2084388463696874E-1,1.264226174007646E-1,1.3199375856348217E-1,1.3750411254655362E-1,1.4288907584870605E-1,1.480771376666289E-1,1.529947253510481E-1,1.575708857074758E-1,1.6174134490947828E-1,1.654515932787919E-1,1.6865878758505623E-1,1.713324306558335E-1,1.7345394684740523E-1,1.7501539518164985E-1,1.760176322022549E-1,1.7646824958001117E-1,1.7637957515781943E-1,1.7576695632267472E-1,1.7464745966425274E-1,1.7303903713347413E-1,1.7096013800950843E-1,1.6842969427143373E-1,1.6546737619623375E-1,1.6209400362996593E-1,1.583320029405186E-1,1.5420581585108278E-1,1.4974218975402928E-1,1.4497030563090363E-1,1.3992172587092158E-1,1.3463016736434819E-1,1.0569273697842099E-1,1.1119493220022703E-1,1.1676876355911761E-1,1.2239413799325939E-1,1.2803400599534548E-1,1.3363648323820834E-1,1.391382940454464E-1,1.4446907765744124E-1,1.495560650509035E-1,1.5432863316117654E-1,1.5872228811251285E-1,1.6268172527348584E-1,1.661627536795145E-1,1.69133034370827E-1,1.715717380680996E-1,1.7346835045748848E-1,1.748209253875646E-1,1.7563410252883624E-1,1.7591717359035264E-1,1.7568241506047383E-1,1.749438233896682E-1,1.7371630657139817E-1,1.7201531583835708E-1,1.698568491995407E-1,1.6725772682419193E-1,1.6423602560315173E-1,1.608115634067416E-1,1.570063385286691E-1,1.5284485229040595E-1,1.4835426877285696E-1,1.4356439166669643E-1,1.3850746152000235E-1,1.0167162158817017E-1,1.0716373244307154E-1,1.1274642710592395E-1,1.1840042343364157E-1,1.2408988253277073E-1,1.2976436304342062E-1,1.3536207200139852E-1,1.408139793310752E-1,1.4604832541041088E-1,1.509950446219836E-1,1.5558966598075638E-1,1.5977634113541753E-1,1.6350978317786646E-1,1.6675605647834799E-1,1.6949231051958147E-1,1.717056728380003E-1,1.7339158967874557E-1,1.745519222310924E-1,1.7519307757131128E-1,1.7532439092658267E-1,1.7495689673306986E-1,1.7410254587978713E-1,1.7277385708672868E-1,1.709839382279979E-1,1.6874678086118514E-1,1.6607771732991838E-1,1.6299393166493642E-1,1.5951492926364572E-1,1.5566289186964322E-1,1.5146286978155968E-1,1.469427890394997E-1,1.421332747622923E-1,9.774357591703088E-2,1.0321157405633466E-1,1.0878776546457121E-1,1.1445376540720191E-1,1.2017504055418432E-1,1.2590270355308525E-1,1.3157657720482824E-1,1.3712912045711706E-1,1.424897669519237E-1,1.4758921522824645E-1,1.5236324169903376E-1,1.5675569000350834E-1,1.607204170004851E-1,1.6422212717107984E-1,1.6723617664029355E-1,1.6974754916684864E-1,1.7174928111982374E-1,1.73240634478251E-1,1.7422529169472983E-1,1.7470978728961167E-1,1.7470231482424922E-1,1.7421196978041445E-1,1.732484203419511E-1,1.7182194591641614E-1,1.6994374996641332E-1,1.6762643869010047E-1,1.648845576656384E-1,1.6173509112390522E-1,1.5819784909073742E-1,1.5429569241844432E-1,1.5005457128073824E-1,1.4550337620492199E-1,9.39153549842232E-2,9.93465975792235E-2,1.0490231256125869E-1,1.1056508288800433E-1,1.1630175778875125E-1,1.2206509534714821E-1,1.277966462781446E-1,1.3343049530238926E-1,1.388974316908391E-1,1.4412910429823902E-1,1.4906174267584274E-1,1.5363910190415914E-1,1.578144091146626E-1,1.6155123586740427E-1,1.6482336651471474E-1,1.676138525745596E-1,1.6991351869852037E-1,1.717192103473559E-1,1.730320514609546E-1,1.738559248873895E-1,1.7419631503887814E-1,1.7405957614545742E-1,1.7345262196230488E-1,1.7238298072437144E-1,1.708591252631665E-1,1.6889097211750617E-1,1.664904428128855E-1,1.636719918447625E-1,1.6045302549867302E-1,1.5685415975014494E-1,1.5289929072313999E-1,1.4861547470037692E-1,9.01925151217084E-2,9.557569444238062E-2,1.0109831356008135E-1,1.0674397836595594E-1,1.1248098088986012E-1,1.1826379764088234E-1,1.2403579956089082E-1,1.2973281318429505E-1,1.352871248948715E-1,1.4063149976225653E-1,1.4570280737057714E-1,1.504449169681862E-1,1.5481063841679227E-1,1.587626263155909E-1,1.6227330703002987E-1,1.653240067776036E-1,1.6790353511751965E-1,1.700065049904209E-1,1.716316518196778E-1,1.7278036202012606E-1,1.7345555086916142E-1,1.7366095567276432E-1,1.7340084375171158E-1,1.7268008291529668E-1,1.7150448770341983E-1,1.698813376250901E-1,1.6781996178515113E-1,1.6533229448405418E-1,1.624333249848578E-1,1.5914138805013894E-1,1.554782667192779E-1,1.5146910226959626E-1,8.657950143348861E-2,9.190458778844734E-2,9.738279756962373E-2,1.0299880100314349E-1,1.0872237766002492E-1,1.145097782745755E-1,1.2030626766546587E-1,1.2604951052996918E-1,1.3167341175230207E-1,1.3711199874446148E-1,1.4230294931863724E-1,1.4719043267438578E-1,1.5172703922810268E-1,1.5587471063930136E-1,1.5960472003079343E-1,1.6289686915477627E-1,1.6573814584416915E-1,1.6812111392967433E-1,1.7004229218197062E-1,1.7150072992533935E-1,1.7249691945674583E-1,1.7303211349329448E-1,1.7310805065100246E-1,1.727270404036445E-1,1.7189232417490058E-1,1.7060861127631952E-1,1.688826854440843E-1,1.6672398677858086E-1,1.6414509150848686E-1,1.611620346805318E-1,1.5779444533139703E-1,1.5406548707665E-1,8.307973580868898E-2,8.83379153533026E-2,9.376165398776397E-2,9.93367150534596E-2,1.050343961863221E-1,1.1081276225546498E-1,1.16619028191488E-1,1.223927746338937E-1,1.2806962718011655E-1,1.335850025961483E-1,1.388775367597419E-1,1.4389186766100787E-1,1.4858054911221494E-1,1.52905001228521E-1,1.5683553859759886E-1,1.6035063197134766E-1,1.6343563607214456E-1,1.6608124676955496E-1,1.682819380991464E-1,1.7003458382419565E-1,1.71337403569251E-1,1.7218930377893693E-1,1.7258961979106596E-1,1.7253821415349205E-1,1.7203585120307194E-1,1.7108474917695313E-1,1.6968920710095742E-1,1.6785621163836498E-1,1.655959457102666E-1,1.6292214262681462E-1,1.598522534719845E-1,1.564074187189528E-1,7.969570434166592E-2,8.487931312546212E-2,9.023971107806174E-2,9.57637720296357E-2,1.0142432927922908E-1,1.0718128717461836E-1,1.1298385087534679E-1,1.1877357737098417E-1,1.2448789703816274E-1,1.3006372468596977E-1,1.3544078624541767E-1,1.405643405827203E-1,1.4538707262413342E-1,1.4987005924659197E-1,1.5398284040832746E-1,1.5770274092155917E-1,1.6101366499844624E-1,1.639046179786063E-1,1.6636819952443466E-1,1.6839926982667403E-1,1.6999392848347974E-1,1.711488780890564E-1,1.718611819167296E-1,1.7212837439865572E-1,1.719488477658569E-1,1.713224187353397E-1,1.702509740981115E-1,1.6873910092082203E-1,1.6679462271821907E-1,1.6442898411349252E-1,1.616574500199425E-1,1.584991084224939E-1,7.64290431831001E-2,8.153149866957517E-2,8.682081553414261E-2,9.228498525605058E-2,9.789838274981265E-2,1.0362276394800264E-1,1.0940934955916032E-1,1.1520171720774905E-1,1.2093916907612609E-1,1.2656020928572972E-1,1.3200576860502294E-1,1.3722186246264678E-1,1.421614595398584E-1,1.4678545843064592E-1,1.5106279701440836E-1,1.5496983000189565E-1,1.5848918663036304E-1,1.6160835417720987E-1,1.6431822533021273E-1,1.6661180761691835E-1,1.6848323395306075E-1,1.6992714789352495E-1,1.7093847587855912E-1,1.7151254863622567E-1,1.71645498418909E-1,1.7133483862220733E-1,1.7058012635314282E-1,1.6938361432959154E-1,1.6775081316458038E-1,1.656909054685399E-1,1.6321697620187664E-1,1.6034604652417206E-1,7.328062200749563E-2,7.829635316212269E-2,8.350791194843657E-2,8.890440560043056E-2,9.44617462065804E-2,1.0014354146574167E-1,1.0590303948328571E-1,1.1168586795609013E-1,1.1743325202109664E-1,1.230853599476396E-1,1.2858442568080405E-1,1.3387734099207288E-1,1.389174960891539E-1,1.436657628054548E-1,1.480906377761761E-1,1.521676716083458E-1,1.5587838618769528E-1,1.592089171889429E-1,1.6214861354856888E-1,1.646887886107044E-1,1.6682176118723602E-1,1.6854026144072573E-1,1.6983721660594517E-1,1.7070588205100448E-1,1.7114024762843036E-1,1.7113562855808445E-1,1.7068934321311038E-1,1.6980138498909014E-1,1.6847500915015404E-1,1.6671717513716497E-1,1.6453880727955691E-1,1.619548593974619E-1,7.02506244331058E-2,7.517500134109763E-2,8.030312125590737E-2,8.562519732966696E-2,9.111866520040829E-2,9.674897387263341E-2,1.0247139853449788E-1,1.082336328281153E-1,1.1397886131015743E-1,1.1964897584560365E-1,1.251875962966056E-1,1.3054259525974382E-1,1.3566790771668966E-1,1.4052451690535459E-1,1.4508062714713357E-1,1.49311140667288E-1,1.5319663105287457E-1,1.5672204197232734E-1,1.5987533663481734E-1,1.6264628908347753E-1,1.650255545510413E-1,1.6700409490218476E-1,1.6857297672077412E-1,1.6972351076046238E-1,1.7044766593054156E-1,1.707386697722809E-1,1.7059169967966725E-1,1.7000457296136887E-1,1.689783566140318E-1,1.675178364768799E-1,1.656318073299444E-1,1.6333316774036236E-1,6.733862486889698E-2,7.216788871510699E-2,7.720781736991664E-2,8.244971318198167E-2,8.787251369082968E-2,9.344348934300035E-2,9.911993121422946E-2,1.048516024719333E-1,1.1058367008043668E-1,1.1625979464470604E-1,1.2182504999741198E-1,1.2722837944377607E-1,1.324243719243314E-1,1.373742471012274E-1,1.42046053972731E-1,1.464141915581587E-1,1.5045843514251042E-1,1.5416268844324868E-1,1.5751368092042448E-1,1.6049979760877214E-1,1.6311017751462248E-1,1.6533415752129202E-1,1.6716108172760347E-1,1.6858044803014222E-1,1.6958232828344416E-1,1.7015797671493518E-1,1.7030053279757304E-1,1.700057277011848E-1,1.6927251529742454E-1,1.6810356670207402E-1,1.665055886494016E-1,1.6448944790236666E-1,6.454366138906592E-2,6.927485550980211E-2,7.422270136458202E-2,7.937956788752908E-2,8.472586594720995E-2,9.023065935106478E-2,9.58532342245915E-2,1.015454157942316E-1,1.0725436414460882E-1,1.129255405655588E-1,1.1850552718366796E-1,1.2394441406777608E-1,1.291975397955113E-1,1.3422647265532597E-1,1.3899923147120685E-1,1.4348984656292035E-1,1.47677435525023E-1,1.5154500612342173E-1,1.5507819932111497E-1,1.582641560210287E-1,1.610906422296889E-1,1.6354551032145098E-1,1.6561651852372203E-1,1.6729148339886685E-1,1.68558704752663E-1,1.694075803653088E-1,1.6982931875154336E-1,1.698176601918504E-1,1.6936952723473175E-1,1.6848554309183383E-1,1.6717037706397594E-1,1.6543289768565686E-1,6.18643043485554E-2,6.649520695018594E-2,7.134787268481069E-2,7.64157095007746E-2,8.16805671319904E-2,8.711326757191226E-2,9.267506270162267E-2,9.831982250244337E-2,1.0399669979949444E-1,1.0965297641987355E-1,1.1523678436144769E-1,1.2069942350483365E-1,1.259970648673038E-1,1.3109172517199766E-1,1.3595150658806976E-1,1.4055019457880083E-1,1.448663800868097E-1,1.4888231050382114E-1,1.5258267629498787E-1,1.559535130216305E-1,1.5898135199232957E-1,1.61652697787691E-1,1.6395385681016617E-1,1.6587109447161702E-1,1.6739106347121507E-1,1.6850142326659664E-1,1.6919156099180074E-1,1.6945332527116386E-1,1.6928169446608834E-1,1.6867531733358054E-1,1.676368841873866E-1,1.661733078195839E-1,5.929872055299634E-2,6.382777958581778E-2,6.858289698092745E-2,7.355848802952523E-2,7.873780193882805E-2,8.409337767592705E-2,8.958839625304131E-2,9.51787464248911E-2,1.0081556343631543E-1,1.0644795850732537E-1,1.120256433335888E-1,1.1750117850495287E-1,1.2283163809328841E-1,1.2797957517322925E-1,1.329132774582284E-1,1.376063988530783E-1,1.4203712505033392E-1,1.461870699906083E-1,1.5004010400123585E-1,1.5358128947975627E-1,1.5679605576140446E-1,1.596696918236563E-1,1.6218718285151823E-1,1.6433337098499415E-1,1.660933856456326E-1,1.6745326623070567E-1,1.6840068950825945E-1,1.6892571444526058E-1,1.6902146644598015E-1,1.6868469865004782E-1,1.6791618744095846E-1,1.6672094008080557E-1,5.684473288382776E-2,6.1271003462244275E-2,6.59268702691471E-2,7.080772095665232E-2,7.589816077503632E-2,8.117239939989569E-2,8.659550407999704E-2,9.212534878932246E-2,9.771503204080301E-2,1.0331549337874386E-1,1.0887804326478805E-1,1.1435654261999614E-1,1.1970902772709517E-1,1.2489866460090952E-1,1.2989401776690188E-1,1.3466871253828563E-1,1.3920064116808803E-1,1.434709023014898E-1,1.4746266858944926E-1,1.5116015443751984E-1,1.5454781383801736E-1,1.5760984720080448E-1,1.603300449264992E-1,1.6269195062459604E-1,1.6467929223469494E-1,1.6627660649553283E-1,1.6746997119751017E-1,1.682477592997255E-1,1.6860133742361053E-1,1.6852564615047846E-1,1.6801961843800223E-1,1.6708641281737746E-1,5.4499875354533066E-2,5.8822960026366375E-2,6.337847921201632E-2,6.816275535098128E-2,7.316170308454084E-2,7.835115238981312E-2,8.36980085775233E-2,8.916209075705013E-2,9.469843378773762E-2,1.002597955845196E-1,1.0579909466282485E-1,1.1127152150240298E-1,1.1663612304959872E-1,1.2185674412951673E-1,1.2690230686902162E-1,1.3174650091971324E-1,1.3636702745325163E-1,1.407445791993057E-1,1.4486174554933412E-1,1.4870201080895923E-1,1.5224897377146415E-1,1.5548586765628092E-1,1.5839540973099536E-1,1.609599659738539E-1,1.631619818094852E-1,1.6498460698179332E-1,1.6641243111547996E-1,1.674322454520806E-1,1.6803375389360975E-1,1.6821017066007754E-1,1.6795866014095157E-1,1.6728059443601928E-1,5.226144363762802E-2,5.648143572635613E-2,6.0936057394574604E-2,6.562252635345389E-2,7.052801750430163E-2,7.562992741307144E-2,8.08969469156249E-2,8.629079462013302E-2,9.176840804599463E-2,9.72843456379591E-2,1.0279313442624513E-1,1.0825131415742366E-1,1.1361898095935473E-1,1.1886071426070668E-1,1.2394586460377961E-1,1.2884826923137044E-1,1.3354553135782873E-1,1.3801803848387223E-1,1.422479030679019E-1,1.4621798976176564E-1,1.499111555378224E-1,1.5330978175778617E-1,1.5639562893802997E-1,1.5915000189803033E-1,1.615541790093841E-1,1.6359003618514825E-1,1.6524078428128972E-1,1.6649173684770385E-1,1.6733103206053987E-1,1.6775024611549816E-1,1.6774485302420153E-1,1.6731450522951588E-1],[3.4818916670946853E-1,9.993548592494965E-1,9.974483417219177E-1,9.943273246445654E-1,9.900429236451004E-1,9.846499188395631E-1,9.782061810569083E-1,9.707721048938651E-1,9.624100546867816E-1,9.531838288296345E-1,9.43158147176909E-1,9.323981655629012E-1,9.209690207602063E-1,9.089354085032382E-1,8.963611965294114E-1,8.833090739511444E-1,8.698402376743603E-1,8.560141160300803E-1,8.41888129289738E-1,8.275174862950373E-1,8.129550160510871E-1,7.98251032807374E-1,7.83453232883883E-1,7.686066212873544E-1,7.537534660024234E-1,7.3893327773075E-1,7.241828127841875E-1,7.095360968112553E-1,6.950244670451066E-1,6.806766308012302E-1,6.665187380196967E-1,6.525744657354096E-1,6.666341734258499E-2,3.4795354733568834E-1,9.993680548405822E-1,9.975010677807784E-1,9.94445669066624E-1,9.902525212599069E-1,9.849757601950682E-1,9.78672437687523E-1,9.714019723260724E-1,9.632256140803349E-1,9.542059278088673E-1,9.444063000812735E-1,9.338904730434728E-1,9.227221083734339E-1,9.109643837076126E-1,8.986796232768969E-1,8.859289638842373E-1,8.727720567916875E-1,8.592668055680243E-1,8.454691394834805E-1,8.314328216279495E-1,8.172092905744107E-1,8.028475341101537E-1,7.883939933134303E-1,7.738924950602819E-1,7.593842109026118E-1,7.449076401605769E-1,7.304986150161976E-1,7.161903253764743E-1,7.02013361288937E-1,6.879957707360078E-1,6.741631307024765E-1,7.236338025742114E-2,6.614759464576385E-2,3.477151115965263E-1,9.99381271487806E-1,9.975538655417278E-1,9.945641497578607E-1,9.904623222497156E-1,9.853018675502956E-1,9.79139015778329E-1,9.720322110484868E-1,9.640415945106974E-1,9.552285067718366E-1,9.456550137996048E-1,9.353834597477035E-1,9.244760494865363E-1,9.129944629861529E-1,9.009995030879598E-1,8.885507776271209E-1,8.757064163351951E-1,8.625228224673811E-1,8.490544586642345E-1,8.353536661759063E-1,8.214705162485445E-1,8.074526921970844E-1,7.933454004647955E-1,7.791913087954121E-1,7.650305095155071E-1,7.50900505839541E-1,7.368362190638976E-1,7.228700145051417E-1,7.090317440575218E-1,6.953488032911813E-1,7.805883746248292E-2,7.176035601472486E-2,6.562542413295444E-2,3.474734021327585E-1,9.993945019507333E-1,9.976067061260816E-1,9.946827020169517E-1,9.906722122200599E-1,9.856280633399952E-1,9.796056615676314E-1,9.726624785705558E-1,9.648575527449937E-1,9.562510102613846E-1,9.469036097018926E-1,9.36876313451182E-1,9.262298883738411E-1,9.15024537703556E-1,9.033195654895635E-1,8.911730744025238E-1,8.78641697200634E-1,8.657803617018911E-1,8.526420887028222E-1,8.392778219292906E-1,8.257362888015327E-1,8.120638905426897E-1,7.983046199561747E-1,7.845000050399203E-1,7.706890764919209E-1,7.569083570881331E-1,7.431918708769882E-1,7.295711701305823E-1,7.160753780170285E-1,8.37207177200519E-2,7.736809849575911E-2,7.114998836353424E-2,6.50960194887204E-2,3.4722806810814705E-1,9.994077390008669E-1,9.976595607074736E-1,9.948012612635014E-1,9.908820769847569E-1,9.859541702949028E-1,9.800721216509833E-1,9.73292432759287E-1,9.656730458057963E-1,9.572728828236415E-1,9.481514087062893E-1,9.383682207622034E-1,9.279826671056141E-1,9.170534955985626E-1,9.056385345097879E-1,8.937944055429861E-1,8.815762694156951E-1,8.690376037442755E-1,8.56230012612578E-1,8.432030668730567E-1,8.300041739493539E-1,8.166784756778287E-1,8.032687725403782E-1,7.898154724998002E-1,7.763565625489073E-1,7.629276010222821E-1,7.495617286913436E-1,7.362896966654812E-1,8.932116713086129E-2,8.294271663265493E-2,7.66689553028363E-2,7.053136588084138E-2,6.455873960774466E-2,3.469788722400132E-1,9.994209754262707E-1,9.977124005302925E-1,9.949197630793704E-1,9.910918026390966E-1,9.862800115556842E-1,9.805381431447582E-1,9.739217320613577E-1,9.664876312607719E-1,9.582935693743502E-1,9.493977317314167E-1,9.398583676695319E-1,9.297334262008945E-1,9.190802215515701E-1,9.079551295699132E-1,8.964133155169763E-1,8.845084933094317E-1,8.722927158877561E-1,8.598161960310623E-1,8.471271566357941E-1,8.342717092182916E-1,8.212937591898488E-1,8.082349362854719E-1,7.951345484016291E-1,7.820295570109181E-1,7.689545722694922E-1,7.55941865912747E-1,9.483379062876512E-2,8.845730871247698E-2,8.215517620462781E-2,7.596048561857036E-2,6.990387457113967E-2,6.401319284952156E-2,3.46725687899044E-1,9.994342040361778E-1,9.977651969280535E-1,9.950381432498806E-1,9.913012756328854E-1,9.866054107868111E-1,9.810034738499062E-1,9.745500357259334E-1,9.673008675139496E-1,9.593125155682317E-1,9.50641900153788E-1,9.413459400981588E-1,9.314812052921729E-1,9.211035983690758E-1,9.102680663996595E-1,8.990283429860253E-1,8.874367207223072E-1,8.755438536197833E-1,8.633985887677764E-1,8.510478262210525E-1,8.385364058685574E-1,8.259070198459959E-1,8.132001489039902E-1,8.004540210318392E-1,7.877045905613462E-1,7.749855359325366E-1,1.0023385823841405E-1,9.388640475383117E-2,8.758269187278907E-2,8.135717673290092E-2,7.524211593224268E-2,6.926719201197339E-2,6.345922173287118E-2,3.464684885553919E-1,9.994474176655757E-1,9.978179213416922E-1,9.951563378048711E-1,9.91510382843296E-1,9.869301922902859E-1,9.814678624157723E-1,9.75177004028025E-1,9.681123140983771E-1,9.603291681710954E-1,9.518832362699665E-1,9.428301244725777E-1,9.332250438013301E-1,9.231225075842632E-1,9.125760579747748E-1,9.01638021891946E-1,8.903592962558186E-1,8.78789162046813E-1,8.669751264166359E-1,8.549627918196302E-1,8.427957509178591E-1,8.30515505838827E-1,8.181614102295953E-1,8.057706324526064E-1,7.933781382039249E-1,1.0549847556156967E-1,9.920616049573139E-2,9.292694748173169E-2,8.669641183674368E-2,8.054819729057369E-2,7.45136047397593E-2,6.862126080707752E-2,6.28968733339533E-2,3.462073319839368E-1,9.994606091797694E-1,9.978705453377668E-1,9.952742830595734E-1,9.917190116474688E-1,9.872541811191322E-1,9.819310585038531E-1,9.758022984922096E-1,9.68921531969932E-1,9.613429754343787E-1,9.531210637630578E-1,9.44310108287081E-1,9.349639816262207E-1,9.251358302729811E-1,9.148778154760852E-1,9.042408825731103E-1,8.93274558560519E-1,8.820267773688157E-1,8.705437320317514E-1,8.588697527012652E-1,8.4704720926328E-1,8.351164371519647E-1,8.231156848395703E-1,8.110810813928638E-1,1.1060671867107737E-1,1.0439451700844644E-1,9.816497463620519E-2,9.195454014811431E-2,8.579801097240322E-2,7.972808746346381E-2,7.377500427706186E-2,6.796624776123661E-2,6.2326360675583954E-2,3.459423415392702E-1,9.994737714789173E-1,9.979230406265566E-1,9.953919156552788E-1,9.919270499948143E-1,9.875772031905675E-1,9.823928129513644E-1,9.764255821165376E-1,9.697280838020438E-1,9.623533874717977E-1,9.543547081731226E-1,9.457850806825444E-1,9.366970598372497E-1,9.27142447884324E-1,9.171720492690548E-1,9.068354529086567E-1,8.961808416611363E-1,8.852548284020302E-1,8.741023178648527E-1,8.627663931839015E-1,8.512882258994997E-1,8.397070080441228E-1,8.280599048210152E-1,1.155397342293497E-1,1.0943132621614156E-1,1.0327554043618803E-1,9.71094579903867E-2,9.096879765736307E-2,8.48874385472875E-2,7.889701703443439E-2,7.302660827088561E-2,6.730249495345574E-2,6.1748019961046056E-2,3.456736865359939E-1,9.994868975025355E-1,9.979753790800454E-1,9.955091725997682E-1,9.92134386478962E-1,9.878990853987701E-1,9.828528779344945E-1,9.770465195964437E-1,9.705315342810749E-1,9.633598566377714E-1,9.555834973710735E-1,9.472542330291515E-1,9.38423321383244E-1,9.291412430849564E-1,9.194574699028231E-1,9.094202594894056E-1,8.990764763173518E-1,8.884714381483065E-1,8.776487871624781E-1,8.666503846784286E-1,8.555162282310486E-1,8.44284389648908E-1,1.2028080620377582E-1,1.142984432156762E-1,1.0823926393733366E-1,1.0214074766785743E-1,9.603930571523277E-2,8.996977594535895E-2,8.396498817489127E-2,7.805541223538826E-2,7.226889272637896E-2,6.663046817253157E-2,6.11622677608469E-2,3.4540156338856154E-1,9.99499980233971E-1,9.980275327497746E-1,9.956259913074764E-1,9.923409104093047E-1,9.882196557271598E-1,9.83311007131214E-1,9.776647775484774E-1,9.713314504021094E-1,9.643618379072819E-1,9.568067620356075E-1,9.487167595144769E-1,9.401418118058993E-1,9.311311006162867E-1,9.217327891276252E-1,9.119938288141648E-1,9.019597914186847E-1,8.916747254092275E-1,8.811810360208424E-1,8.705193878065349E-1,8.597286284759521E-1,1.24815391020701E-1,1.1897978679075955E-1,1.1303870095028322E-1,1.070297851976292E-1,1.0098992027211282E-1,9.495468579288871E-2,8.895789713046753E-2,8.303122260892831E-2,7.720388637828966E-2,7.150245577176129E-2,6.595070716975363E-2,6.056956134742899E-2,3.4512617873664075E-1,9.995130127048374E-1,9.980794738845561E-1,9.957423096393623E-1,9.925465118820856E-1,9.885387433601017E-1,9.837669558835108E-1,9.782800247336658E-1,9.721274017648858E-1,9.653587892568128E-1,9.580238361327086E-1,9.5017185773633E-1,9.418515799620314E-1,9.33110908163534E-1,9.239967209294266E-1,9.145546885100138E-1,9.048291154117954E-1,8.94862806443022E-1,8.846969552960838E-1,8.743710545890286E-1,1.2913112338150348E-1,1.2346136995265114E-1,1.1765839859795343E-1,1.1175981789149958E-1,1.0580276256737736E-1,9.982334206077648E-2,9.385615194855271E-2,8.793386299525072E-2,8.20868944333752E-2,7.6343171384937E-2,7.072796130418933E-2,6.52637810395051E-2,5.997036441249021E-2,3.4484773535561053E-1,9.995259879994113E-1,9.981311749480314E-1,9.958580659424545E-1,9.927510818509754E-1,9.888561787939514E-1,9.842204813589214E-1,9.788919322803175E-1,9.729189608696063E-1,9.663501720460059E-1,9.592340573972391E-1,9.516187292997312E-1,9.435516787528411E-1,9.350795572356914E-1,9.262479825805359E-1,9.171013685750606E-1,9.076827777584034E-1,8.98033796662132E-1,8.881944325673775E-1,1.3321779525980693E-1,1.2773130268728508E-1,1.2208492144634235E-1,1.1631601322000558E-1,1.1046176063711478E-1,1.0455859790576529E-1,9.864169994475536E-2,9.274454605752191E-2,8.689856602631979E-2,8.113286961086957E-2,7.547405519378414E-2,6.994608981019032E-2,6.457025089385156E-2,5.936511948865592E-2,3.445664212628096E-1,9.995388992589868E-1,9.981826086360648E-1,9.959731990890485E-1,9.92954512197086E-1,9.89171793947351E-1,9.846713427112228E-1,9.795001739060749E-1,9.737057034123544E-1,9.673354513996654E-1,9.60436767816125E-1,9.530565804173761E-1,9.452411658593592E-1,9.370359440553354E-1,9.284852957048942E-1,9.196324026420796E-1,9.105191104218897E-1,9.011858123691289E-1,1.370673108116269E-1,1.317797693555591E-1,1.2630685134163822E-1,1.2068548075358987E-1,1.149526927627696E-1,1.0914504978580003E-1,1.0329811142293831E-1,9.744597558511896E-2,9.162089988934609E-2,8.585300536147936E-2,8.01700590486344E-2,7.459732842980658E-2,6.915749841210785E-2,6.387064095062621E-2,5.875422759687389E-2,3.4428240210159805E-1,9.995517396861844E-1,9.982337478939591E-1,9.960876485155217E-1,9.931566957983712E-1,9.894854222706941E-1,9.851193012401567E-1,9.801044261390204E-1,9.744872085798427E-1,9.683140965897299E-1,9.616313141126271E-1,9.544846225129185E-1,9.469191044832108E-1,9.389789704571925E-1,9.307073873566782E-1,9.221463292613464E-1,9.133364493805411E-1,1.406736200649777E-1,1.3559898338239995E-1,1.3031476332634065E-1,1.2485726926331024E-1,1.1926320545459286E-1,1.1356907577977648E-1,1.0781063755862073E-1,1.0202242296314978E-1,9.623733824887784E-2,9.048634387031167E-2,8.479821293400978E-2,7.91993615347785E-2,7.371374223300428E-2,6.836279102118646E-2,6.31654182696238E-2,5.813803499086479E-2,3.439958166284323E-1,9.995645025492119E-1,9.982845659334812E-1,9.962013542607432E-1,9.933575265983594E-1,9.89796898854669E-1,9.855641205500468E-1,9.807043685376385E-1,9.752630593432108E-1,9.692855814168251E-1,9.628170482311769E-1,9.559020728263847E-1,9.485845640918077E-1,9.409075447943216E-1,9.32912991110788E-1,9.246416932009047E-1,1.4403263431872665E-1,1.3918312198590949E-1,1.3410118017352712E-1,1.2882234127817813E-1,1.2338280799909226E-1,1.1781884985162612E-1,1.1216624387968557E-1,1.0645977916045003E-1,1.0073283642191237E-1,9.501704683043805E-2,8.934202823805998E-2,8.373519309239089E-2,7.8221619748272E-2,7.282397785576075E-2,6.756249851864714E-2,6.2454980680768137E-2,5.751682638480566E-2,3.437067749455913E-1,9.99577181186074E-1,9.98335036249686E-1,9.963142570040474E-1,9.935568996741678E-1,9.901060605377963E-1,9.860055667071795E-1,9.812996839094343E-1,9.760328427505891E-1,9.702493845910031E-1,9.639933278222416E-1,9.5730815502101E-1,9.502366211670468E-1,9.428205828507382E-1,9.351008481637326E-1,1.4714212617942485E-1,1.4252824374686185E-1,1.3766050817652345E-1,1.3257352754179746E-1,1.273028457906586E-1,1.2188433403215167E-1,1.1635362105090508E-1,1.1074558365968913E-1,1.0509390924107759E-1,9.943073548857871E-2,9.378636645382743E-2,8.81890597553643E-2,8.266487717514515E-2,7.72375896562324E-2,7.192862761571549E-2,6.67570681643055E-2,6.173965195801753E-2,5.689082372705514E-2,3.434153590092914E-1,9.995897690087271E-1,9.983851326375266E-1,9.964262981027466E-1,9.937547113037475E-1,9.904127460128738E-1,9.864434083958097E-1,9.818900585280105E-1,9.767961502181429E-1,9.712049901112697E-1,9.65159516726677E-1,9.587020997907757E-1,9.518743599565707E-1,9.447170087592602E-1,1.5000161710755472E-1,1.4563219180806933E-1,1.40988956867059E-1,1.3610546389285183E-1,1.3101645479388885E-1,1.2575725066104906E-1,1.20363174877852E-1,1.1486903199932104E-1,1.0930865571711959E-1,1.0371453183189179E-1,9.811749613223503E-2,9.254650267947223E-2,8.702845521295298E-2,8.15880930367756E-2,7.624792253396191E-2,7.102818604721918E-2,6.594686094588366E-2,6.101968299134214E-2,5.626018940550196E-2,3.4312162489108716E-1,9.99602259507179E-1,9.984348292082402E-1,9.965374196291529E-1,9.939508590323058E-1,9.907167959322425E-1,9.868774170726591E-1,9.824751823483971E-1,9.775525778193042E-1,9.721518876434906E-1,9.663149854590117E-1,9.600831454679032E-1,9.53496873226613E-1,1.5261225523931798E-1,1.4849448543040147E-1,1.4408444531556708E-1,1.394145131178647E-1,1.3451849955001077E-1,1.294310369400578E-1,1.2418699759438669E-1,1.1882096378352064E-1,1.1336676356903788E-1,1.0785707925732159E-1,1.023231291448008E-1,9.67944186844172E-2,9.129855427453373E-2,8.586111138355486E-2,8.050554839727793E-2,7.525315808651266E-2,7.012304961962589E-2,6.513215530989552E-2,6.02952575721946E-2,5.5625032715897575E-2,3.4282560626827846E-1,9.996146462535273E-1,9.984841004054971E-1,9.966475644070846E-1,9.941452417378585E-1,9.910180530117882E-1,9.87307367119771E-1,9.830547492204369E-1,9.783017265718985E-1,9.730895728962679E-1,9.674591116890999E-1,9.614505386295489E-1,1.5497668610508178E-1,1.5111620252532726E-1,1.4694649759987027E-1,1.4249867429756014E-1,1.3780549715403623E-1,1.3290078410149073E-1,1.2781882259011607E-1,1.2259383314599427E-1,1.1725949541738225E-1,1.1184854431189693E-1,1.0639243762365408E-1,1.0092109189437252E-1,9.546268019049169E-2,9.004348386376522E-2,8.468778992942874E-2,7.941782612590449E-2,7.425372669435458E-2,6.921352315375785E-2,6.431315562366342E-2,5.95665014042508E-2,5.498541846683186E-2,3.4252731865446495E-1,9.99626922905936E-1,9.985329210213018E-1,9.967566760478291E-1,9.94337759695857E-1,9.913163621335931E-1,9.877330359955864E-1,9.836284571000179E-1,9.790432027228748E-1,9.740175479943693E-1,9.685912807215705E-1,1.5709891868920256E-1,1.534998556407225E-1,1.4957612992055974E-1,1.4535748209675456E-1,1.4087552959525088E-1,1.3616316349991556E-1,1.312539647751013E-1,1.2618166373080847E-1,1.2097965854864579E-1,1.1568060123811919E-1,1.1031605312355222E-1,1.0491620720051996E-1,9.950967151627514E-2,9.412330599462437E-2,8.878210458985862E-2,8.350911500583766E-2,7.832538913851454E-2,7.324995860956335E-2,6.82998310267396E-2,6.349000376876887E-2,5.883349304803101E-2,5.434137670667882E-2,3.422267639425859E-1,9.996390832125471E-1,9.985812662116356E-1,9.968646989855384E-1,9.945283146428466E-1,9.916115704471521E-1,9.88154204384108E-1,9.84196008257953E-1,9.797766180303382E-1,9.74935321849293E-1,1.5898418907572118E-1,1.5564926370504126E-1,1.5197573170052686E-1,1.4799189833940374E-1,1.4372814677919593E-1,1.3921634189488516E-1,1.344892487740231E-1,1.2957999028305947E-1,1.245215602222729E-1,1.1934640115511665E-1,1.1408604967835198E-1,1.087708470450992E-1,1.0342970975655455E-1,9.808995289218617E-2,9.277715831459472E-2,8.751508016068336E-2,8.23255809018E-2,7.722859243686674E-2,7.224209794155521E-2,6.738213136334091E-2,6.26627924196536E-2,5.809627567275559E-2,5.3692912713796226E-2,3.4192393490903017E-1,9.996511210153245E-1,9.986291115118302E-1,9.969715785120278E-1,9.947168098391006E-1,9.91903527469072E-1,9.885706563420169E-1,9.847571094863035E-1,9.805015900425904E-1,1.606388237079319E-1,1.575694216420191E-1,1.5414894283937186E-1,1.5040419807209376E-1,1.4636426244094664E-1,1.4205988811559275E-1,1.3752292709707595E-1,1.3278578892951073E-1,1.2788095051138357E-1,1.2284052775731556E-1,1.176959125062277E-1,1.1247747313770298E-1,1.0721431396018535E-1,1.0193408648443124E-1,9.666284496877507E-2,9.14249388250196E-2,8.624293529448017E-2,8.113756695721551E-2,7.612769988737463E-2,7.123031943866072E-2,6.646053162342505E-2,6.18315787798514E-2,5.735486869303401E-2,5.304001656933374E-2,3.416188194096732E-1,9.99663030253827E-1,9.9867643285166E-1,9.970772608109559E-1,9.949031501301854E-1,9.921920851811669E-1,9.889821794436098E-1,9.853114723019412E-1,1.6207010406349306E-1,1.592663697607706E-1,1.5610052910781103E-1,1.525978521576935E-1,1.4878604502409476E-1,1.4469467319056475E-1,1.4035459035591286E-1,1.3579739818006417E-1,1.3105495464890973E-1,1.261589414229514E-1,1.211404941578119E-1,1.160298947829277E-1,1.1085632123493473E-1,1.0564764809487234E-1,1.0043029076333491E-1,9.522908593922852E-2,9.006720193953299E-2,8.496607352324027E-2,7.994535712319653E-2,7.502290356479399E-2,7.021474634211107E-2,6.553510426814078E-2,6.09963978005613E-2,5.6609278586929705E-2,5.238267181433432E-2,3.4131140407970867E-1,9.996748049689095E-1,9.98723206570144E-1,9.971816929913597E-1,9.950872420074072E-1,9.924770981268698E-1,9.893885649234232E-1,1.6328613431661532E-1,1.6074706461049024E-1,1.5783625746892896E-1,1.5457740826253766E-1,1.509968054435558E-1,1.4712276589322393E-1,1.4298507148620263E-1,1.3861443260067977E-1,1.3404199679794296E-1,1.2929891359945386E-1,1.2441595990381002E-1,1.194232255282413E-1,1.1434985478736119E-1,1.0922383788476639E-1,1.0407184499453143E-1,9.891909597347734E-2,9.378925936891017E-2,8.870437548501023E-2,8.368479950203575E-2,7.874916182163659E-2,7.391434381549565E-2,6.919546791602005E-2,6.460590148706936E-2,6.015727416520502E-2,5.5859508406821065E-2,5.1720862865503495E-2,3.4100167742363147E-1,9.996864393063474E-1,9.987694094300472E-1,9.972848231205189E-1,9.952689936670941E-1,9.927584235058778E-1,1.6429571333010423E-1,1.6201925277059515E-1,1.5936277290792358E-1,1.5634837191118564E-1,1.5300088347916835E-1,1.493473255032534E-1,1.4541634580938845E-1,1.412376910028621E-1,1.3684171708405485E-1,1.3225895327683818E-1,1.275197241283239E-1,1.2265382983603193E-1,1.1769028111369628E-1,1.1265708268706882E-1,1.0758105853386202E-1,1.0248771198081084E-1,9.740111444821621E-2,9.234381770377013E-2,8.73367857087566E-2,8.239934332260829E-2,7.754914014791998E-2,7.280212857542477E-2,6.817255560296359E-2,6.367296826626978E-2,5.931423256955523E-2,5.510556569099279E-2,5.1054581017501814E-2,3.4068963224610493E-1,9.99697927520385E-1,9.988150186320703E-1,9.973866002561281E-1,9.954483150686656E-1,1.6510821209698537E-1,1.6309134883066922E-1,1.6068747814497006E-1,1.5791708908770724E-1,1.5480353436648855E-1,1.5137249341972478E-1,1.4765142862088376E-1,1.4366906086952716E-1,1.394548836234638E-1,1.350387272788588E-1,1.3045037943575818E-1,1.257192614490808E-1,1.208741579563547E-1,1.1594299377749946E-1,1.1095265153096924E-1,1.0592882324716205E-1,1.0089588989237523E-1,9.587682376138099E-2,9.089310990818783E-2,8.596468397093006E-2,8.110988477514348E-2,7.63454208932817E-2,7.168635086884122E-2,6.714607708975685E-2,6.273635335254128E-2,5.8467306045707865E-2,5.434746865304851E-2,5.038382898805671E-2,3.403752674268833E-1,9.99709263977202E-1,9.988600118287186E-1,9.974869744777514E-1,1.6573345753780397E-1,1.6397231860418715E-1,1.6181841740127031E-1,1.5929063166646626E-1,1.5641081696600212E-1,1.5320328508993464E-1,1.4969427183494488E-1,1.4591142059706558E-1,1.4188330115935122E-1,1.3763897599969246E-1,1.3320762009786952E-1,1.2861819505852276E-1,1.2389917460218522E-1,1.1907831611117536E-1,1.1418247179683612E-1,1.0923743293200396E-1,1.0426780118122418E-1,9.929688207987879E-2,9.434659691498666E-2,8.94374104500382E-2,8.458827297660977E-2,7.981657598558475E-2,7.513812129791379E-2,7.056710378467404E-2,6.611610787118341E-2,6.179611790836697E-2,5.761654226122862E-2,5.358525066312296E-2,4.9708624062977366E-2,3.400585890826967E-1,9.997204431582986E-1,9.989043671378409E-1,1.661816233583378E-1,1.6467156841882724E-1,1.6276416519003925E-1,1.6047668676224613E-1,1.578294847065291E-1,1.548454835422707E-1,1.515496610528632E-1,1.4796854098348522E-1,1.4412971778410313E-1,1.4006142609617206E-1,1.357921613676611E-1,1.313503528023436E-1,1.2676408603698838E-1,1.2206087051159824E-1,1.1726744531280128E-1,1.1240961709140794E-1,1.075121242016012E-1,1.0259852220214652E-1,9.76910870515814E-2,9.28107335219307E-2,8.797694740781328E-2,8.320773093442914E-2,7.851956133225356E-2,7.39273628505853E-2,6.944449255650854E-2,6.508274015730535E-2,6.085234184727047E-2,5.6762007868497645E-2,5.2818963138110124E-2,4.902899997131084E-2,3.3973961118665075E-1,9.997314596637957E-1,1.664631284855252E-1,1.651988411370026E-1,1.635337209150384E-1,1.6148345090285E-1,1.5906688031656466E-1,1.563055356362442E-1,1.5322311425471338E-1,1.4984498723697512E-1,1.4619773108212814E-1,1.4230870151649833E-1,1.3820565607299048E-1,1.339164270250062E-1,1.2946864239050085E-1,1.2488949023620453E-1,1.2020552026656728E-1,1.1544247644925042E-1,1.1062515493469885E-1,1.0577728249493104E-1,1.0092141188827555E-1,9.607883175192904E-2,9.126948968829904E-2,8.651192805433884E-2,8.182323254508181E-2,7.721899398225408E-2,7.271328380390724E-2,6.831864364701597E-2,6.40460891757461E-2,5.990512798821487E-2,5.590379108348423E-2,5.204867702908476E-2,4.8345007668273515E-2,3.394183557322981E-1],[],[2.3484847943024147E-3,2.5677980143997087E-4,4.536936299722191E-6,-1.5773719851328854E-5,1.0337959120253224E-4,3.3912345192464065E-4,6.830193883652697E-4,1.127621684055988E-3,2.2574661410169946E-3,3.294242172890316E-3,4.174535439072986E-3,4.887894866827515E-3,5.489523046211192E-3,6.067679229855007E-3,6.709071753652108E-3,7.482424672107779E-3,8.436341967620763E-3,9.60244248871972E-3,1.0998659745293404E-2,1.2631377639715217E-2,1.4496805376065031E-2,1.658242137938766E-2,1.8869149610478884E-2,2.1334508748381387E-2,2.395647686431518E-2,2.671741036268653E-2,2.9607196845643623E-2,3.262496573977787E-2,3.577905208094331E-2,3.908533906883537E-2,4.256442960985214E-2,4.623823544907833E-2,2.174264776801302E-3,2.3632352901462427E-4,2.4958779324966663E-6,-1.6070883953087953E-5,9.497731513193247E-5,3.14516245186737E-4,6.348413677366091E-4,1.0492068420398335E-3,2.1036962527136837E-3,3.0729269982837236E-3,3.897829921067466E-3,4.568624072499846E-3,5.13682486716846E-3,5.684968836446435E-3,6.294353638228048E-3,7.029664330213781E-3,7.936923132926956E-3,9.046362734653566E-3,1.03754600764142E-2,1.1930887800637318E-2,1.370976077167405E-2,1.5700957849477157E-2,1.788714593206904E-2,2.0247736797872107E-2,2.2762536986268483E-2,2.541546641127192E-2,2.8197566447684525E-2,3.1108650409059798E-2,3.415729875904884E-2,3.7359309202198515E-2,4.0735021955678984E-2,4.430607535861156E-2,2.015355347680294E-3,2.1777704450902678E-4,7.688545300900528E-7,-1.622828539940575E-5,8.73656228974442E-5,2.9201820412520286E-4,5.906868898026264E-4,9.772544518305212E-4,1.9623664653189467E-3,2.869293941588841E-3,3.642963266769472E-3,4.2742166828474565E-3,4.81118035033185E-3,5.331116335789574E-3,5.910321744489044E-3,6.609733796578897E-3,7.472962897658739E-3,8.528929097330034E-3,9.794654321633197E-3,1.1277047021535168E-2,1.2974032815034146E-2,1.487576526726736E-2,1.69665099168995E-2,1.9227422662546692E-2,2.1639999076661337E-2,2.4189604896183804E-2,2.6868347144436762E-2,2.9676666515313505E-2,3.2623360438641176E-2,3.572413297905179E-2,3.899906413061064E-2,4.246952237266092E-2,1.8703468931606708E-3,2.0095283546605198E-4,-6.870810706835746E-7,-1.6270588708797804E-5,8.046642680104603E-5,2.714409369903527E-4,5.502076993476526E-4,9.112142673048894E-4,1.8324415089125898E-3,2.681893872946673E-3,3.408172274213019E-3,4.0026980904634794E-3,4.510481071419058E-3,5.003920837107119E-3,5.554692148064247E-3,6.220254156635237E-3,7.041964252077073E-3,8.047500045593584E-3,9.253432203311339E-3,1.0666858101348622E-2,1.2286427891944703E-2,1.4103454433672957E-2,1.6103668580816435E-2,1.82698320246158E-2,2.058499938264624E-2,2.3035872110809433E-2,2.561554015217803E-2,2.8325018330370655E-2,3.117329405503809E-2,3.4175969841098434E-2,3.735286749343896E-2,4.072508855971655E-2,1.7379628202479106E-3,1.856823386644092E-4,-1.9093185532364094E-6,-1.6218875022141953E-5,7.420955195986903E-5,2.5261316724287407E-4,5.130859766114276E-4,8.505831392860814E-4,1.7129722047811808E-3,2.5093958652108147E-3,3.1918348736078767E-3,3.752248466533706E-3,4.232779897616611E-3,4.70134506808627E-3,5.225345169635484E-3,5.8590112301712075E-3,6.641595985797886E-3,7.599601585760336E-3,8.74915308998E-3,1.0097495418999625E-2,1.164392505051653E-2,1.338080832149278E-2,1.5295218355008846E-2,1.737139435416141E-2,1.95938289690471E-2,2.195045653753995E-2,2.443527242896827E-2,2.7049815577162812E-2,2.9803237938234337E-2,3.2711032948173874E-2,3.5792766009552696E-2,3.9069274256087125E-2,1.6170471929565036E-3,1.7181403234566996E-4,-2.9303824926003002E-6,-1.609112139277751E-5,6.853193887798714E-5,2.3537922289137576E-4,4.7903179480603586E-4,7.949012016089355E-4,1.603088793452309E-3,2.350578301468261E-3,2.9924598173828635E-3,3.521191825126336E-3,3.976280040754877E-3,4.421504806916282E-3,4.9203153975052845E-3,5.523946293147494E-3,6.2696841789668814E-3,7.182919596279229E-3,8.279339276279642E-3,9.566299298094053E-3,1.1043671628513878E-2,1.2704779175939089E-2,1.4537923893009695E-2,1.6528703666486972E-2,1.8662936668097364E-2,2.0929694219098002E-2,2.3323804675540138E-2,2.5847284241498104E-2,2.8509425587417456E-2,3.13256060366677E-2,3.4315136282998905E-2,3.749859132856143E-2,1.5065534591318583E-3,1.5921171457027676E-4,-3.7785422329314586E-6,-1.590262005972676E-5,6.337692368039492E-5,2.1959764894035168E-4,4.477807666324662E-4,7.437483249915901E-4,1.5019946926046808E-3,2.2043205212769553E-3,2.8086769558934963E-3,3.307985661704989E-3,3.7393246279420057E-3,4.162658744091949E-3,4.637782031527499E-3,5.213146996794503E-3,5.924203752166482E-3,6.795292067285195E-3,7.841668997247518E-3,9.070769917712003E-3,1.0482978220789302E-2,1.2072484732833323E-2,1.3828715759177983E-2,1.5738517914855296E-2,1.778893041325677E-2,1.997007226251345E-2,2.2277537222337513E-2,2.471377503314641E-2,2.7288196871841686E-2,3.001605749902114E-2,3.291641462545202E-2,3.600958331426141E-2,1.405534183631554E-3,1.4775295095893233E-4,-4.478348486580914E-6,-1.566634468796507E-5,5.869358906023269E-5,2.0513993482250168E-4,4.1909186991010306E-4,6.967408271041775E-4,1.4089606722535724E-3,2.069594995404473E-3,2.639228094225572E-3,3.1112111696218535E-3,3.5203868037376605E-3,3.923198799941905E-3,4.376059587649451E-3,4.924838537989619E-3,5.6032701453575876E-3,6.434701333246071E-3,7.433969284563699E-3,8.608560897556117E-3,9.959313136577908E-3,1.1481203725977378E-2,1.3164687191443217E-2,1.499775723142916E-2,1.6968577187938857E-2,1.906823072184579E-2,2.129301406071584E-2,2.364576976230688E-2,2.613600692798932E-2,2.8778851953605914E-2,3.159311142611204E-2,3.459884269161461E-2,1.3131317080897517E-3,1.3732767632429032E-4,-5.051104947121994E-6,-1.539326983170354E-5,5.443617950111262E-5,1.9188934890289702E-4,3.9274544223167566E-4,6.535284264567973E-4,1.323319432190492E-3,1.9454600147564346E-3,2.482958419858207E-3,2.9295640312822528E-3,3.3180603696437157E-3,3.7016409143864394E-3,4.13358899171314E-3,4.657375123104714E-3,5.305131183063126E-3,6.099266372446754E-3,7.0542087565046725E-3,8.177472668495007E-3,9.470296477902446E-3,1.0928370835602205E-2,1.2543090110689494E-2,1.4303501208400246E-2,1.619880179917023E-2,1.822096308548978E-2,2.0366925257149695E-2,2.2639885880045188E-2,2.504943300770401E-2,2.7610559561858587E-2,3.0341823077477733E-2,3.3263025531188595E-2,1.2285696620856583E-3,1.2783693589993585E-4,-5.515282359323268E-6,-1.509264920965293E-5,5.056357482887987E-5,1.7973987241455547E-4,3.6854133451822563E-4,6.137914272593722E-4,1.2444605648737654E-3,1.831052876025133E-3,2.3388084864494974E-3,2.7618457749317184E-3,3.1310509598100264E-3,3.4966163174563894E-3,3.908929082073651E-3,4.409231757243682E-3,5.028159171456157E-3,5.787235234153256E-3,6.700490419040229E-3,7.775445723805126E-3,9.013693953263124E-3,1.0411571211524136E-2,1.1961330529920171E-2,1.3652985391411212E-2,1.5476684666084312E-2,1.7425215573989173E-2,1.94961079700936E-2,2.1692879413316192E-2,2.4025179515785762E-2,2.6507863335653824E-2,2.9159241700873362E-2,3.199886376736126E-2,1.151145255180606E-3,1.1919175302170455E-4,-5.886881710528012E-6,-1.4772257773679974E-5,4.7038816619582685E-5,1.6859522549855397E-4,3.462972134441339E-4,5.772381221843568E-4,1.1718258857280955E-3,1.7255835442336466E-3,2.2058067355187924E-3,2.6069556834378005E-3,2.9581677462317234E-3,3.3068632824516187E-3,3.700748532874336E-3,4.17899638192544E-3,4.77084326291357E-3,5.496977642861899E-3,6.371044542674513E-3,7.400553832162206E-3,8.587410525152054E-3,9.928534687733989E-3,1.1416963498364394E-2,1.3043597138595566E-2,1.4799458793904168E-2,1.6678085434978833E-2,1.8677546270222407E-2,2.0801646507132846E-2,2.306008145882648E-2,2.5467564663022895E-2,2.8042162903041425E-2,3.08031753220386E-2,1.0802222839065997E-3,1.1131211120457104E-4,-6.179752497984128E-6,-1.4438602000211816E-5,4.382868243882969E-5,1.5836797836718856E-4,3.2584700290367577E-4,5.436023999464998E-4,1.10490511202929E-3,1.6283287706820217E-3,2.083062535182624E-3,2.4638832378664683E-3,2.79831566219582E-3,3.131219358139107E-3,3.507818203325749E-3,3.965362376683574E-3,4.531782114815915E-3,5.226977818975895E-3,6.064221668202771E-3,7.050997280603323E-3,8.189483975715957E-3,9.477129789627881E-3,1.0907687699019682E-2,1.2472870980965067E-2,1.4164506085846672E-2,1.5976818403367756E-2,1.7908369946383937E-2,1.996322376858205E-2,2.215110651018072E-2,2.4486587264868007E-2,2.6987491781539023E-2,2.967287230035409E-2,1.0152247923249408E-3,1.0412603958442357E-4,-6.405871381179307E-6,-1.4097102334718679E-5,4.0903303311564346E-5,1.4897874097260366E-4,3.0703945497501475E-4,5.126415447621037E-4,1.0432318711493865E-3,1.5386266437103025E-3,1.9697597132264807E-3,2.3317010759500716E-3,2.650488129177908E-3,2.9686140719427335E-3,3.329003912938929E-3,3.7671214336192985E-3,4.3096768618103645E-3,4.9758275464502864E-3,5.778485784445761E-3,6.725096204205914E-3,7.818078462054548E-3,9.05535762093803E-3,1.0431339802782928E-2,1.1938483603526293E-2,1.356935312826968E-2,1.531880547731046E-2,1.7185852461915944E-2,1.9174787589973874E-2,2.129535587921493E-2,2.3561979779634257E-2,2.5992247382456677E-2,2.860496746595992E-2,9.556313291821137E-4,9.756879165548494E-5,-6.575585943453176E-6,-1.3752251269403608E-5,3.8235820219283635E-5,1.4035542493936418E-4,2.897368411852841E-4,4.841342150300403E-4,9.863800188501897E-4,1.455871549086211E-3,1.865150560548147E-3,2.209558443582823E-3,2.513760269663381E-3,2.8180620925332607E-3,3.163259638233137E-3,3.583156808545154E-3,4.10332441428262E-3,4.742219510315312E-3,5.5124077121373955E-3,6.421284049040725E-3,7.471478121120862E-3,8.661345704608022E-3,9.985888668300925E-3,1.1438248551429775E-2,1.301166656845507E-2,1.4701579143990074E-2,1.650740820916382E-2,1.843365261162667E-2,2.0490064156582097E-2,2.269091715726001E-2,2.5053565799463603E-2,2.7596579190498E-2,9.009697489379409E-4,9.158210813103293E-5,-6.697827759363687E-6,-1.3407750129891714E-5,3.580207579343502E-5,1.3243257189866084E-4,2.738137552743034E-4,4.578785889593352E-4,9.339602484800939E-4,1.379509516616476E-3,1.7685502802881736E-3,2.0966751161489994E-3,2.387282586353416E-3,2.678656837466504E-3,3.009621122859108E-3,3.41243694787394E-3,3.91161109030522E-3,4.524940920412044E-3,5.264658720390964E-3,6.138101205956154E-3,7.148080773920512E-3,8.293341840324103E-3,9.569429463938274E-3,1.0970110751637818E-2,1.2489248189692052E-2,1.4122809173812626E-2,1.587058919417297E-2,1.773726946878452E-2,1.9732598291419857E-2,2.1870701028362936E-2,2.4168702088640755E-2,2.664493505845968E-2,8.508125080034032E-4,8.611355558856675E-5,-6.780298489107011E-6,-1.306662728422726E-5,3.3580337719681695E-5,1.2515074273970736E-4,2.5915601908075626E-4,4.3369066532755306E-4,8.856169723000344E-4,1.3090339296985146E-3,1.6793318576785454E-3,1.992335765685896E-3,2.270275086809559E-3,2.5495645094323776E-3,2.8671998902429744E-3,3.25400948673559E-3,3.733506583732703E-3,4.32286743206316E-3,5.034004395451471E-3,5.874188844866715E-3,6.8463917696058385E-3,7.949708031097642E-3,9.180177776773674E-3,1.053214092802768E-2,1.2000029774805653E-2,1.358029808732777E-2,1.5273081268697425E-2,1.70832219520271E-2,1.9020455841210406E-2,2.1098759199716457E-2,2.333503115921804E-2,2.5747374295159605E-2,8.047724113856782E-4,8.111593333144278E-5,-6.829632294189166E-6,-1.2731340163607083E-5,3.155105068826421E-5,1.1845596266497318E-4,2.456596836207175E-4,4.114027080709008E-4,8.410254566934999E-4,1.2439815749085781E-3,1.5969213257126579E-3,1.895884749520778E-3,2.1620218316939204E-3,2.430018543171085E-3,2.7351776456613613E-3,3.1069956108472135E-3,3.568058267304106E-3,4.13495736964997E-3,4.81929877566792E-3,5.6282829723477935E-3,6.565018002051932E-3,7.628914522128219E-3,8.816463763230729E-3,1.0122529976470833E-2,1.154206783694207E-2,1.307197638604556E-2,1.4712700012892965E-2,1.6469223696344074E-2,1.8351262620667677E-2,2.0372644412770476E-2,2.255004778636212E-2,2.490134917218935E-2,7.624987685854264E-4,7.654674161012862E-5,-6.851537486794242E-6,-1.2403863195674847E-5,2.9696614021518467E-5,1.1229921729694287E-4,2.3323011788527754E-4,3.9086182396113836E-4,7.998891936671331E-4,1.183929009307894E-3,1.5207934020995178E-3,1.8067212960184954E-3,2.0618658842939852E-3,2.319314444094528E-3,2.6128010530196335E-3,2.9705847723213315E-3,3.4143858264956894E-3,3.9602462550872245E-3,4.619478761695812E-3,5.399208729401174E-3,6.302662124494705E-3,7.329533987076532E-3,8.476726386768068E-3,9.73958335620902E-3,1.1113538285242421E-2,1.25958976263002E-2,1.4187386359360094E-2,1.5893114500840758E-2,1.7722769862507867E-2,1.9690032488371832E-2,2.181136587871047E-2,2.4104425531651635E-2,7.236739210207129E-4,7.236770500008017E-5,-6.850919983477008E-6,-1.2085763494359584E-5,2.8001182381877902E-5,1.0663599543249241E-4,2.2178117834276945E-4,3.7192866320319255E-4,7.619374917883602E-4,1.1284892238931038E-3,1.4504674735523345E-3,1.7242950633662411E-3,1.9692046389046536E-3,2.216804999046246E-3,2.4993768704368313E-3,2.844029747798769E-3,3.271676217358332E-3,3.797841639891691E-3,4.433558806779298E-3,5.185874941161037E-3,6.058116981726247E-3,7.050235889768565E-3,8.159507779914114E-3,9.381715544707998E-3,1.0712731082960896E-2,1.2150233404395536E-2,1.3695202037565845E-2,1.5352856368831106E-2,1.713285099035138E-2,1.9048719968021023E-2,2.1116717120515292E-2,2.3354282557845402E-2,6.880101064623658E-4,6.854434533241255E-5,-6.831990829395535E-6,-1.1778265922579426E-5,2.6450487213702663E-5,1.0142587437427743E-4,2.1123445258617617E-4,3.544762333770541E-4,7.269232705090873E-4,1.0773085824804566E-3,1.3855039042256735E-3,1.6481020478453091E-3,1.8834855058120728E-3,2.121895839369715E-3,2.3942674279744712E-3,2.7266420259529915E-3,3.1391789395947317E-3,3.646918236847406E-3,4.260625888483461E-3,4.987268925973818E-3,5.83026027409525E-3,6.789781043152674E-3,7.863447760769776E-3,9.047444595052993E-3,1.0338044946555592E-2,1.1733268311401202E-2,1.3234324907072714E-2,1.4846529346863492E-2,1.6579498092320302E-2,1.844662135000585E-2,2.0463949096128177E-2,2.26487119129876E-2,6.552466289592313E-4,6.504559912168961E-5,-6.79835978836747E-6,-1.1482308942435739E-5,2.5031676800727032E-5,9.663214408597158E-5,2.0151857101190706E-4,3.383888177392784E-4,6.946210426667236E-4,1.0300640162608148E-3,1.3255006460120998E-3,1.5776808187442175E-3,1.804201931027085E-3,2.034041336474555E-3,2.2968864304142717E-3,2.617787510469825E-3,3.016201614611756E-3,3.5067133451075917E-3,4.099834760369705E-3,4.802451567630998E-3,5.618049463068593E-3,6.547016381962195E-3,7.587278527828449E-3,8.735386827780895E-3,9.987982126240788E-3,1.1343394907110942E-2,1.2803044238404705E-2,1.4372327230986932E-2,1.6060818173138338E-2,1.788176600760765E-2,1.985102299316639E-2,2.1985616342086126E-2,6.251473055136203E-4,6.184347493516102E-5,-6.753116753410096E-6,-1.1198592489204458E-5,2.373317302981704E-5,9.22214667182958E-5,1.925685808488218E-4,3.235609894845486E-4,6.648250708170973E-4,9.864604552658014E-4,1.2700901294016517E-3,1.512609057911176E-3,1.7308897295013352E-3,1.952740810337482E-3,2.2066950678383403E-3,2.5168825239960165E-3,2.902105857157641E-3,3.376522560868949E-3,3.950403479763922E-3,4.630552651484742E-3,5.4205169242994445E-3,6.3208699609187975E-3,7.329819551514036E-3,8.444251682748578E-3,9.661143301366243E-3,1.097910875476302E-2,1.239975599173915E-2,1.3928553199269793E-2,1.5575029252687904E-2,1.7352294866278362E-2,1.927601097009067E-2,2.1363007841282526E-2,5.97498163344368E-4,5.8912746603060254E-5,-6.698902518952322E-6,-1.0927618948488398E-5,2.254454314189974E-5,8.816356833566778E-5,1.8432537727288206E-4,3.098967141404953E-4,6.373476839231044E-4,9.462284790217329E-4,1.2189364146645313E-3,1.4525003828880243E-3,1.6631237112858634E-3,1.8775350318065375E-3,2.1231984168415164E-3,2.4233900982211253E-3,2.7963034283648882E-3,3.255695764450533E-3,3.8116092058857846E-3,4.470766462661217E-3,5.236765350945589E-3,6.110346186373433E-3,7.089972676128735E-3,8.172836751147347E-3,9.35622261771882E-3,1.063900355109568E-2,1.202295813587467E-2,1.3513615421197537E-2,1.5120456370019807E-2,1.6856456907243876E-2,1.8737093264093937E-2,2.0779005473889348E-2,5.721053639556025E-4,5.623067858322004E-5,-6.637970267102616E-6,-1.0669728177182847E-5,2.1456384923680233E-5,8.443095993832397E-5,1.767351867413673E-4,2.9730853282425833E-4,6.12017741786051E-4,9.091221697163607E-4,1.1717325842141967E-3,1.397001433582743E-3,1.6005145809227749E-3,1.80800300015134E-3,2.0459421154683556E-3,2.3368165351598654E-3,2.6982526575157523E-3,3.143633373647016E-3,3.682784261135054E-3,4.322347642546186E-3,5.0659634073158665E-3,5.914521285950917E-3,6.866717441869409E-3,7.920023003014308E-3,9.072002888354197E-3,1.0321766380107164E-2,1.1671246043033389E-2,1.3126022687038984E-2,1.4695527543693254E-2,1.6392605556363626E-2,1.823255510615528E-2,2.023183290897191E-2,5.487933324232083E-4,5.377678016863816E-5,-6.5722389533851625E-6,-1.0425127387532048E-5,2.0460223950918794E-5,8.099868512262552E-5,1.697490980592819E-4,2.8571681962378495E-4,5.886792354540229E-4,8.749171522500925E-4,1.1281983581219416E-3,1.345789203496338E-3,1.5427060912672937E-3,1.7437589779859411E-3,1.974509295378486E-3,2.2567082247969463E-3,2.607455119583008E-3,3.039782852557112E-3,3.5633124472060876E-3,4.184607298086224E-3,4.907341630739067E-3,5.732539017974568E-3,6.659106633141525E-3,7.684770221495938E-3,8.807350974793135E-3,1.0026173113440636E-2,1.1343307988953359E-2,1.276438009354826E-2,1.4298769732020242E-2,1.5959195009250016E-2,1.7760783501831537E-2,1.971981574866797E-2,5.274030723281258E-4,5.1532585566651754E-5,-6.503339629993077E-6,-1.019391660661995E-5,1.9548421635929946E-5,7.784409195289E-5,1.633226370491771E-4,2.7504910687763275E-4,5.671900126657163E-4,8.434088065745332E-4,1.0880779158694187E-3,1.2985685976022456E-3,1.4893724338936596E-3,1.6844497664564961E-3,1.9085177552700568E-3,2.1826487045057854E-3,2.52345255553305E-3,2.9436354646664637E-3,3.452625606879819E-3,4.056909357178755E-3,4.760188577779759E-3,5.563606620139084E-3,6.466262056510728E-3,7.466112651622582E-3,8.561213361294224E-3,9.751083975563936E-3,1.1037920782350573E-2,1.2427384816388934E-2,1.392880483024427E-2,1.55547765365824E-2,1.7320263928820388E-2,1.924137870249497E-2,5.077906486166856E-4,4.948145718584619E-5,-6.432655614650836E-6,-9.976110330103434E-6,1.8714092960877522E-5,7.494662683225969E-5,1.5741538103318148E-4,2.652394726130888E-4,5.474206181834911E-4,8.144106387279167E-4,1.051137908528168E-3,1.2550702000637425E-3,1.4402158492238205E-3,1.629752204407006E-3,1.8476173602065427E-3,2.114255946026253E-3,2.4458240224768868E-3,2.854723258751204E-3,3.3502004217771013E-3,3.93866716246298E-3,4.623847209525294E-3,5.40699099501378E-3,6.287370549225497E-3,7.263154868390394E-3,8.332611931377522E-3,9.495439287788976E-3,1.0753945543124935E-2,1.2113821994390981E-2,1.3584345735852562E-2,1.5177994807201119E-2,1.6909576995499234E-2,1.8795042659633814E-2,4.898258223638283E-4,4.760840974484306E-5,-6.361357298837637E-6,-9.77165590714064E-6,1.7951032894481574E-5,7.22876483585289E-5,1.5199060965279733E-4,2.5622798486198497E-4,5.292532396320344E-4,7.877527979518429E-4,1.0171656466339257E-3,1.2150482360544282E-3,1.3949644405153133E-3,1.5793708760955137E-3,1.7914876521718578E-3,2.051179856256485E-3,2.3741832609859258E-3,2.772616276128299E-3,3.255555436009968E-3,3.829340295128479E-3,4.497711509583667E-3,5.26201512844442E-3,6.121680217259641E-3,7.075067866464288E-3,8.12063995276593E-3,9.258255401628314E-3,1.0490323644587596E-2,1.1822560746111141E-2,1.326419250805119E-2,1.4827584260889043E-2,1.6527395098488506E-2,1.8379421703586276E-2,4.733908229659891E-4,4.5899953067935785E-5,-6.29043228842507E-6,-9.580449121857083E-6,1.725365059476735E-5,6.985025933407774E-5,1.4701498884839507E-4,2.479601980068498E-4,5.125807501861307E-4,7.632807282110643E-4,9.859674500711695E-4,1.1782787130067483E-3,1.3533701768407252E-3,1.533036012911083E-3,1.7398356579037592E-3,1.993099978659012E-3,2.3081762672273374E-3,2.6969199678821974E-3,3.1682482955031465E-3,3.7284316198917104E-3,4.381223327622565E-3,5.128054735730552E-3,5.968496900215548E-3,6.901085371755054E-3,7.924458274372376E-3,9.038620828950678E-3,1.024607283144479E-2,1.1552550335113878E-2,1.2967228642877566E-2,1.4502365557698505E-2,1.617247911176986E-2,1.7993220107638114E-2,4.583792447071534E-4,4.43439516587622E-5,-6.220711481388074E-6,-9.402347374231386E-6,1.6616910595090198E-5,6.761915526802469E-5,1.42458285096637E-4,2.4038669671679825E-4,4.97305840140961E-4,7.40853943334704E-4,9.573671472929573E-4,1.1445577276461651E-3,1.315207071174297E-3,1.4905015754271046E-3,1.692393880809807E-3,1.939723382679594E-3,2.247479057994888E-3,2.6272728109158782E-3,3.0878731927466733E-3,3.635484542014596E-3,4.273869440705835E-3,5.004535129546135E-3,5.8271808591479225E-3,6.740500373437656E-3,7.743291736843341E-3,8.835692573826107E-3,1.0020283522231594E-2,1.130281649687236E-2,1.2692417481425057E-2,1.4201242126213973E-2,1.5843675134957342E-2,1.7635229344194932E-2,4.446950559342734E-4,4.292949934724476E-5,-6.1528916095592335E-6,-9.237180808812372E-6,1.6036280255877625E-5,6.558048786432494E-5,1.3829310726091903E-4,2.3346268341336345E-4,4.83340230050441E-4,7.203449158502448E-4,9.312047121691174E-4,1.1136999261667122E-3,1.2802695206635037E-3,1.4515435030069436E-3,1.6489184645395146E-3,1.8907827292147642E-3,2.1917956171973118E-3,2.563344111987376E-3,3.0140585068543025E-3,3.550080467126498E-3,4.175178824310139E-3,4.890928302902928E-3,5.697143682370066E-3,6.592661873621111E-3,7.576425796421425E-3,8.648692668787893E-3,9.81211530229789E-3,1.1072457937152577E-2,1.243879876517018E-2,1.3923196829204745E-2,1.5539911323946427E-2,1.7304325136245427E-2,4.322517102567703E-4,4.1646807488646655E-5,-6.0875547032093125E-6,-9.084761692232604E-6,1.550768284129464E-5,6.372174213239225E-5,1.3449467364863045E-4,2.2714760556186617E-4,4.706039587333928E-4,7.016380703902113E-4,9.073350276790402E-4,1.0855371058636942E-3,1.2483707970978597E-3,1.4159581190454434E-3,1.6091875165601109E-3,1.846034500825965E-3,2.140856012898465E-3,2.5048319892785414E-3,2.9464646290193845E-3,3.471836454632365E-3,4.084720124700832E-3,4.7867502199957935E-3,5.5778454035558325E-3,6.456971850807951E-3,7.423203360469164E-3,8.476904916447028E-3,9.620793611255937E-3,1.0860643009142886E-2,1.220548534937278E-2,1.3667288761674862E-2,1.5260194823290753E-2,1.6999464574921682E-2],[5.012654115505024E-2,5.4243971328787284E-2,5.859763754274426E-2,6.318561190366777E-2,6.7996278633665E-2,7.300854463084992E-2,7.819283020154098E-2,8.351270317178906E-2,8.892696421551709E-2,9.439194752960282E-2,9.986378121424384E-2,1.0530036533119111E-1,1.1066287454375838E-1,1.1591666926246567E-1,1.2103158982357941E-1,1.259816950487955E-1,1.3074457436920628E-1,1.353004022096563E-1,1.3963091237289044E-1,1.437184527863306E-1,1.4754524503620026E-1,1.5109292763518356E-1,1.5434241508291605E-1,1.5727406261306398E-1,1.5986809293710358E-1,1.6210521815098378E-1,1.6396737759327587E-1,1.654385100816593E-1,1.6650528512740514E-1,1.671577304687153E-1,1.6738971031975444E-1,1.6719922775682777E-1,4.809212086776749E-2,5.210790702752216E-2,5.636099969093568E-2,6.085028364061799E-2,6.556530027257519E-2,7.048640870501352E-2,7.558569991332977E-2,8.082853685482312E-2,8.61755389159455E-2,9.15847852290506E-2,9.701399049562175E-2,1.0242241831700574E-1,1.0777234284552112E-1,1.1302994310791406E-1,1.1816560174254345E-1,1.2315366432470462E-1,1.2797178206374327E-1,1.326000001530753E-1,1.370197640844846E-1,1.4121300048597762E-1,1.4516139496191358E-1,1.4884594567705625E-1,1.5224682592395122E-1,1.5534354765450767E-1,1.58115384784885E-1,1.6054199191185184E-1,1.6260414133505405E-1,1.6428449833082517E-1,1.6556836010627224E-1,1.6644429591677723E-1,1.669046422865707E-1,1.669458258425627E-1,4.6155022934670206E-2,5.007042346143187E-2,5.422371535665796E-2,5.861455397039492E-2,6.323358505128271E-2,6.806256058779188E-2,7.307518137541948E-2,7.823854837899615E-2,8.351505113728709E-2,8.886447770475468E-2,9.424610872945666E-2,9.962056755827223E-2,1.0495124113384079E-1,1.102051566606146E-1,1.1535328329681775E-1,1.2037031021423104E-1,1.2523401772878534E-1,1.2992439761648875E-1,1.3442268964983195E-1,1.3871048716251255E-1,1.4276903214290557E-1,1.4657877830334E-1,1.5011925642716584E-1,1.5336923594468704E-1,1.563071439513659E-1,1.5891167971955625E-1,1.611625496862547E-1,1.630412444027375E-1,1.6453178375717217E-1,1.6562136816997905E-1,1.6630088932771805E-1,1.6656527213507563E-1,4.431200843704725E-2,4.812857879204078E-2,5.218318782182896E-2,5.647621934335013E-2,6.09993704316017E-2,6.573572590721458E-2,7.066053411823704E-2,7.57425745757424E-2,8.094595504564425E-2,8.623213207894719E-2,9.15619262196852E-2,9.689731051758155E-2,1.0220279108072759E-1,1.0744626544286044E-1,1.1259932579550831E-1,1.1763705391845439E-1,1.2253741874031882E-1,1.2728042672416107E-1,1.3184718699401068E-1,1.3621904032006676E-1,1.4037687046310424E-1,1.443006759501289E-1,1.4796943753534453E-1,1.5136127715408335E-1,1.544538718922594E-1,1.572250633730395E-1,1.596535896073441E-1,1.617198623482461E-1,1.634067171884559E-1,1.6470007438499765E-1,1.6558946368126665E-1,1.6606838405329863E-1,4.25597893840817E-2,4.6279342018541454E-2,5.0236688654248254E-2,5.4432899824488054E-2,5.8860671108440156E-2,6.350435991715755E-2,6.834069902671053E-2,7.334008532761106E-2,7.84682902115203E-2,8.368839461402727E-2,8.896272826857189E-2,9.425459836667525E-2,9.952963032936145E-2,1.0475660740963767E-1,1.0990777422565633E-1,1.1495864685646545E-1,1.1988743496048239E-1,1.2467422043652249E-1,1.293000495848637E-1,1.3374608426544315E-1,1.3799292854192216E-1,1.420202084374521E-1,1.4580644090459674E-1,1.493291895636116E-1,1.5256547294571632E-1,1.5549236792768015E-1,1.580877374389444E-1,1.6033100704263167E-1,1.622039185961868E-1,1.6369119932124135E-1,1.6478109933055773E-1,1.6546576786080747E-1,4.089505522773724E-2,4.451962272716513E-2,4.838139062912408E-2,5.2482075074323994E-2,5.6815317880879325E-2,6.136668902839489E-2,6.611434223672956E-2,7.10302294704214E-2,7.608172909462523E-2,8.123349929820263E-2,8.644934432971754E-2,9.169388513089717E-2,9.693386102232564E-2,1.0213895023280058E-1,1.0728207265614322E-1,1.1233921355593979E-1,1.17288868495847E-1,1.2211124858136706E-1,1.2678739817574833E-1,1.3129836704280184E-1,1.3562455139061483E-1,1.3974528093319807E-1,1.4363868882398984E-1,1.472818636557534E-1,1.506512513829564E-1,1.5372325206923543E-1,1.564749425413111E-1,1.5888485111259817E-1,1.609337135804343E-1,1.6260514922673286E-1,1.6388620971570098E-1,1.647677705306621E-1,3.931449612296589E-2,4.28462974854742E-2,4.66143972304416E-2,5.0621116883895506E-2,5.4860993095216186E-2,5.932074897685185E-2,6.397989578500053E-2,6.881187761876864E-2,7.378562167761374E-2,7.886731386200486E-2,8.402219492968949E-2,8.921617499395396E-2,9.441709693259356E-2,9.959553767680346E-2,1.0472510926282173E-1,1.0978229472907086E-1,1.1474591423243374E-1,1.1959635527265396E-1,1.243147145579825E-1,1.2888199000286107E-1,1.3327843532196307E-1,1.3748315377440468E-1,1.4147396857318875E-1,1.4522757069246514E-1,1.4871991395446346E-1,1.5192680444457815E-1,1.548246172972724E-1,1.5739106857264207E-1,1.5960597245080518E-1,1.614519229227064E-1,1.629148527797164E-1,1.639844390051611E-1,3.781482317217515E-2,4.125623310052275E-2,4.4932768926101936E-2,4.884731842778166E-2,5.299526278876072E-2,5.736441971795728E-2,6.19355950567113E-2,6.668366191061194E-2,7.15790371921285E-2,7.658938311365109E-2,8.168133618857339E-2,8.682206753419261E-2,9.198050890890427E-2,9.712813471855829E-2,1.0223926056988956E-1,1.0729089007381339E-1,1.1226220063587461E-1,1.1713379715817208E-1,1.2188687672242379E-1,1.2650243937029904E-1,1.3096065544804042E-1,1.352404654592243E-1,1.3931945051789116E-1,1.4317397557450542E-1,1.4677957722989685E-1,1.501115452596365E-1,1.5314563281011156E-1,1.5585882453199887E-1,1.5823009392050164E-1,1.6024108953228736E-1,1.618767028481121E-1,1.6312548640951052E-1,3.639278589205563E-2,3.97463069638022E-2,4.333354641989129E-2,4.715792041360892E-2,5.121560568353436E-2,5.549545716222714E-2,5.997951310759155E-2,6.464401270473746E-2,6.946080292428967E-2,7.439896953040098E-2,7.942650182390155E-2,8.451180072219122E-2,8.962486840953018E-2,9.473807112935818E-2,9.982643457003915E-2,1.0486750040915299E-1,1.0984083037409603E-1,1.1472728200551864E-1,1.1950819489594353E-1,1.2416461923648174E-1,1.2867669516034486E-1,1.3302325817740585E-1,1.371817092914868E-1,1.4112815331864897E-1,1.4483777906405948E-1,1.4828543248085865E-1,1.514463196448549E-1,1.5429677034094236E-1,1.568149945860056E-1,1.589817722863985E-1,1.6078102881848413E-1,1.622002647462091E-1,3.504518713689123E-2,3.831342470610913E-2,4.181377108817672E-2,4.55501343163045E-2,4.951943919403165E-2,5.3711521887653935E-2,5.810959196296297E-2,6.269119229646969E-2,6.742954012384193E-2,7.229509108543117E-2,7.725714256978257E-2,8.228529156141205E-2,8.735058895441597E-2,9.242628329619508E-2,9.748811244797115E-2,1.0251416881703025E-1,1.0748442038482689E-1,1.1238000720084391E-1,1.1718244798268068E-1,1.2187288546692715E-1,1.264314770460199E-1,1.308370053028383E-1,1.3506674746236783E-1,1.390966085347099E-1,1.4290149356034662E-1,1.464558720084218E-1,1.4973447298553402E-1,1.5271304356099116E-1,1.5536910359652073E-1,1.5768263783804123E-1,1.5963667812541438E-1,1.6121774357632715E-1,3.3768895705938044E-2,3.695453538261599E-2,4.037050281041765E-2,4.402116289096672E-2,4.7904142623532195E-2,5.2010204979775924E-2,5.632367101679696E-2,6.0823325742664226E-2,6.548369707206221E-2,7.027655632576814E-2,7.517246298398657E-2,8.014217429917482E-2,8.515776537538672E-2,9.019335411316953E-2,9.522538868831219E-2,1.0023252052237921E-1,1.0519514107068542E-1,1.1009469779606709E-1,1.1491292000119731E-1,1.1963108007320943E-1,1.242293947523867E-1,1.2868664032745553E-1,1.3298002113848073E-1,1.37085297331977E-1,1.4097714894549698E-1,1.4462973122584052E-1,1.480173616107695E-1,1.5111527216606302E-1,1.5390036193201412E-1,1.5635189052262635E-1,1.5845206594405262E-1,1.6018649418336778E-1,3.256085685393638E-2,3.566664440304196E-2,3.9000835400751346E-2,4.256821816028872E-2,4.636707772973771E-2,5.038905116108115E-2,5.461951266929278E-2,5.9038428907349144E-2,6.362157938877729E-2,6.834199674693701E-2,7.317145565062545E-2,7.808183617466581E-2,8.304621078778147E-2,8.803955082120021E-2,9.303900939980143E-2,9.802380129631774E-2,1.0297475436029478E-1,1.0787364379738132E-1,1.1270243616638351E-1,1.1744256565661916E-1,1.2207434536863616E-1,1.2657658677066108E-1,1.3092646701293792E-1,1.3509965113348657E-1,1.3907064781411047E-1,1.4281335537029977E-1,1.4630174012402627E-1,1.4951058240940332E-1,1.5241622572969094E-1,1.5499727101578675E-1,1.5723516910194568E-1,1.5911467871373505E-1,3.141810091376726E-2,3.444682441445589E-2,3.770190984358949E-2,4.118853707156687E-2,4.490560684334263E-2,4.884557937825244E-2,5.299482535261224E-2,5.733443385496246E-2,6.184137767897588E-2,6.648989653474083E-2,7.125293281537726E-2,7.610345070440841E-2,8.101549124481093E-2,8.596486071604864E-2,9.092940873292071E-2,9.588891421587775E-2,1.008246504246882E-1,1.0571873644054974E-1,1.1055339831889041E-1,1.1531025958529662E-1,1.1996976194773094E-1,1.2451078865162993E-1,1.2891053040597383E-1,1.3314460192549948E-1,1.3718738924705184E-1,1.41012586209719E-1,1.4459386391195145E-1,1.4790560982286874E-1,1.509236731246579E-1,1.5362605885970484E-1,1.5599352418151957E-1,1.5801004379362513E-1,3.03377502291251E-2,3.329222433533867E-2,3.647092552986786E-2,3.987939501497233E-2,4.3517108723074224E-2,4.737730101927516E-2,5.144728410174611E-2,5.5709211729517844E-2,6.014119263509599E-2,6.47186197644548E-2,6.941555551437888E-2,7.42060085340539E-2,7.90649580684453E-2,8.396902468108053E-2,8.889674330812872E-2,9.382845465681208E-2,9.874588288418948E-2,1.0363150324663659E-1,1.0846781945465549E-1,1.1323666761743109E-1,1.1791864584280691E-1,1.2249274116280526E-1,1.2693619390848765E-1,1.3122460851780554E-1,1.3533229235372723E-1,1.3923278255533053E-1,1.4289950634319626E-1,1.4630651284976182E-1,1.4942921410019644E-1,1.5224507835319007E-1,1.5473422931393274E-1,1.568799181341998E-1,2.9317024583197848E-2,3.220007672950375E-2,3.5305149682746034E-2,3.863811738944854E-2,4.21989923282576E-2,4.598173593307999E-2,4.997454883156183E-2,5.416059326575196E-2,5.851905772261812E-2,6.302643516323359E-2,6.765786027745559E-2,7.238834590890872E-2,7.719377787816255E-2,8.205156853248605E-2,8.694092460672138E-2,9.184274343419573E-2,9.673920238201732E-2,1.016131416953927E-1,1.064473571526692E-1,1.1122391673013805E-1,1.1592359858030737E-1,1.2052552123113681E-1,1.2500700628029124E-1,1.2934368343737687E-1,1.3350982083345075E-1,1.3747884218147702E-1,1.4122397776012618E-1,1.447189886488889E-1,1.4793890287541647E-1,1.5086070732844217E-1,1.5346394918763046E-1,1.5573121365402107E-1,2.835324529704114E-2,3.1167703697659192E-2,3.420192515255566E-2,3.7462089395724034E-2,4.094870868553176E-2,4.465642642270755E-2,4.8574280482399174E-2,5.26863870828725E-2,5.697295958461528E-2,6.141153855318321E-2,6.597828350172769E-2,7.064917083476886E-2,7.540096036177861E-2,8.021183219126003E-2,8.506164930644679E-2,8.993185803890212E-2,9.480508843726143E-2,9.966455139255707E-2,1.044933457404424E-1,1.092737869567715E-1,1.1398685303650874E-1,1.1861181769879725E-1,1.2312611130158858E-1,1.275054201228617E-1,1.3172400819511448E-1,1.3575522476673074E-1,1.395721458560144E-1,1.4314829064490028E-1,1.4645835239213217E-1,1.4947888836767678E-1,1.521889228208116E-1,1.5457042966883763E-1,2.7443838158862564E-2,3.019252145310932E-2,3.315867675098059E-2,3.634876422788386E-2,3.9763761020362845E-2,4.339894937934487E-2,4.724415519557444E-2,5.1284395913408005E-2,5.5500856305899675E-2,5.9872073100794065E-2,6.437518360330828E-2,6.898708701579569E-2,7.368538385129617E-2,7.84489967184432E-2,8.325842756960271E-2,8.809566194690976E-2,9.294377952177493E-2,9.778636464200663E-2,1.026068270737219E-1,1.0738774207454752E-1,1.1211030372485692E-1,1.1675396089702633E-1,1.2129627631875105E-1,1.2571302013013114E-1,1.299784833166432E-1,1.340659755117192E-1,1.3794845707005005E-1,1.4159924743761756E-1,1.4499275049778457E-1,1.4810514204460118E-1,1.5091497367523357E-1,1.5340365972299558E-1,2.6586335333007638E-2,2.927204373656675E-2,3.2172916284100184E-2,3.52956698260474E-2,3.864171331682573E-2,4.2206926719421424E-2,4.5981876677256E-2,4.995243091926814E-2,5.4100693679756603E-2,5.840614750375774E-2,6.284686106322841E-2,6.74006156678249E-2,7.204581878163274E-2,7.676210926836262E-2,8.153060931284335E-2,8.633383200305009E-2,9.11553013331906E-2,9.597897536413633E-2,1.0078857983999862E-1,1.055669590195699E-1,1.102955360385954E-1,1.149539514252691E-1,1.1951992026500745E-1,1.2396932009913204E-1,1.2827649606582567E-1,1.3241474912869072E-1,1.3635695867116338E-1,1.4007628272023515E-1,1.435468774564442E-1,1.4674458180844985E-1,1.4964752171853943E-1,1.5223660066308947E-1,2.5778376385238066E-2,2.8403884213510217E-2,3.1242246433299536E-2,3.430041434322161E-2,3.758019746107482E-2,4.107803428057346E-2,4.478518690473607E-2,4.868832424488471E-2,5.277041962043481E-2,5.701185224896564E-2,6.139157648930544E-2,6.588821531401244E-2,7.048094912165319E-2,7.515010602925483E-2,7.987740850565572E-2,8.464588390156884E-2,8.943949325996953E-2,9.424256632833634E-2,9.903914732439444E-2,1.0381235593773111E-1,1.085438543265585E-1,1.1321348798284983E-1,1.1779914097302069E-1,1.2227681826958157E-1,1.2662094274184177E-1,1.3080483393557465E-1,1.3480132123891025E-1,1.3858343589254926E-1,1.4212512445472614E-1,1.454019301611986E-1,1.4839159707282007E-1,1.5107456358224183E-1,2.5017708549046246E-2,2.75857579861312E-2,3.0364363622328663E-2,3.336069046959673E-2,3.6576919115261314E-2,4.0010009325017255E-2,4.365187532348812E-2,4.748993995353467E-2,5.1507996862894416E-2,5.568727407615083E-2,6.0007566818832105E-2,6.444829967553159E-2,6.89893918755136E-2,7.361183323208674E-2,7.829792555878856E-2,8.303119580308832E-2,8.779603305441865E-2,9.257713469018086E-2,9.735886360183794E-2,1.0212461880761639E-1,1.0685630870981551E-1,1.115339941320664E-1,1.1613574162950863E-1,1.2063770036736324E-1,1.2501439113189408E-1,1.2923917582274347E-1,1.3328486128504638E-1,1.371243830902631E-1,1.407315128034239E-1,1.4408153581113795E-1,1.4715185491792027E-1,1.49922486291953E-1,2.4302186346378936E-2,2.6815482340812675E-2,2.9537059998174842E-2,3.247427874760472E-2,3.562966245961162E-2,3.900065679095815E-2,4.2579786676845366E-2,4.6355183487978416E-2,5.031141408816114E-2,5.4430508780492694E-2,5.8693059788035074E-2,6.307925377350132E-2,6.756971475829256E-2,7.214606631699362E-2,7.679116787519823E-2,8.14890301415369E-2,8.622445974629073E-2,9.0982515843237E-2,9.574787814125435E-2,1.0050422659576262E-1,1.0523372057320497E-1,1.0991664389989936E-1,1.1453125625202369E-1,1.1905386471481746E-1,1.2345910500973463E-1,1.2772040189373504E-1,1.3181056379276634E-1,1.3570245838465447E-1,1.3936971356837483E-1,1.42787391517794E-1,1.459325913484234E-1,1.4878494700717163E-1,2.3629770665304594E-2,2.6090976841381338E-2,2.8758224643002046E-2,3.1639050001145634E-2,3.473629393116072E-2,3.8047854424329335E-2,4.1566827602916155E-2,4.528200979066435E-2,4.91786956082904E-2,5.3239672484910835E-2,5.744628679359882E-2,6.1779448359771776E-2,6.622045215361895E-2,7.075152735284214E-2,7.53560686446441E-2,8.001855368570356E-2,8.472419484319842E-2,8.945840561153308E-2,9.420617882605013E-2,9.895147492547957E-2,1.0367670668888052E-1,1.0836238615059718E-1,1.1298697409486955E-1,1.1752694644650169E-1,1.2195706793247861E-1,1.2625084361171166E-1,1.3038110448166643E-1,1.3432067493818048E-1,1.3804306739521785E-1,1.4152315237379468E-1,1.447377599130074E-1,1.4766617895873668E-1,2.2998527386932616E-2,2.5410262868140104E-2,2.8025844124341837E-2,3.0852966992641805E-2,3.389476507837639E-2,3.7149556914606E-2,4.061097212568745E-2,4.426843021217187E-2,4.810790973966764E-2,5.211291150900052E-2,5.626549426946185E-2,6.05472527939732E-2,6.494011946277542E-2,6.942690080937776E-2,7.399150396925518E-2,7.861885592858883E-2,8.329456187494733E-2,8.800438082196406E-2,9.273361341075774E-2,9.746649825829944E-2,1.0218570194897701E-1,1.0687196768340665E-1,1.1150396291495933E-1,1.1605834073743747E-1,1.2051000621891035E-1,1.248325593113507E-1,1.2899887163522464E-1,1.3298174593084008E-1,1.3675460432211103E-1,1.402921542985073E-1,1.435709885935279E-1,1.46570085675108E-1,2.2406625644294565E-2,2.477146269299865E-2,2.7338002481059318E-2,3.011408541209391E-2,3.310311464178274E-2,3.6303799149804326E-2,3.971026615933681E-2,4.3312518329520634E-2,4.7097175987402005E-2,5.1048410956842434E-2,5.514895369883037E-2,5.9381046482600085E-2,6.372722595493052E-2,6.817084778347668E-2,7.269630841150027E-2,7.728896588395817E-2,8.193480434732271E-2,8.661991830654653E-2,9.132990944654137E-2,9.604929060212629E-2,1.0076098070161717E-1,1.054459550288147E-1,1.1008309104936825E-1,1.146492249734896E-1,1.1911941101660503E-1,1.234673559612148E-1,1.2766598735392862E-1,1.3168810509914614E-1,1.3550706340191077E-1,1.39097432545817E-1,1.4243559700853792E-1,1.455002567021545E-1,2.1852335786959193E-2,2.4172798171895337E-2,2.6692880733429184E-2,2.9420554293191216E-2,3.235946996176051E-2,3.550869869722015E-2,3.8862831136731744E-2,4.241241478862951E-2,4.6144671157098235E-2,5.004440214052744E-2,5.409497037718434E-2,5.827922899312995E-2,6.258028622691988E-2,6.698201878152932E-2,7.146928905832248E-2,7.602786737375977E-2,8.064410217711157E-2,8.530441239274893E-2,8.999469271864907E-2,9.469972477260327E-2,9.940267669893406E-2,1.0408475493306686E-1,1.0872504827457401E-1,1.1330057981345842E-1,1.177865593866415E-1,1.2215681008444833E-1,1.2638432812110068E-1,1.304419267543662E-1,1.3430291198075195E-1,1.3794174005419368E-1,1.4133461365179248E-1,1.4445998355535625E-1,2.1334027116873547E-2,2.3612589127177702E-2,2.6088755996982356E-2,2.8770615942815103E-2,3.166204780608159E-2,3.476245760805548E-2,3.8066866865070124E-2,4.1566331277717444E-2,4.524863450350424E-2,4.909916895029287E-2,5.3101891037157796E-2,5.724022895248479E-2,6.1497830378684636E-2,6.585906515913868E-2,7.030923819598903E-2,7.483451289260215E-2,7.942158668451069E-2,8.405719094636575E-2,8.872750424706866E-2,9.341757024430956E-2,9.81108016778145E-2,1.0278863353461935E-1,1.0743036543306199E-1,1.1201320910984583E-1,1.16512534353626E-1,1.2090228776599374E-1,1.251555445900347E-1,1.2924514516925334E-1,1.3314436450331474E-1,1.3682756549109104E-1,1.4027079300045475E-1,1.4345227572297828E-1,2.085016545329746E-2,2.3089251484689315E-2,2.5524000271648986E-2,2.8162605462023475E-2,3.100915470147393E-2,3.406336363593983E-2,3.732065370371479E-2,4.077255373092326E-2,4.4407372018555206E-2,4.8211053275908E-2,5.216811044075723E-2,5.6262511834746946E-2,6.0478413007221926E-2,6.480064931739885E-2,6.921494468971418E-2,7.37078361365422E-2,7.826635422177117E-2,8.287753003583473E-2,8.752781590784854E-2,9.220250963642572E-2,9.688526260387956E-2,1.0155773424779295E-1,1.0619943282631195E-1,1.1078775867025306E-1,1.1529824388530241E-1,1.1970496369249517E-1,1.2398108052029692E-1,1.2809947324284887E-1,1.320334007363296E-1,1.3575715086566761E-1,1.3924663235015852E-1,1.4247987656144748E-1,2.039931057771299E-2,2.2601295222989478E-2,2.499707897014181E-2,2.7594949928836567E-2,3.0399186845657296E-2,3.340979095150819E-2,3.66225541515709E-2,4.002944485399045E-2,4.3619259954307044E-2,4.737845957745148E-2,5.1292077038602744E-2,5.534458673809175E-2,5.9520621117964745E-2,6.380545375218928E-2,6.818520416056195E-2,7.264676328325385E-2,7.717747851822104E-2,8.176466728974693E-2,8.639504473701623E-2,9.105415388363237E-2,9.572587761704401E-2,1.0039209437839891E-1,1.0503251738435788E-1,1.0962473385414148E-1,1.141444387803337E-1,1.185658391867951E-1,1.2286219080811776E-1,1.2700642037115606E-1,1.309717833210734E-1,1.347325086038639E-1,1.3826438825472034E-1,1.4154527894520877E-1,1.99801136032211E-2,2.2147322185406854E-2,2.4506549242492768E-2,2.7066167305883782E-2,2.983062966887493E-2,3.280020042772863E-2,3.597101392392683E-2,3.9335446056582235E-2,4.288274766925876E-2,4.6599858697062395E-2,5.047229778984661E-2,5.448501224558282E-2,5.8623081048003255E-2,6.28721890493954E-2,6.72188280496808E-2,7.16502231094077E-2,7.615402182188447E-2,8.071781402077717E-2,8.532856598198914E-2,8.997205614749919E-2,9.46323907230643E-2,9.929166050374842E-2,1.039297786313119E-1,1.0852451601044366E-1,1.1305172945505812E-1,1.1748575921259054E-1,1.2179995857073508E-1,1.2596730946762488E-1,1.2996107458283715E-1,1.3375543799796086E-1,1.373260924671455E-1,1.4065074055273108E-1,1.959131430716036E-2,2.1726023799471875E-2,2.4051058147173673E-2,2.6574865129214267E-2,2.9302057106985423E-2,3.2233139563581606E-2,3.5364562591552726E-2,3.868907886874916E-2,4.219635987969781E-2,4.5873790996666906E-2,4.970734223029467E-2,5.368240145888307E-2,5.778446449066942E-2,6.1999600914879056E-2,6.631465165678921E-2,7.071715602900609E-2,7.519504491699214E-2,7.973616618958511E-2,8.432772496701343E-2,8.895572452666661E-2,9.360448527994303E-2,9.825630265539573E-2,1.0289128347366021E-1,1.0748737777037849E-1,1.1202060163035982E-1,1.1646542833647247E-1,1.2079531125755298E-1,1.2498329309158747E-1,1.2900265254061694E-1,1.3282754095902208E-1,1.3643356729563272E-1,1.3979829868807112E-1,1.9231738460461483E-2,2.1336178742672286E-2,2.3629340713280784E-2,2.6119739028320144E-2,2.881213064168181E-2,3.1707242107018946E-2,3.4801813848088746E-2,3.808894591228879E-2,4.155869839101505E-2,4.519886890020773E-2,4.8995845870082384E-2,5.2935426288209485E-2,5.7003493705831056E-2,6.118647632353197E-2,6.547154123612325E-2,6.984652213362606E-2,7.429961609488121E-2,7.881891428155717E-2,8.339184783968738E-2,8.8004633625886E-2,9.2641796331163E-2,9.728582734741019E-2,1.0191701984396535E-1,1.065134972170274E-1,1.110514309283206E-1,1.1550542564448384E-1,1.1984903577212627E-1,1.2405536865514852E-1,1.2809772607375952E-1,1.3195023701507252E-1,1.355884403036478E-1,1.3898978455347788E-1,1.8900295182555704E-2,2.0976650588390412E-2,2.3240217932822813E-2,2.569957112166421E-2,2.835959815736974E-2,3.122122743188431E-2,3.428146546534535E-2,3.7533731491266036E-2,4.096844337748269E-2,4.4573778912563214E-2,4.833651299614079E-2,5.224282107607313E-2,5.6278945994896384E-2,6.0431648866953624E-2,6.468840022894273E-2,6.903730831216767E-2,7.346681915333224E-2,7.796525216777007E-2,8.25202512651842E-2,8.711823504469096E-2,9.174392183960084E-2,9.637998949609698E-2,1.0100690923699106E-1,1.0560297095891205E-1,1.1014449639530718E-1,1.1460621861854715E-1,1.1896179259844764E-1,1.2318439268966498E-1,1.2724734921402833E-1,1.311247775106337E-1,1.3479215829679628E-1,1.3822683690302115E-1],[1.6658854342852036E-1,1.6556411938493357E-1,1.6413640988167938E-1,1.6231952974963476E-1,1.6013083518161686E-1,1.5759045197129054E-1,1.5472078314955598E-1,1.51546022621779E-1,1.4809169488025317E-1,1.4438423410993056E-1,1.404506097790301E-1,1.3631800061887245E-1,1.3201351501109224E-1,1.2756395326336648E-1,1.229956059532219E-1,1.1833408223577876E-1,1.1360416247768855E-1,1.0882967052238686E-1,1.0403336206316534E-1,9.923682679808013E-2,9.446040311622078E-2,8.97231049247188E-2,8.504256082591649E-2,8.043496618983752E-2,7.591504876401176E-2,7.149604836452629E-2,6.718971095246264E-2,6.300629707307104E-2,5.895460427151135E-2,5.5042002740732524E-2,5.1274483136034596E-2,4.765671522855563E-2,1.6656850475791193E-1,1.657775363085372E-1,1.6458179116152047E-1,1.6299384392494684E-1,1.610295739989199E-1,1.5870771123091154E-1,1.5604935805751644E-1,1.530775147023338E-1,1.4981662764382164E-1,1.462921749218615E-1,1.4253029567878706E-1,1.385574661496843E-1,1.3440022040347094E-1,1.300849115533129E-1,1.2563750780116503E-1,1.2108341734933828E-1,1.1644733664041422E-1,1.1175311730551227E-1,1.070236483619779E-1,1.0228075140109084E-1,9.75450875929594E-2,9.283607621221111E-2,8.817182500630596E-2,8.356907308084388E-2,7.90431470858446E-2,7.460793139610106E-2,7.027585273985308E-2,6.605787939798986E-2,6.196353472156699E-2,5.800092434177436E-2,5.417677610682849E-2,5.049649149739567E-2,1.664136377596193E-1,1.6584929403046222E-1,1.6487957260119743E-1,1.63515541351729E-1,1.6177162524494113E-1,1.5966516958244256E-1,1.5721597704230242E-1,1.5444584499479905E-1,1.5137812340968737E-1,1.480373071381093E-1,1.4444867023817634E-1,1.406379448447403E-1,1.366310431494772E-1,1.3245381843355175E-1,1.2813185969312668E-1,1.2369031402037467E-1,1.1915373129463903E-1,1.1454592663327666E-1,1.0988985720244805E-1,1.0520751118923914E-1,1.0051980783379318E-1,9.584650831293282E-2,9.120613790335683E-2,8.661592022231034E-2,8.209172446691856E-2,7.764802649091289E-2,7.329788432097811E-2,6.90529283791536E-2,6.492336629396507E-2,6.0918001795383286E-2,5.704426683165493E-2,5.330826574376705E-2,1.6613448720104335E-1,1.657895898551475E-1,1.6503953313242678E-1,1.6389391637064116E-1,1.623657378273996E-1,1.604709756068026E-1,1.582281398662711E-1,1.5565782268986667E-1,1.5278226600468606E-1,1.496249615038904E-1,1.462102904894001E-1,1.425632063967466E-1,1.3870895881456732E-1,1.346728551512308E-1,1.3048005465457857E-1,1.2615538906988888E-1,1.2172320457815236E-1,1.1720722052830587E-1,1.1263040161740516E-1,1.0801484137501571E-1,1.0338165591571706E-1,9.87508878324708E-2,9.414142075870767E-2,8.957090551444354E-2,8.505569888953217E-2,8.061081604415586E-2,7.624989727389893E-2,7.198518954863847E-2,6.782754284286747E-2,6.378642087501649E-2,5.9869925500235774E-2,5.6084833680440066E-2,1.6574145604513213E-1,1.6560855015775194E-1,1.6507145242076515E-1,1.641383357745742E-1,1.6282080416290315E-1,1.611334910983685E-1,1.590936272037951E-1,1.5672060297367882E-1,1.540355471620383E-1,1.510609349091126E-1,1.478202337363075E-1,1.4433759041118932E-1,1.4063755772372358E-1,1.367448575233146E-1,1.3268417487863854E-1,1.2847997776061246E-1,1.2415635697207278E-1,1.197368818965633E-1,1.1524446876840033E-1,1.1070125936928243E-1,1.0612850917417249E-1,1.0154648489378722E-1,9.697437203455223E-2,9.243019350233274E-2,8.793074042915473E-2,8.349151633965995E-2,7.91266955461812E-2,7.484909632229708E-2,7.06701690067417E-2,6.659999877838946E-2,6.26473224551719E-2,5.8819558331980736E-2,1.6524475186264603E-1,1.65316171797853E-1,1.649850477873538E-1,1.642581717896243E-1,1.6314578980435793E-1,1.6166121795330188E-1,1.5982042542339908E-1,1.5764161034633062E-1,1.5514478902000103E-1,1.5235141270413058E-1,1.492840203098411E-1,1.4596593020275597E-1,1.4242097037260498E-1,1.3867324350312407E-1,1.3474692195079785E-1,1.3066606714083767E-1,1.2645446817962072E-1,1.2213549530940017E-1,1.1773196495018583E-1,1.1326601427722041E-1,1.0875898440921167E-1,1.042313122225207E-1,9.970243149825662E-2,9.519068453292813E-2,9.071324551184556E-2,8.628605689342289E-2,8.192377983066973E-2,7.763975931758695E-2,7.344600434515537E-2,6.93531829307294E-2,6.537063148340722E-2,6.1506377613996625E-2,1.6465434062308074E-1,1.6492227081930327E-1,1.6478991824950598E-1,1.642627419352591E-1,1.6334966963912675E-1,1.620627312557511E-1,1.6041665713565192E-1,1.5842846722062298E-1,1.5611707136823055E-1,1.5350289519042196E-1,1.506075398924085E-1,1.4745347952871504E-1,1.440637951249219E-1,1.404619423707986E-1,1.3667154803068712E-1,1.3271622968058816E-1,1.2861943364110084E-1,1.244042867802044E-1,1.2009345896822468E-1,1.1570903417079097E-1,1.1127238930112716E-1,1.068040809080055E-1,1.0232374048546969E-1,9.784997963248977E-2,9.340030647535301E-2,8.899105472669176E-2,8.463732654030529E-2,8.035294998392489E-2,7.61504515453971E-2,7.204104365848044E-2,6.803462682104017E-2,6.413980550962439E-2,1.6397990748941288E-1,1.6443643813269768E-1,1.6449549545203757E-1,1.6416125561426387E-1,1.6344137058936087E-1,1.6234661857539093E-1,1.6089051760248385E-1,1.5908892797810403E-1,1.5695966389851537E-1,1.5452212861979725E-1,1.517969818182966E-1,1.488058427356292E-1,1.455710287368333E-1,1.421153261474451E-1,1.3846178864372127E-1,1.3463355789973355E-1,1.306537014248811E-1,1.2654506330891488E-1,1.2233012468913576E-1,1.1803087195738234E-1,1.1366867186820455E-1,1.0926415367904184E-1,1.0483709918078674E-1,1.0040634193748155E-1,9.598967725501067E-2,9.160378437254814E-2,8.726416216378101E-2,8.298507930067692E-2,7.877953942340442E-2,7.46592614236803E-2,7.06346745244641E-2,6.671492745636678E-2,1.6323082419989082E-1,1.6386800182551742E-1,1.6411100120094768E-1,1.639627672143708E-1,1.6342972066963943E-1,1.6252142540660502E-1,1.612502170144569E-1,1.5963081856525688E-1,1.5767996361828487E-1,1.5541604093450076E-1,1.5285876965397693E-1,1.5002890869157773E-1,1.4694800014500708E-1,1.4363814372966535E-1,1.4012179763439678E-1,1.3642160058953612E-1,1.325602101398717E-1,1.2856015287790984E-1,1.2444368347947359E-1,1.202326505857275E-1,1.1594836872715412E-1,1.116114964682989E-1,1.0724192169715153E-1,1.0285865546157781E-1,9.847973597306743E-2,9.412214438530098E-2,8.980173375715092E-2,8.553317227920516E-2,8.132990143251778E-2,7.720410930601378E-2,7.316671886496477E-2,6.922739056775286E-2,1.624161225901824E-1,1.632259957060995E-1,1.6364541126336185E-1,1.6367613544753232E-1,1.6332340419332775E-1,1.6259560660881126E-1,1.615039285653167E-1,1.6006198162995278E-1,1.5828543749786095E-1,1.561916823892678E-1,1.537995002679694E-1,1.5112878877994346E-1,1.482003078578702E-1,1.4503545814394034E-1,1.4165608473665434E-1,1.380843011344617E-1,1.3434232842286176E-1,1.3045234549398893E-1,1.2643634716348598E-1,1.2231600825009341E-1,1.1811255284194379E-1,1.1384662897014372E-1,1.0953818967227988E-1,1.0520638192512609E-1,1.0086944516053639E-1,9.654462107951291E-2,9.224807629112701E-2,8.799483897714253E-2,8.379875037259386E-2,7.967243140558644E-2,7.562726439700486E-2,7.167338931412641E-2,1.6154447379009818E-1,1.6251913365986437E-1,1.6310742506160877E-1,1.6330998860863E-1,1.6313092286725098E-1,1.6257748364842586E-1,1.61659742187597E-1,1.603902271267467E-1,1.58783570345692E-1,1.56856171115259E-1,1.5462588751519854E-1,1.5211175914328695E-1,1.4933376120015848E-1,1.4631258722991042E-1,1.43069456126041E-1,1.3962593835105044E-1,1.3600379646547284E-1,1.3222483578473515E-1,1.283107620469621E-1,1.242830441737463E-1,1.2016278137089674E-1,1.1597057482551582E-1,1.1172640503435301E-1,1.0744951631286165E-1,1.031583102859861E-1,9.88702501768715E-2,9.460177753153709E-2,9.036824269726226E-2,8.618384996263975E-2,8.206161781663157E-2,7.801335433392628E-2,7.404964727679442E-2,1.6062417261942363E-1,1.617557893785777E-1,1.6250544086365148E-1,1.6287269540204555E-1,1.6286056247340658E-1,1.624752073949889E-1,1.617256237584114E-1,1.6062328825889644E-1,1.591818178395489E-1,1.574166436147338E-1,1.55344710585559E-1,1.5298420728726703E-1,1.5035432557963507E-1,1.4747504797848188E-1,1.4436695823430495E-1,1.410510701762044E-1,1.375486699614941E-1,1.338811675746941E-1,1.300699544732715E-1,1.2613626547423673E-1,1.2210104414654335E-1,1.1798481199569653E-1,1.1380754252159077E-1,1.095885417626102E-1,1.0534633720752608E-1,1.0109857698623287E-1,9.686194108295017E-2,9.265206600149023E-2,8.84834839040985E-2,8.43695767921535E-2,8.032254584057413E-2,7.635339557126632E-2,1.5966312670594604E-1,1.6094398101455284E-1,1.6184753605583296E-1,1.623723409608687E-1,1.6252036480562723E-1,1.6229672618623134E-1,1.6170937954022263E-1,1.607687825744607E-1,1.594875645855665E-1,1.578802101140304E-1,1.5596276700062447E-1,1.5375258308488324E-1,1.5126807187202645E-1,1.485285046753883E-1,1.4555382502985548E-1,1.423644804590086E-1,1.389812667767263E-1,1.3542518078851098E-1,1.3171727830035762E-1,1.278785355371966E-1,1.2392971324904604E-1,1.1989122381591036E-1,1.1578300247257098E-1,1.1162438432360401E-1,1.0743398910419848E-1,1.0322961568644876E-1,9.902814817444454E-2,9.484547512444218E-2,9.069642302081898E-2,8.659470468360471E-2,8.255288282156943E-2,7.858234850990528E-2,1.586688498542299E-1,1.600913603104317E-1,1.611414520757661E-1,1.618167076685415E-1,1.621181045073078E-1,1.620497588484331E-1,1.6161862558658846E-1,1.6083417799296143E-1,1.5970808703033196E-1,1.5825391465059152E-1,1.5648683018583534E-1,1.5442335416052472E-1,1.520811299557795E-1,1.4947872093336068E-1,1.466354288977693E-1,1.4357112903866687E-1,1.4030611657084363E-1,1.3686096095503614E-1,1.3325636461446633E-1,1.29513024253186E-1,1.2565149406314707E-1,1.216920511506061E-1,1.1765456433746556E-1,1.1355836805913264E-1,1.0942214338225494E-1,1.0526380822444503E-1,1.0110041871320785E-1,9.694808332174074E-2,9.282189101695763E-2,8.873585419940326E-2,8.47028667483987E-2,8.07346770433827E-2,1.5764845920500167E-1,1.5920520576039565E-1,1.6039458358215278E-1,1.6121326038534067E-1,1.6166127044258116E-1,1.617417723383944E-1,1.6146076181667987E-1,1.608267635069664E-1,1.5985052101357214E-1,1.5854469972674495E-1,1.5692361149762846E-1,1.5500296558104393E-1,1.5279964637207555E-1,1.5033151563655023E-1,1.4761723519062367E-1,1.446761052265254E-1,1.415279135344832E-1,1.3819279151904204E-1,1.3469107392851268E-1,1.310431604042409E-1,1.2726937814130693E-1,1.2338984600613427E-1,1.1942434129574239E-1,1.1539217090566721E-1,1.1131204899165438E-1,1.0720198328366094E-1,1.0307917207745707E-1,9.895991363756344E-2,9.485952934690965E-2,9.07923014828347E-2,8.67714260291786E-2,8.280898048522271E-2,1.5660867574099122E-1,1.5829241936925192E-1,1.5961397144327888E-1,1.605691356812574E-1,1.6115705122659119E-1,1.613799636607504E-1,1.6124295044400155E-1,1.6075362427893128E-1,1.5992183371943033E-1,1.5875937532828455E-1,1.5727972654541156E-1,1.5549780373699348E-1,1.5342974603738926E-1,1.510927227690229E-1,1.4850476046650046E-1,1.4568458475252608E-1,1.4265147234503683E-1,1.394251091058448E-1,1.3602545105053523E-1,1.3247258642376986E-1,1.2878659813261245E-1,1.2498742689384167E-1,1.2109473630414298E-1,1.171277816401548E-1,1.1310528452943566E-1,1.0904531572141869E-1,1.0496518806603346E-1,1.00881361524517E-1,9.680936164303927E-2,9.276371246477524E-2,8.875788438330522E-2,8.480425698557617E-2,1.5555582771482587E-1,1.573595265908118E-1,1.5880629913586727E-1,1.5989113468157548E-1,1.6061232453991375E-1,1.6097124570830942E-1,1.609720984332383E-1,1.606216208367612E-1,1.599287997622702E-1,1.5890459207873928E-1,1.5756166561635326E-1,1.5591416426074603E-1,1.539774978952822E-1,1.5176815505480346E-1,1.4930353438276406E-1,1.4660179018579544E-1,1.4368168739146464E-1,1.4056246182896126E-1,1.3726368275099635E-1,1.3380511569568732E-1,1.302065849787017E-1,1.2648783617813056E-1,1.2266839984050815E-1,1.1876745824970542E-1,1.148037174502321E-1,1.1079528681884067E-1,1.0675956836896075E-1,1.0271315769796373E-1,9.867175809841308E-2,9.46501089007493E-2,9.066192864011512E-2,8.671987318036985E-2,1.5449585659713766E-1,1.5641267904541786E-1,1.579778921600138E-1,1.591857191407883E-1,1.6003364985666715E-1,1.6052223667265814E-1,1.6065484365373722E-1,1.6043737206113629E-1,1.5987798112755036E-1,1.5898681828003455E-1,1.577757679861217E-1,1.5625822379894566E-1,1.5444888436069465E-1,1.523635712996583E-1,1.5001906517344088E-1,1.4743295479514895E-1,1.446234952718128E-1,1.4160947068194377E-1,1.3841005830680245E-1,1.3504469250630463E-1,1.3153292752449675E-1,1.2789429958996706E-1,1.24148189554805E-1,1.203136879438182E-1,1.1640946465069099E-1,1.124536456344189E-1,1.0846369887192839E-1,1.0445633155720986E-1,1.0044740015384789E-1,9.645183445606004E-2,9.248357633721782E-2,8.855553340094643E-2,1.5343432516763927E-1,1.5545765963755742E-1,1.5713472009313287E-1,1.5845901037363758E-1,1.594272642246809E-1,1.600392526766228E-1,1.6029754439786914E-1,1.60207241652768E-1,1.597757106788463E-1,1.590123205762234E-1,1.5792819988023077E-1,1.5653601543399645E-1,1.548497743832032E-1,1.5288464729416365E-1,1.5065680860383265E-1,1.481832897778375E-1,1.4548184052676094E-1,1.42570794012673E-1,1.3946893295485674E-1,1.3619535471564911E-1,1.3276933464333354E-1,1.2921018803706674E-1,1.255371319887686E-1,1.2176914899910145E-1,1.179248546444748E-1,1.1402237170261081E-1,1.100792130587549E-1,1.061121754580579E-1,1.0213724579205707E-1,9.816952115776736E-2,9.422314345102048E-2,9.031124878825793E-2,1.523764273978623E-1,1.5449988971743586E-1,1.5628240092553197E-1,1.5771679068815156E-1,1.5879908074839183E-1,1.5952830328846968E-1,1.599062719367113E-1,1.5993732776771008E-1,1.596280789377834E-1,1.5898714796840352E-1,1.5802493583790625E-1,1.5675340753245662E-1,1.5518589993490398E-1,1.533369501130886E-1,1.5122214026794512E-1,1.4885795475358476E-1,1.4626164453824023E-1,1.4345109504137277E-1,1.4044469424860284E-1,1.3726119917350701E-1,1.3391959993294303E-1,1.3043898179755545E-1,1.2683838648016155E-1,1.231366745803917E-1,1.1935239149812073E-1,1.1550363927251077E-1,1.1160795672982156E-1,1.0768221007582998E-1,1.0374249569710765E-1,9.980405648885621E-2,9.588121254990199E-2,9.198730661511727E-2,1.513269998008793E-1,1.5354443795460626E-1,1.5542620734164797E-1,1.5696450698392964E-1,1.5815468944019048E-1,1.5899508958927544E-1,1.5948680579332952E-1,1.5963345551288918E-1,1.5944092384379788E-1,1.5891711890516322E-1,1.580717432227186E-1,1.569160857866853E-1,1.55462835713341E-1,1.5372591562721308E-1,1.5172033107196267E-1,1.494620313953203E-1,1.4696777749351422E-1,1.4425501235223853E-1,1.413417312771306E-1,1.382463498693762E-1,1.3498756900081607E-1,1.315842371443458E-1,1.2805521132683312E-1,1.2441921864036079E-1,1.2069472065561782E-1,1.1689978323881789E-1,1.1305195421161125E-1,1.0916815105528174E-1,1.0526456049524217E-1,1.0135655135851386E-1,9.745860161999667E-2,9.358424008071418E-2,1.5029053395017455E-1,1.5259603061660107E-1,1.5457107463355987E-1,1.562072761989107E-1,1.5749936012307425E-1,1.58445004478977E-1,1.5904463142476077E-1,1.593011720014452E-1,1.592198232045498E-1,1.5880781117324144E-1,1.580741696209376E-1,1.570295382092126E-1,1.556859818394557E-1,1.5405682902985451E-1,1.5215652572982258E-1,1.5000050004769422E-1,1.4760503329181135E-1,1.4498713326246288E-1,1.421644066777991E-1,1.3915492877462043E-1,1.3597710932447468E-1,1.3264955541272908E-1,1.2919093224951253E-1,1.256198239622963E-1,1.2195459674115669E-1,1.1821326687831918E-1,1.1441337619309079E-1,1.10571877104324E-1,1.0670502925371231E-1,1.0282830914338431E-1,9.89563337751048E-2,9.510279880393666E-2,1.49271189896422E-1,1.5165906297055073E-1,1.5372160995658532E-1,1.5544989230892176E-1,1.5683804708615903E-1,1.578831349226223E-1,1.5858494001699877E-1,1.5894574367763253E-1,1.589700895548568E-1,1.5866455431688833E-1,1.580375328690987E-1,1.5709904283653314E-1,1.5586054932447754E-1,1.5433480817103973E-1,1.525357240844516E-1,1.5047821916891566E-1,1.4817810725213795E-1,1.4565196995125648E-1,1.4291703134953587E-1,1.3999102930898014E-1,1.3689208264397132E-1,1.336385544935753E-1,1.30248913160542E-1,1.2674159237754198E-1,1.2313485339524619E-1,1.19446651469907E-1,1.1569450928882453E-1,1.1189539965224053E-1,1.080656393778875E-1,1.0422079595832816E-1,1.003756080261771E-1,9.654392020642527E-2,1.4827281023689345E-1,1.5073761155062776E-1,1.5288210266013985E-1,1.546968346059529E-1,1.5617539521420606E-1,1.5731426585578223E-1,1.5811263011223683E-1,1.585721556334154E-1,1.5869676715160627E-1,1.5849242432111296E-1,1.579669134560003E-1,1.5712965789971176E-1,1.5599154807734494E-1,1.5456478948693608E-1,1.5286276505991256E-1,1.508999074202335E-1,1.4869157646689027E-1,1.462539382147781E-1,1.4360384175483462E-1,1.4075869234207508E-1,1.3773631982021306E-1,1.3455484270887136E-1,1.312325292183095E-1,1.2778765716019258E-1,1.2423837516912441E-1,1.2060256784483402E-1,1.1689772739655337E-1,1.1314083416025189E-1,1.0934824801364301E-1,1.0553561228177913E-1,1.0171777125234699E-1,9.790870194302198E-2,1.472989346173142E-1,1.498354470583895E-1,1.5205653545023037E-1,1.5395227700290182E-1,1.555157473325488E-1,1.567428854864031E-1,1.576323108039183E-1,1.581851126528891E-1,1.5840463084369358E-1,1.5829624030306522E-1,1.5786714905073712E-1,1.5712621422288678E-1,1.5608377722513994E-1,1.5475151631024547E-1,1.531423130450629E-1,1.5127012822001765E-1,1.4914988263586526E-1,1.467973387003147E-1,1.4422897968340448E-1,1.4146188462320697E-1,1.3851359807326652E-1,1.354019950048439E-1,1.3214514212388964E-1,1.2876115757670906E-1,1.2526807147607474E-1,1.2168368988634533E-1,1.1802546488836939E-1,1.1431037314289647E-1,1.1055480503203996E-1,1.0677446603032531E-1,1.0298429148482115E-1,9.919837550651314E-2,1.4635281446993512E-1,1.4895604768656998E-1,1.512485961625871E-1,1.5322009813417023E-1,1.5486315252912908E-1,1.5617319174922673E-1,1.5714830625225343E-1,1.577890417358728E-1,1.5809818656918145E-1,1.580805629666921E-1,1.5774283091696228E-1,1.570933096168672E-1,1.56141817522671E-1,1.54899529348393E-1,1.5337884650787853E-1,1.5159327657542762E-1,1.4955731720881066E-1,1.472863404641519E-1,1.447964743392179E-1,1.4210447951928556E-1,1.392276204991562E-1,1.3618353138037803E-1,1.329900775970059E-1,1.296652155470612E-1,1.2622685257569435E-1,1.2269270997396516E-1,1.1908019164961058E-1,1.1540626093271085E-1,1.1168732764650813E-1,1.0793914714978721E-1,1.0417673258710167E-1,1.0041428110550629E-1,1.4543742781424168E-1,1.4810261267923994E-1,1.5046168994738157E-1,1.5250389204266548E-1,1.5422137523556642E-1,1.5560909968791517E-1,1.5666466129046214E-1,1.5738809586803343E-1,1.5778167324609532E-1,1.578496945881456E-1,1.5759830198382932E-1,1.5703530504317012E-1,1.5617002563322513E-1,1.5501315911994956E-1,1.5357664864090723E-1,1.518735680036152E-1,1.499180086613023E-1,1.4772496669198087E-1,1.4531022660485965E-1,1.4269023993073393E-1,1.3988199775169555E-1,1.3690289745444625E-1,1.337706049526281E-1,1.3050291435656602E-1,1.271176075481862E-1,1.2363231634732803E-1,1.2006438995799769E-1,1.1643077019801112E-1,1.1274787668918813E-1,1.0903150376570543E-1,1.0529673039010874E-1,1.0155784388889497E-1,1.4455549396797124E-1,1.4727807596249676E-1,1.49698951687399E-1,1.5180697926421927E-1,1.535939048689422E-1,1.5505424955885835E-1,1.561851479097492E-1,1.5698615882133166E-1,1.5745906583826633E-1,1.576076803127632E-1,1.5743765635566995E-1,1.56956322333544E-1,1.5617253007027443E-1,1.550965201454306E-1,1.5373979984191236E-1,1.5211502935592605E-1,1.5023591172813455E-1,1.4811708241792246E-1,1.4577399533227747E-1,1.4322280324840725E-1,1.404802317670775E-1,1.3756344706563728E-1,1.3448991868712515E-1,1.3127727934348124E-1,1.2794318420007975E-1,1.2450517234737304E-1,1.2098053317717704E-1,1.1738618020409416E-1,1.137385345525791E-1,1.100534199148185E-1,1.0634597031869257E-1,1.0263055156774327E-1,1.4370948803585792E-1,1.4648511969972297E-1,1.4896325849140443E-1,1.511324181400385E-1,1.529839658551194E-1,1.5451201546913756E-1,1.5571327242864416E-1,1.565868507851916E-1,1.571340793930108E-1,1.5735831055848096E-1,1.5726474005499952E-1,1.5686024326097292E-1,1.5615322859911587E-1,1.551535066960318E-1,1.5387217183934643E-1,1.523214913621886E-1,1.5051479842009094E-1,1.4846638407805754E-1,1.4619138550687516E-1,1.437056682104827E-1,1.4102570140305679E-1,1.3816842678915023E-1,1.3515112197345003E-1,1.319912604763791E-1,1.2870637083024916E-1,1.253138974787828E-1,1.2183106622356414E-1,1.1827475679170606E-1,1.1466138478511623E-1,1.1100679486064892E-1,1.0732616652676161E-1,1.0363393346546224E-1,1.429016550617348E-1,1.457261876440034E-1,1.4825724212308466E-1,1.504830162063946E-1,1.5239452787275493E-1,1.539855143789991E-1,1.5525228316962128E-1,1.5619353464527308E-1,1.5681017386297777E-1,1.571051243349734E-1,1.5708315280664487E-1,1.567507097699509E-1,1.5611578690778655E-1,1.5518778991262938E-1,1.5397742327938505E-1,1.5249658271761174E-1,1.507582506536657E-1,1.4877639073622478E-1,1.465658381320251E-1,1.4414218351669067E-1,1.41521649861205E-1,1.3872096225162803E-1,1.357572119582013E-1,1.3264771672711637E-1,1.2940987977538326E-1,1.2606105022638744E-1,1.2261838775296785E-1,1.1909873403301577E-1,1.155184933145949E-1,1.1189352398060005E-1,1.0823904254166562E-1,1.0456954100980215E-1,1.4213402374631837E-1,1.4500349817737962E-1,1.475833012433401E-1,1.4986134152823194E-1,1.51828316174579E-1,1.5347761531637755E-1,1.548051784826633E-1,1.5580932274291123E-1,1.5649055953994878E-1,1.5685141330237493E-1,1.5689625068430363E-1,1.566311251862374E-1,1.560636383677162E-1,1.5520281611716982E-1,1.540589965996491E-1,1.5264372554167313E-1,1.5096965432860643E-1,1.4905043682362182E-1,1.4690062168322773E-1,1.4453553805775618E-1,1.4197117375964988E-1,1.3922404612150308E-1,1.3631106674919533E-1,1.3324940213951073E-1,1.3005633264692176E-1,1.267491125498036E-1,1.2334483400368343E-1,1.1986029751434016E-1,1.1631189126124314E-1,1.1271548119886583E-1,1.0908631340445561E-1,1.0543892966535115E-1,1.4140841964813533E-1,1.443190569423388E-1,1.4694361335977663E-1,1.492697338597105E-1,1.512878218589083E-1,1.5299094866732524E-1,1.543747149715526E-1,1.554370839640122E-1,1.561782029435414E-1,1.5660022640795507E-1,1.5670714945458394E-1,1.5650465623906865E-1,1.5599998471632934E-1,1.5520180614915105E-1,1.5412011602403913E-1,1.5276613204640563E-1,1.5115219469480834E-1,1.492916662389423E-1,1.471988249849012E-1,1.4488875262025067E-1,1.4237721372455947E-1,1.3968052765196537E-1,1.3681543398013168E-1,1.3379895349038953E-1,1.306482471666811E-1,1.2738047597443503E-1,1.2401266422539223E-1,1.2056156918631866E-1,1.1704355929261617E-1,1.1347450292877094E-1,1.0986966928099295E-1,1.0624364229272092E-1],[3.3909485253675115E-1,9.997529836607687E-1,9.99033394173412E-1,9.978734812795618E-1,9.96305447248215E-1,9.943612977230565E-1,9.920727057560342E-1,9.894708889763058E-1,9.865864997094095E-1,9.834495277440137E-1,9.800892153425516E-1,9.765339840069684E-1,9.728113724409572E-1,9.689479850945661E-1,9.649694506349458E-1,9.6090038965717E-1,9.567643909304041E-1,9.525839954660321E-1,9.483806876945519E-1,9.441748930459662E-1,9.399859812429397E-1,9.358322746361067E-1,9.317310609356425E-1,9.276986097216056E-1,9.237501921468152E-1,9.199001032793649E-1,9.161616865666294E-1,9.125473599381856E-1,9.090686431009222E-1,9.057361856153195E-1,9.025597953770438E-1,8.995484671623336E-1,4.696420705897682E-2,3.387691387769439E-1,9.997634809740615E-1,9.990749888723537E-1,9.979661299968289E-1,9.96468401972593E-1,9.946130538389705E-1,9.924309589454783E-1,9.89952500538775E-1,9.872074698045158E-1,9.84224976022E-1,9.810333683991737E-1,9.776601690803098E-1,9.74132016757796E-1,9.704746202719748E-1,9.667127215479322E-1,9.628700671944223E-1,9.58969388076673E-1,9.550323861704976E-1,9.510797280088598E-1,9.47131044042714E-1,9.432049332545372E-1,9.393189723845178E-1,9.354897291549361E-1,9.317327789070412E-1,9.280627240959062E-1,9.244932161216604E-1,9.210369790095152E-1,9.177058344855935E-1,9.1451072803027E-1,9.114617555251348E-1,9.085681901434723E-1,4.971483009969774E-2,4.626758263160615E-2,3.384412583472707E-1,9.997737952613622E-1,9.991158437027272E-1,9.980570994021613E-1,9.966283501240256E-1,9.94860086323237E-1,9.927823825566936E-1,9.904247911313053E-1,9.878162477074675E-1,9.849849884816436E-1,9.819584784914587E-1,9.787633505207065E-1,9.754253540290966E-1,9.719693134915081E-1,9.684190955029595E-1,9.647975839874058E-1,9.61126662839756E-1,9.574272053301017E-1,9.53719069606004E-1,9.500210996417809E-1,9.463511310021094E-1,9.42726000809987E-1,9.391615613353376E-1,9.356726966495286E-1,9.322733418220798E-1,9.289765041682513E-1,9.257942860894619E-1,9.227379090821025E-1,9.198177385238713E-1,9.170433088799117E-1,5.243664570238918E-2,4.892964313600073E-2,4.5566954920353286E-2,3.3811126111711604E-1,9.997839217622829E-1,9.991559398391031E-1,9.981463475440052E-1,9.967852176971016E-1,9.951022802107059E-1,9.931268116703237E-1,9.908875366899238E-1,9.884125407207855E-1,9.857291939082856E-1,9.828640855201944E-1,9.798429684126548E-1,9.766907129551785E-1,9.734312698027766E-1,9.700876408807471E-1,9.666818579346443E-1,9.632349679935223E-1,9.597670250976418E-1,9.562970876514679E-1,9.528432207779934E-1,9.494225030703098E-1,9.460510371600458E-1,9.427439635490356E-1,9.395154771796526E-1,9.363788462499848E-1,9.333464328118974E-1,9.304297147224954E-1,9.276393085521457E-1,9.24984993084677E-1,5.512284780098163E-2,5.156210730046296E-2,4.8141089015380126E-2,4.486244869951206E-2,3.3777920215485674E-1,9.997938558529609E-1,9.991952590061617E-1,9.982338337158541E-1,9.969389329103697E-1,9.953395240247507E-1,9.934640864071104E-1,9.913405200309531E-1,9.889960651584379E-1,9.864572325242955E-1,9.837497435481647E-1,9.80898480033739E-1,9.779274427754332E-1,9.748597184663578E-1,9.717174542842465E-1,9.685218395236188E-1,9.652930936418805E-1,9.620504600932872E-1,9.588122053367816E-1,9.555956224207561E-1,9.524170385689483E-1,9.492918262161574E-1,9.462344169695653E-1,9.432583180004838E-1,9.403761304017666E-1,9.375995690773923E-1,9.349394837623943E-1,9.324058808030079E-1,5.7767175209136185E-2,5.4158550373706E-2,5.068485670519441E-2,4.7349338293822686E-2,4.415419883496156E-2,3.374451409720716E-1,9.998035930487081E-1,9.992337834892744E-1,9.983195184802823E-1,9.970894262499385E-1,9.955717098474797E-1,9.937940520330317E-1,9.917835310009746E-1,9.89566546552433E-1,9.871687562662979E-1,9.846150211645107E-1,9.819293603254118E-1,9.791349138678759E-1,9.762539137078152E-1,9.733076614764543E-1,9.703165129856078E-1,9.672998686280707E-1,9.642761691102258E-1,9.612628959281979E-1,9.58276576017499E-1,9.553327900283205E-1,9.524461837037198E-1,9.496304818652548E-1,9.468985045395402E-1,9.442621847892225E-1,9.417325878425061E-1,9.393199311462361E-1,6.036391678873319E-2,5.671307028053486E-2,5.319219800327414E-2,4.9805112500689384E-2,4.655457166279772E-2,4.3442348670250604E-2,3.371091408289568E-1,9.99813129006561E-1,9.992714961446809E-1,9.984033636920596E-1,9.972366305114183E-1,9.957987333873158E-1,9.941165590605737E-1,9.922163666214115E-1,9.901237198521968E-1,9.87863429052989E-1,9.854595018370813E-1,9.82935102348702E-1,9.803125183300377E-1,9.776131354488815E-1,9.748574182905388E-1,9.720648974172303E-1,9.692541619041929E-1,9.664428567731183E-1,9.636476847596593E-1,9.608844118716768E-1,9.58167876217978E-1,9.555119996128436E-1,9.529298014890397E-1,9.504334146807397E-1,9.480341026673462E-1,9.457422778992002E-1,6.290791070997448E-2,5.9220290594304E-2,5.5657553657839504E-2,5.222405992702935E-2,4.892310338074406E-2,4.575697809832564E-2,4.272704858261552E-2,3.3677126813010594E-1,9.998224595277285E-1,9.993083804092533E-1,9.984853325203278E-1,9.973804808401721E-1,9.960204940438835E-1,9.944314633460379E-1,9.926388312275701E-1,9.906673296164887E-1,9.885409270431839E-1,9.862827842522597E-1,9.839152177241328E-1,9.8145967054022E-1,9.789366900144857E-1,9.76365911510534E-1,9.73766047866418E-1,9.711548838580436E-1,9.685492751456262E-1,9.659651511653504E-1,9.634175214494464E-1,9.60920484881661E-1,9.584872414209659E-1,9.561301058537393E-1,9.538605231631231E-1,9.516890851333302E-1,6.539453839244042E-2,6.1675358070241465E-2,5.807586613348676E-2,5.460094826911508E-2,5.1254415418256954E-2,4.8039066069030564E-2,4.495675324243725E-2,4.200845475944673E-2,3.364315919293356E-1,9.998315805599354E-1,9.993444203098443E-1,9.985653894698239E-1,9.975209147698422E-1,9.962368949701458E-1,9.947386261827879E-1,9.930507366019883E-1,9.911971301976267E-1,9.892009388837517E-1,9.870844826417723E-1,9.848692370551589E-1,9.82575807698159E-1,9.802239108143455E-1,9.778323597209065E-1,9.754190563805989E-1,9.730009875944037E-1,9.705942252833775E-1,9.682139303472478E-1,9.658743596092857E-1,9.635888753812892E-1,9.613699572085687E-1,9.592292153821347E-1,9.571774058334237E-1,6.781971372291383E-2,6.407393530467956E-2,6.044257559844179E-2,5.693102349914565E-2,5.354358697788836E-2,5.028355148444948E-2,4.715324353435683E-2,4.4154098061695055E-2,4.12867282245812E-2,3.36090183553454E-1,9.998404881996629E-1,9.993796004722093E-1,9.986435004011363E-1,9.976578722591242E-1,9.964478431317372E-1,9.950379143903425E-1,9.934519021019423E-1,9.917128859177932E-1,9.898431659471045E-1,9.878642270960003E-1,9.857967103344485E-1,9.836603903441794E-1,9.814741589978817E-1,9.792560141233488E-1,9.77023053014945E-1,9.74791470168003E-1,9.725765587288306E-1,9.703927151732062E-1,9.682534467489826E-1,9.661713812431059E-1,9.641582786595099E-1,9.622250444214901E-1,7.017986814184256E-2,6.641218908727711E-2,6.275361145768053E-2,5.921000447824192E-2,5.5786152613148614E-2,5.2485810064971807E-2,4.931176092310204E-2,4.626588353910442E-2,4.334921780487044E-2,4.0562034126596334E-2,3.35747116347808E-1,9.998491786942808E-1,9.994139061295003E-1,9.987196325499772E-1,9.97791295726757E-1,9.96653249363439E-1,9.953292003992276E-1,9.938421547809736E-1,9.922143712372077E-1,9.904673225579187E-1,9.886216638633328E-1,9.866972073323648E-1,9.847129028559463E-1,9.826868240812565E-1,9.806361593192071E-1,9.785772067986015E-1,9.765253737654827E-1,9.744951789446213E-1,9.725002579012663E-1,9.705533708645981E-1,9.686664125992938E-1,9.668504239377573E-1,7.24719321776089E-2,6.868677500625149E-2,6.500537997049935E-2,6.1434073511082994E-2,5.7978095630250616E-2,5.464165049543194E-2,5.142796312956633E-2,4.833934076583049E-2,4.537723753491238E-2,4.254232126376136E-2,3.983454128789928E-2,3.354024655411731E-1,9.998576484440737E-1,9.994473231303227E-1,9.98793754545459E-1,9.979211300847034E-1,9.968530284227467E-1,9.956123623315011E-1,9.942213295042964E-1,9.927013709139565E-1,9.91073136208784E-1,9.8935645563512E-1,9.875703179670249E-1,9.85732853921963E-1,9.83861324545381E-1,9.819721140560147E-1,9.800807266569013E-1,9.782017868337712E-1,9.763490426820977E-1,9.745353718260307E-1,9.727727895162172E-1,9.710724585186327E-1,7.469331398757377E-2,7.089481885165354E-2,6.719474848126723E-2,6.359986335254651E-2,6.011583780391579E-2,5.674730677000259E-2,5.3497919013081804E-2,5.037039543264629E-2,4.736659111649526E-2,4.448755990119247E-2,4.173362032780025E-2,3.9104422003770144E-2,3.3505630822385374E-1,9.998658940041573E-1,9.994798379463528E-1,9.988658364273617E-1,9.980473227694934E-1,9.97047099040484E-1,9.958872840768731E-1,9.945892690579622E-1,9.931736801552856E-1,9.916603477644845E-1,9.900682818158019E-1,9.884156526553416E-1,9.86719776990995E-1,9.849971084037904E-1,9.832632319366682E-1,9.81532862287647E-1,9.798198451524069E-1,9.781371612818949E-1,9.764969328431345E-1,9.749104316955174E-1,7.684187543871263E-2,7.303389534024435E-2,6.931902677531873E-2,6.570444116451969E-2,6.219622588971684E-2,5.8799427200942334E-2,5.551810000531074E-2,5.23553631241151E-2,4.9313458679485125E-2,4.639381437013512E-2,4.359710750867292E-2,4.092332981381424E-2,3.837185207417277E-2,3.347087234305854E-1,9.998739120862855E-1,9.995114376795086E-1,9.989358496623788E-1,9.981698237717067E-1,9.972353839684169E-1,9.961538553643435E-1,9.949458242516559E-1,9.936311047601653E-1,9.922287116546347E-1,9.907568387778126E-1,9.892328426444815E-1,9.876732306966428E-1,9.860936537393346E-1,9.845089020898479E-1,9.829329049896378E-1,9.813787328474481E-1,9.798586019035458E-1,9.783838809280221E-1,7.89159062297249E-2,7.510200465893088E-2,7.137594604954346E-2,6.774528990287823E-2,6.421651540140874E-2,6.0795060546360455E-2,5.748536853605309E-2,5.4290939979016455E-2,5.121438960379829E-2,4.8257506219179624E-2,4.5421314786383046E-2,4.270613958152301E-2,4.011166754674781E-2,3.763701104770763E-2,3.3435979231878443E-1,9.998816995605458E-1,9.995421100686718E-1,9.990037671593306E-1,9.982885856635717E-1,9.974178100238272E-1,9.964119718292874E-1,9.952908540150124E-1,9.940734612529539E-1,9.927779960544074E-1,9.914218401008795E-1,9.900215403232071E-1,9.885927992563259E-1,9.871504692086893E-1,9.857085498003643E-1,9.842801884417121E-1,9.828776833447467E-1,9.815124886812889E-1,8.091409652208024E-2,7.709754729295477E-2,7.33636359603222E-2,6.972028759154425E-2,6.617435210241521E-2,6.273163969660656E-2,5.939696387941016E-2,5.617419064984984E-2,5.306629253577813E-2,5.007540622227886E-2,4.720289262630293E-2,4.444939838311746E-2,4.1814917826887434E-2,3.9298854664616245E-2,3.6900082655909994E-2,3.340095984325812E-1,9.998892534569435E-1,9.995718434959542E-1,9.990695632833356E-1,9.98403563624659E-1,9.975943081310066E-1,9.966615350759221E-1,9.956242254873443E-1,9.945005770079933E-1,9.933079830531065E-1,9.920630167953588E-1,9.907814195125959E-1,9.894780928439864E-1,9.881670945137518E-1,9.868616370981858E-1,9.85574089430682E-1,9.843159802604864E-1,8.283550851057915E-2,7.901929757148705E-2,7.528060018120912E-2,7.162768491364176E-2,6.806775163714407E-2,6.460696333876474E-2,6.1250485831966524E-2,5.800253396377765E-2,5.486642299073051E-2,5.184462387255508E-2,4.893882133013509E-2,4.614997362263813E-2,4.3478373112247455E-2,4.092370679915599E-2,3.848511612093985E-2,3.616125541691531E-2,3.3365822804373285E-1,9.998965709668717E-1,9.996006269925078E-1,9.991332138689284E-1,9.98514715465651E-1,9.97764813359634E-1,9.969024527350933E-1,9.959458141006815E-1,9.949122903649805E-1,9.93818468810353E-1,9.926801175092751E-1,9.915121757356686E-1,9.903287479358598E-1,9.891431008390442E-1,9.87967663304986E-1,9.868140285266414E-1,8.467954732569144E-2,8.086637632771652E-2,7.712569087012022E-2,7.346608152009935E-2,6.989507770112155E-2,6.641917599513963E-2,6.304387661405618E-2,5.977372666976627E-2,5.661236891865955E-2,5.356259473010783E-2,5.062640012093037E-2,4.78050438021056E-2,4.509910629415879E-2,4.250854927922198E-2,4.003277446734825E-2,3.767068135961633E-2,3.5420723389524775E-2,3.3330577056171995E-1,9.999036494444694E-1,9.996284502438719E-1,9.99194696232117E-1,9.986220016501679E-1,9.979292649600054E-1,9.971346385173231E-1,9.962555036560313E-1,9.953084507349748E-1,9.943092636996722E-1,9.932729087187557E-1,9.92213526465489E-1,9.91144427628717E-1,9.900780912543131E-1,9.890261655371335E-1,8.64459316210081E-2,8.263822303395854E-2,7.889808241165398E-2,7.523440142448981E-2,7.16550191200259E-2,6.816674680529482E-2,6.477540136157693E-2,6.1485845635739965E-2,5.8302034592077966E-2,5.522706597638792E-2,5.226323433154629E-2,4.941208730404297E-2,4.667448328762375E-2,4.405064955923911E-2,4.154024016993396E-2,3.91423929568457E-2,3.6855785140396564E-2,3.4678687061870446E-2,3.3295231900689143E-1,9.999104864078632E-1,9.996553035948564E-1,9.992539891813715E-1,9.987253853146363E-1,9.980876063950842E-1,9.973580122610716E-1,9.965531863927743E-1,9.956889186969078E-1,9.947801924392853E-1,9.938411749015738E-1,9.928852113513335E-1,9.919248219300202E-1,9.909717010815801E-1,8.813466416041776E-2,8.433456773545463E-2,8.059724476537601E-2,7.693186782020335E-2,7.334656617724468E-2,6.984844739312854E-2,6.64436275500677E-2,6.31372688362534E-2,5.993362315372457E-2,5.683608050911858E-2,5.384722102547288E-2,5.096886950926314E-2,4.820215161033518E-2,4.554755071867052E-2,4.300496484730041E-2,4.0573762852707376E-2,3.825283944079664E-2,3.604066849700625E-2,3.393535436248647E-2,3.325979705423311E-1,9.999170795402953E-1,9.996811780539578E-1,9.993110730275366E-1,9.988248322861838E-1,9.982397853693455E-1,9.975724999761605E-1,9.968387630511201E-1,9.960535660844794E-1,9.952310942099272E-1,9.94384718693543E-1,9.935269924225679E-1,9.926696480194926E-1,8.974600268157809E-2,8.59554030700446E-2,8.222291671607034E-2,7.855797762308216E-2,7.49689864984524E-2,7.14633291312655E-2,6.804740366560973E-2,6.472665544605287E-2,6.1505618139069206E-2,5.838795989090901E-2,5.537653336025492E-2,5.2473428556188605E-2,4.9680027512060014E-2,4.699705992948859E-2,4.442465903000555E-2,4.196241695223937E-2,3.960943912813781E-2,3.736439716143562E-2,3.522557981448456E-2,3.319094178564144E-2,3.3224282706200065E-1,9.999234266911351E-1,9.997060652973059E-1,9.993659295926623E-1,9.989203110985482E-1,9.983857538543914E-1,9.977780338823211E-1,9.971121429275541E-1,9.964022760633306E-1,9.956618227595304E-1,9.94903361027532E-1,9.941386542699013E-1,9.128043127564263E-2,8.750095662539838E-2,8.377507928775325E-2,8.011247600976679E-2,7.65218007704443E-2,7.301070008543309E-2,6.958583740920593E-2,6.625292532878042E-2,6.30167642641802E-2,5.988128644215563E-2,5.6849603983094965E-2,5.392406002919114E-2,5.110628193882977E-2,4.839723567311118E-2,4.5797280601566646E-2,4.3306224052910736E-2,4.092337503103747E-2,3.864759660532398E-2,3.6477356566719986E-2,3.441077601691756E-2,3.2445675626854055E-2,3.318869958346563E-1,9.999295258767747E-1,9.997299576721373E-1,9.99418542217748E-1,9.990117930059899E-1,9.985254681113163E-1,9.979745524428293E-1,9.973732439232179E-1,9.96734943198403E-1,9.960722464946359E-1,9.953969412548928E-1,9.273863248817599E-2,8.89716638513254E-2,8.52539295500367E-2,8.159533119000312E-2,7.80047585406253E-2,7.449010189200883E-2,7.105827369319444E-2,6.771523818352282E-2,6.446604774446413E-2,6.131488474547945E-2,5.826510772640762E-2,5.5319300843241694E-2,5.2479325597833165E-2,4.974637397041643E-2,4.712102217285442E-2,4.460328433763022E-2,4.219266555074975E-2,3.988821372463134E-2,3.7688569888975454E-2,3.559201655299194E-2,3.359652386135968E-2,3.169979332853856E-2,3.3153059020485764E-1,9.999353752814085E-1,9.997528481997977E-1,9.994688957693941E-1,9.990992519951984E-1,9.986588887098035E-1,9.981620003931951E-1,9.976219925851685E-1,9.970514735114002E-1,9.964622485584053E-1,9.412146031333155E-2,9.036814171229536E-2,8.66598550137578E-2,8.300670962024043E-2,7.941781431360086E-2,7.590128679297302E-2,7.2464272660553E-2,6.911297258530268E-2,6.585267638456276E-2,6.268780280495184E-2,5.962194384855811E-2,5.665791257107768E-2,5.3797793369194595E-2,5.1042993870163686E-2,4.839429763355902E-2,4.5851916970584786E-2,4.341554527816209E-2,4.1084408372088585E-2,3.885731438471227E-2,3.673270186773697E-2,3.470868580944874E-2,3.2783101338124176E-2,3.095354493956922E-2,3.311737303541918E-1,9.999409732576947E-1,9.997747305782678E-1,9.995169766453605E-1,9.991826647951854E-1,9.987859805439402E-1,9.983403287648847E-1,9.978583241404768E-1,9.973517845282873E-1,9.542991422269373E-2,9.169116323494114E-2,8.799340878281035E-2,8.434695183644138E-2,8.07611041325988E-2,7.724419502462393E-2,7.380358793081576E-2,7.044570512961942E-2,6.717605965467943E-2,6.399929307954505E-2,6.0919218042304255E-2,5.793886443753728E-2,5.506052829056009E-2,5.228582242212093E-2,4.9615728106618344E-2,4.705064702065158E-2,4.4590452869350615E-2,4.223454216392385E-2,3.998188370445142E-2,3.7831066396619414E-2,3.57803450996281E-2,3.3827684264918584E-2,3.1970799181727856E-2,3.020719469609734E-2,3.3081654412745193E-1,9.999463183273007E-1,9.99795599184214E-1,9.995627727790259E-1,9.992620108851592E-1,9.9890671284474E-1,9.985094949040497E-1,9.980821825231289E-1,9.666511434201187E-2,9.294163307717744E-2,8.925528560118194E-2,8.561654905642016E-2,8.203492280626402E-2,7.851893272976362E-2,7.507614525045148E-2,7.171318986586382E-2,6.843578894418743E-2,6.524879358665929E-2,6.2156224410911134E-2,5.916131618417392E-2,5.626656531984238E-2,5.347377934172779E-2,5.078412751310561E-2,4.819819191987814E-2,4.5716018386428074E-2,4.3337166687824696E-2,4.1060759601874816E-2,3.888553041878502E-2,3.6809868594416206E-2,3.483186329552537E-2,3.294934464181732E-2,3.1159922500487332E-2,2.946102273422521E-2,3.30459167930002E-1,9.999514091813312E-1,9.998154490745639E-1,9.996062736427503E-1,9.993372725003766E-1,9.990210591893625E-1,9.98669462485255E-1,9.78282778633971E-2,9.412056421974674E-2,9.044629890837746E-2,8.68161206763351E-2,8.323970191592513E-2,7.972575053794997E-2,7.628202170083612E-2,7.291533818038391E-2,6.96316181599499E-2,6.643590924888515E-2,6.333242758984614E-2,6.032460098602913E-2,5.741511506118287E-2,5.460596155364968E-2,5.189848793656386E-2,4.929344764686429E-2,4.679105029381864E-2,4.439101130183895E-2,4.209260052147546E-2,3.9894689416265804E-2,3.779579650104157E-2,3.5794130769602917E-2,3.388763290616134E-2,3.207401412594519E-2,3.0350792536042826E-2,2.8715326948049003E-2,3.301017477039047E-1,9.999562446806384E-1,9.998342759876033E-1,9.99647470250136E-1,9.9940843463597E-1,9.991289975070298E-1,9.892069675748721E-2,9.522905585766225E-2,9.156735899286288E-2,8.794639276231553E-2,8.437598871487902E-2,8.086502293506104E-2,7.742142559389112E-2,7.405219926718426E-2,7.076344481439974E-2,6.756039363529534E-2,6.444744517081037E-2,6.1428208581908054E-2,5.850554761921957E-2,5.5681627782429674E-2,5.2957964957309714E-2,5.033547480728876E-2,4.781452228319588E-2,4.539497069795173E-2,4.307622989134894E-2,4.085730308331331E-2,3.8736832081721656E-2,3.671314057290899E-2,3.478427527959979E-2,3.294804482205307E-2,3.120205616414625E-2,2.954374856704543E-2,2.7970425009124732E-2,3.297444399915629E-1,9.999608238560157E-1,9.998520763436E-1,9.996863551571908E-1,9.994754850487493E-1,9.994371682955527E-2,9.626827254804043E-2,9.261945231192062E-2,8.90081776168196E-2,8.544442600969705E-2,8.193722852185978E-2,7.849467716397564E-2,7.512394130301016E-2,7.183129172751937E-2,6.86221312279673E-2,6.550103056460513E-2,6.2471768759720055E-2,5.953737672764266E-2,5.670018333981178E-2,5.3961863109266074E-2,5.132348476644377E-2,4.878556008370625E-2,4.634809238808164E-2,4.40106242794851E-2,4.177228414429089E-2,3.9631831121550026E-2,3.758769824099873E-2,3.563803350854726E-2,3.378073876615465E-2,3.201350619908001E-2,3.033385240470712E-2,2.8739149973612866E-2,2.7226656565636765E-2,3.293874130966189E-1,9.999651459082738E-1,9.998688472449482E-1,9.997229224623919E-1,1.00898718145568E-1,9.723942465231174E-2,9.360362202729659E-2,9.000235447993149E-2,8.644573309402816E-2,8.294293124161146E-2,7.950219014500888E-2,7.61308334239814E-2,7.283528944734526E-2,6.962112032517377E-2,6.649305642036998E-2,6.345503531983722E-2,6.05102442796677E-2,5.766116524048726E-2,5.4909621594506894E-2,5.225682597180559E-2,4.970342839773004E-2,4.724956425444896E-2,4.4894901556714474E-2,4.26386871239903E-2,4.047979129813611E-2,3.8416750917543686E-2,3.644781031504973E-2,3.457096015825979E-2,3.2783973997144174E-2,3.1084442425254547E-2,2.9469804797663857E-2,2.793737848127437E-2,2.6484385641339335E-2,3.290308483526729E-1,9.999692102082001E-1,9.998845864758417E-1,1.0178709683861514E-1,9.81437500945721E-2,9.452094978938218E-2,9.092985140877888E-2,8.738068778793735E-2,8.388276263911439E-2,8.044445430388084E-2,7.707322858295637E-2,7.377565947572302E-2,7.055745667483668E-2,6.742349870101136E-2,6.437787062190826E-2,6.14239053708761E-2,5.856422776106473E-2,5.580080037415613E-2,5.313497058751065E-2,5.056751808674897E-2,4.809870229105019E-2,4.572830919468227E-2,4.345569719994014E-2,4.1279841583270756E-2,3.919937729787898E-2,3.7212639872468846E-2,3.53177042170645E-2,3.3512421193263475E-2,3.179445184791638E-2,3.0161299246359442E-2,2.8610337874116175E-2,2.7138840604662557E-2,2.5744003255746356E-2,3.2867494151099275E-1,9.999730162964009E-1,1.026102482928774E-1,9.898249744395198E-2,9.537253878807725E-2,9.179162836314203E-2,8.825010962035504E-2,8.475740519770751E-2,8.132201898523954E-2,7.79515473506789E-2,7.465269836972875E-2,7.143131791548629E-2,6.829242149837789E-2,6.524023080437139E-2,6.2278213948827106E-2,5.940912854129492E-2,5.6635066738650375E-2,5.395750154725801E-2,5.137733371684381E-2,4.889493864828745E-2,4.651021281295128E-2,4.42226192523919E-2,4.20312317935068E-2,3.993477767542773E-2,3.793167834078503E-2,3.602008819520209E-2,3.4197931185433746E-2,3.2462935088345704E-2,3.0812663440325568E-2,2.9244545069843517E-2,2.7755901224898395E-2,2.6343970312377472E-2,2.5005930287988955E-2,3.283199042587231E-1]],"losses":[-9.952125227881714E-2,-1.4657479116128336E-1,-1.930287822505916E-1],"sum":[[-1.380838286046293E-3,-1.3848891583638778E-3,-1.383259980509477E-3,-1.3649820560728276E-3,-1.3179739249842282E-3,-1.2289268235705642E-3,-1.0833109117602824E-3,-8.654907383724986E-4,-5.308189304598088E-4,-2.6506889326305405E-4,-7.089223258116562E-5,4.984296576204805E-5,9.610728500630827E-5,6.775628700972369E-5,-3.443314407958198E-5,-2.0873744631511038E-4,-4.5247290636019066E-4,-7.61994809660882E-4,-1.1327097825171162E-3,-1.5591017007072772E-3,-2.0347713289585734E-3,-2.552489631195032E-3,-3.1042644571701583E-3,-3.6814200705155287E-3,-4.274688741217725E-3,-4.874313386512785E-3,-5.470160013129277E-3,-6.051838495831685E-3,-6.608830026821E-3,-7.1306193930840145E-3,-7.606830088080052E-3,-8.027360144790219E-3,-8.382516492531966E-3,-8.663145592874066E-3,-8.860758103077515E-3,-8.96764534990524E-3,-8.97698547320358E-3,-8.882937217148168E-3,-8.680719506116485E-3,-8.366675139998225E-3,-7.938317177312637E-3,-7.394356839942162E-3,-6.734712066207571E-3,-5.9604961540955514E-3,-5.073986267915664E-3,-4.078571923257446E-3,-2.978683910394686E-3,-1.779704458269915E-3,-4.878597735569201E-4,8.899035949894163E-4,2.3460568235482704E-3,3.872639303768022E-3,5.461419318328442E-3,7.1040624707645605E-3,8.79230528885211E-3,1.0518131315846002E-2,1.227394694614814E-2,1.4052754252170008E-2,1.5848318087466673E-2,1.7655324836500785E-2,1.946953031194898E-2,2.1287894473020597E-2,2.3108700849717723E-2,2.493165880340431E-2,2.6757987028945385E-2,2.859047700215811E-2,3.0433535392925037E-2,3.229320479259146E-2,3.417716243849944E-2,3.6094696952086336E-2,3.805666343454028E-2,4.0075417579353845E-2,4.216472975942964E-2,4.4339680322774244E-2,4.6616537581049444E-2,4.9012620195929335E-2,5.1546145856505965E-2,5.423606829462013E-2,5.710190480282229E-2,6.016355650086924E-2,6.344112364125754E-2,6.695471825315569E-2,7.07242763983923E-2,7.47693722547692E-2,7.910903615348064E-2,8.376157858132449E-2,8.874442201811239E-2,9.407394231839006E-2,9.976532116807557E-2,1.0583241095433116E-1,1.1228761318481117E-1,1.1914177138398085E-1,1.2640407918285446E-1,1.3408200410793714E-1,1.421812273681451E-1,1.507055997382225E-1,1.596571134460576E-1,1.6903588979159867E-1,1.788401820588379E-1,1.8906639313092E-1,1.9970910708317124E-1,2.107611339107358E-1,2.222135664466941E-1,2.3405584844374883E-1,2.4627585272729013E-1,2.5885996827979607E-1,2.717931950854604E-1,2.85059245548851E-1,2.986406513012232E-1,3.1251887422205793E-1,3.266744205297465E-1,3.410869568332757E-1,3.557354270845099E-1,3.705981694271685E-1,3.856530320021061E-1,4.0087748683798896E-1,4.1624874103031884E-1,4.31743844488784E-1,4.473397936120236E-1,4.630136303287298E-1,4.787425360236952E-1,4.9450391994600684E-1,5.102755017731573E-1,5.260353880787676E-1,5.417621425221688E-1,5.574348496448893E-1,5.730331722215354E-1,5.885374021705485E-1],[9.396545171472592E-3,8.932262558255744E-3,8.274832803439214E-3,7.614436929297308E-3,7.039772179309511E-3,6.581254089288446E-3,6.232069830745757E-3,5.950633351090362E-3,5.595698164309937E-3,5.422064986058128E-3,5.3856673482908235E-3,5.448093359401551E-3,5.576569362547135E-3,5.743809844790615E-3,5.927750394786768E-3,6.111182940084947E-3,6.281314059970233E-3,6.429267856548404E-3,6.5495547048266545E-3,6.639526257314898E-3,6.698835446229623E-3,6.728918027410047E-3,6.732509582293322E-3,6.713208984847174E-3,6.675096297912297E-3,6.622410030746373E-3,6.559285796929659E-3,6.4895557716282415E-3,6.416606049592044E-3,6.343287115707863E-3,6.271871197973566E-3,6.204049292334091E-3,6.140960120190719E-3,6.083243171611796E-3,6.031108252279482E-3,5.98441452874332E-3,5.942752885188307E-3,5.905526392106286E-3,5.872024770250728E-3,5.84148984339139E-3,5.813170049668859E-3,5.786363072726508E-3,5.76044652059271E-3,5.734897295228358E-3,5.709300843596221E-3,5.683351858372543E-3,5.656848209598997E-3,5.629679952564359E-3,5.60181519345726E-3,5.57328442855054E-3,5.544164732741663E-3,5.514564887351581E-3,5.4846122317229185E-3,5.454441722177572E-3,5.42418740491335E-3,5.393976271637735E-3,5.363924278327437E-3,5.334134173704763E-3,5.304694705718704E-3,5.275680748191736E-3,5.247153909566427E-3,5.219163242561553E-3,5.191745757394117E-3,5.1649265412554435E-3,5.138718392489361E-3,5.113120979726271E-3,5.088119626024623E-3,5.063683889437676E-3,5.039766160208625E-3,5.016300518769334E-3,4.993202097809291E-3,4.970367167587142E-3,4.9476741196069485E-3,4.9249854641870705E-3,4.902150887435619E-3,4.879011338292383E-3,4.855404041955724E-3,4.831168267443564E-3,4.8061516184964015E-3,4.7802165721531065E-3,4.753246960564672E-3,4.72515408031382E-3,4.695882119966299E-3,4.66541261998521E-3,4.633767717794446E-3,4.601011982197756E-3,4.567252702508462E-3,4.532638565205027E-3,4.497356721147483E-3,4.461628315821642E-3,4.425702620467931E-3,4.389849960319214E-3,4.3543536851560205E-3,4.319501465074094E-3,4.285576219591025E-3,4.252847000351445E-3,4.221560146825398E-3,4.19193102107529E-3,4.164136603049817E-3,4.138309193434941E-3,4.1145314286934465E-3,4.092832764582277E-3,4.073187532293576E-3,4.055514617579803E-3,4.039678759806042E-3,4.025493416792925E-3,4.012725094177938E-3,4.001098996274877E-3,3.9903058201338215E-3,3.980009486489022E-3,3.969855580990944E-3,3.959480266700233E-3,3.94851942418839E-3,3.936617778292906E-3,3.9234377801187215E-3,3.908668028396622E-3,3.8920310349968013E-3,3.8732901641980177E-3,3.852255603266519E-3,3.8287892519215383E-3,3.8028084494032832E-3,3.7742884891170947E-3,3.743263901409777E-3,3.7098285141097254E-3,3.67413432744923E-3,3.636389264316975E-3,3.5968538780816184E-3,3.555837118190297E-3]],"full":[[-1.380838286046293E-3,-1.3848891583638778E-3,-1.383259980509477E-3,-1.3649820560728276E-3,-1.3179739249842282E-3,-1.2289268235705642E-3,-1.0833109117602824E-3,-8.654907383724986E-4,-5.308189304598088E-4,-2.6506889326305405E-4,-7.089223258116562E-5,4.984296576204805E-5,9.610728500630827E-5,6.775628700972369E-5,-3.443314407958198E-5,-2.0873744631511038E-4,-4.5247290636019066E-4,-7.61994809660882E-4,-1.1327097825171162E-3,-1.5591017007072772E-3,-2.0347713289585734E-3,-2.552489631195032E-3,-3.1042644571701583E-3,-3.6814200705155287E-3,-4.274688741217725E-3,-4.874313386512785E-3,-5.470160013129277E-3,-6.051838495831685E-3,-6.608830026821E-3,-7.1306193930840145E-3,-7.606830088080052E-3,-8.027360144790219E-3,-8.382516492531966E-3,-8.663145592874066E-3,-8.860758103077515E-3,-8.96764534990524E-3,-8.97698547320358E-3,-8.882937217148168E-3,-8.680719506116485E-3,-8.366675139998225E-3,-7.938317177312637E-3,-7.394356839942162E-3,-6.734712066207571E-3,-5.9604961540955514E-3,-5.073986267915664E-3,-4.078571923257446E-3,-2.978683910394686E-3,-1.779704458269915E-3,-4.878597735569201E-4,8.899035949894163E-4,2.3460568235482704E-3,3.872639303768022E-3,5.461419318328442E-3,7.1040624707645605E-3,8.79230528885211E-3,1.0518131315846002E-2,1.227394694614814E-2,1.4052754252170008E-2,1.5848318087466673E-2,1.7655324836500785E-2,1.946953031194898E-2,2.1287894473020597E-2,2.3108700849717723E-2,2.493165880340431E-2,2.6757987028945385E-2,2.859047700215811E-2,3.0433535392925037E-2,3.229320479259146E-2,3.417716243849944E-2,3.6094696952086336E-2,3.805666343454028E-2,4.0075417579353845E-2,4.216472975942964E-2,4.4339680322774244E-2,4.6616537581049444E-2,4.9012620195929335E-2,5.1546145856505965E-2,5.423606829462013E-2,5.710190480282229E-2,6.016355650086924E-2,6.344112364125754E-2,6.695471825315569E-2,7.07242763983923E-2,7.47693722547692E-2,7.910903615348064E-2,8.376157858132449E-2,8.874442201811239E-2,9.407394231839006E-2,9.976532116807557E-2,1.0583241095433116E-1,1.1228761318481117E-1,1.1914177138398085E-1,1.2640407918285446E-1,1.3408200410793714E-1,1.421812273681451E-1,1.507055997382225E-1,1.596571134460576E-1,1.6903588979159867E-1,1.788401820588379E-1,1.8906639313092E-1,1.9970910708317124E-1,2.107611339107358E-1,2.222135664466941E-1,2.3405584844374883E-1,2.4627585272729013E-1,2.5885996827979607E-1,2.717931950854604E-1,2.85059245548851E-1,2.986406513012232E-1,3.1251887422205793E-1,3.266744205297465E-1,3.410869568332757E-1,3.557354270845099E-1,3.705981694271685E-1,3.856530320021061E-1,4.0087748683798896E-1,4.1624874103031884E-1,4.31743844488784E-1,4.473397936120236E-1,4.630136303287298E-1,4.787425360236952E-1,4.9450391994600684E-1,5.102755017731573E-1,5.260353880787676E-1,5.417621425221688E-1,5.574348496448893E-1,5.730331722215354E-1,5.885374021705485E-1],[9.396545171472592E-3,8.932262558256188E-3,8.274832803438992E-3,7.61443692929753E-3,7.039772179309511E-3,6.581254089288224E-3,6.232069830745646E-3,5.950633351090029E-3,5.595698164310159E-3,5.422064986058239E-3,5.3856673482907125E-3,5.448093359401107E-3,5.576569362547246E-3,5.743809844789727E-3,5.927750394786435E-3,6.111182940084947E-3,6.281314059970122E-3,6.429267856548293E-3,6.54955470482721E-3,6.639526257314676E-3,6.69883544622929E-3,6.728918027410158E-3,6.732509582292989E-3,6.713208984847285E-3,6.6750962979128525E-3,6.622410030746262E-3,6.559285796929326E-3,6.489555771628797E-3,6.416606049592155E-3,6.343287115707863E-3,6.271871197973677E-3,6.204049292334646E-3,6.140960120189609E-3,6.083243171612129E-3,6.031108252279593E-3,5.984414528743542E-3,5.942752885187863E-3,5.905526392104732E-3,5.872024770250728E-3,5.841489843391612E-3,5.813170049669192E-3,5.786363072727396E-3,5.760446520593487E-3,5.734897295227914E-3,5.709300843596776E-3,5.683351858372432E-3,5.656848209598997E-3,5.629679952563915E-3,5.60181519345726E-3,5.573284428549763E-3,5.544164732742218E-3,5.514564887351692E-3,5.484612231722696E-3,5.454441722177461E-3,5.424187404913461E-3,5.393976271637069E-3,5.363924278327437E-3,5.334134173705318E-3,5.304694705718815E-3,5.275680748191736E-3,5.247153909566427E-3,5.21916324256122E-3,5.191745757394006E-3,5.164926541255888E-3,5.138718392489472E-3,5.113120979725938E-3,5.088119626024512E-3,5.06368388943812E-3,5.039766160208625E-3,5.016300518769223E-3,4.9932020978088465E-3,4.970367167587253E-3,4.947674119607726E-3,4.9249854641867374E-3,4.902150887435619E-3,4.879011338292716E-3,4.855404041955391E-3,4.831168267443009E-3,4.8061516184964015E-3,4.7802165721529954E-3,4.75324696056556E-3,4.72515408031382E-3,4.695882119966188E-3,4.665412619984988E-3,4.633767717794224E-3,4.601011982197867E-3,4.567252702508573E-3,4.532638565204805E-3,4.497356721147483E-3,4.46162831582142E-3,4.4257026204674865E-3,4.389849960319103E-3,4.3543536851559095E-3,4.319501465074427E-3,4.285576219590914E-3,4.252847000351778E-3,4.221560146825731E-3,4.191931021075179E-3,4.164136603049706E-3,4.1383091934352745E-3,4.1145314286933354E-3,4.09283276458261E-3,4.073187532293243E-3,4.055514617579803E-3,4.039678759805931E-3,4.025493416793258E-3,4.01272509417816E-3,4.001098996274766E-3,3.9903058201335995E-3,3.980009486489133E-3,3.969855580990611E-3,3.959480266700122E-3,3.948519424188501E-3,3.936617778292795E-3,3.923437780118388E-3,3.908668028396511E-3,3.892031034996468E-3,3.8732901641981288E-3,3.852255603266741E-3,3.8287892519213163E-3,3.8028084494038383E-3,3.7742884891174278E-3,3.743263901409555E-3,3.7098285141092813E-3,3.674134327449119E-3,3.636389264316864E-3,3.5968538780815074E-3,3.555837118190186E-3]],"pred":[-1.380838286046293E-3,-1.3848891583638778E-3,-1.383259980509477E-3,-1.3649820560728276E-3,-1.3179739249842282E-3,-1.2289268235705642E-3,-1.0833109117602824E-3,-8.654907383724986E-4,-5.308189304598088E-4,-2.6506889326305405E-4,-7.089223258116562E-5,4.984296576204805E-5,9.610728500630827E-5,6.775628700972369E-5,-3.443314407958198E-5,-2.0873744631511038E-4,-4.5247290636019066E-4,-7.61994809660882E-4,-1.1327097825171162E-3,-1.5591017007072772E-3,-2.0347713289585734E-3,-2.552489631195032E-3,-3.1042644571701583E-3,-3.6814200705155287E-3,-4.274688741217725E-3,-4.874313386512785E-3,-5.470160013129277E-3,-6.051838495831685E-3,-6.608830026821E-3,-7.1306193930840145E-3,-7.606830088080052E-3,-8.027360144790219E-3,-8.382516492531966E-3,-8.663145592874066E-3,-8.860758103077515E-3,-8.96764534990524E-3,-8.97698547320358E-3,-8.882937217148168E-3,-8.680719506116485E-3,-8.366675139998225E-3,-7.938317177312637E-3,-7.394356839942162E-3,-6.734712066207571E-3,-5.9604961540955514E-3,-5.073986267915664E-3,-4.078571923257446E-3,-2.978683910394686E-3,-1.779704458269915E-3,-4.878597735569201E-4,8.899035949894163E-4,2.3460568235482704E-3,3.872639303768022E-3,5.461419318328442E-3,7.1040624707645605E-3,8.79230528885211E-3,1.0518131315846002E-2,1.227394694614814E-2,1.4052754252170008E-2,1.5848318087466673E-2,1.7655324836500785E-2,1.946953031194898E-2,2.1287894473020597E-2,2.3108700849717723E-2,2.493165880340431E-2,2.6757987028945385E-2,2.859047700215811E-2,3.0433535392925037E-2,3.229320479259146E-2,3.417716243849944E-2,3.6094696952086336E-2,3.805666343454028E-2,4.0075417579353845E-2,4.216472975942964E-2,4.4339680322774244E-2,4.6616537581049444E-2,4.9012620195929335E-2,5.1546145856505965E-2,5.423606829462013E-2,5.710190480282229E-2,6.016355650086924E-2,6.344112364125754E-2,6.695471825315569E-2,7.07242763983923E-2,7.47693722547692E-2,7.910903615348064E-2,8.376157858132449E-2,8.874442201811239E-2,9.407394231839006E-2,9.976532116807557E-2,1.0583241095433116E-1,1.1228761318481117E-1,1.1914177138398085E-1,1.2640407918285446E-1,1.3408200410793714E-1,1.421812273681451E-1,1.507055997382225E-1,1.596571134460576E-1,1.6903588979159867E-1,1.788401820588379E-1,1.8906639313092E-1,1.9970910708317124E-1,2.107611339107358E-1,2.222135664466941E-1,2.3405584844374883E-1,2.4627585272729013E-1,2.5885996827979607E-1,2.717931950854604E-1,2.85059245548851E-1,2.986406513012232E-1,3.1251887422205793E-1,3.266744205297465E-1,3.410869568332757E-1,3.557354270845099E-1,3.705981694271685E-1,3.856530320021061E-1,4.0087748683798896E-1,4.1624874103031884E-1,4.31743844488784E-1,4.473397936120236E-1,4.630136303287298E-1,4.787425360236952E-1,4.9450391994600684E-1,5.102755017731573E-1,5.260353880787676E-1,5.417621425221688E-1,5.574348496448893E-1,5.730331722215354E-1,5.885374021705485E-1]} +{"cholesky":[[1.0488088481701516E0,9.983462763853087E-1,9.971948660405838E-1,9.962569870514585E-1,9.95245691709372E-1,9.938758189144798E-1,9.918647654899141E-1,9.889340600584038E-1,9.863008018781477E-1,9.814239128903309E-1,9.743431484733321E-1,9.651141501135281E-1,9.538076846989525E-1,9.405086973725397E-1,9.253151964637757E-1,9.083369918799128E-1,8.896943106526867E-1,8.69516315057808E-1,8.479395498252674E-1,8.25106345430617E-1,8.011632043114504E-1,7.762591961174596E-1,7.505443868207682E-1,7.241683247435408E-1,6.972786043711611E-1,6.700195262889018E-1,6.425308687907773E-1,6.149467837463306E-1,5.873948262592331E-1,5.599951245923527E-1,5.328596938435468E-1,5.060918940034972E-1,9.518858256460321E-1,4.403559638907732E-1,9.982024329990548E-1,9.966205341159102E-1,9.949671086435963E-1,9.929574863900363E-1,9.903102838094936E-1,9.867489634733181E-1,9.834890046029382E-1,9.779977052614807E-1,9.703190338848883E-1,9.605126495014892E-1,9.48653093195914E-1,9.348287975810272E-1,9.191409335227059E-1,9.01702116097625E-1,8.826349939399145E-1,8.62070747707032E-1,8.40147524345694E-1,8.170088341615384E-1,7.928019374060763E-1,7.676762462234563E-1,7.417817663950553E-1,7.152676014426042E-1,6.882805393716632E-1,6.609637397357409E-1,6.33455535860819E-1,6.058883640759408E-1,5.783878287321358E-1,5.51071908739928E-1,5.240503083896528E-1,4.9742395240552356E-1,9.507879989574666E-1,2.1155796954346645E-1,3.8890282405904747E-1,9.980587374251528E-1,9.960471191073174E-1,9.936803925906429E-1,9.906774995724066E-1,9.867626287333733E-1,9.831518667663292E-1,9.773140046651455E-1,9.692953907509122E-1,9.591579723987234E-1,9.46978460221211E-1,9.328473125429653E-1,9.168675598300923E-1,8.991534914067097E-1,8.798292288909632E-1,8.590272122778778E-1,8.368866254647221E-1,8.135517882552219E-1,7.891705415090166E-1,7.638926511563258E-1,7.37868255324268E-1,7.112463768829415E-1,6.84173521388729E-1,6.567923777592151E-1,6.29240636142773E-1,6.016499344319168E-1,5.741449417970548E-1,5.468425845664778E-1,5.19851416823149E-1,4.9327113529487604E-1,9.498937664280961E-1,2.0989864919011159E-1,1.2986640585712897E-1,3.6983659391542584E-1,9.97915229073093E-1,9.954747771117294E-1,9.923971832954881E-1,9.88406321730185E-1,9.847204229679979E-1,9.788043654240689E-1,9.707050482509328E-1,9.604849800554243E-1,9.482214361638279E-1,9.340054362881847E-1,9.179405623782859E-1,9.001416391032782E-1,8.807333014969042E-1,8.598484757823092E-1,8.376268002461542E-1,8.14213013256669E-1,7.897553351337906E-1,7.644038696163304E-1,7.383090491810221E-1,7.116201465140736E-1,6.844838720903792E-1,6.570430751590493E-1,6.294355625508715E-1,6.017930466995246E-1,5.742402311881227E-1,5.468940390761758E-1,5.198629863031894E-1,4.932466996695792E-1,9.489295341527383E-1,2.082282132312769E-1,1.2795990439546354E-1,9.790395769217386E-2,3.6085291790768437E-1,9.977719472347261E-1,9.949036634421792E-1,9.911178223119708E-1,9.876356402881383E-1,9.819141158158929E-1,9.739988375597842E-1,9.639511085087087E-1,9.518471171854396E-1,9.377769272706643E-1,9.218433052368341E-1,9.041604082970758E-1,8.848523571174188E-1,8.640517192762011E-1,8.418979303612812E-1,8.185356798713186E-1,7.941132887480834E-1,7.687811044459943E-1,7.426899379917177E-1,7.159895655626723E-1,6.888273147910644E-1,6.613467533595486E-1,6.336864945802454E-1,6.059791316266061E-1,5.783503090022356E-1,5.509179367630067E-1,5.237915500332686E-1,4.9707181354014734E-1,9.476234116907833E-1,2.0648793296188736E-1,1.260141463612267E-1,9.633082159422765E-2,8.311298870330752E-2,3.567991619851197E-1,9.976289310613308E-1,9.943339325389622E-1,9.91339344464842E-1,9.86091742466748E-1,9.786334850376434E-1,9.690228308526938E-1,9.573331458635047E-1,9.436519248940329E-1,9.280796468081213E-1,9.107284851352506E-1,8.917208982988603E-1,8.711881252465042E-1,8.492686133082544E-1,8.261064055033798E-1,8.018495142884102E-1,7.766483079227584E-1,7.506539342674614E-1,7.240168049882169E-1,6.968851608765735E-1,6.694037364117976E-1,6.417125388445882E-1,6.139457540784692E-1,5.862307885406463E-1,5.586874531531141E-1,5.314272925128398E-1,5.045530595351031E-1,9.457059474854856E-1,2.0462127132961727E-1,1.2399594574630425E-1,9.470226369887053E-2,8.244135012699529E-2,7.736586042465483E-2,3.5587192967247533E-1,9.974862195407934E-1,9.952683661138827E-1,9.907814803640083E-1,9.840626987897277E-1,9.751653046898169E-1,9.641579945836999E-1,9.511239535782791E-1,9.361597578491718E-1,9.193741253791287E-1,9.0088653852732E-1,8.808257638409832E-1,8.59328295735186E-1,8.365367512460465E-1,8.12598243015398E-1,7.876627570163635E-1,7.618815603217042E-1,7.354056625064681E-1,7.083843521314696E-1,6.809638272514226E-1,6.532859361140233E-1,6.254870412497011E-1,5.976970170819167E-1,5.700383880977726E-1,5.426256115861873E-1,5.155645060464954E-1,9.429116294964417E-1,2.0257418051224285E-1,1.2187462288118832E-1,9.29950606719435E-2,8.169483546114234E-2,7.812113181859504E-2,7.761318585548678E-2,3.571821542883523E-1,9.988518900108769E-1,9.954190581196096E-1,9.897313559515383E-1,9.81835061591001E-1,9.71792230485948E-1,9.596798485192447E-1,9.455888040855486E-1,9.296226991893284E-1,9.118965222361909E-1,8.925352072699224E-1,8.716721058737622E-1,8.494473987878011E-1,8.260064744955974E-1,8.014983016210725E-1,7.760738209874848E-1,7.498843816748697E-1,7.230802434345562E-1,6.958091654530348E-1,6.682150987833664E-1,6.404369968653992E-1,6.126077555222567E-1,5.848532907341127E-1,5.572917594311539E-1,5.300329255892923E-1,9.404009163337426E-1,2.0059840030284964E-1,1.1980311832034857E-1,9.132606538936672E-2,8.09748518134158E-2,7.888977664191144E-2,8.035471974681917E-2,8.228929752966851E-2,3.5595537363197827E-1,9.988536933972448E-1,9.954268716203156E-1,9.897502304832465E-1,9.81870802250616E-1,9.718512887767433E-1,9.597691993983815E-1,9.457158107937641E-1,9.297949691077079E-1,9.12121757201779E-1,8.928210518676031E-1,8.720259972060331E-1,8.498764211100407E-1,8.265172218986714E-1,8.020967516550934E-1,7.767652217621105E-1,7.506731545564874E-1,7.239699030041512E-1,6.968022579062401E-1,6.693131594619738E-1,6.416405271227767E-1,6.13916218657903E-1,5.862651262977375E-1,5.588044148050514E-1,9.357509851319555E-1,1.9817968492805021E-1,1.1747589221408314E-1,8.946253075707929E-2,8.007369907144662E-2,7.946683500584431E-2,8.288427480587283E-2,8.713487322601209E-2,8.509593584780317E-2,3.5897129976724407E-1,9.988558100916567E-1,9.954359317213732E-1,9.897718883023335E-1,9.819114412252787E-1,9.719179058618361E-1,9.598692750590352E-1,9.458571676877856E-1,9.299856228021106E-1,9.123697624259818E-1,8.931343478615462E-1,8.724122556758167E-1,8.503429001608896E-1,8.270706290825097E-1,8.027431189579683E-1,7.775097949776758E-1,7.515202990599902E-1,7.249230274722614E-1,6.978637570375075E-1,6.704843762564766E-1,6.42921734792746E-1,6.153066217776846E-1,5.87762880373681E-1,9.289997411570858E-1,1.9533594478570854E-1,1.1490970803456522E-1,8.741785944135132E-2,7.899811837962627E-2,7.984887779160454E-2,8.518495196709994E-2,9.17167106710492E-2,9.487727963912801E-2,9.39215217185593E-2,3.631105877981804E-1,9.988582388761283E-1,9.954462332290304E-1,9.897963170824723E-1,9.819569556310943E-1,9.719920447573411E-1,9.599800209225353E-1,9.460127993201629E-1,9.301945610779254E-1,9.126404126541883E-1,8.934749423486132E-1,8.728307000090213E-1,8.508466265586875E-1,8.276664599004646E-1,8.034371431036945E-1,7.783072595897209E-1,7.524255183582494E-1,7.259393102069966E-1,6.989933534663272E-1,6.717284450794061E-1,6.44280329989664E-1,6.167786988334732E-1,9.202002364848036E-1,1.9208798011523934E-1,1.121228367774541E-1,8.520658770023318E-2,7.775605757089032E-2,8.003401885695097E-2,8.724186950285168E-2,9.600433681887907E-2,1.0429880176496036E-1,1.0707601700708445E-1,1.0304231627377945E-1,3.66416951023689E-1,9.988609783501585E-1,9.954577702270767E-1,9.89823502897527E-1,9.820073198002579E-1,9.720736642446255E-1,9.601013765057033E-1,9.461826225041332E-1,9.304216750594677E-1,9.129335709624108E-1,8.93842668782331E-1,8.732811333882342E-1,8.513873736092277E-1,8.283044593074766E-1,8.041785434126535E-1,7.791573132168064E-1,7.533884935101394E-1,7.270184220193645E-1,7.001907151665141E-1,6.730450394774814E-1,6.45716001117991E-1,9.094199446954067E-1,1.8845921274076977E-1,1.0913482694744828E-1,8.284420261576221E-2,7.635656768372633E-2,8.002192903313421E-2,8.904233306924039E-2,9.997014116132927E-2,1.1329788337182257E-1,1.1977225516088724E-1,1.1794063818924215E-1,1.0920484804454826E-1,3.680910481807598E-1,9.98864026931642E-1,9.954705360806387E-1,9.898534302302388E-1,9.820625052964183E-1,9.721627188936215E-1,9.602332754525789E-1,9.463665463531333E-1,9.306668462353024E-1,9.132490888048878E-1,8.942373470175393E-1,8.737633434873971E-1,8.519648973216633E-1,8.289843533467189E-1,8.049670188969767E-1,7.800596320313004E-1,7.544088832824833E-1,7.281600109015266E-1,7.01455487105761E-1,6.74433810157735E-1,8.967398578048209E-1,1.8447538879007783E-1,1.0596626283662326E-1,8.034695086447088E-2,7.48096869259535E-2,7.981382849020757E-2,9.057597191749864E-2,1.0358968804579946E-1,1.2181653258009509E-1,1.3192672512749448E-1,1.323078240072696E-1,1.2444318710080576E-1,1.1151294117428191E-1,3.681981515112831E-1,9.988673828579022E-1,9.954845234404425E-1,9.898860819819234E-1,9.821224809317344E-1,9.722591590885858E-1,9.603756455693387E-1,9.465644723241518E-1,9.309299465078708E-1,9.135868060661796E-1,8.946587833593667E-1,8.742771025102154E-1,8.525789364270628E-1,8.297058491372667E-1,8.058022482047306E-1,7.810138706461787E-1,7.554863239645916E-1,7.293637017536072E-1,7.02787290869096E-1,8.822534230886454E-1,1.801642579243263E-1,1.0263851548022593E-1,7.773164248998812E-2,7.312631426710936E-2,7.941245782749877E-2,9.18348391855569E-2,1.0684197687671246E-1,1.2980203864774345E-1,1.434620993832832E-1,1.4605049708771944E-1,1.3911790712968197E-1,1.2614728847632758E-1,1.1059800870976823E-1,3.6719297597085576E-1,9.98871044186844E-1,9.954997242475443E-1,9.899214394831746E-1,9.821872127856176E-1,9.723629310562987E-1,9.605284088624009E-1,9.467762942649272E-1,9.312108382474459E-1,9.139465511178199E-1,8.951067706166456E-1,8.74822167232482E-1,8.53229212399882E-1,8.304686348631618E-1,8.066838895634166E-1,7.820196619984708E-1,7.566204291761711E-1,7.306290960999915E-1,8.660653401853742E-1,1.7555523492588318E-1,9.917349069169581E-2,7.501545313948998E-2,7.131807498866959E-2,7.882202867139515E-2,9.281347497956867E-2,1.0970964627849411E-1,1.3720753415155584E-1,1.5430808998862247E-1,1.59082503225814E-1,1.5313464281088415E-1,1.4022579015606715E-1,1.2416286252607184E-1,1.0761909796023673E-1,3.655719413180943E-1,9.988750087982254E-1,9.955161297385232E-1,9.899594825055664E-1,9.822566642251502E-1,9.724739768966897E-1,9.606914815797104E-1,9.470018984649996E-1,9.315093743504493E-1,9.143281408795864E-1,8.955810881598869E-1,8.753982790485051E-1,8.539154294826323E-1,8.312723797642644E-1,8.076115807233076E-1,7.830766172300198E-1,7.57810789669436E-1,8.482902410719829E-1,1.7067904966147157E-1,9.559337849228777E-2,7.221572814241288E-2,6.93971806113453E-2,7.804815496239319E-2,9.350893176767738E-2,1.1217911957950884E-1,1.4399245672134833E-1,1.6440218040062834E-1,1.7132584423214192E-1,1.6640664498984276E-1,1.5365849925682853E-1,1.3721046127165154E-1,1.2000430200364434E-1,1.0364776354602073E-1,3.637257315213025E-1,9.988792743950471E-1,9.95533730451135E-1,9.90000189274349E-1,9.823307959271713E-1,9.725922346158846E-1,9.608647742552023E-1,9.472411637106224E-1,9.318253983021592E-1,9.147313808854632E-1,8.960815019839369E-1,8.760051640218398E-1,8.546372747140429E-1,8.321167341293065E-1,8.085849389011703E-1,7.841843255662585E-1,8.290512771463038E-1,1.6556739146562263E-1,9.19204080665371E-2,6.934979165031484E-2,6.737628565086648E-2,7.709776647717297E-2,9.392076241520908E-2,1.1424069029417347E-1,1.501229042290935E-1,1.7369022244628143E-1,1.8271146747983294E-1,1.7885570280186705E-1,1.663629061221123E-1,1.4965738206762974E-1,1.319299314490676E-1,1.1495124276805806E-1,9.946070650342467E-2,3.6191613821837704E-1,9.988838385050591E-1,9.955525162304208E-1,9.900435364821286E-1,9.824095659020176E-1,9.727176381616578E-1,9.610481917564327E-1,9.474939613435399E-1,9.321587442438397E-1,9.151560653543657E-1,8.966077647754507E-1,8.766425329405354E-1,8.553944179610274E-1,8.330013292915796E-1,8.09603560724951E-1,8.084786387001414E-1,1.602525538791924E-1,8.817661210172825E-2,6.643476382820561E-2,6.526834362899342E-2,7.597900645048308E-2,9.405097196918631E-2,1.1588854759636151E-1,1.5557187978964582E-1,1.8212689103678856E-1,1.9317990051831208E-1,1.9041291552010448E-1,1.7826480484242593E-1,1.6142706763408168E-1,1.433189163963001E-1,1.2586189678044818E-1,1.0987637915794825E-1,9.554601738797078E-2,3.6029906424408525E-1,9.988886984823842E-1,9.955724762352689E-1,9.900894993035262E-1,9.824929295189088E-1,9.728501174612797E-1,9.61241633335372E-1,9.477601553236399E-1,9.325092370443291E-1,9.156019772657028E-1,8.971596159853163E-1,8.773100813771157E-1,8.561865119547788E-1,8.33925777627709E-1,7.867080325172441E-1,1.5476708543772724E-1,8.438360401835868E-2,6.348738879904155E-2,6.308646468787789E-2,7.470111542837202E-2,9.390393502980111E-2,1.1712074305417024E-1,1.6031942540046168E-1,1.8967599247295144E-1,2.0268172348150112E-1,2.0101930395171858E-1,1.8929901403270671E-1,1.7245063007990113E-1,1.541002757470896E-1,1.3630763656140665E-1,1.1996777226688098E-1,1.0529460285744686E-1,9.217275065574995E-2,3.5895406756517473E-1,9.988938515092547E-1,9.955935989454241E-1,9.901380514108027E-1,9.825808395329648E-1,9.729895984617465E-1,9.614449926823518E-1,9.480396022954849E-1,9.328766923761163E-1,9.160688884398581E-1,8.97736781906174E-1,8.780074897535224E-1,8.57013192331332E-1,7.63879143191091E-1,1.4914345184645117E-1,8.056237118226527E-2,6.052387570486829E-2,6.0843777027524436E-2,7.327430369332122E-2,9.348628120841368E-2,1.1793910109975744E-1,1.6435264546449932E-1,1.9631062545585493E-1,2.1117787571287794E-1,2.1062625493638204E-1,1.9940994273643023E-1,1.8266752015329366E-1,1.6420987369354512E-1,1.4622162655036142E-1,1.2966597817574016E-1,1.147843712650352E-1,1.0146396580790043E-1,8.945843542878774E-2,3.579078319671605E-1,9.988992945978645E-1,9.956158721689399E-1,9.901891649904444E-1,9.826732461138415E-1,9.731360031723769E-1,9.616581579831577E-1,9.483321516587309E-1,9.332609167959439E-1,9.165565596236659E-1,8.983389757551751E-1,8.787344234112554E-1,7.40134103055855E-1,1.43413714417214E-1,7.673308672180451E-2,5.755975487162852E-2,5.8553294213573685E-2,7.170961474951758E-2,9.280675174994493E-2,1.1834907680716346E-1,1.6766562373734573E-1,2.0201319708582932E-1,2.1863979668440248E-1,2.1919579626700433E-1,2.0855199583378511E-1,1.9202605344435883E-1,1.7359105533013167E-1,1.5554301825671407E-1,1.3890654662038132E-1,1.239478290450957E-1,1.1055560216162309E-1,9.847209882933211E-2,8.741841237581299E-2,3.5715056537709716E-1,9.989050245923325E-1,9.956392830500693E-1,9.90242810760698E-1,9.827700968759707E-1,9.732892497097603E-1,9.618810119792548E-1,9.48637645642436E-1,9.336617078299709E-1,9.170647405809688E-1,8.989658977621333E-1,7.15615994401875E-1,1.376092290948305E-1,7.291494207021289E-2,5.460975066198998E-2,5.6227790192462095E-2,7.00187824411875E-2,9.187603087943008E-2,1.1835956551951889E-1,1.702592393572444E-1,2.0677529912052245E-1,2.2504940480011248E-1,2.2670070304786313E-1,2.1668981692895725E-1,2.0048378833950384E-1,1.8219515307693204E-1,1.6421757635207657E-1,1.4763022031310605E-1,1.3272124173895203E-1,1.1938008763903359E-1,1.0733727236350674E-1,9.629608881667351E-2,8.599935389214512E-2,3.566476263354939E-1,9.989110381707773E-1,9.956638180775891E-1,9.902989579900435E-1,9.828713369103884E-1,9.734492523450408E-1,9.621134320311392E-1,9.489559193832674E-1,9.340788540635304E-1,9.17593170188338E-1,6.904674059596193E-1,1.3176036978449934E-1,6.912600182932994E-2,5.168767218373334E-2,5.3879683610627255E-2,6.821408429902513E-2,9.070655580888894E-2,1.1798266968361112E-1,1.7214088950390494E-1,2.1059745249438452E-1,2.303989209561024E-1,2.3312444002963245E-1,2.2379837020461918E-1,2.0800775384878328E-1,1.899818586151428E-1,1.7219818862339717E-1,1.5578357438587342E-1,1.4104539221497817E-1,1.2787303939710967E-1,1.1598520116188187E-1,1.0506718821483328E-1,9.484200238094057E-2,8.510318557960882E-2,3.5634870410263697E-1,9.98917331847502E-1,9.956894630935506E-1,9.903575745165966E-1,9.82976908818138E-1,9.736159215535197E-1,9.623552901847997E-1,9.49286801007607E-1,9.345121352355193E-1,6.648290635492802E-1,1.2589627902786754E-1,6.538308202120047E-2,4.8806322602168384E-2,5.152093277154805E-2,6.630819367140865E-2,8.931230960604147E-2,1.1723342889891179E-1,1.7332412784724377E-1,2.1348873051306388E-1,2.346905466958455E-1,2.3846094772376641E-1,2.298628660658278E-1,2.1457452866864463E-1,1.969194580742814E-1,1.7944525392548086E-1,1.6331955035885462E-1,1.4886625132119113E-1,1.3597405905799545E-1,1.2434988928563653E-1,1.1366109572960029E-1,1.0361051521357793E-1,9.397266367486255E-2,8.460634007174693E-2,3.561959164658303E-1,9.989239019752856E-1,9.957162033024535E-1,9.904186267684248E-1,9.830867527452284E-1,9.73789164066557E-1,9.626064532412784E-1,9.496301117175631E-1,6.388385523805215E-1,1.2004464838269881E-1,6.170165227292862E-2,4.5977427394785435E-2,4.916294228714746E-2,6.431403310227413E-2,8.770860127898925E-2,1.1612951966059552E-1,1.738282292596811E-1,2.1546627317608769E-1,2.3793600938648768E-1,2.4271428302194936E-1,2.3487853846635978E-1,2.201701759171919E-1,2.0298493118853927E-1,1.859269450808475E-1,1.7019787788614266E-1,1.561355506831375E-1,1.4362744593211504E-1,1.3236893945761802E-1,1.2200966171580907E-1,1.1223215809485865E-1,1.0279131822381474E-1,9.352975328412873E-2,8.437677819025881E-2,3.5613115694206543E-1,9.98930744747783E-1,9.957440232808342E-1,9.90482079784771E-1,9.83200806419131E-1,9.739688829257528E-1,9.628667828293157E-1,6.126291458274744E-1,1.1423153015928568E-1,5.8095761980567526E-2,4.321158149519946E-2,4.6816482196317566E-2,6.224463127156261E-2,8.59118374725666E-2,1.14690931568097E-1,1.7367769225537036E-1,2.1655470671344032E-1,2.4015598899609825E-1,2.4589812756639837E-1,2.3885028454582183E-1,2.2479004080945614E-1,2.0816391797666928E-1,1.9161934645165382E-1,1.763853801906622E-1,1.6281124984916065E-1,1.5078281690328693E-1,1.3998431351249727E-1,1.3004808683691638E-1,1.2063649103228674E-1,1.1148440823570187E-1,1.024174196671833E-1,9.335298044432189E-2,8.428902018560853E-2,3.561023145166233E-1,9.989378562020277E-1,9.95772906987265E-1,9.905478972381655E-1,9.833190051867977E-1,9.741549775393874E-1,5.863287526790256E-1,1.084811814741481E-1,5.4577990031332076E-2,4.051821491017107E-2,4.4491620040706385E-2,6.0112985623633396E-2,8.393929010769421E-2,1.1293962688487165E-1,1.729016912781979E-1,2.1678548362420821E-1,2.4137944273856599E-1,2.480351791857619E-1,2.41792179547583E-1,2.2843842106019502E-1,2.124505591236807E-1,1.9650646857624993E-1,1.818561617583479E-1,1.688578925792515E-1,1.5739562411674912E-1,1.4714300124566038E-1,1.3771572823651354E-1,1.2875629397982669E-1,1.1997941726740673E-1,1.1119300253706225E-1,1.0230160615493071E-1,9.329648009924152E-2,8.42361638176644E-2,3.560677564067851E-1,9.989452322210387E-1,9.95802837772754E-1,9.906160414574179E-1,9.834412820541782E-1,5.600589919545932E-1,1.0281594091498139E-1,5.115941723970596E-2,3.790557606564619E-2,4.21976661134795E-2,5.79319325815248E-2,8.18088641327306E-2,1.1089919027869133E-1,1.715334912894976E-1,2.1619615927114766E-1,2.4164284505289374E-1,2.4915644329820869E-1,2.437268818930601E-1,2.3112812195821875E-1,2.1584721859143696E-1,2.005801447525304E-1,1.8659167944273022E-1,1.7424684969390436E-1,1.6342756421194868E-1,1.5379758785625564E-1,1.4495681362677454E-1,1.3652841210788458E-1,1.282070103359254E-1,1.197823942886237E-1,1.1114533827826736E-1,1.0227923373446213E-1,9.324124176249186E-2,8.413767756994776E-2,3.559986605388377E-1,9.989528685365284E-1,9.958337983915431E-1,9.906864734514724E-1,5.339344014587326E-1,9.725613748513984E-2,4.7849620279833735E-2,3.538073185113855E-2,3.994313183686925E-2,5.571402698851961E-2,7.953886930597033E-2,1.0859447535741892E-1,1.6960983711827687E-1,2.148296214203739E-1,2.4098936109438737E-1,2.4930044227359138E-1,2.4468494473024335E-1,2.3287990981039453E-1,2.1836409900871864E-1,2.0383981670127121E-1,1.905807005660578E-1,1.789564484697836E-1,1.688468754912058E-1,1.5990671284237684E-1,1.5172105275397296E-1,1.4389450698479564E-1,1.361019079518395E-1,1.2811469252545213E-1,1.1980913880617688E-1,1.1115970107182595E-1,1.0222088384012779E-1,9.310232474558892E-2,8.394239704311111E-2,3.5587920882429636E-1,9.989607607317095E-1,9.95865771012293E-1,5.080617833966817E-1,9.182003092374635E-2,4.465668557956558E-2,3.294958309054693E-2,3.773570098437202E-2,5.347143214162401E-2,7.714779960344435E-2,1.0605125425902925E-1,1.6717032975219243E-1,2.1273328903977523E-1,2.3946797214893564E-1,2.4851236134192073E-1,2.447040512426887E-1,2.3372187878095832E-1,2.200187620523452E-1,2.0629221840557893E-1,1.9381915383132087E-1,1.8297199101889122E-1,1.7362852203432655E-1,1.6543541593128103E-1,1.579641384584538E-1,1.508017026622964E-1,1.436036632738071E-1,1.361230904307706E-1,1.282212310064762E-1,1.1986264887463216E-1,1.1109796903388626E-1,1.0203882015788455E-1,9.283046374493284E-2,8.362711422068737E-2,3.5570506241865574E-1,9.989689042441995E-1,4.8253968765278027E-1,8.652378198885732E-2,4.1587241384208405E-2,3.0616893974183674E-2,3.558221324792104E-2,5.121582149273538E-2,7.465412345984257E-2,1.032958760761346E-1,1.6425680119503475E-1,2.0995829621352619E-1,2.3713257116436423E-1,2.4684314975258836E-1,2.4382819150363064E-1,2.3368874704290443E-1,2.2083556730534967E-1,2.0795096885953207E-1,1.9630988082994172E-1,1.8628566635452073E-1,1.7775426628458854E-1,1.7035536833294446E-1,1.6364813237144155E-1,1.5720311852073787E-1,1.5065733119621366E-1,1.4374566738335695E-1,1.3631399326882154E-1,1.283161665007761E-1,1.197977851007045E-1,1.1087114769163502E-1,1.0168705659397625E-1,9.24087888878468E-2,8.319193229943493E-2,3.554807706509569E-1],[],[],[],[4.574580308014191E-1,8.13814508534836E-2,3.864650600197933E-2,2.8386333842311314E-2,3.348865946262215E-2,4.8958292800652295E-2,7.207608761728121E-2,1.003549393160897E-1,1.609126987304168E-1,2.0655867623317054E-1,2.3404104596248082E-1,2.4434859555764948E-1,2.4210679870667315E-1,2.328210986172364E-1,2.208450439556598E-1,2.0883608574451865E-1,1.98062297602596E-1,1.8889636287680608E-1,1.8121263397725101E-1,1.7464499021448082E-1,1.6874173309827997E-1,1.6305828365747962E-1,1.5721402114253627E-1,1.5092606872137673E-1,1.4402475082096441E-1,1.3645255140749085E-1,1.2824898729298692E-1,1.1952573881214383E-1,1.1043777829841137E-1,1.0115611489510568E-1,9.184621027824069E-2,8.265389010256845E-2,4.3289784662289427E-1,7.640502140244285E-2,3.583835010792846E-2,2.626052961416736E-2,3.146018764402009E-2,4.670929522840551E-2,6.943153689166295E-2,9.725498294089883E-2,1.571824884506777E-1,2.0259055983498725E-1,2.302543666994424E-1,2.4108839165448462E-1,2.395938622299818E-1,2.3116458731970216E-1,2.2008321018108842E-1,2.0897343297280588E-1,1.9909197705736753E-1,1.9080938976045644E-1,1.8399877740112297E-1,1.7828945773667884E-1,1.7322042744749874E-1,1.6833343050594246E-1,1.6323132835179788E-1,1.5761406659034077E-1,1.512964545351374E-1,1.442090910731866E-1,1.3638446588066275E-1,1.279324062612948E-1,1.1901068437893753E-1,1.0979666727642261E-1,1.0046440445326174E-1,9.116928258386134E-2,4.0893116187097805E-1,7.160444893431243E-2,3.3165370906637966E-2,2.4241127106490522E-2,2.950111886666938E-2,4.4478569602550866E-2,6.673775168416617E-2,9.402219982017071E-2,1.5311108677600482E-1,1.9811140022095863E-1,2.2583569283511964E-1,2.37125209628465E-1,2.363470342362262E-1,2.2876911889165139E-1,2.1859085516804902E-1,2.083941155931682E-1,1.9942016405389995E-1,1.9203611716566543E-1,1.8611424483086655E-1,1.8128060521284028E-1,1.7706652780551824E-1,1.73001668171013E-1,1.686736414245532E-1,1.637659968838894E-1,1.5807823911594052E-1,1.5152873103469006E-1,1.4414210978437292E-1,1.3602518678977812E-1,1.273371869694584E-1,1.1826044199258517E-1,1.0897625202698183E-1,9.964834349705452E-2,3.856209893112823E-1,6.69877285670583E-2,3.0628975932736717E-2,2.232885947878242E-2,2.7614971918265965E-2,4.2275101790266605E-2,6.40113045798699E-2,9.068217568831886E-2,1.4874332744424615E-1,1.9317923598148748E-1,2.2084951331381497E-1,2.3252379654208657E-1,2.3242674542446162E-1,2.2568802669952043E-1,2.1641279845640857E-1,2.07133835753341E-1,1.990732356197039E-1,1.925935463008566E-1,1.8756666550827486E-1,1.836167298954364E-1,1.8026910106630473E-1,1.7704303858538697E-1,1.7351232675507444E-1,1.6934507030736634E-1,1.6432585605431077E-1,1.583606218096877E-1,1.5146545658657587E-1,1.4374308087776932E-1,1.3535286895864507E-1,1.2648072791187548E-1,1.173138443730891E-1,1.0802301477934588E-1,3.630214286352342E-1,6.256098151595686E-2,2.822947429737685E-2,2.052362107497679E-2,2.5804495600162004E-2,4.0107088911348204E-2,6.126793689952102E-2,8.725965594617092E-2,1.441234701389168E-1,1.8785200138794725E-1,2.1536083191093125E-1,2.273501081843139E-1,2.2789534418791813E-1,2.219772553914222E-1,2.1359714072480937E-1,2.0523222327864593E-1,1.9808211908165307E-1,1.9250382113463332E-1,1.8836936076234884E-1,1.8530230853152518E-1,1.8282379655354428E-1,1.8044446096842387E-1,1.7772579314377873E-1,1.7432155848109285E-1,1.7000197975732842E-1,1.646605405493962E-1,1.583042222219767E-1,1.5103068030121766E-1,1.429981970573856E-1,1.3439489131823448E-1,1.2541246775007395E-1,1.1622749738507802E-1,3.411778647593642E-1,5.832855635410884E-2,2.5966173262573927E-2,1.8824544998133377E-2,2.4071707511324425E-2,3.798191788957632E-2,5.852245561539043E-2,8.377834190745044E-2,1.3929475558192841E-1,1.8218689179685157E-1,2.0943440782519163E-1,2.216704904857805E-1,2.2281627185167405E-1,2.176945656498842E-1,2.1019451926975893E-1,2.0273215398415054E-1,1.9648168088806656E-1,1.9179369398733406E-1,1.8854089273014532E-1,1.863476361290428E-1,1.8473258208231214E-1,1.8319957215320068E-1,1.8129944229599737E-1,1.7867285867990731E-1,1.750763881392174E-1,1.7039118625784372E-1,1.6461470667080313E-1,1.5783867736800808E-1,1.502191252060152E-1,1.4194506210860708E-1,1.3321135934748637E-1,1.2419906309241886E-1,3.2012725224010663E-1,5.429314237349466E-2,2.3837478137321455E-2,1.7230082850992742E-2,2.2417938146581634E-2,3.5906155664357835E-2,5.578865061779953E-2,8.026071738031922E-2,1.3429901058608001E-1,1.7623979015681823E-1,2.0313405965396256E-1,2.1555091888440042E-1,2.172532849263037E-1,2.1289877173069122E-1,2.062573803333133E-1,1.9967906812466868E-1,1.9431009858943762E-1,1.904939573429216E-1,1.881045626739449E-1,1.8676839833115022E-1,1.860033986728376E-1,1.853084721012931E-1,1.8422551301985726E-1,1.8238344321666097E-1,1.7952602161390713E-1,1.755223502426951E-1,1.7036007490352317E-1,1.6412425258961363E-1,1.5696758261305702E-1,1.4907871357875396E-1,1.4065436831926578E-1,1.3187878477698745E-1,2.9989847405874603E-1,5.045589223121271E-2,2.1840993632845012E-2,1.5738085195273806E-2,2.0843879158757874E-2,3.388555023085052E-2,5.307923193318196E-2,7.672790580883235E-2,1.29176305273952E-1,1.7006475888225636E-1,1.9652203893676665E-1,2.0905630345195897E-1,2.1126973347691488E-1,2.0764902188389903E-1,2.0183927914671473E-1,1.9612030044359888E-1,1.91608227870642E-1,1.8863885403148736E-1,1.8708787109638464E-1,1.8658518940453253E-1,1.86649745438566E-1,1.867773853236999E-1,1.865028287007573E-1,1.8544470157178625E-1,1.8333492680517838E-1,1.8003096606025282E-1,1.755105150779761E-1,1.6985134038853528E-1,1.632018435596766E-1,1.557491304734302E-1,1.4769051409887435E-1,1.392121752063944E-1,2.8051276284081544E-1,4.681655118359473E-2,1.9973624982316827E-2,1.434588142092011E-2,1.9349634674919892E-2,3.192504155578732E-2,5.0405786153552755E-2,7.319955759147058E-2,1.2396466345354312E-1,1.637135996961654E-1,1.8965847754049664E-1,2.0224986562128755E-1,2.0492790282793175E-1,2.0200413006853593E-1,1.9699421713069074E-1,1.9210443215196712E-1,1.8841897572139948E-1,1.862654774707735E-1,1.8552195175426267E-1,1.858229881203377E-1,1.8669020682419496E-1,1.8761824995890874E-1,1.8813645902974746E-1,1.8785468511419295E-1,1.8649409334102587E-1,1.8390104552828615E-1,1.800432785050161E-1,1.7499077509787828E-1,1.6888677883389408E-1,1.6191576271196628E-1,1.542744369636078E-1,1.461497269548139E-1,2.6198417264481194E-1,4.3373590371920026E-2,1.823167731604851E-2,1.3050357867654077E-2,1.7934774616254062E-2,3.0028781326767298E-2,4.777875104512526E-2,6.969376665356669E-2,1.1869982602078959E-1,1.5723548248472127E-1,1.82600911334309E-1,1.9519259043593498E-1,1.9828842395482485E-1,1.9602196564895805E-1,1.9177602417661893E-1,1.876806738988046E-1,1.8478668983575539E-1,1.8341317295651796E-1,1.834409912916101E-1,1.8451060376331863E-1,1.861479346774498E-1,1.8784824692629315E-1,1.8913730798809827E-1,1.8961776562983132E-1,1.890011937926722E-1,1.8712350936230815E-1,1.8394260812428695E-1,1.795203219259441E-1,1.739939912078345E-1,1.6754446482038304E-1,1.603667384434286E-1,1.52647348609983E-1,2.443200897578164E-1,4.012434181900942E-2,1.6610951979979256E-2,1.1848033200064157E-2,1.6598389045500844E-2,2.8200160433889634E-2,4.520740706295805E-2,6.622701488425393E-2,1.1341506625369202E-1,1.5067664277791212E-1,1.7540388090061348E-1,1.8794275642360533E-1,1.9140975610153313E-1,1.8975890604609932E-1,1.862377923736515E-1,1.8289828742854713E-1,1.8075657318806462E-1,1.801229500952252E-1,1.808816455873254E-1,1.8268010417339856E-1,1.8505009762167934E-1,1.874892818867416E-1,1.8952164074328004E-1,1.907442198656764E-1,1.9086023813743808E-1,1.896959226148905E-1,1.8719956412856534E-1,1.8342459968696573E-1,1.7850183968246042E-1,1.7260762354174397E-1,1.6593421168283562E-1,1.586666949725505E-1,2.2752177143876331E-1,3.706513301755069E-2,1.5106838687231646E-2,1.0735130199224861E-2,1.5339142652091235E-2,2.6441843052504143E-2,4.269988430955878E-2,6.28141426604756E-2,1.081410549855653E-1,1.4408014619593423E-1,1.6811860848140323E-1,1.8055554350734856E-1,1.8434774344693128E-1,1.832693556537209E-1,1.804313659890825E-1,1.778060522046582E-1,1.7637413148557896E-1,1.7643691542018825E-1,1.778824630804322E-1,1.8036623713850566E-1,1.8342730988337835E-1,1.8656743272461054E-1,1.893105624060988E-1,1.912497529134246E-1,1.9208115506331505E-1,1.9162214634829638E-1,1.898117569173625E-1,1.86694903903109E-1,1.8239535925200004E-1,1.7708417830351103E-1,1.709499642013597E-1,1.6417539136227266E-1,2.115849022202602E-1,3.419141923043301E-2,1.3714402594043893E-2,9.707643294313832E-3,1.415532857966292E-2,2.4755806192278833E-2,4.026318333743828E-2,5.946834337190112E-2,1.0290577290418541E-1,1.3748571709603158E-1,1.6079274898914828E-1,1.7308271784330206E-1,1.7715524605881539E-1,1.7660533275516663E-1,1.7440689099222734E-1,1.7245178185212703E-1,1.7168465988819853E-1,1.723977330643824E-1,1.7448332433770272E-1,1.7760585565659254E-1,1.8131305115447416E-1,1.8511237494554197E-1,1.8852946155843736E-1,1.9115497351455882E-1,1.9267931299861313E-1,1.9291191784534947E-1,1.9178299873544227E-1,1.89328940339607E-1,1.8566608465158765E-1,1.8095954115172858E-1,1.7539343760825457E-1,1.6914715438880526E-1,1.965001581829894E-1,3.149791187303381E-2,1.2428465587800355E-2,8.76140131308587E-3,1.3044920900429488E-2,2.3143383597882792E-2,3.790320810657932E-2,5.620117963022153E-2,9.773446662283175E-2,1.309296277281175E-1,1.5347021173370734E-1,1.6557239113164066E-1,1.6988184394556588E-1,1.6981612472058155E-1,1.6821242597009667E-1,1.6688189387234753E-1,1.6673277405401332E-1,1.6804812012333492E-1,1.7072490600584328E-1,1.7443735660961393E-1,1.78743088273095E-1,1.8315679679965363E-1,1.8720743111731714E-1,1.904848342919487E-1,1.9267499396008095E-1,1.9358037217116283E-1,1.9312288615907014E-1,1.9133048013396775E-1,1.8831178792585743E-1,1.8422542438642062E-1,1.7925033066982207E-1,1.735618135681651E-1,1.8225377051938044E-1,2.8978701600242875E-2,1.12436812620696E-2,7.89212507737754E-3,1.20056251428895E-2,2.16053129273188E-2,3.562480936426188E-2,5.3022618691124825E-2,9.26496447075042E-2,1.2444464346289257E-1,1.4619104853930565E-1,1.5806885080171143E-1,1.6257361176274115E-1,1.629480104519215E-1,1.6189361494467838E-1,1.611410347447352E-1,1.6156198925119333E-1,1.634303820665612E-1,1.6664817608504975E-1,1.7090014128531208E-1,1.7575490853081813E-1,1.8073581512972114E-1,1.8537667849136538E-1,1.8926804953554854E-1,1.920928331942016E-1,1.9364751805831898E-1,1.938463260429578E-1,1.927089484228297E-1,1.9033614068486432E-1,1.8687958543202274E-1,1.8251243367516695E-1,1.7740523993148152E-1,1.688280806733429E-1,2.662737497093568E-2,1.0154603228310037E-2,7.095479606474643E-3,1.1034926381085306E-2,2.014178519196264E-2,3.343183671262918E-2,4.994108453236315E-2,8.767110951734454E-2,1.1806001909084132E-1,1.3899140315000078E-1,1.506124565295659E-1,1.5527296066610038E-1,1.5604404789053192E-1,1.5549342138921327E-1,1.5527176127778797E-1,1.5621435000469974E-1,1.5858599228386944E-1,1.622939262120386E-1,1.6703410498598434E-1,1.7238717330239878E-1,1.7788640195253638E-1,1.8307193615203884E-1,1.8753650252987206E-1,1.9096123717293031E-1,1.9313768092819872E-1,1.9397301765422703E-1,1.9347895876823656E-1,1.9174831259932493E-1,1.8892549944383658E-1,1.8517738328097358E-1,1.8066918925370729E-1,1.5620208035055458E-1,2.4437123804184755E-2,9.155746573656866E-3,6.367120815408856E-3,1.013013449266878E-2,1.875249551436229E-2,3.132719766388833E-2,4.696352401058657E-2,8.281602051461052E-2,1.1180154079736944E-1,1.3190351624392851E-1,1.4323959780617584E-1,1.480185429291516E-1,1.4914392342044575E-1,1.4905192167085216E-1,1.4931427793019872E-1,1.5073011154753846E-1,1.5355521861502044E-1,1.577023453853911E-1,1.6287916171721997E-1,1.686791994886015E-1,1.7464683065286693E-1,1.803298827282699E-1,1.8532465355118016E-1,1.893117918363579E-1,1.9207892541606603E-1,1.935269035249956E-1,1.9365980575978764E-1,1.9256251804239266E-1,1.9037197078995793E-1,1.8724834793201078E-1,1.8335106871065468E-1,1.443519307119633E-1,2.2400846570420824E-2,8.241642417220234E-3,5.7027367057087015E-3,9.288426287574874E-3,1.7436694342477146E-2,2.9312922048995962E-2,4.409548455572113E-2,7.809898461613501E-2,1.0569160818741292E-1,1.2495577998670324E-1,1.3598270673195517E-1,1.4084521426148766E-1,1.4228385919455241E-1,1.4260615523019513E-1,1.4330622880654878E-1,1.4514747324320312E-1,1.4837679853573174E-1,1.5291263833706015E-1,1.5847480869137864E-1,1.6467047500499654E-1,1.710561494469674E-1,1.771885835844523E-1,1.8266895862750862E-1,1.8717867209357938E-1,1.905024690767911E-1,1.9253560108690956E-1,1.9327492794900794E-1,1.9279752283129764E-1,1.9123269487066316E-1,1.8873365455553043E-1,1.854536366477063E-1,1.3325145606787653E-1,2.0511241373423507E-2,7.406885642528375E-3,5.09808314210478E-3,8.506884297536193E-3,1.6193238349105018E-2,2.7390230237644198E-2,4.134120094685935E-2,7.353216917776065E-2,9.974935064804993E-2,1.1817283583937203E-1,1.288703198574025E-1,1.3378404826799833E-1,1.3549657377983293E-1,1.3619002804947863E-1,1.372825421531556E-1,1.3950236315549802E-1,1.4308766358279773E-1,1.479626905797854E-1,1.5385973414389753E-1,1.6040021327761123E-1,1.671536884980278E-1,1.7368695860186506E-1,1.7960730798979274E-1,1.8459806254409242E-1,1.884420980545014E-1,1.9102982644862596E-1,1.9235135279166496E-1,1.924761227873554E-1,1.9152578176509488E-1,1.896463675274384E-1,1.8698464571709567E-1,1.2287260836076266E-1,1.8760890272900153E-2,6.646175990631032E-3,4.5490143899430645E-3,7.782532097840846E-3,1.5020640339800561E-2,2.555960373993097E-2,3.870368883965938E-2,6.912543331328642E-2,9.399077238369467E-2,1.1157570927986334E-1,1.2192718270659478E-1,1.2686239716820583E-1,1.2881129105655004E-1,1.298342653608488E-1,1.3127532444376164E-1,1.338282720762042E-1,1.377227126140128E-1,1.4288878106465716E-1,1.4907147077476168E-1,1.5590695045432654E-1,1.629786057778256E-1,1.6986428359458827E-1,1.7617849189137869E-1,1.8160759821004255E-1,1.859335944470568E-1,1.890428207826907E-1,1.909191345712003E-1,1.9162460535080963E-1,1.912732529556706E-1,1.9000383092672202E-1,1.879564399255028E-1,1.1318589964473773E-1,1.714233487066784E-2,5.9543527870752795E-3,4.0515086547101824E-3,7.1123661058094E-3,1.3917117588898513E-2,2.3820856888041104E-2,3.618484287394115E-2,6.488647343580166E-2,8.842892061763032E-2,1.0518197518037876E-1,1.1517439059274753E-1,1.2010399273571408E-1,1.222537920053518E-1,1.2356640909994106E-1,1.2531380055335745E-1,1.2815613458698194E-1,1.3231463262764892E-1,1.377253423848965E-1,1.4414609601692158E-1,1.5122818783874353E-1,1.585694755017022E-1,1.6575973049121537E-1,1.7242170017768804E-1,1.7824583281800635E-1,1.830141839289957E-1,1.8660978874467263E-1,1.890107953927526E-1,1.9027220479499002E-1,1.905005219066619E-1,1.898271848588103E-1,1.8838551614991622E-1,1.0416080062525368E-1,1.5648143235110337E-2,5.326423646971814E-3,3.6016889177107794E-3,6.493383864899515E-3,1.2880638118939842E-2,2.2173208434587928E-2,3.378553737355225E-2,6.082097915752971E-2,8.307407170752112E-2,9.900594778668739E-2,1.0862955944418477E-1,1.1352908140372153E-1,1.1584650386312927E-1,1.1741085531013316E-1,1.1942429606859348E-1,1.2251425413218871E-1,1.2689376511949596E-1,1.3250476757497356E-1,1.3911797931768674E-1,1.464000809256966E-1,1.539639217477729E-1,1.6141195013764456E-1,1.6837606068584138E-1,1.745517408785167E-1,1.7972201095676754E-1,1.837673571973652E-1,1.8666077831412842E-1,1.88450560721779E-1,1.8923586860077618E-1,1.891408661697427E-1,1.8829206045304805E-1,9.576610410375239E-2,1.4270968368303733E-2,4.7575875566363435E-3,3.195839401328878E-3,5.922608878954879E-3,1.1908964531790444E-2,2.061535204843255E-2,3.150572785105038E-2,5.693279598044095E-2,7.793393025265409E-2,9.305888954836397E-2,1.0230702058449984E-1,1.0715458759558305E-1,1.0960862110841031E-1,1.1138892653839728E-1,1.1363025746883136E-1,1.1692826861241216E-1,1.2148801533673431E-1,1.2725726178736751E-1,1.3401957571249673E-1,1.4145717538452363E-1,1.491982987309222E-1,1.5685870035360372E-1,1.64080220279419E-1,1.7056425851933468E-1,1.7609564760731472E-1,1.805530612972687E-1,1.8390492055853788E-1,1.8619318852740746E-1,1.875099173040975E-1,1.879721032257498E-1,1.8769946909024773E-1,8.797025287223563E-2,1.300359852825898E-2,4.243252769013095E-3,2.8304180244986053E-3,5.39711210789832E-3,1.0999695088324444E-2,1.9145524834678303E-2,2.9344551740408755E-2,5.322409154047441E-2,7.301383665904734E-2,8.734923343128664E-2,9.621803373198548E-2,1.0099429956042377E-1,1.0355625283350314E-1,1.0551897422171615E-1,1.079523057235927E-1,1.1142115266971352E-1,1.1612280129682452E-1,1.2201073648728056E-1,1.2888126418257675E-1,1.3643218941226723E-1,1.4430741815739584E-1,1.5213652073094475E-1,1.595719711053384E-1,1.6632186676747124E-1,1.7217364083120407E-1,1.7700486375747798E-1,1.807799535731554E-1,1.8353496944338107E-1,1.8535512587374492E-1,1.8635041363323068E-1,1.86633863480964E-1,8.074163221797745E-2,1.1838999805883835E-2,3.77904997470613E-3,2.502065225213968E-3,4.914030274369821E-3,1.0150301816372215E-2,1.776157314960739E-2,2.730042699546485E-2,4.96955225208582E-2,6.831697905820323E-2,8.188281378559283E-2,9.037101288018903E-2,9.505907230341112E-2,9.770259125624475E-2,9.981650612881574E-2,1.024083187787751E-1,1.0601325261699877E-1,1.1082103907246603E-1,1.1679074328890153E-1,1.237312286239991E-1,1.3135584107407383E-1,1.3932432315135437E-1,1.472804546145208E-1,1.5488792352190797E-1,1.618622197731196E-1,1.6799410166613585E-1,1.7316071186482881E-1,1.7732303549391118E-1,1.80511666619275E-1,1.8280529388141947E-1,1.843071128587339E-1,1.8512360765387412E-1,7.404882772774818E-2,1.0770351423681095E-2,3.3608412225120668E-3,2.207609533377842E-3,4.470581160861971E-3,9.358165502651472E-3,1.646101512053391E-2,2.53711474048149E-2,4.634639971346065E-2,6.384460593052355E-2,7.66631013253234E-2,8.47717601743041E-2,8.93570425794539E-2,9.205809640138073E-2,9.429433408009517E-2,9.701353843246927E-2,1.0072234985578302E-1,1.0560316059387187E-1,1.1162044416248469E-1,1.1859537871650103E-1,1.2625671856740645E-1,1.3428010743030466E-1,1.4232381777088313E-1,1.5006322610819786E-1,1.572218193489185E-1,1.635943387825185E-1,1.6905813562981312E-1,1.7357132038305878E-1,1.7715947255667286E-1,1.7989509573523108E-1,1.818748407129424E-1,1.8319883580077248E-1,6.786084952494173E-2,9.791074272348994E-3,2.9847250645200054E-3,1.9440702753958249E-3,4.064076099351172E-3,8.620607492922063E-3,1.5241099412454396E-2,2.3553973680602008E-2,4.3174849071494395E-2,5.959623625115781E-2,7.169143828334054E-2,7.942370338885892E-2,8.389385134958609E-2,8.663069232302266E-2,8.896273740317594E-2,9.178069721773854E-2,9.55637486171682E-2,1.0048716007820796E-1,1.0652061446361837E-1,1.13497307563658E-1,1.2116119079149167E-1,1.292037777170253E-1,1.3729801243544235E-1,1.4513133223854605E-1,1.524357361780954E-1,1.59010537641621E-1,1.647338893106316E-1,1.6956156745034634E-1,1.7351459205770964E-1,1.7665964387451608E-1,1.7908711162072213E-1,1.8089099662409946E-1,6.214732443481551E-2,8.894853234005835E-3,2.6470383927603134E-3,1.7086577829722451E-3,3.6919298709093416E-3,7.934918285191946E-3,1.4098859906070104E-2,2.1845719575405136E-2,4.017796695373886E-2,5.556986444198979E-2,6.696727032168584E-2,7.43281331242853E-2,7.867286956419545E-2,8.142597062867013E-2,8.382963787689365E-2,8.672016109992896E-2,9.055038393758387E-2,9.548866515241503E-2,1.01509675066389E-1,1.0845828267602478E-1,1.1609335517128609E-1,1.2412215681253812E-1,1.322323847399063E-1,1.4012381190098616E-1,1.4753737713777898E-1,1.5427748555528278E-1,1.602236374983193E-1,1.6532979237509274E-1,1.696128637442421E-1,1.7313408601707558E-1,1.759778935419458E-1,1.7823242016878332E-1,5.687865785708025E-2,8.075653858566794E-3,2.3443554186753377E-3,1.4987714638739027E-3,3.351668242046846E-3,7.2983829532930885E-3,1.3031166063829088E-2,2.024283246521835E-2,3.7351968102782455E-2,5.176215786812895E-2,6.2488372290333466E-2,6.94844363587551E-2,7.369542362115036E-2,7.644739748656751E-2,7.890078225769884E-2,8.18400840457438E-2,8.569294593049394E-2,9.062102877798567E-2,9.660374981057965E-2,1.0349726667779843E-1,1.1107501937067935E-1,1.190598243152522E-1,1.2715412295948206E-1,1.3507020675895778E-1,1.4255829739711717E-1,1.4942834205615038E-1,1.55561685993719E-1,1.6091096183415207E-1,1.6548942215724086E-1,1.693532393807596E-1,1.725812193629326E-1,1.7525591182037198E-1,5.2026167336912975E-2,7.3277339647235E-3,2.0734842248924176E-3,1.31199607321782E-3,3.0409333683171546E-3,6.708303482590946E-3,1.2034768861182337E-2,1.874146800511469E-2,3.469232522199229E-2,4.8168645052038356E-2,5.825106542522434E-2,6.489032350450084E-2,6.896101733615166E-2,7.169652073758484E-2,7.417992885533463E-2,7.714657081663288E-2,8.100001662462299E-2,8.589543820217575E-2,9.181674448834025E-2,9.863096402555199E-2,1.0612571332485092E-1,1.1403909165013068E-1,1.2208819358066977E-1,1.2999792590206613E-1,1.3752805528748785E-1,1.4449445322609522E-1,1.5078075686011488E-1,1.5633873142428145E-1,1.611784014784053E-1,1.6535126380274556E-1,1.689308335698167E-1,1.7199437715462587E-1,4.756218997152592E-2,6.645650730928642E-3,1.8314612923518434E-3,1.146096501252782E-3,2.7574872947946547E-3,6.162018136242008E-3,1.1106342248757893E-2,1.7337558616145634E-2,3.219389931383547E-2,4.478389318650963E-2,5.425042405058735E-2,6.0542046614057654E-2,6.446754774553723E-2,6.717317417797981E-2,6.966903501641292E-2,7.264384466701551E-2,7.647821589536499E-2,8.13210373369531E-2,8.716044368587784E-2,9.387389002363901E-2,1.0126272791686468E-1,1.0908000786061958E-1,1.1705731186974144E-1,1.2493217930080112E-1,1.324741074038066E-1,1.3950520799098828E-1,1.4591180630405284E-1,1.5164522635679786E-1,1.5671268104092925E-1,1.611613747571204E-1,1.65059876063096E-1,1.684804803616051E-1,4.346016587666661E-2,6.0242638265985285E-3,1.6155443760884137E-3,9.990113686823524E-4,2.499213778158954E-3,5.65691799963762E-3,1.024252018752529E-2,1.6026875696496058E-2,2.9851060212816603E-2,4.160167390402564E-2,5.048047029385396E-2,5.6434606852888744E-2,6.021151252849088E-2,6.28756765195094E-2,6.536844277371695E-2,6.833441697651789E-2,7.213235330661542E-2,7.690505919232121E-2,8.264462194838451E-2,8.923845849308852E-2,9.650117660775803E-2,1.0420039250532169E-1,1.1208194341106265E-1,1.1989594566595595E-1,1.2742174097831668E-1,1.3448793387167485E-1,1.4098388342384863E-1,1.4686086360347325E-1,1.5212367202293642E-1,1.5681559643713375E-1,1.6100060409285047E-1,1.6474633805877037E-1],[3.55216779472357E-1,9.989859262616928E-1,9.959675740347118E-1,9.909902545660512E-1,9.841113345123599E-1,9.753993603783353E-1,9.649330798426005E-1,9.528003785447788E-1,9.390971515503972E-1,9.239261289228025E-1,9.073956746327408E-1,8.896185774558119E-1,8.707108515832154E-1,8.507905634462458E-1,8.299766997788786E-1,8.083880902675622E-1,7.861423963162245E-1,7.633551755403274E-1,7.401390296474168E-1,7.166028414106114E-1,6.928511045391035E-1,6.689833484341212E-1,6.450936581222145E-1,6.21270288106452E-1,5.975953674901199E-1,5.741446925207114E-1,5.509876016824107E-1,5.281869276354986E-1,5.057990196588761E-1,4.8387382979063376E-1,4.6245505557117217E-1,4.4158033216076903E-1,8.204024429561232E-2,3.549265653819703E-1,9.989947949414174E-1,9.960034050509223E-1,9.910714961486673E-1,9.842565473545044E-1,9.756269763807625E-1,9.652611660273185E-1,9.532464102163196E-1,9.396777984592267E-1,9.246570577863565E-1,9.082913709096846E-1,8.906921887635387E-1,8.71974054613011E-1,8.522534556805386E-1,8.316477167656223E-1,8.102739486720684E-1,7.882480624633081E-1,7.656838586903967E-1,7.426921988281675E-1,7.193802642582896E-1,6.958509062948246E-1,6.722020889943537E-1,6.485264248592166E-1,6.249108020533014E-1,6.01436100423571E-1,5.781769924695939E-1,5.552018244347189E-1,5.325725719079057E-1,5.10344863721731E-1,4.885680675028397E-1,4.6728542996583444E-1,9.041412577851199E-2,8.138241295320048E-2,3.546242221026255E-1,9.99003895294351E-1,9.960401505464292E-1,9.911547652836205E-1,9.84405307414713E-1,9.758600401040223E-1,9.655969541388735E-1,9.537027238732698E-1,9.40271605301069E-1,9.25404294877589E-1,9.09206767391565E-1,8.917891105209315E-1,8.73264372724349E-1,8.537474398696892E-1,8.333539545286013E-1,8.121992902227412E-1,7.903975911426396E-1,7.680608860239484E-1,7.452982830049408E-1,7.222152504472352E-1,6.98912986917866E-1,6.754878818391122E-1,6.5203106674135E-1,6.286280556263585E-1,6.053584716808138E-1,5.822958564833935E-1,5.595075569298327E-1,5.370546843593708E-1,5.149921397999069E-1,4.9336869885060397E-1,9.87529704402439E-2,8.961946804661568E-2,8.071113662311367E-2,3.5432264514385287E-1,9.990132220769636E-1,9.960777894321033E-1,9.912400144781723E-1,9.84557530566469E-1,9.760984211571426E-1,9.659402587437738E-1,9.541690713432319E-1,9.408782547504295E-1,9.261674487544547E-1,9.101413951413475E-1,8.92908794601343E-1,8.745811786533383E-1,8.552718114402778E-1,8.350946347831237E-1,8.141632682568266E-1,7.925900743181611E-1,7.704852967200947E-1,7.479562786356323E-1,7.251067651273871E-1,7.020362928745675E-1,6.788396684387328E-1,6.556065348401967E-1,6.324210248493387E-1,6.093614981867687E-1,5.865003587832116E-1,5.639039473790419E-1,5.416325040447991E-1,5.197401946738617E-1,1.0699084930391005E-1,9.782415717379254E-2,8.88213373403465E-2,8.005304234419058E-2,3.5403232977438615E-1,9.990227699194839E-1,9.961163001217601E-1,9.913271951398261E-1,9.847131307617697E-1,9.763419861989981E-1,9.662908902332824E-1,9.546451988654446E-1,9.414974222982508E-1,9.269461190174801E-1,9.110947743130442E-1,8.940506798389276E-1,8.759238297852984E-1,8.56825847971617E-1,8.36868958712146E-1,8.161650127024398E-1,7.948245774745638E-1,7.72956100215832E-1,7.506651489839944E-1,7.280537366205784E-1,7.052197299986741E-1,6.82256345671968E-1,6.592517315431747E-1,6.362886328615605E-1,6.134441397050282E-1,5.907895121110208E-1,5.683900781962705E-1,5.463051999476987E-1,1.150639778318088E-1,1.0593252162583129E-1,9.69029070375544E-2,8.804950787858419E-2,7.942855372749263E-2,3.5376072380943563E-1,9.990325333294234E-1,9.96155660546167E-1,9.914162576072435E-1,9.848720200843769E-1,9.76590599017861E-1,9.666486549313983E-1,9.551308472271507E-1,9.421287764142049E-1,9.277398964929057E-1,9.120664143479086E-1,8.952141922273187E-1,8.772916683425969E-1,8.584088093567387E-1,8.386761070818327E-1,8.182036301277086E-1,7.971001395768001E-1,7.754722760506951E-1,7.534238238224129E-1,7.310550559528538E-1,7.084621628232993E-1,6.857367649266068E-1,6.629655093909776E-1,6.402297484597393E-1,6.176052970511368E-1,5.951622655813723E-1,5.729649634551685E-1,1.229115022568281E-1,1.1388262300883303E-1,1.0489365083750074E-1,9.602175471205356E-2,8.732555061439946E-2,7.885096508033056E-2,3.5351204383609525E-1,9.990425066951822E-1,9.961958481673617E-1,9.915071511818583E-1,9.850341088042932E-1,9.768441206128614E-1,9.67013355205586E-1,9.556257519037336E-1,9.427719787139621E-1,9.285483634222219E-1,9.130558141786669E-1,8.963987451282237E-1,8.786840215845215E-1,8.600199379777644E-1,8.405152403740564E-1,8.202782038095804E-1,7.994157730520942E-1,7.78032773736765E-1,7.562311991628148E-1,7.341095764174929E-1,7.117624139458001E-1,6.892797312346808E-1,6.667466699505387E-1,6.442431846752911E-1,6.218438103401721E-1,5.996175025647534E-1,1.3047620757063486E-1,1.2161530791110547E-1,1.1273326997519195E-1,1.0390912988022137E-1,9.520301717745479E-2,8.666221725390047E-2,7.832645177612657E-2,3.532874544659319E-1,9.990526842897305E-1,9.96236839993275E-1,9.915998241601646E-1,9.851993054334331E-1,9.771024092773161E-1,9.673847895802197E-1,9.561296432025946E-1,9.434266841314373E-1,9.293710936581497E-1,9.140624624419125E-1,8.976037394901668E-1,8.801002020195628E-1,8.616584588962227E-1,8.423854989366327E-1,8.223877938233723E-1,8.01770463795861E-1,7.806365126558381E-1,7.590861370179656E-1,7.372161131715008E-1,7.151192634289009E-1,6.928840024462246E-1,6.705939627281776E-1,6.483276973925517E-1,6.261584572748425E-1,1.3770513753553218E-1,1.2907489724487414E-1,1.2036410841591574E-1,1.1165276035206821E-1,1.0300163126052958E-1,9.445853424745836E-2,8.606385567729047E-2,7.785478461963838E-2,3.530855114886867E-1,9.990630602743644E-1,9.962786125926462E-1,9.916942238666614E-1,9.853675167824585E-1,9.773653206838883E-1,9.677627528526965E-1,9.566422464107381E-1,9.440925410960043E-1,9.302076528671053E-1,9.150858376987747E-1,8.988285640776007E-1,8.815395076304727E-1,8.633235800588619E-1,8.442860031520728E-1,8.245314371541301E-1,8.041631712029413E-1,7.832823819855558E-1,7.619874651954142E-1,7.403734428683505E-1,7.185314482414394E-1,6.965482884456154E-1,6.745060841276793E-1,6.52481984013452E-1,1.4455011954491837E-1,1.362097908734482E-1,1.277318268288078E-1,1.1919628459680873E-1,1.1066374862958198E-1,1.0218174369473436E-1,9.379052154342049E-2,8.552756508817068E-2,7.74305271067753E-2,3.5290277431110156E-1,9.99073628702534E-1,9.963211421102224E-1,9.917902966874304E-1,9.85538648018746E-1,9.776327079715353E-1,9.68147036212176E-1,9.571632819460291E-1,9.447691917146714E-1,9.310575987381802E-1,9.161254086639727E-1,9.000725957105976E-1,8.830012221124494E-1,8.650144925194938E-1,8.462158536256207E-1,8.267081478308421E-1,8.065928282255379E-1,7.859692406562829E-1,7.649339771263397E-1,7.435803033297631E-1,7.219976617421224E-1,7.002712504145631E-1,6.784816764581273E-1,1.509681896408474E-1,1.429729805173489E-1,1.3478599472634342E-1,1.2648651375502912E-1,1.1813412161311801E-1,1.0977526722689644E-1,1.0144928787575495E-1,9.31931854108768E-2,8.504482324951926E-2,7.7044509605401E-2,3.527344989761173E-1,9.990843835237396E-1,9.96364404282231E-1,9.918879881043283E-1,9.857126027254522E-1,9.779044218342023E-1,9.685374273609E-1,9.57692465512084E-1,9.454562719591968E-1,9.319204811986702E-1,9.171806344433467E-1,9.013351995153187E-1,8.844846151247854E-1,8.667303706773872E-1,8.481741313933198E-1,8.289169170845405E-1,8.09058341459226E-1,7.886959173405114E-1,7.679244317315481E-1,7.468353932593182E-1,7.255165532097051E-1,7.040515001458585E-1,1.5692191543493209E-1,1.4932246633887672E-1,1.414805938999562E-1,1.3347401340553597E-1,1.253605491338105E-1,1.1718482733698357E-1,1.0898452303806179E-1,1.007954033338969E-1,9.265478695345623E-2,8.460334412266209E-2,7.668539219005555E-2,3.5257533144754033E-1,9.990953185874948E-1,9.964083744521144E-1,9.919872427297708E-1,9.858892829616444E-1,9.781803106112164E-1,9.689337106380429E-1,9.582295082567514E-1,9.461534118581252E-1,9.327958426361662E-1,9.182509647799569E-1,9.026157291854461E-1,8.859889425563009E-1,8.684703725327083E-1,8.501598981508355E-1,8.311567135312957E-1,8.115585912583814E-1,7.914612104765395E-1,7.709575533268439E-1,7.50137372000674E-1,7.290867274230074E-1,1.6237961700631712E-1,1.5522157496494676E-1,1.4777442862276638E-1,1.401135991880393E-1,1.3229444930932205E-1,1.2435908698696E-1,1.1634282055175363E-1,1.082794618315812E-1,1.002050502312858E-1,9.215987967693451E-2,8.4188951859111E-2,7.634115138923381E-2,3.524199333196225E-1,9.991064276473531E-1,9.964530275865169E-1,9.920880043420852E-1,9.860685893234589E-1,9.784602203793363E-1,9.693356671460421E-1,9.587741169341369E-1,9.468602356937174E-1,9.336832181272232E-1,9.19335840308825E-1,9.039135272547489E-1,8.875134468048643E-1,8.70233639959488E-1,8.521721965037375E-1,8.334264833810815E-1,8.140924318823503E-1,7.942638883281551E-1,7.740320315699887E-1,7.534848593431651E-1,1.673154880114751E-1,1.606391789604754E-1,1.5363144038520438E-1,1.4636474182842465E-1,1.3889134802769287E-1,1.3125021334742948E-1,1.2347362811868627E-1,1.1559277222713271E-1,1.076417032847745E-1,9.965961896935072E-2,9.169148320502557E-2,8.378729064153712E-2,7.60003584691332E-2,3.5226348917048894E-1,9.991177043649948E-1,9.964983382915134E-1,9.921902159214114E-1,9.862504210062554E-1,9.787439950464102E-1,9.697430748793533E-1,9.593259940701192E-1,9.475763622037381E-1,9.345821356726076E-1,9.204346928203815E-1,9.052279253809417E-1,8.890573570712856E-1,8.720192989965719E-1,8.542100502399133E-1,8.357251506734654E-1,8.166586916736441E-1,7.971026890820146E-1,7.771465214514195E-1,1.7170962118885955E-1,1.6554981985506775E-1,1.5902092711772717E-1,1.5219187935239084E-1,1.4511127914310007E-1,1.3781435925207164E-1,1.3032980201241307E-1,1.226855317556627E-1,1.1491296423259675E-1,1.0704951039059044E-1,9.913938904979094E-2,9.123299937579483E-2,8.338523254354156E-2,7.565315801955007E-2,3.5210206522285364E-1,9.991291423143719E-1,9.965442808290683E-1,9.92293819686126E-1,9.864346758677257E-1,9.7903147644659E-1,9.701557088555738E-1,9.598848381313033E-1,9.483014047880626E-1,9.354921164391183E-1,9.215469455326734E-1,9.06558244640972E-1,8.906198896678473E-1,8.738264601569811E-1,8.562724646247611E-1,8.380516175410376E-1,8.192561732694129E-1,7.999763209843773E-1,1.755479441407478E-1,1.6993373870970568E-1,1.6391766888466958E-1,1.575646364061991E-1,1.5091909412802237E-1,1.440120581482175E-1,1.3686808063816805E-1,1.2951126750651326E-1,1.2196978383261992E-1,1.1427860275563466E-1,1.064805162355115E-1,9.862563291169148E-2,9.076973010017803E-2,8.297189666276795E-2,7.529190183055515E-2,3.5193281025261375E-1,9.991407349859083E-1,9.965908291337134E-1,9.923987571297666E-1,9.866212504919233E-1,9.793225044370552E-1,9.705733412488768E-1,9.604503436973518E-1,9.49034971720057E-1,9.364126750079658E-1,9.2267201337237E-1,9.079037958378654E-1,8.922002483417139E-1,8.756542187560903E-1,8.58358426719777E-1,8.404047645014598E-1,8.218836538474078E-1,1.7882207269969672E-1,1.7377681985294072E-1,1.6830196386149346E-1,1.62457952579656E-1,1.562846811007825E-1,1.4980853046976295E-1,1.430494732215613E-1,1.360273008082638E-1,1.2876637747725403E-1,1.2129863552783543E-1,1.136647936164426E-1,1.0591399585822014E-1,9.810222389262098E-2,9.028991724038195E-2,8.25392474544016E-2,7.491143831308579E-2,3.517540087985154E-1,9.991524757907513E-1,9.966379568294333E-1,9.925049690584343E-1,9.868100402541726E-1,9.796169169961902E-1,9.709957415256911E-1,9.610222016366298E-1,9.497766663626772E-1,9.373433196296859E-1,9.238093032645947E-1,9.092638798192283E-1,8.937976246134425E-1,8.77501655258998E-1,8.604669057251122E-1,8.427834507789742E-1,1.8152909032299877E-1,1.7707045479369612E-1,1.7215958000135975E-1,1.6685212340484668E-1,1.6118309507444123E-1,1.551739013938304E-1,1.4883956168569046E-1,1.4219512823827143E-1,1.352606788308263E-1,1.2806455719329965E-1,1.2064480607058206E-1,1.1304896167251331E-1,1.0533254450213081E-1,9.755667786116484E-2,8.978528748962869E-2,8.208229133125008E-2,7.450909578444048E-2,3.515650112033293E-1,9.991643580650731E-1,9.966856372467485E-1,9.926123956286471E-1,9.870009393868203E-1,9.79914550323164E-1,9.714226765825636E-1,9.616000992850943E-1,9.505260873892283E-1,9.382835524855512E-1,9.24958214431592E-1,9.106377878074999E-1,8.954111981307867E-1,8.793678356474309E-1,8.625968533466439E-1,1.8367126280051904E-1,1.7981133441606686E-1,1.7548162913279872E-1,1.7073275925288772E-1,1.655946030043529E-1,1.600833318212718E-1,1.5420871576308984E-1,1.479807174909023E-1,1.4141471155121707E-1,1.3453496649541824E-1,1.273762976057104E-1,1.1998402887574175E-1,1.124125799979485E-1,1.0472310312705109E-1,9.69806283648653E-2,8.9251141659733E-2,8.159893135647432E-2,7.408442431717624E-2,3.5136607355336424E-1,9.991763750744175E-1,9.967338434399817E-1,9.927209763856223E-1,9.871938410457877E-1,9.802152389388544E-1,9.718539108861364E-1,9.621837206283583E-1,9.512828290087165E-1,9.39232869955437E-1,9.261181387002325E-1,9.12024801742018E-1,8.970401370379658E-1,8.812518118064977E-1,1.8525569811383594E-1,1.8200117837628024E-1,1.7826437129536865E-1,1.7409066864823658E-1,1.6950464871704093E-1,1.6451706610525543E-1,1.5913222321775364E-1,1.5335471827385955E-1,1.4719487753855975E-1,1.4067247326208585E-1,1.338185986358208E-1,1.2667580743508325E-1,1.1929681304695802E-1,1.1174216276821587E-1,1.0407734937199592E-1,9.636979622587417E-2,8.868607055538363E-2,8.108956579091267E-2,7.36387738216182E-2,3.511581431832455E-1,9.991885200180904E-1,9.967825482046988E-1,9.928306503019604E-1,9.873886373778832E-1,9.805188157880613E-1,9.722892066151676E-1,9.627727464868476E-1,9.520464811957206E-1,9.401907628920849E-1,9.272884608183327E-1,9.134241946329446E-1,8.986835983605392E-1,1.8629396156007622E-1,1.8364641115766134E-1,1.805089579105958E-1,1.7692167355354044E-1,1.7290374406206685E-1,1.6846040151329936E-1,1.6359033868722964E-1,1.5829259017744787E-1,1.5257216203303983E-1,1.464439775016023E-1,1.3993497447002065E-1,1.3308443076759083E-1,1.2594278942411863E-1,1.1856938869736972E-1,1.1102955954677828E-1,1.0339153727212617E-1,9.572355863545402E-2,8.809140444975967E-2,8.055652628116387E-2,7.317478661416661E-2,3.50942623115443E-1,9.992007860335893E-1,9.968317240953098E-1,9.929413558167082E-1,9.875852195888334E-1,9.808251123429499E-1,9.727283238045232E-1,9.633668547039724E-1,9.528166299246997E-1,9.411567169016978E-1,9.284685587797599E-1,9.148352309270782E-1,1.8680165627178405E-1,1.847577945083971E-1,1.8222112290595768E-1,1.792263649445703E-1,1.757872936296741E-1,1.7190358562692518E-1,1.675682560687521E-1,1.6277465104325217E-1,1.575222576013459E-1,1.5182086726122657E-1,1.4569289393658044E-1,1.3917389072537556E-1,1.3231151376166364E-1,1.2516332487409285E-1,1.1779389411648288E-1,1.1027165715900138E-1,1.026659138582424E-1,9.50442459274559E-2,8.747050970794217E-2,8.000344756257571E-2,7.269587383381197E-2,3.5072114319449005E-1,9.992131662010709E-1,9.968813434428199E-1,9.930530308747723E-1,9.877834780119904E-1,9.811339587076628E-1,9.731710204910629E-1,9.639657203372233E-1,9.535928574086506E-1,9.421302126307872E-1,9.296578041582724E-1,1.867979790493767E-1,1.8535002600802516E-1,1.8341083117244675E-1,1.810098074993852E-1,1.7815536111814947E-1,1.748416488496068E-1,1.710560105488744E-1,1.6678605072160244E-1,1.6202561057533532E-1,1.5677913739707308E-1,1.5106421881644286E-1,1.4491229473411557E-1,1.3836777021104274E-1,1.314859061915455E-1,1.2432994533236714E-1,1.1696793404325266E-1,1.094696402682804E-1,1.0190386164327037E-1,9.433629678095273E-2,8.6828037321474E-2,7.943464662406842E-2,7.220573040809293E-2,3.504953584044152E-1,9.992256535478515E-1,9.969313783727167E-1,9.931656129666586E-1,9.879833021776715E-1,9.814451837240404E-1,9.736170528613418E-1,9.645690158521026E-1,9.54374742342015E-1,9.431107260591849E-1,1.8630526100441802E-1,1.854413133059379E-1,1.8409189375974103E-1,1.8228120248072613E-1,1.800123859210806E-1,1.772741799062844E-1,1.7404831730437767E-1,1.7031667623549215E-1,1.6606739481408736E-1,1.6129943286599613E-1,1.560253163479446E-1,1.502720459377735E-1,1.4408036743189584E-1,1.3750276436229233E-1,1.306006242576865E-1,1.2344104365661643E-1,1.1609368278274952E-1,1.086279799133424E-1,1.0111091421895184E-1,9.360538865453062E-2,8.616920895622981E-2,7.885456986377576E-2,7.17079263451474E-2,3.5026678730371213E-1,9.992382410529387E-1,9.969818008229836E-1,9.932790391685119E-1,9.881845808830876E-1,9.817586150783848E-1,9.740661754010463E-1,9.651764113187926E-1,9.551618601477355E-1,1.8534850192166075E-1,1.850529331769252E-1,1.8428155902072538E-1,1.8305351791409047E-1,1.8136685874882663E-1,1.7920505268241071E-1,1.7654435458262704E-1,1.733609952547854E-1,1.6963741873760152E-1,1.653670213984711E-1,1.6055709846053784E-1,1.5522994871894927E-1,1.494223089292728E-1,1.4318346044523583E-1,1.3657245177240548E-1,1.2965490409266717E-1,1.2249982020393453E-1,1.151767209085072E-1,1.0775331282512461E-1,1.0029377286299448E-1,9.285763574018234E-2,8.549920190401672E-2,7.82673458999544E-2,7.120559566129933E-2,3.5003669663169756E-1,9.992509216515899E-1,9.970325825622243E-1,9.933932461824267E-1,9.883872022628154E-1,9.82074079409204E-1,9.745181410460778E-1,9.657875746114588E-1,1.8395490651889473E-1,1.842087839753935E-1,1.8400008853632754E-1,1.8334309497885817E-1,1.8223096511826434E-1,1.8064211298003321E-1,1.7854749930896327E-1,1.7591784542917233E-1,1.7272997242087076E-1,1.6897170143393794E-1,1.646449925812964E-1,1.5976724329163086E-1,1.5437089120351968E-1,1.4850164518663805E-1,1.4221577864446622E-1,1.3557695212482643E-1,1.2865299337430597E-1,1.2151297142498343E-1,1.1422478296635641E-1,1.0685334951397962E-1,9.945942214377206E-2,9.209891774470987E-2,8.482266960635661E-2,7.76764623540825E-2,7.07012299800667E-2,3.4980603246881403E-1,9.992636882398962E-1,9.970836952078886E-1,9.935081703770057E-1,9.885910538597682E-1,9.82391402415869E-1,9.749727013351983E-1,1.821534299493428E-1,1.8293493937326533E-1,1.832703261117256E-1,1.8316923916275696E-1,1.826202053632672E-1,1.815968337808642E-1,1.8006502357998244E-1,1.7799017753883273E-1,1.753436221426499E-1,1.7210765199199637E-1,1.682788498233536E-1,1.6386957418475712E-1,1.589077334344409E-1,1.5343514971715022E-1,1.4750493597206643E-1,1.4117835109078122E-1,1.3452156723496275E-1,1.276026969747043E-1,1.2048931178515399E-1,1.132465632114265E-1,1.0593591382995698E-1,9.861440884347276E-2,9.133437435283151E-2,8.414341234801452E-2,7.708456884275604E-2,7.019657260620474E-2,3.495753940732294E-1,9.992765336793862E-1,9.971351102445852E-1,9.936237478281351E-1,9.887960226966188E-1,9.827104089681153E-1,1.7997433898415552E-1,1.8125921046881086E-1,1.8211726746697438E-1,1.82553804209679E-1,1.8255299946094025E-1,1.820839474240484E-1,1.8110776040301424E-1,1.795847606116206E-1,1.7748096016204132E-1,1.7477323171701026E-1,1.7145279710693578E-1,1.6752689834190926E-1,1.630187434778447E-1,1.579660103335824E-1,1.524183185964098E-1,1.4643413175747694E-1,1.4007752698504358E-1,1.334151901699088E-1,1.2651387991377705E-1,1.1943848401540165E-1,1.12250685834724E-1,1.0500817847975306E-1,9.776431649825222E-2,9.056807561329434E-2,8.346419502141637E-2,7.649339631973913E-2,6.969260088117656E-2,3.4934504364906444E-1,9.992894508016489E-1,9.971867990424697E-1,9.937399143599523E-1,9.89001995347628E-1,1.7744879436317573E-1,1.792107224857311E-1,1.805676374796001E-1,1.8152077624697432E-1,1.8205028446372862E-1,1.821210627548727E-1,1.81689746855917E-1,1.8071185714304752E-1,1.791483176619996E-1,1.7697073467897056E-1,1.741650402851461E-1,1.7073333925293718E-1,1.6669402580098508E-1,1.6208043208597533E-1,1.5693840520182398E-1,1.5132326880346159E-1,1.4529660984486234E-1,1.3892325574018605E-1,1.3226869685704395E-1,1.2539708952021342E-1,1.1836986697776823E-1,1.11244903541228E-1,1.0407612558712323E-1,9.691344089891049E-2,8.980285937556973E-2,8.278669609830971E-2,7.590377479871241E-2,6.918957965861272E-2,3.491149436889318E-1,9.993024324129702E-1,9.972387328756949E-1,9.938566055859762E-1,1.746084588387728E-1,1.7681951137329666E-1,1.7864948100380063E-1,1.8009586474092715E-1,1.8113511170377378E-1,1.817282748072659E-1,1.8182785249242092E-1,1.813848763625241E-1,1.8035544877032386E-1,1.7870611065410932E-1,1.76417625657614E-1,1.7348699401192885E-1,1.699277376232641E-1,1.6576869668147426E-1,1.6105171974885032E-1,1.558286966054066E-1,1.501583750780542E-1,1.441033337542328E-1,1.3772737550344097E-1,1.310934879306081E-1,1.242624080385926E-1,1.1729174367679558E-1,1.1023554978946676E-1,1.0314423229941815E-1,9.606465156692226E-2,8.904031365996148E-2,8.211156389651451E-2,7.531572695045284E-2,6.86871663951857E-2,3.488848129826916E-1,9.993154712989823E-1,9.972908829409115E-1,1.7148513448520247E-1,1.741161446960572E-1,1.7639177241875523E-1,1.783061061267523E-1,1.7983225022232072E-1,1.809277739757721E-1,1.8154140033348298E-1,1.8162001314069234E-1,1.8111519336752097E-1,1.7998865756322413E-1,1.7821616737012821E-1,1.7578970047288042E-1,1.7271789996522183E-1,1.690250208071843E-1,1.6474873962138636E-1,1.5993726888364596E-1,1.546462159134745E-1,1.4893556370401004E-1,1.4286704739015152E-1,1.3650208270103945E-1,1.2990029319428253E-1,1.2311859625556369E-1,1.1621075047909372E-1,1.0922723901039676E-1,1.0221536010059598E-1,9.521941067773328E-2,8.828087402129609E-2,8.1438552270362E-2,7.472861351485574E-2,6.818454815684051E-2,3.4865419268645076E-1,9.993285602293198E-1,1.6811043192650024E-1,1.7113137028965675E-1,1.7382404817305458E-1,1.7617948511956733E-1,1.7816780210144254E-1,1.7974346093965815E-1,1.808517871917069E-1,1.8143587965442745E-1,1.8144312604123153E-1,1.8083069353546202E-1,1.795695481357542E-1,1.7764677176434862E-1,1.7506617055292298E-1,1.7184737137061531E-1,1.680237564126276E-1,1.6363966744417058E-1,1.5874731781786283E-1,1.534037930330429E-1,1.4766842136931194E-1,1.416006804043229E-1,1.3525869537672527E-1,1.2869829677260947E-1,1.2197254458417676E-1,1.1513159592785616E-1,1.0822278696412542E-1,1.0129081282120043E-1,9.437791345556025E-2,8.752400271453167E-2,8.076670720233328E-2,7.414130726508454E-2,6.768059230588128E-2,3.484225147907412E-1],[],[],[3.969469997306232E-2,5.458735111189851E-3,1.4232040710716622E-3,8.688456942222264E-4,2.2641186470091753E-3,5.190460873009591E-3,9.439929363430162E-3,1.4805085566621379E-2,2.765779698788415E-2,3.8615116601142384E-2,4.6934355728817836E-2,5.256194979405294E-2,5.618820727821596E-2,5.880102295947698E-2,6.1277060315742767E-2,6.42192562040444E-2,6.796558299392175E-2,7.265296525263738E-2,7.827716593944659E-2,8.47350845870847E-2,9.185407639071894E-2,9.941589197998107E-2,1.0718033297338803E-1,1.149099712077426E-1,1.2239404026496375E-1,1.2946782928014594E-1,1.3602402736951613E-1,1.4201421358752167E-1,1.4744114405080463E-1,1.5234455433138702E-1,1.567841524986503E-1,1.6082324946781568E-1,3.624160434411349E-2,4.944525400508913E-3,1.2521143765000273E-3,7.538628721102438E-4,2.0503289063816383E-3,4.76018269817707E-3,8.695217740893057E-3,1.3667799257262832E-2,2.560781810088269E-2,3.5816848920312075E-2,4.3604529230634737E-2,4.891714749312381E-2,5.2391911264054174E-2,5.4945067698081905E-2,5.739253731684813E-2,6.0297953910720375E-2,6.397955904629833E-2,6.856858897205309E-2,7.406420450794744E-2,8.037229943435358E-2,8.733244456633105E-2,9.474005564138464E-2,1.0236855704001319E-1,1.0999279568233775E-1,1.1741188347527351E-1,1.2446792916010521E-1,1.3105720007544194E-1,1.3713189904103582E-1,1.4269308988209964E-1,1.4777730608817313E-1,1.524403317350732E-1,1.567414631702258E-1,3.307792337017654E-2,4.477388767084306E-3,1.1001425336971253E-3,6.524761703554119E-4,1.8560907798618026E-3,4.363706715758294E-3,8.00507915663554E-3,1.261061633144341E-2,2.3694641389568737E-2,3.319912425726206E-2,4.048289065287337E-2,4.549256666433579E-2,4.881606070434813E-2,5.130269611830419E-2,5.3711432536485276E-2,5.65688859505779E-2,6.017458917420714E-2,6.465428086820385E-2,7.0010243844943E-2,7.615687352038845E-2,8.294540801525631E-2,9.018442823119602E-2,9.76605963933882E-2,1.0516080209367232E-1,1.1249396670550044E-1,1.1950910058410111E-1,1.2610625145171603E-1,1.3223852828637606E-1,1.3790562588788027E-1,1.431412089307311E-1,1.4799746255762375E-1,1.525299799844622E-1,3.018194376834073E-2,4.053364806008119E-3,9.6533838001048E-4,5.632399341876477E-4,1.6797668687490467E-3,3.998750554509939E-3,7.366274187347715E-3,1.1629162997741783E-2,2.1911674096633003E-2,3.0753936389884048E-2,3.756093022153535E-2,4.228002260022085E-2,4.5453408910199354E-2,4.786798569037763E-2,5.022937244111475E-2,5.302936726570222E-2,5.654978477726109E-2,6.091105300275843E-2,6.611830520019675E-2,7.209394597442458E-2,7.870032186549722E-2,8.575865527245136E-2,9.306842526437664E-2,1.0042828647394447E-1,1.0765685127876896E-1,1.1461006482526334E-1,1.2119191374337826E-1,1.273566599375139E-1,1.331029257077012E-1,1.3846182145697586E-1,1.434822457361035E-1,1.4821639092769648E-1,2.753319156604665E-2,3.6687692605206264E-3,8.459234294538869E-4,4.8484065389119016E-4,1.519832592944612E-3,3.663131455475636E-3,6.775647547645046E-3,1.0719124823441846E-2,2.025228329145266E-2,2.8473121515705902E-2,3.4829853784243255E-2,3.927091875644598E-2,4.22961729616912E-2,4.463435497601378E-2,4.6941199920503565E-2,4.967579904120707E-2,5.3103205840665614E-2,5.733872094564856E-2,6.239006292399703E-2,6.818715720744474E-2,7.460289470257114E-2,8.14705983278797E-2,8.860211372880741E-2,9.580754428561673E-2,1.0291503098331975E-1,1.0978744240963345E-1,1.1633282167932954E-1,1.2250679585018882E-1,1.2830718420172382E-1,1.337628373264699E-1,1.3891966475181441E-1,1.438267487384084E-1,2.5112417918048965E-2,3.320183363777195E-3,7.402798607301854E-4,4.1608803231960723E-4,1.3748720630165077E-3,3.354769830992388E-3,6.2301422895761046E-3,9.876274393903865E-3,1.8709857130721427E-2,2.634844814125061E-2,3.228069425611449E-2,3.645637216180555E-2,3.933616684029321E-2,4.159470038548202E-2,4.384111245858517E-2,4.650380727091489E-2,4.983199938902256E-2,5.393604162020472E-2,5.882598089676096E-2,6.443878263421275E-2,7.065731774249939E-2,7.732645725642297E-2,8.426994024779613E-2,9.13089701587093E-2,9.828101580710025E-2,1.0505581771383549E-1,1.1154555502380348E-1,1.1770739906766113E-1,1.2353860866517051E-1,1.2906604809919398E-1,1.3433291911769069E-1,1.393854710416946E-1,2.290157554435244E-2,3.0044422155739575E-3,6.469395650583069E-4,3.5590616514290875E-4,1.2435735176319514E-3,3.0716913529509203E-3,5.726811082635891E-3,9.096494290089458E-3,1.7277857479787783E-2,2.437169539028096E-2,2.990440976930734E-2,3.3827325011952056E-2,3.656492116473264E-2,3.8741520583060005E-2,4.092278937636397E-2,4.35083720542248E-2,4.6732530505858835E-2,5.070084571367778E-2,5.5425445700106823E-2,6.084986550254659E-2,6.686639567042481E-2,7.333089687230507E-2,8.007851149268157E-2,8.694116788870292E-2,9.376542893817198E-2,1.0042781979087662E-1,1.0684470020216119E-1,1.1297493350172953E-1,1.1881543419208883E-1,1.243913323377286E-1,1.297433857310868E-1,1.3491527293337743E-1,2.08837874265035E-2,2.7186224759953546E-3,5.645733801602205E-4,3.033249264316827E-4,1.1247244455350406E-3,2.8120277566401762E-3,5.262824854812422E-3,8.375795771082556E-3,1.5949864470790037E-2,2.2534720391824963E-2,2.7691969163556925E-2,3.13746429666697E-2,3.3973789864095744E-2,3.606702864377457E-2,3.817950798992322E-2,4.0683947186666125E-2,4.380050518417496E-2,4.763016360755829E-2,5.218689516313073E-2,5.7420347139020805E-2,6.323167713400973E-2,6.948717569072987E-2,7.603288686040709E-2,8.27110678616409E-2,8.93771140087314E-2,9.591421627307917E-2,1.0224292778830334E-1,1.0832392214606394E-1,1.1415396006836541E-1,1.1975666800828547E-1,1.2517060552048306E-1,1.3043712653674308E-1,1.9043309255041437E-2,2.460029622567709E-3,4.919806129648816E-4,2.5747163364179333E-4,1.0172064967297312E-3,2.5740165365769866E-3,4.835479071630446E-3,7.7103335541192424E-3,1.4719613608932359E-2,2.082951547593527E-2,2.563442555325719E-2,2.908920079706129E-2,3.155404427340092E-2,3.356325223804067E-2,3.560424872077822E-2,3.802456982028512E-2,4.103108450555798E-2,4.472034403162779E-2,4.910794118218809E-2,5.414919319650879E-2,5.975358316378863E-2,6.57972747278816E-2,7.213670536185868E-2,7.862404933438247E-2,8.512324979754114E-2,9.152401740472833E-2,9.775108280244978E-2,1.0376702073021879E-1,1.0956860412818066E-1,1.1517816520753846E-1,1.2063229257185644E-1,1.2597024494037348E-1,1.736548697544571E-2,2.22618498396831E-3,4.280789321493977E-4,2.1756304944584454E-4,9.199902737054165E-4,2.355999699424555E-3,4.442197922370557E-3,7.096417082511476E-3,1.3581026056949273E-2,1.9248255948444936E-2,2.3722978776071973E-2,2.6961956124011262E-2,2.9296955255962587E-2,3.122212226260809E-2,3.318978935955923E-2,3.5523960155329194E-2,3.841898985194771E-2,4.1967164872669244E-2,4.6185485958363644E-2,5.103451475097479E-2,5.6431532066734666E-2,6.226202460362687E-2,6.83923128462971E-2,7.468406527064526E-2,8.100946986184711E-2,8.726458748804235E-2,9.337828496511907E-2,9.931510387766584E-2,1.050719721136011E-1,1.106701162919177E-1,1.1614436290924711E-1,1.2153208784957494E-1,1.5836710636419418E-2,2.014812731972734E-3,3.718946925419806E-4,1.8289776316040275E-4,8.321300805496371E-4,2.1564217268920465E-3,4.0805366714956656E-3,6.530518663266722E-3,1.2528232732360993E-2,1.77833392386425E-2,2.1949027572077288E-2,2.498401205599025E-2,2.7193864046402835E-2,2.9035550448440053E-2,3.0928788818873287E-2,3.317561128237567E-2,3.595859903473737E-2,3.93659357720193E-2,4.341583102167232E-2,4.807368333936071E-2,5.326405959997855E-2,5.8881229467570996E-2,6.480088780289177E-2,7.08937677099066E-2,7.70399848369066E-2,8.314176127540357E-2,8.913203627630445E-2,9.497736102003523E-2,1.0067493922400331E-1,1.0624506058445517E-1,1.1172098014821871E-1,1.1713838626915936E-1,1.4444365605143209E-2,1.8238269843277224E-3,3.225537366233944E-4,1.5284898167795545E-4,7.527586957320672E-4,1.973826888757813E-3,3.7481824196034658E-3,6.009278842431339E-3,1.1555592844836822E-2,1.6427416218828032E-2,2.0304212364409338E-2,2.314666957605942E-2,2.523624257126097E-2,2.6995496561332842E-2,2.881386081909709E-2,3.0972869425279784E-2,3.3644033380975324E-2,3.691159232517561E-2,4.0794778613510226E-2,4.5263439254853585E-2,5.024893347541761E-2,5.565378652841864E-2,6.1362564249991966E-2,6.72546319198868E-2,7.32177054117374E-2,7.915996310029548E-2,8.501833352935859E-2,9.076139953338026E-2,9.638674122123289E-2,1.0191386097222403E-1,1.0737461533146404E-1,1.1280318357339526E-1,1.317678208104246E-2,1.651319144736968E-3,2.792727037807534E-4,1.2685774873881717E-4,6.810822232756044E-4,1.8068560332080096E-3,3.4429535026296652E-3,5.529509368385958E-3,1.065770748402702E-2,1.5173415485035497E-2,1.878044951562761E-2,2.144147054815568E-2,2.3415744043933637E-2,2.5094025872006532E-2,2.683763803405121E-2,2.8909004941763402E-2,3.146923594689579E-2,3.459878185166239E-2,3.831772517828758E-2,4.259999261874568E-2,4.7383261470440384E-2,5.257780020947534E-2,5.80765504797183E-2,6.376707784883567E-2,6.954436425731582E-2,7.532232680200829E-2,8.104178361923736E-2,8.66733527923937E-2,9.221507265922131E-2,9.768578987603659E-2,1.0311611838409496E-1,1.0853889040132017E-1,1.2023183713997824E-2,1.4955455821863048E-3,2.413508654706258E-4,1.0442660197232212E-4,6.16375066984745E-4,1.6542429688068412E-3,3.16279774119822E-3,5.088194072522917E-3,9.829428843598751E-3,1.4014561366527772E-2,1.7369957921625087E-2,1.986023221465994E-2,2.172424465027883E-2,2.3323357611868947E-2,2.499282728438593E-2,2.6977274521991314E-2,2.94280411362378E-2,3.242194083501689E-2,3.5979746871534525E-2,4.007911692871806E-2,4.466359262350238E-2,4.965069017710702E-2,5.494124266630663E-2,6.043058764688362E-2,6.60206354430052E-2,7.163081475886865E-2,7.720571975773077E-2,8.271799107775962E-2,8.816619002533821E-2,9.35686222653133E-2,9.895479878380617E-2,1.0435635093409942E-1,1.097363601577118E-2,1.3549157303976288E-3,2.0816249389107373E-4,8.511366925771463E-5,5.579750633779422E-4,1.5148105398382335E-3,2.9057897344623527E-3,4.6824879738779634E-3,9.06586563672474E-3,1.2944386400494674E-2,1.6065278779859284E-2,1.839507404394245E-2,2.0153877143666184E-2,2.167590515150789E-2,2.327225640759084E-2,2.5170975088225037E-2,2.751423608641662E-2,3.037536424220059E-2,3.377567712560824E-2,3.76962349415809E-2,4.208601117501536E-2,4.6869292692413E-2,5.1954332568936355E-2,5.7243818262965776E-2,6.264625012433625E-2,6.80863345965474E-2,7.351231695841033E-2,7.889883351377315E-2,8.424501780810087E-2,8.956873359739746E-2,9.489851322048992E-2,1.0026491825786164E-1,1.0018995145333434E-2,1.227980669224019E-3,1.7914976298291017E-4,6.852719948046569E-5,5.052788009531584E-4,1.3874664846620498E-3,2.67012737498352E-3,4.309714890153747E-3,8.362385223552121E-3,1.1956738969964076E-2,1.4859289333619291E-2,1.703843776093198E-2,1.869705715643481E-2,2.0144308643926842E-2,2.1668913457322813E-2,2.348348994280128E-2,2.5721614251468388E-2,2.845326702040182E-2,3.170017642640302E-2,3.544649688468092E-2,3.9646223073728934E-2,4.422995491838764E-2,4.911290876190181E-2,5.420470834288418E-2,5.9420107517180076E-2,6.46888523779048E-2,6.996270539649141E-2,7.521825945260974E-2,8.045525573590176E-2,8.56912007755263E-2,9.09537582139354E-2,9.627253668314995E-2,9.150857550094696E-3,1.1134222331747527E-3,1.5381617341434918E-4,5.432051754306489E-5,4.577371463626238E-4,1.2711991552494147E-3,2.454127743516692E-3,3.967363812858637E-3,7.714612933625204E-3,1.104578675929686E-2,1.3745211351413232E-2,1.5783101358392074E-2,1.7346503011299405E-2,1.8721460866226294E-2,2.0175978893678108E-2,2.1908327739500348E-2,2.4044021658769118E-2,2.6649838138752064E-2,2.974779454645809E-2,3.332485110520608E-2,3.733963500682182E-2,4.172862197518753E-2,4.6413551006053676E-2,5.131057885339596E-2,5.634038038755176E-2,6.143750130583035E-2,6.655708047986729E-2,7.16776179536132E-2,7.679948565901182E-2,8.19399044374074E-2,8.712576586076559E-2,9.238582907419148E-2,8.361510855826582E-3,1.0100426778600071E-3,1.3172048747922197E-4,4.218738939335413E-5,4.1485099194196084E-4,1.1650731652982247E-3,2.256222525328219E-3,3.653084279550789E-3,7.118429027076327E-3,1.02060166345181E-2,1.2716615052494617E-2,1.4622187843887987E-2,1.609524978369086E-2,1.7400526974271868E-2,1.878685142247962E-2,2.043915486704879E-2,2.247539634885516E-2,2.495928759471469E-2,2.7913025553099925E-2,3.132610736165335E-2,3.516142602907752E-2,3.9360916675103684E-2,4.385241753520547E-2,4.855822703590254E-2,5.3404614481257766E-2,5.833068517837393E-2,6.329480868430984E-2,6.827733422715586E-2,7.327927676797422E-2,7.831763110201459E-2,8.34186010872576E-2,8.861018743165759E-2,7.643886318203873E-3,9.167549228146536E-4,1.1247115539002888E-4,3.1857779721919826E-5,3.7616723376117503E-4,1.0682250243518438E-3,2.074953073102607E-3,3.364680951898377E-3,6.569963698657819E-3,9.432231506667452E-3,1.1767419137925214E-2,1.3549169429481594E-2,1.4936658326528006E-2,1.6174958857120614E-2,1.7495168127788115E-2,1.906982183518398E-2,2.1009801526277416E-2,2.337588684171232E-2,2.6190355966425233E-2,2.9444993038196893E-2,3.310661196389767E-2,3.712221198717908E-2,4.142532516992978E-2,4.594401345116742E-2,5.060982149252514E-2,5.536617602476229E-2,6.017452840616883E-2,6.50170121202262E-2,6.98952880522549E-2,7.482617391174123E-2,7.983525898858872E-2,8.494986516629838E-2,6.991513078090022E-3,8.325733787373477E-4,9.572121111362696E-5,2.309398272320566E-5,3.412749848869257E-4,9.798588061833147E-4,1.9089652257840393E-3,3.100107584804047E-3,6.065590489217566E-3,8.719544686590398E-3,1.0891887532995507E-2,1.2557867819837405E-2,1.3864419924455067E-2,1.5038504743618727E-2,1.6294819519732894E-2,1.7794384245405102E-2,1.9641452956264693E-2,2.189400311780923E-2,2.4574306482788116E-2,2.7676202622222614E-2,3.1170102827861455E-2,3.5007696380189926E-2,3.912782228960288E-2,4.346394201374948E-2,4.7952565325401646E-2,5.254120552083118E-2,5.7194245268461195E-2,6.18955319129178E-2,6.664736710098793E-2,7.146643090723062E-2,7.637776103342232E-2,8.140806969339963E-2,6.3984744005346995E-3,7.566053584912006E-4,8.116361352596194E-5,1.5687104789297984E-5,3.098020247881482E-4,8.992418913887785E-4,1.757003977975969E-3,2.8574605494898664E-3,5.601918430701353E-3,8.063372190200783E-3,1.0084623392644867E-2,1.164245120121257E-2,1.287255719685243E-2,1.3985214674421367E-2,1.5179960091221176E-2,1.6607118912108608E-2,1.8364741138929358E-2,2.0508128166819743E-2,2.3059467706801447E-2,2.601444082954213E-2,2.9346753592635465E-2,3.301243227323805E-2,3.6955254792680775E-2,4.111373303222016E-2,4.5429041536373456E-2,4.9852549932800326E-2,5.435142148028435E-2,5.891114287016064E-2,6.353464453100448E-2,6.823849996048661E-2,7.304724910258252E-2,7.798705416573556E-2,5.85936602343809E-3,6.880430640844021E-4,6.852700710992755E-5,9.453877098852553E-6,2.814114827188884E-4,8.257008166421508E-4,1.617908080876906E-3,2.634972052394366E-3,5.175783213743703E-3,7.4594234050625735E-3,9.340560867847682E-3,1.0797428480066226E-2,1.1955421819393557E-2,1.3009442410300392E-2,1.414501494377765E-2,1.5502535676977203E-2,1.71742487815689E-2,1.921290184483952E-2,2.1640530350459576E-2,2.4454459792515062E-2,2.7631408644888788E-2,3.1131407886986595E-2,3.490282525634519E-2,3.8888889369720195E-2,4.303514996196006E-2,4.7296608469409515E-2,5.164305899483033E-2,5.6061550150604156E-2,6.0555623494770186E-2,6.51417696665E-2,6.98440765094058E-2,7.468820734264561E-2,5.369256695398857E-3,6.261561361135328E-4,5.757187555948719E-5,4.233775671585366E-6,2.557987503985832E-4,7.586172563864064E-4,1.4906046432095741E-3,2.431003172147268E-3,4.784237631780296E-3,6.903690482835187E-3,8.654955078657328E-3,1.0017641266826579E-2,1.110768958381128E-2,1.2105844303331625E-2,1.318468300614081E-2,1.4475385431781078E-2,1.6064764071916385E-2,1.8003131098567954E-2,2.0312310363551737E-2,2.2991090745199397E-2,2.6018940338167765E-2,2.9359582837196807E-2,3.296564557125469E-2,3.678475592027435E-2,4.076656063201988E-2,4.4869475034898174E-2,4.906577633814003E-2,5.334399581436241E-2,5.7708263871704864E-2,6.217500565334383E-2,6.676789531551962E-2,7.151214076272416E-2,4.923650942796997E-3,5.702847476437541E-4,4.808706136090093E-5,-1.1357351046257191E-7,2.3268861731718169E-4,6.974241568365243E-4,1.3741037892208716E-3,2.2440368188394585E-3,4.424541522675253E-3,6.392436778196407E-3,8.023370689419945E-3,9.29825404857514E-3,1.032435326586568E-2,1.1269375612542019E-2,1.2293937330539474E-2,1.3520664833528867E-2,1.5031290232419992E-2,1.687380478845273E-2,1.9069769456681644E-2,2.1619270648382642E-2,2.450428205211273E-2,2.7691927847348856E-2,3.1138783376766625E-2,3.479657266092683E-2,3.861877314930478E-2,4.256700347004642E-2,4.661587908976041E-2,5.075533379356477E-2,5.4990060880434725E-2,5.933643191486063E-2,6.381773940804066E-2,6.845877254572653E-2,4.51845407304539E-3,5.198332210659763E-4,3.9886624596587156E-5,-3.7107263452324585E-6,2.1183262045442982E-4,6.416020370102073E-4,1.2674934205829413E-3,2.072670703336306E-3,4.094151398292383E-3,5.922184613654882E-3,7.441669434105832E-3,8.634742944718967E-3,9.600713723087118E-3,1.0495284700782311E-2,1.1468022911872672E-2,1.2633618162347237E-2,1.4069051809094102E-2,1.5820104811048237E-2,1.790803146843688E-2,2.0334064197506347E-2,2.3082456185577187E-2,2.612345898038213E-2,2.9417302658244996E-2,3.291952158970352E-2,3.658716977985418E-2,4.0384866446694284E-2,4.4289424088513E-2,4.829209879491914E-2,5.239811796696936E-2,5.662380689842423E-2,6.0992102941894694E-2,6.552740729447859E-2,4.149939393554205E-3,4.7426414396138205E-4,3.280701476050331E-5,-6.664510811785026E-6,1.930065990603137E-4,5.906754670293861E-4,1.1699341198795348E-3,1.915610389489354E-3,3.790709924357057E-3,5.489702611427548E-3,6.905996895128722E-3,8.022883392625961E-3,8.932369597341118E-3,9.779105505744155E-3,1.0702452435195166E-2,1.1809736737593026E-2,1.3173498119316692E-2,1.4837413952303547E-2,1.6822395012952615E-2,1.9130681649557797E-2,2.1748597512706858E-2,2.4649266802589366E-2,2.7796298892552605E-2,3.1148767896213306E-2,3.4667062548532884E-2,3.8318608244112935E-2,4.208227751277364E-2,4.5950569192579935E-2,4.992921392518942E-2,5.40344941930031E-2,5.828901387384447E-2,6.271681169916199E-2,3.814717603677243E-3,4.330929582896486E-4,2.6704530207609466E-5,-9.06789608846299E-6,1.760084443405055E-4,5.442097301039467E-4,1.0806542252736545E-3,1.771662488753151E-3,3.5120353873877574E-3,5.091992798409355E-3,6.412768797670327E-3,7.4587370660610455E-3,8.315205953101762E-3,9.11664863575821E-3,9.993000317699298E-3,1.1044756272364419E-2,1.2340304252137542E-2,1.3921320877897157E-2,1.5808342824517926E-2,1.8004492892333815E-2,2.0497972326295997E-2,2.3264540896952127E-2,2.6270929142111467E-2,2.9479495736928964E-2,3.285373467094184E-2,3.6363691684719604E-2,3.9990167046225725E-2,4.372682404359634E-2,4.7579864292085494E-2,5.156552776030603E-2,5.570610242302071E-2,6.0025285564099494E-2,3.509708299163452E-3,3.9588299617071164E-4,2.1453040909454453E-5,-1.1001660161289927E-5,1.6065603337497923E-4,5.018076713598102E-4,9.98945098861282E-4,1.6397280448533697E-3,3.2561112624055486E-3,4.726277658246959E-3,5.958657043527301E-3,6.938638288305191E-3,7.74538214087336E-3,8.503991400750113E-3,9.335695373367347E-3,1.0334652511477048E-2,1.156536998304368E-2,1.3067622639189128E-2,1.486154819309377E-2,1.6951038162299013E-2,1.9325993782122276E-2,2.196459014017057E-2,2.4836437503493788E-2,2.790693900236378E-2,3.1142476678549795E-2,3.451553954335767E-2,3.8008728388333746E-2,4.161679441824065E-2,4.534637713190618E-2,4.9213671734883856E-2,5.3240664386659343E-2,5.7450728081081905E-2,3.2321135148613567E-3,3.622409350441694E-4,1.6941951394728044E-5,-1.2535874409792726E-5,1.4678533632524765E-4,4.6310673395339667E-4,9.241566050582568E-4,1.5187961457067368E-3,3.02107597448455E-3,4.389987275618015E-3,5.540575673890826E-3,6.459180164190825E-3,7.219319136685496E-3,7.937467050829152E-3,8.726812392079774E-3,9.675635463687196E-3,1.0844816933404867E-2,1.2272325044691994E-2,1.3977878859611298E-2,1.5966035796681034E-2,1.8228233842667155E-2,2.074485914862828E-2,2.3488176314794527E-2,2.642640746994729E-2,2.952861760968982E-2,3.276957077015026E-2,3.6133546405141465E-2,3.961630928483935E-2,4.3224903381822E-2,4.697547488856921E-2,5.0889719320017186E-2,5.4990699263797495E-2,2.97939322109848E-3,3.318126449637497E-4,1.3074382064715942E-5,-1.3731222508010661E-5,1.3424868591093418E-4,4.2777618067125415E-4,8.556928100723333E-4,1.407937790672129E-3,2.805212928890566E-3,4.080746691927984E-3,5.155666919213547E-3,6.017200620985069E-3,6.73368657312566E-3,7.413653459655106E-3,8.162862890549924E-3,9.064142505912809E-3,1.0174984273560618E-2,1.1531641217879533E-2,1.315339871353202E-2,1.5045387382414744E-2,1.7200432199775652E-2,1.9600941284754633E-2,2.2221623518327814E-2,2.503330873576179E-2,2.800755164645021E-2,3.1121231883186263E-2,3.436019124183448E-2,3.7721136224663984E-2,4.121148197807656E-2,4.484731991156184E-2,4.865006365685755E-2,5.2642476535538656E-2,2.7492426817994813E-3,3.042794011302682E-4,9.765548447328563E-6,-1.4640169798897243E-5,1.2291319822610932E-4,3.9551449739156367E-4,7.930079090041562E-4,1.3063000333234421E-3,2.6069408684375244E-3,3.796363568642527E-3,4.801287466328326E-3,5.609768517051308E-3,6.285389645012327E-3,6.92936145710835E-3,7.640585260231398E-3,8.496830605773832E-3,9.552423238165252E-3,1.0841988633229075E-2,1.238436760808462E-2,1.4185180639919984E-2,1.6238502534331557E-2,1.8528588597788158E-2,2.1032396562678666E-2,2.372316631171846E-2,2.6574760577784056E-2,2.9566023895373623E-2,3.268424973513266E-2,3.592701727826024E-2,3.930208001708708E-2,4.282546770792204E-2,4.6518318902408894E-2,5.0403106527854256E-2,2.5395715775743117E-3,2.793544354081905E-4,6.941319353604737E-6,-1.530799811520095E-5,1.1265933418430174E-4,3.6604697333674093E-4,7.356023833297734E-4,1.2131004131744729E-3,2.424804602631913E-3,3.5348162342169857E-3,4.4749950481125225E-3,5.234169949437319E-3,5.871556043513474E-3,6.481622985926124E-3,7.156934507463919E-3,7.970567879180102E-3,8.973890693337821E-3,1.019998489409526E-2,1.1667239581437063E-2,1.3381690354172589E-2,1.533853644778447E-2,1.7523719052754034E-2,1.991626321188574E-2,2.2491634263364417E-2,2.5225832463602153E-2,2.8099525140962308E-2,3.1101352472305638E-2,3.4229700241594385E-2,3.749262823179407E-2,4.090609693832729E-2,4.449097507531481E-2,4.8269452202022674E-2],[1.6451547326723E-1,1.6789579527837523E-1,1.709760657164614E-1,1.737445778600596E-1,1.7616883456399177E-1,1.7820057284995075E-1,1.79782109401023E-1,1.8085313634471614E-1,1.81357198074052E-1,1.812472157140803E-1,1.8048960049397092E-1,1.7906670534555472E-1,1.769775855911148E-1,1.7423724436945928E-1,1.7087469563316365E-1,1.6693026575399725E-1,1.624525682030686E-1,1.5749553444638648E-1,1.5211578918881766E-1,1.4637054445726003E-1,1.4031607724689799E-1,1.3400676544258242E-1,1.2749459448581874E-1,1.2082901391039015E-1,1.1405701475142133E-1,1.0722330975428472E-1,1.0037052139580097E-1,9.353931163123619E-2,8.676841681563836E-2,8.009457764037989E-2,7.355237479507636E-2,6.717399528915953E-2,1.6073062970702245E-1,1.6443959721735174E-1,1.678774913639239E-1,1.7103022020525582E-1,1.7386303288448202E-1,1.7632532550466654E-1,1.7835679929342224E-1,1.7989412804436758E-1,1.8087737878145518E-1,1.8125555245314048E-1,1.8099077547201856E-1,1.8006087355962053E-1,1.7846027732500314E-1,1.761994141470266E-1,1.7330290180910388E-1,1.6980695341021992E-1,1.657564231098772E-1,1.612018769259847E-1,1.5619698220563608E-1,1.5079639814216023E-1,1.4505424038802167E-1,1.3902310170372256E-1,1.3275354628222055E-1,1.2629395960743944E-1,1.1969062526769016E-1,1.1298790920044792E-1,1.0622845370258065E-1,9.94533118977731E-2,9.270198297071147E-2,8.601233544755016E-2,7.942042757277722E-2,7.296024910017886E-2,1.567852940923994E-1,1.6079226835181065E-1,1.6455761883653394E-1,1.680652036597862E-1,1.7127837733975085E-1,1.7414457544130982E-1,1.7660127700301204E-1,1.7858253044243763E-1,1.8002530187426452E-1,1.8087501499513411E-1,1.8108980505092326E-1,1.8064320228727673E-1,1.7952517407744922E-1,1.777416596833273E-1,1.7531289546330614E-1,1.722709277216776E-1,1.6865673670160647E-1,1.6451735579518348E-1,1.5990328399233694E-1,1.5486638101988173E-1,1.494583260791622E-1,1.4372962920492457E-1,1.3772911816196798E-1,1.3150378574303515E-1,1.2509886964076267E-1,1.1855804424205349E-1,1.1192362425041093E-1,1.0523670775146253E-1,9.853721592456871E-2,9.186381404929572E-2,8.525372105041033E-2,7.874243109103206E-2,1.52707688015259E-1,1.5698239328726993E-1,1.610451194830706E-1,1.6487800067228095E-1,1.6844284664196807E-1,1.71685505089259E-1,1.7454162140691856E-1,1.7694301131364085E-1,1.7882392182994256E-1,1.8012655409347622E-1,1.8080536429154573E-1,1.8082984384955253E-1,1.8018568909747523E-1,1.7887447433432624E-1,1.7691210835578428E-1,1.7432645863028928E-1,1.711545595358518E-1,1.6743978743778493E-1,1.6322930398230248E-1,1.5857196333224396E-1,1.5351677162256877E-1,1.481118945595857E-1,1.424041414285771E-1,1.3643881361716664E-1,1.3025979089652828E-1,1.2390973399680788E-1,1.1743030120920142E-1,1.1086230371255104E-1,1.0424575377105004E-1,9.761978776950574E-2,9.102246939124661E-2,8.449049545676439E-2,1.4852470251071984E-1,1.5303745974564378E-1,1.5736782451371045E-1,1.6149652030747363E-1,1.6538414955302239E-1,1.6897533336530193E-1,1.7220426325222232E-1,1.750009101950616E-1,1.7729718454109356E-1,1.7903242637369562E-1,1.8015773836674015E-1,1.8063884977371436E-1,1.804574041094435E-1,1.7961076508407756E-1,1.781106031193668E-1,1.7598063307362416E-1,1.732539115762202E-1,1.6997007439135564E-1,1.6617281753377558E-1,1.6190782334382595E-1,1.5722122666242805E-1,1.5215862371928435E-1,1.4676455738340324E-1,1.4108237033645676E-1,1.3515430077786078E-1,1.2902169869445132E-1,1.2272525851332687E-1,1.1630519009000304E-1,1.0980127918975682E-1,1.0325281671298288E-1,9.669839991429385E-2,9.01756269686361E-2,1.4426177093913067E-1,1.4898370154636867E-1,1.5355253898113166E-1,1.579478946567068E-1,1.621294856904577E-1,1.660410533778544E-1,1.6961570278470542E-1,1.7278193945766893E-1,1.754697157882351E-1,1.7761587453435873E-1,1.7916849909640967E-1,1.8008984844524556E-1,1.8035775293211595E-1,1.7996554693767142E-1,1.7892078308363996E-1,1.7724308464952881E-1,1.7496153577381895E-1,1.7211198651532614E-1,1.6873457788854435E-1,1.6487169278316768E-1,1.6056643425456338E-1,1.5586164024924384E-1,1.5079937380319786E-1,1.454207839067896E-1,1.3976621328896385E-1,1.3387543094936405E-1,1.2778788360420912E-1,1.2154288543484652E-1,1.1517969439221323E-1,1.0873745157721558E-1,1.02254984791099E-1,9.57704962827588E-2,1.3994277225673327E-1,1.4484597250042675E-1,1.4962488672741847E-1,1.542582957741578E-1,1.5870533590996064E-1,1.6290919824063507E-1,1.6680225350253464E-1,1.7031190901235657E-1,1.733665303746618E-1,1.759008247923547E-1,1.7786019491309837E-1,1.7920373204103562E-1,1.7990570996421926E-1,1.7995563757808805E-1,1.7935709765451235E-1,1.78125714106857E-1,1.762866378084137E-1,1.738719237975116E-1,1.7091810547103867E-1,1.674641756222476E-1,1.6355008163394186E-1,1.5921575008105227E-1,1.5450058514401413E-1,1.4944333981161567E-1,1.4408223802590842E-1,1.3845522568200863E-1,1.3260024325718858E-1,1.2655543708656264E-1,1.2035925473344837E-1,1.1405039824633041E-1,1.0766763415753502E-1,1.0124947877613198E-1,1.3558996258353903E-1,1.406476495373911E-1,1.4560918507907347E-1,1.5045278242691984E-1,1.5513728209394073E-1,1.5960563539332E-1,1.6378981301685067E-1,1.6761647622244502E-1,1.7101276407917737E-1,1.7391160429394162E-1,1.7625605751493548E-1,1.7800235649420584E-1,1.7912148772802558E-1,1.7959935685735048E-1,1.7943574812832067E-1,1.7864240577287124E-1,1.7724061724982962E-1,1.7525866612497604E-1,1.7272945983327098E-1,1.696885453937333E-1,1.6617262569038754E-1,1.6221859748437512E-1,1.5786306087004562E-1,1.531422030632481E-1,1.4809193680877036E-1,1.427481716805533E-1,1.3714710991706186E-1,1.31325481636797E-1,1.253206621903721E-1,1.1917064273320103E-1,1.1291385056909581E-1,1.0658883620911082E-1,1.3122393276052013E-1,1.3641056309828092E-1,1.4152834771615144E-1,1.4655517552521755E-1,1.51449855693464E-1,1.5615538929063477E-1,1.606036614196433E-1,1.647209219770563E-1,1.6843342993978058E-1,1.7167268055698107E-1,1.7437972780600988E-1,1.765082575964107E-1,1.780262470428974E-1,1.789162351105262E-1,1.7917439828732215E-1,1.7880874455671172E-1,1.7783679499981545E-1,1.76283115024199E-1,1.7417699931644595E-1,1.7155052610271027E-1,1.6843709811539606E-1,1.6487049704892484E-1,1.608844064525073E-1,1.5651230995612647E-1,1.5178764746406975E-1,1.4674410821370956E-1,1.4141595146609634E-1,1.3583826770597215E-1,1.300471205423016E-1,1.2407953772242204E-1,1.179733454568542E-1,1.1176686127267951E-1,1.268635894449837E-1,1.3215495261549923E-1,1.374038138620589E-1,1.425879607535975E-1,1.476664139627687E-1,1.525824918557552E-1,1.5726828704259474E-1,1.6164995331994092E-1,1.6565319978773826E-1,1.6920842439262834E-1,1.7225500309488034E-1,1.7474438571372866E-1,1.7664182278288654E-1,1.7792673368726697E-1,1.785918935654003E-1,1.7864173765735725E-1,1.7809014142107754E-1,1.7695803198873677E-1,1.7527113318803741E-1,1.730580615588006E-1,1.7034889503840484E-1,1.6717424641309028E-1,1.635648016201551E-1,1.5955123387894915E-1,1.5516437882384798E-1,1.5043555041009476E-1,1.453968877345141E-1,1.4008164389033714E-1,1.3452435461952375E-1,1.2876085255747216E-1,1.2282811888283333E-1,1.167639857615318E-1,1.225261572159424E-1,1.2789944475955428E-1,1.3325550173365575E-1,1.385722166521079E-1,1.438090424908776E-1,1.4890985969964654E-1,1.5380723904176297E-1,1.5842753253124606E-1,1.6269621141376833E-1,1.6654289718535695E-1,1.6990560693071438E-1,1.7273386098992083E-1,1.7499046757018746E-1,1.766519805047789E-1,1.777079920048741E-1,1.781595445705275E-1,1.7801700907059356E-1,1.7729777757695764E-1,1.760240706401774E-1,1.7422107765173112E-1,1.7191555574428447E-1,1.6913492432993432E-1,1.6590682038150154E-1,1.6225902956679686E-1,1.582196811179611E-1,1.5381758731416192E-1,1.4908261733985195E-1,1.440460150908858E-1,1.3874059641152195E-1,1.3320078900646712E-1,1.2746250444219057E-1,1.2156285371175674E-1,1.1822719914267864E-1,1.2366105205388839E-1,1.291017840512369E-1,1.345275661941516E-1,1.3989848237075253E-1,1.4515919678420885E-1,1.5024300586284636E-1,1.5507673212804168E-1,1.5958590127095268E-1,1.636996628950099E-1,1.673549824117964E-1,1.7049975034587675E-1,1.7309461518116245E-1,1.7511352285141407E-1,1.7654310966166495E-1,1.7738121844694474E-1,1.7763487344420384E-1,1.7731805499401362E-1,1.7644957061737687E-1,1.750512417342307E-1,1.7314653477017744E-1,1.7075967843897374E-1,1.679152371922276E-1,1.6463806010662665E-1,1.6095349594881553E-1,1.5688775662209728E-1,1.5246831861445403E-1,1.4772427068534638E-1,1.4268654114946955E-1,1.3738796553193952E-1,1.318631816127323E-1,1.2614836135014873E-1,1.1398065330153023E-1,1.1945518943672702E-1,1.2495948332852899E-1,1.3047214976949054E-1,1.3595408014902557E-1,1.4135092095115057E-1,1.4659691832935193E-1,1.5161961488381842E-1,1.5634486220489546E-1,1.6070162468785254E-1,1.646261093088371E-1,1.680648670642211E-1,1.709766649031128E-1,1.7333309912226E-1,1.751180825687954E-1,1.7632646131762744E-1,1.7696208462308027E-1,1.7703566138564963E-1,1.7656269599394225E-1,1.7556172287570307E-1,1.740529713341107E-1,1.720575068276191E-1,1.6959682342328694E-1,1.6669281086228477E-1,1.6336798996422375E-1,1.5964590010279717E-1,1.5555152845765832E-1,1.511116881563685E-1,1.4635527670184303E-1,1.413133730833321E-1,1.360191582099753E-1,1.3050766611877498E-1,1.0979888280026781E-1,1.1529570637476019E-1,1.2084388463696874E-1,1.264226174007646E-1,1.3199375856348217E-1,1.3750411254655362E-1,1.4288907584870605E-1,1.480771376666289E-1,1.529947253510481E-1,1.575708857074758E-1,1.6174134490947828E-1,1.654515932787919E-1,1.6865878758505623E-1,1.713324306558335E-1,1.7345394684740523E-1,1.7501539518164985E-1,1.760176322022549E-1,1.7646824958001117E-1,1.7637957515781943E-1,1.7576695632267472E-1,1.7464745966425274E-1,1.7303903713347413E-1,1.7096013800950843E-1,1.6842969427143373E-1,1.6546737619623375E-1,1.6209400362996593E-1,1.583320029405186E-1,1.5420581585108278E-1,1.4974218975402928E-1,1.4497030563090363E-1,1.3992172587092158E-1,1.3463016736434819E-1,1.0569273697842099E-1,1.1119493220022703E-1,1.1676876355911761E-1,1.2239413799325939E-1,1.2803400599534548E-1,1.3363648323820834E-1,1.391382940454464E-1,1.4446907765744124E-1,1.495560650509035E-1,1.5432863316117654E-1,1.5872228811251285E-1,1.6268172527348584E-1,1.661627536795145E-1,1.69133034370827E-1,1.715717380680996E-1,1.7346835045748848E-1,1.748209253875646E-1,1.7563410252883624E-1,1.7591717359035264E-1,1.7568241506047383E-1,1.749438233896682E-1,1.7371630657139817E-1,1.7201531583835708E-1,1.698568491995407E-1,1.6725772682419193E-1,1.6423602560315173E-1,1.608115634067416E-1,1.570063385286691E-1,1.5284485229040595E-1,1.4835426877285696E-1,1.4356439166669643E-1,1.3850746152000235E-1,1.0167162158817017E-1,1.0716373244307154E-1,1.1274642710592395E-1,1.1840042343364157E-1,1.2408988253277073E-1,1.2976436304342062E-1,1.3536207200139852E-1,1.408139793310752E-1,1.4604832541041088E-1,1.509950446219836E-1,1.5558966598075638E-1,1.5977634113541753E-1,1.6350978317786646E-1,1.6675605647834799E-1,1.6949231051958147E-1,1.717056728380003E-1,1.7339158967874557E-1,1.745519222310924E-1,1.7519307757131128E-1,1.7532439092658267E-1,1.7495689673306986E-1,1.7410254587978713E-1,1.7277385708672868E-1,1.709839382279979E-1,1.6874678086118514E-1,1.6607771732991838E-1,1.6299393166493642E-1,1.5951492926364572E-1,1.5566289186964322E-1,1.5146286978155968E-1,1.469427890394997E-1,1.421332747622923E-1,9.774357591703088E-2,1.0321157405633466E-1,1.0878776546457121E-1,1.1445376540720191E-1,1.2017504055418432E-1,1.2590270355308525E-1,1.3157657720482824E-1,1.3712912045711706E-1,1.424897669519237E-1,1.4758921522824645E-1,1.5236324169903376E-1,1.5675569000350834E-1,1.607204170004851E-1,1.6422212717107984E-1,1.6723617664029355E-1,1.6974754916684864E-1,1.7174928111982374E-1,1.73240634478251E-1,1.7422529169472983E-1,1.7470978728961167E-1,1.7470231482424922E-1,1.7421196978041445E-1,1.732484203419511E-1,1.7182194591641614E-1,1.6994374996641332E-1,1.6762643869010047E-1,1.648845576656384E-1,1.6173509112390522E-1,1.5819784909073742E-1,1.5429569241844432E-1,1.5005457128073824E-1,1.4550337620492199E-1,9.39153549842232E-2,9.93465975792235E-2,1.0490231256125869E-1,1.1056508288800433E-1,1.1630175778875125E-1,1.2206509534714821E-1,1.277966462781446E-1,1.3343049530238926E-1,1.388974316908391E-1,1.4412910429823902E-1,1.4906174267584274E-1,1.5363910190415914E-1,1.578144091146626E-1,1.6155123586740427E-1,1.6482336651471474E-1,1.676138525745596E-1,1.6991351869852037E-1,1.717192103473559E-1,1.730320514609546E-1,1.738559248873895E-1,1.7419631503887814E-1,1.7405957614545742E-1,1.7345262196230488E-1,1.7238298072437144E-1,1.708591252631665E-1,1.6889097211750617E-1,1.664904428128855E-1,1.636719918447625E-1,1.6045302549867302E-1,1.5685415975014494E-1,1.5289929072313999E-1,1.4861547470037692E-1,9.01925151217084E-2,9.557569444238062E-2,1.0109831356008135E-1,1.0674397836595594E-1,1.1248098088986012E-1,1.1826379764088234E-1,1.2403579956089082E-1,1.2973281318429505E-1,1.352871248948715E-1,1.4063149976225653E-1,1.4570280737057714E-1,1.504449169681862E-1,1.5481063841679227E-1,1.587626263155909E-1,1.6227330703002987E-1,1.653240067776036E-1,1.6790353511751965E-1,1.700065049904209E-1,1.716316518196778E-1,1.7278036202012606E-1,1.7345555086916142E-1,1.7366095567276432E-1,1.7340084375171158E-1,1.7268008291529668E-1,1.7150448770341983E-1,1.698813376250901E-1,1.6781996178515113E-1,1.6533229448405418E-1,1.624333249848578E-1,1.5914138805013894E-1,1.554782667192779E-1,1.5146910226959626E-1,8.657950143348861E-2,9.190458778844734E-2,9.738279756962373E-2,1.0299880100314349E-1,1.0872237766002492E-1,1.145097782745755E-1,1.2030626766546587E-1,1.2604951052996918E-1,1.3167341175230207E-1,1.3711199874446148E-1,1.4230294931863724E-1,1.4719043267438578E-1,1.5172703922810268E-1,1.5587471063930136E-1,1.5960472003079343E-1,1.6289686915477627E-1,1.6573814584416915E-1,1.6812111392967433E-1,1.7004229218197062E-1,1.7150072992533935E-1,1.7249691945674583E-1,1.7303211349329448E-1,1.7310805065100246E-1,1.727270404036445E-1,1.7189232417490058E-1,1.7060861127631952E-1,1.688826854440843E-1,1.6672398677858086E-1,1.6414509150848686E-1,1.611620346805318E-1,1.5779444533139703E-1,1.5406548707665E-1,8.307973580868898E-2,8.83379153533026E-2,9.376165398776397E-2,9.93367150534596E-2,1.050343961863221E-1,1.1081276225546498E-1,1.16619028191488E-1,1.223927746338937E-1,1.2806962718011655E-1,1.335850025961483E-1,1.388775367597419E-1,1.4389186766100787E-1,1.4858054911221494E-1,1.52905001228521E-1,1.5683553859759886E-1,1.6035063197134766E-1,1.6343563607214456E-1,1.6608124676955496E-1,1.682819380991464E-1,1.7003458382419565E-1,1.71337403569251E-1,1.7218930377893693E-1,1.7258961979106596E-1,1.7253821415349205E-1,1.7203585120307194E-1,1.7108474917695313E-1,1.6968920710095742E-1,1.6785621163836498E-1,1.655959457102666E-1,1.6292214262681462E-1,1.598522534719845E-1,1.564074187189528E-1,7.969570434166592E-2,8.487931312546212E-2,9.023971107806174E-2,9.57637720296357E-2,1.0142432927922908E-1,1.0718128717461836E-1,1.1298385087534679E-1,1.1877357737098417E-1,1.2448789703816274E-1,1.3006372468596977E-1,1.3544078624541767E-1,1.405643405827203E-1,1.4538707262413342E-1,1.4987005924659197E-1,1.5398284040832746E-1,1.5770274092155917E-1,1.6101366499844624E-1,1.639046179786063E-1,1.6636819952443466E-1,1.6839926982667403E-1,1.6999392848347974E-1,1.711488780890564E-1,1.718611819167296E-1,1.7212837439865572E-1,1.719488477658569E-1,1.713224187353397E-1,1.702509740981115E-1,1.6873910092082203E-1,1.6679462271821907E-1,1.6442898411349252E-1,1.616574500199425E-1,1.584991084224939E-1,7.64290431831001E-2,8.153149866957517E-2,8.682081553414261E-2,9.228498525605058E-2,9.789838274981265E-2,1.0362276394800264E-1,1.0940934955916032E-1,1.1520171720774905E-1,1.2093916907612609E-1,1.2656020928572972E-1,1.3200576860502294E-1,1.3722186246264678E-1,1.421614595398584E-1,1.4678545843064592E-1,1.5106279701440836E-1,1.5496983000189565E-1,1.5848918663036304E-1,1.6160835417720987E-1,1.6431822533021273E-1,1.6661180761691835E-1,1.6848323395306075E-1,1.6992714789352495E-1,1.7093847587855912E-1,1.7151254863622567E-1,1.71645498418909E-1,1.7133483862220733E-1,1.7058012635314282E-1,1.6938361432959154E-1,1.6775081316458038E-1,1.656909054685399E-1,1.6321697620187664E-1,1.6034604652417206E-1,7.328062200749563E-2,7.829635316212269E-2,8.350791194843657E-2,8.890440560043056E-2,9.44617462065804E-2,1.0014354146574167E-1,1.0590303948328571E-1,1.1168586795609013E-1,1.1743325202109664E-1,1.230853599476396E-1,1.2858442568080405E-1,1.3387734099207288E-1,1.389174960891539E-1,1.436657628054548E-1,1.480906377761761E-1,1.521676716083458E-1,1.5587838618769528E-1,1.592089171889429E-1,1.6214861354856888E-1,1.646887886107044E-1,1.6682176118723602E-1,1.6854026144072573E-1,1.6983721660594517E-1,1.7070588205100448E-1,1.7114024762843036E-1,1.7113562855808445E-1,1.7068934321311038E-1,1.6980138498909014E-1,1.6847500915015404E-1,1.6671717513716497E-1,1.6453880727955691E-1,1.619548593974619E-1,7.02506244331058E-2,7.517500134109763E-2,8.030312125590737E-2,8.562519732966696E-2,9.111866520040829E-2,9.674897387263341E-2,1.0247139853449788E-1,1.082336328281153E-1,1.1397886131015743E-1,1.1964897584560365E-1,1.251875962966056E-1,1.3054259525974382E-1,1.3566790771668966E-1,1.4052451690535459E-1,1.4508062714713357E-1,1.49311140667288E-1,1.5319663105287457E-1,1.5672204197232734E-1,1.5987533663481734E-1,1.6264628908347753E-1,1.650255545510413E-1,1.6700409490218476E-1,1.6857297672077412E-1,1.6972351076046238E-1,1.7044766593054156E-1,1.707386697722809E-1,1.7059169967966725E-1,1.7000457296136887E-1,1.689783566140318E-1,1.675178364768799E-1,1.656318073299444E-1,1.6333316774036236E-1,6.733862486889698E-2,7.216788871510699E-2,7.720781736991664E-2,8.244971318198167E-2,8.787251369082968E-2,9.344348934300035E-2,9.911993121422946E-2,1.048516024719333E-1,1.1058367008043668E-1,1.1625979464470604E-1,1.2182504999741198E-1,1.2722837944377607E-1,1.324243719243314E-1,1.373742471012274E-1,1.42046053972731E-1,1.464141915581587E-1,1.5045843514251042E-1,1.5416268844324868E-1,1.5751368092042448E-1,1.6049979760877214E-1,1.6311017751462248E-1,1.6533415752129202E-1,1.6716108172760347E-1,1.6858044803014222E-1,1.6958232828344416E-1,1.7015797671493518E-1,1.7030053279757304E-1,1.700057277011848E-1,1.6927251529742454E-1,1.6810356670207402E-1,1.665055886494016E-1,1.6448944790236666E-1,6.454366138906592E-2,6.927485550980211E-2,7.422270136458202E-2,7.937956788752908E-2,8.472586594720995E-2,9.023065935106478E-2,9.58532342245915E-2,1.015454157942316E-1,1.0725436414460882E-1,1.129255405655588E-1,1.1850552718366796E-1,1.2394441406777608E-1,1.291975397955113E-1,1.3422647265532597E-1,1.3899923147120685E-1,1.4348984656292035E-1,1.47677435525023E-1,1.5154500612342173E-1,1.5507819932111497E-1,1.582641560210287E-1,1.610906422296889E-1,1.6354551032145098E-1,1.6561651852372203E-1,1.6729148339886685E-1,1.68558704752663E-1,1.694075803653088E-1,1.6982931875154336E-1,1.698176601918504E-1,1.6936952723473175E-1,1.6848554309183383E-1,1.6717037706397594E-1,1.6543289768565686E-1,6.18643043485554E-2,6.649520695018594E-2,7.134787268481069E-2,7.64157095007746E-2,8.16805671319904E-2,8.711326757191226E-2,9.267506270162267E-2,9.831982250244337E-2,1.0399669979949444E-1,1.0965297641987355E-1,1.1523678436144769E-1,1.2069942350483365E-1,1.259970648673038E-1,1.3109172517199766E-1,1.3595150658806976E-1,1.4055019457880083E-1,1.448663800868097E-1,1.4888231050382114E-1,1.5258267629498787E-1,1.559535130216305E-1,1.5898135199232957E-1,1.61652697787691E-1,1.6395385681016617E-1,1.6587109447161702E-1,1.6739106347121507E-1,1.6850142326659664E-1,1.6919156099180074E-1,1.6945332527116386E-1,1.6928169446608834E-1,1.6867531733358054E-1,1.676368841873866E-1,1.661733078195839E-1,5.929872055299634E-2,6.382777958581778E-2,6.858289698092745E-2,7.355848802952523E-2,7.873780193882805E-2,8.409337767592705E-2,8.958839625304131E-2,9.51787464248911E-2,1.0081556343631543E-1,1.0644795850732537E-1,1.120256433335888E-1,1.1750117850495287E-1,1.2283163809328841E-1,1.2797957517322925E-1,1.329132774582284E-1,1.376063988530783E-1,1.4203712505033392E-1,1.461870699906083E-1,1.5004010400123585E-1,1.5358128947975627E-1,1.5679605576140446E-1,1.596696918236563E-1,1.6218718285151823E-1,1.6433337098499415E-1,1.660933856456326E-1,1.6745326623070567E-1,1.6840068950825945E-1,1.6892571444526058E-1,1.6902146644598015E-1,1.6868469865004782E-1,1.6791618744095846E-1,1.6672094008080557E-1,5.684473288382776E-2,6.1271003462244275E-2,6.59268702691471E-2,7.080772095665232E-2,7.589816077503632E-2,8.117239939989569E-2,8.659550407999704E-2,9.212534878932246E-2,9.771503204080301E-2,1.0331549337874386E-1,1.0887804326478805E-1,1.1435654261999614E-1,1.1970902772709517E-1,1.2489866460090952E-1,1.2989401776690188E-1,1.3466871253828563E-1,1.3920064116808803E-1,1.434709023014898E-1,1.4746266858944926E-1,1.5116015443751984E-1,1.5454781383801736E-1,1.5760984720080448E-1,1.603300449264992E-1,1.6269195062459604E-1,1.6467929223469494E-1,1.6627660649553283E-1,1.6746997119751017E-1,1.682477592997255E-1,1.6860133742361053E-1,1.6852564615047846E-1,1.6801961843800223E-1,1.6708641281737746E-1,5.4499875354533066E-2,5.8822960026366375E-2,6.337847921201632E-2,6.816275535098128E-2,7.316170308454084E-2,7.835115238981312E-2,8.36980085775233E-2,8.916209075705013E-2,9.469843378773762E-2,1.002597955845196E-1,1.0579909466282485E-1,1.1127152150240298E-1,1.1663612304959872E-1,1.2185674412951673E-1,1.2690230686902162E-1,1.3174650091971324E-1,1.3636702745325163E-1,1.407445791993057E-1,1.4486174554933412E-1,1.4870201080895923E-1,1.5224897377146415E-1,1.5548586765628092E-1,1.5839540973099536E-1,1.609599659738539E-1,1.631619818094852E-1,1.6498460698179332E-1,1.6641243111547996E-1,1.674322454520806E-1,1.6803375389360975E-1,1.6821017066007754E-1,1.6795866014095157E-1,1.6728059443601928E-1,5.226144363762802E-2,5.648143572635613E-2,6.0936057394574604E-2,6.562252635345389E-2,7.052801750430163E-2,7.562992741307144E-2,8.08969469156249E-2,8.629079462013302E-2,9.176840804599463E-2,9.72843456379591E-2,1.0279313442624513E-1,1.0825131415742366E-1,1.1361898095935473E-1,1.1886071426070668E-1,1.2394586460377961E-1,1.2884826923137044E-1,1.3354553135782873E-1,1.3801803848387223E-1,1.422479030679019E-1,1.4621798976176564E-1,1.499111555378224E-1,1.5330978175778617E-1,1.5639562893802997E-1,1.5915000189803033E-1,1.615541790093841E-1,1.6359003618514825E-1,1.6524078428128972E-1,1.6649173684770385E-1,1.6733103206053987E-1,1.6775024611549816E-1,1.6774485302420153E-1,1.6731450522951588E-1],[3.4818916670946853E-1,9.993548592494965E-1,9.974483417219177E-1,9.943273246445654E-1,9.900429236451004E-1,9.846499188395631E-1,9.782061810569083E-1,9.707721048938651E-1,9.624100546867816E-1,9.531838288296345E-1,9.43158147176909E-1,9.323981655629012E-1,9.209690207602063E-1,9.089354085032382E-1,8.963611965294114E-1,8.833090739511444E-1,8.698402376743603E-1,8.560141160300803E-1,8.41888129289738E-1,8.275174862950373E-1,8.129550160510871E-1,7.98251032807374E-1,7.83453232883883E-1,7.686066212873544E-1,7.537534660024234E-1,7.3893327773075E-1,7.241828127841875E-1,7.095360968112553E-1,6.950244670451066E-1,6.806766308012302E-1,6.665187380196967E-1,6.525744657354096E-1,6.666341734258499E-2,3.4795354733568834E-1,9.993680548405822E-1,9.975010677807784E-1,9.94445669066624E-1,9.902525212599069E-1,9.849757601950682E-1,9.78672437687523E-1,9.714019723260724E-1,9.632256140803349E-1,9.542059278088673E-1,9.444063000812735E-1,9.338904730434728E-1,9.227221083734339E-1,9.109643837076126E-1,8.986796232768969E-1,8.859289638842373E-1,8.727720567916875E-1,8.592668055680243E-1,8.454691394834805E-1,8.314328216279495E-1,8.172092905744107E-1,8.028475341101537E-1,7.883939933134303E-1,7.738924950602819E-1,7.593842109026118E-1,7.449076401605769E-1,7.304986150161976E-1,7.161903253764743E-1,7.02013361288937E-1,6.879957707360078E-1,6.741631307024765E-1,7.236338025742114E-2,6.614759464576385E-2,3.477151115965263E-1,9.99381271487806E-1,9.975538655417278E-1,9.945641497578607E-1,9.904623222497156E-1,9.853018675502956E-1,9.79139015778329E-1,9.720322110484868E-1,9.640415945106974E-1,9.552285067718366E-1,9.456550137996048E-1,9.353834597477035E-1,9.244760494865363E-1,9.129944629861529E-1,9.009995030879598E-1,8.885507776271209E-1,8.757064163351951E-1,8.625228224673811E-1,8.490544586642345E-1,8.353536661759063E-1,8.214705162485445E-1,8.074526921970844E-1,7.933454004647955E-1,7.791913087954121E-1,7.650305095155071E-1,7.50900505839541E-1,7.368362190638976E-1,7.228700145051417E-1,7.090317440575218E-1,6.953488032911813E-1,7.805883746248292E-2,7.176035601472486E-2,6.562542413295444E-2,3.474734021327585E-1,9.993945019507333E-1,9.976067061260816E-1,9.946827020169517E-1,9.906722122200599E-1,9.856280633399952E-1,9.796056615676314E-1,9.726624785705558E-1,9.648575527449937E-1,9.562510102613846E-1,9.469036097018926E-1,9.36876313451182E-1,9.262298883738411E-1,9.15024537703556E-1,9.033195654895635E-1,8.911730744025238E-1,8.78641697200634E-1,8.657803617018911E-1,8.526420887028222E-1,8.392778219292906E-1,8.257362888015327E-1,8.120638905426897E-1,7.983046199561747E-1,7.845000050399203E-1,7.706890764919209E-1,7.569083570881331E-1,7.431918708769882E-1,7.295711701305823E-1,7.160753780170285E-1,8.37207177200519E-2,7.736809849575911E-2,7.114998836353424E-2,6.50960194887204E-2,3.4722806810814705E-1,9.994077390008669E-1,9.976595607074736E-1,9.948012612635014E-1,9.908820769847569E-1,9.859541702949028E-1,9.800721216509833E-1,9.73292432759287E-1,9.656730458057963E-1,9.572728828236415E-1,9.481514087062893E-1,9.383682207622034E-1,9.279826671056141E-1,9.170534955985626E-1,9.056385345097879E-1,8.937944055429861E-1,8.815762694156951E-1,8.690376037442755E-1,8.56230012612578E-1,8.432030668730567E-1,8.300041739493539E-1,8.166784756778287E-1,8.032687725403782E-1,7.898154724998002E-1,7.763565625489073E-1,7.629276010222821E-1,7.495617286913436E-1,7.362896966654812E-1,8.932116713086129E-2,8.294271663265493E-2,7.66689553028363E-2,7.053136588084138E-2,6.455873960774466E-2,3.469788722400132E-1,9.994209754262707E-1,9.977124005302925E-1,9.949197630793704E-1,9.910918026390966E-1,9.862800115556842E-1,9.805381431447582E-1,9.739217320613577E-1,9.664876312607719E-1,9.582935693743502E-1,9.493977317314167E-1,9.398583676695319E-1,9.297334262008945E-1,9.190802215515701E-1,9.079551295699132E-1,8.964133155169763E-1,8.845084933094317E-1,8.722927158877561E-1,8.598161960310623E-1,8.471271566357941E-1,8.342717092182916E-1,8.212937591898488E-1,8.082349362854719E-1,7.951345484016291E-1,7.820295570109181E-1,7.689545722694922E-1,7.55941865912747E-1,9.483379062876512E-2,8.845730871247698E-2,8.215517620462781E-2,7.596048561857036E-2,6.990387457113967E-2,6.401319284952156E-2,3.46725687899044E-1,9.994342040361778E-1,9.977651969280535E-1,9.950381432498806E-1,9.913012756328854E-1,9.866054107868111E-1,9.810034738499062E-1,9.745500357259334E-1,9.673008675139496E-1,9.593125155682317E-1,9.50641900153788E-1,9.413459400981588E-1,9.314812052921729E-1,9.211035983690758E-1,9.102680663996595E-1,8.990283429860253E-1,8.874367207223072E-1,8.755438536197833E-1,8.633985887677764E-1,8.510478262210525E-1,8.385364058685574E-1,8.259070198459959E-1,8.132001489039902E-1,8.004540210318392E-1,7.877045905613462E-1,7.749855359325366E-1,1.0023385823841405E-1,9.388640475383117E-2,8.758269187278907E-2,8.135717673290092E-2,7.524211593224268E-2,6.926719201197339E-2,6.345922173287118E-2,3.464684885553919E-1,9.994474176655757E-1,9.978179213416922E-1,9.951563378048711E-1,9.91510382843296E-1,9.869301922902859E-1,9.814678624157723E-1,9.75177004028025E-1,9.681123140983771E-1,9.603291681710954E-1,9.518832362699665E-1,9.428301244725777E-1,9.332250438013301E-1,9.231225075842632E-1,9.125760579747748E-1,9.01638021891946E-1,8.903592962558186E-1,8.78789162046813E-1,8.669751264166359E-1,8.549627918196302E-1,8.427957509178591E-1,8.30515505838827E-1,8.181614102295953E-1,8.057706324526064E-1,7.933781382039249E-1,1.0549847556156967E-1,9.920616049573139E-2,9.292694748173169E-2,8.669641183674368E-2,8.054819729057369E-2,7.45136047397593E-2,6.862126080707752E-2,6.28968733339533E-2,3.462073319839368E-1,9.994606091797694E-1,9.978705453377668E-1,9.952742830595734E-1,9.917190116474688E-1,9.872541811191322E-1,9.819310585038531E-1,9.758022984922096E-1,9.68921531969932E-1,9.613429754343787E-1,9.531210637630578E-1,9.44310108287081E-1,9.349639816262207E-1,9.251358302729811E-1,9.148778154760852E-1,9.042408825731103E-1,8.93274558560519E-1,8.820267773688157E-1,8.705437320317514E-1,8.588697527012652E-1,8.4704720926328E-1,8.351164371519647E-1,8.231156848395703E-1,8.110810813928638E-1,1.1060671867107737E-1,1.0439451700844644E-1,9.816497463620519E-2,9.195454014811431E-2,8.579801097240322E-2,7.972808746346381E-2,7.377500427706186E-2,6.796624776123661E-2,6.2326360675583954E-2,3.459423415392702E-1,9.994737714789173E-1,9.979230406265566E-1,9.953919156552788E-1,9.919270499948143E-1,9.875772031905675E-1,9.823928129513644E-1,9.764255821165376E-1,9.697280838020438E-1,9.623533874717977E-1,9.543547081731226E-1,9.457850806825444E-1,9.366970598372497E-1,9.27142447884324E-1,9.171720492690548E-1,9.068354529086567E-1,8.961808416611363E-1,8.852548284020302E-1,8.741023178648527E-1,8.627663931839015E-1,8.512882258994997E-1,8.397070080441228E-1,8.280599048210152E-1,1.155397342293497E-1,1.0943132621614156E-1,1.0327554043618803E-1,9.71094579903867E-2,9.096879765736307E-2,8.48874385472875E-2,7.889701703443439E-2,7.302660827088561E-2,6.730249495345574E-2,6.1748019961046056E-2,3.456736865359939E-1,9.994868975025355E-1,9.979753790800454E-1,9.955091725997682E-1,9.92134386478962E-1,9.878990853987701E-1,9.828528779344945E-1,9.770465195964437E-1,9.705315342810749E-1,9.633598566377714E-1,9.555834973710735E-1,9.472542330291515E-1,9.38423321383244E-1,9.291412430849564E-1,9.194574699028231E-1,9.094202594894056E-1,8.990764763173518E-1,8.884714381483065E-1,8.776487871624781E-1,8.666503846784286E-1,8.555162282310486E-1,8.44284389648908E-1,1.2028080620377582E-1,1.142984432156762E-1,1.0823926393733366E-1,1.0214074766785743E-1,9.603930571523277E-2,8.996977594535895E-2,8.396498817489127E-2,7.805541223538826E-2,7.226889272637896E-2,6.663046817253157E-2,6.11622677608469E-2,3.4540156338856154E-1,9.99499980233971E-1,9.980275327497746E-1,9.956259913074764E-1,9.923409104093047E-1,9.882196557271598E-1,9.83311007131214E-1,9.776647775484774E-1,9.713314504021094E-1,9.643618379072819E-1,9.568067620356075E-1,9.487167595144769E-1,9.401418118058993E-1,9.311311006162867E-1,9.217327891276252E-1,9.119938288141648E-1,9.019597914186847E-1,8.916747254092275E-1,8.811810360208424E-1,8.705193878065349E-1,8.597286284759521E-1,1.24815391020701E-1,1.1897978679075955E-1,1.1303870095028322E-1,1.070297851976292E-1,1.0098992027211282E-1,9.495468579288871E-2,8.895789713046753E-2,8.303122260892831E-2,7.720388637828966E-2,7.150245577176129E-2,6.595070716975363E-2,6.056956134742899E-2,3.4512617873664075E-1,9.995130127048374E-1,9.980794738845561E-1,9.957423096393623E-1,9.925465118820856E-1,9.885387433601017E-1,9.837669558835108E-1,9.782800247336658E-1,9.721274017648858E-1,9.653587892568128E-1,9.580238361327086E-1,9.5017185773633E-1,9.418515799620314E-1,9.33110908163534E-1,9.239967209294266E-1,9.145546885100138E-1,9.048291154117954E-1,8.94862806443022E-1,8.846969552960838E-1,8.743710545890286E-1,1.2913112338150348E-1,1.2346136995265114E-1,1.1765839859795343E-1,1.1175981789149958E-1,1.0580276256737736E-1,9.982334206077648E-2,9.385615194855271E-2,8.793386299525072E-2,8.20868944333752E-2,7.6343171384937E-2,7.072796130418933E-2,6.52637810395051E-2,5.997036441249021E-2,3.4484773535561053E-1,9.995259879994113E-1,9.981311749480314E-1,9.958580659424545E-1,9.927510818509754E-1,9.888561787939514E-1,9.842204813589214E-1,9.788919322803175E-1,9.729189608696063E-1,9.663501720460059E-1,9.592340573972391E-1,9.516187292997312E-1,9.435516787528411E-1,9.350795572356914E-1,9.262479825805359E-1,9.171013685750606E-1,9.076827777584034E-1,8.98033796662132E-1,8.881944325673775E-1,1.3321779525980693E-1,1.2773130268728508E-1,1.2208492144634235E-1,1.1631601322000558E-1,1.1046176063711478E-1,1.0455859790576529E-1,9.864169994475536E-2,9.274454605752191E-2,8.689856602631979E-2,8.113286961086957E-2,7.547405519378414E-2,6.994608981019032E-2,6.457025089385156E-2,5.936511948865592E-2,3.445664212628096E-1,9.995388992589868E-1,9.981826086360648E-1,9.959731990890485E-1,9.92954512197086E-1,9.89171793947351E-1,9.846713427112228E-1,9.795001739060749E-1,9.737057034123544E-1,9.673354513996654E-1,9.60436767816125E-1,9.530565804173761E-1,9.452411658593592E-1,9.370359440553354E-1,9.284852957048942E-1,9.196324026420796E-1,9.105191104218897E-1,9.011858123691289E-1,1.370673108116269E-1,1.317797693555591E-1,1.2630685134163822E-1,1.2068548075358987E-1,1.149526927627696E-1,1.0914504978580003E-1,1.0329811142293831E-1,9.744597558511896E-2,9.162089988934609E-2,8.585300536147936E-2,8.01700590486344E-2,7.459732842980658E-2,6.915749841210785E-2,6.387064095062621E-2,5.875422759687389E-2,3.4428240210159805E-1,9.995517396861844E-1,9.982337478939591E-1,9.960876485155217E-1,9.931566957983712E-1,9.894854222706941E-1,9.851193012401567E-1,9.801044261390204E-1,9.744872085798427E-1,9.683140965897299E-1,9.616313141126271E-1,9.544846225129185E-1,9.469191044832108E-1,9.389789704571925E-1,9.307073873566782E-1,9.221463292613464E-1,9.133364493805411E-1,1.406736200649777E-1,1.3559898338239995E-1,1.3031476332634065E-1,1.2485726926331024E-1,1.1926320545459286E-1,1.1356907577977648E-1,1.0781063755862073E-1,1.0202242296314978E-1,9.623733824887784E-2,9.048634387031167E-2,8.479821293400978E-2,7.91993615347785E-2,7.371374223300428E-2,6.836279102118646E-2,6.31654182696238E-2,5.813803499086479E-2,3.439958166284323E-1,9.995645025492119E-1,9.982845659334812E-1,9.962013542607432E-1,9.933575265983594E-1,9.89796898854669E-1,9.855641205500468E-1,9.807043685376385E-1,9.752630593432108E-1,9.692855814168251E-1,9.628170482311769E-1,9.559020728263847E-1,9.485845640918077E-1,9.409075447943216E-1,9.32912991110788E-1,9.246416932009047E-1,1.4403263431872665E-1,1.3918312198590949E-1,1.3410118017352712E-1,1.2882234127817813E-1,1.2338280799909226E-1,1.1781884985162612E-1,1.1216624387968557E-1,1.0645977916045003E-1,1.0073283642191237E-1,9.501704683043805E-2,8.934202823805998E-2,8.373519309239089E-2,7.8221619748272E-2,7.282397785576075E-2,6.756249851864714E-2,6.2454980680768137E-2,5.751682638480566E-2,3.437067749455913E-1,9.99577181186074E-1,9.98335036249686E-1,9.963142570040474E-1,9.935568996741678E-1,9.901060605377963E-1,9.860055667071795E-1,9.812996839094343E-1,9.760328427505891E-1,9.702493845910031E-1,9.639933278222416E-1,9.5730815502101E-1,9.502366211670468E-1,9.428205828507382E-1,9.351008481637326E-1,1.4714212617942485E-1,1.4252824374686185E-1,1.3766050817652345E-1,1.3257352754179746E-1,1.273028457906586E-1,1.2188433403215167E-1,1.1635362105090508E-1,1.1074558365968913E-1,1.0509390924107759E-1,9.943073548857871E-2,9.378636645382743E-2,8.81890597553643E-2,8.266487717514515E-2,7.72375896562324E-2,7.192862761571549E-2,6.67570681643055E-2,6.173965195801753E-2,5.689082372705514E-2,3.434153590092914E-1,9.995897690087271E-1,9.983851326375266E-1,9.964262981027466E-1,9.937547113037475E-1,9.904127460128738E-1,9.864434083958097E-1,9.818900585280105E-1,9.767961502181429E-1,9.712049901112697E-1,9.65159516726677E-1,9.587020997907757E-1,9.518743599565707E-1,9.447170087592602E-1,1.5000161710755472E-1,1.4563219180806933E-1,1.40988956867059E-1,1.3610546389285183E-1,1.3101645479388885E-1,1.2575725066104906E-1,1.20363174877852E-1,1.1486903199932104E-1,1.0930865571711959E-1,1.0371453183189179E-1,9.811749613223503E-2,9.254650267947223E-2,8.702845521295298E-2,8.15880930367756E-2,7.624792253396191E-2,7.102818604721918E-2,6.594686094588366E-2,6.101968299134214E-2,5.626018940550196E-2,3.4312162489108716E-1,9.99602259507179E-1,9.984348292082402E-1,9.965374196291529E-1,9.939508590323058E-1,9.907167959322425E-1,9.868774170726591E-1,9.824751823483971E-1,9.775525778193042E-1,9.721518876434906E-1,9.663149854590117E-1,9.600831454679032E-1,9.53496873226613E-1,1.5261225523931798E-1,1.4849448543040147E-1,1.4408444531556708E-1,1.394145131178647E-1,1.3451849955001077E-1,1.294310369400578E-1,1.2418699759438669E-1,1.1882096378352064E-1,1.1336676356903788E-1,1.0785707925732159E-1,1.023231291448008E-1,9.67944186844172E-2,9.129855427453373E-2,8.586111138355486E-2,8.050554839727793E-2,7.525315808651266E-2,7.012304961962589E-2,6.513215530989552E-2,6.02952575721946E-2,5.5625032715897575E-2,3.4282560626827846E-1,9.996146462535273E-1,9.984841004054971E-1,9.966475644070846E-1,9.941452417378585E-1,9.910180530117882E-1,9.87307367119771E-1,9.830547492204369E-1,9.783017265718985E-1,9.730895728962679E-1,9.674591116890999E-1,9.614505386295489E-1,1.5497668610508178E-1,1.5111620252532726E-1,1.4694649759987027E-1,1.4249867429756014E-1,1.3780549715403623E-1,1.3290078410149073E-1,1.2781882259011607E-1,1.2259383314599427E-1,1.1725949541738225E-1,1.1184854431189693E-1,1.0639243762365408E-1,1.0092109189437252E-1,9.546268019049169E-2,9.004348386376522E-2,8.468778992942874E-2,7.941782612590449E-2,7.425372669435458E-2,6.921352315375785E-2,6.431315562366342E-2,5.95665014042508E-2,5.498541846683186E-2,3.4252731865446495E-1,9.99626922905936E-1,9.985329210213018E-1,9.967566760478291E-1,9.94337759695857E-1,9.913163621335931E-1,9.877330359955864E-1,9.836284571000179E-1,9.790432027228748E-1,9.740175479943693E-1,9.685912807215705E-1,1.5709891868920256E-1,1.534998556407225E-1,1.4957612992055974E-1,1.4535748209675456E-1,1.4087552959525088E-1,1.3616316349991556E-1,1.312539647751013E-1,1.2618166373080847E-1,1.2097965854864579E-1,1.1568060123811919E-1,1.1031605312355222E-1,1.0491620720051996E-1,9.950967151627514E-2,9.412330599462437E-2,8.878210458985862E-2,8.350911500583766E-2,7.832538913851454E-2,7.324995860956335E-2,6.82998310267396E-2,6.349000376876887E-2,5.883349304803101E-2,5.434137670667882E-2,3.422267639425859E-1,9.996390832125471E-1,9.985812662116356E-1,9.968646989855384E-1,9.945283146428466E-1,9.916115704471521E-1,9.88154204384108E-1,9.84196008257953E-1,9.797766180303382E-1,9.74935321849293E-1,1.5898418907572118E-1,1.5564926370504126E-1,1.5197573170052686E-1,1.4799189833940374E-1,1.4372814677919593E-1,1.3921634189488516E-1,1.344892487740231E-1,1.2957999028305947E-1,1.245215602222729E-1,1.1934640115511665E-1,1.1408604967835198E-1,1.087708470450992E-1,1.0342970975655455E-1,9.808995289218617E-2,9.277715831459472E-2,8.751508016068336E-2,8.23255809018E-2,7.722859243686674E-2,7.224209794155521E-2,6.738213136334091E-2,6.26627924196536E-2,5.809627567275559E-2,5.3692912713796226E-2,3.4192393490903017E-1,9.996511210153245E-1,9.986291115118302E-1,9.969715785120278E-1,9.947168098391006E-1,9.91903527469072E-1,9.885706563420169E-1,9.847571094863035E-1,9.805015900425904E-1,1.606388237079319E-1,1.575694216420191E-1,1.5414894283937186E-1,1.5040419807209376E-1,1.4636426244094664E-1,1.4205988811559275E-1,1.3752292709707595E-1,1.3278578892951073E-1,1.2788095051138357E-1,1.2284052775731556E-1,1.176959125062277E-1,1.1247747313770298E-1,1.0721431396018535E-1,1.0193408648443124E-1,9.666284496877507E-2,9.14249388250196E-2,8.624293529448017E-2,8.113756695721551E-2,7.612769988737463E-2,7.123031943866072E-2,6.646053162342505E-2,6.18315787798514E-2,5.735486869303401E-2,5.304001656933374E-2,3.416188194096732E-1,9.99663030253827E-1,9.9867643285166E-1,9.970772608109559E-1,9.949031501301854E-1,9.921920851811669E-1,9.889821794436098E-1,9.853114723019412E-1,1.6207010406349306E-1,1.592663697607706E-1,1.5610052910781103E-1,1.525978521576935E-1,1.4878604502409476E-1,1.4469467319056475E-1,1.4035459035591286E-1,1.3579739818006417E-1,1.3105495464890973E-1,1.261589414229514E-1,1.211404941578119E-1,1.160298947829277E-1,1.1085632123493473E-1,1.0564764809487234E-1,1.0043029076333491E-1,9.522908593922852E-2,9.006720193953299E-2,8.496607352324027E-2,7.994535712319653E-2,7.502290356479399E-2,7.021474634211107E-2,6.553510426814078E-2,6.09963978005613E-2,5.6609278586929705E-2,5.238267181433432E-2,3.4131140407970867E-1,9.996748049689095E-1,9.98723206570144E-1,9.971816929913597E-1,9.950872420074072E-1,9.924770981268698E-1,9.893885649234232E-1,1.6328613431661532E-1,1.6074706461049024E-1,1.5783625746892896E-1,1.5457740826253766E-1,1.509968054435558E-1,1.4712276589322393E-1,1.4298507148620263E-1,1.3861443260067977E-1,1.3404199679794296E-1,1.2929891359945386E-1,1.2441595990381002E-1,1.194232255282413E-1,1.1434985478736119E-1,1.0922383788476639E-1,1.0407184499453143E-1,9.891909597347734E-2,9.378925936891017E-2,8.870437548501023E-2,8.368479950203575E-2,7.874916182163659E-2,7.391434381549565E-2,6.919546791602005E-2,6.460590148706936E-2,6.015727416520502E-2,5.5859508406821065E-2,5.1720862865503495E-2,3.4100167742363147E-1,9.996864393063474E-1,9.987694094300472E-1,9.972848231205189E-1,9.952689936670941E-1,9.927584235058778E-1,1.6429571333010423E-1,1.6201925277059515E-1,1.5936277290792358E-1,1.5634837191118564E-1,1.5300088347916835E-1,1.493473255032534E-1,1.4541634580938845E-1,1.412376910028621E-1,1.3684171708405485E-1,1.3225895327683818E-1,1.275197241283239E-1,1.2265382983603193E-1,1.1769028111369628E-1,1.1265708268706882E-1,1.0758105853386202E-1,1.0248771198081084E-1,9.740111444821621E-2,9.234381770377013E-2,8.73367857087566E-2,8.239934332260829E-2,7.754914014791998E-2,7.280212857542477E-2,6.817255560296359E-2,6.367296826626978E-2,5.931423256955523E-2,5.510556569099279E-2,5.1054581017501814E-2,3.4068963224610493E-1,9.99697927520385E-1,9.988150186320703E-1,9.973866002561281E-1,9.954483150686656E-1,1.6510821209698537E-1,1.6309134883066922E-1,1.6068747814497006E-1,1.5791708908770724E-1,1.5480353436648855E-1,1.5137249341972478E-1,1.4765142862088376E-1,1.4366906086952716E-1,1.394548836234638E-1,1.350387272788588E-1,1.3045037943575818E-1,1.257192614490808E-1,1.208741579563547E-1,1.1594299377749946E-1,1.1095265153096924E-1,1.0592882324716205E-1,1.0089588989237523E-1,9.587682376138099E-2,9.089310990818783E-2,8.596468397093006E-2,8.110988477514348E-2,7.63454208932817E-2,7.168635086884122E-2,6.714607708975685E-2,6.273635335254128E-2,5.8467306045707865E-2,5.434746865304851E-2,5.038382898805671E-2,3.403752674268833E-1,9.99709263977202E-1,9.988600118287186E-1,9.974869744777514E-1,1.6573345753780397E-1,1.6397231860418715E-1,1.6181841740127031E-1,1.5929063166646626E-1,1.5641081696600212E-1,1.5320328508993464E-1,1.4969427183494488E-1,1.4591142059706558E-1,1.4188330115935122E-1,1.3763897599969246E-1,1.3320762009786952E-1,1.2861819505852276E-1,1.2389917460218522E-1,1.1907831611117536E-1,1.1418247179683612E-1,1.0923743293200396E-1,1.0426780118122418E-1,9.929688207987879E-2,9.434659691498666E-2,8.94374104500382E-2,8.458827297660977E-2,7.981657598558475E-2,7.513812129791379E-2,7.056710378467404E-2,6.611610787118341E-2,6.179611790836697E-2,5.761654226122862E-2,5.358525066312296E-2,4.9708624062977366E-2,3.400585890826967E-1,9.997204431582986E-1,9.989043671378409E-1,1.661816233583378E-1,1.6467156841882724E-1,1.6276416519003925E-1,1.6047668676224613E-1,1.578294847065291E-1,1.548454835422707E-1,1.515496610528632E-1,1.4796854098348522E-1,1.4412971778410313E-1,1.4006142609617206E-1,1.357921613676611E-1,1.313503528023436E-1,1.2676408603698838E-1,1.2206087051159824E-1,1.1726744531280128E-1,1.1240961709140794E-1,1.075121242016012E-1,1.0259852220214652E-1,9.76910870515814E-2,9.28107335219307E-2,8.797694740781328E-2,8.320773093442914E-2,7.851956133225356E-2,7.39273628505853E-2,6.944449255650854E-2,6.508274015730535E-2,6.085234184727047E-2,5.6762007868497645E-2,5.2818963138110124E-2,4.902899997131084E-2,3.3973961118665075E-1,9.997314596637957E-1,1.664631284855252E-1,1.651988411370026E-1,1.635337209150384E-1,1.6148345090285E-1,1.5906688031656466E-1,1.563055356362442E-1,1.5322311425471338E-1,1.4984498723697512E-1,1.4619773108212814E-1,1.4230870151649833E-1,1.3820565607299048E-1,1.339164270250062E-1,1.2946864239050085E-1,1.2488949023620453E-1,1.2020552026656728E-1,1.1544247644925042E-1,1.1062515493469885E-1,1.0577728249493104E-1,1.0092141188827555E-1,9.607883175192904E-2,9.126948968829904E-2,8.651192805433884E-2,8.182323254508181E-2,7.721899398225408E-2,7.271328380390724E-2,6.831864364701597E-2,6.40460891757461E-2,5.990512798821487E-2,5.590379108348423E-2,5.204867702908476E-2,4.8345007668273515E-2,3.394183557322981E-1],[],[2.3484847943024147E-3,2.5677980143997087E-4,4.536936299722191E-6,-1.5773719851328854E-5,1.0337959120253224E-4,3.3912345192464065E-4,6.830193883652697E-4,1.127621684055988E-3,2.2574661410169946E-3,3.294242172890316E-3,4.174535439072986E-3,4.887894866827515E-3,5.489523046211192E-3,6.067679229855007E-3,6.709071753652108E-3,7.482424672107779E-3,8.436341967620763E-3,9.60244248871972E-3,1.0998659745293404E-2,1.2631377639715217E-2,1.4496805376065031E-2,1.658242137938766E-2,1.8869149610478884E-2,2.1334508748381387E-2,2.395647686431518E-2,2.671741036268653E-2,2.9607196845643623E-2,3.262496573977787E-2,3.577905208094331E-2,3.908533906883537E-2,4.256442960985214E-2,4.623823544907833E-2,2.174264776801302E-3,2.3632352901462427E-4,2.4958779324966663E-6,-1.6070883953087953E-5,9.497731513193247E-5,3.14516245186737E-4,6.348413677366091E-4,1.0492068420398335E-3,2.1036962527136837E-3,3.0729269982837236E-3,3.897829921067466E-3,4.568624072499846E-3,5.13682486716846E-3,5.684968836446435E-3,6.294353638228048E-3,7.029664330213781E-3,7.936923132926956E-3,9.046362734653566E-3,1.03754600764142E-2,1.1930887800637318E-2,1.370976077167405E-2,1.5700957849477157E-2,1.788714593206904E-2,2.0247736797872107E-2,2.2762536986268483E-2,2.541546641127192E-2,2.8197566447684525E-2,3.1108650409059798E-2,3.415729875904884E-2,3.7359309202198515E-2,4.0735021955678984E-2,4.430607535861156E-2,2.015355347680294E-3,2.1777704450902678E-4,7.688545300900528E-7,-1.622828539940575E-5,8.73656228974442E-5,2.9201820412520286E-4,5.906868898026264E-4,9.772544518305212E-4,1.9623664653189467E-3,2.869293941588841E-3,3.642963266769472E-3,4.2742166828474565E-3,4.81118035033185E-3,5.331116335789574E-3,5.910321744489044E-3,6.609733796578897E-3,7.472962897658739E-3,8.528929097330034E-3,9.794654321633197E-3,1.1277047021535168E-2,1.2974032815034146E-2,1.487576526726736E-2,1.69665099168995E-2,1.9227422662546692E-2,2.1639999076661337E-2,2.4189604896183804E-2,2.6868347144436762E-2,2.9676666515313505E-2,3.2623360438641176E-2,3.572413297905179E-2,3.899906413061064E-2,4.246952237266092E-2,1.8703468931606708E-3,2.0095283546605198E-4,-6.870810706835746E-7,-1.6270588708797804E-5,8.046642680104603E-5,2.714409369903527E-4,5.502076993476526E-4,9.112142673048894E-4,1.8324415089125898E-3,2.681893872946673E-3,3.408172274213019E-3,4.0026980904634794E-3,4.510481071419058E-3,5.003920837107119E-3,5.554692148064247E-3,6.220254156635237E-3,7.041964252077073E-3,8.047500045593584E-3,9.253432203311339E-3,1.0666858101348622E-2,1.2286427891944703E-2,1.4103454433672957E-2,1.6103668580816435E-2,1.82698320246158E-2,2.058499938264624E-2,2.3035872110809433E-2,2.561554015217803E-2,2.8325018330370655E-2,3.117329405503809E-2,3.4175969841098434E-2,3.735286749343896E-2,4.072508855971655E-2,1.7379628202479106E-3,1.856823386644092E-4,-1.9093185532364094E-6,-1.6218875022141953E-5,7.420955195986903E-5,2.5261316724287407E-4,5.130859766114276E-4,8.505831392860814E-4,1.7129722047811808E-3,2.5093958652108147E-3,3.1918348736078767E-3,3.752248466533706E-3,4.232779897616611E-3,4.70134506808627E-3,5.225345169635484E-3,5.8590112301712075E-3,6.641595985797886E-3,7.599601585760336E-3,8.74915308998E-3,1.0097495418999625E-2,1.164392505051653E-2,1.338080832149278E-2,1.5295218355008846E-2,1.737139435416141E-2,1.95938289690471E-2,2.195045653753995E-2,2.443527242896827E-2,2.7049815577162812E-2,2.9803237938234337E-2,3.2711032948173874E-2,3.5792766009552696E-2,3.9069274256087125E-2,1.6170471929565036E-3,1.7181403234566996E-4,-2.9303824926003002E-6,-1.609112139277751E-5,6.853193887798714E-5,2.3537922289137576E-4,4.7903179480603586E-4,7.949012016089355E-4,1.603088793452309E-3,2.350578301468261E-3,2.9924598173828635E-3,3.521191825126336E-3,3.976280040754877E-3,4.421504806916282E-3,4.9203153975052845E-3,5.523946293147494E-3,6.2696841789668814E-3,7.182919596279229E-3,8.279339276279642E-3,9.566299298094053E-3,1.1043671628513878E-2,1.2704779175939089E-2,1.4537923893009695E-2,1.6528703666486972E-2,1.8662936668097364E-2,2.0929694219098002E-2,2.3323804675540138E-2,2.5847284241498104E-2,2.8509425587417456E-2,3.13256060366677E-2,3.4315136282998905E-2,3.749859132856143E-2,1.5065534591318583E-3,1.5921171457027676E-4,-3.7785422329314586E-6,-1.590262005972676E-5,6.337692368039492E-5,2.1959764894035168E-4,4.477807666324662E-4,7.437483249915901E-4,1.5019946926046808E-3,2.2043205212769553E-3,2.8086769558934963E-3,3.307985661704989E-3,3.7393246279420057E-3,4.162658744091949E-3,4.637782031527499E-3,5.213146996794503E-3,5.924203752166482E-3,6.795292067285195E-3,7.841668997247518E-3,9.070769917712003E-3,1.0482978220789302E-2,1.2072484732833323E-2,1.3828715759177983E-2,1.5738517914855296E-2,1.778893041325677E-2,1.997007226251345E-2,2.2277537222337513E-2,2.471377503314641E-2,2.7288196871841686E-2,3.001605749902114E-2,3.291641462545202E-2,3.600958331426141E-2,1.405534183631554E-3,1.4775295095893233E-4,-4.478348486580914E-6,-1.566634468796507E-5,5.869358906023269E-5,2.0513993482250168E-4,4.1909186991010306E-4,6.967408271041775E-4,1.4089606722535724E-3,2.069594995404473E-3,2.639228094225572E-3,3.1112111696218535E-3,3.5203868037376605E-3,3.923198799941905E-3,4.376059587649451E-3,4.924838537989619E-3,5.6032701453575876E-3,6.434701333246071E-3,7.433969284563699E-3,8.608560897556117E-3,9.959313136577908E-3,1.1481203725977378E-2,1.3164687191443217E-2,1.499775723142916E-2,1.6968577187938857E-2,1.906823072184579E-2,2.129301406071584E-2,2.364576976230688E-2,2.613600692798932E-2,2.8778851953605914E-2,3.159311142611204E-2,3.459884269161461E-2,1.3131317080897517E-3,1.3732767632429032E-4,-5.051104947121994E-6,-1.539326983170354E-5,5.443617950111262E-5,1.9188934890289702E-4,3.9274544223167566E-4,6.535284264567973E-4,1.323319432190492E-3,1.9454600147564346E-3,2.482958419858207E-3,2.9295640312822528E-3,3.3180603696437157E-3,3.7016409143864394E-3,4.13358899171314E-3,4.657375123104714E-3,5.305131183063126E-3,6.099266372446754E-3,7.0542087565046725E-3,8.177472668495007E-3,9.470296477902446E-3,1.0928370835602205E-2,1.2543090110689494E-2,1.4303501208400246E-2,1.619880179917023E-2,1.822096308548978E-2,2.0366925257149695E-2,2.2639885880045188E-2,2.504943300770401E-2,2.7610559561858587E-2,3.0341823077477733E-2,3.3263025531188595E-2,1.2285696620856583E-3,1.2783693589993585E-4,-5.515282359323268E-6,-1.509264920965293E-5,5.056357482887987E-5,1.7973987241455547E-4,3.6854133451822563E-4,6.137914272593722E-4,1.2444605648737654E-3,1.831052876025133E-3,2.3388084864494974E-3,2.7618457749317184E-3,3.1310509598100264E-3,3.4966163174563894E-3,3.908929082073651E-3,4.409231757243682E-3,5.028159171456157E-3,5.787235234153256E-3,6.700490419040229E-3,7.775445723805126E-3,9.013693953263124E-3,1.0411571211524136E-2,1.1961330529920171E-2,1.3652985391411212E-2,1.5476684666084312E-2,1.7425215573989173E-2,1.94961079700936E-2,2.1692879413316192E-2,2.4025179515785762E-2,2.6507863335653824E-2,2.9159241700873362E-2,3.199886376736126E-2,1.151145255180606E-3,1.1919175302170455E-4,-5.886881710528012E-6,-1.4772257773679974E-5,4.7038816619582685E-5,1.6859522549855397E-4,3.462972134441339E-4,5.772381221843568E-4,1.1718258857280955E-3,1.7255835442336466E-3,2.2058067355187924E-3,2.6069556834378005E-3,2.9581677462317234E-3,3.3068632824516187E-3,3.700748532874336E-3,4.17899638192544E-3,4.77084326291357E-3,5.496977642861899E-3,6.371044542674513E-3,7.400553832162206E-3,8.587410525152054E-3,9.928534687733989E-3,1.1416963498364394E-2,1.3043597138595566E-2,1.4799458793904168E-2,1.6678085434978833E-2,1.8677546270222407E-2,2.0801646507132846E-2,2.306008145882648E-2,2.5467564663022895E-2,2.8042162903041425E-2,3.08031753220386E-2,1.0802222839065997E-3,1.1131211120457104E-4,-6.179752497984128E-6,-1.4438602000211816E-5,4.382868243882969E-5,1.5836797836718856E-4,3.2584700290367577E-4,5.436023999464998E-4,1.10490511202929E-3,1.6283287706820217E-3,2.083062535182624E-3,2.4638832378664683E-3,2.79831566219582E-3,3.131219358139107E-3,3.507818203325749E-3,3.965362376683574E-3,4.531782114815915E-3,5.226977818975895E-3,6.064221668202771E-3,7.050997280603323E-3,8.189483975715957E-3,9.477129789627881E-3,1.0907687699019682E-2,1.2472870980965067E-2,1.4164506085846672E-2,1.5976818403367756E-2,1.7908369946383937E-2,1.996322376858205E-2,2.215110651018072E-2,2.4486587264868007E-2,2.6987491781539023E-2,2.967287230035409E-2,1.0152247923249408E-3,1.0412603958442357E-4,-6.405871381179307E-6,-1.4097102334718679E-5,4.0903303311564346E-5,1.4897874097260366E-4,3.0703945497501475E-4,5.126415447621037E-4,1.0432318711493865E-3,1.5386266437103025E-3,1.9697597132264807E-3,2.3317010759500716E-3,2.650488129177908E-3,2.9686140719427335E-3,3.329003912938929E-3,3.7671214336192985E-3,4.3096768618103645E-3,4.9758275464502864E-3,5.778485784445761E-3,6.725096204205914E-3,7.818078462054548E-3,9.05535762093803E-3,1.0431339802782928E-2,1.1938483603526293E-2,1.356935312826968E-2,1.531880547731046E-2,1.7185852461915944E-2,1.9174787589973874E-2,2.129535587921493E-2,2.3561979779634257E-2,2.5992247382456677E-2,2.860496746595992E-2,9.556313291821137E-4,9.756879165548494E-5,-6.575585943453176E-6,-1.3752251269403608E-5,3.8235820219283635E-5,1.4035542493936418E-4,2.897368411852841E-4,4.841342150300403E-4,9.863800188501897E-4,1.455871549086211E-3,1.865150560548147E-3,2.209558443582823E-3,2.513760269663381E-3,2.8180620925332607E-3,3.163259638233137E-3,3.583156808545154E-3,4.10332441428262E-3,4.742219510315312E-3,5.5124077121373955E-3,6.421284049040725E-3,7.471478121120862E-3,8.661345704608022E-3,9.985888668300925E-3,1.1438248551429775E-2,1.301166656845507E-2,1.4701579143990074E-2,1.650740820916382E-2,1.843365261162667E-2,2.0490064156582097E-2,2.269091715726001E-2,2.5053565799463603E-2,2.7596579190498E-2,9.009697489379409E-4,9.158210813103293E-5,-6.697827759363687E-6,-1.3407750129891714E-5,3.580207579343502E-5,1.3243257189866084E-4,2.738137552743034E-4,4.578785889593352E-4,9.339602484800939E-4,1.379509516616476E-3,1.7685502802881736E-3,2.0966751161489994E-3,2.387282586353416E-3,2.678656837466504E-3,3.009621122859108E-3,3.41243694787394E-3,3.91161109030522E-3,4.524940920412044E-3,5.264658720390964E-3,6.138101205956154E-3,7.148080773920512E-3,8.293341840324103E-3,9.569429463938274E-3,1.0970110751637818E-2,1.2489248189692052E-2,1.4122809173812626E-2,1.587058919417297E-2,1.773726946878452E-2,1.9732598291419857E-2,2.1870701028362936E-2,2.4168702088640755E-2,2.664493505845968E-2,8.508125080034032E-4,8.611355558856675E-5,-6.780298489107011E-6,-1.306662728422726E-5,3.3580337719681695E-5,1.2515074273970736E-4,2.5915601908075626E-4,4.3369066532755306E-4,8.856169723000344E-4,1.3090339296985146E-3,1.6793318576785454E-3,1.992335765685896E-3,2.270275086809559E-3,2.5495645094323776E-3,2.8671998902429744E-3,3.25400948673559E-3,3.733506583732703E-3,4.32286743206316E-3,5.034004395451471E-3,5.874188844866715E-3,6.8463917696058385E-3,7.949708031097642E-3,9.180177776773674E-3,1.053214092802768E-2,1.2000029774805653E-2,1.358029808732777E-2,1.5273081268697425E-2,1.70832219520271E-2,1.9020455841210406E-2,2.1098759199716457E-2,2.333503115921804E-2,2.5747374295159605E-2,8.047724113856782E-4,8.111593333144278E-5,-6.829632294189166E-6,-1.2731340163607083E-5,3.155105068826421E-5,1.1845596266497318E-4,2.456596836207175E-4,4.114027080709008E-4,8.410254566934999E-4,1.2439815749085781E-3,1.5969213257126579E-3,1.895884749520778E-3,2.1620218316939204E-3,2.430018543171085E-3,2.7351776456613613E-3,3.1069956108472135E-3,3.568058267304106E-3,4.13495736964997E-3,4.81929877566792E-3,5.6282829723477935E-3,6.565018002051932E-3,7.628914522128219E-3,8.816463763230729E-3,1.0122529976470833E-2,1.154206783694207E-2,1.307197638604556E-2,1.4712700012892965E-2,1.6469223696344074E-2,1.8351262620667677E-2,2.0372644412770476E-2,2.255004778636212E-2,2.490134917218935E-2,7.624987685854264E-4,7.654674161012862E-5,-6.851537486794242E-6,-1.2403863195674847E-5,2.9696614021518467E-5,1.1229921729694287E-4,2.3323011788527754E-4,3.9086182396113836E-4,7.998891936671331E-4,1.183929009307894E-3,1.5207934020995178E-3,1.8067212960184954E-3,2.0618658842939852E-3,2.319314444094528E-3,2.6128010530196335E-3,2.9705847723213315E-3,3.4143858264956894E-3,3.9602462550872245E-3,4.619478761695812E-3,5.399208729401174E-3,6.302662124494705E-3,7.329533987076532E-3,8.476726386768068E-3,9.73958335620902E-3,1.1113538285242421E-2,1.25958976263002E-2,1.4187386359360094E-2,1.5893114500840758E-2,1.7722769862507867E-2,1.9690032488371832E-2,2.181136587871047E-2,2.4104425531651635E-2,7.236739210207129E-4,7.236770500008017E-5,-6.850919983477008E-6,-1.2085763494359584E-5,2.8001182381877902E-5,1.0663599543249241E-4,2.2178117834276945E-4,3.7192866320319255E-4,7.619374917883602E-4,1.1284892238931038E-3,1.4504674735523345E-3,1.7242950633662411E-3,1.9692046389046536E-3,2.216804999046246E-3,2.4993768704368313E-3,2.844029747798769E-3,3.271676217358332E-3,3.797841639891691E-3,4.433558806779298E-3,5.185874941161037E-3,6.058116981726247E-3,7.050235889768565E-3,8.159507779914114E-3,9.381715544707998E-3,1.0712731082960896E-2,1.2150233404395536E-2,1.3695202037565845E-2,1.5352856368831106E-2,1.713285099035138E-2,1.9048719968021023E-2,2.1116717120515292E-2,2.3354282557845402E-2,6.880101064623658E-4,6.854434533241255E-5,-6.831990829395535E-6,-1.1778265922579426E-5,2.6450487213702663E-5,1.0142587437427743E-4,2.1123445258617617E-4,3.544762333770541E-4,7.269232705090873E-4,1.0773085824804566E-3,1.3855039042256735E-3,1.6481020478453091E-3,1.8834855058120728E-3,2.121895839369715E-3,2.3942674279744712E-3,2.7266420259529915E-3,3.1391789395947317E-3,3.646918236847406E-3,4.260625888483461E-3,4.987268925973818E-3,5.83026027409525E-3,6.789781043152674E-3,7.863447760769776E-3,9.047444595052993E-3,1.0338044946555592E-2,1.1733268311401202E-2,1.3234324907072714E-2,1.4846529346863492E-2,1.6579498092320302E-2,1.844662135000585E-2,2.0463949096128177E-2,2.26487119129876E-2,6.552466289592313E-4,6.504559912168961E-5,-6.79835978836747E-6,-1.1482308942435739E-5,2.5031676800727032E-5,9.663214408597158E-5,2.0151857101190706E-4,3.383888177392784E-4,6.946210426667236E-4,1.0300640162608148E-3,1.3255006460120998E-3,1.5776808187442175E-3,1.804201931027085E-3,2.034041336474555E-3,2.2968864304142717E-3,2.617787510469825E-3,3.016201614611756E-3,3.5067133451075917E-3,4.099834760369705E-3,4.802451567630998E-3,5.618049463068593E-3,6.547016381962195E-3,7.587278527828449E-3,8.735386827780895E-3,9.987982126240788E-3,1.1343394907110942E-2,1.2803044238404705E-2,1.4372327230986932E-2,1.6060818173138338E-2,1.788176600760765E-2,1.985102299316639E-2,2.1985616342086126E-2,6.251473055136203E-4,6.184347493516102E-5,-6.753116753410096E-6,-1.1198592489204458E-5,2.373317302981704E-5,9.22214667182958E-5,1.925685808488218E-4,3.235609894845486E-4,6.648250708170973E-4,9.864604552658014E-4,1.2700901294016517E-3,1.512609057911176E-3,1.7308897295013352E-3,1.952740810337482E-3,2.2066950678383403E-3,2.5168825239960165E-3,2.902105857157641E-3,3.376522560868949E-3,3.950403479763922E-3,4.630552651484742E-3,5.4205169242994445E-3,6.3208699609187975E-3,7.329819551514036E-3,8.444251682748578E-3,9.661143301366243E-3,1.097910875476302E-2,1.239975599173915E-2,1.3928553199269793E-2,1.5575029252687904E-2,1.7352294866278362E-2,1.927601097009067E-2,2.1363007841282526E-2,5.97498163344368E-4,5.8912746603060254E-5,-6.698902518952322E-6,-1.0927618948488398E-5,2.254454314189974E-5,8.816356833566778E-5,1.8432537727288206E-4,3.098967141404953E-4,6.373476839231044E-4,9.462284790217329E-4,1.2189364146645313E-3,1.4525003828880243E-3,1.6631237112858634E-3,1.8775350318065375E-3,2.1231984168415164E-3,2.4233900982211253E-3,2.7963034283648882E-3,3.255695764450533E-3,3.8116092058857846E-3,4.470766462661217E-3,5.236765350945589E-3,6.110346186373433E-3,7.089972676128735E-3,8.172836751147347E-3,9.35622261771882E-3,1.063900355109568E-2,1.202295813587467E-2,1.3513615421197537E-2,1.5120456370019807E-2,1.6856456907243876E-2,1.8737093264093937E-2,2.0779005473889348E-2,5.721053639556025E-4,5.623067858322004E-5,-6.637970267102616E-6,-1.0669728177182847E-5,2.1456384923680233E-5,8.443095993832397E-5,1.767351867413673E-4,2.9730853282425833E-4,6.12017741786051E-4,9.091221697163607E-4,1.1717325842141967E-3,1.397001433582743E-3,1.6005145809227749E-3,1.80800300015134E-3,2.0459421154683556E-3,2.3368165351598654E-3,2.6982526575157523E-3,3.143633373647016E-3,3.682784261135054E-3,4.322347642546186E-3,5.0659634073158665E-3,5.914521285950917E-3,6.866717441869409E-3,7.920023003014308E-3,9.072002888354197E-3,1.0321766380107164E-2,1.1671246043033389E-2,1.3126022687038984E-2,1.4695527543693254E-2,1.6392605556363626E-2,1.823255510615528E-2,2.023183290897191E-2,5.487933324232083E-4,5.377678016863816E-5,-6.5722389533851625E-6,-1.0425127387532048E-5,2.0460223950918794E-5,8.099868512262552E-5,1.697490980592819E-4,2.8571681962378495E-4,5.886792354540229E-4,8.749171522500925E-4,1.1281983581219416E-3,1.345789203496338E-3,1.5427060912672937E-3,1.7437589779859411E-3,1.974509295378486E-3,2.2567082247969463E-3,2.607455119583008E-3,3.039782852557112E-3,3.5633124472060876E-3,4.184607298086224E-3,4.907341630739067E-3,5.732539017974568E-3,6.659106633141525E-3,7.684770221495938E-3,8.807350974793135E-3,1.0026173113440636E-2,1.1343307988953359E-2,1.276438009354826E-2,1.4298769732020242E-2,1.5959195009250016E-2,1.7760783501831537E-2,1.971981574866797E-2,5.274030723281258E-4,5.1532585566651754E-5,-6.503339629993077E-6,-1.019391660661995E-5,1.9548421635929946E-5,7.784409195289E-5,1.633226370491771E-4,2.7504910687763275E-4,5.671900126657163E-4,8.434088065745332E-4,1.0880779158694187E-3,1.2985685976022456E-3,1.4893724338936596E-3,1.6844497664564961E-3,1.9085177552700568E-3,2.1826487045057854E-3,2.52345255553305E-3,2.9436354646664637E-3,3.452625606879819E-3,4.056909357178755E-3,4.760188577779759E-3,5.563606620139084E-3,6.466262056510728E-3,7.466112651622582E-3,8.561213361294224E-3,9.751083975563936E-3,1.1037920782350573E-2,1.2427384816388934E-2,1.392880483024427E-2,1.55547765365824E-2,1.7320263928820388E-2,1.924137870249497E-2,5.077906486166856E-4,4.948145718584619E-5,-6.432655614650836E-6,-9.976110330103434E-6,1.8714092960877522E-5,7.494662683225969E-5,1.5741538103318148E-4,2.652394726130888E-4,5.474206181834911E-4,8.144106387279167E-4,1.051137908528168E-3,1.2550702000637425E-3,1.4402158492238205E-3,1.629752204407006E-3,1.8476173602065427E-3,2.114255946026253E-3,2.4458240224768868E-3,2.854723258751204E-3,3.3502004217771013E-3,3.93866716246298E-3,4.623847209525294E-3,5.40699099501378E-3,6.287370549225497E-3,7.263154868390394E-3,8.332611931377522E-3,9.495439287788976E-3,1.0753945543124935E-2,1.2113821994390981E-2,1.3584345735852562E-2,1.5177994807201119E-2,1.6909576995499234E-2,1.8795042659633814E-2,4.898258223638283E-4,4.760840974484306E-5,-6.361357298837637E-6,-9.77165590714064E-6,1.7951032894481574E-5,7.22876483585289E-5,1.5199060965279733E-4,2.5622798486198497E-4,5.292532396320344E-4,7.877527979518429E-4,1.0171656466339257E-3,1.2150482360544282E-3,1.3949644405153133E-3,1.5793708760955137E-3,1.7914876521718578E-3,2.051179856256485E-3,2.3741832609859258E-3,2.772616276128299E-3,3.255555436009968E-3,3.829340295128479E-3,4.497711509583667E-3,5.26201512844442E-3,6.121680217259641E-3,7.075067866464288E-3,8.12063995276593E-3,9.258255401628314E-3,1.0490323644587596E-2,1.1822560746111141E-2,1.326419250805119E-2,1.4827584260889043E-2,1.6527395098488506E-2,1.8379421703586276E-2,4.733908229659891E-4,4.5899953067935785E-5,-6.29043228842507E-6,-9.580449121857083E-6,1.725365059476735E-5,6.985025933407774E-5,1.4701498884839507E-4,2.479601980068498E-4,5.125807501861307E-4,7.632807282110643E-4,9.859674500711695E-4,1.1782787130067483E-3,1.3533701768407252E-3,1.533036012911083E-3,1.7398356579037592E-3,1.993099978659012E-3,2.3081762672273374E-3,2.6969199678821974E-3,3.1682482955031465E-3,3.7284316198917104E-3,4.381223327622565E-3,5.128054735730552E-3,5.968496900215548E-3,6.901085371755054E-3,7.924458274372376E-3,9.038620828950678E-3,1.024607283144479E-2,1.1552550335113878E-2,1.2967228642877566E-2,1.4502365557698505E-2,1.617247911176986E-2,1.7993220107638114E-2,4.583792447071534E-4,4.43439516587622E-5,-6.220711481388074E-6,-9.402347374231386E-6,1.6616910595090198E-5,6.761915526802469E-5,1.42458285096637E-4,2.4038669671679825E-4,4.97305840140961E-4,7.40853943334704E-4,9.573671472929573E-4,1.1445577276461651E-3,1.315207071174297E-3,1.4905015754271046E-3,1.692393880809807E-3,1.939723382679594E-3,2.247479057994888E-3,2.6272728109158782E-3,3.0878731927466733E-3,3.635484542014596E-3,4.273869440705835E-3,5.004535129546135E-3,5.8271808591479225E-3,6.740500373437656E-3,7.743291736843341E-3,8.835692573826107E-3,1.0020283522231594E-2,1.130281649687236E-2,1.2692417481425057E-2,1.4201242126213973E-2,1.5843675134957342E-2,1.7635229344194932E-2,4.446950559342734E-4,4.292949934724476E-5,-6.1528916095592335E-6,-9.237180808812372E-6,1.6036280255877625E-5,6.558048786432494E-5,1.3829310726091903E-4,2.3346268341336345E-4,4.83340230050441E-4,7.203449158502448E-4,9.312047121691174E-4,1.1136999261667122E-3,1.2802695206635037E-3,1.4515435030069436E-3,1.6489184645395146E-3,1.8907827292147642E-3,2.1917956171973118E-3,2.563344111987376E-3,3.0140585068543025E-3,3.550080467126498E-3,4.175178824310139E-3,4.890928302902928E-3,5.697143682370066E-3,6.592661873621111E-3,7.576425796421425E-3,8.648692668787893E-3,9.81211530229789E-3,1.1072457937152577E-2,1.243879876517018E-2,1.3923196829204745E-2,1.5539911323946427E-2,1.7304325136245427E-2,4.322517102567703E-4,4.1646807488646655E-5,-6.0875547032093125E-6,-9.084761692232604E-6,1.550768284129464E-5,6.372174213239225E-5,1.3449467364863045E-4,2.2714760556186617E-4,4.706039587333928E-4,7.016380703902113E-4,9.073350276790402E-4,1.0855371058636942E-3,1.2483707970978597E-3,1.4159581190454434E-3,1.6091875165601109E-3,1.846034500825965E-3,2.140856012898465E-3,2.5048319892785414E-3,2.9464646290193845E-3,3.471836454632365E-3,4.084720124700832E-3,4.7867502199957935E-3,5.5778454035558325E-3,6.456971850807951E-3,7.423203360469164E-3,8.476904916447028E-3,9.620793611255937E-3,1.0860643009142886E-2,1.220548534937278E-2,1.3667288761674862E-2,1.5260194823290753E-2,1.6999464574921682E-2],[5.012654115505024E-2,5.4243971328787284E-2,5.859763754274426E-2,6.318561190366777E-2,6.7996278633665E-2,7.300854463084992E-2,7.819283020154098E-2,8.351270317178906E-2,8.892696421551709E-2,9.439194752960282E-2,9.986378121424384E-2,1.0530036533119111E-1,1.1066287454375838E-1,1.1591666926246567E-1,1.2103158982357941E-1,1.259816950487955E-1,1.3074457436920628E-1,1.353004022096563E-1,1.3963091237289044E-1,1.437184527863306E-1,1.4754524503620026E-1,1.5109292763518356E-1,1.5434241508291605E-1,1.5727406261306398E-1,1.5986809293710358E-1,1.6210521815098378E-1,1.6396737759327587E-1,1.654385100816593E-1,1.6650528512740514E-1,1.671577304687153E-1,1.6738971031975444E-1,1.6719922775682777E-1,4.809212086776749E-2,5.210790702752216E-2,5.636099969093568E-2,6.085028364061799E-2,6.556530027257519E-2,7.048640870501352E-2,7.558569991332977E-2,8.082853685482312E-2,8.61755389159455E-2,9.15847852290506E-2,9.701399049562175E-2,1.0242241831700574E-1,1.0777234284552112E-1,1.1302994310791406E-1,1.1816560174254345E-1,1.2315366432470462E-1,1.2797178206374327E-1,1.326000001530753E-1,1.370197640844846E-1,1.4121300048597762E-1,1.4516139496191358E-1,1.4884594567705625E-1,1.5224682592395122E-1,1.5534354765450767E-1,1.58115384784885E-1,1.6054199191185184E-1,1.6260414133505405E-1,1.6428449833082517E-1,1.6556836010627224E-1,1.6644429591677723E-1,1.669046422865707E-1,1.669458258425627E-1,4.6155022934670206E-2,5.007042346143187E-2,5.422371535665796E-2,5.861455397039492E-2,6.323358505128271E-2,6.806256058779188E-2,7.307518137541948E-2,7.823854837899615E-2,8.351505113728709E-2,8.886447770475468E-2,9.424610872945666E-2,9.962056755827223E-2,1.0495124113384079E-1,1.102051566606146E-1,1.1535328329681775E-1,1.2037031021423104E-1,1.2523401772878534E-1,1.2992439761648875E-1,1.3442268964983195E-1,1.3871048716251255E-1,1.4276903214290557E-1,1.4657877830334E-1,1.5011925642716584E-1,1.5336923594468704E-1,1.563071439513659E-1,1.5891167971955625E-1,1.611625496862547E-1,1.630412444027375E-1,1.6453178375717217E-1,1.6562136816997905E-1,1.6630088932771805E-1,1.6656527213507563E-1,4.431200843704725E-2,4.812857879204078E-2,5.218318782182896E-2,5.647621934335013E-2,6.09993704316017E-2,6.573572590721458E-2,7.066053411823704E-2,7.57425745757424E-2,8.094595504564425E-2,8.623213207894719E-2,9.15619262196852E-2,9.689731051758155E-2,1.0220279108072759E-1,1.0744626544286044E-1,1.1259932579550831E-1,1.1763705391845439E-1,1.2253741874031882E-1,1.2728042672416107E-1,1.3184718699401068E-1,1.3621904032006676E-1,1.4037687046310424E-1,1.443006759501289E-1,1.4796943753534453E-1,1.5136127715408335E-1,1.544538718922594E-1,1.572250633730395E-1,1.596535896073441E-1,1.617198623482461E-1,1.634067171884559E-1,1.6470007438499765E-1,1.6558946368126665E-1,1.6606838405329863E-1,4.25597893840817E-2,4.6279342018541454E-2,5.0236688654248254E-2,5.4432899824488054E-2,5.8860671108440156E-2,6.350435991715755E-2,6.834069902671053E-2,7.334008532761106E-2,7.84682902115203E-2,8.368839461402727E-2,8.896272826857189E-2,9.425459836667525E-2,9.952963032936145E-2,1.0475660740963767E-1,1.0990777422565633E-1,1.1495864685646545E-1,1.1988743496048239E-1,1.2467422043652249E-1,1.293000495848637E-1,1.3374608426544315E-1,1.3799292854192216E-1,1.420202084374521E-1,1.4580644090459674E-1,1.493291895636116E-1,1.5256547294571632E-1,1.5549236792768015E-1,1.580877374389444E-1,1.6033100704263167E-1,1.622039185961868E-1,1.6369119932124135E-1,1.6478109933055773E-1,1.6546576786080747E-1,4.089505522773724E-2,4.451962272716513E-2,4.838139062912408E-2,5.2482075074323994E-2,5.6815317880879325E-2,6.136668902839489E-2,6.611434223672956E-2,7.10302294704214E-2,7.608172909462523E-2,8.123349929820263E-2,8.644934432971754E-2,9.169388513089717E-2,9.693386102232564E-2,1.0213895023280058E-1,1.0728207265614322E-1,1.1233921355593979E-1,1.17288868495847E-1,1.2211124858136706E-1,1.2678739817574833E-1,1.3129836704280184E-1,1.3562455139061483E-1,1.3974528093319807E-1,1.4363868882398984E-1,1.472818636557534E-1,1.506512513829564E-1,1.5372325206923543E-1,1.564749425413111E-1,1.5888485111259817E-1,1.609337135804343E-1,1.6260514922673286E-1,1.6388620971570098E-1,1.647677705306621E-1,3.931449612296589E-2,4.28462974854742E-2,4.66143972304416E-2,5.0621116883895506E-2,5.4860993095216186E-2,5.932074897685185E-2,6.397989578500053E-2,6.881187761876864E-2,7.378562167761374E-2,7.886731386200486E-2,8.402219492968949E-2,8.921617499395396E-2,9.441709693259356E-2,9.959553767680346E-2,1.0472510926282173E-1,1.0978229472907086E-1,1.1474591423243374E-1,1.1959635527265396E-1,1.243147145579825E-1,1.2888199000286107E-1,1.3327843532196307E-1,1.3748315377440468E-1,1.4147396857318875E-1,1.4522757069246514E-1,1.4871991395446346E-1,1.5192680444457815E-1,1.548246172972724E-1,1.5739106857264207E-1,1.5960597245080518E-1,1.614519229227064E-1,1.629148527797164E-1,1.639844390051611E-1,3.781482317217515E-2,4.125623310052275E-2,4.4932768926101936E-2,4.884731842778166E-2,5.299526278876072E-2,5.736441971795728E-2,6.19355950567113E-2,6.668366191061194E-2,7.15790371921285E-2,7.658938311365109E-2,8.168133618857339E-2,8.682206753419261E-2,9.198050890890427E-2,9.712813471855829E-2,1.0223926056988956E-1,1.0729089007381339E-1,1.1226220063587461E-1,1.1713379715817208E-1,1.2188687672242379E-1,1.2650243937029904E-1,1.3096065544804042E-1,1.352404654592243E-1,1.3931945051789116E-1,1.4317397557450542E-1,1.4677957722989685E-1,1.501115452596365E-1,1.5314563281011156E-1,1.5585882453199887E-1,1.5823009392050164E-1,1.6024108953228736E-1,1.618767028481121E-1,1.6312548640951052E-1,3.639278589205563E-2,3.97463069638022E-2,4.333354641989129E-2,4.715792041360892E-2,5.121560568353436E-2,5.549545716222714E-2,5.997951310759155E-2,6.464401270473746E-2,6.946080292428967E-2,7.439896953040098E-2,7.942650182390155E-2,8.451180072219122E-2,8.962486840953018E-2,9.473807112935818E-2,9.982643457003915E-2,1.0486750040915299E-1,1.0984083037409603E-1,1.1472728200551864E-1,1.1950819489594353E-1,1.2416461923648174E-1,1.2867669516034486E-1,1.3302325817740585E-1,1.371817092914868E-1,1.4112815331864897E-1,1.4483777906405948E-1,1.4828543248085865E-1,1.514463196448549E-1,1.5429677034094236E-1,1.568149945860056E-1,1.589817722863985E-1,1.6078102881848413E-1,1.622002647462091E-1,3.504518713689123E-2,3.831342470610913E-2,4.181377108817672E-2,4.55501343163045E-2,4.951943919403165E-2,5.3711521887653935E-2,5.810959196296297E-2,6.269119229646969E-2,6.742954012384193E-2,7.229509108543117E-2,7.725714256978257E-2,8.228529156141205E-2,8.735058895441597E-2,9.242628329619508E-2,9.748811244797115E-2,1.0251416881703025E-1,1.0748442038482689E-1,1.1238000720084391E-1,1.1718244798268068E-1,1.2187288546692715E-1,1.264314770460199E-1,1.308370053028383E-1,1.3506674746236783E-1,1.390966085347099E-1,1.4290149356034662E-1,1.464558720084218E-1,1.4973447298553402E-1,1.5271304356099116E-1,1.5536910359652073E-1,1.5768263783804123E-1,1.5963667812541438E-1,1.6121774357632715E-1,3.3768895705938044E-2,3.695453538261599E-2,4.037050281041765E-2,4.402116289096672E-2,4.7904142623532195E-2,5.2010204979775924E-2,5.632367101679696E-2,6.0823325742664226E-2,6.548369707206221E-2,7.027655632576814E-2,7.517246298398657E-2,8.014217429917482E-2,8.515776537538672E-2,9.019335411316953E-2,9.522538868831219E-2,1.0023252052237921E-1,1.0519514107068542E-1,1.1009469779606709E-1,1.1491292000119731E-1,1.1963108007320943E-1,1.242293947523867E-1,1.2868664032745553E-1,1.3298002113848073E-1,1.37085297331977E-1,1.4097714894549698E-1,1.4462973122584052E-1,1.480173616107695E-1,1.5111527216606302E-1,1.5390036193201412E-1,1.5635189052262635E-1,1.5845206594405262E-1,1.6018649418336778E-1,3.256085685393638E-2,3.566664440304196E-2,3.9000835400751346E-2,4.256821816028872E-2,4.636707772973771E-2,5.038905116108115E-2,5.461951266929278E-2,5.9038428907349144E-2,6.362157938877729E-2,6.834199674693701E-2,7.317145565062545E-2,7.808183617466581E-2,8.304621078778147E-2,8.803955082120021E-2,9.303900939980143E-2,9.802380129631774E-2,1.0297475436029478E-1,1.0787364379738132E-1,1.1270243616638351E-1,1.1744256565661916E-1,1.2207434536863616E-1,1.2657658677066108E-1,1.3092646701293792E-1,1.3509965113348657E-1,1.3907064781411047E-1,1.4281335537029977E-1,1.4630174012402627E-1,1.4951058240940332E-1,1.5241622572969094E-1,1.5499727101578675E-1,1.5723516910194568E-1,1.5911467871373505E-1,3.141810091376726E-2,3.444682441445589E-2,3.770190984358949E-2,4.118853707156687E-2,4.490560684334263E-2,4.884557937825244E-2,5.299482535261224E-2,5.733443385496246E-2,6.184137767897588E-2,6.648989653474083E-2,7.125293281537726E-2,7.610345070440841E-2,8.101549124481093E-2,8.596486071604864E-2,9.092940873292071E-2,9.588891421587775E-2,1.008246504246882E-1,1.0571873644054974E-1,1.1055339831889041E-1,1.1531025958529662E-1,1.1996976194773094E-1,1.2451078865162993E-1,1.2891053040597383E-1,1.3314460192549948E-1,1.3718738924705184E-1,1.41012586209719E-1,1.4459386391195145E-1,1.4790560982286874E-1,1.509236731246579E-1,1.5362605885970484E-1,1.5599352418151957E-1,1.5801004379362513E-1,3.03377502291251E-2,3.329222433533867E-2,3.647092552986786E-2,3.987939501497233E-2,4.3517108723074224E-2,4.737730101927516E-2,5.144728410174611E-2,5.5709211729517844E-2,6.014119263509599E-2,6.47186197644548E-2,6.941555551437888E-2,7.42060085340539E-2,7.90649580684453E-2,8.396902468108053E-2,8.889674330812872E-2,9.382845465681208E-2,9.874588288418948E-2,1.0363150324663659E-1,1.0846781945465549E-1,1.1323666761743109E-1,1.1791864584280691E-1,1.2249274116280526E-1,1.2693619390848765E-1,1.3122460851780554E-1,1.3533229235372723E-1,1.3923278255533053E-1,1.4289950634319626E-1,1.4630651284976182E-1,1.4942921410019644E-1,1.5224507835319007E-1,1.5473422931393274E-1,1.568799181341998E-1,2.9317024583197848E-2,3.220007672950375E-2,3.5305149682746034E-2,3.863811738944854E-2,4.21989923282576E-2,4.598173593307999E-2,4.997454883156183E-2,5.416059326575196E-2,5.851905772261812E-2,6.302643516323359E-2,6.765786027745559E-2,7.238834590890872E-2,7.719377787816255E-2,8.205156853248605E-2,8.694092460672138E-2,9.184274343419573E-2,9.673920238201732E-2,1.016131416953927E-1,1.064473571526692E-1,1.1122391673013805E-1,1.1592359858030737E-1,1.2052552123113681E-1,1.2500700628029124E-1,1.2934368343737687E-1,1.3350982083345075E-1,1.3747884218147702E-1,1.4122397776012618E-1,1.447189886488889E-1,1.4793890287541647E-1,1.5086070732844217E-1,1.5346394918763046E-1,1.5573121365402107E-1,2.835324529704114E-2,3.1167703697659192E-2,3.420192515255566E-2,3.7462089395724034E-2,4.094870868553176E-2,4.465642642270755E-2,4.8574280482399174E-2,5.26863870828725E-2,5.697295958461528E-2,6.141153855318321E-2,6.597828350172769E-2,7.064917083476886E-2,7.540096036177861E-2,8.021183219126003E-2,8.506164930644679E-2,8.993185803890212E-2,9.480508843726143E-2,9.966455139255707E-2,1.044933457404424E-1,1.092737869567715E-1,1.1398685303650874E-1,1.1861181769879725E-1,1.2312611130158858E-1,1.275054201228617E-1,1.3172400819511448E-1,1.3575522476673074E-1,1.395721458560144E-1,1.4314829064490028E-1,1.4645835239213217E-1,1.4947888836767678E-1,1.521889228208116E-1,1.5457042966883763E-1,2.7443838158862564E-2,3.019252145310932E-2,3.315867675098059E-2,3.634876422788386E-2,3.9763761020362845E-2,4.339894937934487E-2,4.724415519557444E-2,5.1284395913408005E-2,5.5500856305899675E-2,5.9872073100794065E-2,6.437518360330828E-2,6.898708701579569E-2,7.368538385129617E-2,7.84489967184432E-2,8.325842756960271E-2,8.809566194690976E-2,9.294377952177493E-2,9.778636464200663E-2,1.026068270737219E-1,1.0738774207454752E-1,1.1211030372485692E-1,1.1675396089702633E-1,1.2129627631875105E-1,1.2571302013013114E-1,1.299784833166432E-1,1.340659755117192E-1,1.3794845707005005E-1,1.4159924743761756E-1,1.4499275049778457E-1,1.4810514204460118E-1,1.5091497367523357E-1,1.5340365972299558E-1,2.6586335333007638E-2,2.927204373656675E-2,3.2172916284100184E-2,3.52956698260474E-2,3.864171331682573E-2,4.2206926719421424E-2,4.5981876677256E-2,4.995243091926814E-2,5.4100693679756603E-2,5.840614750375774E-2,6.284686106322841E-2,6.74006156678249E-2,7.204581878163274E-2,7.676210926836262E-2,8.153060931284335E-2,8.633383200305009E-2,9.11553013331906E-2,9.597897536413633E-2,1.0078857983999862E-1,1.055669590195699E-1,1.102955360385954E-1,1.149539514252691E-1,1.1951992026500745E-1,1.2396932009913204E-1,1.2827649606582567E-1,1.3241474912869072E-1,1.3635695867116338E-1,1.4007628272023515E-1,1.435468774564442E-1,1.4674458180844985E-1,1.4964752171853943E-1,1.5223660066308947E-1,2.5778376385238066E-2,2.8403884213510217E-2,3.1242246433299536E-2,3.430041434322161E-2,3.758019746107482E-2,4.107803428057346E-2,4.478518690473607E-2,4.868832424488471E-2,5.277041962043481E-2,5.701185224896564E-2,6.139157648930544E-2,6.588821531401244E-2,7.048094912165319E-2,7.515010602925483E-2,7.987740850565572E-2,8.464588390156884E-2,8.943949325996953E-2,9.424256632833634E-2,9.903914732439444E-2,1.0381235593773111E-1,1.085438543265585E-1,1.1321348798284983E-1,1.1779914097302069E-1,1.2227681826958157E-1,1.2662094274184177E-1,1.3080483393557465E-1,1.3480132123891025E-1,1.3858343589254926E-1,1.4212512445472614E-1,1.454019301611986E-1,1.4839159707282007E-1,1.5107456358224183E-1,2.5017708549046246E-2,2.75857579861312E-2,3.0364363622328663E-2,3.336069046959673E-2,3.6576919115261314E-2,4.0010009325017255E-2,4.365187532348812E-2,4.748993995353467E-2,5.1507996862894416E-2,5.568727407615083E-2,6.0007566818832105E-2,6.444829967553159E-2,6.89893918755136E-2,7.361183323208674E-2,7.829792555878856E-2,8.303119580308832E-2,8.779603305441865E-2,9.257713469018086E-2,9.735886360183794E-2,1.0212461880761639E-1,1.0685630870981551E-1,1.115339941320664E-1,1.1613574162950863E-1,1.2063770036736324E-1,1.2501439113189408E-1,1.2923917582274347E-1,1.3328486128504638E-1,1.371243830902631E-1,1.407315128034239E-1,1.4408153581113795E-1,1.4715185491792027E-1,1.49922486291953E-1,2.4302186346378936E-2,2.6815482340812675E-2,2.9537059998174842E-2,3.247427874760472E-2,3.562966245961162E-2,3.900065679095815E-2,4.2579786676845366E-2,4.6355183487978416E-2,5.031141408816114E-2,5.4430508780492694E-2,5.8693059788035074E-2,6.307925377350132E-2,6.756971475829256E-2,7.214606631699362E-2,7.679116787519823E-2,8.14890301415369E-2,8.622445974629073E-2,9.0982515843237E-2,9.574787814125435E-2,1.0050422659576262E-1,1.0523372057320497E-1,1.0991664389989936E-1,1.1453125625202369E-1,1.1905386471481746E-1,1.2345910500973463E-1,1.2772040189373504E-1,1.3181056379276634E-1,1.3570245838465447E-1,1.3936971356837483E-1,1.42787391517794E-1,1.459325913484234E-1,1.4878494700717163E-1,2.3629770665304594E-2,2.6090976841381338E-2,2.8758224643002046E-2,3.1639050001145634E-2,3.473629393116072E-2,3.8047854424329335E-2,4.1566827602916155E-2,4.528200979066435E-2,4.91786956082904E-2,5.3239672484910835E-2,5.744628679359882E-2,6.1779448359771776E-2,6.622045215361895E-2,7.075152735284214E-2,7.53560686446441E-2,8.001855368570356E-2,8.472419484319842E-2,8.945840561153308E-2,9.420617882605013E-2,9.895147492547957E-2,1.0367670668888052E-1,1.0836238615059718E-1,1.1298697409486955E-1,1.1752694644650169E-1,1.2195706793247861E-1,1.2625084361171166E-1,1.3038110448166643E-1,1.3432067493818048E-1,1.3804306739521785E-1,1.4152315237379468E-1,1.447377599130074E-1,1.4766617895873668E-1,2.2998527386932616E-2,2.5410262868140104E-2,2.8025844124341837E-2,3.0852966992641805E-2,3.389476507837639E-2,3.7149556914606E-2,4.061097212568745E-2,4.426843021217187E-2,4.810790973966764E-2,5.211291150900052E-2,5.626549426946185E-2,6.05472527939732E-2,6.494011946277542E-2,6.942690080937776E-2,7.399150396925518E-2,7.861885592858883E-2,8.329456187494733E-2,8.800438082196406E-2,9.273361341075774E-2,9.746649825829944E-2,1.0218570194897701E-1,1.0687196768340665E-1,1.1150396291495933E-1,1.1605834073743747E-1,1.2051000621891035E-1,1.248325593113507E-1,1.2899887163522464E-1,1.3298174593084008E-1,1.3675460432211103E-1,1.402921542985073E-1,1.435709885935279E-1,1.46570085675108E-1,2.2406625644294565E-2,2.477146269299865E-2,2.7338002481059318E-2,3.011408541209391E-2,3.310311464178274E-2,3.6303799149804326E-2,3.971026615933681E-2,4.3312518329520634E-2,4.7097175987402005E-2,5.1048410956842434E-2,5.514895369883037E-2,5.9381046482600085E-2,6.372722595493052E-2,6.817084778347668E-2,7.269630841150027E-2,7.728896588395817E-2,8.193480434732271E-2,8.661991830654653E-2,9.132990944654137E-2,9.604929060212629E-2,1.0076098070161717E-1,1.054459550288147E-1,1.1008309104936825E-1,1.146492249734896E-1,1.1911941101660503E-1,1.234673559612148E-1,1.2766598735392862E-1,1.3168810509914614E-1,1.3550706340191077E-1,1.39097432545817E-1,1.4243559700853792E-1,1.455002567021545E-1,2.1852335786959193E-2,2.4172798171895337E-2,2.6692880733429184E-2,2.9420554293191216E-2,3.235946996176051E-2,3.550869869722015E-2,3.8862831136731744E-2,4.241241478862951E-2,4.6144671157098235E-2,5.004440214052744E-2,5.409497037718434E-2,5.827922899312995E-2,6.258028622691988E-2,6.698201878152932E-2,7.146928905832248E-2,7.602786737375977E-2,8.064410217711157E-2,8.530441239274893E-2,8.999469271864907E-2,9.469972477260327E-2,9.940267669893406E-2,1.0408475493306686E-1,1.0872504827457401E-1,1.1330057981345842E-1,1.177865593866415E-1,1.2215681008444833E-1,1.2638432812110068E-1,1.304419267543662E-1,1.3430291198075195E-1,1.3794174005419368E-1,1.4133461365179248E-1,1.4445998355535625E-1,2.1334027116873547E-2,2.3612589127177702E-2,2.6088755996982356E-2,2.8770615942815103E-2,3.166204780608159E-2,3.476245760805548E-2,3.8066866865070124E-2,4.1566331277717444E-2,4.524863450350424E-2,4.909916895029287E-2,5.3101891037157796E-2,5.724022895248479E-2,6.1497830378684636E-2,6.585906515913868E-2,7.030923819598903E-2,7.483451289260215E-2,7.942158668451069E-2,8.405719094636575E-2,8.872750424706866E-2,9.341757024430956E-2,9.81108016778145E-2,1.0278863353461935E-1,1.0743036543306199E-1,1.1201320910984583E-1,1.16512534353626E-1,1.2090228776599374E-1,1.251555445900347E-1,1.2924514516925334E-1,1.3314436450331474E-1,1.3682756549109104E-1,1.4027079300045475E-1,1.4345227572297828E-1,2.085016545329746E-2,2.3089251484689315E-2,2.5524000271648986E-2,2.8162605462023475E-2,3.100915470147393E-2,3.406336363593983E-2,3.732065370371479E-2,4.077255373092326E-2,4.4407372018555206E-2,4.8211053275908E-2,5.216811044075723E-2,5.6262511834746946E-2,6.0478413007221926E-2,6.480064931739885E-2,6.921494468971418E-2,7.37078361365422E-2,7.826635422177117E-2,8.287753003583473E-2,8.752781590784854E-2,9.220250963642572E-2,9.688526260387956E-2,1.0155773424779295E-1,1.0619943282631195E-1,1.1078775867025306E-1,1.1529824388530241E-1,1.1970496369249517E-1,1.2398108052029692E-1,1.2809947324284887E-1,1.320334007363296E-1,1.3575715086566761E-1,1.3924663235015852E-1,1.4247987656144748E-1,2.039931057771299E-2,2.2601295222989478E-2,2.499707897014181E-2,2.7594949928836567E-2,3.0399186845657296E-2,3.340979095150819E-2,3.66225541515709E-2,4.002944485399045E-2,4.3619259954307044E-2,4.737845957745148E-2,5.1292077038602744E-2,5.534458673809175E-2,5.9520621117964745E-2,6.380545375218928E-2,6.818520416056195E-2,7.264676328325385E-2,7.717747851822104E-2,8.176466728974693E-2,8.639504473701623E-2,9.105415388363237E-2,9.572587761704401E-2,1.0039209437839891E-1,1.0503251738435788E-1,1.0962473385414148E-1,1.141444387803337E-1,1.185658391867951E-1,1.2286219080811776E-1,1.2700642037115606E-1,1.309717833210734E-1,1.347325086038639E-1,1.3826438825472034E-1,1.4154527894520877E-1,1.99801136032211E-2,2.2147322185406854E-2,2.4506549242492768E-2,2.7066167305883782E-2,2.983062966887493E-2,3.280020042772863E-2,3.597101392392683E-2,3.9335446056582235E-2,4.288274766925876E-2,4.6599858697062395E-2,5.047229778984661E-2,5.448501224558282E-2,5.8623081048003255E-2,6.28721890493954E-2,6.72188280496808E-2,7.16502231094077E-2,7.615402182188447E-2,8.071781402077717E-2,8.532856598198914E-2,8.997205614749919E-2,9.46323907230643E-2,9.929166050374842E-2,1.039297786313119E-1,1.0852451601044366E-1,1.1305172945505812E-1,1.1748575921259054E-1,1.2179995857073508E-1,1.2596730946762488E-1,1.2996107458283715E-1,1.3375543799796086E-1,1.373260924671455E-1,1.4065074055273108E-1,1.959131430716036E-2,2.1726023799471875E-2,2.4051058147173673E-2,2.6574865129214267E-2,2.9302057106985423E-2,3.2233139563581606E-2,3.5364562591552726E-2,3.868907886874916E-2,4.219635987969781E-2,4.5873790996666906E-2,4.970734223029467E-2,5.368240145888307E-2,5.778446449066942E-2,6.1999600914879056E-2,6.631465165678921E-2,7.071715602900609E-2,7.519504491699214E-2,7.973616618958511E-2,8.432772496701343E-2,8.895572452666661E-2,9.360448527994303E-2,9.825630265539573E-2,1.0289128347366021E-1,1.0748737777037849E-1,1.1202060163035982E-1,1.1646542833647247E-1,1.2079531125755298E-1,1.2498329309158747E-1,1.2900265254061694E-1,1.3282754095902208E-1,1.3643356729563272E-1,1.3979829868807112E-1,1.9231738460461483E-2,2.1336178742672286E-2,2.3629340713280784E-2,2.6119739028320144E-2,2.881213064168181E-2,3.1707242107018946E-2,3.4801813848088746E-2,3.808894591228879E-2,4.155869839101505E-2,4.519886890020773E-2,4.8995845870082384E-2,5.2935426288209485E-2,5.7003493705831056E-2,6.118647632353197E-2,6.547154123612325E-2,6.984652213362606E-2,7.429961609488121E-2,7.881891428155717E-2,8.339184783968738E-2,8.8004633625886E-2,9.2641796331163E-2,9.728582734741019E-2,1.0191701984396535E-1,1.065134972170274E-1,1.110514309283206E-1,1.1550542564448384E-1,1.1984903577212627E-1,1.2405536865514852E-1,1.2809772607375952E-1,1.3195023701507252E-1,1.355884403036478E-1,1.3898978455347788E-1,1.8900295182555704E-2,2.0976650588390412E-2,2.3240217932822813E-2,2.569957112166421E-2,2.835959815736974E-2,3.122122743188431E-2,3.428146546534535E-2,3.7533731491266036E-2,4.096844337748269E-2,4.4573778912563214E-2,4.833651299614079E-2,5.224282107607313E-2,5.6278945994896384E-2,6.0431648866953624E-2,6.468840022894273E-2,6.903730831216767E-2,7.346681915333224E-2,7.796525216777007E-2,8.25202512651842E-2,8.711823504469096E-2,9.174392183960084E-2,9.637998949609698E-2,1.0100690923699106E-1,1.0560297095891205E-1,1.1014449639530718E-1,1.1460621861854715E-1,1.1896179259844764E-1,1.2318439268966498E-1,1.2724734921402833E-1,1.311247775106337E-1,1.3479215829679628E-1,1.3822683690302115E-1],[1.6658854342852036E-1,1.6556411938493357E-1,1.6413640988167938E-1,1.6231952974963476E-1,1.6013083518161686E-1,1.5759045197129054E-1,1.5472078314955598E-1,1.51546022621779E-1,1.4809169488025317E-1,1.4438423410993056E-1,1.404506097790301E-1,1.3631800061887245E-1,1.3201351501109224E-1,1.2756395326336648E-1,1.229956059532219E-1,1.1833408223577876E-1,1.1360416247768855E-1,1.0882967052238686E-1,1.0403336206316534E-1,9.923682679808013E-2,9.446040311622078E-2,8.97231049247188E-2,8.504256082591649E-2,8.043496618983752E-2,7.591504876401176E-2,7.149604836452629E-2,6.718971095246264E-2,6.300629707307104E-2,5.895460427151135E-2,5.5042002740732524E-2,5.1274483136034596E-2,4.765671522855563E-2,1.6656850475791193E-1,1.657775363085372E-1,1.6458179116152047E-1,1.6299384392494684E-1,1.610295739989199E-1,1.5870771123091154E-1,1.5604935805751644E-1,1.530775147023338E-1,1.4981662764382164E-1,1.462921749218615E-1,1.4253029567878706E-1,1.385574661496843E-1,1.3440022040347094E-1,1.300849115533129E-1,1.2563750780116503E-1,1.2108341734933828E-1,1.1644733664041422E-1,1.1175311730551227E-1,1.070236483619779E-1,1.0228075140109084E-1,9.75450875929594E-2,9.283607621221111E-2,8.817182500630596E-2,8.356907308084388E-2,7.90431470858446E-2,7.460793139610106E-2,7.027585273985308E-2,6.605787939798986E-2,6.196353472156699E-2,5.800092434177436E-2,5.417677610682849E-2,5.049649149739567E-2,1.664136377596193E-1,1.6584929403046222E-1,1.6487957260119743E-1,1.63515541351729E-1,1.6177162524494113E-1,1.5966516958244256E-1,1.5721597704230242E-1,1.5444584499479905E-1,1.5137812340968737E-1,1.480373071381093E-1,1.4444867023817634E-1,1.406379448447403E-1,1.366310431494772E-1,1.3245381843355175E-1,1.2813185969312668E-1,1.2369031402037467E-1,1.1915373129463903E-1,1.1454592663327666E-1,1.0988985720244805E-1,1.0520751118923914E-1,1.0051980783379318E-1,9.584650831293282E-2,9.120613790335683E-2,8.661592022231034E-2,8.209172446691856E-2,7.764802649091289E-2,7.329788432097811E-2,6.90529283791536E-2,6.492336629396507E-2,6.0918001795383286E-2,5.704426683165493E-2,5.330826574376705E-2,1.6613448720104335E-1,1.657895898551475E-1,1.6503953313242678E-1,1.6389391637064116E-1,1.623657378273996E-1,1.604709756068026E-1,1.582281398662711E-1,1.5565782268986667E-1,1.5278226600468606E-1,1.496249615038904E-1,1.462102904894001E-1,1.425632063967466E-1,1.3870895881456732E-1,1.346728551512308E-1,1.3048005465457857E-1,1.2615538906988888E-1,1.2172320457815236E-1,1.1720722052830587E-1,1.1263040161740516E-1,1.0801484137501571E-1,1.0338165591571706E-1,9.87508878324708E-2,9.414142075870767E-2,8.957090551444354E-2,8.505569888953217E-2,8.061081604415586E-2,7.624989727389893E-2,7.198518954863847E-2,6.782754284286747E-2,6.378642087501649E-2,5.9869925500235774E-2,5.6084833680440066E-2,1.6574145604513213E-1,1.6560855015775194E-1,1.6507145242076515E-1,1.641383357745742E-1,1.6282080416290315E-1,1.611334910983685E-1,1.590936272037951E-1,1.5672060297367882E-1,1.540355471620383E-1,1.510609349091126E-1,1.478202337363075E-1,1.4433759041118932E-1,1.4063755772372358E-1,1.367448575233146E-1,1.3268417487863854E-1,1.2847997776061246E-1,1.2415635697207278E-1,1.197368818965633E-1,1.1524446876840033E-1,1.1070125936928243E-1,1.0612850917417249E-1,1.0154648489378722E-1,9.697437203455223E-2,9.243019350233274E-2,8.793074042915473E-2,8.349151633965995E-2,7.91266955461812E-2,7.484909632229708E-2,7.06701690067417E-2,6.659999877838946E-2,6.26473224551719E-2,5.8819558331980736E-2,1.6524475186264603E-1,1.65316171797853E-1,1.649850477873538E-1,1.642581717896243E-1,1.6314578980435793E-1,1.6166121795330188E-1,1.5982042542339908E-1,1.5764161034633062E-1,1.5514478902000103E-1,1.5235141270413058E-1,1.492840203098411E-1,1.4596593020275597E-1,1.4242097037260498E-1,1.3867324350312407E-1,1.3474692195079785E-1,1.3066606714083767E-1,1.2645446817962072E-1,1.2213549530940017E-1,1.1773196495018583E-1,1.1326601427722041E-1,1.0875898440921167E-1,1.042313122225207E-1,9.970243149825662E-2,9.519068453292813E-2,9.071324551184556E-2,8.628605689342289E-2,8.192377983066973E-2,7.763975931758695E-2,7.344600434515537E-2,6.93531829307294E-2,6.537063148340722E-2,6.1506377613996625E-2,1.6465434062308074E-1,1.6492227081930327E-1,1.6478991824950598E-1,1.642627419352591E-1,1.6334966963912675E-1,1.620627312557511E-1,1.6041665713565192E-1,1.5842846722062298E-1,1.5611707136823055E-1,1.5350289519042196E-1,1.506075398924085E-1,1.4745347952871504E-1,1.440637951249219E-1,1.404619423707986E-1,1.3667154803068712E-1,1.3271622968058816E-1,1.2861943364110084E-1,1.244042867802044E-1,1.2009345896822468E-1,1.1570903417079097E-1,1.1127238930112716E-1,1.068040809080055E-1,1.0232374048546969E-1,9.784997963248977E-2,9.340030647535301E-2,8.899105472669176E-2,8.463732654030529E-2,8.035294998392489E-2,7.61504515453971E-2,7.204104365848044E-2,6.803462682104017E-2,6.413980550962439E-2,1.6397990748941288E-1,1.6443643813269768E-1,1.6449549545203757E-1,1.6416125561426387E-1,1.6344137058936087E-1,1.6234661857539093E-1,1.6089051760248385E-1,1.5908892797810403E-1,1.5695966389851537E-1,1.5452212861979725E-1,1.517969818182966E-1,1.488058427356292E-1,1.455710287368333E-1,1.421153261474451E-1,1.3846178864372127E-1,1.3463355789973355E-1,1.306537014248811E-1,1.2654506330891488E-1,1.2233012468913576E-1,1.1803087195738234E-1,1.1366867186820455E-1,1.0926415367904184E-1,1.0483709918078674E-1,1.0040634193748155E-1,9.598967725501067E-2,9.160378437254814E-2,8.726416216378101E-2,8.298507930067692E-2,7.877953942340442E-2,7.46592614236803E-2,7.06346745244641E-2,6.671492745636678E-2,1.6323082419989082E-1,1.6386800182551742E-1,1.6411100120094768E-1,1.639627672143708E-1,1.6342972066963943E-1,1.6252142540660502E-1,1.612502170144569E-1,1.5963081856525688E-1,1.5767996361828487E-1,1.5541604093450076E-1,1.5285876965397693E-1,1.5002890869157773E-1,1.4694800014500708E-1,1.4363814372966535E-1,1.4012179763439678E-1,1.3642160058953612E-1,1.325602101398717E-1,1.2856015287790984E-1,1.2444368347947359E-1,1.202326505857275E-1,1.1594836872715412E-1,1.116114964682989E-1,1.0724192169715153E-1,1.0285865546157781E-1,9.847973597306743E-2,9.412214438530098E-2,8.980173375715092E-2,8.553317227920516E-2,8.132990143251778E-2,7.720410930601378E-2,7.316671886496477E-2,6.922739056775286E-2,1.624161225901824E-1,1.632259957060995E-1,1.6364541126336185E-1,1.6367613544753232E-1,1.6332340419332775E-1,1.6259560660881126E-1,1.615039285653167E-1,1.6006198162995278E-1,1.5828543749786095E-1,1.561916823892678E-1,1.537995002679694E-1,1.5112878877994346E-1,1.482003078578702E-1,1.4503545814394034E-1,1.4165608473665434E-1,1.380843011344617E-1,1.3434232842286176E-1,1.3045234549398893E-1,1.2643634716348598E-1,1.2231600825009341E-1,1.1811255284194379E-1,1.1384662897014372E-1,1.0953818967227988E-1,1.0520638192512609E-1,1.0086944516053639E-1,9.654462107951291E-2,9.224807629112701E-2,8.799483897714253E-2,8.379875037259386E-2,7.967243140558644E-2,7.562726439700486E-2,7.167338931412641E-2,1.6154447379009818E-1,1.6251913365986437E-1,1.6310742506160877E-1,1.6330998860863E-1,1.6313092286725098E-1,1.6257748364842586E-1,1.61659742187597E-1,1.603902271267467E-1,1.58783570345692E-1,1.56856171115259E-1,1.5462588751519854E-1,1.5211175914328695E-1,1.4933376120015848E-1,1.4631258722991042E-1,1.43069456126041E-1,1.3962593835105044E-1,1.3600379646547284E-1,1.3222483578473515E-1,1.283107620469621E-1,1.242830441737463E-1,1.2016278137089674E-1,1.1597057482551582E-1,1.1172640503435301E-1,1.0744951631286165E-1,1.031583102859861E-1,9.88702501768715E-2,9.460177753153709E-2,9.036824269726226E-2,8.618384996263975E-2,8.206161781663157E-2,7.801335433392628E-2,7.404964727679442E-2,1.6062417261942363E-1,1.617557893785777E-1,1.6250544086365148E-1,1.6287269540204555E-1,1.6286056247340658E-1,1.624752073949889E-1,1.617256237584114E-1,1.6062328825889644E-1,1.591818178395489E-1,1.574166436147338E-1,1.55344710585559E-1,1.5298420728726703E-1,1.5035432557963507E-1,1.4747504797848188E-1,1.4436695823430495E-1,1.410510701762044E-1,1.375486699614941E-1,1.338811675746941E-1,1.300699544732715E-1,1.2613626547423673E-1,1.2210104414654335E-1,1.1798481199569653E-1,1.1380754252159077E-1,1.095885417626102E-1,1.0534633720752608E-1,1.0109857698623287E-1,9.686194108295017E-2,9.265206600149023E-2,8.84834839040985E-2,8.43695767921535E-2,8.032254584057413E-2,7.635339557126632E-2,1.5966312670594604E-1,1.6094398101455284E-1,1.6184753605583296E-1,1.623723409608687E-1,1.6252036480562723E-1,1.6229672618623134E-1,1.6170937954022263E-1,1.607687825744607E-1,1.594875645855665E-1,1.578802101140304E-1,1.5596276700062447E-1,1.5375258308488324E-1,1.5126807187202645E-1,1.485285046753883E-1,1.4555382502985548E-1,1.423644804590086E-1,1.389812667767263E-1,1.3542518078851098E-1,1.3171727830035762E-1,1.278785355371966E-1,1.2392971324904604E-1,1.1989122381591036E-1,1.1578300247257098E-1,1.1162438432360401E-1,1.0743398910419848E-1,1.0322961568644876E-1,9.902814817444454E-2,9.484547512444218E-2,9.069642302081898E-2,8.659470468360471E-2,8.255288282156943E-2,7.858234850990528E-2,1.586688498542299E-1,1.600913603104317E-1,1.611414520757661E-1,1.618167076685415E-1,1.621181045073078E-1,1.620497588484331E-1,1.6161862558658846E-1,1.6083417799296143E-1,1.5970808703033196E-1,1.5825391465059152E-1,1.5648683018583534E-1,1.5442335416052472E-1,1.520811299557795E-1,1.4947872093336068E-1,1.466354288977693E-1,1.4357112903866687E-1,1.4030611657084363E-1,1.3686096095503614E-1,1.3325636461446633E-1,1.29513024253186E-1,1.2565149406314707E-1,1.216920511506061E-1,1.1765456433746556E-1,1.1355836805913264E-1,1.0942214338225494E-1,1.0526380822444503E-1,1.0110041871320785E-1,9.694808332174074E-2,9.282189101695763E-2,8.873585419940326E-2,8.47028667483987E-2,8.07346770433827E-2,1.5764845920500167E-1,1.5920520576039565E-1,1.6039458358215278E-1,1.6121326038534067E-1,1.6166127044258116E-1,1.617417723383944E-1,1.6146076181667987E-1,1.608267635069664E-1,1.5985052101357214E-1,1.5854469972674495E-1,1.5692361149762846E-1,1.5500296558104393E-1,1.5279964637207555E-1,1.5033151563655023E-1,1.4761723519062367E-1,1.446761052265254E-1,1.415279135344832E-1,1.3819279151904204E-1,1.3469107392851268E-1,1.310431604042409E-1,1.2726937814130693E-1,1.2338984600613427E-1,1.1942434129574239E-1,1.1539217090566721E-1,1.1131204899165438E-1,1.0720198328366094E-1,1.0307917207745707E-1,9.895991363756344E-2,9.485952934690965E-2,9.07923014828347E-2,8.67714260291786E-2,8.280898048522271E-2,1.5660867574099122E-1,1.5829241936925192E-1,1.5961397144327888E-1,1.605691356812574E-1,1.6115705122659119E-1,1.613799636607504E-1,1.6124295044400155E-1,1.6075362427893128E-1,1.5992183371943033E-1,1.5875937532828455E-1,1.5727972654541156E-1,1.5549780373699348E-1,1.5342974603738926E-1,1.510927227690229E-1,1.4850476046650046E-1,1.4568458475252608E-1,1.4265147234503683E-1,1.394251091058448E-1,1.3602545105053523E-1,1.3247258642376986E-1,1.2878659813261245E-1,1.2498742689384167E-1,1.2109473630414298E-1,1.171277816401548E-1,1.1310528452943566E-1,1.0904531572141869E-1,1.0496518806603346E-1,1.00881361524517E-1,9.680936164303927E-2,9.276371246477524E-2,8.875788438330522E-2,8.480425698557617E-2,1.5555582771482587E-1,1.573595265908118E-1,1.5880629913586727E-1,1.5989113468157548E-1,1.6061232453991375E-1,1.6097124570830942E-1,1.609720984332383E-1,1.606216208367612E-1,1.599287997622702E-1,1.5890459207873928E-1,1.5756166561635326E-1,1.5591416426074603E-1,1.539774978952822E-1,1.5176815505480346E-1,1.4930353438276406E-1,1.4660179018579544E-1,1.4368168739146464E-1,1.4056246182896126E-1,1.3726368275099635E-1,1.3380511569568732E-1,1.302065849787017E-1,1.2648783617813056E-1,1.2266839984050815E-1,1.1876745824970542E-1,1.148037174502321E-1,1.1079528681884067E-1,1.0675956836896075E-1,1.0271315769796373E-1,9.867175809841308E-2,9.46501089007493E-2,9.066192864011512E-2,8.671987318036985E-2,1.5449585659713766E-1,1.5641267904541786E-1,1.579778921600138E-1,1.591857191407883E-1,1.6003364985666715E-1,1.6052223667265814E-1,1.6065484365373722E-1,1.6043737206113629E-1,1.5987798112755036E-1,1.5898681828003455E-1,1.577757679861217E-1,1.5625822379894566E-1,1.5444888436069465E-1,1.523635712996583E-1,1.5001906517344088E-1,1.4743295479514895E-1,1.446234952718128E-1,1.4160947068194377E-1,1.3841005830680245E-1,1.3504469250630463E-1,1.3153292752449675E-1,1.2789429958996706E-1,1.24148189554805E-1,1.203136879438182E-1,1.1640946465069099E-1,1.124536456344189E-1,1.0846369887192839E-1,1.0445633155720986E-1,1.0044740015384789E-1,9.645183445606004E-2,9.248357633721782E-2,8.855553340094643E-2,1.5343432516763927E-1,1.5545765963755742E-1,1.5713472009313287E-1,1.5845901037363758E-1,1.594272642246809E-1,1.600392526766228E-1,1.6029754439786914E-1,1.60207241652768E-1,1.597757106788463E-1,1.590123205762234E-1,1.5792819988023077E-1,1.5653601543399645E-1,1.548497743832032E-1,1.5288464729416365E-1,1.5065680860383265E-1,1.481832897778375E-1,1.4548184052676094E-1,1.42570794012673E-1,1.3946893295485674E-1,1.3619535471564911E-1,1.3276933464333354E-1,1.2921018803706674E-1,1.255371319887686E-1,1.2176914899910145E-1,1.179248546444748E-1,1.1402237170261081E-1,1.100792130587549E-1,1.061121754580579E-1,1.0213724579205707E-1,9.816952115776736E-2,9.422314345102048E-2,9.031124878825793E-2,1.523764273978623E-1,1.5449988971743586E-1,1.5628240092553197E-1,1.5771679068815156E-1,1.5879908074839183E-1,1.5952830328846968E-1,1.599062719367113E-1,1.5993732776771008E-1,1.596280789377834E-1,1.5898714796840352E-1,1.5802493583790625E-1,1.5675340753245662E-1,1.5518589993490398E-1,1.533369501130886E-1,1.5122214026794512E-1,1.4885795475358476E-1,1.4626164453824023E-1,1.4345109504137277E-1,1.4044469424860284E-1,1.3726119917350701E-1,1.3391959993294303E-1,1.3043898179755545E-1,1.2683838648016155E-1,1.231366745803917E-1,1.1935239149812073E-1,1.1550363927251077E-1,1.1160795672982156E-1,1.0768221007582998E-1,1.0374249569710765E-1,9.980405648885621E-2,9.588121254990199E-2,9.198730661511727E-2,1.513269998008793E-1,1.5354443795460626E-1,1.5542620734164797E-1,1.5696450698392964E-1,1.5815468944019048E-1,1.5899508958927544E-1,1.5948680579332952E-1,1.5963345551288918E-1,1.5944092384379788E-1,1.5891711890516322E-1,1.580717432227186E-1,1.569160857866853E-1,1.55462835713341E-1,1.5372591562721308E-1,1.5172033107196267E-1,1.494620313953203E-1,1.4696777749351422E-1,1.4425501235223853E-1,1.413417312771306E-1,1.382463498693762E-1,1.3498756900081607E-1,1.315842371443458E-1,1.2805521132683312E-1,1.2441921864036079E-1,1.2069472065561782E-1,1.1689978323881789E-1,1.1305195421161125E-1,1.0916815105528174E-1,1.0526456049524217E-1,1.0135655135851386E-1,9.745860161999667E-2,9.358424008071418E-2,1.5029053395017455E-1,1.5259603061660107E-1,1.5457107463355987E-1,1.562072761989107E-1,1.5749936012307425E-1,1.58445004478977E-1,1.5904463142476077E-1,1.593011720014452E-1,1.592198232045498E-1,1.5880781117324144E-1,1.580741696209376E-1,1.570295382092126E-1,1.556859818394557E-1,1.5405682902985451E-1,1.5215652572982258E-1,1.5000050004769422E-1,1.4760503329181135E-1,1.4498713326246288E-1,1.421644066777991E-1,1.3915492877462043E-1,1.3597710932447468E-1,1.3264955541272908E-1,1.2919093224951253E-1,1.256198239622963E-1,1.2195459674115669E-1,1.1821326687831918E-1,1.1441337619309079E-1,1.10571877104324E-1,1.0670502925371231E-1,1.0282830914338431E-1,9.89563337751048E-2,9.510279880393666E-2,1.49271189896422E-1,1.5165906297055073E-1,1.5372160995658532E-1,1.5544989230892176E-1,1.5683804708615903E-1,1.578831349226223E-1,1.5858494001699877E-1,1.5894574367763253E-1,1.589700895548568E-1,1.5866455431688833E-1,1.580375328690987E-1,1.5709904283653314E-1,1.5586054932447754E-1,1.5433480817103973E-1,1.525357240844516E-1,1.5047821916891566E-1,1.4817810725213795E-1,1.4565196995125648E-1,1.4291703134953587E-1,1.3999102930898014E-1,1.3689208264397132E-1,1.336385544935753E-1,1.30248913160542E-1,1.2674159237754198E-1,1.2313485339524619E-1,1.19446651469907E-1,1.1569450928882453E-1,1.1189539965224053E-1,1.080656393778875E-1,1.0422079595832816E-1,1.003756080261771E-1,9.654392020642527E-2,1.4827281023689345E-1,1.5073761155062776E-1,1.5288210266013985E-1,1.546968346059529E-1,1.5617539521420606E-1,1.5731426585578223E-1,1.5811263011223683E-1,1.585721556334154E-1,1.5869676715160627E-1,1.5849242432111296E-1,1.579669134560003E-1,1.5712965789971176E-1,1.5599154807734494E-1,1.5456478948693608E-1,1.5286276505991256E-1,1.508999074202335E-1,1.4869157646689027E-1,1.462539382147781E-1,1.4360384175483462E-1,1.4075869234207508E-1,1.3773631982021306E-1,1.3455484270887136E-1,1.312325292183095E-1,1.2778765716019258E-1,1.2423837516912441E-1,1.2060256784483402E-1,1.1689772739655337E-1,1.1314083416025189E-1,1.0934824801364301E-1,1.0553561228177913E-1,1.0171777125234699E-1,9.790870194302198E-2,1.472989346173142E-1,1.498354470583895E-1,1.5205653545023037E-1,1.5395227700290182E-1,1.555157473325488E-1,1.567428854864031E-1,1.576323108039183E-1,1.581851126528891E-1,1.5840463084369358E-1,1.5829624030306522E-1,1.5786714905073712E-1,1.5712621422288678E-1,1.5608377722513994E-1,1.5475151631024547E-1,1.531423130450629E-1,1.5127012822001765E-1,1.4914988263586526E-1,1.467973387003147E-1,1.4422897968340448E-1,1.4146188462320697E-1,1.3851359807326652E-1,1.354019950048439E-1,1.3214514212388964E-1,1.2876115757670906E-1,1.2526807147607474E-1,1.2168368988634533E-1,1.1802546488836939E-1,1.1431037314289647E-1,1.1055480503203996E-1,1.0677446603032531E-1,1.0298429148482115E-1,9.919837550651314E-2,1.4635281446993512E-1,1.4895604768656998E-1,1.512485961625871E-1,1.5322009813417023E-1,1.5486315252912908E-1,1.5617319174922673E-1,1.5714830625225343E-1,1.577890417358728E-1,1.5809818656918145E-1,1.580805629666921E-1,1.5774283091696228E-1,1.570933096168672E-1,1.56141817522671E-1,1.54899529348393E-1,1.5337884650787853E-1,1.5159327657542762E-1,1.4955731720881066E-1,1.472863404641519E-1,1.447964743392179E-1,1.4210447951928556E-1,1.392276204991562E-1,1.3618353138037803E-1,1.329900775970059E-1,1.296652155470612E-1,1.2622685257569435E-1,1.2269270997396516E-1,1.1908019164961058E-1,1.1540626093271085E-1,1.1168732764650813E-1,1.0793914714978721E-1,1.0417673258710167E-1,1.0041428110550629E-1,1.4543742781424168E-1,1.4810261267923994E-1,1.5046168994738157E-1,1.5250389204266548E-1,1.5422137523556642E-1,1.5560909968791517E-1,1.5666466129046214E-1,1.5738809586803343E-1,1.5778167324609532E-1,1.578496945881456E-1,1.5759830198382932E-1,1.5703530504317012E-1,1.5617002563322513E-1,1.5501315911994956E-1,1.5357664864090723E-1,1.518735680036152E-1,1.499180086613023E-1,1.4772496669198087E-1,1.4531022660485965E-1,1.4269023993073393E-1,1.3988199775169555E-1,1.3690289745444625E-1,1.337706049526281E-1,1.3050291435656602E-1,1.271176075481862E-1,1.2363231634732803E-1,1.2006438995799769E-1,1.1643077019801112E-1,1.1274787668918813E-1,1.0903150376570543E-1,1.0529673039010874E-1,1.0155784388889497E-1,1.4455549396797124E-1,1.4727807596249676E-1,1.49698951687399E-1,1.5180697926421927E-1,1.535939048689422E-1,1.5505424955885835E-1,1.561851479097492E-1,1.5698615882133166E-1,1.5745906583826633E-1,1.576076803127632E-1,1.5743765635566995E-1,1.56956322333544E-1,1.5617253007027443E-1,1.550965201454306E-1,1.5373979984191236E-1,1.5211502935592605E-1,1.5023591172813455E-1,1.4811708241792246E-1,1.4577399533227747E-1,1.4322280324840725E-1,1.404802317670775E-1,1.3756344706563728E-1,1.3448991868712515E-1,1.3127727934348124E-1,1.2794318420007975E-1,1.2450517234737304E-1,1.2098053317717704E-1,1.1738618020409416E-1,1.137385345525791E-1,1.100534199148185E-1,1.0634597031869257E-1,1.0263055156774327E-1,1.4370948803585792E-1,1.4648511969972297E-1,1.4896325849140443E-1,1.511324181400385E-1,1.529839658551194E-1,1.5451201546913756E-1,1.5571327242864416E-1,1.565868507851916E-1,1.571340793930108E-1,1.5735831055848096E-1,1.5726474005499952E-1,1.5686024326097292E-1,1.5615322859911587E-1,1.551535066960318E-1,1.5387217183934643E-1,1.523214913621886E-1,1.5051479842009094E-1,1.4846638407805754E-1,1.4619138550687516E-1,1.437056682104827E-1,1.4102570140305679E-1,1.3816842678915023E-1,1.3515112197345003E-1,1.319912604763791E-1,1.2870637083024916E-1,1.253138974787828E-1,1.2183106622356414E-1,1.1827475679170606E-1,1.1466138478511623E-1,1.1100679486064892E-1,1.0732616652676161E-1,1.0363393346546224E-1,1.429016550617348E-1,1.457261876440034E-1,1.4825724212308466E-1,1.504830162063946E-1,1.5239452787275493E-1,1.539855143789991E-1,1.5525228316962128E-1,1.5619353464527308E-1,1.5681017386297777E-1,1.571051243349734E-1,1.5708315280664487E-1,1.567507097699509E-1,1.5611578690778655E-1,1.5518778991262938E-1,1.5397742327938505E-1,1.5249658271761174E-1,1.507582506536657E-1,1.4877639073622478E-1,1.465658381320251E-1,1.4414218351669067E-1,1.41521649861205E-1,1.3872096225162803E-1,1.357572119582013E-1,1.3264771672711637E-1,1.2940987977538326E-1,1.2606105022638744E-1,1.2261838775296785E-1,1.1909873403301577E-1,1.155184933145949E-1,1.1189352398060005E-1,1.0823904254166562E-1,1.0456954100980215E-1,1.4213402374631837E-1,1.4500349817737962E-1,1.475833012433401E-1,1.4986134152823194E-1,1.51828316174579E-1,1.5347761531637755E-1,1.548051784826633E-1,1.5580932274291123E-1,1.5649055953994878E-1,1.5685141330237493E-1,1.5689625068430363E-1,1.566311251862374E-1,1.560636383677162E-1,1.5520281611716982E-1,1.540589965996491E-1,1.5264372554167313E-1,1.5096965432860643E-1,1.4905043682362182E-1,1.4690062168322773E-1,1.4453553805775618E-1,1.4197117375964988E-1,1.3922404612150308E-1,1.3631106674919533E-1,1.3324940213951073E-1,1.3005633264692176E-1,1.267491125498036E-1,1.2334483400368343E-1,1.1986029751434016E-1,1.1631189126124314E-1,1.1271548119886583E-1,1.0908631340445561E-1,1.0543892966535115E-1,1.4140841964813533E-1,1.443190569423388E-1,1.4694361335977663E-1,1.492697338597105E-1,1.512878218589083E-1,1.5299094866732524E-1,1.543747149715526E-1,1.554370839640122E-1,1.561782029435414E-1,1.5660022640795507E-1,1.5670714945458394E-1,1.5650465623906865E-1,1.5599998471632934E-1,1.5520180614915105E-1,1.5412011602403913E-1,1.5276613204640563E-1,1.5115219469480834E-1,1.492916662389423E-1,1.471988249849012E-1,1.4488875262025067E-1,1.4237721372455947E-1,1.3968052765196537E-1,1.3681543398013168E-1,1.3379895349038953E-1,1.306482471666811E-1,1.2738047597443503E-1,1.2401266422539223E-1,1.2056156918631866E-1,1.1704355929261617E-1,1.1347450292877094E-1,1.0986966928099295E-1,1.0624364229272092E-1],[3.3909485253675115E-1,9.997529836607687E-1,9.99033394173412E-1,9.978734812795618E-1,9.96305447248215E-1,9.943612977230565E-1,9.920727057560342E-1,9.894708889763058E-1,9.865864997094095E-1,9.834495277440137E-1,9.800892153425516E-1,9.765339840069684E-1,9.728113724409572E-1,9.689479850945661E-1,9.649694506349458E-1,9.6090038965717E-1,9.567643909304041E-1,9.525839954660321E-1,9.483806876945519E-1,9.441748930459662E-1,9.399859812429397E-1,9.358322746361067E-1,9.317310609356425E-1,9.276986097216056E-1,9.237501921468152E-1,9.199001032793649E-1,9.161616865666294E-1,9.125473599381856E-1,9.090686431009222E-1,9.057361856153195E-1,9.025597953770438E-1,8.995484671623336E-1,4.696420705897682E-2,3.387691387769439E-1,9.997634809740615E-1,9.990749888723537E-1,9.979661299968289E-1,9.96468401972593E-1,9.946130538389705E-1,9.924309589454783E-1,9.89952500538775E-1,9.872074698045158E-1,9.84224976022E-1,9.810333683991737E-1,9.776601690803098E-1,9.74132016757796E-1,9.704746202719748E-1,9.667127215479322E-1,9.628700671944223E-1,9.58969388076673E-1,9.550323861704976E-1,9.510797280088598E-1,9.47131044042714E-1,9.432049332545372E-1,9.393189723845178E-1,9.354897291549361E-1,9.317327789070412E-1,9.280627240959062E-1,9.244932161216604E-1,9.210369790095152E-1,9.177058344855935E-1,9.1451072803027E-1,9.114617555251348E-1,9.085681901434723E-1,4.971483009969774E-2,4.626758263160615E-2,3.384412583472707E-1,9.997737952613622E-1,9.991158437027272E-1,9.980570994021613E-1,9.966283501240256E-1,9.94860086323237E-1,9.927823825566936E-1,9.904247911313053E-1,9.878162477074675E-1,9.849849884816436E-1,9.819584784914587E-1,9.787633505207065E-1,9.754253540290966E-1,9.719693134915081E-1,9.684190955029595E-1,9.647975839874058E-1,9.61126662839756E-1,9.574272053301017E-1,9.53719069606004E-1,9.500210996417809E-1,9.463511310021094E-1,9.42726000809987E-1,9.391615613353376E-1,9.356726966495286E-1,9.322733418220798E-1,9.289765041682513E-1,9.257942860894619E-1,9.227379090821025E-1,9.198177385238713E-1,9.170433088799117E-1,5.243664570238918E-2,4.892964313600073E-2,4.5566954920353286E-2,3.3811126111711604E-1,9.997839217622829E-1,9.991559398391031E-1,9.981463475440052E-1,9.967852176971016E-1,9.951022802107059E-1,9.931268116703237E-1,9.908875366899238E-1,9.884125407207855E-1,9.857291939082856E-1,9.828640855201944E-1,9.798429684126548E-1,9.766907129551785E-1,9.734312698027766E-1,9.700876408807471E-1,9.666818579346443E-1,9.632349679935223E-1,9.597670250976418E-1,9.562970876514679E-1,9.528432207779934E-1,9.494225030703098E-1,9.460510371600458E-1,9.427439635490356E-1,9.395154771796526E-1,9.363788462499848E-1,9.333464328118974E-1,9.304297147224954E-1,9.276393085521457E-1,9.24984993084677E-1,5.512284780098163E-2,5.156210730046296E-2,4.8141089015380126E-2,4.486244869951206E-2,3.3777920215485674E-1,9.997938558529609E-1,9.991952590061617E-1,9.982338337158541E-1,9.969389329103697E-1,9.953395240247507E-1,9.934640864071104E-1,9.913405200309531E-1,9.889960651584379E-1,9.864572325242955E-1,9.837497435481647E-1,9.80898480033739E-1,9.779274427754332E-1,9.748597184663578E-1,9.717174542842465E-1,9.685218395236188E-1,9.652930936418805E-1,9.620504600932872E-1,9.588122053367816E-1,9.555956224207561E-1,9.524170385689483E-1,9.492918262161574E-1,9.462344169695653E-1,9.432583180004838E-1,9.403761304017666E-1,9.375995690773923E-1,9.349394837623943E-1,9.324058808030079E-1,5.7767175209136185E-2,5.4158550373706E-2,5.068485670519441E-2,4.7349338293822686E-2,4.415419883496156E-2,3.374451409720716E-1,9.998035930487081E-1,9.992337834892744E-1,9.983195184802823E-1,9.970894262499385E-1,9.955717098474797E-1,9.937940520330317E-1,9.917835310009746E-1,9.89566546552433E-1,9.871687562662979E-1,9.846150211645107E-1,9.819293603254118E-1,9.791349138678759E-1,9.762539137078152E-1,9.733076614764543E-1,9.703165129856078E-1,9.672998686280707E-1,9.642761691102258E-1,9.612628959281979E-1,9.58276576017499E-1,9.553327900283205E-1,9.524461837037198E-1,9.496304818652548E-1,9.468985045395402E-1,9.442621847892225E-1,9.417325878425061E-1,9.393199311462361E-1,6.036391678873319E-2,5.671307028053486E-2,5.319219800327414E-2,4.9805112500689384E-2,4.655457166279772E-2,4.3442348670250604E-2,3.371091408289568E-1,9.99813129006561E-1,9.992714961446809E-1,9.984033636920596E-1,9.972366305114183E-1,9.957987333873158E-1,9.941165590605737E-1,9.922163666214115E-1,9.901237198521968E-1,9.87863429052989E-1,9.854595018370813E-1,9.82935102348702E-1,9.803125183300377E-1,9.776131354488815E-1,9.748574182905388E-1,9.720648974172303E-1,9.692541619041929E-1,9.664428567731183E-1,9.636476847596593E-1,9.608844118716768E-1,9.58167876217978E-1,9.555119996128436E-1,9.529298014890397E-1,9.504334146807397E-1,9.480341026673462E-1,9.457422778992002E-1,6.290791070997448E-2,5.9220290594304E-2,5.5657553657839504E-2,5.222405992702935E-2,4.892310338074406E-2,4.575697809832564E-2,4.272704858261552E-2,3.3677126813010594E-1,9.998224595277285E-1,9.993083804092533E-1,9.984853325203278E-1,9.973804808401721E-1,9.960204940438835E-1,9.944314633460379E-1,9.926388312275701E-1,9.906673296164887E-1,9.885409270431839E-1,9.862827842522597E-1,9.839152177241328E-1,9.8145967054022E-1,9.789366900144857E-1,9.76365911510534E-1,9.73766047866418E-1,9.711548838580436E-1,9.685492751456262E-1,9.659651511653504E-1,9.634175214494464E-1,9.60920484881661E-1,9.584872414209659E-1,9.561301058537393E-1,9.538605231631231E-1,9.516890851333302E-1,6.539453839244042E-2,6.1675358070241465E-2,5.807586613348676E-2,5.460094826911508E-2,5.1254415418256954E-2,4.8039066069030564E-2,4.495675324243725E-2,4.200845475944673E-2,3.364315919293356E-1,9.998315805599354E-1,9.993444203098443E-1,9.985653894698239E-1,9.975209147698422E-1,9.962368949701458E-1,9.947386261827879E-1,9.930507366019883E-1,9.911971301976267E-1,9.892009388837517E-1,9.870844826417723E-1,9.848692370551589E-1,9.82575807698159E-1,9.802239108143455E-1,9.778323597209065E-1,9.754190563805989E-1,9.730009875944037E-1,9.705942252833775E-1,9.682139303472478E-1,9.658743596092857E-1,9.635888753812892E-1,9.613699572085687E-1,9.592292153821347E-1,9.571774058334237E-1,6.781971372291383E-2,6.407393530467956E-2,6.044257559844179E-2,5.693102349914565E-2,5.354358697788836E-2,5.028355148444948E-2,4.715324353435683E-2,4.4154098061695055E-2,4.12867282245812E-2,3.36090183553454E-1,9.998404881996629E-1,9.993796004722093E-1,9.986435004011363E-1,9.976578722591242E-1,9.964478431317372E-1,9.950379143903425E-1,9.934519021019423E-1,9.917128859177932E-1,9.898431659471045E-1,9.878642270960003E-1,9.857967103344485E-1,9.836603903441794E-1,9.814741589978817E-1,9.792560141233488E-1,9.77023053014945E-1,9.74791470168003E-1,9.725765587288306E-1,9.703927151732062E-1,9.682534467489826E-1,9.661713812431059E-1,9.641582786595099E-1,9.622250444214901E-1,7.017986814184256E-2,6.641218908727711E-2,6.275361145768053E-2,5.921000447824192E-2,5.5786152613148614E-2,5.2485810064971807E-2,4.931176092310204E-2,4.626588353910442E-2,4.334921780487044E-2,4.0562034126596334E-2,3.35747116347808E-1,9.998491786942808E-1,9.994139061295003E-1,9.987196325499772E-1,9.97791295726757E-1,9.96653249363439E-1,9.953292003992276E-1,9.938421547809736E-1,9.922143712372077E-1,9.904673225579187E-1,9.886216638633328E-1,9.866972073323648E-1,9.847129028559463E-1,9.826868240812565E-1,9.806361593192071E-1,9.785772067986015E-1,9.765253737654827E-1,9.744951789446213E-1,9.725002579012663E-1,9.705533708645981E-1,9.686664125992938E-1,9.668504239377573E-1,7.24719321776089E-2,6.868677500625149E-2,6.500537997049935E-2,6.1434073511082994E-2,5.7978095630250616E-2,5.464165049543194E-2,5.142796312956633E-2,4.833934076583049E-2,4.537723753491238E-2,4.254232126376136E-2,3.983454128789928E-2,3.354024655411731E-1,9.998576484440737E-1,9.994473231303227E-1,9.98793754545459E-1,9.979211300847034E-1,9.968530284227467E-1,9.956123623315011E-1,9.942213295042964E-1,9.927013709139565E-1,9.91073136208784E-1,9.8935645563512E-1,9.875703179670249E-1,9.85732853921963E-1,9.83861324545381E-1,9.819721140560147E-1,9.800807266569013E-1,9.782017868337712E-1,9.763490426820977E-1,9.745353718260307E-1,9.727727895162172E-1,9.710724585186327E-1,7.469331398757377E-2,7.089481885165354E-2,6.719474848126723E-2,6.359986335254651E-2,6.011583780391579E-2,5.674730677000259E-2,5.3497919013081804E-2,5.037039543264629E-2,4.736659111649526E-2,4.448755990119247E-2,4.173362032780025E-2,3.9104422003770144E-2,3.3505630822385374E-1,9.998658940041573E-1,9.994798379463528E-1,9.988658364273617E-1,9.980473227694934E-1,9.97047099040484E-1,9.958872840768731E-1,9.945892690579622E-1,9.931736801552856E-1,9.916603477644845E-1,9.900682818158019E-1,9.884156526553416E-1,9.86719776990995E-1,9.849971084037904E-1,9.832632319366682E-1,9.81532862287647E-1,9.798198451524069E-1,9.781371612818949E-1,9.764969328431345E-1,9.749104316955174E-1,7.684187543871263E-2,7.303389534024435E-2,6.931902677531873E-2,6.570444116451969E-2,6.219622588971684E-2,5.8799427200942334E-2,5.551810000531074E-2,5.23553631241151E-2,4.9313458679485125E-2,4.639381437013512E-2,4.359710750867292E-2,4.092332981381424E-2,3.837185207417277E-2,3.347087234305854E-1,9.998739120862855E-1,9.995114376795086E-1,9.989358496623788E-1,9.981698237717067E-1,9.972353839684169E-1,9.961538553643435E-1,9.949458242516559E-1,9.936311047601653E-1,9.922287116546347E-1,9.907568387778126E-1,9.892328426444815E-1,9.876732306966428E-1,9.860936537393346E-1,9.845089020898479E-1,9.829329049896378E-1,9.813787328474481E-1,9.798586019035458E-1,9.783838809280221E-1,7.89159062297249E-2,7.510200465893088E-2,7.137594604954346E-2,6.774528990287823E-2,6.421651540140874E-2,6.0795060546360455E-2,5.748536853605309E-2,5.4290939979016455E-2,5.121438960379829E-2,4.8257506219179624E-2,4.5421314786383046E-2,4.270613958152301E-2,4.011166754674781E-2,3.763701104770763E-2,3.3435979231878443E-1,9.998816995605458E-1,9.995421100686718E-1,9.990037671593306E-1,9.982885856635717E-1,9.974178100238272E-1,9.964119718292874E-1,9.952908540150124E-1,9.940734612529539E-1,9.927779960544074E-1,9.914218401008795E-1,9.900215403232071E-1,9.885927992563259E-1,9.871504692086893E-1,9.857085498003643E-1,9.842801884417121E-1,9.828776833447467E-1,9.815124886812889E-1,8.091409652208024E-2,7.709754729295477E-2,7.33636359603222E-2,6.972028759154425E-2,6.617435210241521E-2,6.273163969660656E-2,5.939696387941016E-2,5.617419064984984E-2,5.306629253577813E-2,5.007540622227886E-2,4.720289262630293E-2,4.444939838311746E-2,4.1814917826887434E-2,3.9298854664616245E-2,3.6900082655909994E-2,3.340095984325812E-1,9.998892534569435E-1,9.995718434959542E-1,9.990695632833356E-1,9.98403563624659E-1,9.975943081310066E-1,9.966615350759221E-1,9.956242254873443E-1,9.945005770079933E-1,9.933079830531065E-1,9.920630167953588E-1,9.907814195125959E-1,9.894780928439864E-1,9.881670945137518E-1,9.868616370981858E-1,9.85574089430682E-1,9.843159802604864E-1,8.283550851057915E-2,7.901929757148705E-2,7.528060018120912E-2,7.162768491364176E-2,6.806775163714407E-2,6.460696333876474E-2,6.1250485831966524E-2,5.800253396377765E-2,5.486642299073051E-2,5.184462387255508E-2,4.893882133013509E-2,4.614997362263813E-2,4.3478373112247455E-2,4.092370679915599E-2,3.848511612093985E-2,3.616125541691531E-2,3.3365822804373285E-1,9.998965709668717E-1,9.996006269925078E-1,9.991332138689284E-1,9.98514715465651E-1,9.97764813359634E-1,9.969024527350933E-1,9.959458141006815E-1,9.949122903649805E-1,9.93818468810353E-1,9.926801175092751E-1,9.915121757356686E-1,9.903287479358598E-1,9.891431008390442E-1,9.87967663304986E-1,9.868140285266414E-1,8.467954732569144E-2,8.086637632771652E-2,7.712569087012022E-2,7.346608152009935E-2,6.989507770112155E-2,6.641917599513963E-2,6.304387661405618E-2,5.977372666976627E-2,5.661236891865955E-2,5.356259473010783E-2,5.062640012093037E-2,4.78050438021056E-2,4.509910629415879E-2,4.250854927922198E-2,4.003277446734825E-2,3.767068135961633E-2,3.5420723389524775E-2,3.3330577056171995E-1,9.999036494444694E-1,9.996284502438719E-1,9.99194696232117E-1,9.986220016501679E-1,9.979292649600054E-1,9.971346385173231E-1,9.962555036560313E-1,9.953084507349748E-1,9.943092636996722E-1,9.932729087187557E-1,9.92213526465489E-1,9.91144427628717E-1,9.900780912543131E-1,9.890261655371335E-1,8.64459316210081E-2,8.263822303395854E-2,7.889808241165398E-2,7.523440142448981E-2,7.16550191200259E-2,6.816674680529482E-2,6.477540136157693E-2,6.1485845635739965E-2,5.8302034592077966E-2,5.522706597638792E-2,5.226323433154629E-2,4.941208730404297E-2,4.667448328762375E-2,4.405064955923911E-2,4.154024016993396E-2,3.91423929568457E-2,3.6855785140396564E-2,3.4678687061870446E-2,3.3295231900689143E-1,9.999104864078632E-1,9.996553035948564E-1,9.992539891813715E-1,9.987253853146363E-1,9.980876063950842E-1,9.973580122610716E-1,9.965531863927743E-1,9.956889186969078E-1,9.947801924392853E-1,9.938411749015738E-1,9.928852113513335E-1,9.919248219300202E-1,9.909717010815801E-1,8.813466416041776E-2,8.433456773545463E-2,8.059724476537601E-2,7.693186782020335E-2,7.334656617724468E-2,6.984844739312854E-2,6.64436275500677E-2,6.31372688362534E-2,5.993362315372457E-2,5.683608050911858E-2,5.384722102547288E-2,5.096886950926314E-2,4.820215161033518E-2,4.554755071867052E-2,4.300496484730041E-2,4.0573762852707376E-2,3.825283944079664E-2,3.604066849700625E-2,3.393535436248647E-2,3.325979705423311E-1,9.999170795402953E-1,9.996811780539578E-1,9.993110730275366E-1,9.988248322861838E-1,9.982397853693455E-1,9.975724999761605E-1,9.968387630511201E-1,9.960535660844794E-1,9.952310942099272E-1,9.94384718693543E-1,9.935269924225679E-1,9.926696480194926E-1,8.974600268157809E-2,8.59554030700446E-2,8.222291671607034E-2,7.855797762308216E-2,7.49689864984524E-2,7.14633291312655E-2,6.804740366560973E-2,6.472665544605287E-2,6.1505618139069206E-2,5.838795989090901E-2,5.537653336025492E-2,5.2473428556188605E-2,4.9680027512060014E-2,4.699705992948859E-2,4.442465903000555E-2,4.196241695223937E-2,3.960943912813781E-2,3.736439716143562E-2,3.522557981448456E-2,3.319094178564144E-2,3.3224282706200065E-1,9.999234266911351E-1,9.997060652973059E-1,9.993659295926623E-1,9.989203110985482E-1,9.983857538543914E-1,9.977780338823211E-1,9.971121429275541E-1,9.964022760633306E-1,9.956618227595304E-1,9.94903361027532E-1,9.941386542699013E-1,9.128043127564263E-2,8.750095662539838E-2,8.377507928775325E-2,8.011247600976679E-2,7.65218007704443E-2,7.301070008543309E-2,6.958583740920593E-2,6.625292532878042E-2,6.30167642641802E-2,5.988128644215563E-2,5.6849603983094965E-2,5.392406002919114E-2,5.110628193882977E-2,4.839723567311118E-2,4.5797280601566646E-2,4.3306224052910736E-2,4.092337503103747E-2,3.864759660532398E-2,3.6477356566719986E-2,3.441077601691756E-2,3.2445675626854055E-2,3.318869958346563E-1,9.999295258767747E-1,9.997299576721373E-1,9.99418542217748E-1,9.990117930059899E-1,9.985254681113163E-1,9.979745524428293E-1,9.973732439232179E-1,9.96734943198403E-1,9.960722464946359E-1,9.953969412548928E-1,9.273863248817599E-2,8.89716638513254E-2,8.52539295500367E-2,8.159533119000312E-2,7.80047585406253E-2,7.449010189200883E-2,7.105827369319444E-2,6.771523818352282E-2,6.446604774446413E-2,6.131488474547945E-2,5.826510772640762E-2,5.5319300843241694E-2,5.2479325597833165E-2,4.974637397041643E-2,4.712102217285442E-2,4.460328433763022E-2,4.219266555074975E-2,3.988821372463134E-2,3.7688569888975454E-2,3.559201655299194E-2,3.359652386135968E-2,3.169979332853856E-2,3.3153059020485764E-1,9.999353752814085E-1,9.997528481997977E-1,9.994688957693941E-1,9.990992519951984E-1,9.986588887098035E-1,9.981620003931951E-1,9.976219925851685E-1,9.970514735114002E-1,9.964622485584053E-1,9.412146031333155E-2,9.036814171229536E-2,8.66598550137578E-2,8.300670962024043E-2,7.941781431360086E-2,7.590128679297302E-2,7.2464272660553E-2,6.911297258530268E-2,6.585267638456276E-2,6.268780280495184E-2,5.962194384855811E-2,5.665791257107768E-2,5.3797793369194595E-2,5.1042993870163686E-2,4.839429763355902E-2,4.5851916970584786E-2,4.341554527816209E-2,4.1084408372088585E-2,3.885731438471227E-2,3.673270186773697E-2,3.470868580944874E-2,3.2783101338124176E-2,3.095354493956922E-2,3.311737303541918E-1,9.999409732576947E-1,9.997747305782678E-1,9.995169766453605E-1,9.991826647951854E-1,9.987859805439402E-1,9.983403287648847E-1,9.978583241404768E-1,9.973517845282873E-1,9.542991422269373E-2,9.169116323494114E-2,8.799340878281035E-2,8.434695183644138E-2,8.07611041325988E-2,7.724419502462393E-2,7.380358793081576E-2,7.044570512961942E-2,6.717605965467943E-2,6.399929307954505E-2,6.0919218042304255E-2,5.793886443753728E-2,5.506052829056009E-2,5.228582242212093E-2,4.9615728106618344E-2,4.705064702065158E-2,4.4590452869350615E-2,4.223454216392385E-2,3.998188370445142E-2,3.7831066396619414E-2,3.57803450996281E-2,3.3827684264918584E-2,3.1970799181727856E-2,3.020719469609734E-2,3.3081654412745193E-1,9.999463183273007E-1,9.99795599184214E-1,9.995627727790259E-1,9.992620108851592E-1,9.9890671284474E-1,9.985094949040497E-1,9.980821825231289E-1,9.666511434201187E-2,9.294163307717744E-2,8.925528560118194E-2,8.561654905642016E-2,8.203492280626402E-2,7.851893272976362E-2,7.507614525045148E-2,7.171318986586382E-2,6.843578894418743E-2,6.524879358665929E-2,6.2156224410911134E-2,5.916131618417392E-2,5.626656531984238E-2,5.347377934172779E-2,5.078412751310561E-2,4.819819191987814E-2,4.5716018386428074E-2,4.3337166687824696E-2,4.1060759601874816E-2,3.888553041878502E-2,3.6809868594416206E-2,3.483186329552537E-2,3.294934464181732E-2,3.1159922500487332E-2,2.946102273422521E-2,3.30459167930002E-1,9.999514091813312E-1,9.998154490745639E-1,9.996062736427503E-1,9.993372725003766E-1,9.990210591893625E-1,9.98669462485255E-1,9.78282778633971E-2,9.412056421974674E-2,9.044629890837746E-2,8.68161206763351E-2,8.323970191592513E-2,7.972575053794997E-2,7.628202170083612E-2,7.291533818038391E-2,6.96316181599499E-2,6.643590924888515E-2,6.333242758984614E-2,6.032460098602913E-2,5.741511506118287E-2,5.460596155364968E-2,5.189848793656386E-2,4.929344764686429E-2,4.679105029381864E-2,4.439101130183895E-2,4.209260052147546E-2,3.9894689416265804E-2,3.779579650104157E-2,3.5794130769602917E-2,3.388763290616134E-2,3.207401412594519E-2,3.0350792536042826E-2,2.8715326948049003E-2,3.301017477039047E-1,9.999562446806384E-1,9.998342759876033E-1,9.99647470250136E-1,9.9940843463597E-1,9.991289975070298E-1,9.892069675748721E-2,9.522905585766225E-2,9.156735899286288E-2,8.794639276231553E-2,8.437598871487902E-2,8.086502293506104E-2,7.742142559389112E-2,7.405219926718426E-2,7.076344481439974E-2,6.756039363529534E-2,6.444744517081037E-2,6.1428208581908054E-2,5.850554761921957E-2,5.5681627782429674E-2,5.2957964957309714E-2,5.033547480728876E-2,4.781452228319588E-2,4.539497069795173E-2,4.307622989134894E-2,4.085730308331331E-2,3.8736832081721656E-2,3.671314057290899E-2,3.478427527959979E-2,3.294804482205307E-2,3.120205616414625E-2,2.954374856704543E-2,2.7970425009124732E-2,3.297444399915629E-1,9.999608238560157E-1,9.998520763436E-1,9.996863551571908E-1,9.994754850487493E-1,9.994371682955527E-2,9.626827254804043E-2,9.261945231192062E-2,8.90081776168196E-2,8.544442600969705E-2,8.193722852185978E-2,7.849467716397564E-2,7.512394130301016E-2,7.183129172751937E-2,6.86221312279673E-2,6.550103056460513E-2,6.2471768759720055E-2,5.953737672764266E-2,5.670018333981178E-2,5.3961863109266074E-2,5.132348476644377E-2,4.878556008370625E-2,4.634809238808164E-2,4.40106242794851E-2,4.177228414429089E-2,3.9631831121550026E-2,3.758769824099873E-2,3.563803350854726E-2,3.378073876615465E-2,3.201350619908001E-2,3.033385240470712E-2,2.8739149973612866E-2,2.7226656565636765E-2,3.293874130966189E-1,9.999651459082738E-1,9.998688472449482E-1,9.997229224623919E-1,1.00898718145568E-1,9.723942465231174E-2,9.360362202729659E-2,9.000235447993149E-2,8.644573309402816E-2,8.294293124161146E-2,7.950219014500888E-2,7.61308334239814E-2,7.283528944734526E-2,6.962112032517377E-2,6.649305642036998E-2,6.345503531983722E-2,6.05102442796677E-2,5.766116524048726E-2,5.4909621594506894E-2,5.225682597180559E-2,4.970342839773004E-2,4.724956425444896E-2,4.4894901556714474E-2,4.26386871239903E-2,4.047979129813611E-2,3.8416750917543686E-2,3.644781031504973E-2,3.457096015825979E-2,3.2783973997144174E-2,3.1084442425254547E-2,2.9469804797663857E-2,2.793737848127437E-2,2.6484385641339335E-2,3.290308483526729E-1,9.999692102082001E-1,9.998845864758417E-1,1.0178709683861514E-1,9.81437500945721E-2,9.452094978938218E-2,9.092985140877888E-2,8.738068778793735E-2,8.388276263911439E-2,8.044445430388084E-2,7.707322858295637E-2,7.377565947572302E-2,7.055745667483668E-2,6.742349870101136E-2,6.437787062190826E-2,6.14239053708761E-2,5.856422776106473E-2,5.580080037415613E-2,5.313497058751065E-2,5.056751808674897E-2,4.809870229105019E-2,4.572830919468227E-2,4.345569719994014E-2,4.1279841583270756E-2,3.919937729787898E-2,3.7212639872468846E-2,3.53177042170645E-2,3.3512421193263475E-2,3.179445184791638E-2,3.0161299246359442E-2,2.8610337874116175E-2,2.7138840604662557E-2,2.5744003255746356E-2,3.2867494151099275E-1,9.999730162964009E-1,1.026102482928774E-1,9.898249744395198E-2,9.537253878807725E-2,9.179162836314203E-2,8.825010962035504E-2,8.475740519770751E-2,8.132201898523954E-2,7.79515473506789E-2,7.465269836972875E-2,7.143131791548629E-2,6.829242149837789E-2,6.524023080437139E-2,6.2278213948827106E-2,5.940912854129492E-2,5.6635066738650375E-2,5.395750154725801E-2,5.137733371684381E-2,4.889493864828745E-2,4.651021281295128E-2,4.42226192523919E-2,4.20312317935068E-2,3.993477767542773E-2,3.793167834078503E-2,3.602008819520209E-2,3.4197931185433746E-2,3.2462935088345704E-2,3.0812663440325568E-2,2.9244545069843517E-2,2.7755901224898395E-2,2.6343970312377472E-2,2.5005930287988955E-2,3.283199042587231E-1]],"losses":[-9.952125227881714E-2,-1.4657479116128336E-1,-1.930287822505916E-1],"sum":[[-1.380838286046293E-3,-1.3848891583638778E-3,-1.383259980509477E-3,-1.3649820560728276E-3,-1.3179739249842282E-3,-1.2289268235705642E-3,-1.0833109117602824E-3,-8.654907383724986E-4,-5.308189304598088E-4,-2.6506889326305405E-4,-7.089223258116562E-5,4.984296576204805E-5,9.610728500630827E-5,6.775628700972369E-5,-3.443314407958198E-5,-2.0873744631511038E-4,-4.5247290636019066E-4,-7.61994809660882E-4,-1.1327097825171162E-3,-1.5591017007072772E-3,-2.0347713289585734E-3,-2.552489631195032E-3,-3.1042644571701583E-3,-3.6814200705155287E-3,-4.274688741217725E-3,-4.874313386512785E-3,-5.470160013129277E-3,-6.051838495831685E-3,-6.608830026821E-3,-7.1306193930840145E-3,-7.606830088080052E-3,-8.027360144790219E-3,-8.382516492531966E-3,-8.663145592874066E-3,-8.860758103077515E-3,-8.96764534990524E-3,-8.97698547320358E-3,-8.882937217148168E-3,-8.680719506116485E-3,-8.366675139998225E-3,-7.938317177312637E-3,-7.394356839942162E-3,-6.734712066207571E-3,-5.9604961540955514E-3,-5.073986267915664E-3,-4.078571923257446E-3,-2.978683910394686E-3,-1.779704458269915E-3,-4.878597735569201E-4,8.899035949894163E-4,2.3460568235482704E-3,3.872639303768022E-3,5.461419318328442E-3,7.1040624707645605E-3,8.79230528885211E-3,1.0518131315846002E-2,1.227394694614814E-2,1.4052754252170008E-2,1.5848318087466673E-2,1.7655324836500785E-2,1.946953031194898E-2,2.1287894473020597E-2,2.3108700849717723E-2,2.493165880340431E-2,2.6757987028945385E-2,2.859047700215811E-2,3.0433535392925037E-2,3.229320479259146E-2,3.417716243849944E-2,3.6094696952086336E-2,3.805666343454028E-2,4.0075417579353845E-2,4.216472975942964E-2,4.4339680322774244E-2,4.6616537581049444E-2,4.9012620195929335E-2,5.1546145856505965E-2,5.423606829462013E-2,5.710190480282229E-2,6.016355650086924E-2,6.344112364125754E-2,6.695471825315569E-2,7.07242763983923E-2,7.47693722547692E-2,7.910903615348064E-2,8.376157858132449E-2,8.874442201811239E-2,9.407394231839006E-2,9.976532116807557E-2,1.0583241095433116E-1,1.1228761318481117E-1,1.1914177138398085E-1,1.2640407918285446E-1,1.3408200410793714E-1,1.421812273681451E-1,1.507055997382225E-1,1.596571134460576E-1,1.6903588979159867E-1,1.788401820588379E-1,1.8906639313092E-1,1.9970910708317124E-1,2.107611339107358E-1,2.222135664466941E-1,2.3405584844374883E-1,2.4627585272729013E-1,2.5885996827979607E-1,2.717931950854604E-1,2.85059245548851E-1,2.986406513012232E-1,3.1251887422205793E-1,3.266744205297465E-1,3.410869568332757E-1,3.557354270845099E-1,3.705981694271685E-1,3.856530320021061E-1,4.0087748683798896E-1,4.1624874103031884E-1,4.31743844488784E-1,4.473397936120236E-1,4.630136303287298E-1,4.787425360236952E-1,4.9450391994600684E-1,5.102755017731573E-1,5.260353880787676E-1,5.417621425221688E-1,5.574348496448893E-1,5.730331722215354E-1,5.885374021705485E-1],[9.396545171472592E-3,8.932262558255744E-3,8.274832803439214E-3,7.614436929297308E-3,7.039772179309511E-3,6.581254089288446E-3,6.232069830745757E-3,5.950633351090362E-3,5.595698164309937E-3,5.422064986058128E-3,5.3856673482908235E-3,5.448093359401551E-3,5.576569362547135E-3,5.743809844790615E-3,5.927750394786768E-3,6.111182940084947E-3,6.281314059970233E-3,6.429267856548404E-3,6.5495547048266545E-3,6.639526257314898E-3,6.698835446229623E-3,6.728918027410047E-3,6.732509582293322E-3,6.713208984847174E-3,6.675096297912297E-3,6.622410030746373E-3,6.559285796929659E-3,6.4895557716282415E-3,6.416606049592044E-3,6.343287115707863E-3,6.271871197973566E-3,6.204049292334091E-3,6.140960120190719E-3,6.083243171611796E-3,6.031108252279482E-3,5.98441452874332E-3,5.942752885188307E-3,5.905526392106286E-3,5.872024770250728E-3,5.84148984339139E-3,5.813170049668859E-3,5.786363072726508E-3,5.76044652059271E-3,5.734897295228358E-3,5.709300843596221E-3,5.683351858372543E-3,5.656848209598997E-3,5.629679952564359E-3,5.60181519345726E-3,5.57328442855054E-3,5.544164732741663E-3,5.514564887351581E-3,5.4846122317229185E-3,5.454441722177572E-3,5.42418740491335E-3,5.393976271637735E-3,5.363924278327437E-3,5.334134173704763E-3,5.304694705718704E-3,5.275680748191736E-3,5.247153909566427E-3,5.219163242561553E-3,5.191745757394117E-3,5.1649265412554435E-3,5.138718392489361E-3,5.113120979726271E-3,5.088119626024623E-3,5.063683889437676E-3,5.039766160208625E-3,5.016300518769334E-3,4.993202097809291E-3,4.970367167587142E-3,4.9476741196069485E-3,4.9249854641870705E-3,4.902150887435619E-3,4.879011338292383E-3,4.855404041955724E-3,4.831168267443564E-3,4.8061516184964015E-3,4.7802165721531065E-3,4.753246960564672E-3,4.72515408031382E-3,4.695882119966299E-3,4.66541261998521E-3,4.633767717794446E-3,4.601011982197756E-3,4.567252702508462E-3,4.532638565205027E-3,4.497356721147483E-3,4.461628315821642E-3,4.425702620467931E-3,4.389849960319214E-3,4.3543536851560205E-3,4.319501465074094E-3,4.285576219591025E-3,4.252847000351445E-3,4.221560146825398E-3,4.19193102107529E-3,4.164136603049817E-3,4.138309193434941E-3,4.1145314286934465E-3,4.092832764582277E-3,4.073187532293576E-3,4.055514617579803E-3,4.039678759806042E-3,4.025493416792925E-3,4.012725094177938E-3,4.001098996274877E-3,3.9903058201338215E-3,3.980009486489022E-3,3.969855580990944E-3,3.959480266700233E-3,3.94851942418839E-3,3.936617778292906E-3,3.9234377801187215E-3,3.908668028396622E-3,3.8920310349968013E-3,3.8732901641980177E-3,3.852255603266519E-3,3.8287892519215383E-3,3.8028084494032832E-3,3.7742884891170947E-3,3.743263901409777E-3,3.7098285141097254E-3,3.67413432744923E-3,3.636389264316975E-3,3.5968538780816184E-3,3.555837118190297E-3]],"full":[[-1.380838286046293E-3,-1.3848891583638778E-3,-1.383259980509477E-3,-1.3649820560728276E-3,-1.3179739249842282E-3,-1.2289268235705642E-3,-1.0833109117602824E-3,-8.654907383724986E-4,-5.308189304598088E-4,-2.6506889326305405E-4,-7.089223258116562E-5,4.984296576204805E-5,9.610728500630827E-5,6.775628700972369E-5,-3.443314407958198E-5,-2.0873744631511038E-4,-4.5247290636019066E-4,-7.61994809660882E-4,-1.1327097825171162E-3,-1.5591017007072772E-3,-2.0347713289585734E-3,-2.552489631195032E-3,-3.1042644571701583E-3,-3.6814200705155287E-3,-4.274688741217725E-3,-4.874313386512785E-3,-5.470160013129277E-3,-6.051838495831685E-3,-6.608830026821E-3,-7.1306193930840145E-3,-7.606830088080052E-3,-8.027360144790219E-3,-8.382516492531966E-3,-8.663145592874066E-3,-8.860758103077515E-3,-8.96764534990524E-3,-8.97698547320358E-3,-8.882937217148168E-3,-8.680719506116485E-3,-8.366675139998225E-3,-7.938317177312637E-3,-7.394356839942162E-3,-6.734712066207571E-3,-5.9604961540955514E-3,-5.073986267915664E-3,-4.078571923257446E-3,-2.978683910394686E-3,-1.779704458269915E-3,-4.878597735569201E-4,8.899035949894163E-4,2.3460568235482704E-3,3.872639303768022E-3,5.461419318328442E-3,7.1040624707645605E-3,8.79230528885211E-3,1.0518131315846002E-2,1.227394694614814E-2,1.4052754252170008E-2,1.5848318087466673E-2,1.7655324836500785E-2,1.946953031194898E-2,2.1287894473020597E-2,2.3108700849717723E-2,2.493165880340431E-2,2.6757987028945385E-2,2.859047700215811E-2,3.0433535392925037E-2,3.229320479259146E-2,3.417716243849944E-2,3.6094696952086336E-2,3.805666343454028E-2,4.0075417579353845E-2,4.216472975942964E-2,4.4339680322774244E-2,4.6616537581049444E-2,4.9012620195929335E-2,5.1546145856505965E-2,5.423606829462013E-2,5.710190480282229E-2,6.016355650086924E-2,6.344112364125754E-2,6.695471825315569E-2,7.07242763983923E-2,7.47693722547692E-2,7.910903615348064E-2,8.376157858132449E-2,8.874442201811239E-2,9.407394231839006E-2,9.976532116807557E-2,1.0583241095433116E-1,1.1228761318481117E-1,1.1914177138398085E-1,1.2640407918285446E-1,1.3408200410793714E-1,1.421812273681451E-1,1.507055997382225E-1,1.596571134460576E-1,1.6903588979159867E-1,1.788401820588379E-1,1.8906639313092E-1,1.9970910708317124E-1,2.107611339107358E-1,2.222135664466941E-1,2.3405584844374883E-1,2.4627585272729013E-1,2.5885996827979607E-1,2.717931950854604E-1,2.85059245548851E-1,2.986406513012232E-1,3.1251887422205793E-1,3.266744205297465E-1,3.410869568332757E-1,3.557354270845099E-1,3.705981694271685E-1,3.856530320021061E-1,4.0087748683798896E-1,4.1624874103031884E-1,4.31743844488784E-1,4.473397936120236E-1,4.630136303287298E-1,4.787425360236952E-1,4.9450391994600684E-1,5.102755017731573E-1,5.260353880787676E-1,5.417621425221688E-1,5.574348496448893E-1,5.730331722215354E-1,5.885374021705485E-1],[9.396545171472592E-3,8.932262558256188E-3,8.274832803438992E-3,7.61443692929753E-3,7.039772179309511E-3,6.581254089288224E-3,6.232069830745646E-3,5.950633351090029E-3,5.595698164310159E-3,5.422064986058239E-3,5.3856673482907125E-3,5.448093359401107E-3,5.576569362547246E-3,5.743809844789727E-3,5.927750394786435E-3,6.111182940084947E-3,6.281314059970122E-3,6.429267856548293E-3,6.54955470482721E-3,6.639526257314676E-3,6.69883544622929E-3,6.728918027410158E-3,6.732509582292989E-3,6.713208984847285E-3,6.6750962979128525E-3,6.622410030746262E-3,6.559285796929326E-3,6.489555771628797E-3,6.416606049592155E-3,6.343287115707863E-3,6.271871197973677E-3,6.204049292334646E-3,6.140960120189609E-3,6.083243171612129E-3,6.031108252279593E-3,5.984414528743542E-3,5.942752885187863E-3,5.905526392104732E-3,5.872024770250728E-3,5.841489843391612E-3,5.813170049669192E-3,5.786363072727396E-3,5.760446520593487E-3,5.734897295227914E-3,5.709300843596776E-3,5.683351858372432E-3,5.656848209598997E-3,5.629679952563915E-3,5.60181519345726E-3,5.573284428549763E-3,5.544164732742218E-3,5.514564887351692E-3,5.484612231722696E-3,5.454441722177461E-3,5.424187404913461E-3,5.393976271637069E-3,5.363924278327437E-3,5.334134173705318E-3,5.304694705718815E-3,5.275680748191736E-3,5.247153909566427E-3,5.21916324256122E-3,5.191745757394006E-3,5.164926541255888E-3,5.138718392489472E-3,5.113120979725938E-3,5.088119626024512E-3,5.06368388943812E-3,5.039766160208625E-3,5.016300518769223E-3,4.9932020978088465E-3,4.970367167587253E-3,4.947674119607726E-3,4.9249854641867374E-3,4.902150887435619E-3,4.879011338292716E-3,4.855404041955391E-3,4.831168267443009E-3,4.8061516184964015E-3,4.7802165721529954E-3,4.75324696056556E-3,4.72515408031382E-3,4.695882119966188E-3,4.665412619984988E-3,4.633767717794224E-3,4.601011982197867E-3,4.567252702508573E-3,4.532638565204805E-3,4.497356721147483E-3,4.46162831582142E-3,4.4257026204674865E-3,4.389849960319103E-3,4.3543536851559095E-3,4.319501465074427E-3,4.285576219590914E-3,4.252847000351778E-3,4.221560146825731E-3,4.191931021075179E-3,4.164136603049706E-3,4.1383091934352745E-3,4.1145314286933354E-3,4.09283276458261E-3,4.073187532293243E-3,4.055514617579803E-3,4.039678759805931E-3,4.025493416793258E-3,4.01272509417816E-3,4.001098996274766E-3,3.9903058201335995E-3,3.980009486489133E-3,3.969855580990611E-3,3.959480266700122E-3,3.948519424188501E-3,3.936617778292795E-3,3.923437780118388E-3,3.908668028396511E-3,3.892031034996468E-3,3.8732901641981288E-3,3.852255603266741E-3,3.8287892519213163E-3,3.8028084494038383E-3,3.7742884891174278E-3,3.743263901409555E-3,3.7098285141092813E-3,3.674134327449119E-3,3.636389264316864E-3,3.5968538780815074E-3,3.555837118190186E-3]],"pred":[-1.380838286046293E-3,-1.3848891583638778E-3,-1.383259980509477E-3,-1.3649820560728276E-3,-1.3179739249842282E-3,-1.2289268235705642E-3,-1.0833109117602824E-3,-8.654907383724986E-4,-5.308189304598088E-4,-2.6506889326305405E-4,-7.089223258116562E-5,4.984296576204805E-5,9.610728500630827E-5,6.775628700972369E-5,-3.443314407958198E-5,-2.0873744631511038E-4,-4.5247290636019066E-4,-7.61994809660882E-4,-1.1327097825171162E-3,-1.5591017007072772E-3,-2.0347713289585734E-3,-2.552489631195032E-3,-3.1042644571701583E-3,-3.6814200705155287E-3,-4.274688741217725E-3,-4.874313386512785E-3,-5.470160013129277E-3,-6.051838495831685E-3,-6.608830026821E-3,-7.1306193930840145E-3,-7.606830088080052E-3,-8.027360144790219E-3,-8.382516492531966E-3,-8.663145592874066E-3,-8.860758103077515E-3,-8.96764534990524E-3,-8.97698547320358E-3,-8.882937217148168E-3,-8.680719506116485E-3,-8.366675139998225E-3,-7.938317177312637E-3,-7.394356839942162E-3,-6.734712066207571E-3,-5.9604961540955514E-3,-5.073986267915664E-3,-4.078571923257446E-3,-2.978683910394686E-3,-1.779704458269915E-3,-4.878597735569201E-4,8.899035949894163E-4,2.3460568235482704E-3,3.872639303768022E-3,5.461419318328442E-3,7.1040624707645605E-3,8.79230528885211E-3,1.0518131315846002E-2,1.227394694614814E-2,1.4052754252170008E-2,1.5848318087466673E-2,1.7655324836500785E-2,1.946953031194898E-2,2.1287894473020597E-2,2.3108700849717723E-2,2.493165880340431E-2,2.6757987028945385E-2,2.859047700215811E-2,3.0433535392925037E-2,3.229320479259146E-2,3.417716243849944E-2,3.6094696952086336E-2,3.805666343454028E-2,4.0075417579353845E-2,4.216472975942964E-2,4.4339680322774244E-2,4.6616537581049444E-2,4.9012620195929335E-2,5.1546145856505965E-2,5.423606829462013E-2,5.710190480282229E-2,6.016355650086924E-2,6.344112364125754E-2,6.695471825315569E-2,7.07242763983923E-2,7.47693722547692E-2,7.910903615348064E-2,8.376157858132449E-2,8.874442201811239E-2,9.407394231839006E-2,9.976532116807557E-2,1.0583241095433116E-1,1.1228761318481117E-1,1.1914177138398085E-1,1.2640407918285446E-1,1.3408200410793714E-1,1.421812273681451E-1,1.507055997382225E-1,1.596571134460576E-1,1.6903588979159867E-1,1.788401820588379E-1,1.8906639313092E-1,1.9970910708317124E-1,2.107611339107358E-1,2.222135664466941E-1,2.3405584844374883E-1,2.4627585272729013E-1,2.5885996827979607E-1,2.717931950854604E-1,2.85059245548851E-1,2.986406513012232E-1,3.1251887422205793E-1,3.266744205297465E-1,3.410869568332757E-1,3.557354270845099E-1,3.705981694271685E-1,3.856530320021061E-1,4.0087748683798896E-1,4.1624874103031884E-1,4.31743844488784E-1,4.473397936120236E-1,4.630136303287298E-1,4.787425360236952E-1,4.9450391994600684E-1,5.102755017731573E-1,5.260353880787676E-1,5.417621425221688E-1,5.574348496448893E-1,5.730331722215354E-1,5.885374021705485E-1]} diff --git a/examples/gpflow_reference/comment.txt b/examples/gpflow_reference/comment.txt deleted file mode 100644 index 5da830fb..00000000 --- a/examples/gpflow_reference/comment.txt +++ /dev/null @@ -1,15 +0,0 @@ -Comments about configuration parameters. - -General Parameters - - "train_in_file": file path containing training control inputs, - "train_out_file": file path containing training outputs, - "test_in_file": file path containing test control inputs, - "test_out_file": file path containing test outputs, - "START": Starting number of training samples, - "END": End number of training samples, - "STEP": Increment of training samples, - "N_CORES": Number of cores to use for computation, - "N_TEST": Number of test samples, - "N_REG": Number of regressors, - "LOOP": Number of iterations to be performed for each number of training samples, - "PRECISION": Set floating-point type used by gpflow \ No newline at end of file diff --git a/examples/gpflow_reference/config.json b/examples/gpflow_reference/config.json index c1137a0b..827c0ce1 100644 --- a/examples/gpflow_reference/config.json +++ b/examples/gpflow_reference/config.json @@ -1,16 +1,17 @@ { - "train_in_file": "../../data/data_1024/training_input.txt", - "train_out_file": "../../data/data_1024/training_output.txt", - "test_in_file": "../../data/data_1024/test_input.txt", - "test_out_file": "../../data/data_1024/test_output.txt", - "START": 512, - "END": 1024, + "TRAIN_IN_FILE": "../../data/data_1024/training_input.txt", + "TRAIN_OUT_FILE": "../../data/data_1024/training_output.txt", + "TEST_IN_FILE": "../../data/data_1024/test_input.txt", + "TEST_OUT_FILE": "../../data/data_1024/test_output.txt", + "TRAIN_SIZE_START": 512, + "TRAIN_SIZE_END": 1024, "STEP": 2, "START_CORES": 1, - "N_CORES": 4, - "N_TEST": 1024, + "END_CORES": 4, + "TEST_SIZE": 1024, + "SCALE_TEST_WITH_TRAIN": true, "N_REG": 8, - "LOOP": 2, "PRECISION": "float64", - "OPT_ITER": 1 + "OPT_ITER": 1, + "LOOP": 2 } diff --git a/examples/gpflow_reference/execute.py b/examples/gpflow_reference/execute.py index d2cc1cf5..7e5b8f90 100644 --- a/examples/gpflow_reference/execute.py +++ b/examples/gpflow_reference/execute.py @@ -1,23 +1,32 @@ +''' +Reference implementation for Gaussian process regression using GPflow. +''' + +# Imports import argparse +import gc import logging import os import time - -import gpflow import numpy as np -import tensorflow as tf -import tensorflow.python.util._pywrap_util_port as tf_util - from config import get_config -from gpflow_logger import setup_logging from utils import ( init_model, load_data, optimize_model, predict, + predict_with_full_cov, predict_with_var, ) +import tensorflow as tf +import tensorflow.python.util._pywrap_util_port as tf_util +from tensorflow.python.eager import context +import gpflow +from gpflow_logger import setup_logging +# Global definitions +logger = logging.getLogger() +log_filename = "./gpflow_logs.log" parser = argparse.ArgumentParser() parser.add_argument( "--use-gpu", @@ -26,43 +35,49 @@ ) args = parser.parse_args() +# Environment variables if not args.use_gpu: os.environ["CUDA_VISIBLE_DEVICES"] = "" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" +os.environ["TF_OVERRIDE_GLOBAL_THREADPOOL"] = "1" -logger = logging.getLogger() -log_filename = "./gpflow_logs.log" +def sync_if_needed(is_cuda_gpu): + if is_cuda_gpu: + tf.test.experimental.sync_devices() -def gpflow_run(target, config, output_file, size_train, l, cores): + +def gpflow_run(target, is_cuda_gpu, config, output_file, size_train, size_test, \ + loop_index, cores, is_warmup=False): """ Run the GPflow regression pipeline. Args: - target (str): String of target (cpu/gpu) for logs. - config (dict): Configuration parameters for the pipeline. + target (str): String of target (cpu/gpu) for logs. + is_cuda_gpu (bool): Whether CUDA GPU is being used or not. + config (dict): Configuration parameters for the pipeline. output_csv_obj (csv.writer): CSV writer object for writing output data. - size_train (int): Size of the training dataset. - l (int): Loop index. - - Returns: - None + size_train (int): Size of the training dataset. + size_test (int): Size of the test dataset. + loop_index (int): Index for the current loop iteration. + cores (int): Number of CPU cores to use. + is_warmup (bool): Flag to indicate if this is a warmup run. """ - total_t = time.time() + total_t = time.perf_counter() + load_t = time.perf_counter() X_train, Y_train, X_test, Y_test = load_data( - train_in_path=config["train_in_file"], - train_out_path=config["train_out_file"], - test_in_path=config["test_in_file"], - test_out_path=config["test_out_file"], + train_in_path=config["TRAIN_IN_FILE"], + train_out_path=config["TRAIN_OUT_FILE"], + test_in_path=config["TEST_IN_FILE"], + test_out_path=config["TEST_OUT_FILE"], size_train=size_train, - size_test=config["N_TEST"], + size_test=size_test, n_regressors=config["N_REG"], ) + load_t = time.perf_counter() - load_t - # logger.info("Finished loading the data.") - - init_t = time.time() + init_t = time.perf_counter() model = init_model( X_train, Y_train, @@ -71,37 +86,49 @@ def gpflow_run(target, config, output_file, size_train, l, cores): noise_var=0.1, params_summary=False, ) - init_t = time.time() - init_t + init_t = time.perf_counter() - init_t opti_t = time.perf_counter() optimize_model(model, training_iter=config["OPT_ITER"]) + sync_if_needed(is_cuda_gpu) opti_t = time.perf_counter() - opti_t - # logger.info("Finished optimization.") - pred_var_t = time.time() + pred_full_t = time.perf_counter() + f_pred_full, f_var_full = predict_with_full_cov(model, X_test) + sync_if_needed(is_cuda_gpu) + pred_full_t = time.perf_counter() - pred_full_t + + pred_var_t = time.perf_counter() f_pred, f_var = predict_with_var(model, X_test) - pred_var_t = time.time() - pred_var_t - # logger.info("Finished making predictions.") + sync_if_needed(is_cuda_gpu) + pred_var_t = time.perf_counter() - pred_var_t - pred_t = time.time() + pred_t = time.perf_counter() f_pred = predict(model, X_test) - pred_t = time.time() - pred_t - # logger.info("Finished making predictions.") + sync_if_needed(is_cuda_gpu) + pred_t = time.perf_counter() - pred_t - TOTAL_TIME = time.time() - total_t + TOTAL_TIME = time.perf_counter() - total_t + LOAD_TIME = load_t INIT_TIME = init_t OPT_TIME = opti_t + PRED_FULL_TIME = pred_full_t PRED_UNCER_TIME = pred_var_t PREDICTION_TIME = pred_t - # ERROR = calculate_error(Y_test, y_pred).detach().cpu().numpy() - row_data = f"{target},{cores},{size_train},{config['N_TEST']},{config['N_REG']},{config['OPT_ITER']},{TOTAL_TIME},{INIT_TIME},{OPT_TIME},{PRED_UNCER_TIME},{PREDICTION_TIME},{l}\n" - output_file.write(row_data) + if not is_warmup: - logger.info( - f"{target},{cores},{size_train},{config['N_TEST']},{config['N_REG']},{config['OPT_ITER']},{TOTAL_TIME},{INIT_TIME},{OPT_TIME},{PRED_UNCER_TIME},{PREDICTION_TIME},{l}" - ) - # logger.info("Completed iteration.") + row_data = \ + f"{target},{cores},{size_train},{size_test},{config['N_REG']},"\ + f"{config['OPT_ITER']},{TOTAL_TIME},{LOAD_TIME},{INIT_TIME},{OPT_TIME},"\ + f"{PRED_FULL_TIME},{PRED_UNCER_TIME},{PREDICTION_TIME},{loop_index}\n" + output_file.write(row_data) + + logger.info( + f"{target},{cores},{size_train},{size_test},{config['N_REG']},"\ + f"{config['OPT_ITER']},{TOTAL_TIME},{LOAD_TIME},{INIT_TIME},{OPT_TIME},"\ + f"{PRED_FULL_TIME},{PRED_UNCER_TIME},{PREDICTION_TIME},{loop_index}" + ) def execute(): @@ -115,59 +142,90 @@ def execute(): - Iterate through different training sizes and for each training size loop for a specified amount of times while executing `gpflow_run` function. """ - setup_logging(log_filename, True, logger) - # Check if TensorFlow is using GPU - physical_devices = tf.config.list_physical_devices("GPU") - if len(physical_devices) > 0: - logger.info(f"GPUs available: {physical_devices}") - target = "gpu" + # Init + config = get_config() + if config["PRECISION"] == "float32": + gpflow.config.set_default_float(np.float32) + else: + gpflow.config.set_default_float(np.float64) + test_scale_factor = config["STEP"] if config["SCALE_TEST_WITH_TRAIN"] else 1 + + # Check whether TensorFlow is using GPU + is_cuda_gpu = False + gpu_devices = tf.config.list_physical_devices("GPU") + for gpu in gpu_devices: + tf.config.experimental.set_memory_growth(gpu, True) + xpu_devices = tf.config.list_physical_devices("XPU") + if gpu_devices: + logger.info(f"GPUs available: {gpu_devices}") + details = tf.config.experimental.get_device_details(gpu_devices[0]) + target = details['device_name'] + is_cuda_gpu = True + elif xpu_devices: + logger.info(f"XPUs available: {xpu_devices}") + target = "xpu" else: - logger.info("No GPUs found. Using CPU.") + logger.info("No GPUs/XPUs found. Using CPU.") target = "cpu" - # logger.info("\n") - # logger.info("-" * 40) - # logger.info("Load config file.") - config = get_config() - + # Output CSV file setup file_path = "./output.csv" file_exists = os.path.isfile(file_path) with open(file_path, "a") as output_file: + + # If CSV file non-existent or empty, create/write header if not file_exists or os.stat(file_path).st_size == 0: - # logger.info("Write output file header") logger.info( - "Target,Cores,N_train,N_test,N_reg,Opt_iter,Total_time,Init_time,Opt_Time,Pred_Var_time,Pred_time,N_loop" + "Target,Cores,N_train,N_test,N_regressor,Opt_iter,Total_time,Load_time,"\ + "Init_time,Opt_Time,Pred_Full_time,Pred_Uncer_time,Predict_time,N_loop" ) - header = "Target,Cores,N_train,N_test,N_regressor,Opt_iter,Total_time,Init_time,Opt_time,Pred_Uncer_time,Predict_time,N_loop\n" + header = \ + "Target,Cores,N_train,N_test,N_regressor,Opt_iter,Total_time,Load_time,"\ + "Init_time,Opt_Time,Pred_Full_time,Pred_Uncer_time,Predict_time,N_loop\n" output_file.write(header) - if config["PRECISION"] == "float32": - gpflow.config.set_default_float(np.float32) - else: - gpflow.config.set_default_float(np.float64) + gpflow_run(target, is_cuda_gpu, config, output_file, config["TRAIN_SIZE_END"], \ + config["TRAIN_SIZE_END"],0, config["END_CORES"], is_warmup=True) - # runs tests on exponentially increasing number of cores and - # data size, for multiple loops (each loop starts with *s) - tf.config.threading.set_intra_op_parallelism_threads(config["N_CORES"]) - tf.config.threading.set_inter_op_parallelism_threads(config["N_CORES"]) cores = config["START_CORES"] - while cores <= config["N_CORES"]: - data_size = config["START"] - while data_size <= config["END"]: - for l in range(config["LOOP"]): + + while cores <= config["END_CORES"]: + + data_size = config["TRAIN_SIZE_START"] + test_size = config["TEST_SIZE"] if not config["SCALE_TEST_WITH_TRAIN"] \ + else config["TRAIN_SIZE_START"] + + context._reset_context() + tf.config.threading.set_intra_op_parallelism_threads(cores) + tf.config.threading.set_inter_op_parallelism_threads(1) + + while data_size <= config["TRAIN_SIZE_END"]: + + for loop_index in range(config["LOOP"]): + logger.info("*" * 40) - logger.info(f"Core: {cores}, Train Size: {data_size}, Loop: {l}") - gpflow_run(target,config, output_file, data_size, l, cores) + gc.collect() + gpflow_run( + target, is_cuda_gpu, config, output_file, data_size,\ + test_size,loop_index, cores + ) + + # Update sizes data_size = data_size * config["STEP"] + test_size = test_size * test_scale_factor + cores = cores * 2 + logger.info("Completed the program.") + def is_mkl_enabled(): return tf_util.IsMklEnabled() + if __name__ == "__main__": - # check if Intel oneAPI MKL is enabled + setup_logging(log_filename, True, logger) print("","-" * 18, "\n", "MKL enabled:", is_mkl_enabled(), "\n", "-" * 18) execute() diff --git a/examples/gpflow_reference/gpflow_mkl.patch b/examples/gpflow_reference/gpflow_mkl.patch deleted file mode 100644 index 92f373eb..00000000 --- a/examples/gpflow_reference/gpflow_mkl.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/setup.py b/setup.py -index c2d65897..794fb4fa 100644 ---- a/setup.py -+++ b/setup.py -@@ -17,7 +17,7 @@ requirements = [ - "setuptools>=41.0.0", # to satisfy dependency constraints - "tabulate", - "tensorflow-probability[tf]>=0.12.0", -- "tensorflow>=2.4.0; platform_system!='Darwin' or platform_machine!='arm64'", -+ "intel-tensorflow>=2.4.0; platform_system!='Darwin' or platform_machine!='arm64'", - # NOTE: Support of Apple Silicon MacOS platforms is in an experimental mode - "tensorflow-macos>=2.4.0; platform_system=='Darwin' and platform_machine=='arm64'", - # NOTE: once we require tensorflow-probability>=0.12, we can remove our custom deepcopy handling diff --git a/examples/gpflow_reference/requirements/requirements_gpflow_amd.txt b/examples/gpflow_reference/requirements/requirements_gpflow_amd.txt new file mode 100644 index 00000000..2b2ff42f --- /dev/null +++ b/examples/gpflow_reference/requirements/requirements_gpflow_amd.txt @@ -0,0 +1,50 @@ +absl-py==2.4.0 +astunparse==1.6.3 +attrs==25.4.0 +certifi==2026.2.25 +charset-normalizer==3.4.5 +check-shapes==1.1.1 +cloudpickle==3.1.2 +decorator==5.2.1 +Deprecated==1.3.1 +dm-tree==0.1.9 +dropstackframe==0.1.1 +flatbuffers==25.12.19 +gast==0.7.0 +google-pasta==0.2.0 +gpflow==2.9.2 +grpcio==1.78.0 +h5py==3.16.0 +idna==3.11 +keras==3.12.1 +lark==1.3.1 +libclang==18.1.1 +Markdown==3.10.2 +markdown-it-py==4.0.0 +MarkupSafe==3.0.3 +mdurl==0.1.2 +ml-dtypes==0.3.1 +multipledispatch==1.0.0 +namex==0.1.0 +numpy==1.26.4 +opt_einsum==3.4.0 +optree==0.19.0 +packaging==26.0 +protobuf==4.25.8 +Pygments==2.19.2 +requests==2.32.5 +rich==14.3.3 +scipy==1.15.3 +six==1.17.0 +tabulate==0.10.0 +tensorboard==2.17.0 +tensorboard-data-server==0.7.2 +tensorflow-io-gcs-filesystem==0.37.1 +tensorflow-probability==0.24.0 +tensorflow-rocm==2.17.1 +termcolor==3.3.0 +tf_keras==2.17.0 +typing_extensions==4.15.0 +urllib3==2.6.3 +Werkzeug==3.1.6 +wrapt==2.1.2 diff --git a/examples/gpflow_reference/requirements/requirements_gpflow_cpu.txt b/examples/gpflow_reference/requirements/requirements_gpflow_cpu.txt new file mode 100644 index 00000000..b7bcb370 --- /dev/null +++ b/examples/gpflow_reference/requirements/requirements_gpflow_cpu.txt @@ -0,0 +1,44 @@ +absl-py==2.4.0 +astunparse==1.6.3 +attrs==26.1.0 +certifi==2026.2.25 +charset-normalizer==3.4.6 +check-shapes==1.1.1 +cloudpickle==3.1.2 +decorator==5.2.1 +Deprecated==1.3.1 +dm-tree==0.1.9 +dropstackframe==0.1.1 +flatbuffers==25.12.19 +gast==0.7.0 +google-pasta==0.2.0 +gpflow==2.9.2 +grpcio==1.80.0 +h5py==3.14.0 +idna==3.11 +keras==3.12.1 +lark==1.3.1 +libclang==18.1.1 +markdown-it-py==4.0.0 +mdurl==0.1.2 +ml_dtypes==0.5.4 +multipledispatch==1.0.0 +namex==0.1.0 +numpy==2.2.6 +opt_einsum==3.4.0 +optree==0.19.0 +packaging==26.0 +protobuf==7.34.1 +Pygments==2.20.0 +requests==2.33.1 +rich==14.3.3 +scipy==1.15.3 +six==1.17.0 +tabulate==0.10.0 +tensorflow==2.21.0 +tensorflow-probability==0.25.0 +termcolor==3.3.0 +tf_keras==2.21.0 +typing_extensions==4.15.0 +urllib3==2.6.3 +wrapt==2.1.2 diff --git a/examples/gpflow_reference/requirements_gpu.txt b/examples/gpflow_reference/requirements/requirements_gpflow_gpu.txt similarity index 100% rename from examples/gpflow_reference/requirements_gpu.txt rename to examples/gpflow_reference/requirements/requirements_gpflow_gpu.txt diff --git a/examples/gpflow_reference/requirements/requirements_gpflow_intel.txt b/examples/gpflow_reference/requirements/requirements_gpflow_intel.txt new file mode 100644 index 00000000..af86f065 --- /dev/null +++ b/examples/gpflow_reference/requirements/requirements_gpflow_intel.txt @@ -0,0 +1,61 @@ +absl-py==1.4.0 +astunparse==1.6.3 +attrs==25.4.0 +certifi==2026.2.25 +cffi==2.0.0 +charset-normalizer==3.4.5 +check-shapes==1.1.1 +cloudpickle==3.1.2 +cryptography==46.0.5 +decorator==5.2.1 +Deprecated==1.3.1 +dm-tree==0.1.9 +dropstackframe==0.1.1 +flatbuffers==25.12.19 +gast==0.7.0 +google-auth==2.49.1 +google-auth-oauthlib==1.3.0 +google-pasta==0.2.0 +gpflow==2.10.0 +grpcio==1.78.0 +h5py==3.14.0 +idna==3.11 +intel_extension_for_tensorflow==2.15.0.2 +intel_extension_for_tensorflow_lib==2.15.0.2.2 +keras==2.15.0 +lark==1.3.1 +libclang==18.1.1 +Markdown==3.10.2 +markdown-it-py==4.0.0 +MarkupSafe==3.0.3 +mdurl==0.1.2 +ml-dtypes==0.3.2 +multipledispatch==1.0.0 +namex==0.1.0 +numpy==1.26.4 +oauthlib==3.3.1 +opt_einsum==3.4.0 +optree==0.19.0 +packaging==26.0 +protobuf==4.23.4 +pyasn1==0.6.2 +pyasn1_modules==0.4.2 +pycparser==3.0 +Pygments==2.19.2 +requests==2.32.5 +requests-oauthlib==2.0.0 +rich==14.3.3 +scipy==1.15.3 +six==1.17.0 +tabulate==0.10.0 +tensorboard==2.15.2 +tensorboard-data-server==0.7.2 +tensorflow==2.15.1 +tensorflow-estimator==2.15.0 +tensorflow-io-gcs-filesystem==0.37.1 +tensorflow-probability==0.23.0 +termcolor==3.3.0 +typing_extensions==4.15.0 +urllib3==2.6.3 +Werkzeug==3.1.6 +wrapt==1.14.2 diff --git a/examples/gpflow_reference/requirements/requirements_gpflow_nvidia.txt b/examples/gpflow_reference/requirements/requirements_gpflow_nvidia.txt new file mode 100644 index 00000000..55cdb6f8 --- /dev/null +++ b/examples/gpflow_reference/requirements/requirements_gpflow_nvidia.txt @@ -0,0 +1,56 @@ +absl-py==2.4.0 +astunparse==1.6.3 +attrs==26.1.0 +certifi==2026.5.20 +charset-normalizer==3.4.7 +check-shapes==1.1.1 +cloudpickle==3.1.2 +decorator==5.3.1 +Deprecated==1.3.1 +dm-tree==0.1.10 +dropstackframe==0.1.1 +flatbuffers==25.12.19 +gast==0.7.0 +google-pasta==0.2.0 +gpflow==2.9.2 +grpcio==1.80.0 +h5py==3.14.0 +idna==3.16 +keras==3.12.2 +lark==1.3.1 +libclang==18.1.1 +markdown-it-py==4.2.0 +mdurl==0.1.2 +ml_dtypes==0.5.4 +multipledispatch==1.0.0 +namex==0.1.0 +numpy==2.2.6 +nvidia-cublas-cu12==12.9.2.10 +nvidia-cuda-cupti-cu12==12.9.79 +nvidia-cuda-nvcc-cu12==12.9.86 +nvidia-cuda-nvrtc-cu12==12.9.86 +nvidia-cuda-runtime-cu12==12.9.79 +nvidia-cudnn-cu12==9.22.0.52 +nvidia-cufft-cu12==11.4.1.4 +nvidia-curand-cu12==10.3.10.19 +nvidia-cusolver-cu12==11.7.5.82 +nvidia-cusparse-cu12==12.5.10.65 +nvidia-nccl-cu12==2.30.4 +nvidia-nvjitlink-cu12==12.9.86 +opt_einsum==3.4.0 +optree==0.19.1 +packaging==26.2 +protobuf==7.35.0 +Pygments==2.20.0 +requests==2.34.2 +rich==15.0.0 +scipy==1.15.3 +six==1.17.0 +tabulate==0.10.0 +tensorflow==2.21.0 +tensorflow-probability==0.25.0 +termcolor==3.3.0 +tf_keras==2.21.0 +typing_extensions==4.15.0 +urllib3==2.7.0 +wrapt==2.2.1 diff --git a/examples/gpflow_reference/requirements_cpu.txt b/examples/gpflow_reference/requirements_cpu.txt deleted file mode 100644 index e9d8d1a6..00000000 --- a/examples/gpflow_reference/requirements_cpu.txt +++ /dev/null @@ -1,5 +0,0 @@ -intel-tensorflow==2.13.0 -numpy==1.24.3 -gast==0.4.0 -tensorflow-probability==0.21.0 -typing-extensions==4.5.0 diff --git a/examples/gpflow_reference/run_gpflow.sh b/examples/gpflow_reference/run_gpflow.sh index 9615766d..a33af4d6 100755 --- a/examples/gpflow_reference/run_gpflow.sh +++ b/examples/gpflow_reference/run_gpflow.sh @@ -1,43 +1,104 @@ #!/bin/bash # Input $1: Specify cpu/gpu/arm -if [[ "$1" == "gpu" ]] +# Input $2: Specify nvidia/amd/intel (only necessary if gpu is specified) + +if [[ "$1" == "gpu" ]] ############################################################################# then - module load cuda/12.0.1 - # Create & Activate python environment + + # Create Python environment if not present if [ ! -d "gpflow_gpu_env" ]; then - python -m venv gpflow_gpu_env + python -m venv gpflow_gpu_env --clear fi + + # Activate Python environment and take measures to avoid instant catastrophy source gpflow_gpu_env/bin/activate + python -m ensurepip --upgrade + pip install --upgrade pip + pip install setuptools==80.0.0 + # Install gpflow if not already installed if ! python -c "import gpflow"; then - pip install --no-cache-dir -r requirements_gpu.txt + + if [[ "$2" == "nvidia" ]]; then ########################################################### + + module load cuda/12.0.1 + + pip install --no-cache-dir tensorflow[and-cuda] gpflow==2.9.2 + + export XLA_FLAGS=--xla_gpu_cuda_data_dir=$CUDA_HOME + + pip freeze > requirements/requirements_gpflow_nvidia.txt + + elif [[ "$2" == "amd" ]]; then ############################################################ + + pip install --no-cache-dir tensorflow-probability[tf]==0.24.0 tensorboard==2.17 \ + ml-dtypes==0.3.1 --timeout 600 + + pip install --no-cache-dir gpflow==2.9.2 + + pip uninstall -y tensorflow tensorflow-cpu tensorflow-gpu + + pip install tensorflow-rocm==2.17.1 \ + -f https://repo.radeon.com/rocm/manylinux/rocm-rel-6.4/ + + pip freeze > requirements/requirements_gpflow_amd.txt + + elif [[ "$2" == "intel" ]]; then ########################################################## + + module load python/3.10.16 + + # Very important + source /opt/intel/oneapi/setvars.sh + + # First, let pip install GPflow and cause some havoc. We'll fix it later. + pip install --no-cache-dir gpflow tensorflow-probability~=0.23.0 + + # Whatever pip installs here is almost guaranteed to fail, so away with it. + pip uninstall -y tensorflow tensorflow-cpu tensorflow-gpu + + # Install a TensorFlow version that matches what Intel expects + pip install --no-cache-dir tensorflow==2.15.1 + + # Install Intel extensions for TensorFlow + pip install --no-cache-dir --upgrade intel-extension-for-tensorflow[xpu] + + # Install setuptools because something keeps overwriting it + pip install setuptools==78.0.0 + + pip freeze > requirements/requirements_gpflow_intel.txt + + elif [[ -z "$2" ]]; then ################################################################## + + echo "Please specify gpu type: nvidia/amd/intel" + exit 1 + + fi ######################################################################################## + fi - # Run on GPU - export XLA_FLAGS=--xla_gpu_cuda_data_dir=$CUDA_HOME + python execute.py --use-gpu + elif [[ "$1" == "cpu" ]] then - module load python/3.10.16 + # Create & Activate python environment if [ ! -d "gpflow_cpu_env" ]; then python -m venv gpflow_cpu_env fi source gpflow_cpu_env/bin/activate + # Install gpflow if not already installed - if ! python -c "import gpflow"; then - pip install --no-cache-dir -r requirements_cpu.txt - # manually install GPflow - git clone https://github.com/GPflow/GPflow.git - cd GPflow - git checkout v2.10.0 - git apply ../gpflow_mkl.patch - pip install -e . - cd .. - fi - # Run on CPU - python execute.py + pip install --no-cache-dir tensorflow gpflow==2.9.2 + pip freeze > requirements/requirements_gpflow_cpu.txt + + end_cores=$(python3 -c "import json; print(json.load(open('config.json'))['END_CORES'])") + core_count=$((end_cores * 2)) + + taskset -c 0-$core_count:2 python execute.py + elif [[ "$1" == "arm" ]] then + spack load python@3.10 # Create & Activate python environment if [ ! -d "gpflow_arm_env" ]; then @@ -46,11 +107,14 @@ then source gpflow_arm_env/bin/activate # Install gpflow if not already installed if ! python -c "import gpflow"; then - pip install --no-cache-dir -r requirements_gpu.txt + pip install --no-cache-dir -r requirements/requirements_gpflow_gpu.txt fi # Run on ARM python execute.py + else + echo "Please specify input parameter: cpu/gpu/arm" exit 1 + fi diff --git a/examples/gpflow_reference/utils.py b/examples/gpflow_reference/utils.py index 4395a1ae..02b385b4 100644 --- a/examples/gpflow_reference/utils.py +++ b/examples/gpflow_reference/utils.py @@ -132,6 +132,24 @@ def optimization_step(): return None + +def predict_with_full_cov(model, X_test): + """ + Predict latent function values and observed target values for the given test data. + + Args: + model (gpflow.models.GPModel): The trained GPflow model. + X_test (numpy.ndarray): The test input data. + + Returns: + f_pred (numpy.ndarray): Mean of latent function values for test data. + f_var_matrix (numpy.ndarray): Full covariance of latent function values for test data. + """ + f_pred, f_var_matrix = model.predict_f(X_test, full_cov=True) + + return f_pred, f_var_matrix + + def predict_with_var(model, X_test): """ Predict latent function values and observed target values for the given test data. @@ -148,6 +166,7 @@ def predict_with_var(model, X_test): return f_pred, f_var + def predict(model, X_test): """ Predict latent function values and observed target values for the given test data. diff --git a/examples/gprat_cpp/CMakeLists.txt b/examples/gprat_cpp/CMakeLists.txt index 807d5da2..a13885f5 100644 --- a/examples/gprat_cpp/CMakeLists.txt +++ b/examples/gprat_cpp/CMakeLists.txt @@ -2,26 +2,53 @@ cmake_minimum_required(VERSION 3.16) project(gprat_cpp) +# Option for GPU support with CUDA, cuSolver, cuBLAS +option(GPRAT_WITH_CUDA "Enable GPU support with CUDA, cuSolver, cuBLAS" OFF) +option(GPRAT_WITH_SYCL "Enable SYCL support with oneMath" OFF) + +# Pass variable to C++ code +add_compile_definitions(GPRAT_WITH_CUDA=$ + GPRAT_WITH_SYCL=$) + # This project can be built as part of GPRat itself or as a standalone project # in which case below find_package() call is used. if(TARGET GPRat::core) + message("Using in-tree GPRat::core") + else() + message("Using out-of-tree GPRat::core") + find_package(GPRat REQUIRED) + + get_target_property(_gprat_defs GPRat::core INTERFACE_COMPILE_DEFINITIONS) + get_target_property(_gprat_libs GPRat::core INTERFACE_LINK_LIBRARIES) + + foreach(def ${_gprat_defs}) + if(def MATCHES "GPRAT_WITH_SYCL") + set(GPRAT_WITH_SYCL ON) + endif() + endforeach() + + foreach(lib ${_gprat_libs}) + if(lib MATCHES "ONEMATH") + set(GPRAT_WITH_SYCL ON) + endif() + endforeach() + + if(GPRAT_WITH_SYCL) + find_package(oneMath CONFIG REQUIRED) + endif() + if(USE_MKL) # Try to find Intel oneMKL set(MKL_INTERFACE_FULL "intel_lp64") set(MKL_THREADING "sequential") find_package(MKL CONFIG REQUIRED) endif() -endif() -# Enables/disables computation with CUDA on test system -option(GPRAT_WITH_CUDA - "Enable additional computation with CUDA, cuSolver, cuBLAS" OFF) -# Pass variable to C++ code -add_compile_definitions(GPRAT_WITH_CUDA=$) +endif() # Option for steps duration measurement with APEX option(GPRAT_APEX_STEPS "Enable measuring duration of steps with APEX" OFF) @@ -44,6 +71,12 @@ add_compile_definitions(GPRAT_APEX_CHOLESKY=$) # Add the executable add_executable(gprat_cpp src/execute.cpp) +# Bake in the absolute path to config.json so the binary works from any working +# directory +target_compile_definitions( + gprat_cpp + PRIVATE GPRAT_CPP_CONFIG_PATH="${CMAKE_CURRENT_SOURCE_DIR}/config.json") + target_compile_features(gprat_cpp PUBLIC cxx_std_17) # Link the libraries diff --git a/examples/gprat_cpp/config.json b/examples/gprat_cpp/config.json new file mode 100644 index 00000000..4072e451 --- /dev/null +++ b/examples/gprat_cpp/config.json @@ -0,0 +1,20 @@ +{ + "TRAIN_IN_FILE": "../../data/data_1024/training_input.txt", + "TRAIN_OUT_FILE": "../../data/data_1024/training_output.txt", + "TEST_IN_FILE": "../../data/data_1024/test_input.txt", + "TEST_OUT_FILE": "../../data/data_1024/test_output.txt", + "TRAIN_SIZE_START": 512, + "TRAIN_SIZE_END": 1024, + "STEP": 2, + "START_CORES": 1, + "END_CORES": 2, + "TEST_SIZE": 1024, + "SCALE_TEST_WITH_TRAIN": true, + "N_REG": 8, + "OPT_ITER": 1, + "LOOP": 2, + "N_TILES_START": 1, + "N_TILES_END": 2, + "STEP_TILES": 2, + "CHOLESKY": true +} diff --git a/examples/gprat_cpp/run_gprat_cpp.sh b/examples/gprat_cpp/run_gprat_cpp.sh index a2a00b42..c4a5fd7e 100755 --- a/examples/gprat_cpp/run_gprat_cpp.sh +++ b/examples/gprat_cpp/run_gprat_cpp.sh @@ -1,111 +1,359 @@ #!/bin/bash -# $1 cpu/gpu +# Input $1: Specify how GPRat was compiled, options: cpu/cuda/sycl +# Input $2: If GPRat was compiled with SYCL backend: nvidia/amd/intel -################################################################################ -set -e # Exit immediately if a command exits with a non-zero status. -#set -x # Print each command before executing it. +set -e # Exit immediately if a command exits with a non-zero status. -################################################################################ -# Configurations -################################################################################ +################################################################################################### +# Set GPU flag +################################################################################################### if [[ -z "$1" ]]; then - echo "Input parameter is missing. Using default: Run computations on CPU" -elif [[ "$1" == "gpu" ]]; then - use_gpu="--use_gpu" -elif [[ "$1" != "cpu" ]]; then - echo "Please specify input parameter: cpu/gpu" + echo "Input parameter is missing. Using default: Run computations on CPU" + use_gpu="" +elif [[ "$1" == "cuda" ]]; then + use_gpu="--use-gpu" + if [[ \ + "$HOSTNAME" != "simcl1n1" && \ + "$HOSTNAME" != "simcl1n2" && \ + "$HOSTNAME" != "simcl1n3" && \ + "$HOSTNAME" != "simcl1n4" ]]; + then + echo "GPU execution with this script is only supported on simcl1n1, simcl1n2, simcl1n3, and simcl1n4." 1>&2 + exit 1 + fi +elif [[ "$1" == "sycl" ]]; then + use_gpu="--use-gpu" + if [[ \ + "$HOSTNAME" != "simcl1n1" && \ + "$HOSTNAME" != "simcl1n2" && \ + "$HOSTNAME" != "simcl1n3" && \ + "$HOSTNAME" != "simcl1n4" ]]; + then + echo "GPU execution with this script is only supported on simcl1n1, simcl1n2, simcl1n3, and simcl1n4." 1>&2 exit 1 + fi +elif [[ "$1" != "cpu" ]]; then + echo "Please specify input parameter: cpu/cuda/sycl" + exit 1 fi -# Select BLAS library -if [[ "$2" == "mkl" ]] +################################################################################################### +# Set Spack if on simcl1n1, simcl1n2, simcl1n3, or simcl1n4 +################################################################################################### + +if [[ \ + "$HOSTNAME" == "simcl1n1" || \ + "$HOSTNAME" == "simcl1n2" || \ + "$HOSTNAME" == "simcl1n3" || \ + "$HOSTNAME" == "simcl1n4" ]]; then - USE_MKL=ON -else - USE_MKL=OFF + + spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" + source $spack_destination/spack/share/spack/setup-env.sh + fi -if command -v spack &> /dev/null; then - echo "Spack command found, checking for environments..." - # Get current hostname - HOSTNAME=$(hostname -s) - - if [[ "$HOSTNAME" == "ipvs-epyc1" ]]; then - # Check if the gprat_cpu_gcc environment exists - if spack env list | grep -q "gprat_cpu_gcc"; then - echo "Found gprat_cpu_gcc environment, activating it." - module load gcc/14.2.0 - export CXX=g++ - export CC=gcc - spack env activate gprat_cpu_gcc - GPRAT_WITH_CUDA=OFF # whether GPRAT_WITH_CUDA is ON of OFF is irrelevant for this example - GPRAT_APEX_STEPS=OFF - GPRAT_APEX_CHOLESKY=OFF - fi - elif [[ "$HOSTNAME" == "sven0" || "$HOSTNAME" == "sven1" ]]; then - #module load gcc/13.2.1 - spack load openblas arch=linux-fedora38-riscv64 - HPX_CMAKE=$HOME/git_workspace/build-scripts/build/hpx/lib64/cmake/HPX - GPRAT_WITH_CUDA=OFF - GPRAT_APEX_STEPS=OFF - GPRAT_APEX_CHOLESKY=OFF - ADD=64 - elif [[ $(uname -i) == "aarch64" ]]; then - spack load gcc@14.2.0 - # Check if the gprat_cpu_arm environment exists - if spack env list | grep -q "gprat_cpu_arm"; then - echo "Found gprat_cpu_arm environment, activating it." - spack env activate gprat_cpu_arm - fi - GPRAT_WITH_CUDA=OFF - GPRAT_APEX_STEPS=OFF - GPRAT_APEX_CHOLESKY=OFF - ADD=64 - elif [[ "$HOSTNAME" == "simcl1n1" || "$HOSTNAME" == "simcl1n2" ]]; then - # Check if the gprat_gpu_clang environment exists - if spack env list | grep -q "gprat_gpu_clang"; then - echo "Found gprat_gpu_clang environment, activating it." - module load clang/17.0.1 - export CXX=clang++ - export CC=clang - module load cuda/12.0.1 - spack env activate gprat_gpu_clang - GPRAT_WITH_CUDA=ON - GPRAT_APEX_STEPS=OFF - GPRAT_APEX_CHOLESKY=OFF - fi +################################################################################################### +# Setup environment depending on the host +################################################################################################### + +if command -v spack &>/dev/null; then + + echo "Spack command found, checking for environments..." + + HOSTNAME=$(hostname -s) + + # ipvs-epyc1 #################################################################################### + if [[ "$HOSTNAME" == "ipvs-epyc1" ]]; then + + if spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.2.0 + export CXX=g++ + export CC=gcc + fi + + # sven0 and sven1 ############################################################################### + elif [[ "$HOSTNAME" == "sven0" || "$HOSTNAME" == "sven1" ]]; then + + spack load openblas arch=linux-fedora38-riscv64 + HPX_CMAKE=$HOME/git_workspace/build-scripts/build/hpx/lib64/cmake/HPX + export LD_LIBRARY_PATH=$HOME/git_workspace/build-scripts/build/hpx/lib64:$LD_LIBRARY_PATH + export LD_LIBRARY_PATH=$HOME/git_workspace/build-scripts/build/boost/lib:$LD_LIBRARY_PATH + export LD_PRELOAD=$HOME/git_workspace/build-scripts/build/jemalloc/lib/libjemalloc.so.2 + GPRAT_LIB_SUFFIX=64 + + # aarch64 ####################################################################################### + elif [[ $(uname -i) == "aarch64" ]]; then + + spack load gcc@14.2.0 + if spack env list | grep -q "gprat_cpu_arm"; then + echo "Found gprat_cpu_arm environment, activating it." + spack env activate gprat_cpu_arm + fi + GPRAT_LIB_SUFFIX=64 + + # simcl1n1 and simcl1n2 with NVIDIA GPUs ######################################################## + elif [[ "$HOSTNAME" == "simcl1n1" || "$HOSTNAME" == "simcl1n2" ]]; then + + if [[ "$1" == "cpu" ]]; then + + if spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.1.0 + export CXX=g++ + export CC=gcc + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + else + echo "Cannot find Spack environment gprat_cpu_gcc. Please run spack-repo/environments/setup_gprat_cpu_gcc.sh" 1>&2 + exit 1 + fi + else - echo "Hostname is $HOSTNAME — no action taken." + + if spack env list | grep -q "gprat_gpu_clang"; then + echo "Found gprat_gpu_clang environment, activating it." + spack env activate gprat_gpu_clang + module load cuda/12.0.1 + module load clang/17.0.1 + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + else + echo "Cannot find Spack environment gprat_gpu_clang. Please run spack-repo/environments/setup_gprat_gpu_clang.sh" 1>&2 + exit 1 + fi + + if [[ "$1" == "cuda" ]]; then + + export CXX=clang++ + export CC=clang + + elif [[ "$1" == "sycl" ]]; then + + # Source Intel oneAPI environment if icpx is not yet in PATH + ONEAPI_COMPILER_ROOT="" + if ! command -v icpx &>/dev/null; then + ONEAPI_SETVARS="/import/sgs.scratch-simcl1/breyerml/Programs/spack/opt/spack/linux-zen4/intel-oneapi-compilers-2025.1.1-5ynklzzqslh265azbglzqdtecdghl7ob/setvars.sh" + if [[ -f "$ONEAPI_SETVARS" ]]; then + ONEAPI_COMPILER_ROOT="$(dirname $ONEAPI_SETVARS)/compiler/2025.1" + export PATH="$ONEAPI_COMPILER_ROOT/bin:$PATH" + export LD_LIBRARY_PATH="$ONEAPI_COMPILER_ROOT/lib:${LD_LIBRARY_PATH:-}" + fi + fi + + if command -v icpx &>/dev/null; then + export CXX=icpx + export CC=icx + CMAKE_PREFIX_PATH="/scratch-simcl1/grafml/Programs/oneMath_nvidia/oneMath/install/lib/cmake/oneMath:${CMAKE_PREFIX_PATH:-}" + else + echo "Intel oneAPI DPC++ compiler (icpx) not found. Please make sure that icpx is available in your PATH." 1>&2 + exit 1 + fi + + fi + fi + + # simcl1n3 with AMD GPU ######################################################################### + elif [[ "$HOSTNAME" == "simcl1n3" ]]; then + + if [[ "$1" == "cpu" ]]; then + + if spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.1.0 + export CXX=g++ + export CC=gcc + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + else + echo "Cannot find Spack environment gprat_cpu_gcc. Please run spack-repo/environments/setup_gprat_cpu_gcc.sh" 1>&2 + exit 1 + fi + + else + + if spack env list | grep -q "gprat_gpu_clang"; then + echo "Found gprat_gpu_clang environment, activating it." + spack env activate gprat_gpu_clang + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + else + echo "Cannot find Spack environment gprat_gpu_clang. Please run spack-repo/environments/setup_gprat_gpu_clang.sh" 1>&2 + exit 1 + fi + + if [[ "$1" == "sycl" ]]; then + + # Source Intel oneAPI environment if icpx is not yet in PATH + ONEAPI_COMPILER_ROOT="" + if ! command -v icpx &>/dev/null; then + ONEAPI_SETVARS="/import/sgs.scratch-simcl1/breyerml/Programs/spack/opt/spack/linux-zen4/intel-oneapi-compilers-2025.1.1-5ynklzzqslh265azbglzqdtecdghl7ob/setvars.sh" + if [[ -f "$ONEAPI_SETVARS" ]]; then + ONEAPI_COMPILER_ROOT="$(dirname $ONEAPI_SETVARS)/compiler/2025.1" + export PATH="$ONEAPI_COMPILER_ROOT/bin:$PATH" + export LD_LIBRARY_PATH="$ONEAPI_COMPILER_ROOT/lib:${LD_LIBRARY_PATH:-}" + fi + fi + if [[ -z "$ONEAPI_COMPILER_ROOT" ]] && command -v icpx &>/dev/null; then + ONEAPI_COMPILER_ROOT="$(dirname $(dirname $(which icpx)))" + export LD_LIBRARY_PATH="$ONEAPI_COMPILER_ROOT/lib:${LD_LIBRARY_PATH:-}" + fi + + # Set up ROCm/HIP environment (required for AMD GPU device libraries at link and run time) + ROCM_PATH=${ROCM_PATH:-/opt/rocm-6.4.0} + if [[ -d "$ROCM_PATH" ]]; then + export PATH="$ROCM_PATH/bin:$PATH" + export LD_LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib64:$ROCM_PATH/hip/lib:${LD_LIBRARY_PATH:-}" + export LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib64:$ROCM_PATH/hip/lib:${LIBRARY_PATH:-}" + export ROCM_PATH + fi + # Compatibility shim: libamd_comgr.so.2 → libamd_comgr.so.3 for icpx HIP adapter + COMGR_COMPAT_DIR="/data/scratch-simcl1/breyerml/Programs/.modulefiles/icpx" + if [[ -d "$COMGR_COMPAT_DIR" ]]; then + export LD_LIBRARY_PATH="$COMGR_COMPAT_DIR:${LD_LIBRARY_PATH:-}" + fi + export HSA_XNACK=1 + + if command -v icpx &>/dev/null; then + export CXX=icpx + export CC=icx + CMAKE_PREFIX_PATH="/scratch-simcl1/grafml/Programs/oneMath_amd/oneMath/install/lib/cmake/oneMath:${CMAKE_PREFIX_PATH:-}" + else + echo "Intel oneAPI DPC++ compiler (icpx) not found. Please make sure that icpx is available in your PATH." 1>&2 + exit 1 + fi + + fi + + fi + + # simcl1n4 without GPU ########################################################################## + elif [[ "$HOSTNAME" == "simcl1n4" ]]; then + + if [[ "$1" == "cuda" || "$1" == "sycl" ]]; then + echo "Error: simcl1n4 does not have a GPU." 1>&2 + exit 1 + fi + + if spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.1.0 + export CXX=g++ + export CC=gcc + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + else + echo "Cannot find Spack environment gprat_cpu_gcc. Please run spack-repo/environments/setup_gprat_cpu_gcc.sh" 1>&2 + exit 1 + fi + + # pcsgs04 with Intel GPU ######################################################################## + elif [[ "$HOSTNAME" == "pcsgs04" ]]; then + + echo "Host pcsgs04 is currently not supported." 1>&2 + exit 1 + + # unknown host ################################################################################## + else + + echo "Caution: This script does not cover host $HOSTNAME." + + fi + else - echo "Spack command not found. Building example without Spack." - # Assuming that Spack is not required on given system + + echo "Spack command not found. Building example without Spack." + fi +################################################################################################### # Configure APEX +################################################################################################### + export APEX_SCREEN_OUTPUT=0 export APEX_DISABLE=1 -################################################################################ +################################################################################################### # Compile code -################################################################################ -rm -rf build && mkdir build && cd build - -# Configure the project -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DGPRat_DIR=./lib$ADD/cmake/GPRat \ - -DGPRAT_WITH_CUDA=${GPRAT_WITH_CUDA} \ - -DGPRAT_APEX_STEPS=${GPRAT_APEX_STEPS} \ - -DGPRAT_APEX_CHOLESKY=${GPRAT_APEX_CHOLESKY} \ - -DHPX_DIR=$HPX_CMAKE \ - -DUSE_MKL=$USE_MKL - -# Build the project +################################################################################################### + +# Resolve the script's own directory so cmake paths are always correct +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +GPRAT_ROOT="$(pwd)/../.." +LIB_DIR="$(pwd)/lib${GPRAT_LIB_SUFFIX}" + +if [[ "$1" == "cuda" ]]; then + GPRAT_WITH_CUDA=ON + GPRAT_WITH_SYCL=OFF + GPRAT_BUILD_DIR="$GPRAT_ROOT/build/release-linux-cuda" +elif [[ "$1" == "sycl" ]]; then + GPRAT_WITH_CUDA=OFF + GPRAT_WITH_SYCL=ON + GPRAT_BUILD_DIR="$GPRAT_ROOT/build/release-linux-sycl" +else + GPRAT_WITH_CUDA=OFF + GPRAT_WITH_SYCL=OFF + GPRAT_BUILD_DIR="$GPRAT_ROOT/build/release-linux" +fi + +# Install the matching GPRat build so the lib dir always matches the backend. +# Use $(pwd) as prefix: cmake places cmake files at $PREFIX/lib/cmake/GPRat +# which matches GPRAT_DIR below. +cmake --install "$GPRAT_BUILD_DIR" --prefix "$(pwd)" + +GPRAT_DIR="$LIB_DIR/cmake/GPRat" + +if [[ ! -d build ]]; then + mkdir -p build + cd build + + SYCL_COMPILER_ARGS=() + if [[ "$1" == "sycl" ]]; then + SYCL_COMPILER_ARGS=( + -DCMAKE_C_COMPILER="$(which icx)" + -DCMAKE_CXX_COMPILER="$(which icpx)" + ) + fi + + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DGPRat_DIR=$GPRAT_DIR \ + -DHPX_DIR=$HPX_CMAKE \ + -DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH \ + -DGPRAT_WITH_CUDA=$GPRAT_WITH_CUDA \ + -DGPRAT_WITH_SYCL=$GPRAT_WITH_SYCL \ + -DGPRAT_APEX_STEPS=OFF \ + -DGPRAT_APEX_CHOLESKY=OFF \ + "${SYCL_COMPILER_ARGS[@]}" +else + cd build +fi + make -j -################################################################################ +################################################################################################### # Run code -################################################################################ +################################################################################################### + +echo "Running GPRat C++ example" + +end_cores=$(python3 -c "import json; print(json.load(open('../config.json'))['END_CORES'])") +core_count=$((end_cores * 2)) + +taskset -c 0-$core_count:2 ./gprat_cpp $use_gpu -./gprat_cpp $use_gpu +echo "Finished running GPRat C++ example" diff --git a/examples/gprat_cpp/run_gprat_spack.sh b/examples/gprat_cpp/run_gprat_spack.sh deleted file mode 100755 index 856a112d..00000000 --- a/examples/gprat_cpp/run_gprat_spack.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# $1 cpu/gpu - -################################################################################ -set -e # Exit immediately if a command exits with a non-zero status. -#set -x # Print each command before executing it. - -################################################################################ -# Configurations -################################################################################ - -if command -v spack &> /dev/null; then - echo "Spack command found." - # Get current hostname - HOSTNAME=$(hostname -s) - - if [[ "$HOSTNAME" == "ipvs-epyc1" ]]; then - module load gcc/14.2.0 - export CXX=g++ - export CC=gcc - spack install gprat%gcc@14.2.0 blas=openblas - spack load gprat%gcc blas=openblas - elif [[ "$HOSTNAME" == "simcl1n1" || "$HOSTNAME" == "simcl1n2" ]]; then - # Check if the gprat_gpu_clang environment exists - module load clang/17.0.1 - export CXX=clang++ - export CC=clang - GPRAT_WITH_CUDA=ON - GPRAT_APEX_STEPS=OFF - GPRAT_APEX_CHOLESKY=OFF - spack install gprat%clang@17.0.1 blas=openblas +cuda cuda_arch=80 ^cmake@3.30.5 - spack load gprat blas=openblas +cuda - else - echo "Hostname is $HOSTNAME — no action taken." - fi -else - echo "Spack command not found." - exit 1 -fi - -# Configure APEX -export APEX_SCREEN_OUTPUT=0 -export APEX_DISABLE=1 - -################################################################################ -# Compile code -################################################################################ -rm -rf build && mkdir build && cd build - -# Configure the project -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DGPRAT_WITH_CUDA=${GPRAT_WITH_CUDA} \ - -DGPRAT_APEX_STEPS=${GPRAT_APEX_STEPS} \ - -DGPRAT_APEX_CHOLESKY=${GPRAT_APEX_CHOLESKY} - -# Build the project -make -j - -################################################################################ -# Run code -################################################################################ -if [[ -z "$1" ]]; then - echo "Input parameter is missing. Using default: Run computations on CPU" -elif [[ "$1" == "gpu" ]]; then - GPU="--use_gpu" -elif [[ "$1" != "cpu" ]]; then - echo "Please specify input parameter: cpu/gpu" - exit 1 -fi - -./gprat_cpp $GPU diff --git a/examples/gprat_cpp/src/execute.cpp b/examples/gprat_cpp/src/execute.cpp index 8c415727..420a0e11 100644 --- a/examples/gprat_cpp/src/execute.cpp +++ b/examples/gprat_cpp/src/execute.cpp @@ -1,42 +1,314 @@ -#include "gprat_c.hpp" -#include "utils_c.hpp" +// GPRat +#include "gprat/gprat.hpp" +#include "gprat/utils.hpp" + +// Boost +#include + +// Standard library #include +#include #include #include +#include + +namespace gprat::example +{ +struct Runtimes +{ + std::chrono::duration init; + std::chrono::duration cholesky; + std::chrono::duration opt; + std::chrono::duration pred_uncer; + std::chrono::duration pred_full_cov; + std::chrono::duration pred; +}; + +struct GpratSettings +{ + std::string train_in_file; + std::string train_out_file; + std::string test_in_file; + + int train_size_start; + int train_size_end; + int train_size_step; + + int start_cores; + int end_cores; + + int test_size; + bool scale_test_with_train; + + int n_reg; + int opt_iter; + int loop; + int n_tiles_start; + int n_tiles_end; + int step_tiles; + + bool cholesky; +}; + +template +inline void extract(const boost::json::object &obj, T &t, std::string_view key) +{ + t = boost::json::value_to(obj.at(key)); +} + +GpratSettings tag_invoke(boost::json::value_to_tag, const boost::json::value &jv) +{ + GpratSettings settings; + const auto &obj = jv.as_object(); + extract(obj, settings.train_in_file, "TRAIN_IN_FILE"); + extract(obj, settings.train_out_file, "TRAIN_OUT_FILE"); + extract(obj, settings.test_in_file, "TEST_IN_FILE"); + extract(obj, settings.train_size_start, "TRAIN_SIZE_START"); + extract(obj, settings.train_size_end, "TRAIN_SIZE_END"); + extract(obj, settings.train_size_step, "STEP"); + extract(obj, settings.test_size, "TEST_SIZE"); + extract(obj, settings.scale_test_with_train, "SCALE_TEST_WITH_TRAIN"); + extract(obj, settings.n_reg, "N_REG"); + extract(obj, settings.opt_iter, "OPT_ITER"); + extract(obj, settings.loop, "LOOP"); + extract(obj, settings.start_cores, "START_CORES"); + extract(obj, settings.end_cores, "END_CORES"); + extract(obj, settings.n_tiles_start, "N_TILES_START"); + extract(obj, settings.n_tiles_end, "N_TILES_END"); + extract(obj, settings.step_tiles, "STEP_TILES"); + extract(obj, settings.cholesky, "CHOLESKY"); + + return settings; +} + +// GPU test settings +constexpr int device_id = 0; +constexpr int n_units = 1; + +void append_to_output_file( + std::string &target, + int &core, + int &n_tiles, + int &n_train, + int &n_test, + int &n_reg, + int &n_opt_iter, + std::chrono::duration &total_time, + Runtimes &runtimes, + int &l) +{ + const std::filesystem::path output_path = std::filesystem::path(GPRAT_CPP_CONFIG_PATH).parent_path() / "output.csv"; + std::ofstream outfile(output_path, std::ios::app); + if (outfile.tellp() == 0) + { + outfile << "Target," << "Cores," << "N_tiles," << "N_train," << "N_test," << "N_regressor," << "Opt_iter," + << "Total_time," << "Init_time," << "Cholesky_time," << "Opt_Time," << "Predict_time," + << "Pred_uncer_time," << "Pred_Full_time," << "N_loop\n"; + } + outfile << target << "," << core << "," << n_tiles << "," << n_train << "," << n_test << "," << n_reg << "," + << n_opt_iter << "," << total_time.count() << "," << runtimes.init.count() << "," + << runtimes.cholesky.count() << "," << runtimes.opt.count() << "," << runtimes.pred.count() << "," + << runtimes.pred_uncer.count() << "," << runtimes.pred_full_cov.count() << "," << l << "\n"; + outfile.close(); +} + +void example_cpu(Runtimes &runtimes, + std::pair &result, + gprat::GP_data &training_input, + gprat::GP_data &training_output, + gprat::GP_data &test_input, + const std::size_t n_tiles, + const std::size_t tile_size, + std::vector trainable, + GpratSettings &settings) +{ + gprat::AdamParams hpar = { 0.1, 0.9, 0.999, 1e-8, static_cast(settings.opt_iter) }; + + auto start_init = std::chrono::high_resolution_clock::now(); + gprat::GP gp_cpu(training_input.data, + training_output.data, + n_tiles, + tile_size, + static_cast(settings.n_reg), + { 1.0, 1.0, 0.1 }, + trainable); + auto end_init = std::chrono::high_resolution_clock::now(); + runtimes.init = end_init - start_init; + + auto start_cholesky = std::chrono::high_resolution_clock::now(); + if (settings.cholesky) + { + gp_cpu.cholesky(); + } + auto end_cholesky = std::chrono::high_resolution_clock::now(); + runtimes.cholesky = settings.cholesky ? end_cholesky - start_cholesky : std::chrono::seconds(-1); + + auto start_opt = std::chrono::high_resolution_clock::now(); + if (!settings.cholesky) + { + gp_cpu.optimize(hpar); + } + auto end_opt = std::chrono::high_resolution_clock::now(); + runtimes.opt = settings.cholesky ? std::chrono::seconds(-1) : end_opt - start_opt; + + auto start_pred_uncer = std::chrono::high_resolution_clock::now(); + if (!settings.cholesky) + { + gp_cpu.predict_with_uncertainty(test_input.data, result.first, result.second); + } + auto end_pred_uncer = std::chrono::high_resolution_clock::now(); + runtimes.pred_uncer = settings.cholesky ? std::chrono::seconds(-1) : end_pred_uncer - start_pred_uncer; + + auto start_pred_full_cov = std::chrono::high_resolution_clock::now(); + if (!settings.cholesky) + { + gp_cpu.predict_with_full_cov(test_input.data, result.first, result.second); + } + auto end_pred_full_cov = std::chrono::high_resolution_clock::now(); + runtimes.pred_full_cov = settings.cholesky ? std::chrono::seconds(-1) : end_pred_full_cov - start_pred_full_cov; + + auto start_pred = std::chrono::high_resolution_clock::now(); + if (!settings.cholesky) + { + gp_cpu.predict(test_input.data, result.first, result.second); + } + auto end_pred = std::chrono::high_resolution_clock::now(); + runtimes.pred = settings.cholesky ? std::chrono::seconds(-1) : end_pred - start_pred; +} + +void example_gpu(Runtimes &runtimes, + std::pair &result, + gprat::GP_data &training_input, + gprat::GP_data &training_output, + gprat::GP_data &test_input, + const std::size_t n_tiles, + const std::size_t tile_size, + std::vector trainable, + std::size_t n_reg, + bool &cholesky) +{ + auto start_init = std::chrono::high_resolution_clock::now(); + gprat::GP gp_gpu( + training_input.data, + training_output.data, + n_tiles, + tile_size, + n_reg, + std::vector{ 1.0, 1.0, 0.1 }, + trainable, + device_id, + n_units); + auto end_init = std::chrono::high_resolution_clock::now(); + runtimes.init = end_init - start_init; + + auto start_cholesky = std::chrono::high_resolution_clock::now(); + if (cholesky) + { + gp_gpu.cholesky(); + } + auto end_cholesky = std::chrono::high_resolution_clock::now(); + runtimes.cholesky = cholesky ? end_cholesky - start_cholesky : std::chrono::seconds(-1); + + // NOTE: optimization is not implemented for GPU + runtimes.opt = std::chrono::seconds(-1); + + auto start_pred_uncer = std::chrono::high_resolution_clock::now(); + if (!cholesky) + { + gp_gpu.predict_with_uncertainty(test_input.data, result.first, result.second); + } + auto end_pred_uncer = std::chrono::high_resolution_clock::now(); + runtimes.pred_uncer = cholesky ? std::chrono::seconds(-1) : end_pred_uncer - start_pred_uncer; + + auto start_pred_full_cov = std::chrono::high_resolution_clock::now(); + if (!cholesky) + { + gp_gpu.predict_with_full_cov(test_input.data, result.first, result.second); + } + auto end_pred_full_cov = std::chrono::high_resolution_clock::now(); + runtimes.pred_full_cov = cholesky ? std::chrono::seconds(-1) : end_pred_full_cov - start_pred_full_cov; + + auto start_pred = std::chrono::high_resolution_clock::now(); + if (!cholesky) + { + gp_gpu.predict(test_input.data, result.first, result.second); + } + auto end_pred = std::chrono::high_resolution_clock::now(); + runtimes.pred = cholesky ? std::chrono::seconds(-1) : end_pred - start_pred; +} + +} // namespace gprat::example int main(int argc, char *argv[]) { - ///////////////////// - /////// configuration - std::size_t START = 512; - std::size_t END = 1024; - std::size_t STEP = 2; - std::size_t LOOP = 2; - const std::size_t OPT_ITER = 1; - - int n_test = 1024; - const std::size_t N_CORES = 4; - const std::size_t n_tiles = 16; - const std::size_t n_reg = 8; - - std::string train_path = "../../../data/data_1024/training_input.txt"; - std::string out_path = "../../../data/data_1024/training_output.txt"; - std::string test_path = "../../../data/data_1024/test_input.txt"; - - bool use_gpu = - utils::compiled_with_cuda() && gprat::gpu_count() > 0 && argc > 1 && std::strcmp(argv[1], "--use_gpu") == 0; - - for (std::size_t core = 2; core <= N_CORES; core = core * 2) + gprat::example::GpratSettings settings; + + bool use_gpu = false; + + std::ifstream ifs(GPRAT_CPP_CONFIG_PATH); + if (!ifs.fail()) { - // Create new argc and argv to include the --hpx:threads argument - std::vector args(argv, argv + argc); - if (use_gpu) + using iterator_type = std::istreambuf_iterator; + const std::string content(iterator_type{ ifs }, iterator_type{}); + settings = boost::json::value_to(boost::json::parse(content)); + + const std::filesystem::path config_dir = std::filesystem::path(GPRAT_CPP_CONFIG_PATH).parent_path(); + auto resolve = [&](std::string &p) + { + if (!std::filesystem::path(p).is_absolute()) + { + p = (config_dir / p).lexically_normal().string(); + } + }; + resolve(settings.train_in_file); + resolve(settings.train_out_file); + resolve(settings.test_in_file); + } + else + { + std::cerr << "Could not read config file. Please make sure config.json is present and valid.\n"; + return 1; + } + + if (argc > 1 && std::strcmp(argv[1], "--use-gpu") == 0) + { + if (!gprat::compiled_with_cuda() && !gprat::compiled_with_sycl()) + { + std::cerr << "Error: GPU support is not available. Please compile with CUDA or SYCL support.\n"; + return 1; + } + else if (gprat::gpu_count() == 0) { - args.erase(args.begin() + 1); + std::cerr << "GPU support requested but GPRat found no GPUs.\n"; + return 1; } + else + { + use_gpu = true; + if (gprat::compiled_with_cuda()) + { + std::cout << "Using CUDA GPU for computations.\n"; + } + else if (gprat::compiled_with_sycl()) + { + std::cout << "Using SYCL GPU for computations.\n"; + } + } + } + else + { + std::cout << "Using CPU for computations.\n"; + } + + std::string target = use_gpu ? gprat::compiled_with_cuda() ? "cuda" : "sycl" : "cpu"; + + // Loop over cores + for (int core = settings.start_cores; core <= settings.end_cores; core *= 2) + { + std::vector args(argv, argv + argc); + args.erase(args.begin() + argc - 1); args.push_back("--hpx:threads=" + std::to_string(core)); - // Convert the arguments to char* array std::vector cstr_args; for (auto &arg : args) { @@ -46,152 +318,85 @@ int main(int argc, char *argv[]) int new_argc = static_cast(cstr_args.size()); char **new_argv = cstr_args.data(); - for (std::size_t start = START; start <= END; start = start * STEP) + gprat::start_hpx_runtime(new_argc, new_argv); + + // Loop over tiles + for (int n_tiles = settings.n_tiles_start; n_tiles <= settings.n_tiles_end; n_tiles *= settings.step_tiles) { - int n_train = static_cast(start); - for (std::size_t l = 0; l < LOOP; l++) + int training_baseline = settings.train_size_start > n_tiles ? settings.train_size_start : n_tiles; + + // Loop over training sizes + for (int train_size = training_baseline; train_size <= settings.train_size_end; + train_size *= settings.train_size_step) { - // Compute tile sizes and number of predict tiles - int tile_size = utils::compute_train_tile_size(n_train, n_tiles); - auto result = utils::compute_test_tiles(n_test, n_tiles, tile_size); - ///////////////////// - ///// hyperparams - gprat_hyper::AdamParams hpar = { 0.1, 0.9, 0.999, 1e-8, OPT_ITER }; - - ///////////////////// - ////// data loading - gprat::GP_data training_input(train_path, n_train, n_reg); - gprat::GP_data training_output(out_path, n_train, n_reg); - gprat::GP_data test_input(test_path, n_test, n_reg); - - auto start_total = std::chrono::high_resolution_clock::now(); - - std::chrono::duration init_time; - std::chrono::duration cholesky_time; - std::chrono::duration opt_time; - std::chrono::duration pred_uncer_time; - std::chrono::duration pred_full_cov_time; - std::chrono::duration pred_time; - std::vector trainable = { true, true, true }; - std::string target; - - if (!use_gpu) - { - target = "cpu"; - - ///////////////////// - ///// GP - auto start_init = std::chrono::high_resolution_clock::now(); - gprat::GP gp_cpu(training_input.data, - training_output.data, - n_tiles, - tile_size, - n_reg, - { 1.0, 1.0, 0.1 }, - trainable); - auto end_init = std::chrono::high_resolution_clock::now(); - init_time = end_init - start_init; - - // Initialize HPX with the new arguments, don't run hpx_main - utils::start_hpx_runtime(new_argc, new_argv); - - // Measure the time taken to execute gp.cholesky(); - auto start_cholesky = std::chrono::high_resolution_clock::now(); - std::vector> choleksy_cpu = gp_cpu.cholesky(); - auto end_cholesky = std::chrono::high_resolution_clock::now(); - cholesky_time = end_cholesky - start_cholesky; - - // Measure the time taken to execute gp.optimize(hpar); - auto start_opt = std::chrono::high_resolution_clock::now(); - std::vector losses = gp_cpu.optimize(hpar); - auto end_opt = std::chrono::high_resolution_clock::now(); - opt_time = end_opt - start_opt; - - auto start_pred_uncer = std::chrono::high_resolution_clock::now(); - std::vector> sum_cpu = - gp_cpu.predict_with_uncertainty(test_input.data, result.first, result.second); - auto end_pred_uncer = std::chrono::high_resolution_clock::now(); - pred_uncer_time = end_pred_uncer - start_pred_uncer; - - auto start_pred_full_cov = std::chrono::high_resolution_clock::now(); - std::vector> full_cpu = - gp_cpu.predict_with_full_cov(test_input.data, result.first, result.second); - auto end_pred_full_cov = std::chrono::high_resolution_clock::now(); - pred_full_cov_time = end_pred_full_cov - start_pred_full_cov; - - auto start_pred = std::chrono::high_resolution_clock::now(); - std::vector pred_cpu = gp_cpu.predict(test_input.data, result.first, result.second); - auto end_pred = std::chrono::high_resolution_clock::now(); - pred_time = end_pred - start_pred; - } - else + int n_test = settings.scale_test_with_train ? train_size : settings.test_size; + + // Loop over repetitions + for (int l = 0; l < settings.loop; l++) { - target = "gpu"; + auto n_tiles_st = static_cast(n_tiles); + auto train_size_st = static_cast(train_size); + auto n_test_st = static_cast(n_test); + auto n_reg_st = static_cast(settings.n_reg); + std::size_t tile_size = gprat::compute_train_tile_size(train_size_st, n_tiles_st); + auto result = gprat::compute_test_tiles(n_test_st, n_tiles_st, tile_size); - auto start_init = std::chrono::high_resolution_clock::now(); - gprat::GP gp_gpu( - training_input.data, - training_output.data, - n_tiles, - tile_size, - n_reg, - { 1.0, 1.0, 0.1 }, - trainable, - 0, - 2); - auto end_init = std::chrono::high_resolution_clock::now(); - init_time = end_init - start_init; - - // Initialize HPX with the new arguments, don't run hpx_main - utils::start_hpx_runtime(new_argc, new_argv); - - auto start_cholesky = std::chrono::high_resolution_clock::now(); - std::vector> choleksy_gpu = gp_gpu.cholesky(); - auto end_cholesky = std::chrono::high_resolution_clock::now(); - cholesky_time = end_cholesky - start_cholesky; - - // NOTE: optimization is not implemented for GPU - opt_time = std::chrono::seconds(-1); - - auto start_pred_uncer = std::chrono::high_resolution_clock::now(); - std::vector> sum_gpu = - gp_gpu.predict_with_uncertainty(test_input.data, result.first, result.second); - auto end_pred_uncer = std::chrono::high_resolution_clock::now(); - pred_uncer_time = end_pred_uncer - start_pred_uncer; - - auto start_pred_full_cov = std::chrono::high_resolution_clock::now(); - std::vector> full_gpu = - gp_gpu.predict_with_full_cov(test_input.data, result.first, result.second); - auto end_pred_full_cov = std::chrono::high_resolution_clock::now(); - pred_full_cov_time = end_pred_full_cov - start_pred_full_cov; - - auto start_pred = std::chrono::high_resolution_clock::now(); - std::vector pred_gpu = gp_gpu.predict(test_input.data, result.first, result.second); - auto end_pred = std::chrono::high_resolution_clock::now(); - pred_time = end_pred - start_pred; - } + gprat::GP_data training_input(settings.train_in_file, train_size_st, n_reg_st); + gprat::GP_data training_output(settings.train_out_file, train_size_st, n_reg_st); + gprat::GP_data test_input(settings.test_in_file, n_test_st, n_reg_st); - // Stop the HPX runtime - utils::stop_hpx_runtime(); + gprat::example::Runtimes runtimes; + std::vector trainable = { true, true, true }; - auto end_total = std::chrono::high_resolution_clock::now(); - auto total_time = end_total - start_total; + auto start_total = std::chrono::high_resolution_clock::now(); - // Save parameters and times to a .txt file with a header - std::ofstream outfile("../output.csv", std::ios::app); // Append mode - if (outfile.tellp() == 0) - { - // If file is empty, write the header - outfile << "Target,Cores,N_train,N_test,N_tiles,N_regressor,Opt_iter,Total_time,Init_time,Cholesky_" - "time,Opt_time,Pred_Uncer_time,Pred_Full_time,Pred_time,N_loop\n"; + if (use_gpu) + { + gprat::example::example_gpu( + runtimes, + result, + training_input, + training_output, + test_input, + n_tiles_st, + tile_size, + trainable, + n_reg_st, + settings.cholesky); + } + else + { + gprat::example::example_cpu( + runtimes, + result, + training_input, + training_output, + test_input, + n_tiles_st, + tile_size, + trainable, + settings); + } + + auto end_total = std::chrono::high_resolution_clock::now(); + std::chrono::duration total_time = end_total - start_total; + + gprat::example::append_to_output_file( + target, + core, + n_tiles, + train_size, + n_test, + settings.n_reg, + settings.opt_iter, + total_time, + runtimes, + l); } - outfile << target << "," << core << "," << n_train << "," << n_test << "," << n_tiles << "," << n_reg - << "," << OPT_ITER << "," << total_time.count() << "," << init_time.count() << "," - << cholesky_time.count() << "," << opt_time.count() << "," << pred_uncer_time.count() << "," - << pred_full_cov_time.count() << "," << pred_time.count() << "," << l << "\n"; - outfile.close(); } } + + gprat::stop_hpx_runtime(); } return 0; diff --git a/examples/gprat_distributed/CMakeLists.txt b/examples/gprat_distributed/CMakeLists.txt new file mode 100644 index 00000000..04bdb275 --- /dev/null +++ b/examples/gprat_distributed/CMakeLists.txt @@ -0,0 +1,16 @@ +add_executable(gprat_distributed src/main.cpp) +# HPX_REGISTER_STARTUP_MODULE creates a static that icpx sees as unused +set_source_files_properties(src/main.cpp PROPERTIES COMPILE_OPTIONS + "-Wno-unused-variable") +target_compile_features(gprat_distributed PUBLIC cxx_std_20) + +# Bake in the absolute path to this example directory so the default output.csv +# location works regardless of the current working directory, matching +# gprat_cpp. +target_compile_definitions( + gprat_distributed PRIVATE GPRAT_DISTRIBUTED_DIR="${CMAKE_CURRENT_SOURCE_DIR}") + +target_link_libraries(gprat_distributed PUBLIC GPRat::core HPX::hpx) + +set_target_properties(gprat_distributed PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}") diff --git a/examples/gprat_distributed/run_gprat_distributed.sh b/examples/gprat_distributed/run_gprat_distributed.sh new file mode 100755 index 00000000..17e92a01 --- /dev/null +++ b/examples/gprat_distributed/run_gprat_distributed.sh @@ -0,0 +1,210 @@ +#!/bin/bash +# Builds and runs the gprat_distributed benchmark against the CPU (OpenBLAS/MKL) backend. +# All arguments are forwarded to the gprat_distributed binary, e.g.: +# ./run_gprat_distributed.sh --start 128 --end 4096 --step 2 --tiles 8 --loop 3 +# +# NOTE: this script only launches a single HPX locality. To launch multiple localities +# (e.g. one per process on the same node), run this binary directly N times with +# --hpx:localities=N --hpx:node= instead of via this script, and see the +# "To run the distributed GPRat benchmark" section in the top-level README for a +# required workaround (HPX's TCP zero-copy serialization threshold) and the caveats +# for launching across multiple actual nodes. +# +# NOTE: the default Spack environment (gprat_cpu_gcc) builds HPX with networking=none, +# which rejects --hpx:localities outright. To build a binary that supports > 1 locality, this +# script defaults GPRAT_DIST_MULTI_LOCALITY=1 (set it to 0 beforehand to opt back into the +# single-locality build); on the simcl hosts this switches to the gprat_cpu_gcc_dist Spack +# environment (networking=tcp, OpenBLAS-only, see +# spack-repo/environments/setup_gprat_cpu_gcc_dist.sh). Since the shared scratch Spack instance +# on those hosts is owned by another account, GPRAT_DIST_MULTI_LOCALITY=1 skips sourcing it and +# instead uses whatever `spack` is already on the user's own PATH (e.g. a personal Spack +# install with its own gprat_cpu_gcc_dist environment). +# +# With GPRAT_DIST_MULTI_LOCALITY=1, the script itself launches one run per locality count in +# GPRAT_DIST_LOCALITIES (default "1 2 4"), spawning the N processes (--hpx:localities=N +# --hpx:node=0..N-1) each round instead of a single-locality invocation. + +set -e # Exit immediately if a command exits with a non-zero status. + +: "${GPRAT_DIST_MULTI_LOCALITY:=1}" + +is_simcl_host() { + case " simcl1n1 simcl1n2 simcl1n3 simcl1n4 " in + *" $1 "*) return 0 ;; + *) return 1 ;; + esac +} + +################################################################################################### +# Set Spack if on simcl1n1, simcl1n2, simcl1n3, or simcl1n4 +################################################################################################### + +if [[ "$GPRAT_DIST_MULTI_LOCALITY" != "1" ]] && is_simcl_host "$HOSTNAME"; then + + spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" + source $spack_destination/spack/share/spack/setup-env.sh + +fi + +################################################################################################### +# Setup environment depending on the host +################################################################################################### + +if command -v spack &>/dev/null; then + + echo "Spack command found, checking for environments..." + + HOSTNAME=$(hostname -s) + + # ipvs-epyc1 #################################################################################### + if [[ "$HOSTNAME" == "ipvs-epyc1" ]]; then + + if spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.2.0 + export CXX=g++ + export CC=gcc + fi + + # sven0 and sven1 ############################################################################### + elif [[ "$HOSTNAME" == "sven0" || "$HOSTNAME" == "sven1" ]]; then + + spack load openblas arch=linux-fedora38-riscv64 + HPX_CMAKE=$HOME/git_workspace/build-scripts/build/hpx/lib64/cmake/HPX + export LD_LIBRARY_PATH=$HOME/git_workspace/build-scripts/build/hpx/lib64:$LD_LIBRARY_PATH + export LD_LIBRARY_PATH=$HOME/git_workspace/build-scripts/build/boost/lib:$LD_LIBRARY_PATH + export LD_PRELOAD=$HOME/git_workspace/build-scripts/build/jemalloc/lib/libjemalloc.so.2 + + # aarch64 ####################################################################################### + elif [[ $(uname -i) == "aarch64" ]]; then + + spack load gcc@14.2.0 + if spack env list | grep -q "gprat_cpu_arm"; then + echo "Found gprat_cpu_arm environment, activating it." + spack env activate gprat_cpu_arm + fi + + # simcl1n1, simcl1n2, simcl1n3, simcl1n4 (CPU only) ############################################# + elif is_simcl_host "$HOSTNAME"; then + + if [[ "$GPRAT_DIST_MULTI_LOCALITY" == "1" ]]; then + + if spack env list | grep -q "gprat_cpu_gcc_dist"; then + echo "Found gprat_cpu_gcc_dist environment, activating it." + spack env activate gprat_cpu_gcc_dist + module load gcc/14.1.0 + export CXX=g++ + export CC=gcc + # No MKL variant is maintained for this environment; build against OpenBLAS. + GPRAT_ENABLE_MKL_ARGS=(-DGPRAT_ENABLE_MKL=OFF) + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + else + echo "Cannot find Spack environment gprat_cpu_gcc_dist. Please run spack-repo/environments/setup_gprat_cpu_gcc_dist.sh" 1>&2 + exit 1 + fi + + elif spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.1.0 + export CXX=g++ + export CC=gcc + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + else + echo "Cannot find Spack environment gprat_cpu_gcc. Please run spack-repo/environments/setup_gprat_cpu_gcc.sh" 1>&2 + exit 1 + fi + + # unknown host ################################################################################## + else + + echo "Caution: This script does not cover host $HOSTNAME." + + fi + +else + + echo "Spack command not found. Building example without Spack." + +fi + +################################################################################################### +# Configure APEX +################################################################################################### + +export APEX_SCREEN_OUTPUT=0 +export APEX_DISABLE=1 + +################################################################################################### +# Compile code +################################################################################################### + +# Unlike examples/gprat_cpp, examples/gprat_distributed is only ever built in-tree +# (it has no standalone/out-of-tree CMake support), so we build it as part of the +# main GPRat build with GPRAT_WITH_DISTRIBUTED enabled. + +# Resolve the script's own directory so cmake paths are always correct +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +GPRAT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$GPRAT_ROOT" + +HPX_DIR_ARGS=() +if [[ -n "$HPX_CMAKE" ]]; then + HPX_DIR_ARGS=(-DHPX_DIR="$HPX_CMAKE") +fi + +# Multi-locality builds use a distinct Spack toolchain (networking=tcp HPX, OpenBLAS-only) +# from the default single-locality build. Building both into the same build/release-linux +# directory poisons the CMake cache with paths from whichever toolchain configured it last +# (e.g. linking against one env's HPX headers while another env's .so is on +# LD_LIBRARY_PATH), so give multi-locality builds their own build directory. +BUILD_DIR="build/release-linux" +if [[ "$GPRAT_DIST_MULTI_LOCALITY" == "1" ]]; then + BUILD_DIR="build/release-linux-dist" +fi + +cmake --preset release-linux -B "$BUILD_DIR" -DGPRAT_WITH_DISTRIBUTED=ON "${HPX_DIR_ARGS[@]}" "${GPRAT_ENABLE_MKL_ARGS[@]}" +cmake --build "$BUILD_DIR" --target gprat_distributed -j + +################################################################################################### +# Run code +################################################################################################### + +GPRAT_DISTRIBUTED_BIN="$GPRAT_ROOT/$BUILD_DIR/examples/gprat_distributed/gprat_distributed" + +if [[ "$GPRAT_DIST_MULTI_LOCALITY" == "1" ]]; then + + # Run from GPRAT_ROOT so the default data/data_1024/... paths resolve. + for N in ${GPRAT_DIST_LOCALITIES:-1 2 4}; do + + echo "Running GPRat distributed benchmark ($N locality/localities)" + + pids=() + "$GPRAT_DISTRIBUTED_BIN" --hpx:localities="$N" --hpx:node=0 \ + --hpx:ini=hpx.parcel.zero_copy_serialization_threshold=999999999 "$@" & + pids+=($!) + for ((node = 1; node < N; node++)); do + "$GPRAT_DISTRIBUTED_BIN" --hpx:localities="$N" --hpx:node="$node" \ + --hpx:ini=hpx.parcel.zero_copy_serialization_threshold=999999999 & + pids+=($!) + done + wait "${pids[@]}" + + echo "Finished running GPRat distributed benchmark ($N locality/localities)" + + done + +else + + echo "Running GPRat distributed benchmark (single locality)" + + # Run from GPRAT_ROOT so the default data/data_1024/... paths resolve. + "$GPRAT_DISTRIBUTED_BIN" "$@" + + echo "Finished running GPRat distributed benchmark" + +fi diff --git a/examples/gprat_distributed/src/main.cpp b/examples/gprat_distributed/src/main.cpp new file mode 100644 index 00000000..9cd5c241 --- /dev/null +++ b/examples/gprat_distributed/src/main.cpp @@ -0,0 +1,292 @@ +// All of these are necessary: +#include "gprat/cpu/adapter_cblas_fp64_actions.hpp" +#include "gprat/cpu/gp_algorithms_actions.hpp" +#include "gprat/cpu/gp_functions.hpp" +#include "gprat/cpu/gp_optimizer_actions.hpp" +#include "gprat/cpu/gp_uncertainty_actions.hpp" +#include "gprat/gprat.hpp" +#include "gprat/kernels.hpp" +#include "gprat/performance_counters.hpp" +#include "gprat/scheduler/sma.hpp" +#include "gprat/tiled_dataset.hpp" +#include "gprat/utils.hpp" + +#include +#include +#include +#include +#include +#include +#include + +GPRAT_NS_BEGIN + +void finish_step(const char *name, double elapsed_seconds) +{ + std::cerr << name << " done in " << elapsed_seconds << " seconds" << std::endl; + hpx::evaluate_active_counters(true, name); +} + +void run(hpx::program_options::variables_map &vm) +{ + ///////////////////// + /////// configuration + const std::size_t START = vm["start"].as(); + const std::size_t END = vm["end"].as(); + const std::size_t STEP = vm["step"].as(); + const std::size_t LOOP = vm["loop"].as(); + const std::size_t OPT_ITER = vm["opt_iter"].as(); + const std::size_t enabled = vm["enabled"].as(); + + const std::size_t n_test = vm["n_test"].as(); + const std::size_t n_tiles = vm["tiles"].as(); + const std::size_t n_reg = vm["regressors"].as(); + + const auto &train_path = vm["train_x_path"].as(); + const auto &out_path = vm["train_y_path"].as(); + const auto &test_path = vm["test_path"].as(); + + tiled_scheduler_sma scheduler; + const auto n_localities = hpx::get_num_localities().get(); + + for (std::size_t start = START; start <= END; start = start * STEP) + { + const auto n_train = start; + for (std::size_t l = 0; l < LOOP; l++) + { + hpx::chrono::high_resolution_timer total_timer; + + // Compute tile sizes and number of predict tiles + const auto tile_size = compute_train_tile_size(n_train, n_tiles); + const auto result = compute_test_tiles(n_test, n_tiles, tile_size); + ///////////////////// + ///// hyperparams + AdamParams hpar = { 0.1, 0.9, 0.999, 1e-8, OPT_ITER }; + SEKParams sek_params = { 1.0, 1.0, 0.1 }; + std::vector trainable = { true, true, true }; + + ///////////////////// + ////// data loading + hpx::chrono::high_resolution_timer init_timer; + GP_data training_input(train_path, n_train, n_reg); + GP_data training_output(out_path, n_train, n_reg); + GP_data test_input(test_path, n_test, n_reg); + const auto init_time = init_timer.elapsed(); + finish_step("init", init_time); + + ///////////////////// + ///// GP + + // Start with a clean slate + hpx::reset_active_counters(); + + hpx::chrono::high_resolution_timer cholesky_timer; + if (enabled & (1 << 0)) + { + cpu::cholesky(scheduler, training_input.data, sek_params, n_tiles, tile_size, n_reg); + } + const auto cholesky_time = cholesky_timer.elapsed(); + finish_step("cholesky", cholesky_time); + + hpx::chrono::high_resolution_timer opt_timer; + if (enabled & (1 << 1)) + { + cpu::optimize( + scheduler, + training_input.data, + training_output.data, + n_tiles, + tile_size, + n_reg, + hpar, + sek_params, + trainable); + } + const auto opt_time = opt_timer.elapsed(); + finish_step("opt", opt_time); + + hpx::chrono::high_resolution_timer predict_timer; + if (enabled & (1 << 2)) + { + cpu::predict( + scheduler, + training_input.data, + training_output.data, + test_input.data, + sek_params, + n_tiles, + tile_size, + result.first, + result.second, + n_reg); + } + const auto predict_time = predict_timer.elapsed(); + finish_step("predict", predict_time); + + hpx::chrono::high_resolution_timer predict_with_uncertainty_timer; + if (enabled & (1 << 3)) + { + cpu::predict_with_uncertainty( + scheduler, + training_input.data, + training_output.data, + test_input.data, + sek_params, + n_tiles, + tile_size, + result.first, + result.second, + n_reg); + } + const auto predict_with_uncertainty_time = predict_with_uncertainty_timer.elapsed(); + finish_step("predict_with_uncertainty", predict_with_uncertainty_time); + + hpx::chrono::high_resolution_timer predict_with_full_cov_timer; + if (enabled & (1 << 4)) + { + cpu::predict_with_full_cov( + scheduler, + training_input.data, + training_output.data, + test_input.data, + sek_params, + n_tiles, + tile_size, + result.first, + result.second, + n_reg); + } + const auto predict_with_full_cov_time = predict_with_full_cov_timer.elapsed(); + finish_step("predict_with_full_cov", predict_with_full_cov_time); + + // Save parameters and times to a .csv file with a header + const auto &csv_path = vm["output_csv"].as(); + const std::string csv_header = + "Cores,Localities,N_train,N_test,N_tiles,N_regressor,Opt_iter,Total_time,Init_time," + "Cholesky_time,Opt_time,Pred_Uncer_time,Pred_Full_time,Pred_time,N_loop"; + + std::ofstream outfile(csv_path, std::ios::app); + if (outfile.tellp() == 0) + { + // If file is empty, write the header + outfile << csv_header << "\n"; + } + else + { + // Guard against silently misaligned columns when appending to a file written + // by an older/different version of this binary. + std::ifstream existing(csv_path); + std::string existing_header; + std::getline(existing, existing_header); + if (existing_header != csv_header) + { + throw std::runtime_error("output_csv '" + csv_path + + "' already exists with a different column layout. Use a different " + "--output_csv path or remove the old file."); + } + } + outfile << hpx::get_locality_id() << "," << n_localities << "," << n_train << "," << n_test << "," + << n_tiles << "," << n_reg << "," << OPT_ITER << "," << total_timer.elapsed() << "," << init_time + << "," << cholesky_time << "," << opt_time << "," << predict_with_uncertainty_time << "," + << predict_with_full_cov_time << "," << predict_time << "," << l << "\n"; + outfile.close(); + + std::cerr << "====================" << std::endl; + } + } + std::cerr << "DONE!" << std::endl; +} + +void startup() +{ + std::cerr << "startup() called" << std::endl; + + static struct once_dummy_struct + { + once_dummy_struct() { register_performance_counters(); } + } once_dummy; +} + +bool check_startup(hpx::startup_function_type &startup_func, bool &pre_startup) +{ + // perform full module startup (counters will be used) + startup_func = startup; + pre_startup = true; + return true; +} + +GPRAT_NS_END + +HPX_REGISTER_STARTUP_MODULE(GPRAT_NS::check_startup) + +int hpx_main(hpx::program_options::variables_map &vm) +{ + // Debugging: dumps the full HPX runtime configuration (AGAS, logging, thread pools, etc.) + // hpx::get_runtime().get_config().dump(0, std::cerr); + std::cerr << "OS Threads: " << hpx::get_os_thread_count() << std::endl; + std::cerr << "All localities: " << hpx::get_num_localities().get() << std::endl; + std::cerr << "Root locality: " << hpx::find_root_locality() << std::endl; + std::cerr << "This locality: " << hpx::find_here() << std::endl; + std::cerr << "Remote localities: " << hpx::find_remote_localities().size() << std::endl; + + auto numa_domains = hpx::compute::host::numa_domains(); + std::cerr << "Local NUMA domains: " << numa_domains.size() << std::endl; + for (const auto &domain : numa_domains) + { + const auto &num_pus = domain.num_pus(); + std::cerr << " Domain: " << num_pus.first << " " << num_pus.second << std::endl; + } + + bool success = true; + try + { + GPRAT_NS::run(vm); + } + catch (const std::exception &e) + { + std::cerr << e.what() << std::endl; + success = false; + } + + // hpx::finalize() always returns 0 by design; report failure via hpx_main's own + // return value instead, since that is what hpx::init() ultimately propagates. + hpx::finalize(); + return success ? 0 : 1; +} + +int main(int argc, char *argv[]) +{ + namespace po = hpx::program_options; + po::options_description desc("Allowed options"); + + // Default to /output.csv, matching gprat_cpp's convention of writing + // its output next to the example sources regardless of the current working directory. + const std::string default_output_csv = (std::filesystem::path(GPRAT_DISTRIBUTED_DIR) / "output.csv").string(); + + // clang-format off + desc.add_options() + ("help", "produce help message") + ("train_x_path", po::value()->default_value("data/data_1024/training_input.txt"), "training data (x)") + ("train_y_path", po::value()->default_value("data/data_1024/training_output.txt"), "training data (y)") + ("test_path", po::value()->default_value("data/data_1024/test_input.txt"), "test data") + ("output_csv", po::value()->default_value(default_output_csv), "output timing reports") + ("tiles", po::value()->default_value(16), "tiles per dimension") + ("regressors", po::value()->default_value(8), "num regressors") + ("start", po::value()->default_value(128), "Starting number of training samples") + ("end", po::value()->default_value(128), "End number of training samples") + ("step", po::value()->default_value(2), "Increment of training samples") + ("n_test", po::value()->default_value(128), "Number of test samples") + ("loop", po::value()->default_value(1), "Number of iterations to be performed for each number of training samples") + ("opt_iter", po::value()->default_value(3), "Number of optimization iterations") + ("enabled", po::value()->default_value((std::numeric_limits::max)()), "Bitmask of enabled steps") + ; + // clang-format on + + hpx::init_params init_args; + init_args.desc_cmdline = desc; + // If example requires to run hpx_main on all localities + // std::vector const cfg = {"hpx.run_hpx_main!=1"}; + // init_args.cfg = cfg; + // Run HPX main + return hpx::init(argc, argv, init_args); +} diff --git a/examples/gprat_python/comment.txt b/examples/gprat_python/comment.txt deleted file mode 100644 index 68abe877..00000000 --- a/examples/gprat_python/comment.txt +++ /dev/null @@ -1,16 +0,0 @@ -Comments about configuration parameters. - -General Parameters - - "train_in_file": file path containing training control inputs, - "train_out_file": file path containing training outputs, - "test_in_file": file path containing test control inputs, - "test_out_file": file path containing test outputs, - "START": Starting number of training samples, - "END": End number of training samples, - "STEP": Increment of training samples, - "N_TILES": Number of tiles in one dimension, - "N_CORES": Number of cores to use for computation, - "N_TEST": Number of test samples, - "N_REG": Number of regressors, - "LOOP": Number of iterations to be performed for each number of training samples, - "OPT_ITER": Number of optimization iterations \ No newline at end of file diff --git a/examples/gprat_python/config.json b/examples/gprat_python/config.json index a42a4276..e99fcb69 100644 --- a/examples/gprat_python/config.json +++ b/examples/gprat_python/config.json @@ -1,15 +1,19 @@ { - "train_in_file": "../../data/data_1024/training_input.txt", - "train_out_file": "../../data/data_1024/training_output.txt", - "test_in_file": "../../data/data_1024/test_input.txt", - "test_out_file": "../../data/data_1024/test_output.txt", - "START": 512, - "END": 1024, + "TRAIN_IN_FILE": "../../data/data_1024/training_input.txt", + "TRAIN_OUT_FILE": "../../data/data_1024/training_output.txt", + "TEST_IN_FILE": "../../data/data_1024/test_input.txt", + "TEST_OUT_FILE": "../../data/data_1024/test_output.txt", + "TRAIN_SIZE_START": 512, + "TRAIN_SIZE_END": 1024, "STEP": 2, - "N_TILES": 16, - "N_CORES": 4, - "N_TEST": 1024, + "START_CORES": 1, + "END_CORES": 2, + "TEST_SIZE": 1024, + "SCALE_TEST_WITH_TRAIN": true, "N_REG": 8, + "OPT_ITER": 1, "LOOP": 2, - "OPT_ITER": 1 + "N_TILES_START": 1, + "N_TILES_END": 2, + "STEP_TILES": 2 } diff --git a/examples/gprat_python/execute.py b/examples/gprat_python/execute.py index 04a643a2..c986693f 100644 --- a/examples/gprat_python/execute.py +++ b/examples/gprat_python/execute.py @@ -1,178 +1,217 @@ +''' +GPRat with Python bindings reference implementation +''' + +# IMPORTS ############################################################################### + + +import time import logging import os import sys -import time -from csv import writer +import subprocess import argparse - -import lib.gprat as gprat -#import lib64.gprat as gprat # depending on system -#import gprat # if installed with pip - from config import get_config from hpx_logger import setup_logging +import gc + +# GPRat +import lib.gprat as gprat +# import lib64.gprat as gprat # depending on system +# import gprat # if installed with pip +# GLOBAL DEFINITIONS #################################################################### logger = logging.getLogger() log_filename = "./hpx_logs.log" parser = argparse.ArgumentParser() parser.add_argument( - "--use_gpu", + "--use-gpu", + action="store_true", + help="Flag to use GPU (assuming available)", +) +parser.add_argument( + "--optimize", action="store_true", help="Flag to use GPU (assuming available)", ) -args = parser.parse_args() -if args.use_gpu: - sys.argv.remove("--use_gpu") -use_gpu = gprat.compiled_with_cuda() and gprat.gpu_count() > 0 and args.use_gpu +args = parser.parse_args() +if args.use_gpu: + sys.argv.remove("--use-gpu") +if args.optimize: + sys.argv.remove("--optimize") + +if args.optimize and args.use_gpu: + print("Optimization is not implemented for GPU. Please run without --optimize flag.") + sys.exit(1) + +compiled_with_gpu = gprat.compiled_with_cuda() or gprat.compiled_with_sycl() + +if not compiled_with_gpu and args.use_gpu: + print("GPRat is not compiled with GPU support but GPU selected for execution.") + sys.exit(1) + +use_gpu = compiled_with_gpu and gprat.gpu_count() > 0 and args.use_gpu + +# GPRAT_RUN ############################################################################# +def gprat_run( + config, + output_file, + size_train, + size_test, + loop_index, + n_cores, + n_tiles, + is_warmup=False + ): + + print(f"Running GPRat with train size {size_train}, test size {size_test}, cores {n_cores}, tiles {n_tiles}, loop index {loop_index}.") + + target = "deadbeef" + opti_t = -1 + gp = None + + total_t = time.perf_counter() + + # Load data + load_t = time.perf_counter() + train_in = gprat.GP_data(config["TRAIN_IN_FILE"], size_train, config["N_REG"]) + train_out = gprat.GP_data(config["TRAIN_OUT_FILE"], size_train, config["N_REG"]) + test_in = gprat.GP_data(config["TEST_IN_FILE"], size_test, config["N_REG"]) + load_t = time.perf_counter() - load_t + + # CPU setup + if not use_gpu: + + target_query_time = time.perf_counter() -def gprat_run(config, output_csv_obj, n_train, l, cores): + cmd = "lscpu | grep 'Model name' | cut -f 2 -d ':' | awk '{$1=$1}1'" + result = subprocess.run(cmd, shell=True, capture_output=True, text=True) + target = result.stdout.strip() + "@HPX" + print("Running on: " + target) - n_tile_size = gprat.compute_train_tile_size(n_train, config["N_TILES"]) - m_tiles, m_tile_size = gprat.compute_test_tiles( - config["N_TEST"], config["N_TILES"], n_tile_size - ) - hpar = gprat.AdamParams(learning_rate=0.1, opt_iter=config["OPT_ITER"]) - train_in = gprat.GP_data(config["train_in_file"], n_train, config["N_REG"]) - train_out = gprat.GP_data( - config["train_out_file"], n_train, config["N_REG"] - ) - test_in = gprat.GP_data( - config["test_in_file"], config["N_TEST"], config["N_REG"] - ) + target_query_time = time.perf_counter() - target_query_time - total_t = time.time() + # Initialization + init_t = time.perf_counter() - if not use_gpu: + ## Tiles + n_tile_size = gprat.compute_train_tile_size(size_train, n_tiles) + m_tiles, m_tile_size = gprat.compute_test_tiles( + size_test, n_tiles, n_tile_size + ) - target = "cpu" + ## Hyperparameters + hpar = gprat.AdamParams(learning_rate=0.1, opt_iter=config["OPT_ITER"]) - ###### GP object ###### - init_t = time.time() - gp_cpu = gprat.GP( + ## GP object + gp = gprat.GP( train_in.data, train_out.data, - config["N_TILES"], + n_tiles, n_tile_size, kernel_params=[1.0, 1.0, 0.1], n_reg=config["N_REG"], - trainable=[True, True, True], + trainable=[True, True, True] ) - init_t = time.time() - init_t - # Init hpx runtime but do not start it yet - gprat.start_hpx(sys.argv, cores) + init_t = time.perf_counter() - init_t - # Perform optmization - opti_t = time.time() - losses = gp_cpu.optimize(hpar) - opti_t = time.time() - opti_t - logger.info("Finished optimization.") + # GPU setup + elif use_gpu: - # gprat.suspend_hpx() - # gprat.resume_hpx() + target_query_time = time.perf_counter() - # Predict - pred_uncer_t = time.time() - pr, var = gp_cpu.predict_with_uncertainty( - test_in.data, m_tiles, m_tile_size - ) - pred_uncer_t = time.time() - pred_uncer_t - logger.info("Finished predictions.") + cmd = "lshw -C display | grep \"product:\" | head -n1 | cut -d: -f2" + result = subprocess.run(cmd, shell=True, capture_output=True, text=True) + target = result.stdout.strip() - # Predict - pred_full_t = time.time() - pr__, var__ = gp_cpu.predict_with_full_cov( - test_in.data, m_tiles, m_tile_size - ) - pred_full_t = time.time() - pred_full_t - logger.info("Finished predictions with full cov.") + if gprat.compiled_with_cuda(): + target += "@CUDA" + elif gprat.compiled_with_sycl(): + target += "@SYCL" + + print("Running on: " + target) - # Predict - pred_t = time.time() - pr_ = gp_cpu.predict(test_in.data, m_tiles, m_tile_size) - pred_t = time.time() - pred_t - logger.info("Finished predictions.") + target_query_time = time.perf_counter() - target_query_time - else: + # Initialization - target = "gpu" + init_t = time.perf_counter() - ###### GP object ###### - init_t = time.time() - gp_gpu = gprat.GP( + ## Tiles + n_tile_size = gprat.compute_train_tile_size(size_train, n_tiles) + m_tiles, m_tile_size = gprat.compute_test_tiles( + size_test, n_tiles, n_tile_size + ) + + ## Hyperparameters + hpar = gprat.AdamParams(learning_rate=0.1, opt_iter=config["OPT_ITER"]) + + # GP object + gp = gprat.GP( train_in.data, train_out.data, - config["N_TILES"], + n_tiles, n_tile_size, kernel_params=[1.0, 1.0, 0.1], n_reg=config["N_REG"], trainable=[True, True, True], gpu_id=0, - n_streams=2, + n_units=1 ) - init_t = time.time() - init_t - # Init hpx runtime but do not start it yet - gprat.start_hpx(sys.argv, cores) + init_t = time.perf_counter() - init_t - # NOTE: optimization is not implemented for GPU - opti_t = -1 + # Execution - # gprat.suspend_hpx() - # gprat.resume_hpx() + gprat.start_hpx(sys.argv, n_cores) - # Predict - pred_uncer_t = time.time() - pr, var = gp_gpu.predict_with_uncertainty( - test_in.data, m_tiles, m_tile_size - ) - pred_uncer_t = time.time() - pred_uncer_t - logger.info("Finished predictions.") + # Perform optmization - # Predict - pred_full_t = time.time() - pr__, var__ = gp_gpu.predict_with_full_cov( - test_in.data, m_tiles, m_tile_size - ) - pred_full_t = time.time() - pred_full_t - logger.info("Finished predictions with full cov.") + if args.optimize: + opti_t = time.perf_counter() + losses = gp.optimize(hpar) + opti_t = time.perf_counter() - opti_t + + # Predict without uncertainty + pred_t = time.perf_counter() + pr_ = gp.predict(test_in.data, m_tiles, m_tile_size) + pred_t = time.perf_counter() - pred_t + + # Predict with uncertainty + pred_uncer_t = time.perf_counter() + pr, var = gp.predict_with_uncertainty( + test_in.data, m_tiles, m_tile_size + ) + pred_uncer_t = time.perf_counter() - pred_uncer_t - # Predict - pred_t = time.time() - pr_ = gp_gpu.predict(test_in.data, m_tiles, m_tile_size) - pred_t = time.time() - pred_t - logger.info("Finished predictions.") + # Predict with full covariance + pred_full_t = time.perf_counter() + pr__, var__ = gp.predict_with_full_cov( + test_in.data, m_tiles, m_tile_size + ) + pred_full_t = time.perf_counter() - pred_full_t # Stop HPX runtime gprat.stop_hpx() - total_t = time.time() - total_t + total_t = time.perf_counter() - total_t - target_query_time # config and measurements - row_data = [ - target, - cores, - n_train, - config["N_TEST"], - config["N_TILES"], - config["N_REG"], - config["OPT_ITER"], - init_t, - -1, # NOTE: optimization is not implemented for GPU - total_t, - pred_uncer_t, - pred_full_t, - pred_t, - l, - ] - output_csv_obj.writerow(row_data) - - logger.info("Completed iteration.") + row_data = \ + f"{target},{n_cores},{n_tiles},{size_train},{size_test},{config['N_REG']}," \ + f"{config['OPT_ITER']},{total_t},{load_t},{init_t},{opti_t},{pred_t}," \ + f"{pred_uncer_t},{pred_full_t},{loop_index}\n" + if not is_warmup: + output_file.write(row_data) + logger.info(row_data) + +# EXECUTE ############################################################################### def execute(): """ Execute the main process: @@ -183,55 +222,69 @@ def execute(): - Iterate through different training sizes and for each training size """ - # setup logging - setup_logging(log_filename, True, logger) - # load config logger.info("\n") logger.info("-" * 40) logger.info("Load config file.") config = get_config() - # append log to ./output.csv - file_exists = os.path.isfile("./output.csv") - output_file = open("./output.csv", "a", newline="") - output_csv_obj = writer(output_file) - - # write headers - if not file_exists: - logger.info("Write output file header") - header = [ - "Target", - "Cores", - "N_train", - "N_test", - "N_TILES", - "N_regressor", - "Opt_iter", - "Init_time", - "Optimization_Time", - "Pred_Var_time", - "Pred_Full_time", - "Predict_time", - "N_loop", - ] - output_csv_obj.writerow(header) - - # runs tests on exponentially increasing number of cores and - # data size, for multiple loops (each loop starts with *s) - cores = 2 - while cores <= config["N_CORES"]: - data_size = config["START"] - while data_size <= config["END"]: - for l in range(config["LOOP"]): - logger.info("*" * 40) - logger.info( - f"Core: {cores}, Train Size: {data_size}, Loop: {l}" - ) - gprat_run(config, output_csv_obj, data_size, l, cores) - data_size = data_size * config["STEP"] - cores = cores * 2 + file_path = "./output.csv" + file_exists = os.path.isfile(file_path) + + with open(file_path, "a") as output_file: + + if not file_exists or os.stat(file_path).st_size == 0: + logger.info( + "Target,Cores,N_tiles,N_train,N_test,N_regressor,Opt_iter,Total_time,Load_time,"\ + "Init_time,Opt_Time,Predict_time,Pred_Uncer_time,Pred_Full_time,N_loop" + ) + header = \ + "Target,Cores,N_tiles,N_train,N_test,N_regressor,Opt_iter,Total_time,Load_time,"\ + "Init_time,Opt_Time,Predict_time,Pred_Uncer_time,Pred_Full_time,N_loop\n" + output_file.write(header) + + # Perform warmup run + gprat_run(config, output_file, config['TRAIN_SIZE_END'], config['TRAIN_SIZE_END'], 0, + config['END_CORES'], config['N_TILES_END'], True) + test_scale_factor = config['STEP'] if config['SCALE_TEST_WITH_TRAIN'] else 1 + cores = config["START_CORES"] + + while cores <= config['END_CORES']: + + n_tiles = config['N_TILES_START'] + + while n_tiles <= config['N_TILES_END']: + + # Set train and test sizes + data_size = config['TRAIN_SIZE_START'] if config['TRAIN_SIZE_START'] >= n_tiles \ + else n_tiles + test_size = config['TEST_SIZE'] if not config['SCALE_TEST_WITH_TRAIN'] \ + else data_size + + # Loop over training data sizes + while data_size <= config['TRAIN_SIZE_END']: + + # Loop over different test iterations + for loop_index in range(config["LOOP"]): + logger.info("*" * 40) + logger.info(f"Cores: {cores}, Train Size: {data_size}, Loop: {loop_index}") + gc.collect() + gprat_run(config, output_file, data_size, test_size, loop_index, cores, n_tiles) + + # Update sizes + data_size = data_size * config['STEP'] + test_size = test_size * test_scale_factor + + n_tiles *= config['STEP_TILES'] + + cores *= 2 + + logger.info("Completed the program.") + + +# MAIN ################################################################################## if __name__ == "__main__": + setup_logging(log_filename, True, logger) execute() diff --git a/examples/gprat_python/run_gprat_python.sh b/examples/gprat_python/run_gprat_python.sh index 5add1c7e..6ad8d6b8 100755 --- a/examples/gprat_python/run_gprat_python.sh +++ b/examples/gprat_python/run_gprat_python.sh @@ -1,28 +1,177 @@ #!/bin/bash +# Input $1: Specify how GPRat was compiled, options: cpu/cuda/sycl +# Input $2: If GPRat was compiled with SYCL backend: nvidia/amd/intel + +# Set --use-gpu flag +if [[ -z "$1" ]]; then + echo "Input parameter is missing. Using default: Run computations on CPU" + GPU="" +elif [[ "$1" == "cuda" || "$1" == "sycl" ]]; then + GPU="--use-gpu" + if [[ \ + "$HOSTNAME" != "simcl1n1" && \ + "$HOSTNAME" != "simcl1n2" && \ + "$HOSTNAME" != "simcl1n3" && \ + "$HOSTNAME" != "simcl1n4" ]]; + then + echo "GPU execution with this script is only supported on simcl1n1, simcl1n2, simcl1n3, and simcl1n4." 1>&2 + exit 1 + fi +elif [[ "$1" != "cpu" ]]; then + echo "Please specify input parameter: cpu/cuda/sycl" + exit 1 +fi + +### SVEN0 AND SVEN1 ############################################################################### + +# Setup LD_LIBRARY_PATH on sven0 and sven1 +if [[ $(hostname -s) == "sven0" || $(hostname -s) == "sven1" ]]; then -if [[ $(hostname -s) == "sven0" || $(hostname -s) == "sven1" ]] -then export LD_LIBRARY_PATH=$HOME/git_workspace/build-scripts/build/hpx/lib64:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=$HOME/git_workspace/build-scripts/build/boost/lib:$LD_LIBRARY_PATH export LD_PRELOAD=$HOME/git_workspace/build-scripts/build/jemalloc/lib/libjemalloc.so.2 -elif [[ $(hostname) == "simcl1n1" || $(hostname) == "simcl1n2" ]]; then - # Check if the gprat_gpu_clang environment exists - if spack env list | grep -q "gprat_gpu_clang"; then - echo "Found gprat_gpu_clang environment, activating it." - module load cuda/12.0.1 - spack env activate gprat_gpu_clang - LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH - LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH - LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + +fi + +### SIMCL1N1, SIMCL1N2, SIMCL1N3, SIMCL1N4 ######################################################## + +if [[ \ + "$HOSTNAME" == "simcl1n1" || \ + "$HOSTNAME" == "simcl1n2" || \ + "$HOSTNAME" == "simcl1n3" || \ + "$HOSTNAME" == "simcl1n4" ]]; +then + + # Setup Spack + spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" + source $spack_destination/spack/share/spack/setup-env.sh + + # GPU setup + if [[ "$1" == "cuda" || "$1" == "sycl" ]]; then + + # simcl1n4 does not have a GPU + if [[ "$HOSTNAME" == "simcl1n4" ]]; then + echo "Machine $HOSTNAME does not have a GPU but you selected GPU execution." 1>&2 + exit 1 + fi + + # Check if the gprat_gpu_clang environment exists + if spack env list | grep -q "gprat_gpu_clang"; then + + echo "Found gprat_gpu_clang environment, activating it." + spack env activate gprat_gpu_clang + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + + fi + + if [[ "$1" == "cuda" || ( "$1" == "sycl" && "$2" == "nvidia" ) ]]; then + + module load cuda/12.0.1 + module load clang/17.0.1 + + fi + + if [[ "$1" == "sycl" ]]; then + + # Add oneMath installation to LD_LIBRARY_PATH if gpu is specified + if [[ "$2" == "nvidia" ]]; then + + ONEMATH_PATH="/scratch-simcl1/grafml/Programs/oneMath_nvidia/oneMath/install/lib/" + LD_LIBRARY_PATH="$ONEMATH_PATH:$LD_LIBRARY_PATH" + + elif [[ "$2" == "amd" ]]; then + + ONEMATH_PATH="/scratch-simcl1/grafml/Programs/oneMath_amd/oneMath/install/lib/" + LD_LIBRARY_PATH="$ONEMATH_PATH:$LD_LIBRARY_PATH" + + # ROCm runtime libraries + ROCM_PATH=${ROCM_PATH:-/opt/rocm-6.4.0} + if [[ -d "$ROCM_PATH" ]]; then + export LD_LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib64:$ROCM_PATH/hip/lib:$LD_LIBRARY_PATH" + export ROCM_PATH + fi + + # Compatibility shim: libamd_comgr.so.2 → libamd_comgr.so.3 for icpx HIP adapter + COMGR_COMPAT_DIR="/data/scratch-simcl1/breyerml/Programs/.modulefiles/icpx" + if [[ -d "$COMGR_COMPAT_DIR" ]]; then + export LD_LIBRARY_PATH="$COMGR_COMPAT_DIR:$LD_LIBRARY_PATH" + fi + + # Intel oneAPI compiler runtime libraries (needed by SYCL AMD shared objects) + ONEAPI_SETVARS="/import/sgs.scratch-simcl1/breyerml/Programs/spack/opt/spack/linux-zen4/intel-oneapi-compilers-2025.1.1-5ynklzzqslh265azbglzqdtecdghl7ob/setvars.sh" + if ! command -v icpx &>/dev/null && [[ -f "$ONEAPI_SETVARS" ]]; then + ONEAPI_COMPILER_ROOT="$(dirname $ONEAPI_SETVARS)/compiler/2025.1" + export PATH="$ONEAPI_COMPILER_ROOT/bin:$PATH" + export LD_LIBRARY_PATH="$ONEAPI_COMPILER_ROOT/lib:$LD_LIBRARY_PATH" + elif command -v icpx &>/dev/null; then + ONEAPI_COMPILER_ROOT="$(dirname $(dirname $(which icpx)))" + export LD_LIBRARY_PATH="$ONEAPI_COMPILER_ROOT/lib:$LD_LIBRARY_PATH" + fi + + export HSA_XNACK=1 + + elif [[ "$2" == "intel" ]]; then + + echo "Machine $HOSTNAME does not have an Intel GPU." 1>&2 + exit 1 + + elif [[ "$2" != "nvidia" ]]; then + + echo "Please specify gpu vendor: nvidia/amd/intel" + exit 1 + + fi + + fi + + # CPU setup + elif [[ "$1" == "cpu" ]]; then + + if spack env list | grep -q "gprat_cpu_gcc"; then + echo "Found gprat_cpu_gcc environment, activating it." + spack env activate gprat_cpu_gcc + module load gcc/14.1.0 + LD_LIBRARY_PATH=$(spack location -i hpx)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i openblas)/lib:$LD_LIBRARY_PATH + LD_LIBRARY_PATH=$(spack location -i intel-oneapi-mkl)/lib:$LD_LIBRARY_PATH + fi + fi + fi -if [[ -z "$1" ]]; then - echo "Input parameter is missing. Using default: Run computations on CPU" -elif [[ "$1" == "gpu" ]]; then - GPU="--use_gpu" -elif [[ "$1" != "cpu" ]]; then - echo "Please specify input parameter: cpu/gpu" - exit 1 +### PCSGS04 ####################################################################################### + +if [[ $(hostname) == "pcsgs04" ]]; then + + echo "The Intel setup is not supported yet." 1>&2 + exit 1 + +fi + +### INSTALL MATCHING GPRAT BUILD ################################################################## + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +GPRAT_ROOT="$SCRIPT_DIR/../.." + +if [[ "$1" == "cuda" ]]; then + GPRAT_BUILD_DIR="$GPRAT_ROOT/build/release-linux-cuda" +elif [[ "$1" == "sycl" ]]; then + GPRAT_BUILD_DIR="$GPRAT_ROOT/build/release-linux-sycl" +else + GPRAT_BUILD_DIR="$GPRAT_ROOT/build/release-linux" fi -python3 execute.py $GPU + +cmake --install "$GPRAT_BUILD_DIR" --prefix "$SCRIPT_DIR" +cp "$GPRAT_BUILD_DIR"/bindings/gprat.cpython-*.so "$SCRIPT_DIR/lib/" + +### EXECUTION ##################################################################################### + +cd "$SCRIPT_DIR" + +end_cores=$(python3 -c "import json; print(json.load(open('config.json'))['END_CORES'])") +core_count=$((end_cores * 2)) + +taskset -c 0-$core_count:2 python execute.py $GPU diff --git a/examples/gpytorch_reference/comment.txt b/examples/gpytorch_reference/comment.txt deleted file mode 100644 index f3e79798..00000000 --- a/examples/gpytorch_reference/comment.txt +++ /dev/null @@ -1,15 +0,0 @@ -Comments about configuration parameters. - -General Parameters - - "train_in_file": file path containing training control inputs, - "train_out_file": file path containing training outputs, - "test_in_file": file path containing test control inputs, - "test_out_file": file path containing test outputs, - "START": Starting number of training samples, - "END": End number of training samples, - "STEP": Increment of training samples, - "N_CORES": Number of cores to use for computation, - "N_TEST": Number of test samples, - "N_REG": Number of regressors, - "LOOP": Number of iterations to be performed for each number of training samples, - "PRECISION": Set floating-point type used by gpytorch \ No newline at end of file diff --git a/examples/gpytorch_reference/config.json b/examples/gpytorch_reference/config.json index c1137a0b..827c0ce1 100644 --- a/examples/gpytorch_reference/config.json +++ b/examples/gpytorch_reference/config.json @@ -1,16 +1,17 @@ { - "train_in_file": "../../data/data_1024/training_input.txt", - "train_out_file": "../../data/data_1024/training_output.txt", - "test_in_file": "../../data/data_1024/test_input.txt", - "test_out_file": "../../data/data_1024/test_output.txt", - "START": 512, - "END": 1024, + "TRAIN_IN_FILE": "../../data/data_1024/training_input.txt", + "TRAIN_OUT_FILE": "../../data/data_1024/training_output.txt", + "TEST_IN_FILE": "../../data/data_1024/test_input.txt", + "TEST_OUT_FILE": "../../data/data_1024/test_output.txt", + "TRAIN_SIZE_START": 512, + "TRAIN_SIZE_END": 1024, "STEP": 2, "START_CORES": 1, - "N_CORES": 4, - "N_TEST": 1024, + "END_CORES": 4, + "TEST_SIZE": 1024, + "SCALE_TEST_WITH_TRAIN": true, "N_REG": 8, - "LOOP": 2, "PRECISION": "float64", - "OPT_ITER": 1 + "OPT_ITER": 1, + "LOOP": 2 } diff --git a/examples/gpytorch_reference/execute.py b/examples/gpytorch_reference/execute.py index 1331abd7..0e5d1fbf 100644 --- a/examples/gpytorch_reference/execute.py +++ b/examples/gpytorch_reference/execute.py @@ -1,14 +1,20 @@ +''' +Reference implementation for Gaussian process regression using GPyTorch. +''' + +# Imports import time import logging import torch import gpytorch import os import argparse - from config import get_config from gpytorch_logger import setup_logging -from utils import load_data, ExactGPModel, train, predict, predict_with_var +from utils import load_data, ExactGPModel, predict_with_full_cov, train, predict, predict_with_var +import gc +# Global definitions logger = logging.getLogger() log_filename = "./gpytorch_logs.log" @@ -18,73 +24,137 @@ action="store_true", help="Flag to use GPU (assuming available)", ) + args = parser.parse_args() +def get_device(use_gpu): + """ + Returns a tuple containing + - a device object corrsponding to user preference if available, and the CPU + otherwise + - a string representation of the device + + Args: + use_gpu (bool): whether to use GPU or not if available + + Returns: + tuple: a tuple of a device and a string + """ + if not use_gpu: + return torch.device("cpu"), "cpu" + + # NVIDIA CUDA or AMD ROCm + if torch.cuda.is_available(): + return torch.device("cuda"), torch.cuda.get_device_name(0) -def gpytorch_run(config, output_file, size_train, l, cores): + # Intel GPU + if hasattr(torch, "xpu") and torch.xpu.is_available(): + return torch.device("xpu"), torch.xpu.get_device_name(0) + + return torch.device("cpu"), "cpu" + + +def sync_if_needed(device): + if device.type == "cuda": + torch.cuda.synchronize() + if device.type == "xpu": + torch.xpu.synchronize() + + +def gpytorch_run( + config, output_file, size_train, size_test, loop_index, cores, device, target, \ + is_warmup=False + ): """ Run the Gaussian process regression pipeline. Args: - config (dict): Configuration parameters for the pipeline. - output_csv_obj (csv.writer): CSV writer object for writing output data. - size_train (int): Size of the training dataset. - l (int): Loop index. + config (dict): Configuration parameters for the pipeline. + output_csv_obj (csv.writer): CSV writer object for writing output data. + size_train (int): Size of the training dataset. + size_test (int): Size of the test dataset. + loop_index (int): Loop index. + cores (int): Number of CPU cores to use. + device (torch.device): Device to use for computation. + target (str): Target device name. + is_warmup (bool): Flag to indicate if this is a warmup run. """ - total_t = time.time() - target = "gpu" if args.use_gpu and torch.cuda.is_available() else "cpu" - device = torch.device("cuda" if args.use_gpu and torch.cuda.is_available() else "cpu") + total_t = time.perf_counter() + + # Load data + load_t = time.perf_counter() X_train, Y_train, X_test, Y_test = load_data( - train_in_path=config["train_in_file"], - train_out_path=config["train_out_file"], - test_in_path=config["test_in_file"], - test_out_path=config["test_out_file"], + train_in_path=config["TRAIN_IN_FILE"], + train_out_path=config["TRAIN_OUT_FILE"], + test_in_path=config["TEST_IN_FILE"], + test_out_path=config["TEST_OUT_FILE"], size_train=size_train, - size_test=config["N_TEST"], - n_regressors=config["N_REG"], + size_test=size_test, + n_regressors=config["N_REG"] ) - if args.use_gpu and torch.cuda.is_available(): - X_train, Y_train, X_test, Y_test = X_train.to(device), Y_train.to(device), X_test.to(device), Y_test.to(device) - - # logger.info("Finished loading the data.") - - init_t = time.time() + if args.use_gpu and device.type != "cpu": + X_train, Y_train, X_test, Y_test = \ + X_train.to(device), Y_train.to(device), X_test.to(device), Y_test.to(device) + sync_if_needed(device) + load_t = time.perf_counter() - load_t + + # Initialize model + init_t = time.perf_counter() likelihood = gpytorch.likelihoods.GaussianLikelihood() likelihood.noise = 0.1 model = ExactGPModel(X_train, Y_train, likelihood) - if args.use_gpu and torch.cuda.is_available(): + if args.use_gpu and device.type != "cpu": model = model.to(device) likelihood = likelihood.to(device) - init_t = time.time() - init_t - # logger.info("Initialized model.") + sync_if_needed(device) + init_t = time.perf_counter() - init_t - train_t = time.time() + # Train model + train_t = time.perf_counter() train(model, likelihood, X_train, Y_train, training_iter=config['OPT_ITER']) - train_t = time.time() - train_t - # logger.info("Trained model.") - - pred_var_t = time.time() - f_pred, f_var = predict_with_var(model, likelihood, X_test) - pred_var_t = time.time() - pred_var_t - # logger.info("Finished making predictions.") - - pred_t = time.time() + sync_if_needed(device) + train_t = time.perf_counter() - train_t + + # Make predictions with full covariance matrix + pred_full_t = time.perf_counter() + f_pred_full, f_var_full = predict_with_full_cov(model, likelihood, X_test) + sync_if_needed(device) + pred_full_t = time.perf_counter() - pred_full_t + + # Make predictions with uncertainty + pred_var_t = time.perf_counter() + predict_with_var(model, likelihood, X_test) + sync_if_needed(device) + pred_var_t = time.perf_counter() - pred_var_t + + # Make predictions without uncertainty + pred_t = time.perf_counter() f_pred = predict(model, likelihood, X_test) - pred_t = time.time() - pred_t - # logger.info("Finished making predictions.") + sync_if_needed(device) + pred_t = time.perf_counter() - pred_t - TOTAL_TIME = time.time() - total_t + # Assign runtimes + TOTAL_TIME = time.perf_counter() - total_t + LOAD_TIME = load_t INIT_TIME = init_t OPT_TIME = train_t + PRED_FULL_TIME = pred_full_t PRED_UNCER_TIME = pred_var_t PREDICTION_TIME = pred_t - # ERROR = calculate_error(Y_test, y_pred).detach().cpu().numpy() - row_data = f"{target},{cores},{size_train},{config['N_TEST']},{config['N_REG']},{config['OPT_ITER']},{TOTAL_TIME},{INIT_TIME},{OPT_TIME},{PREDICTION_TIME},{l}\n" - output_file.write(row_data) + if not is_warmup: + + row_data = \ + f"{target},{cores},{size_train},{size_test},{config['N_REG']},"\ + f"{config['OPT_ITER']},{TOTAL_TIME},{LOAD_TIME},{INIT_TIME},{OPT_TIME},"\ + f"{PRED_FULL_TIME},{PRED_UNCER_TIME},{PREDICTION_TIME},{loop_index}\n" + output_file.write(row_data) - logger.info(f"{cores},{size_train},{config['N_TEST']},{config['N_REG']},{config['OPT_ITER']},{TOTAL_TIME},{INIT_TIME},{OPT_TIME},{PRED_UNCER_TIME},{PREDICTION_TIME},{l}") - #logger.info("Completed iteration.") + logger.info( + f"{target},{cores},{size_train},{size_test},{config['N_REG']},"\ + f"{config['OPT_ITER']},{TOTAL_TIME},{LOAD_TIME},{INIT_TIME},{OPT_TIME},"\ + f"{PRED_FULL_TIME},{PRED_UNCER_TIME},{PREDICTION_TIME},{loop_index}\n" + ) def execute(): @@ -97,7 +167,9 @@ def execute(): - Iterate through different training sizes and for each training size loop for a specified amount of times while executing `gpytorch_run` function. """ - setup_logging(log_filename, True, logger) + + torch.set_num_interop_threads(1) + logger.info("\n") logger.info("-" * 40) logger.info("Load config file.") @@ -108,30 +180,64 @@ def execute(): with open(file_path, "a") as output_file: if not file_exists or os.stat(file_path).st_size == 0: - # logger.info("Write output file header") - logger.info("Target,Cores,N_train,N_test,N_reg,Opt_iter,Total_time,Init_time,Opt_Time,Pred_Var_time,Pred_time,N_loop") - header = "Target,Cores,N_train,N_test,N_regressor,Opt_iter,Total_time,Init_time,Opt_time,Pred_Uncer_time,Predict_time,N_loop\n" + logger.info( + "Target,Cores,N_train,N_test,N_regressor,Opt_iter,Total_time,Load_time,"\ + "Init_time,Opt_Time,Pred_Full_time,Pred_Uncer_time,Predict_time,N_loop" + ) + header = \ + "Target,Cores,N_train,N_test,N_regressor,Opt_iter,Total_time,Load_time,"\ + "Init_time,Opt_Time,Pred_Full_time,Pred_Uncer_time,Predict_time,N_loop\n" output_file.write(header) - if config["PRECISION"] == "float32": - torch.set_default_dtype(torch.float32) + if config["PRECISION"] == "float128": + torch.set_default_dtype(torch.float128) else: torch.set_default_dtype(torch.float64) - # runs tests on exponentially increasing number of cores and - # data size, for multiple loops (each loop starts with *s) - torch.set_num_threads(config["N_CORES"]) + device, target = get_device(args.use_gpu) + test_scale_factor = config["STEP"] if config["SCALE_TEST_WITH_TRAIN"] else 1 + + gpytorch_run(config, output_file, config["TRAIN_SIZE_END"], \ + config["TRAIN_SIZE_END"], 0, config["END_CORES"], device, \ + target, True) + cores = config["START_CORES"] - while cores <= config["N_CORES"]: - data_size = config["START"] - while data_size <= config["END"]: - for l in range(config["LOOP"]): + + while cores <= config["END_CORES"]: + + torch.set_num_threads(cores) + + data_size = config["TRAIN_SIZE_START"] + test_size = config["TEST_SIZE"] if not config["SCALE_TEST_WITH_TRAIN"] \ + else config["TRAIN_SIZE_START"] + + # Loop over training data sizes + while data_size <= config["TRAIN_SIZE_END"]: + + # Loop over different test iterations + for loop_index in range(config["LOOP"]): + + # Loop to create test runs logger.info("*" * 40) - logger.info(f"Core: {cores}, Train Size: {data_size}, Loop: {l}") - gpytorch_run(config, output_file, data_size, l, cores) + logger.info( + f"Cores: {cores}, Train Size: {data_size}, Loop: {loop_index}" + ) + gc.collect() + if not target == "cpu": + torch.cuda.empty_cache() + gpytorch_run( + config, output_file, data_size, test_size, loop_index, cores, + device, target + ) + + # Update sizes data_size = data_size * config["STEP"] - cores = cores * 2 - logger.info("Completed the program.") + test_size = test_size * test_scale_factor + + cores *= 2 + + logger.info("Completed the program.") + def is_mkl_enabled(): torch_config = torch.__config__.show() @@ -139,7 +245,8 @@ def is_mkl_enabled(): value = torch_config[index+8:index+10] return True if value == 'ON' else False + if __name__ == "__main__": - # check if Intel oneAPI MKL is enabled + setup_logging(log_filename, True, logger) print("","-" * 18, "\n", "MKL enabled:", is_mkl_enabled(), "\n", "-" * 18) execute() diff --git a/examples/gpytorch_reference/requirements/requirements_gpytorch_amd.txt b/examples/gpytorch_reference/requirements/requirements_gpytorch_amd.txt new file mode 100644 index 00000000..6841e82c --- /dev/null +++ b/examples/gpytorch_reference/requirements/requirements_gpytorch_amd.txt @@ -0,0 +1,14 @@ +filelock==3.25.2 +fsspec==2026.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +mpmath==1.3.0 +networkx==3.4.2 +numpy==2.2.6 +packaging==26.0 +pillow==12.1.1 +pytorch-triton-rocm==3.5.1 +sympy==1.14.0 +torch==2.9.1+rocm6.4 +torchvision==0.24.1+rocm6.4 +typing_extensions==4.15.0 diff --git a/examples/gpytorch_reference/requirements/requirements_gpytorch_cpu.txt b/examples/gpytorch_reference/requirements/requirements_gpytorch_cpu.txt new file mode 100644 index 00000000..4f37ac64 --- /dev/null +++ b/examples/gpytorch_reference/requirements/requirements_gpytorch_cpu.txt @@ -0,0 +1,37 @@ +cuda-bindings==13.2.0 +cuda-pathfinder==1.5.0 +cuda-toolkit==13.0.2 +filelock==3.25.2 +fsspec==2026.3.0 +gpytorch==1.13 +jaxtyping==0.2.19 +Jinja2==3.1.6 +joblib==1.5.3 +linear_operator==0.6.1 +MarkupSafe==3.0.3 +mpmath==1.3.0 +networkx==3.4.2 +numpy==2.2.6 +nvidia-cublas==13.1.0.3 +nvidia-cuda-cupti==13.0.85 +nvidia-cuda-nvrtc==13.0.88 +nvidia-cuda-runtime==13.0.96 +nvidia-cudnn-cu13==9.19.0.56 +nvidia-cufft==12.0.0.61 +nvidia-cufile==1.15.1.6 +nvidia-curand==10.4.0.35 +nvidia-cusolver==12.0.4.66 +nvidia-cusparse==12.6.3.3 +nvidia-cusparselt-cu13==0.8.0 +nvidia-nccl-cu13==2.28.9 +nvidia-nvjitlink==13.0.88 +nvidia-nvshmem-cu13==3.4.5 +nvidia-nvtx==13.0.85 +scikit-learn==1.7.2 +scipy==1.15.3 +sympy==1.14.0 +threadpoolctl==3.6.0 +torch==2.11.0 +triton==3.6.0 +typeguard==4.5.1 +typing_extensions==4.15.0 diff --git a/examples/gpytorch_reference/requirements/requirements_gpytorch_intel.txt b/examples/gpytorch_reference/requirements/requirements_gpytorch_intel.txt new file mode 100644 index 00000000..2b8e38b1 --- /dev/null +++ b/examples/gpytorch_reference/requirements/requirements_gpytorch_intel.txt @@ -0,0 +1,38 @@ +dpcpp-cpp-rt==2025.3.1 +filelock==3.20.0 +fsspec==2025.12.0 +impi-rt==2021.17.0 +intel-cmplr-lib-rt==2025.3.1 +intel-cmplr-lib-ur==2025.3.1 +intel-cmplr-lic-rt==2025.3.1 +intel-opencl-rt==2025.3.1 +intel-openmp==2025.3.1 +intel-pti==0.15.0 +intel-sycl-rt==2025.3.1 +Jinja2==3.1.6 +MarkupSafe==3.0.2 +mkl==2025.3.0 +mpmath==1.3.0 +networkx==3.6.1 +numpy==2.3.5 +oneccl==2021.17.1 +oneccl-devel==2021.17.1 +onemkl-license==2025.3.0 +onemkl-sycl-blas==2025.3.0 +onemkl-sycl-dft==2025.3.0 +onemkl-sycl-lapack==2025.3.0 +onemkl-sycl-rng==2025.3.0 +onemkl-sycl-sparse==2025.3.0 +packaging==26.0 +pillow==12.0.0 +pyelftools==0.32 +setuptools==82.0.1 +sympy==1.14.0 +tbb==2022.3.0 +tcmlib==1.4.1 +torch==2.10.0+xpu +torchvision==0.25.0+xpu +triton-xpu==3.6.0 +typing_extensions==4.15.0 +umf==1.0.2 +wheel==0.46.3 diff --git a/examples/gpytorch_reference/requirements/requirements_gpytorch_nvidia.txt b/examples/gpytorch_reference/requirements/requirements_gpytorch_nvidia.txt new file mode 100644 index 00000000..dc48b019 --- /dev/null +++ b/examples/gpytorch_reference/requirements/requirements_gpytorch_nvidia.txt @@ -0,0 +1,32 @@ +cuda-bindings==12.9.4 +cuda-pathfinder==1.2.2 +cuda-toolkit==12.6.3 +filelock==3.29.0 +fsspec==2026.4.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +mpmath==1.3.0 +networkx==3.4.2 +numpy==2.2.6 +nvidia-cublas-cu12==12.6.4.1 +nvidia-cuda-cupti-cu12==12.6.80 +nvidia-cuda-nvrtc-cu12==12.6.85 +nvidia-cuda-runtime-cu12==12.6.77 +nvidia-cudnn-cu12==9.10.2.21 +nvidia-cufft-cu12==11.3.0.4 +nvidia-cufile-cu12==1.11.1.6 +nvidia-curand-cu12==10.3.7.77 +nvidia-cusolver-cu12==11.7.1.2 +nvidia-cusparse-cu12==12.5.4.2 +nvidia-cusparselt-cu12==0.7.1 +nvidia-nccl-cu12==2.29.3 +nvidia-nvjitlink-cu12==12.6.85 +nvidia-nvshmem-cu12==3.4.5 +nvidia-nvtx-cu12==12.6.77 +packaging==26.2 +pillow==12.2.0 +sympy==1.14.0 +torch==2.12.0+cu126 +torchvision==0.27.0+cu126 +triton==3.7.0 +typing_extensions==4.15.0 diff --git a/examples/gpytorch_reference/run_gpytorch.sh b/examples/gpytorch_reference/run_gpytorch.sh index 7229f9d4..bf20bffc 100755 --- a/examples/gpytorch_reference/run_gpytorch.sh +++ b/examples/gpytorch_reference/run_gpytorch.sh @@ -1,5 +1,7 @@ #!/bin/bash # Input $1: Specify cpu/gpu/arm +# Input $2: Specify nvidia/amd/intel (only necessary if gpu is specified) + if [[ "$1" == "gpu" ]] then # Create & Activate python enviroment @@ -8,14 +10,58 @@ then fi # Activate enviroment source gpytorch_gpu_env/bin/activate + python -m ensurepip --upgrade + # Install requirements if ! python -c "import gpytorch"; then + + pip install --upgrade pip setuptools wheel + + if [[ "$2" == "nvidia" ]]; then ########################################################### + + pip3 install --no-cache-dir torch torchvision \ + --index-url https://download.pytorch.org/whl/cu126 + + pip freeze > requirements/requirements_gpytorch_nvidia.txt + + elif [[ "$2" == "amd" ]]; then ############################################################ + + pip3 install --no-cache-dir torch torchvision \ + --index-url https://download.pytorch.org/whl/rocm6.4 + + pip freeze > requirements/requirements_gpytorch_amd.txt + + elif [[ "$2" == "intel" ]]; then ########################################################## + + export PYTORCH_DEBUG_XPU_FALLBACK=1 + + # Careful: Intel pulls its own SYCL installation here, make sure no other is loaded! + pip install --no-cache-dir torch torchvision \ + --index-url https://download.pytorch.org/whl/xpu + + pip freeze > requirements/requirements_gpytorch_intel.txt + + elif [[ -z "$2" ]]; then #################################################################### + + echo "Please specify gpu type: nvidia/amd/intel" + exit 1 + + fi ######################################################################################## + pip install gpytorch==1.13 + fi - # Execute the python script + + export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True + python execute.py --use-gpu + elif [[ "$1" == "cpu" ]] then + + end_cores=$(python3 -c "import json; print(json.load(open('config.json'))['END_CORES'])") + core_count=$((end_cores * 2)) + # Create & Activate python enviroment if [ ! -d "gpytorch_cpu_env" ]; then python -m venv gpytorch_cpu_env @@ -25,11 +71,14 @@ then # Install requirements if ! python -c "import gpytorch"; then pip install gpytorch==1.13 + pip freeze > requirements/requirements_gpytorch_cpu.txt fi - # Execute the python script - python execute.py + + taskset -c 0-$core_count:2 python execute.py + elif [[ "$1" == "arm" ]] then + spack load python@3.10 # Create & Activate python enviroment if [ ! -d "gpytorch_arm_env" ]; then @@ -40,10 +89,13 @@ then # Install requirements if ! python -c "import gpytorch"; then pip install gpytorch==1.13 + pip freeze > requirements/requirements_gpytorch_arm.txt fi - # Execute the python script python execute.py + else + echo "Please specify input parameter: cpu/gpu/arm" exit 1 + fi diff --git a/examples/gpytorch_reference/utils.py b/examples/gpytorch_reference/utils.py index 6f0f6b63..1012ab8e 100644 --- a/examples/gpytorch_reference/utils.py +++ b/examples/gpytorch_reference/utils.py @@ -143,6 +143,42 @@ def train(model, likelihood, X_train, Y_train, training_iter=10): return None +def predict_with_full_cov(model, likelihood, X_test): + """ + Predict the mean and full covariance matrix of latent function values and observed target values. + + Args: + model (gpytorch.models.ExactGP): The trained Gaussian process regression model. + likelihood (gpytorch.likelihoods.GaussianLikelihood): The likelihood function. + X_test (torch.Tensor): The test input data. + + Returns: + - f_mean (torch.Tensor): Mean of latent function values. + - f_var_matrix (torch.Tensor): Full covariance matrix of latent function values. + """ + model.eval() + likelihood.eval() + with (torch.no_grad(), \ + # Compute the exact posterior covariance + gpytorch.settings.fast_pred_var(False), \ + # Kernel matrices are computed immediately, not lazily + gpytorch.settings.lazily_evaluate_kernels(False), \ + gpytorch.settings.fast_computations( + # Compute exact Cholesky + covar_root_decomposition=False, \ + # Compute the log-determinant exactly (via Cholesky) + log_prob=False, \ + # Use direct solver + solves=False) + ): + + f_pred = model(X_test) + f_mean = f_pred.mean + f_var_matrix = f_pred.covariance_matrix + + return f_mean, f_var_matrix + + def predict_with_var(model, likelihood, X_test): """ Predict the mean and variance of latent function values and observed target values. @@ -182,6 +218,7 @@ def predict_with_var(model, likelihood, X_test): return f_mean, f_var + def predict(model, likelihood, X_test): """ Predict the mean and variance of latent function values and observed target values. diff --git a/execute-benchmark.sh b/execute-benchmark.sh new file mode 100755 index 00000000..54497542 --- /dev/null +++ b/execute-benchmark.sh @@ -0,0 +1,166 @@ +#!/bin/bash + +set -e # Exit immediately if a command exits with a non-zero status. + +################################################################################################### +# Parameters +################################################################################################### +# $1: toggle gpflow yes/no +# $2: toggle gpytorch yes/no +# $3: toggle GPRat Cholesky yes/no +# $4: toggle GPRat Python yes/no +# $5: hardware cpu/gpu +# $6: vendor nvidia/amd/cpu +# $7: toggle GPRat CUDA/SYCL cuda/sycl only for NVIDIA GPUs + +# Set global variables +HARDWARE=$5 +VENDOR=$6 + +# Set variables relevant for GPRat +if [[ "$HARDWARE" == "cpu" ]]; then + + GPRAT_TARGET="cpu" + GPRAT_USE_GPU="" + BUILD_DIR="build/release-linux" + +elif [[ "$HARDWARE" == "gpu" ]]; then + + GPRAT_USE_GPU="--use-gpu" + + if [[ "$VENDOR" == "nvidia" ]]; then + + if [[ "$7" == "cuda" ]]; then + + GPRAT_TARGET="cuda" + BUILD_DIR="build/release-linux-cuda" + + elif [[ "$7" == "sycl" ]]; then + + GPRAT_TARGET="sycl" + BUILD_DIR="build/release-linux-sycl" + + else + + echo -e "\e[31mUnsupported GPRat target: ${5}\e[0m" + exit 1 + + fi + + elif [[ "$VENDOR" == "amd" ]]; then + + GPRAT_TARGET="sycl" + BUILD_DIR="build/release-linux-sycl" + + else + + echo -e "\e[31mUnsupported GPU vendor: ${VENDOR}\e[0m" + exit 1 + + fi + +else + + echo -e "\e[31mUnsupported hardware type: ${HARDWARE}\e[0m" + exit 1 + +fi + +# Build joined suffixes without double/trailing underscores when parts are empty +join_parts() { local IFS=_; echo "$*" | tr -s '_' | sed 's/^_//;s/_$//'; } +HARDWARE_VENDOR=$(join_parts "$HARDWARE" "$VENDOR") +VENDOR_TARGET=$(join_parts "$VENDOR" "$GPRAT_TARGET") + +# Create benchmark folder +mkdir -p benchmark_results_${HARDWARE_VENDOR} + +# GPflow +if [[ "$1" == "yes" ]]; then + echo -e "\e[32mRunning GPflow benchmarks on ${HARDWARE} ${VENDOR}...\e[0m" + + + cd examples/gpflow_reference + ./run_gpflow.sh ${HARDWARE} ${VENDOR} > /dev/null + cp output.csv ../../benchmark_results_${HARDWARE_VENDOR}/gpflow_${VENDOR_TARGET}.csv + rm -rf gpflow_${HARDWARE}_env + cd ../.. + +else + + echo -e "\e[33mSkipping GPflow benchmarks.\e[0m" + +fi + +# GPyTorch +if [[ "$2" == "yes" ]]; then + echo -e "\e[32mRunning GPyTorch benchmarks on ${HARDWARE} ${VENDOR}...\e[0m" + + cd examples/gpytorch_reference + ./run_gpytorch.sh ${HARDWARE} ${VENDOR} > /dev/null + cp output.csv ../../benchmark_results_${HARDWARE_VENDOR}/gpytorch_${VENDOR_TARGET}.csv + rm -rf gpytorch_${HARDWARE}_env + cd ../.. + +else + + echo -e "\e[33mSkipping GPyTorch benchmarks.\e[0m" + +fi + +# GPRat compile +if [[ "$3" == "yes" || $4 == "yes" ]]; then + + echo -e "\e[32mCompiling GPRat for ${VENDOR} ${HARDWARE} with ${GPRAT_TARGET} target...\e[0m" + + rm -rf build + + ./compile_gprat.sh cpp $GPRAT_TARGET release mkl > /dev/null + ./compile_gprat.sh python $GPRAT_TARGET release mkl > /dev/null + +else + + echo -e "\e[33mNot compiling GPRat.\e[0m" + +fi + +# GPRat Cholesky +if [[ "$3" == "yes" ]]; then + echo -e "\e[32mRunning GPRat Cholesky benchmarks on ${VENDOR} ${HARDWARE} with ${GPRAT_TARGET} target...\e[0m" + + cd examples/gprat_cpp + end_cores=$(python3 -c "import json; print(json.load(open('config.json'))['END_CORES'])") + core_count=$((end_cores * 2)) + cd ../.. + + cd ${BUILD_DIR}/examples/gprat_cpp/ + taskset -c 0-$core_count:2 ./gprat_cpp $GPRAT_USE_GPU > /dev/null + cp ../../../../examples/gprat_cpp/output.csv ../../../../benchmark_results_${HARDWARE_VENDOR}/gprat_cholesky_${VENDOR_TARGET}.csv + cd ../../../.. + +else + + echo -e "\e[33mSkipping GPRat Cholesky benchmarks.\e[0m" + +fi + +# GPRat Python +if [[ "$4" == "yes" ]]; then + echo -e "\e[32mRunning GPRat Python benchmarks on ${VENDOR} ${HARDWARE} with ${GPRAT_TARGET} target...\e[0m" + + cd examples/gprat_python + ./run_gprat_python.sh ${GPRAT_TARGET} ${VENDOR} > /dev/null + cp output.csv ../../benchmark_results_${HARDWARE_VENDOR}/gprat_python_${VENDOR_TARGET}.csv + cd ../.. + +else + + echo -e "\e[33mSkipping GPRat Python benchmarks.\e[0m" + +fi + +echo -e "\e[32mCopying results to home directory... \e[0m" +mkdir -p ${HOME}/GPRAT-BENCHMARKS + +cp -r benchmark_results_${HARDWARE_VENDOR}/ ${HOME}/GPRAT-BENCHMARKS/ + +echo -e "\e[32mDone.\e[0m" diff --git a/spack-repo/environments/setup_gprat_cpu_gcc.sh b/spack-repo/environments/setup_gprat_cpu_gcc.sh index fb45ecfc..cec9be16 100755 --- a/spack-repo/environments/setup_gprat_cpu_gcc.sh +++ b/spack-repo/environments/setup_gprat_cpu_gcc.sh @@ -17,13 +17,14 @@ else fi # Find GCC compiler with spack -source $HOME/spack/share/spack/setup-env.sh +spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" +source $spack_destination/spack/share/spack/setup-env.sh spack compiler find # Create environment and copy config file env_name=gprat_cpu_gcc spack env create $env_name -cp spack_cpu_gcc.yaml $HOME/spack/var/spack/environments/$env_name/spack.yaml +cp spack_cpu_gcc.yaml $spack_destination/spack/var/spack/environments/$env_name/spack.yaml spack env activate $env_name # Use external python diff --git a/spack-repo/environments/setup_gprat_cpu_gcc_dist.sh b/spack-repo/environments/setup_gprat_cpu_gcc_dist.sh new file mode 100755 index 00000000..b3aedbc0 --- /dev/null +++ b/spack-repo/environments/setup_gprat_cpu_gcc_dist.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -e +# Script to setup a CPU spack environment for GPRat's multi-locality distributed +# benchmark using a recent gcc. Unlike setup_gprat_cpu_gcc.sh, this builds HPX with +# networking=tcp (required for --hpx:localities > 1) instead of networking=none, and +# uses OpenBLAS instead of MKL since no MKL variant of this environment is maintained. + +# Load GCC compiler +module load gcc/14.1.0 +env_name=gprat_cpu_gcc_dist + +# Find GCC compiler with spack +spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" +source $spack_destination/spack/share/spack/setup-env.sh +spack compiler find + +# Create environment and copy config file +spack env create $env_name +cp spack_cpu_gcc_dist.yaml $spack_destination/spack/var/spack/environments/$env_name/spack.yaml +spack env activate $env_name + +# Use external python +spack external find python + +# setup environment +spack concretize -f +spack install diff --git a/spack-repo/environments/setup_gprat_gpu_clang.sh b/spack-repo/environments/setup_gprat_gpu_clang.sh index 2a9d58f2..c9203057 100755 --- a/spack-repo/environments/setup_gprat_gpu_clang.sh +++ b/spack-repo/environments/setup_gprat_gpu_clang.sh @@ -4,9 +4,11 @@ set -e # Script to setup GPU spack environment for GPRat on simcl1n1-2 # Create environment and copy config file -source $HOME/spack/share/spack/setup-env.sh +spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" +source $spack_destination/spack/share/spack/setup-env.sh + spack env create gprat_gpu_clang -cp spack_gpu_clang.yaml $HOME/spack/var/spack/environments/gprat_gpu_clang/spack.yaml +cp spack_gpu_clang.yaml $spack_destination/spack/var/spack/environments/gprat_gpu_clang/spack.yaml spack env activate gprat_gpu_clang # Find external compiler diff --git a/spack-repo/environments/spack_cpu_gcc.yaml b/spack-repo/environments/spack_cpu_gcc.yaml index c6f54ba5..06fcefe7 100644 --- a/spack-repo/environments/spack_cpu_gcc.yaml +++ b/spack-repo/environments/spack_cpu_gcc.yaml @@ -1,8 +1,9 @@ spack: specs: - - hpx@1.10.0%gcc malloc=system networking=none max_cpu_count=256 instrumentation=apex ^cmake@3.30 ^curl@8.10.1 ^ninja@1.12.1 + - hpx@1.10.0+static%gcc malloc=system max_cpu_count=256 instrumentation=apex ^cmake@3.30 ^curl@8.10.1 ^ninja@1.12.1 - intel-oneapi-mkl@2024.2.1%gcc shared=false - openblas@0.3.28 shared=false fortran=false + - cmake@3.30 view: true concretizer: unify: true diff --git a/spack-repo/environments/spack_cpu_gcc_dist.yaml b/spack-repo/environments/spack_cpu_gcc_dist.yaml new file mode 100644 index 00000000..c55d238c --- /dev/null +++ b/spack-repo/environments/spack_cpu_gcc_dist.yaml @@ -0,0 +1,8 @@ +spack: + specs: + - hpx@1.10.0%gcc networking=tcp malloc=system max_cpu_count=256 instrumentation=none ^cmake@3.30 ^curl@8.10.1 ^ninja@1.12.1 + - openblas@0.3.28 shared=false fortran=true + - cmake@3.30 + view: true + concretizer: + unify: true diff --git a/spack-repo/packages/hpx/package.py b/spack-repo/packages/hpx/package.py index 0ed413b9..46c368bb 100644 --- a/spack-repo/packages/hpx/package.py +++ b/spack-repo/packages/hpx/package.py @@ -24,6 +24,7 @@ class Hpx(CMakePackage, CudaPackage, ROCmPackage): version("master", branch="master") version("stable", tag="stable", commit="103a7b8e3719a0db948d1abde29de0ff91e070be") + version("1.11.0", sha256="01ec47228a2253b41e318bb09c83325a75021eb6ef3262400fbda30ac7389279") version("1.10.0", sha256="5720ed7d2460fa0b57bd8cb74fa4f70593fe8675463897678160340526ec3c19") version("1.9.1", sha256="1adae9d408388a723277290ddb33c699aa9ea72defadf3f12d4acc913a0ff22d") version("1.9.0", sha256="2a8dca78172fbb15eae5a5e9facf26ab021c845f9c09e61b1912e6cf9e72915a") @@ -171,6 +172,10 @@ class Hpx(CMakePackage, CudaPackage, ROCmPackage): # Patches and one-off conflicts + # Asio 1.34.0 removed io_context::work, used by HPX: + # https://github.com/chriskohlhoff/asio/commit/a70f2df321ff40c1809773c2c09986745abf8d20. + conflicts("^asio@1.34:") + # Certain Asio headers don't compile with nvcc from 1.17.0 onwards with # C++17. Starting with CUDA 11.3 they compile again. conflicts("^asio@1.17.0:", when="+cuda cxxstd=17 ^cuda@:11.2") @@ -253,6 +258,7 @@ def cmake_args(self): self.define_from_variant("HPX_WITH_GENERIC_CONTEXT_COROUTINES", "generic_coroutines"), self.define("BOOST_ROOT", spec["boost"].prefix), self.define("HWLOC_ROOT", spec["hwloc"].prefix), + self.define("HPX_WITH_THREAD_IDLE_RATES", True), self.define("HPX_WITH_BOOST_ALL_DYNAMIC_LINK", True), self.define("BUILD_SHARED_LIBS", True), self.define("HPX_DATASTRUCTURES_WITH_ADAPT_STD_TUPLE", False), diff --git a/spack-repo/setup_spack.sh b/spack-repo/setup_spack.sh index e94ec99b..a3ce2619 100755 --- a/spack-repo/setup_spack.sh +++ b/spack-repo/setup_spack.sh @@ -5,13 +5,14 @@ set -e spack_repo_dir=$PWD +spack_destination="/scratch-simcl1/grafml/Programs/spack-fp2-simcl1n1" -# Clone spack repository into $HOME/spack -cd +# Clone spack repository +cd $spack_destination git clone -c feature.manyFiles=true --branch=v0.23.1 --depth=1 https://github.com/spack/spack.git # Configure spack (add this to your .bashrc file) -source $HOME/spack/share/spack/setup-env.sh +source $spack_destination/spack/share/spack/setup-env.sh # Find external compilers & software spack compiler find spack external find diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5c04f5a0..2bf4f1e1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,8 +9,11 @@ endif() # Option for GPU support with CUDA, cuSolver, cuBLAS option(GPRAT_WITH_CUDA "Enable GPU support with CUDA, cuSolver, cuBLAS" OFF) +option(GPRAT_WITH_SYCL "Enable SYCL support with oneMath" OFF) + # Pass variable to C++ code -add_compile_definitions(GPRAT_WITH_CUDA=$) +add_compile_definitions(GPRAT_WITH_CUDA=$ + GPRAT_WITH_SYCL=$) # Option for steps duration measurement with APEX option(GPRAT_APEX_STEPS "Enable measuring duration of steps with APEX" OFF) @@ -39,16 +42,112 @@ FetchContent_Declare( FetchContent_MakeAvailable(Catch2) +# catch_discover_tests registers each Catch2 test case as a separate CTest +# entry. +list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) +include(Catch) + find_package(Boost REQUIRED) # ---- Tests ---- -add_executable(GPRat_test_output_correctness src/output_correctness.cpp) +add_executable(GPRat_test_output_correctness src/test_data.hpp + src/output_correctness.cpp) target_link_libraries(GPRat_test_output_correctness PRIVATE GPRat::core Catch2::Catch2WithMain Boost::boost) target_compile_features(GPRat_test_output_correctness PRIVATE cxx_std_17) +# APEX's malloc wrapper initialises internal containers during process startup. +# With _GLIBCXX_ASSERTIONS enabled those accesses trip bounds checks before APEX +# is fully set up. Undefine the assertion macro for this target only. +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(GPRat_test_output_correctness + PRIVATE -U_GLIBCXX_ASSERTIONS) +endif() +catch_discover_tests(GPRat_test_output_correctness WORKING_DIRECTORY + "${CMAKE_CURRENT_LIST_DIR}") -add_test( - NAME GPRat_test_output_correctness - COMMAND GPRat_test_output_correctness - WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") +add_executable(GPRat_test_unit src/unit_tests.cpp) +target_link_libraries(GPRat_test_unit PRIVATE GPRat::core + Catch2::Catch2WithMain) +target_compile_features(GPRat_test_unit PRIVATE cxx_std_17) +catch_discover_tests(GPRat_test_unit WORKING_DIRECTORY + "${CMAKE_CURRENT_LIST_DIR}") + +# Multi-locality smoke tests for examples/gprat_distributed. Off by default: +# they need an HPX build with networking enabled (networking=none, used by the +# default gprat_cpu_gcc Spack environment, rejects --hpx:localities outright) -- +# see spack-repo/environments/setup_gprat_cpu_gcc_dist.sh and the "To run the +# distributed GPRat benchmark" section of the top-level README for how to build +# one. +option( + GPRAT_TEST_MULTI_LOCALITY + "Enable gprat_distributed smoke tests across multiple HPX localities (requires an HPX build with networking enabled)" + OFF) +if(GPRAT_TEST_MULTI_LOCALITY) + if(NOT TARGET gprat_distributed) + message( + FATAL_ERROR + "GPRAT_TEST_MULTI_LOCALITY requires GPRAT_WITH_DISTRIBUTED and GPRAT_ENABLE_EXAMPLES to be ON" + ) + endif() + foreach(n_localities 1 2 4) + add_test( + NAME GPRat_test_distributed_multi_locality_${n_localities} + COMMAND + bash + "${CMAKE_CURRENT_LIST_DIR}/scripts/run_distributed_multi_locality.sh" + "$" ${n_localities} --start 128 --end + 128 --step 2 --tiles 2 --loop 1 --output_csv /dev/null) + set_tests_properties( + GPRat_test_distributed_multi_locality_${n_localities} + PROPERTIES TIMEOUT + 120 + # The binary resolves its default data/data_1024/... paths + # relative to the current working directory, matching + # run_gprat_distributed.sh's `cd "$GPRAT_ROOT"` before invoking + # it. + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + # Node 0 of each run binds HPX's default AGAS/parcel TCP port + # on localhost; running two of these tests concurrently makes + # the second's bind fail ("Address already in use"), which then + # hangs its orphaned peer processes until they hit TIMEOUT. + # Force them to run one at a time. + RUN_SERIAL + TRUE) + endforeach() + + # gprat::GP (used by GPRat_test_output_correctness) always uses + # tiled_scheduler_local, which is locality-oblivious -- it never exercises the + # distributed action dispatch no matter how many localities are running. This + # binary instead calls the same free functions examples/gprat_distributed uses + # with tiled_scheduler_sma, so running it across multiple localities actually + # verifies that dispatch, against the same data_1024/output.json baseline. + add_executable(GPRat_test_distributed_output_correctness + src/test_data.hpp src/distributed_output_correctness.cpp) + target_link_libraries(GPRat_test_distributed_output_correctness + PRIVATE GPRat::core Boost::boost) + target_compile_features(GPRat_test_distributed_output_correctness + PRIVATE cxx_std_17) + # Baked-in default data/ directory, overridable via the GPRAT_ROOT env var + # (see test_data.hpp's get_data_directory()) so this always agrees with + # GPRat_test_output_correctness on which data_1024/output.json baseline to + # read/write. + target_compile_definitions( + GPRat_test_distributed_output_correctness + PRIVATE GPRAT_TEST_DATA_DIR="${CMAKE_SOURCE_DIR}/data") + + foreach(n_localities 1 2 4) + add_test( + NAME GPRat_test_distributed_output_correctness_${n_localities} + COMMAND + bash + "${CMAKE_CURRENT_LIST_DIR}/scripts/run_distributed_multi_locality.sh" + "$" + ${n_localities}) + set_tests_properties( + GPRat_test_distributed_output_correctness_${n_localities} + PROPERTIES TIMEOUT 120 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" RUN_SERIAL + TRUE) + endforeach() +endif() diff --git a/test/scripts/run_distributed_multi_locality.sh b/test/scripts/run_distributed_multi_locality.sh new file mode 100755 index 00000000..03191f46 --- /dev/null +++ b/test/scripts/run_distributed_multi_locality.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Runs a binary across N HPX localities on one node, forwarding extra arguments to node 0 only +# (the other nodes just join the runtime and take no CLI arguments of their own). +# Usage: run_distributed_multi_locality.sh [extra node-0 args...] +# +# Used both for the gprat_distributed smoke tests (exit-code-only) and the distributed +# correctness check (compares computed results to a baseline, see +# test/src/distributed_output_correctness.cpp). Requires a binary built against an HPX with +# networking enabled (networking=none rejects --hpx:localities outright), which is why the CTest +# entries that invoke this script are opt-in via GPRAT_TEST_MULTI_LOCALITY (see +# test/CMakeLists.txt). +set -e + +BIN="$1" +N="$2" +shift 2 || true + +if [[ -z "$BIN" || -z "$N" ]]; then + echo "usage: $0 [extra node-0 args...]" 1>&2 + exit 1 +fi + +# HPX's TCP parcelport zero-copy path hangs once tile sizes exceed the default 8192-byte +# threshold in a multi-locality run; raise it to avoid this (see top-level README). +ZC_ARGS=(--hpx:ini=hpx.parcel.zero_copy_serialization_threshold=999999999) + +pids=() + +"$BIN" --hpx:localities="$N" --hpx:node=0 "${ZC_ARGS[@]}" "$@" & +pids+=($!) + +for ((node = 1; node < N; node++)); do + "$BIN" --hpx:localities="$N" --hpx:node="$node" "${ZC_ARGS[@]}" & + pids+=($!) +done + +# `wait pid1 pid2 ...` only reports the last PID's status, so check each individually to make +# sure a failure on any locality fails the test. +failed=0 +for pid in "${pids[@]}"; do + wait "$pid" || failed=1 +done + +exit "$failed" diff --git a/test/src/distributed_output_correctness.cpp b/test/src/distributed_output_correctness.cpp new file mode 100644 index 00000000..13fd4f65 --- /dev/null +++ b/test/src/distributed_output_correctness.cpp @@ -0,0 +1,170 @@ +// Verifies the distributed compute path (tiled_scheduler_sma, the scheduler +// examples/gprat_distributed uses to spread tiles across HPX localities, and the +// gp_*_actions.cpp action dispatch it goes through) against the same data/data_1024/output.json +// baseline that GPRat_test_output_correctness checks. GPRat_test_output_correctness always uses +// gprat::GP, which hardcodes the locality-oblivious tiled_scheduler_local -- it never touches the +// distributed action code no matter how many HPX localities are running. This binary calls the +// same free functions examples/gprat_distributed/src/main.cpp calls, with tiled_scheduler_sma, so +// it actually exercises that dispatch, and is meant to be run across multiple localities via +// test/scripts/run_distributed_multi_locality.sh (see test/CMakeLists.txt). +// +// Unlike GPRat_test_output_correctness this isn't a Catch2 test: it needs to run under +// hpx::init/hpx_main so the runtime bootstraps as a real (possibly multi-locality) HPX job, and +// hpx_main only executes on locality 0 by default -- which is exactly the gating we want, since +// only locality 0 should compute and compare results while the others just service actions. +#include "gprat/cpu/adapter_cblas_fp64_actions.hpp" +#include "gprat/cpu/gp_algorithms_actions.hpp" +#include "gprat/cpu/gp_functions.hpp" +#include "gprat/cpu/gp_optimizer_actions.hpp" +#include "gprat/cpu/gp_uncertainty_actions.hpp" +#include "gprat/gprat.hpp" +#include "gprat/scheduler/sma.hpp" +#include "gprat/utils.hpp" + +#include "test_data.hpp" +#include +#include +#include +#include +#include +#include + +namespace +{ + +// Matches GPRat_test_output_correctness's CPU test settings so both can compare against the +// same data/data_1024/output.json baseline. +constexpr std::size_t n_test = 128; +constexpr std::size_t n_train = 128; +constexpr std::size_t n_tiles = 4; +constexpr std::size_t n_reg = 8; +constexpr int OPT_ITER = 3; + +bool nearly_equal(double a, double b, double eps) +{ + return std::fabs(a - b) <= eps * (std::max)(std::fabs(a), std::fabs(b)); +} + +bool compare( + const std::vector &actual, const std::vector &expected, double eps, const std::string &label) +{ + if (actual.size() != expected.size()) + { + std::cerr << label << ": size mismatch (" << actual.size() << " vs " << expected.size() << ")\n"; + return false; + } + bool ok = true; + for (std::size_t i = 0; i < actual.size(); ++i) + { + if (!nearly_equal(actual[i], expected[i], eps)) + { + std::cerr << label << "[" << i << "]: " << actual[i] << " != " << expected[i] << "\n"; + ok = false; + } + } + return ok; +} + +bool compare(const std::vector> &actual, + const std::vector> &expected, + double eps, + const std::string &label) +{ + if (actual.size() != expected.size()) + { + std::cerr << label << ": outer size mismatch (" << actual.size() << " vs " << expected.size() << ")\n"; + return false; + } + bool ok = true; + for (std::size_t i = 0; i < actual.size(); ++i) + { + ok = compare(actual[i], expected[i], eps, label + "[" + std::to_string(i) + "]") && ok; + } + return ok; +} + +} // namespace + +int hpx_main(hpx::program_options::variables_map & /*vm*/) +{ + // GPRAT_TEST_DATA_DIR is baked in at configure time (CMAKE_SOURCE_DIR/data); GPRAT_ROOT, if + // set, overrides it -- matching GPRat_test_output_correctness's own resolution so both always + // agree on which data/data_1024/output.json baseline they're reading/writing. + const auto root = get_data_directory(GPRAT_TEST_DATA_DIR); + + const std::size_t tile_size = gprat::compute_train_tile_size(n_train, n_tiles); + const auto test_tiles = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::AdamParams hpar = { 0.1, 0.9, 0.999, 1e-8, OPT_ITER }; + gprat::SEKParams sek_params = { 1.0, 1.0, 0.1 }; + const std::vector trainable = { true, true, true }; + + gprat::GP_data training_input(root + "/data_1024/training_input.txt", n_train, n_reg); + gprat::GP_data training_output(root + "/data_1024/training_output.txt", n_train, n_reg); + gprat::GP_data test_input(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::tiled_scheduler_sma scheduler; + + gprat_results results; + results.cholesky = + to_vector(gprat::cpu::cholesky(scheduler, training_input.data, sek_params, n_tiles, tile_size, n_reg)); + results.sum = gprat::cpu::predict_with_uncertainty( + scheduler, + training_input.data, + training_output.data, + test_input.data, + sek_params, + n_tiles, + tile_size, + test_tiles.first, + test_tiles.second, + n_reg); + results.full = gprat::cpu::predict_with_full_cov( + scheduler, + training_input.data, + training_output.data, + test_input.data, + sek_params, + n_tiles, + tile_size, + test_tiles.first, + test_tiles.second, + n_reg); + results.pred = gprat::cpu::predict( + scheduler, + training_input.data, + training_output.data, + test_input.data, + sek_params, + n_tiles, + tile_size, + test_tiles.first, + test_tiles.second, + n_reg); + results.losses = gprat::cpu::optimize( + scheduler, training_input.data, training_output.data, n_tiles, tile_size, n_reg, hpar, sek_params, trainable); + + gprat_results expected; + if (!load_or_create_expected_results(root + "/data_1024/output.json", results, expected)) + { + std::cerr << "No previous results to compare to. The current results have been saved instead!\n"; + hpx::finalize(); + return 0; + } + + const double eps = std::numeric_limits::epsilon() * 1'000'000; + bool ok = true; + ok = compare(results.cholesky, expected.cholesky, eps, "cholesky") && ok; + ok = compare(results.losses, expected.losses, eps, "losses") && ok; + ok = compare(results.sum, expected.sum, eps, "sum") && ok; + ok = compare(results.full, expected.full, eps, "full") && ok; + ok = compare(results.pred, expected.pred, eps, "pred") && ok; + + std::cerr << (ok ? "PASS: distributed results match baseline\n" + : "FAIL: distributed results differ from baseline\n"); + + hpx::finalize(); + return ok ? 0 : 1; +} + +int main(int argc, char *argv[]) { return hpx::init(argc, argv); } diff --git a/test/src/output_correctness.cpp b/test/src/output_correctness.cpp index 87ae7457..6f13e403 100644 --- a/test/src/output_correctness.cpp +++ b/test/src/output_correctness.cpp @@ -1,134 +1,86 @@ -#include "gprat_c.hpp" -#include "utils_c.hpp" +#include "gprat/gprat.hpp" +#include "gprat/utils.hpp" + +#include "test_data.hpp" #include #include +using Catch::Matchers::WithinRel; -// This is a standalone test, so including this directly is fine. -// Better than having the whole project depend on compiled Boost.Json! +// Boost #include -// std headers last -#include +// Standard library #include #include -// Struct containing all results we'd like to compare -struct gprat_results -{ - std::vector> choleksy; - std::vector losses; - std::vector> sum; - std::vector> full; - std::vector pred; -}; - -// The following two functions are for JSON (de-)serialization -void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, const gprat_results &results) +namespace gprat::test { - jv = { - { "choleksy", boost::json::value_from(results.choleksy) }, - { "losses", boost::json::value_from(results.losses) }, - { "sum", boost::json::value_from(results.sum) }, - { "full", boost::json::value_from(results.full) }, - { "pred", boost::json::value_from(results.pred) }, - }; -} -// This helper function deduces the type and assigns the value with the matching key -template -inline void extract(const boost::json::object &obj, T &t, std::string_view key) -{ - t = boost::json::value_to(obj.at(key)); -} +// Parameters ///////////////////////////////////////////////////////////////////////////////////// -gprat_results tag_invoke(boost::json::value_to_tag, const boost::json::value &jv) -{ - gprat_results results; - const auto &obj = jv.as_object(); - extract(obj, results.choleksy, "choleksy"); - extract(obj, results.losses, "losses"); - extract(obj, results.sum, "sum"); - extract(obj, results.full, "full"); - extract(obj, results.pred, "pred"); - return results; -} +// Global test settings +constexpr std::size_t n_test = 128; +constexpr std::size_t n_train = 128; +constexpr std::size_t n_tiles = 4; +constexpr std::size_t n_reg = 8; + +// CPU test settings +constexpr int OPT_ITER = 3; + +// CUDA and SYCL test settings +constexpr int gpu_id = 0; +constexpr int n_streams = 4; + +// Test execution ///////////////////////////////////////////////////////////////////////////////// -// This logic is basically equivalent to the GPRat C++ example (for now). +/** + * @brief Generates results using the CPU for computations. + */ gprat_results run_on_data_cpu(const std::string &train_path, const std::string &out_path, const std::string &test_path) { - // configuration - const std::size_t OPT_ITER = 3; - const std::size_t n_test = 128; - const std::size_t n_train = 128; - const std::size_t n_tiles = 4; - const std::size_t n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n_train, n_tiles); + const auto test_tiles = gprat::compute_test_tiles(n_test, n_tiles, tile_size); - // Compute tile sizes and number of predict tiles - const int tile_size = utils::compute_train_tile_size(n_train, n_tiles); - const auto test_tiles = utils::compute_test_tiles(n_test, n_tiles, tile_size); + gprat::AdamParams hpar = { 0.1, 0.9, 0.999, 1e-8, OPT_ITER }; - // hyperparams - gprat_hyper::AdamParams hpar = { 0.1, 0.9, 0.999, 1e-8, OPT_ITER }; - - // data loading gprat::GP_data training_input(train_path, n_train, n_reg); gprat::GP_data training_output(out_path, n_train, n_reg); gprat::GP_data test_input(test_path, n_test, n_reg); - // GP const std::vector trainable = { true, true, true }; + // GP constructors do not use HPX, so it is safe to construct before starting the runtime. gprat::GP gp_cpu( training_input.data, training_output.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, trainable); - // Initialize HPX with no arguments, don't run hpx_main - utils::start_hpx_runtime(0, nullptr); + gprat::start_hpx_runtime(0, nullptr); gprat_results results_cpu; - - // Cholesky decomposition - results_cpu.choleksy = gp_cpu.cholesky(); - // Prediction + results_cpu.cholesky = to_vector(gp_cpu.cholesky()); results_cpu.sum = gp_cpu.predict_with_uncertainty(test_input.data, test_tiles.first, test_tiles.second); results_cpu.full = gp_cpu.predict_with_full_cov(test_input.data, test_tiles.first, test_tiles.second); results_cpu.pred = gp_cpu.predict(test_input.data, test_tiles.first, test_tiles.second); - // Optimization results_cpu.losses = gp_cpu.optimize(hpar); - // // Sequential version for creating reference - // const auto test_total = utils::compute_test_tiles(n_test, 1, n_test); - // gprat::GP gp_cpu_seq( - // training_input.data, training_output.data, 1, n_train, n_reg, { 1.0, 1.0, 0.1 }, trainable); - // results_cpu.choleksy = gp_cpu.cholesky(); - // results_cpu.sum = gp_cpu_seq.predict_with_uncertainty(test_input.data, test_total.first, test_total.second); - // results_cpu.full = gp_cpu_seq.predict_with_full_cov(test_input.data, test_total.first, test_total.second); - // results_cpu.pred = gp_cpu_seq.predict(test_input.data, test_total.first, test_total.second); - // results_cpu.losses = gp_cpu_seq.optimize(hpar); - - // Stop the HPX runtime - utils::stop_hpx_runtime(); + gprat::stop_hpx_runtime(); return results_cpu; } -// Add this helper function +/** + * @brief Generates results using a CUDA GPU or SYCL device. + */ gprat_results run_on_data_gpu(const std::string &train_path, const std::string &out_path, const std::string &test_path) { - const std::size_t n_test = 128; - const std::size_t n_train = 128; - const std::size_t n_tiles = 4; - const std::size_t n_reg = 8; - const int gpu_id = 0; - const int n_streams = 1; - - const int tile_size = utils::compute_train_tile_size(n_train, n_tiles); - const auto test_tiles = utils::compute_test_tiles(n_test, n_tiles, tile_size); + const std::size_t tile_size = gprat::compute_train_tile_size(n_train, n_tiles); + const auto test_tiles = gprat::compute_test_tiles(n_test, n_tiles, tile_size); gprat::GP_data training_input(train_path, n_train, n_reg); gprat::GP_data training_output(out_path, n_train, n_reg); gprat::GP_data test_input(test_path, n_test, n_reg); const std::vector trainable = { true, true, true }; + gprat::GP gp_gpu( training_input.data, training_output.data, @@ -140,57 +92,27 @@ gprat_results run_on_data_gpu(const std::string &train_path, const std::string & gpu_id, n_streams); - utils::start_hpx_runtime(0, nullptr); + gprat::start_hpx_runtime(0, nullptr); gprat_results results_gpu; - - // Cholesky - results_gpu.choleksy = gp_gpu.cholesky(); - - // Prediction + results_gpu.cholesky = to_vector(gp_gpu.cholesky()); + // NOTE: optimize and optimize_step are currently not implemented for GPU. + // When GPU optimize is added, extend this function and update the GPU test case to verify losses. results_gpu.sum = gp_gpu.predict_with_uncertainty(test_input.data, test_tiles.first, test_tiles.second); results_gpu.full = gp_gpu.predict_with_full_cov(test_input.data, test_tiles.first, test_tiles.second); results_gpu.pred = gp_gpu.predict(test_input.data, test_tiles.first, test_tiles.second); - utils::stop_hpx_runtime(); + gprat::stop_hpx_runtime(); return results_gpu; } -bool load_or_create_expected_results( - const std::string &filename, const gprat_results &fallback_results, gprat_results &results) -{ - // First try to read our expected results file - { - std::ifstream ifs(filename); - if (!ifs.fail()) - { - using iterator_type = std::istreambuf_iterator; - const std::string content(iterator_type{ ifs }, iterator_type{}); - results = boost::json::value_to(boost::json::parse(content)); - return true; - } - } +// Test cases ///////////////////////////////////////////////////////////////////////////////////// - // If that doesn't work, just write out the results we want - std::ofstream fout(filename); - fout << boost::json::value_from(fallback_results); - return false; -} - -std::string get_root_directory() +TEST_CASE("GP CPU: results match baseline", "[integration][cpu]") { - const char *env_root = std::getenv("GPRAT_ROOT"); - if (env_root) - { - return env_root; - } - return "../data"; -} + const std::string root = get_data_directory("../data"); -TEST_CASE("GP CPU results match known-good values", "[integration][cpu]") -{ - const std::string root = get_root_directory(); const auto results = run_on_data_cpu(root + "/data_1024/training_input.txt", root + "/data_1024/training_output.txt", root + "/data_1024/test_input.txt"); @@ -198,24 +120,21 @@ TEST_CASE("GP CPU results match known-good values", "[integration][cpu]") gprat_results expected_results; if (!load_or_create_expected_results(root + "/data_1024/output.json", results, expected_results)) { - std::cerr << "No previous results to compare to. The current results have been saved instead!" << std::endl; + std::cerr << "No previous results to compare to. The current results have been saved instead!\n"; return; } - // Compare content - // The default-constructed WithinRel() matcher has a tolerance of epsilon * 100 - // see: - // https://github.com/catchorg/Catch2/blob/914aeecfe23b1e16af6ea675a4fb5dbd5a5b8d0a/docs/comparing-floating-point-numbers.md#withinrel - using Catch::Matchers::WithinRel; double eps = std::numeric_limits::epsilon() * 1'000'000; - for (std::size_t i = 0, n = results.choleksy.size(); i != n; ++i) + + for (std::size_t i = 0, n = results.cholesky.size(); i != n; ++i) { - for (std::size_t j = 0, m = results.choleksy[i].size(); j != m; ++j) + for (std::size_t j = 0, m = results.cholesky[i].size(); j != m; ++j) { - INFO("CPU choleksy " << i << " " << j); - REQUIRE_THAT(results.choleksy[i][j], WithinRel(expected_results.choleksy[i][j], eps)); + INFO("CPU cholesky " << i << " " << j); + REQUIRE_THAT(results.cholesky[i][j], WithinRel(expected_results.cholesky[i][j], eps)); } } + for (std::size_t i = 0, n = results.losses.size(); i != n; ++i) { INFO("CPU losses " << i); @@ -247,39 +166,38 @@ TEST_CASE("GP CPU results match known-good values", "[integration][cpu]") } } -// Test for GPU -TEST_CASE("GP GPU results match known-good values (no loss)", "[integration][gpu]") +TEST_CASE("GP GPU: results match baseline", "[integration][gpu]") { - if (!utils::compiled_with_cuda()) + if (!gprat::compiled_with_cuda() && !gprat::compiled_with_sycl()) { - WARN("CUDA not available — skipping GPU test."); - return; + SKIP("GPU not compiled in — skipping GPU integration test."); + } + if (gprat::compiled_with_sycl() && !gprat::sycl_gpu_functional()) + { + SKIP("SYCL GPU runtime not functional (oneMath ABI mismatch)."); } - const std::string root = get_root_directory(); - const std::string train = root + "/data_1024/training_input.txt"; - const std::string out = root + "/data_1024/training_output.txt"; - const std::string test = root + "/data_1024/test_input.txt"; + const std::string root = get_data_directory("../data"); - const gprat_results results = run_on_data_gpu(train, out, test); + const auto results = run_on_data_gpu(root + "/data_1024/training_input.txt", + root + "/data_1024/training_output.txt", + root + "/data_1024/test_input.txt"); gprat_results expected_results; - const std::string ref_file = root + "/data_1024/output.json"; - - if (!load_or_create_expected_results(ref_file, results, expected_results)) + if (!load_or_create_expected_results(root + "/data_1024/output.json", results, expected_results)) { - std::cerr << "No previous results to compare to. The current results have been saved instead!" << std::endl; + std::cerr << "No previous results to compare to. The current results have been saved instead!\n"; return; } - using Catch::Matchers::WithinRel; double eps = std::numeric_limits::epsilon() * 1'000'000; - for (std::size_t i = 0, n = results.choleksy.size(); i != n; ++i) + + for (std::size_t i = 0, n = results.cholesky.size(); i != n; ++i) { - for (std::size_t j = 0, m = results.choleksy[i].size(); j != m; ++j) + for (std::size_t j = 0, m = results.cholesky[i].size(); j != m; ++j) { - INFO("GPU choleksy " << i << " " << j); - REQUIRE_THAT(results.choleksy[i][j], WithinRel(expected_results.choleksy[i][j], eps)); + INFO("GPU cholesky " << i << " " << j); + REQUIRE_THAT(results.cholesky[i][j], WithinRel(expected_results.cholesky[i][j], eps)); } } @@ -307,3 +225,5 @@ TEST_CASE("GP GPU results match known-good values (no loss)", "[integration][gpu REQUIRE_THAT(results.pred[i], WithinRel(expected_results.pred[i], eps)); } } + +} // namespace gprat::test diff --git a/test/src/test_data.hpp b/test/src/test_data.hpp new file mode 100644 index 00000000..bcb055e9 --- /dev/null +++ b/test/src/test_data.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include "gprat/gprat.hpp" + +#include +#include +#include +#include +#include +#include + +/** + * @brief Resolves the data/ directory to use: the GPRAT_ROOT environment variable if set, + * otherwise `fallback`. Shared so every test binary that reads data/data_1024/... agrees + * on the same directory when GPRAT_ROOT is set, regardless of each binary's own default. + */ +inline std::string get_data_directory(const std::string &fallback) +{ + const char *env_root = std::getenv("GPRAT_ROOT"); + if (env_root) + { + return env_root; + } + return fallback; +} + +// Struct containing all results we'd like to compare +struct gprat_results +{ + std::vector> cholesky; + std::vector losses; + std::vector> sum; + std::vector> full; + std::vector pred; +}; + +// The following two functions are for JSON (de-)serialization +inline void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, const gprat_results &results) +{ + jv = { + { "cholesky", boost::json::value_from(results.cholesky) }, + { "losses", boost::json::value_from(results.losses) }, + { "sum", boost::json::value_from(results.sum) }, + { "full", boost::json::value_from(results.full) }, + { "pred", boost::json::value_from(results.pred) }, + }; +} + +// This helper function deduces the type and assigns the value with the matching key +template +BOOST_FORCEINLINE void extract(const boost::json::object &obj, T &t, std::string_view key) +{ + t = boost::json::value_to(obj.at(key)); +} + +inline gprat_results tag_invoke(boost::json::value_to_tag, const boost::json::value &jv) +{ + gprat_results results; + const auto &obj = jv.as_object(); + extract(obj, results.cholesky, "cholesky"); + extract(obj, results.losses, "losses"); + extract(obj, results.sum, "sum"); + extract(obj, results.full, "full"); + extract(obj, results.pred, "pred"); + return results; +} + +template +std::vector to_vector(const gprat::const_tile_data &data) +{ + return { data.begin(), data.end() }; +} + +template +std::vector> to_vector(const std::vector> &data) +{ + std::vector> out; + out.reserve(data.size()); + for (const auto &row : data) + { + out.emplace_back(to_vector(row)); + } + return out; +} + +template +std::vector> to_vector(const std::vector> &data) +{ + std::vector> out; + out.reserve(data.size()); + for (const auto &row : data) + { + out.emplace_back(to_vector(row)); + } + return out; +} + +/** + * @brief Tries to load expected results from `filename`. If the file does not exist, writes + * `fallback_results` to it and returns false. Returns true when results are loaded. + */ +inline bool load_or_create_expected_results( + const std::string &filename, const gprat_results &fallback_results, gprat_results &results) +{ + { + std::ifstream ifs(filename); + if (!ifs.fail()) + { + try + { + using iterator_type = std::istreambuf_iterator; + const std::string content(iterator_type{ ifs }, iterator_type{}); + results = boost::json::value_to(boost::json::parse(content)); + } + catch (const std::exception &e) + { + std::cerr << "Failed to parse baseline " << filename << ": " << e.what() + << " — overwriting with current results.\n"; + results = gprat_results{}; + } + + // Stale if any field present in the current run is absent or has a different outer + // size in the baseline (e.g. CPU baseline loaded by the GPU test, or n_tiles changed). + const bool stale = + (!fallback_results.cholesky.empty() + && (results.cholesky.empty() || results.cholesky.size() != fallback_results.cholesky.size())) + || (!fallback_results.losses.empty() && results.losses.size() != fallback_results.losses.size()) + || (!fallback_results.sum.empty() + && (results.sum.empty() || results.sum.size() != fallback_results.sum.size())) + || (!fallback_results.full.empty() + && (results.full.empty() || results.full.size() != fallback_results.full.size())) + || (!fallback_results.pred.empty() && results.pred.size() != fallback_results.pred.size()); + if (!stale) + { + return true; + } + + std::cerr << "Baseline in " << filename << " is incomplete or mismatched" + << " — overwriting with current results.\n"; + } + } + + std::ofstream fout(filename); + fout << boost::json::serialize(boost::json::value_from(fallback_results)); + return false; +} diff --git a/test/src/unit_tests.cpp b/test/src/unit_tests.cpp new file mode 100644 index 00000000..4d1f1ac6 --- /dev/null +++ b/test/src/unit_tests.cpp @@ -0,0 +1,1788 @@ +#include "gprat/cpu/adapter_cblas_fp32.hpp" +#include "gprat/cpu/adapter_cblas_fp64.hpp" +#include "gprat/cpu/gp_algorithms.hpp" +#include "gprat/gprat.hpp" +#include "gprat/hyperparameters.hpp" +#include "gprat/kernels.hpp" +#include "gprat/performance_counters.hpp" +#include "gprat/utils.hpp" + +#include +#include +#include +#include +#include +#include +#include +using Catch::Matchers::ContainsSubstring; +using Catch::Matchers::WithinAbs; +using Catch::Matchers::WithinRel; + +// Helper: build a tile_data from an initializer list +template +static gprat::mutable_tile_data make_tile(std::initializer_list vals) +{ + gprat::mutable_tile_data t(vals.size()); + std::size_t i = 0; + for (const auto &v : vals) + { + t.data()[i++] = v; + } + return t; +} + +template +static gprat::const_tile_data make_const_tile(std::initializer_list vals) +{ + // const_tile_data has no mutable operator[], so build via mutable first + gprat::mutable_tile_data m = make_tile(vals); + return m; +} + +namespace +{ +// Starts the HPX runtime on construction and stops it on destruction so that +// stop_hpx_runtime() is always called even when a test assertion fails mid-test. +struct hpx_runtime_guard +{ + hpx_runtime_guard() { gprat::start_hpx_runtime(0, nullptr); } + + ~hpx_runtime_guard() { gprat::stop_hpx_runtime(); } +}; +} // namespace + +namespace gprat::test +{ + +static std::string gprat_data_root() +{ + const char *env = std::getenv("GPRAT_ROOT"); + return env ? env : "../data"; +} + +// GP_data /////////////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("GP_data: sample count", "[unit][gp_data]") +{ + const std::string root = gprat_data_root(); + const std::string path = root + "/data_1024/training_input.txt"; + + constexpr std::size_t n = 64; + constexpr std::size_t n_reg = 8; + + gprat::GP_data d(path, n, n_reg); + + REQUIRE(d.n_samples == n); + REQUIRE(d.n_regressors == n_reg); + // load_data allocates n_samples + (n_reg - 1) elements: data starts at offset n_reg-1 + REQUIRE(d.data.size() == n + n_reg - 1); + REQUIRE(d.file_path == path); +} + +TEST_CASE("GP_data: n_reg=1 sample count", "[unit][gp_data]") +{ + const std::string root = gprat_data_root(); + const std::string path = root + "/data_1024/training_input.txt"; + + constexpr std::size_t n = 32; + gprat::GP_data d(path, n, 1); + + REQUIRE(d.data.size() == n + 1 - 1); // n + (n_reg - 1) with n_reg=1 +} + +// Tile utilities //////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("tile_size: divides evenly", "[unit][tiles]") +{ + REQUIRE(gprat::compute_train_tile_size(1024, 16) == 64); + REQUIRE(gprat::compute_train_tile_size(512, 8) == 64); + REQUIRE(gprat::compute_train_tile_size(256, 4) == 64); +} + +TEST_CASE("tile_count: divides evenly", "[unit][tiles]") +{ + REQUIRE(gprat::compute_train_tiles(1024, 64) == 16); + REQUIRE(gprat::compute_train_tiles(512, 64) == 8); +} + +TEST_CASE("tile_size: throws on zero tiles", "[unit][tiles]") +{ + REQUIRE_THROWS_AS(gprat::compute_train_tile_size(1024, 0), std::runtime_error); +} + +TEST_CASE("tile_count: throws on zero tile_size", "[unit][tiles]") +{ + REQUIRE_THROWS_AS(gprat::compute_train_tiles(1024, 0), std::runtime_error); +} + +TEST_CASE("test_tiles: divisible n_test", "[unit][tiles]") +{ + // n_test=512, tile_size=64 → 512 % 64 == 0, so use m_tile_size=64, m_tiles=8 + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(512, 16, 64); + REQUIRE(m_tile_size == 64); + REQUIRE(m_tiles == 8); + REQUIRE(m_tiles * m_tile_size == 512); +} + +TEST_CASE("test_tiles: non-divisible n_test", "[unit][tiles]") +{ + // n_test=100, tile_size=64 → 100 % 64 != 0, so use m_tiles=16, m_tile_size=100/16 + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(100, 16, 64); + REQUIRE(m_tiles == 16); + REQUIRE(m_tile_size == 100 / 16); +} + +TEST_CASE("tile_size and tile_count: inverses", "[unit][tiles]") +{ + constexpr std::size_t n = 1024; + constexpr std::size_t tiles = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, tiles); + const std::size_t recovered = gprat::compute_train_tiles(n, tile_size); + REQUIRE(recovered == tiles); +} + +// Optimizer (CPU) //////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("GP::optimize: loss count", "[unit][optimizer][cpu]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128; + constexpr std::size_t n_tiles = 4; + constexpr std::size_t n_reg = 8; + constexpr int opt_iter = 5; + + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, opt_iter }; + const auto losses = gp.optimize(params); + + REQUIRE(losses.size() == static_cast(opt_iter)); +} + +TEST_CASE("GP::optimize_step: finite loss", "[unit][optimizer][cpu]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128; + constexpr std::size_t n_tiles = 4; + constexpr std::size_t n_reg = 8; + + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + hpx_runtime_guard hpx_guard; + gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, 1 }; + const double loss = gp.optimize_step(params, 1); + + REQUIRE(std::isfinite(loss)); +} + +TEST_CASE("GP::calculate_loss: finite", "[unit][loss][cpu]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128; + constexpr std::size_t n_tiles = 4; + constexpr std::size_t n_reg = 8; + + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + hpx_runtime_guard hpx_guard; + const double loss = gp.calculate_loss(); + + REQUIRE(std::isfinite(loss)); +} + +TEST_CASE("GP::optimize: loss decreases", "[unit][optimizer][cpu][fragile]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128; + constexpr std::size_t n_tiles = 4; + constexpr std::size_t n_reg = 8; + + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.1, 0.9, 0.999, 1e-8, 10 }; + const auto losses = gp.optimize(params); + + // Loss should be finite and have decreased over 10 Adam steps. + // The decrease is not strictly guaranteed for all hyperparameter settings, + // but with lr=0.1 and 10 steps on this dataset it is reliable in practice. + REQUIRE(std::isfinite(losses.back())); + REQUIRE(losses.front() > losses.back()); +} + +// SEKParams ///////////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("SEKParams: size is 3", "[unit][sek]") +{ + gprat::SEKParams p(1.0, 2.0, 0.1); + REQUIRE(p.size() == 3); +} + +TEST_CASE("SEKParams: get_param fields", "[unit][sek]") +{ + gprat::SEKParams p(1.5, 2.5, 0.3); + REQUIRE_THAT(p.get_param(0), WithinRel(1.5, 1e-12)); + REQUIRE_THAT(p.get_param(1), WithinRel(2.5, 1e-12)); + REQUIRE_THAT(p.get_param(2), WithinRel(0.3, 1e-12)); +} + +TEST_CASE("SEKParams: set_param mutates", "[unit][sek]") +{ + gprat::SEKParams p(1.0, 1.0, 0.1); + p.set_param(0, 3.0); + p.set_param(1, 4.0); + p.set_param(2, 0.5); + REQUIRE_THAT(p.lengthscale, WithinRel(3.0, 1e-12)); + REQUIRE_THAT(p.vertical_lengthscale, WithinRel(4.0, 1e-12)); + REQUIRE_THAT(p.noise_variance, WithinRel(0.5, 1e-12)); +} + +TEST_CASE("SEKParams: get_param throws", "[unit][sek]") +{ + gprat::SEKParams p(1.0, 1.0, 0.1); + REQUIRE_THROWS_AS(p.get_param(3), std::invalid_argument); +} + +TEST_CASE("SEKParams: set_param throws", "[unit][sek]") +{ + gprat::SEKParams p(1.0, 1.0, 0.1); + REQUIRE_THROWS_AS(p.set_param(3, 0.0), std::invalid_argument); +} + +TEST_CASE("SEKParams: m_T and w_T size", "[unit][sek]") +{ + gprat::SEKParams p(1.0, 1.0, 0.1); + REQUIRE(p.m_T.size() == 3); + REQUIRE(p.w_T.size() == 3); +} + +// AdamParams //////////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("AdamParams: default values", "[unit][adam]") +{ + gprat::AdamParams p; + REQUIRE_THAT(p.learning_rate, WithinRel(0.001, 1e-12)); + REQUIRE_THAT(p.beta1, WithinRel(0.9, 1e-12)); + REQUIRE_THAT(p.beta2, WithinRel(0.999, 1e-12)); + REQUIRE_THAT(p.epsilon, WithinRel(1e-8, 1e-12)); + REQUIRE(p.opt_iter == 0); +} + +TEST_CASE("AdamParams: repr fields", "[unit][adam]") +{ + gprat::AdamParams p(0.01, 0.9, 0.999, 1e-8, 5); + const auto s = p.repr(); + REQUIRE_THAT(s, ContainsSubstring("learning_rate")); + REQUIRE_THAT(s, ContainsSubstring("beta1")); + REQUIRE_THAT(s, ContainsSubstring("beta2")); + REQUIRE_THAT(s, ContainsSubstring("epsilon")); + REQUIRE_THAT(s, ContainsSubstring("opt_iter")); +} + +// GP_data error handling ///////////////////////////////////////////////////////////////////////// + +TEST_CASE("GP_data: throws on missing file", "[unit][gp_data]") +{ + REQUIRE_THROWS_AS(gprat::GP_data("/nonexistent/path/file.txt", 10, 4), std::runtime_error); +} + +// GP accessors and repr ////////////////////////////////////////////////////////////////////////// + +TEST_CASE("GP: training data round-trip", "[unit][gp]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 64, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + REQUIRE(gp.get_training_input() == train_in.data); + REQUIRE(gp.get_training_output() == train_out.data); +} + +TEST_CASE("GP: repr fields", "[unit][gp]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 64, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + const auto s = gp.repr(); + REQUIRE_THAT(s, ContainsSubstring("lengthscale")); + REQUIRE_THAT(s, ContainsSubstring("n_tiles")); +} + +// GP prediction shapes /////////////////////////////////////////////////////////////////////////// + +TEST_CASE("GP::predict: output size", "[unit][gp][predict]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 128; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + hpx_runtime_guard hpx_guard; + const auto pred = gp.predict(test_in.data, m_tiles, m_tile_size); + const auto pred_unc = gp.predict_with_uncertainty(test_in.data, m_tiles, m_tile_size); + const auto pred_cov = gp.predict_with_full_cov(test_in.data, m_tiles, m_tile_size); + + REQUIRE(pred.size() == n_test); + REQUIRE(pred_unc.size() == 2); + REQUIRE(pred_unc[0].size() == n_test); + REQUIRE(pred_unc[1].size() == n_test); + // predict_with_full_cov returns {mean, diagonal(Sigma)} — same shape as predict_with_uncertainty + REQUIRE(pred_cov.size() == 2); + REQUIRE(pred_cov[0].size() == n_test); + REQUIRE(pred_cov[1].size() == n_test); +} + +TEST_CASE("GP::cholesky: tile structure", "[unit][gp][cholesky]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + hpx_runtime_guard hpx_guard; + const auto L = gp.cholesky(); + + // n_tiles × n_tiles blocks stored as flat list of n_tiles^2 tiles + REQUIRE(L.size() == n_tiles * n_tiles); + REQUIRE(L[0].size() == tile_size * tile_size); +} + +// GP trainable mask ////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("GP::optimize: no trainable params", "[unit][optimizer][cpu]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { false, false, false }); + + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.1, 0.9, 0.999, 1e-8, 5 }; + const auto losses = gp.optimize(params); + + // All losses should be equal — no parameters moved + for (std::size_t i = 1; i < losses.size(); ++i) + { + REQUIRE_THAT(losses[i], WithinRel(losses[0], 1e-10)); + } +} + +// GP kernel_params live mutation ///////////////////////////////////////////////////////////////// + +TEST_CASE("GP::calculate_loss: sensitive to kernel_params", "[unit][gp][loss]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + + hpx_runtime_guard hpx_guard; + const double loss_before = gp.calculate_loss(); + gp.kernel_params.lengthscale = 5.0; + const double loss_after = gp.calculate_loss(); + + // Different hyperparameters must produce a different loss value. + // We use WithinAbs to check the absolute difference is non-trivially non-zero. + REQUIRE_THAT(std::abs(loss_before - loss_after), !WithinAbs(0.0, 1e-10)); +} + +// guess_good_tile_count_per_dimension //////////////////////////////////////////////////////////// + +TEST_CASE("tile_count_per_dim: 1 for small n", "[unit][tiles]") +{ + // n < 2^8 = 256 → always returns 1 + REQUIRE(gprat::guess_good_tile_count_per_dimension(100) == 1); + REQUIRE(gprat::guess_good_tile_count_per_dimension(1) == 1); +} + +TEST_CASE("tile_count_per_dim: positive for medium n", "[unit][tiles]") +{ + hpx_runtime_guard hpx_guard; + const std::size_t count = gprat::guess_good_tile_count_per_dimension(1 << 14); + REQUIRE(count >= 1); +} + +// compiled_with_cuda / compiled_with_sycl //////////////////////////////////////////////////////// + +#if !GPRAT_WITH_CUDA +TEST_CASE("compiled_with_cuda: false", "[unit][target]") { REQUIRE_FALSE(gprat::compiled_with_cuda()); } +#else +TEST_CASE("compiled_with_cuda: true", "[unit][target]") { REQUIRE(gprat::compiled_with_cuda()); } +#endif + +#if !GPRAT_WITH_SYCL +TEST_CASE("compiled_with_sycl: false", "[unit][target]") { REQUIRE_FALSE(gprat::compiled_with_sycl()); } +#else +TEST_CASE("compiled_with_sycl: true", "[unit][target]") { REQUIRE(gprat::compiled_with_sycl()); } +#endif + +// GP GPU constructor throws without CUDA/SYCL //////////////////////////////////////////////////// + +#if !GPRAT_WITH_CUDA && !GPRAT_WITH_SYCL +TEST_CASE("GP GPU: throws without CUDA/SYCL", "[unit][gp]") +{ + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 64, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + REQUIRE_THROWS_AS( + (gprat::GP( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1)), + std::runtime_error); +} +#endif + +// print_vector /////////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("print_vector: basic range", "[unit][utils]") +{ + const std::vector v = { 1.0, 2.0, 3.0 }; + std::streambuf *old = std::cout.rdbuf(); + std::ostringstream buf; + std::cout.rdbuf(buf.rdbuf()); + gprat::print_vector(v, 0, 3, ","); + std::cout.rdbuf(old); + REQUIRE_THAT(buf.str(), ContainsSubstring("1") && ContainsSubstring("2") && ContainsSubstring("3")); +} + +TEST_CASE("print_vector: negative start", "[unit][utils]") +{ + const std::vector v = { 10.0, 20.0, 30.0 }; + std::streambuf *old = std::cout.rdbuf(); + std::ostringstream buf; + std::cout.rdbuf(buf.rdbuf()); + gprat::print_vector(v, -2, 3, " "); // start = 3 - 2 = 1 → prints 20 30 + std::cout.rdbuf(old); + REQUIRE_THAT(buf.str(), ContainsSubstring("20")); +} + +TEST_CASE("print_vector: negative end", "[unit][utils]") +{ + const std::vector v = { 10.0, 20.0, 30.0 }; + std::streambuf *old = std::cout.rdbuf(); + std::ostringstream buf; + std::cout.rdbuf(buf.rdbuf()); + gprat::print_vector(v, 0, -1, " "); // end = 3 + 1 - 1 = 3 + std::cout.rdbuf(old); + REQUIRE_THAT(buf.str(), ContainsSubstring("10")); +} + +TEST_CASE("print_vector: end clamped", "[unit][utils]") +{ + const std::vector v = { 5.0, 6.0 }; + std::streambuf *old_out = std::cout.rdbuf(); + std::streambuf *old_err = std::cerr.rdbuf(); + std::ostringstream buf_out, buf_err; + std::cout.rdbuf(buf_out.rdbuf()); + std::cerr.rdbuf(buf_err.rdbuf()); + gprat::print_vector(v, 0, 100, ","); // end clamped to 2 + std::cout.rdbuf(old_out); + std::cerr.rdbuf(old_err); + REQUIRE_THAT(buf_out.str(), ContainsSubstring("5")); +} + +TEST_CASE("print_vector: invalid range", "[unit][utils]") +{ + const std::vector v = { 1.0, 2.0, 3.0 }; + std::streambuf *old_err = std::cerr.rdbuf(); + std::ostringstream buf; + std::cerr.rdbuf(buf.rdbuf()); + gprat::print_vector(v, 2, 1, ","); // start >= end → invalid + std::cerr.rdbuf(old_err); + REQUIRE_THAT(buf.str(), ContainsSubstring("Invalid")); +} + +// fp32 BLAS adapters ///////////////////////////////////////////////////////////////////////////// + +TEST_CASE("fp32 BLAS: basic ops", "[unit][blas][fp32]") +{ + hpx_runtime_guard hpx_guard; + + // potrf: Cholesky of 2x2 identity → L = I + { + auto A = make_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + const auto L = gprat::potrf(A, 2); + REQUIRE_THAT(static_cast(L.data()[0]), WithinAbs(1.0, 1e-5)); + REQUIRE_THAT(static_cast(L.data()[3]), WithinAbs(1.0, 1e-5)); + } + + // dot: 1*4 + 2*5 + 3*6 = 32 + { + const std::vector a = { 1.0f, 2.0f, 3.0f }; + const std::vector b = { 4.0f, 5.0f, 6.0f }; + REQUIRE_THAT(static_cast(gprat::dot(std::span(a), std::span(b), 3)), + WithinAbs(32.0, 1e-4)); + } + + // axpy: y -= x (alpha = -1 by convention in gprat) + { + auto y = make_tile({ 10.0f, 20.0f, 30.0f }); + auto x = make_const_tile({ 1.0f, 2.0f, 3.0f }); + const auto r = gprat::axpy(y, x, 3); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(9.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(18.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[2]), WithinAbs(27.0, 1e-5)); + } + + // syrk: C -= B*B^T (alpha = -1), C=0, B=diag(1,2) → C = -diag(1,4) + { + auto C = make_tile({ 0.0f, 0.0f, 0.0f, 0.0f }); + auto B = make_const_tile({ 1.0f, 0.0f, 0.0f, 2.0f }); + const auto r = gprat::syrk(C, B, 2); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-1.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[3]), WithinAbs(-4.0, 1e-5)); + } + + // gemm: C -= A*B (alpha=-1), C=0, A=I, B=diag(2,3) → C = -diag(2,3) + { + auto A = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto B = make_const_tile({ 2.0f, 0.0f, 0.0f, 3.0f }); + auto C = make_tile({ 0.0f, 0.0f, 0.0f, 0.0f }); + const auto r = gprat::gemm(A, B, C, 2, 2, 2, gprat::Blas_no_trans, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-2.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[3]), WithinAbs(-3.0, 1e-5)); + } + + // trsm: I * X = B → X = B + { + auto L = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto B = make_tile({ 5.0f, 7.0f, 9.0f, 11.0f }); + const auto X = gprat::trsm(L, B, 2, 2, gprat::Blas_no_trans, gprat::Blas_left); + REQUIRE_THAT(static_cast(X.data()[0]), WithinAbs(5.0, 1e-5)); + REQUIRE_THAT(static_cast(X.data()[1]), WithinAbs(7.0, 1e-5)); + } + + // trsv: I * x = b → x = b + { + auto L = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto b = make_tile({ 3.0f, 4.0f }); + const auto x = gprat::trsv(L, b, 2, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(x.data()[0]), WithinAbs(3.0, 1e-5)); + REQUIRE_THAT(static_cast(x.data()[1]), WithinAbs(4.0, 1e-5)); + } + + // gemv: I * [1,2] = [1,2] + { + auto A = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto x = make_const_tile({ 1.0f, 2.0f }); + auto y = make_tile({ 0.0f, 0.0f }); + const auto r = gprat::gemv(A, x, y, 2, 2, gprat::Blas_add, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(1.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(2.0, 1e-5)); + } + + // dot_diag_syrk: r[j] += dot(col_j(A), col_j(A)) + // A = [[1,0],[2,0]] (col-major 2x2), M=2, N=2 → r[0] += 1²+2²=5, r[1] += 0 + { + // A stored row-major 2x2: rows=[1,0],[2,0] → col 0 = [1,2], col 1 = [0,0] + auto A = make_const_tile({ 1.0f, 0.0f, 2.0f, 0.0f }); + auto r = make_tile({ 0.0f, 0.0f }); + const auto out = gprat::dot_diag_syrk(A, r, 2, 2); + REQUIRE_THAT(static_cast(out.data()[0]), WithinAbs(5.0, 1e-4)); // 1² + 2² + REQUIRE_THAT(static_cast(out.data()[1]), WithinAbs(0.0, 1e-4)); // 0² + 0² + } + + // dot_diag_gemm: r[i] += dot(row_i(A), col_i(B)) + // A=I2, B=I2 → r[i] += 1, so r = [1, 1] + { + auto A = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto B = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto r = make_tile({ 0.0f, 0.0f }); + const auto out = gprat::dot_diag_gemm(A, B, r, 2, 2); + REQUIRE_THAT(static_cast(out.data()[0]), WithinAbs(1.0, 1e-4)); + REQUIRE_THAT(static_cast(out.data()[1]), WithinAbs(1.0, 1e-4)); + } +} + +// HPX runtime suspend/resume ///////////////////////////////////////////////////////////////////// + +TEST_CASE("hpx: suspend and resume", "[unit][hpx]") +{ + hpx_runtime_guard hpx_guard; + // Suspend pauses HPX worker threads without stopping the runtime. + // Resume brings them back. A loss calculation after resume confirms the + // runtime is fully functional again. + gprat::suspend_hpx_runtime(); + gprat::resume_hpx_runtime(); + + const std::string root = gprat_data_root(); + constexpr std::size_t n = 64, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + REQUIRE(std::isfinite(gp.calculate_loss())); +} + +// gpu_algorithms coverage: gen_tile_identity, gen_tile_zeros, gen_tile_output ////////////////// + +TEST_CASE("GP::optimize: noise-only trainable", "[unit][optimizer][cpu]") +{ + // Optimising with only noise_variance trainable triggers the identity-tile + // assembly path in the gradient computation for the noise parameter. + const std::string root = gprat_data_root(); + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP gp(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { false, false, true }); + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, 3 }; + const auto losses = gp.optimize(params); + REQUIRE(losses.size() == 3); + REQUIRE(std::isfinite(losses.back())); +} + +// compute_error_norm ///////////////////////////////////////////////////////////////////////////// + +TEST_CASE("compute_error_norm: exact match", "[unit][gp_algorithms]") +{ + // Two identical tiles → error norm should be 0 + const std::size_t n_tiles = 2, tile_size = 3; + const std::vector b = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; + const std::vector> tiles = { { 1.0, 2.0, 3.0 }, { 4.0, 5.0, 6.0 } }; + REQUIRE_THAT(gprat::cpu::compute_error_norm(n_tiles, tile_size, b, tiles), WithinAbs(0.0, 1e-12)); +} + +TEST_CASE("compute_error_norm: known residual", "[unit][gp_algorithms]") +{ + // b = [0,0], tiles = [[1,0]] → error = sqrt(1²+0²) = 1 + const std::vector b = { 0.0, 0.0 }; + const std::vector> tiles = { { 1.0, 0.0 } }; + REQUIRE_THAT(gprat::cpu::compute_error_norm(1, 2, b, tiles), WithinAbs(1.0, 1e-12)); +} + +TEST_CASE("compute_error_norm: multi-tile", "[unit][gp_algorithms]") +{ + // b = [3,4,0,0], tiles = [[0,0],[0,0]] → error = sqrt(9+16) = 5 + const std::vector b = { 3.0, 4.0, 0.0, 0.0 }; + const std::vector> tiles = { { 0.0, 0.0 }, { 0.0, 0.0 } }; + REQUIRE_THAT(gprat::cpu::compute_error_norm(2, 2, b, tiles), WithinAbs(5.0, 1e-12)); +} + +// guess_good_tile_count_per_dimension: large-n paths ///////////////////////////////////////////// + +TEST_CASE("tile_count_per_dim: positive for large n", "[unit][tiles]") +{ + // n >= 2^18: enters the min(hw_concurrency, n/256) branch when hw_concurrency >= 32, + // or returns 16 when hw_concurrency < 32. Either way count >= 1 and count <= n/256. + hpx_runtime_guard hpx_guard; + const std::size_t n = 1 << 18; + const std::size_t count = gprat::guess_good_tile_count_per_dimension(n); + REQUIRE(count >= 1); + REQUIRE(count <= n / 256); +} + +// load_data error path /////////////////////////////////////////////////////////////////////////// + +TEST_CASE("load_data: throws on short file", "[unit][utils]") +{ + // Write a file with only 2 values, then try to load 5. + // Use a process-unique path so parallel test runners don't collide and so + // the file is cleaned up even if REQUIRE_THROWS_AS propagates an exception. + std::string tmp_template = + std::string(std::getenv("TMPDIR") ? std::getenv("TMPDIR") : "/tmp") + "/gprat_test_XXXXXX"; + std::vector tmp_buf(tmp_template.begin(), tmp_template.end()); + tmp_buf.push_back('\0'); + { + const int fd = ::mkstemp(tmp_buf.data()); + REQUIRE(fd != -1); + ::close(fd); + } + const std::string tmp(tmp_buf.data()); + + struct Cleanup + { + const std::string &path; + + ~Cleanup() { std::remove(path.c_str()); } + } cleanup{ tmp }; + + { + std::ofstream f(tmp); + REQUIRE(f.is_open()); + f << "1.0\n2.0\n"; + } + REQUIRE_THROWS_AS(gprat::GP_data(tmp, 5, 1), std::runtime_error); +} + +// print_vector: start clamped to 0 after negative wrap ////////////////////////////////////////// + +TEST_CASE("print_vector: deeply negative start", "[unit][utils]") +{ + // start=-10 on a 3-element vec → start = 3 + (-10) = -7, clamped to 0 + const std::vector v = { 7.0, 8.0, 9.0 }; + std::streambuf *old = std::cout.rdbuf(); + std::ostringstream buf; + std::cout.rdbuf(buf.rdbuf()); + gprat::print_vector(v, -10, 3, ","); + std::cout.rdbuf(old); + // start clamped to 0, end=3 → all elements printed + REQUIRE_THAT(buf.str(), ContainsSubstring("7")); +} + +// GPU tests (NVIDIA only) //////////////////////////////////////////////////////////////////////// +// +// Each test calls SKIP() immediately if GPRat was compiled without CUDA or if +// no NVIDIA device is detected at runtime, so they are safe to include in +// every build. When GPRAT_WITH_CUDA=ON and a GPU is present the tests run +// in full and compare GPU results against the CPU reference. + +namespace +{ +// Returns the number of visible CUDA devices (0 when CUDA is absent). +int cuda_device_count() +{ +#if GPRAT_WITH_CUDA + int n = 0; + cudaGetDeviceCount(&n); + return n; +#else + return 0; +#endif +} +} // namespace + +// Macro that skips the test if CUDA is unavailable or no GPU is present. +#define GPRAT_SKIP_IF_NO_GPU() \ + do { \ + if (!gprat::compiled_with_cuda()) \ + SKIP("GPRat not compiled with CUDA support"); \ + if (cuda_device_count() == 0) \ + SKIP("No NVIDIA GPU detected"); \ + } while (false) + +TEST_CASE("GP GPU: constructor", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + // Should not throw when a real GPU is present. + REQUIRE_NOTHROW((gprat::GP( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1))); +} + +TEST_CASE("GP::predict: GPU matches CPU", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_pred = gp_cpu.predict(test_in.data, m_tiles, m_tile_size); + const auto gpu_pred = gp_gpu.predict(test_in.data, m_tiles, m_tile_size); + + REQUIRE(cpu_pred.size() == n_test); + REQUIRE(gpu_pred.size() == n_test); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE_THAT(gpu_pred[i], WithinRel(cpu_pred[i], 1e-4)); + } +} + +TEST_CASE("GP::predict_with_uncertainty: GPU matches CPU", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_unc = gp_cpu.predict_with_uncertainty(test_in.data, m_tiles, m_tile_size); + const auto gpu_unc = gp_gpu.predict_with_uncertainty(test_in.data, m_tiles, m_tile_size); + + // cpu_unc[0] = mean, cpu_unc[1] = variance + REQUIRE(gpu_unc.size() == 2); + REQUIRE(gpu_unc[0].size() == n_test); + REQUIRE(gpu_unc[1].size() == n_test); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE_THAT(gpu_unc[0][i], WithinRel(cpu_unc[0][i], 1e-4)); + REQUIRE_THAT(gpu_unc[1][i], WithinRel(cpu_unc[1][i], 1e-4)); + } +} + +TEST_CASE("GP::predict_with_full_cov: GPU matches CPU", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_cov = gp_cpu.predict_with_full_cov(test_in.data, m_tiles, m_tile_size); + const auto gpu_cov = gp_gpu.predict_with_full_cov(test_in.data, m_tiles, m_tile_size); + + REQUIRE(gpu_cov.size() == 2); + REQUIRE(gpu_cov[0].size() == n_test); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE_THAT(gpu_cov[0][i], WithinRel(cpu_cov[0][i], 1e-4)); + } +} + +TEST_CASE("GP::calculate_loss: GPU matches CPU", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const double cpu_loss = gp_cpu.calculate_loss(); + const double gpu_loss = gp_gpu.calculate_loss(); + + REQUIRE(std::isfinite(gpu_loss)); + REQUIRE_THAT(gpu_loss, WithinRel(cpu_loss, 1e-4)); +} + +TEST_CASE("GP::cholesky: GPU tile count", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_L = gp_cpu.cholesky(); + const auto gpu_L = gp_gpu.cholesky(); + + REQUIRE(gpu_L.size() == cpu_L.size()); + REQUIRE(gpu_L[0].size() == cpu_L[0].size()); + // Diagonal tiles of L should match CPU within tolerance + for (std::size_t t = 0; t < n_tiles; ++t) + { + const std::size_t diag = t * n_tiles + t; + for (std::size_t e = 0; e < tile_size * tile_size; ++e) + { + REQUIRE_THAT(gpu_L[diag].data()[e], WithinRel(cpu_L[diag].data()[e], 1e-4)); + } + } +} + +// fp64 BLAS: additional transpose/side/alpha paths /////////////////////////////////////////////// + +TEST_CASE("fp64 BLAS: basic ops", "[unit][blas][fp64]") +{ + hpx_runtime_guard hpx_guard; + + // potrf: 2x2 identity → L = I + { + auto A = make_tile({ 1.0, 0.0, 0.0, 1.0 }); + const auto L = gprat::potrf(A, 2); + REQUIRE_THAT(static_cast(L.data()[0]), WithinAbs(1.0, 1e-10)); + REQUIRE_THAT(static_cast(L.data()[3]), WithinAbs(1.0, 1e-10)); + } + + // dot: 1*4 + 2*5 + 3*6 = 32 + { + const std::vector a = { 1.0, 2.0, 3.0 }; + const std::vector b = { 4.0, 5.0, 6.0 }; + REQUIRE_THAT(gprat::dot(std::span(a), std::span(b), 3), WithinAbs(32.0, 1e-10)); + } + + // axpy: y -= x + { + auto y = make_tile({ 10.0, 20.0, 30.0 }); + auto x = make_const_tile({ 1.0, 2.0, 3.0 }); + const auto r = gprat::axpy(y, x, 3); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(9.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[2]), WithinAbs(27.0, 1e-10)); + } + + // syrk: C -= B*B^T, C=0, B=diag(1,2) → C[0,0]=-1, C[1,1]=-4 + { + auto C = make_tile({ 0.0, 0.0, 0.0, 0.0 }); + auto B = make_const_tile({ 1.0, 0.0, 0.0, 2.0 }); + const auto r = gprat::syrk(C, B, 2); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-1.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[3]), WithinAbs(-4.0, 1e-10)); + } + + // gemm no-trans/no-trans: C -= A*B, A=I, B=diag(2,3) + { + auto A = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto B = make_const_tile({ 2.0, 0.0, 0.0, 3.0 }); + auto C = make_tile({ 0.0, 0.0, 0.0, 0.0 }); + const auto r = gprat::gemm(A, B, C, 2, 2, 2, gprat::Blas_no_trans, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-2.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[3]), WithinAbs(-3.0, 1e-10)); + } + + // gemm with trans_A: C -= A^T*B, A=[[1,2],[0,0]], B=I → C[0,0]=-1, C[1,0]=-2 + { + auto A = make_const_tile({ 1.0, 2.0, 0.0, 0.0 }); + auto B = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto C = make_tile({ 0.0, 0.0, 0.0, 0.0 }); + const auto r = gprat::gemm(A, B, C, 2, 2, 2, gprat::Blas_trans, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-1.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[2]), WithinAbs(-2.0, 1e-10)); + } + + // gemm with trans_B: C -= A*B^T, A=I, B=[[1,0],[2,0]] → C -= [[1,2],[0,0]] + { + auto A = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto B = make_const_tile({ 1.0, 0.0, 2.0, 0.0 }); + auto C = make_tile({ 0.0, 0.0, 0.0, 0.0 }); + const auto r = gprat::gemm(A, B, C, 2, 2, 2, gprat::Blas_no_trans, gprat::Blas_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-1.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(-2.0, 1e-10)); + } + + // trsm left no-trans: L*X = B → X = L^{-1}*B, L=I, B=[[5,7],[9,11]] + { + auto L = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto B = make_tile({ 5.0, 7.0, 9.0, 11.0 }); + const auto X = gprat::trsm(L, B, 2, 2, gprat::Blas_no_trans, gprat::Blas_left); + REQUIRE_THAT(static_cast(X.data()[0]), WithinAbs(5.0, 1e-10)); + REQUIRE_THAT(static_cast(X.data()[1]), WithinAbs(7.0, 1e-10)); + } + + // trsm with trans: L^T * X = B, L=[[2,0],[1,4]], L^T=[[2,1],[0,4]] + // Row-major B = [10,6,4,8] → col0=[10,4], col1=[6,8] + // X col0: x1=1, x0=(10-1)/2=4.5 → X[0,0]=4.5 + // X col1: x1=2, x0=(6-2)/2=2 → X[0,1]=2.0 + { + auto L = make_const_tile({ 2.0, 0.0, 1.0, 4.0 }); + auto B = make_tile({ 10.0, 6.0, 4.0, 8.0 }); + const auto X = gprat::trsm(L, B, 2, 2, gprat::Blas_trans, gprat::Blas_left); + REQUIRE_THAT(static_cast(X.data()[0]), WithinAbs(4.5, 1e-10)); + REQUIRE_THAT(static_cast(X.data()[1]), WithinAbs(2.0, 1e-10)); + } + + // trsm right: X * L = B, L=I → X=B + { + auto L = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto B = make_tile({ 2.0, 3.0, 4.0, 5.0 }); + const auto X = gprat::trsm(L, B, 2, 2, gprat::Blas_no_trans, gprat::Blas_right); + REQUIRE_THAT(static_cast(X.data()[0]), WithinAbs(2.0, 1e-10)); + REQUIRE_THAT(static_cast(X.data()[3]), WithinAbs(5.0, 1e-10)); + } + + // trsv no-trans: L*x = b, L=I, b=[3,4] → x=[3,4] + { + auto L = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto b = make_tile({ 3.0, 4.0 }); + const auto x = gprat::trsv(L, b, 2, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(x.data()[0]), WithinAbs(3.0, 1e-10)); + REQUIRE_THAT(static_cast(x.data()[1]), WithinAbs(4.0, 1e-10)); + } + + // trsv trans: L^T*x = b, L=[[2,0],[1,4]], L^T=[[2,1],[0,4]] + // b=[10,4]: x[1]=1, x[0]=(10-1)/2=4.5 + { + auto L = make_const_tile({ 2.0, 0.0, 1.0, 4.0 }); + auto b = make_tile({ 10.0, 4.0 }); + const auto x = gprat::trsv(L, b, 2, gprat::Blas_trans); + REQUIRE_THAT(static_cast(x.data()[0]), WithinAbs(4.5, 1e-10)); + REQUIRE_THAT(static_cast(x.data()[1]), WithinAbs(1.0, 1e-10)); + } + + // gemv Blas_add no-trans: b += A*x, A=I, x=[1,2], b=[3,4] → b=[4,6] + { + auto A = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto x = make_const_tile({ 1.0, 2.0 }); + auto b = make_tile({ 3.0, 4.0 }); + const auto r = gprat::gemv(A, x, b, 2, 2, gprat::Blas_add, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(4.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(6.0, 1e-10)); + } + + // gemv Blas_substract no-trans: b -= A*x, A=I, x=[1,2], b=[5,7] → b=[4,5] + { + auto A = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto x = make_const_tile({ 1.0, 2.0 }); + auto b = make_tile({ 5.0, 7.0 }); + const auto r = gprat::gemv(A, x, b, 2, 2, gprat::Blas_substract, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(4.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(5.0, 1e-10)); + } + + // gemv trans: b += A^T*x, A=[[1,0],[0,2]], x=[3,4], b=[0,0] + // A^T = [[1,0],[0,2]] (symmetric), A^T*x = [3, 8] + { + auto A = make_const_tile({ 1.0, 0.0, 0.0, 2.0 }); + auto x = make_const_tile({ 3.0, 4.0 }); + auto b = make_tile({ 0.0, 0.0 }); + const auto r = gprat::gemv(A, x, b, 2, 2, gprat::Blas_add, gprat::Blas_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(3.0, 1e-10)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(8.0, 1e-10)); + } + + // dot_diag_syrk fp64: r[j] += sum_i A[i,j]^2 + { + auto A = make_const_tile({ 1.0, 0.0, 2.0, 0.0 }); + auto r = make_tile({ 0.0, 0.0 }); + const auto out = gprat::dot_diag_syrk(A, r, 2, 2); + REQUIRE_THAT(static_cast(out.data()[0]), WithinAbs(5.0, 1e-10)); + REQUIRE_THAT(static_cast(out.data()[1]), WithinAbs(0.0, 1e-10)); + } + + // dot_diag_gemm fp64: r[i] += dot(row_i(A), col_i(B)), A=B=I → r=[1,1] + { + auto A = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto B = make_const_tile({ 1.0, 0.0, 0.0, 1.0 }); + auto r = make_tile({ 0.0, 0.0 }); + const auto out = gprat::dot_diag_gemm(A, B, r, 2, 2); + REQUIRE_THAT(static_cast(out.data()[0]), WithinAbs(1.0, 1e-10)); + REQUIRE_THAT(static_cast(out.data()[1]), WithinAbs(1.0, 1e-10)); + } +} + +// fp32 BLAS: additional transpose/side/alpha paths ////////////////////////////////////////////// + +TEST_CASE("fp32 BLAS: transpose and side variants", "[unit][blas][fp32]") +{ + hpx_runtime_guard hpx_guard; + + // gemm trans_A: C -= A^T*B, A=[[1,2],[0,0]], B=I + { + auto A = make_const_tile({ 1.0f, 2.0f, 0.0f, 0.0f }); + auto B = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto C = make_tile({ 0.0f, 0.0f, 0.0f, 0.0f }); + const auto r = gprat::gemm(A, B, C, 2, 2, 2, gprat::Blas_trans, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-1.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[2]), WithinAbs(-2.0, 1e-5)); + } + + // gemm trans_B: C -= A*B^T, A=I, B=[[1,0],[2,0]] + { + auto A = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto B = make_const_tile({ 1.0f, 0.0f, 2.0f, 0.0f }); + auto C = make_tile({ 0.0f, 0.0f, 0.0f, 0.0f }); + const auto r = gprat::gemm(A, B, C, 2, 2, 2, gprat::Blas_no_trans, gprat::Blas_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(-1.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(-2.0, 1e-5)); + } + + // trsm trans: L^T*X = B, L=[[2,0],[1,4]], L^T=[[2,1],[0,4]] + // Row-major B=[10,6,4,8] → col0=[10,4], col1=[6,8] + // X col0: x1=1, x0=4.5 → X[0,0]=4.5; X col1: x1=2, x0=2 → X[0,1]=2.0 + { + auto L = make_const_tile({ 2.0f, 0.0f, 1.0f, 4.0f }); + auto B = make_tile({ 10.0f, 6.0f, 4.0f, 8.0f }); + const auto X = gprat::trsm(L, B, 2, 2, gprat::Blas_trans, gprat::Blas_left); + REQUIRE_THAT(static_cast(X.data()[0]), WithinAbs(4.5, 1e-5)); + REQUIRE_THAT(static_cast(X.data()[1]), WithinAbs(2.0, 1e-5)); + } + + // trsm right: X*L = B, L=I → X=B + { + auto L = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto B = make_tile({ 2.0f, 3.0f, 4.0f, 5.0f }); + const auto X = gprat::trsm(L, B, 2, 2, gprat::Blas_no_trans, gprat::Blas_right); + REQUIRE_THAT(static_cast(X.data()[0]), WithinAbs(2.0, 1e-5)); + REQUIRE_THAT(static_cast(X.data()[3]), WithinAbs(5.0, 1e-5)); + } + + // trsv trans: L^T*x = b, L=[[2,0],[1,4]], L^T=[[2,1],[0,4]] + // b=[10,4]: x[1]=1, x[0]=(10-1)/2=4.5 + { + auto L = make_const_tile({ 2.0f, 0.0f, 1.0f, 4.0f }); + auto b = make_tile({ 10.0f, 4.0f }); + const auto x = gprat::trsv(L, b, 2, gprat::Blas_trans); + REQUIRE_THAT(static_cast(x.data()[0]), WithinAbs(4.5, 1e-5)); + REQUIRE_THAT(static_cast(x.data()[1]), WithinAbs(1.0, 1e-5)); + } + + // gemv Blas_substract: b -= A*x, A=I, x=[1,2], b=[5,7] → b=[4,5] + { + auto A = make_const_tile({ 1.0f, 0.0f, 0.0f, 1.0f }); + auto x = make_const_tile({ 1.0f, 2.0f }); + auto b = make_tile({ 5.0f, 7.0f }); + const auto r = gprat::gemv(A, x, b, 2, 2, gprat::Blas_substract, gprat::Blas_no_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(4.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(5.0, 1e-5)); + } + + // gemv trans: b += A^T*x, A=[[1,0],[0,2]], x=[3,4], b=[0,0] + // A^T = [[1,0],[0,2]] (symmetric), A^T*x = [3, 8] + { + auto A = make_const_tile({ 1.0f, 0.0f, 0.0f, 2.0f }); + auto x = make_const_tile({ 3.0f, 4.0f }); + auto b = make_tile({ 0.0f, 0.0f }); + const auto r = gprat::gemv(A, x, b, 2, 2, gprat::Blas_add, gprat::Blas_trans); + REQUIRE_THAT(static_cast(r.data()[0]), WithinAbs(3.0, 1e-5)); + REQUIRE_THAT(static_cast(r.data()[1]), WithinAbs(8.0, 1e-5)); + } +} + +// performance counters ////////////////////////////////////////////////////////////////////////// + +TEST_CASE("perf_counters: register", "[unit][perf]") +{ + hpx_runtime_guard hpx_guard; + REQUIRE_NOTHROW(gprat::register_performance_counters()); +} + +TEST_CASE("perf_counters: tile_data tracking", "[unit][perf]") +{ + // Reset counters to a known zero state via get(..., reset=true) + gprat::get_tile_data_allocations(true); + gprat::get_tile_data_deallocations(true); + + gprat::track_tile_data_allocation(64); + gprat::track_tile_data_allocation(128); + REQUIRE(gprat::get_tile_data_allocations(false) == 2); + + gprat::track_tile_data_deallocation(64); + REQUIRE(gprat::get_tile_data_deallocations(false) == 1); + + // reset=true clears to zero + REQUIRE(gprat::get_tile_data_allocations(true) == 2); + REQUIRE(gprat::get_tile_data_allocations(false) == 0); +} + +TEST_CASE("perf_counters: tile_server tracking", "[unit][perf]") +{ + gprat::get_tile_server_allocations(true); + gprat::get_tile_server_deallocations(true); + + gprat::track_tile_server_allocation(256); + gprat::track_tile_server_allocation(512); + gprat::track_tile_server_deallocation(256); + + REQUIRE(gprat::get_tile_server_allocations(false) == 2); + REQUIRE(gprat::get_tile_server_deallocations(false) == 1); + + gprat::get_tile_server_allocations(true); + gprat::get_tile_server_deallocations(true); +} + +TEST_CASE("perf_counters: transmission time", "[unit][perf]") +{ + gprat::get_tile_transmission_count(true); + gprat::get_tile_transmission_time(true); + + gprat::record_transmission_time(1000); + gprat::record_transmission_time(2000); + gprat::record_transmission_time(0); // zero elapsed: count increments, time does not + + REQUIRE(gprat::get_tile_transmission_count(false) == 3); + REQUIRE(gprat::get_tile_transmission_time(false) == 3000); + + gprat::get_tile_transmission_count(true); + gprat::get_tile_transmission_time(true); +} + +TEST_CASE("perf_counters: force_evict", "[unit][perf]") +{ + // force_evict_memory flushes CPU cache lines — verify it runs cleanly on a + // small buffer aligned to a typical cache line (64 bytes). + alignas(64) std::array buf{}; + buf.fill(3.14); + gprat::force_evict_memory(buf.data(), sizeof(buf)); + // verify buffer contents are unchanged after eviction + for (const auto v : buf) + { + REQUIRE_THAT(v, WithinAbs(3.14, 1e-15)); + } +} + +TEST_CASE("perf_counters: force_evict span", "[unit][perf]") +{ + std::vector data(32, 1.5); + gprat::force_evict_memory(std::span(data)); + for (const auto v : data) + { + REQUIRE_THAT(v, WithinAbs(1.5, 1e-15)); + } +} + +// GPU optimize and optimize_step tests ////////////////////////////////////////////////////////// + +TEST_CASE("GP::optimize: GPU loss count", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, 5 }; + const auto losses = gp_gpu.optimize(params); + + REQUIRE(losses.size() == 5); + for (const double l : losses) + { + REQUIRE(std::isfinite(l)); + } +} + +TEST_CASE("GP::optimize: GPU losses decrease", "[gpu][cuda][fragile]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 4); + + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, 10 }; + const auto losses = gp_gpu.optimize(params); + + REQUIRE(losses.size() == 10); + REQUIRE(losses.back() < losses.front()); +} + +TEST_CASE("GP::optimize_step: GPU finite loss", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, 3 }; + const double loss0 = gp_gpu.optimize_step(params, 0); + const double loss1 = gp_gpu.optimize_step(params, 1); + const double loss2 = gp_gpu.optimize_step(params, 2); + + REQUIRE(std::isfinite(loss0)); + REQUIRE(std::isfinite(loss1)); + REQUIRE(std::isfinite(loss2)); +} + +TEST_CASE("GP::optimize: GPU matches CPU", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, 5 }; + const auto cpu_losses = gp_cpu.optimize(params); + const auto gpu_losses = gp_gpu.optimize(params); + + REQUIRE(cpu_losses.size() == gpu_losses.size()); + for (std::size_t i = 0; i < cpu_losses.size(); ++i) + { + REQUIRE_THAT(gpu_losses[i], WithinRel(cpu_losses[i], 1e-3)); + } +} + +TEST_CASE("GP::cholesky: GPU values", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_L = gp_cpu.cholesky(); + const auto gpu_L = gp_gpu.cholesky(); + + REQUIRE(gpu_L.size() == cpu_L.size()); + for (std::size_t t = 0; t < cpu_L.size(); ++t) + { + REQUIRE(gpu_L[t].size() == cpu_L[t].size()); + for (std::size_t e = 0; e < cpu_L[t].size(); ++e) + { + REQUIRE_THAT(gpu_L[t].data()[e], WithinRel(cpu_L[t].data()[e], 1e-4)); + } + } +} + +TEST_CASE("GP::predict_with_uncertainty: GPU variances positive", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto gpu_unc = gp_gpu.predict_with_uncertainty(test_in.data, m_tiles, m_tile_size); + + REQUIRE(gpu_unc.size() == 2); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE(std::isfinite(gpu_unc[0][i])); + REQUIRE(gpu_unc[1][i] > 0.0); // variances must be positive + } +} + +TEST_CASE("GP::optimize: GPU no trainable params", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { false, false, false }, 0, 1); + + hpx_runtime_guard hpx_guard; + const gprat::AdamParams params{ 0.01, 0.9, 0.999, 1e-8, 3 }; + const auto losses = gp_gpu.optimize(params); + + REQUIRE(losses.size() == 3); + // With no trainable parameters all losses should be identical + REQUIRE_THAT(losses[0], WithinRel(losses[1], 1e-10)); + REQUIRE_THAT(losses[0], WithinRel(losses[2], 1e-10)); +} + +TEST_CASE("GP GPU: training data round-trip", "[gpu][cuda]") +{ + GPRAT_SKIP_IF_NO_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 64, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + REQUIRE(gp_gpu.get_training_input() == train_in.data); + REQUIRE(gp_gpu.get_training_output() == train_out.data); +} + +// SYCL GPU tests //////////////////////////////////////////////////////////////////////////////// +// Mirror of the CUDA GPU tests above, using the same GP API. +// Optimizer tests are omitted because the SYCL optimizer stubs are not yet implemented. + +#if GPRAT_WITH_SYCL + +namespace +{ +int sycl_device_count() { return gprat::gpu_count(); } +} // namespace + +#define GPRAT_SKIP_IF_NO_SYCL_GPU() \ + do { \ + if (!gprat::compiled_with_sycl()) \ + SKIP("GPRat not compiled with SYCL support"); \ + if (sycl_device_count() == 0) \ + SKIP("No SYCL GPU detected"); \ + if (!gprat::sycl_gpu_functional()) \ + SKIP("SYCL GPU runtime not functional (oneMath ABI mismatch)"); \ + } while (false) + +TEST_CASE("GP SYCL GPU: constructor", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + REQUIRE_NOTHROW((gprat::GP( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1))); +} + +TEST_CASE("GP SYCL::predict: GPU matches CPU", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_pred = gp_cpu.predict(test_in.data, m_tiles, m_tile_size); + const auto gpu_pred = gp_gpu.predict(test_in.data, m_tiles, m_tile_size); + + REQUIRE(cpu_pred.size() == n_test); + REQUIRE(gpu_pred.size() == n_test); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE_THAT(gpu_pred[i], WithinRel(cpu_pred[i], 1e-4)); + } +} + +TEST_CASE("GP SYCL::predict_with_uncertainty: GPU matches CPU", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_unc = gp_cpu.predict_with_uncertainty(test_in.data, m_tiles, m_tile_size); + const auto gpu_unc = gp_gpu.predict_with_uncertainty(test_in.data, m_tiles, m_tile_size); + + REQUIRE(gpu_unc.size() == 2); + REQUIRE(gpu_unc[0].size() == n_test); + REQUIRE(gpu_unc[1].size() == n_test); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE_THAT(gpu_unc[0][i], WithinRel(cpu_unc[0][i], 1e-4)); + REQUIRE_THAT(gpu_unc[1][i], WithinRel(cpu_unc[1][i], 1e-4)); + } +} + +TEST_CASE("GP SYCL::predict_with_full_cov: GPU matches CPU", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_cov = gp_cpu.predict_with_full_cov(test_in.data, m_tiles, m_tile_size); + const auto gpu_cov = gp_gpu.predict_with_full_cov(test_in.data, m_tiles, m_tile_size); + + REQUIRE(gpu_cov.size() == 2); + REQUIRE(gpu_cov[0].size() == n_test); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE_THAT(gpu_cov[0][i], WithinRel(cpu_cov[0][i], 1e-4)); + } +} + +TEST_CASE("GP SYCL::calculate_loss: GPU matches CPU", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const double cpu_loss = gp_cpu.calculate_loss(); + const double gpu_loss = gp_gpu.calculate_loss(); + + REQUIRE(std::isfinite(gpu_loss)); + REQUIRE_THAT(gpu_loss, WithinRel(cpu_loss, 1e-4)); +} + +TEST_CASE("GP SYCL::cholesky: GPU tile count", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_L = gp_cpu.cholesky(); + const auto gpu_L = gp_gpu.cholesky(); + + REQUIRE(gpu_L.size() == cpu_L.size()); + REQUIRE(gpu_L[0].size() == cpu_L[0].size()); + for (std::size_t t = 0; t < n_tiles; ++t) + { + const std::size_t diag = t * n_tiles + t; + for (std::size_t e = 0; e < tile_size * tile_size; ++e) + { + REQUIRE_THAT(gpu_L[diag].data()[e], WithinRel(cpu_L[diag].data()[e], 1e-4)); + } + } +} + +TEST_CASE("GP SYCL::cholesky: GPU values", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_cpu(train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }); + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto cpu_L = gp_cpu.cholesky(); + const auto gpu_L = gp_gpu.cholesky(); + + REQUIRE(gpu_L.size() == cpu_L.size()); + for (std::size_t t = 0; t < cpu_L.size(); ++t) + { + REQUIRE(gpu_L[t].size() == cpu_L[t].size()); + for (std::size_t e = 0; e < cpu_L[t].size(); ++e) + { + REQUIRE_THAT(gpu_L[t].data()[e], WithinRel(cpu_L[t].data()[e], 1e-4)); + } + } +} + +TEST_CASE("GP SYCL::predict_with_uncertainty: GPU variances positive", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 128, n_tiles = 4, n_reg = 8, n_test = 64; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + const auto [m_tiles, m_tile_size] = gprat::compute_test_tiles(n_test, n_tiles, tile_size); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + gprat::GP_data test_in(root + "/data_1024/test_input.txt", n_test, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + hpx_runtime_guard hpx_guard; + const auto gpu_unc = gp_gpu.predict_with_uncertainty(test_in.data, m_tiles, m_tile_size); + + REQUIRE(gpu_unc.size() == 2); + for (std::size_t i = 0; i < n_test; ++i) + { + REQUIRE(std::isfinite(gpu_unc[0][i])); + REQUIRE(gpu_unc[1][i] > 0.0); + } +} + +TEST_CASE("GP SYCL GPU: training data round-trip", "[gpu][sycl]") +{ + GPRAT_SKIP_IF_NO_SYCL_GPU(); + + const std::string root = gprat_data_root(); + + constexpr std::size_t n = 64, n_tiles = 4, n_reg = 8; + const std::size_t tile_size = gprat::compute_train_tile_size(n, n_tiles); + + gprat::GP_data train_in(root + "/data_1024/training_input.txt", n, n_reg); + gprat::GP_data train_out(root + "/data_1024/training_output.txt", n, n_reg); + + gprat::GP gp_gpu( + train_in.data, train_out.data, n_tiles, tile_size, n_reg, { 1.0, 1.0, 0.1 }, { true, true, true }, 0, 1); + + REQUIRE(gp_gpu.get_training_input() == train_in.data); + REQUIRE(gp_gpu.get_training_output() == train_out.data); +} + +#endif // GPRAT_WITH_SYCL + +} // namespace gprat::test diff --git a/vcpkg.json b/vcpkg.json index 438621a2..0b252332 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -13,9 +13,19 @@ "name": "fmt" }, { - "name": "hpx" + "name": "hpx", + "features": [ + "cuda", + "bzip2", + "mpi", + "snappy", + "zlib" + ] + }, + { + "name": "cuda" } ], "default-features": [], - "builtin-baseline": "e08b7bd89ae162f8579df2f8d39a1ae94107c8fd" + "builtin-baseline": "365f6444ab40ee87c73c947b475b3a267b3cb77c" }