diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..b165063 --- /dev/null +++ b/.flake8 @@ -0,0 +1,8 @@ +[flake8] +max-line-length = 120 +exclude = + .git, + __pycache__, + build, + dist, + *.egg-info \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a36493..8f6041a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,10 +2,10 @@ name: CI on: push: - branches: [ master, dev ] + branches: [ '**'] tags: [ 'v*' ] pull_request: - branches: [ master, dev ] + branches: [ master ] permissions: contents: write @@ -25,25 +25,21 @@ jobs: if: runner.os == 'Linux' run: | sudo apt-get update - sudo apt-get install -y cmake libeigen3-dev + sudo apt-get install -y cmake libeigen3-dev libgtest-dev - name: Install dependencies (macOS) if: runner.os == 'macOS' run: | - brew install cmake eigen + brew install cmake eigen googletest - name: Configure CMake - run: | - cmake -B build -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTS=ON \ - -DBUILD_EXAMPLES=ON + run: cmake -B build -DCMAKE_BUILD_TYPE=Release -DLIBGP_BUILD_TESTS=ON - name: Build - run: cmake --build build --config Release + run: cmake --build build - name: Test - working-directory: build - run: ctest --output-on-failure -C Release + run: cmake --build build --target test - name: Create Package run: | diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index bc16fe5..6ade3e5 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,127 +1,110 @@ -# Created by Manuel Blum on 2011-05-25. -# Copyright 2013 University of Freiburg. - -cmake_minimum_required(VERSION 3.14) - -# Add cmake modules directory -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -# Include version validation -include(VersionValidation) +cmake_minimum_required(VERSION 3.14...3.22) project(libgp - VERSION 0.1.5 - DESCRIPTION "Gaussian Process Regression Library" + VERSION "0.1.5" + DESCRIPTION "C++ Library for Gaussian Process Regression" LANGUAGES CXX) -# Validate version -validate_version(VERSION ${PROJECT_VERSION}) - -# Load common settings -include(CommonSettings) +include(FetchContent) -# Check for required C++ features -include(CheckCXXCompilerFlag) -include(CheckCXXSourceCompiles) +# Options +option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF) +option(LIBGP_BUILD_ALL "Build everything (tests and examples)" OFF) +option(LIBGP_BUILD_TESTS "Build libgp tests" ${LIBGP_BUILD_ALL}) +option(LIBGP_BUILD_EXAMPLES "Build example applications" ${LIBGP_BUILD_ALL}) +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) # Changed to OFF for static linking -# Force C++17 before feature test +# Set C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Added for Python bindings -# Configure version header +# Dependencies +find_package(Eigen3 REQUIRED) + +# Generate version header configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/include/gp_version.h.in - ${CMAKE_CURRENT_BINARY_DIR}/include/gp_version.h + "${PROJECT_SOURCE_DIR}/include/gp_version.h.in" + "${PROJECT_BINARY_DIR}/include/gp_version.h" @ONLY ) -# Feature tests -check_cxx_source_compiles(" - #include - #include - #include - int main() { - static_assert(std::is_same_v); - std::string_view sv = \"test\"; - std::optional opt; - return 0; - }" - HAVE_CPP17_FEATURES +# Core library +add_library(gp STATIC # Changed to STATIC + src/gp.cc + src/gp_utils.cc + src/sampleset.cc + src/rprop.cc + src/cg.cc + src/input_dim_filter.cc + src/cov.cc + src/cov_factory.cc + src/cov_linear_ard.cc + src/cov_linear_one.cc + src/cov_matern3_iso.cc + src/cov_matern5_iso.cc + src/cov_noise.cc + src/cov_periodic.cc + src/cov_periodic_matern3_iso.cc + src/cov_prod.cc + src/cov_rq_iso.cc + src/cov_se_ard.cc + src/cov_se_iso.cc + src/cov_sum.cc ) -if(NOT HAVE_CPP17_FEATURES) - message(FATAL_ERROR "Compiler does not support required C++17 features") -endif() - -# Set visibility settings -set(CMAKE_CXX_VISIBILITY_PRESET hidden) -set(CMAKE_VISIBILITY_INLINES_HIDDEN YES) - -# Find dependencies -set(CMAKE_PREFIX_PATH "/opt/homebrew/share/eigen3/cmake" ${CMAKE_PREFIX_PATH}) -find_package(Eigen3 3.0.1 NO_MODULE REQUIRED) -find_package(Threads REQUIRED) - -# Create library target -add_library(gp) -add_library(libgp::gp ALIAS gp) - -# Include sources -include("Sources.cmake") -target_sources(gp PRIVATE ${LIBGP_SRC}) - -# Apply common settings -libgp_set_common_properties(gp) - -# Modern way to handle include directories target_include_directories(gp PUBLIC $ + $ $ - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src ) -target_link_libraries(gp - PUBLIC - Eigen3::Eigen - PRIVATE - Threads::Threads -) +target_link_libraries(gp PUBLIC Eigen3::Eigen) -target_compile_definitions(gp - PRIVATE - libgp_EXPORTS - $<$:ENABLE_TESTING> -) +# Python bindings +if(BUILD_PYTHON_BINDINGS) + set(PYBIND11_FINDPYTHON ON) + find_package(pybind11 CONFIG REQUIRED) + pybind11_add_module(libgp src/bindings.cpp) + target_link_libraries(libgp PRIVATE gp Eigen3::Eigen) -# Enable testing with CTest -if(BUILD_TESTS) + # Install both the Python module and the shared library together + install(TARGETS libgp gp + LIBRARY DESTINATION . + RUNTIME DESTINATION .) +endif() + +# Tests +if(LIBGP_BUILD_TESTS) enable_testing() - include(CTest) - add_subdirectory(tests ${CMAKE_CURRENT_BINARY_DIR}/tests_build) + find_package(GTest REQUIRED) + + function(add_gp_test name) + add_executable(${name} tests/${name}.cc) + target_link_libraries(${name} PRIVATE gp GTest::GTest GTest::Main) + add_test(NAME ${name} COMMAND ${name}) + endfunction() + + add_gp_test(test_gp_regression) + add_gp_test(test_log_likelihood) + add_gp_test(test_cov_factory) + add_gp_test(test_covariance_functions) + add_gp_test(test_gp_utils) + add_gp_test(test_optimizer) +endif() + +# Examples +if(LIBGP_BUILD_EXAMPLES) + add_executable(gp_example_dense examples/gp_example_dense.cc) + target_link_libraries(gp_example_dense PRIVATE gp) endif() # Installation include(GNUInstallDirs) -include(CMakePackageConfigHelpers) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/libgp) -# Configure version file -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/libgpConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion -) - -# Configure config files -configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/libgp-config.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/libgpConfig.cmake" - INSTALL_DESTINATION ${INSTALL_CONFIGDIR} -) - install(TARGETS gp EXPORT libgp-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -130,16 +113,15 @@ install(TARGETS gp INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) + install(DIRECTORY include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gp + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" + PATTERN "*.h.in" EXCLUDE ) -# Install CMake config files -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/libgpConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/libgpConfigVersion.cmake" - DESTINATION ${INSTALL_CONFIGDIR} +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/gp_version.h" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) # Export targets @@ -149,14 +131,33 @@ install(EXPORT libgp-targets DESTINATION ${INSTALL_CONFIGDIR} ) -# Generate pkg-config file -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/contrib/libgp.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/libgp.pc @ONLY) +# Create and install config files +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/libgpConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion +) + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/contrib/libgp.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/libgpConfig.cmake" + INSTALL_DESTINATION ${INSTALL_CONFIGDIR} +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/libgpConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/libgpConfigVersion.cmake" + DESTINATION ${INSTALL_CONFIGDIR} +) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgp.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +# Generate and install pkg-config file +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/contrib/libgp.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/libgp.pc" + @ONLY +) -# Add components -if(BUILD_EXAMPLES) - add_subdirectory(examples) -endif() +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libgp.pc" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig +) \ No newline at end of file diff --git a/README.md b/README.md index 4110701..437dfbd 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ A C++ library for Gaussian process regression. A Gaussian process defines a dist 1. Create a build directory and configure the project with tests enabled: ```bash -cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON +cmake -B build -DCMAKE_BUILD_TYPE=Release ``` 2. Build the library: @@ -27,22 +27,22 @@ cmake --build build For development and debugging, you can use Debug build type: ```bash -cmake -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON +cmake -B build -DCMAKE_BUILD_TYPE=Debug -DLIBGP_BUILD_TESTS=ON ``` ### Running Tests The project uses Google Test for unit testing. Tests are automatically configured when building the project. -1. Build the tests (they are built automatically with the main build): +1. Build the tests: ```bash +cmake -B build -DCMAKE_BUILD_TYPE=Release -DLIBGP_BUILD_TESTS=ON cmake --build build ``` 2. Run all tests: ```bash -cd build -ctest --output-on-failure +cmake --build build --target test ``` ### Examples @@ -50,7 +50,13 @@ ctest --output-on-failure The library includes example code demonstrating how to use Gaussian Process regression. To build and run the examples: ```bash -./build/examples/gpdense +cmake -B build -DCMAKE_BUILD_TYPE=Release -DLIBGP_BUILD_EXAMPLES=ON +cmake --build build +``` + +Then run the example: +```bash +./build/gp_example_dense ``` The example demonstrates: @@ -62,17 +68,13 @@ The example demonstrates: For more details, see the source code in `examples/gp_example_dense.cc`. -## Installing +## Python Bindings -```bash -cmake --install build -``` +This library provides Python bindings for Gaussian Process regression. The bindings are generated using pybind11, allowing you to use the C++ library directly in Python. -After installation, you can use libgp in your CMake project: - -```cmake -find_package(libgp REQUIRED) -target_link_libraries(your_target PRIVATE libgp::gp) +```bash +pip install . +python examples/python_example.py ``` ## Implemented covariance functions diff --git a/Sources.cmake b/Sources.cmake deleted file mode 100755 index 6eefdd6..0000000 --- a/Sources.cmake +++ /dev/null @@ -1,45 +0,0 @@ -SET(LIBGP_SRC - src/cov.cc - src/cov_factory.cc - src/cov_linear_ard.cc - src/cov_linear_one.cc - src/cov_matern3_iso.cc - src/cov_matern5_iso.cc - src/cov_noise.cc - src/cov_rq_iso.cc - src/cov_periodic_matern3_iso.cc - src/cov_periodic.cc - src/cov_se_ard.cc - src/cov_se_iso.cc - src/cov_sum.cc - src/cov_prod.cc - src/gp.cc - src/gp_utils.cc - src/sampleset.cc - src/rprop.cc - src/input_dim_filter.cc - src/cg.cc -) - -SET(LIBGP_INTERFACES - include/cov.h - include/cov_factory.h - include/cov_linear_ard.h - include/cov_linear_one.h - include/cov_matern3_iso.h - include/cov_matern5_iso.h - include/cov_noise.h - include/cov_rq_iso.h - include/cov_periodic_matern3_iso.h - include/cov_periodic.h - include/cov_se_ard.h - include/cov_se_iso.h - include/cov_sum.h - include/cov_prod.h - include/gp.h - include/gp_utils.h - include/sampleset.h - include/rprop.h - include/input_dim_filter.h - include/cg.h -) diff --git a/cmake/CommonSettings.cmake b/cmake/CommonSettings.cmake deleted file mode 100644 index 52dc2f3..0000000 --- a/cmake/CommonSettings.cmake +++ /dev/null @@ -1,26 +0,0 @@ -# Common settings for all targets in libgp project - -# Set C++ standard -macro(libgp_set_cpp_standard target) - set_target_properties(${target} - PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON - CXX_EXTENSIONS OFF - ) -endmacro() - -# Set common compiler warnings -macro(libgp_set_compiler_warnings target) - target_compile_options(${target} - PRIVATE - $<$:-Wall -Wextra -Wpedantic> - $<$:/W4> - ) -endmacro() - -# Set common build settings -macro(libgp_set_common_properties target) - libgp_set_cpp_standard(${target}) - libgp_set_compiler_warnings(${target}) -endmacro() \ No newline at end of file diff --git a/cmake/VersionValidation.cmake b/cmake/VersionValidation.cmake deleted file mode 100644 index 5fc99f3..0000000 --- a/cmake/VersionValidation.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# Validates that version numbers follow semantic versioning -include(CMakeParseArguments) - -function(validate_version) - cmake_parse_arguments(PARSE_ARGV 0 ARG "" "VERSION" "") - - if(NOT ARG_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+$") - message(FATAL_ERROR "Version '${ARG_VERSION}' does not follow semantic versioning (major.minor.patch)") - endif() - - string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" VERSION_MATCH "${ARG_VERSION}") - set(MAJOR "${CMAKE_MATCH_1}") - set(MINOR "${CMAKE_MATCH_2}") - set(PATCH "${CMAKE_MATCH_3}") - - if(MAJOR EQUAL 0) - message(STATUS "Package is still in initial development (version ${ARG_VERSION})") - endif() -endfunction() \ No newline at end of file diff --git a/cmake/libgp-config-version.cmake.in b/cmake/libgp-config-version.cmake.in deleted file mode 100644 index ca5947f..0000000 --- a/cmake/libgp-config-version.cmake.in +++ /dev/null @@ -1,10 +0,0 @@ -set(PACKAGE_VERSION "@PROJECT_VERSION@") - -if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) - set(PACKAGE_VERSION_COMPATIBLE FALSE) -else() - set(PACKAGE_VERSION_COMPATIBLE TRUE) - if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) - set(PACKAGE_VERSION_EXACT TRUE) - endif() -endif() \ No newline at end of file diff --git a/cmake/libgp-config.cmake.in b/cmake/libgp-config.cmake.in deleted file mode 100644 index f9052a4..0000000 --- a/cmake/libgp-config.cmake.in +++ /dev/null @@ -1,21 +0,0 @@ -@PACKAGE_INIT@ - -include(CMakeFindDependencyMacro) - -# Find dependencies -find_dependency(Eigen3 3.0.1) - -# Include targets -include("${CMAKE_CURRENT_LIST_DIR}/libgpTargets.cmake") - -# Provide component support -foreach(_comp ${libgp_FIND_COMPONENTS}) - if(_comp STREQUAL "examples") - set(libgp_examples_FOUND TRUE) - else() - set(libgp_${_comp}_FOUND FALSE) - if(libgp_FIND_REQUIRED_${_comp}) - message(FATAL_ERROR "Unsupported libgp component: ${_comp}") - endif() - endif() -endforeach() \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt deleted file mode 100755 index 8eb3a6b..0000000 --- a/examples/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# libgp - Gaussian process library for Machine Learning -# Copyright (c) 2013, Manuel Blum -# All rights reserved. - -# Examples configuration -add_executable(gpdense gp_example_dense.cc) -target_link_libraries(gpdense - PRIVATE - libgp::gp -) - -# Apply common settings -libgp_set_common_properties(gpdense) - -# Install examples (optional) -install(TARGETS gpdense - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/examples - OPTIONAL -) - -# Install example source files for reference -install(FILES - gp_example_dense.cc - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/libgp/examples - OPTIONAL -) diff --git a/examples/python_example.py b/examples/python_example.py new file mode 100644 index 0000000..afb8bb4 --- /dev/null +++ b/examples/python_example.py @@ -0,0 +1,42 @@ +import math + +from libgp import GaussianProcess + + +def main(): + # Create a 2D Gaussian Process with SE kernel + input_dim = 2 + gp = GaussianProcess(input_dim, "CovSum(CovSEiso, CovNoise)") + + # Set hyperparameters (log-values for length-scale, signal variance, and noise) + params = [0.0, 0.0, -2.0] # [log(l), log(sf), log(sigma_n)] + gp.set_loghyper(params) + + # Generate some sample data + x = [ + [0.0, 0.0], + [0.0, 1.0], + [1.0, 0.0], + [1.0, 1.0] + ] + y = [0.0, 0.5, 0.5, 1.0] + + # Add training data + for xi, yi in zip(x, y): + gp.add_pattern(xi, yi) + + # Make predictions + test_point = [0.5, 0.5] + mean = gp.predict(test_point) + var = gp.get_variance(test_point) + + print(f"Number of training points: {gp.get_sampleset_size()}") + print(f"Prediction at {test_point}:") + print(f"Mean: {mean:.3f}") + print(f"Variance: {var:.3f}") + print(f"95% Confidence Interval: [{mean-2*math.sqrt(var):.3f}, {mean+2*math.sqrt(var):.3f}]") + print(f"Log likelihood: {gp.get_log_likelihood():.3f}") + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4af8da9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,27 @@ +[build-system] +requires = ["scikit-build-core>=0.10", "pybind11"] +build-backend = "scikit_build_core.build" + +[project] +name = "libgp" +version = "0.1.5" +description = "C++ Library for Gaussian Process Regression" +readme = "README.md" +requires-python = ">=3.7" +authors = [ + {name = "libgp contributors"} +] +dependencies = ["numpy"] + +[project.optional-dependencies] +dev = ["flake8>=6.0.0"] + +[tool.scikit-build] +cmake.minimum-version = "3.14" +cmake.args = [ + "-DBUILD_PYTHON_BINDINGS=ON", + "-DBUILD_SHARED_LIBS=ON", + "-DLIBGP_BUILD_TESTS=OFF", + "-DLIBGP_BUILD_EXAMPLES=OFF", + "-DCMAKE_POSITION_INDEPENDENT_CODE=ON", +] \ No newline at end of file diff --git a/src/bindings.cpp b/src/bindings.cpp new file mode 100644 index 0000000..135de12 --- /dev/null +++ b/src/bindings.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include "gp.h" +#include "cov_factory.h" + +namespace py = pybind11; + +PYBIND11_MODULE(libgp, m) { + m.doc() = "Python bindings for libgp - Gaussian Process Regression Library"; + + py::class_(m, "GaussianProcess") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def("add_pattern", [](libgp::GaussianProcess& self, py::array_t x, double y) { + py::buffer_info buf = x.request(); + if (buf.ndim != 1) + throw std::runtime_error("Input array must be 1-dimensional"); + double* ptr = static_cast(buf.ptr); + self.add_pattern(ptr, y); + }) + .def("predict", [](libgp::GaussianProcess& self, py::array_t x) { + py::buffer_info buf = x.request(); + if (buf.ndim != 1) + throw std::runtime_error("Input array must be 1-dimensional"); + double* ptr = static_cast(buf.ptr); + return self.f(ptr); + }) + .def("get_variance", [](libgp::GaussianProcess& self, py::array_t x) { + py::buffer_info buf = x.request(); + if (buf.ndim != 1) + throw std::runtime_error("Input array must be 1-dimensional"); + double* ptr = static_cast(buf.ptr); + return self.var(ptr); + }) + .def("set_y", &libgp::GaussianProcess::set_y) + .def("get_sampleset_size", &libgp::GaussianProcess::get_sampleset_size) + .def("clear_sampleset", &libgp::GaussianProcess::clear_sampleset) + .def("get_log_likelihood", &libgp::GaussianProcess::log_likelihood) + .def("get_log_likelihood_gradient", &libgp::GaussianProcess::log_likelihood_gradient) + .def("get_input_dim", &libgp::GaussianProcess::get_input_dim) + .def("set_loghyper", [](libgp::GaussianProcess& self, py::array_t params) { + py::buffer_info buf = params.request(); + if (buf.ndim != 1) + throw std::runtime_error("Parameter array must be 1-dimensional"); + Eigen::Map eigen_params(static_cast(buf.ptr), buf.shape[0]); + self.covf().set_loghyper(eigen_params); + }) + .def("get_loghyper", [](libgp::GaussianProcess& self) { + return py::array_t( + {static_cast(self.covf().get_param_dim())}, + {sizeof(double)}, + self.covf().get_loghyper().data() + ); + }) + .def("get_param_dim", [](libgp::GaussianProcess& self) { + return self.covf().get_param_dim(); + }); + + py::class_(m, "CovFactory") + .def(py::init<>()) + .def("create", &libgp::CovFactory::create) + .def("list", &libgp::CovFactory::list); +} \ No newline at end of file diff --git a/src/gp_sparse.cc b/src/gp_sparse.cc deleted file mode 100644 index a796bf7..0000000 --- a/src/gp_sparse.cc +++ /dev/null @@ -1,39 +0,0 @@ -// libgp - Gaussian process library for Machine Learning -// Copyright (c) 2013, Manuel Blum -// All rights reserved. - -#include "gp_sparse.h" - -namespace libgp { - - SparseGaussianProcess::SparseGaussianProcess (size_t input_dim, std::string covf_def) : GaussianProcess(input_dim, covf_def) {} - - SparseGaussianProcess::SparseGaussianProcess (const char * filename) : GaussianProcess(filename) {} - - SparseGaussianProcess::~SparseGaussianProcess () {} - - void SparseGaussianProcess::compute() - { - if (cf->get_threshold() == INFINITY) { - std::cerr << "warning: no threshold defined, computation will be slow." << std::endl - << "Use full GP or define distance threshold!" << std::endl; - } - if (sampleset->empty()) return; - Eigen::SparseMatrix K(sampleset->size(), sampleset->size()); - alpha.resize(sampleset->size()); - // compute kernel matrix (lower triangle) - for(size_t i = 0; i < sampleset->size(); ++i) { - K.startVec(i); - for(size_t j = i; j < sampleset->size(); ++j) { - double cov = cf->get(sampleset->x(i), sampleset->x(j)); - if (cov != 0) K.insertBack(j,i) = cov; - } - alpha(i) = sampleset->y(i); - } - K.finalize(); - // perform cholesky factorization - solver.compute(K); - alpha = solver.solve(alpha); - } - -} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100755 index a440084..0000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -include(FetchContent) - -# Set minimum CMake version for Google Test -set(CMAKE_MINIMUM_REQUIRED_VERSION 3.14) - -# Modern GTest integration using FetchContent -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.14.0 -) - -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - -# Enable testing -include(GoogleTest) -enable_testing() - -# Include test sources -include("Sources.cmake") - -# Create test executable -add_executable(gptest ${LIBGP_TESTS}) -target_link_libraries(gptest - PRIVATE - gp - GTest::gtest - GTest::gtest_main - ${CMAKE_THREAD_LIBS_INIT} -) - -# Apply common settings -libgp_set_common_properties(gptest) - -# Add test labels based on file names -foreach(TEST_FILE ${LIBGP_TESTS}) - get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE) - if(${TEST_NAME} MATCHES "^test_") - string(SUBSTRING ${TEST_NAME} 5 -1 LABEL_NAME) - else() - set(LABEL_NAME ${TEST_NAME}) - endif() - set_source_files_properties(${TEST_FILE} PROPERTIES - LABELS "${LABEL_NAME}" - ) -endforeach() - -# Configure test discovery with increased timeout -gtest_discover_tests(gptest - PROPERTIES - LABELS "unit" - TIMEOUT 30 - DISCOVERY_TIMEOUT 60 - XML_OUTPUT_DIR "${CMAKE_BINARY_DIR}/test-results" -) diff --git a/tests/Sources.cmake b/tests/Sources.cmake deleted file mode 100755 index 4b89410..0000000 --- a/tests/Sources.cmake +++ /dev/null @@ -1,9 +0,0 @@ -SET(LIBGP_TESTS - gp_regression_test.cc - #gp_sparse_regression_test.cc - log_likelihood_test.cc - test_optimizer.cc - test_covariance_functions.cc - test_gp_utils.cc - test_cov_factory.cc -) diff --git a/tests/gp_sparse_regression_test.cc b/tests/gp_sparse_regression_test.cc deleted file mode 100644 index 75ce055..0000000 --- a/tests/gp_sparse_regression_test.cc +++ /dev/null @@ -1,45 +0,0 @@ -// libgp - Gaussian process library for Machine Learning -// Copyright (c) 2011, Manuel Blum -// All rights reserved. - -#include "gp.h" -#include "gp_sparse.h" -#include "gp_utils.h" - -#include -#include -#include - - -TEST(GPSparseRegressionTest, CompareToDense) { - - libgp::GaussianProcess gp(2, "CovSum(CovSEiso, CovNoise)"); - libgp::SparseGaussianProcess gp_sparse(2, "CovSum(CovRBFCS, CovNoise)"); - - double params[] = {0.0, 0.0, -2}; - gp.covf().set_loghyper(params); - gp_sparse.covf().set_loghyper(params); - gp_sparse.covf().set_threshold(1e12); - for (int i=0; i<500; ++i) { - double x[] = {drand48()*4-2, drand48()*4-2}; - double y = libgp::Utils::hill(x[0], x[1]); - gp.add_pattern(x, y); - gp_sparse.add_pattern(x, y); - } - gp.compute(); - gp_sparse.compute(); - double error, tss = 0.0; - for (int i=0; i<500; ++i) { - double x[] = {drand48()*4-2, drand48()*4-2}; - error = gp.f(x) - gp_sparse.f(x); - ASSERT_NEAR(0.0, error, 1e-9); - } - gp_sparse.covf().set_threshold(1); - gp_sparse.compute(); - for (int i=0; i<500; ++i) { - double x[] = {drand48()*4-2, drand48()*4-2}; - error = gp.f(x) - gp_sparse.f(x); - tss += error*error; - } - ASSERT_GT(0.1, tss/500); -} diff --git a/tests/gp_regression_test.cc b/tests/test_gp_regression.cc similarity index 100% rename from tests/gp_regression_test.cc rename to tests/test_gp_regression.cc diff --git a/tests/log_likelihood_test.cc b/tests/test_log_likelihood.cc similarity index 100% rename from tests/log_likelihood_test.cc rename to tests/test_log_likelihood.cc