diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 193aee2..87d27d7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,12 +30,12 @@ jobs: - name: Set compile target shell: bash run: | - if [[ "$RUNNER_OS" == "Linux" ]]; then - VCPKG_HOST_TRIPLET=x64-linux-dynamic - elif [[ "$RUNNER_OS" == "Windows" ]]; then - VCPKG_HOST_TRIPLET=x64-mingw-dynamic + if [[ "$RUNNER_OS" == "Windows" ]]; then + VCPKG_HOST_TRIPLET=x64-windows-static-md + elif [[ "$RUNNER_OS" == "Linux" ]]; then + VCPKG_HOST_TRIPLET=x64-linux elif [[ "$RUNNER_OS" == "macOS" ]]; then - VCPKG_HOST_TRIPLET=arm64-osx-dynamic + VCPKG_HOST_TRIPLET=arm64-osx fi echo VCPKG_HOST_TRIPLET="$VCPKG_HOST_TRIPLET" >> $GITHUB_ENV echo $VCPKG_HOST_TRIPLET diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index edd1509..929e237 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Cache dependencies + - name: Cache dependencies. # TODO - this may not work on linux b/c os is different than container? id: cache-vcpkg-deps uses: actions/cache@v4 with: @@ -38,13 +38,13 @@ jobs: run: | case "${RUNNER_OS}" in "Windows") - VCPKG_HOST_TRIPLET="x64-mingw-dynamic" + VCPKG_HOST_TRIPLET="x64-windows-static-md" ;; "Linux") - VCPKG_HOST_TRIPLET="x64-linux-dynamic" + VCPKG_HOST_TRIPLET="x64-linux" ;; "macOS") - VCPKG_HOST_TRIPLET="arm64-osx-dynamic" + VCPKG_HOST_TRIPLET="arm64-osx" ;; *) echo "Unsupported RUNNER_OS: ${RUNNER_OS}" diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bfb83e..34d1481 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.4...3.18) project(cppcore) -set(VCPKG_HOST_TRIPLET $ENV{VCPKG_HOST_TRIPLET}) set(VCPKG_HOST_TRIPLET $ENV{VCPKG_HOST_TRIPLET}) set(PYBIND11_FINDPYTHON ON) @@ -13,9 +12,24 @@ message(STATUS "vcpkg Triplet: ${VCPKG_HOST_TRIPLET}") set(EIGEN_PATH "${CMAKE_SOURCE_DIR}/vcpkg_installed/${VCPKG_HOST_TRIPLET}/include") message(STATUS "Eigen Path: ${EIGEN_PATH}") +set(GSL_DIR "${CMAKE_SOURCE_DIR}/vcpkg_installed/${VCPKG_HOST_TRIPLET}") +message(STATUS "GSL Path: ${GSL_DIR}") +set(GSL_INCLUDE_DIR "${GSL_DIR}/include") +set(GSL_LIBRARY_DIR "${GSL_DIR}/lib") +find_library(GSL_LIB gsl PATHS "${GSL_LIBRARY_DIR}") +find_library(GSLCBLAS_LIB gslcblas PATHS "${GSL_LIBRARY_DIR}") + +set(NLOPT_DIR "${CMAKE_SOURCE_DIR}/vcpkg_installed/${VCPKG_HOST_TRIPLET}") +message(STATUS "NLOPT Path: ${NLOPT_DIR}") +set(NLOPT_DIR_INCLUDE_DIR "${NLOPT_DIR}/include") +set(NLOPT_DIR_LIBRARY_DIR "${NLOPT_DIR}/lib") +find_library(NLOPT_LIB nlopt PATHS "${NLOPT_DIR_LIBRARY_DIR}") + pybind11_add_module(cppcore src/cpp/main.cpp) -include_directories(${CMAKE_SOURCE_DIR}/src/cpp ${EIGEN_PATH}) +include_directories(${CMAKE_SOURCE_DIR}/src/cpp ${EIGEN_PATH} ${GSL_INCLUDE_DIR} ${NLOPT_DIR_INCLUDE_DIR}) +target_include_directories(cppcore PRIVATE ${GSL_INCLUDE_DIR} ${NLOPT_DIR_INCLUDE_DIR}) +target_link_libraries(cppcore PRIVATE ${GSL_LIB} ${GSLCBLAS_LIB} ${NLOPT_LIB}) target_compile_definitions( cppcore diff --git a/src/cpp/main.cpp b/src/cpp/main.cpp index 9601dfd..38e0c98 100644 --- a/src/cpp/main.cpp +++ b/src/cpp/main.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include #include +#include #define STRINGIFY(x) #x #define MACRO_STRINGIFY(x) STRINGIFY(x) @@ -32,6 +35,37 @@ py::array_t eigen_matmul(py::array_t nlopt_demo(const std::vector& lower_bounds, + const std::vector& upper_bounds) { + if (lower_bounds.size() != 2 || upper_bounds.size() != 2) + throw std::invalid_argument("Bounds must have size 2"); + + nlopt_opt opt = nlopt_create(NLOPT_LN_NELDERMEAD, 2); + nlopt_set_lower_bounds(opt, lower_bounds.data()); + nlopt_set_upper_bounds(opt, upper_bounds.data()); + nlopt_set_min_objective(opt, objfunc, nullptr); + + double x[2] = {0.0, 0.0}; + double minf; + int result = nlopt_optimize(opt, x, &minf); + nlopt_destroy(opt); + if (result < 0) throw std::runtime_error("nlopt failed"); + return {x[0], x[1]}; +} + PYBIND11_MODULE(cppcore, m) { m.doc() = R"pbdoc( Pybind11 example plugin @@ -59,4 +93,8 @@ PYBIND11_MODULE(cppcore, m) { )pbdoc"); m.def("eigen_matmul", &eigen_matmul, "Matrix multiplication using Eigen"); + m.def("gsl_bessel", &gsl_bessel, "Bessel function using GSL"); + m.def("nlopt_optimize", &nlopt_demo, + py::arg("lower_bounds"), py::arg("upper_bounds"), + "Run NLOPT optimization with specified bounds"); } diff --git a/tests/test_basic.py b/tests/test_basic.py index fbb9120..0592450 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1,3 +1,4 @@ +import pytest import numpy as np import demo @@ -16,3 +17,13 @@ def test_eigen_matmul(): result = cppcore.eigen_matmul(a, b) expected = np.matmul(a, b) np.testing.assert_allclose(result, expected) + + +def test_gsl_bessel(): + assert pytest.approx(1.0, rel=1e-8) == cppcore.gsl_bessel(0.0) + assert pytest.approx(0.7651976865, rel=1e-8) == cppcore.gsl_bessel(1.0) + + +def test_nlopt_optimize(): + res = cppcore.nlopt_optimize([-10, -10], [10, 10]) + assert pytest.approx([1.0, 2.0]) == res