diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 30cc96d..87ef251 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -11,17 +11,17 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] build_type: [Release, Debug] steps: - uses: actions/checkout@v3 - name: Configure CMake - run: cmake -B build -S . -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + run: cmake -B build -S . -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_VERBOSE_MAKEFILE=ON - name: Build run: cmake --build build --config ${{ matrix.build_type }} - name: Run tests - run: ./build/all_tests + run: cd build && ctest -C ${{ matrix.build_type }} --verbose diff --git a/CMakeLists.txt b/CMakeLists.txt index 24f9139..b0d91c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,19 +20,23 @@ else() message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") endif() -# Warning flags (always enabled) -add_compile_options( - -Wall # Enable most warnings - -Wextra # Extra warnings - -Wpedantic # Strict ISO C compliance - -Wshadow # Warn about variable shadowing - -Wformat=2 # Extra format string checks - -Wcast-qual # Warn about cast that removes qualifiers - -Wcast-align # Warn about pointer cast alignment issues - -Wunused # Warn about unused variables/functions - -Wdouble-promotion # Warn about float->double promotion - -Wnull-dereference # Warn about null pointer dereference -) +# Warning flags (compiler-specific) +if(MSVC) + add_compile_options(/W4 /WX) +else() + add_compile_options( + -Wall # Enable most warnings + -Wextra # Extra warnings + -Wpedantic # Strict ISO C compliance + -Wshadow # Warn about variable shadowing + -Wformat=2 # Extra format string checks + -Wcast-qual # Warn about cast that removes qualifiers + -Wcast-align # Warn about pointer cast alignment issues + -Wunused # Warn about unused variables/functions + -Wdouble-promotion # Warn about float to double promotion + -Wnull-dereference # Warn about null pointer dereference + ) +endif() # Include directories include_directories(${PROJECT_SOURCE_DIR}/include) @@ -43,15 +47,28 @@ file(GLOB_RECURSE SOURCES "src/*.c") # Create core library add_library(dnlp_diff ${SOURCES}) -target_link_libraries(dnlp_diff m) -# Config-specific compile options -target_compile_options(dnlp_diff PRIVATE - $<$:-g -O0> - $<$:-O3 -DNDEBUG> - $<$:-O2 -g -DNDEBUG> - $<$:-Os -DNDEBUG> -) +# Link math library (Unix/Linux only) +if(NOT MSVC) + target_link_libraries(dnlp_diff m) +endif() + +# Config-specific compile options (compiler-specific) +if(MSVC) + target_compile_options(dnlp_diff PRIVATE + $<$:/Od /Zi> + $<$:/O2 /DNDEBUG> + $<$:/O2 /Zi /DNDEBUG> + $<$:/Os /DNDEBUG> + ) +else() + target_compile_options(dnlp_diff PRIVATE + $<$:-g -O0> + $<$:-O3 -DNDEBUG> + $<$:-O2 -g -DNDEBUG> + $<$:-Os -DNDEBUG> + ) +endif() # This is needed for clock_gettime on Linux without compiler extensions if(CMAKE_SYSTEM_NAME STREQUAL "Linux") diff --git a/include/utils/Timer.h b/include/utils/Timer.h index c88c294..f967dc3 100644 --- a/include/utils/Timer.h +++ b/include/utils/Timer.h @@ -1,25 +1,61 @@ +/* + * Copyright 2025 Daniel Cederberg + * + * This file is part of the PSLP project (LP Presolver). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #ifndef TIMER_H #define TIMER_H -#include "time.h" - +#if defined(_WIN32) || defined(_WIN64) +#include +typedef struct +{ + LARGE_INTEGER start, end; +} Timer; +static inline void clock_gettime_monotonic(Timer *timer, int is_start) +{ + if (is_start) + { + QueryPerformanceCounter(&timer->start); + } + else + { + QueryPerformanceCounter(&timer->end); + } +} +static inline double get_elapsed_seconds(const Timer *timer) +{ + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return (double) (timer->end.QuadPart - timer->start.QuadPart) / + (double) freq.QuadPart; +} +#define clock_gettime(CLOCK, PTR) \ + clock_gettime_monotonic((Timer *) (PTR), ((PTR) == &((Timer *) (PTR))->start)) +#define GET_ELAPSED_SECONDS(timer) get_elapsed_seconds(&(timer)) +#else +#include typedef struct { struct timespec start, end; } Timer; -// Macro to compute elapsed time in seconds #define GET_ELAPSED_SECONDS(timer) \ - (((timer).end.tv_sec - (timer).start.tv_sec) + \ - ((double) ((timer).end.tv_nsec - (timer).start.tv_nsec) * 1e-9)) - -#define RUN_AND_TIME(func, timer, time_variable, result_var, ...) \ - do \ - { \ - clock_gettime(CLOCK_MONOTONIC, &timer.start); \ - (result_var) = func(__VA_ARGS__); \ - clock_gettime(CLOCK_MONOTONIC, &timer.end); \ - (time_variable) += GET_ELAPSED_SECONDS(timer); \ - } while (0) + ((double) ((timer).end.tv_sec - (timer).start.tv_sec) + \ + (double) ((timer).end.tv_nsec - (timer).start.tv_nsec) / 1e9) +#endif #endif // TIMER_H diff --git a/include/utils/Vec_macros.h b/include/utils/Vec_macros.h index c3c0f14..def45e4 100644 --- a/include/utils/Vec_macros.h +++ b/include/utils/Vec_macros.h @@ -24,17 +24,23 @@ #include #include +// Portable UNUSED macro +#if defined(_MSC_VER) +#define PSLP_UNUSED +#else +#define PSLP_UNUSED __attribute__((unused)) +#endif + // Macro to define a generic vector class #define DEFINE_VECTOR(TYPE, TYPE_NAME) \ typedef struct TYPE_NAME##Vec \ { \ TYPE *data; \ - size_t len; \ - size_t capacity; \ + int len; \ + int capacity; \ } TYPE_NAME##Vec; \ \ - __attribute__((unused)) static TYPE_NAME##Vec *TYPE_NAME##Vec_new( \ - size_t capacity) \ + PSLP_UNUSED static TYPE_NAME##Vec *TYPE_NAME##Vec_new(int capacity) \ { \ assert(capacity > 0); \ TYPE_NAME##Vec *vec = (TYPE_NAME##Vec *) malloc(sizeof(TYPE_NAME##Vec)); \ @@ -68,7 +74,8 @@ { \ vec->capacity *= 2; \ assert(vec->capacity > 0); \ - TYPE *temp = (TYPE *) realloc(vec->data, vec->capacity * sizeof(TYPE)); \ + TYPE *temp = \ + (TYPE *) realloc(vec->data, (size_t) vec->capacity * sizeof(TYPE)); \ if (temp == NULL) \ { \ TYPE_NAME##Vec_free(vec); \ @@ -83,17 +90,18 @@ } \ \ static inline void TYPE_NAME##Vec_append_array(TYPE_NAME##Vec *vec, \ - const TYPE *values, size_t n) \ + const TYPE *values, int n) \ { \ if (vec->len + n > vec->capacity) \ { \ - size_t new_capacity = vec->capacity > 0 ? vec->capacity : 1; \ + int new_capacity = vec->capacity > 0 ? vec->capacity : 1; \ while (vec->len + n > new_capacity) \ { \ new_capacity *= 2; \ } \ \ - TYPE *temp = (TYPE *) realloc(vec->data, new_capacity * sizeof(TYPE)); \ + TYPE *temp = \ + (TYPE *) realloc(vec->data, (size_t) new_capacity * sizeof(TYPE)); \ if (temp == NULL) \ { \ TYPE_NAME##Vec_free(vec); \ @@ -105,13 +113,13 @@ vec->capacity = new_capacity; \ } \ \ - memcpy(vec->data + vec->len, values, n * sizeof(TYPE)); \ + memcpy(vec->data + vec->len, values, (size_t) n * sizeof(TYPE)); \ vec->len += n; \ } \ - __attribute__((unused)) static int TYPE_NAME##Vec_contains( \ - const TYPE_NAME##Vec *vec, TYPE value) \ + PSLP_UNUSED static int TYPE_NAME##Vec_contains(const TYPE_NAME##Vec *vec, \ + TYPE value) \ { \ - for (size_t i = 0; i < vec->len; ++i) \ + for (int i = 0; i < vec->len; ++i) \ { \ if (vec->data[i] == value) \ { \ diff --git a/src/affine/add.c b/src/affine/add.c index 8ebc2ef..2d1542f 100644 --- a/src/affine/add.c +++ b/src/affine/add.c @@ -101,8 +101,5 @@ expr *new_add(expr *left, expr *right) expr_retain(left); expr_retain(right); - // just for debugging, should be removed - strcpy(node->name, "add"); - return node; } diff --git a/src/bivariate/const_scalar_mult.c b/src/bivariate/const_scalar_mult.c index 44ba5f1..4898389 100644 --- a/src/bivariate/const_scalar_mult.c +++ b/src/bivariate/const_scalar_mult.c @@ -110,8 +110,5 @@ expr *new_const_scalar_mult(double a, expr *child) mult_node->a = a; expr_retain(child); - // just for debugging, should be removed - strcpy(node->name, "const_scalar_mult"); - return node; } diff --git a/src/elementwise_univariate/exp.c b/src/elementwise_univariate/exp.c index 165a658..fceac21 100644 --- a/src/elementwise_univariate/exp.c +++ b/src/elementwise_univariate/exp.c @@ -51,7 +51,5 @@ expr *new_exp(expr *child) node->local_jacobian = local_jacobian; node->local_wsum_hess = local_wsum_hess; - // just for debugging, should be removed - strcpy(node->name, "exp"); return node; } diff --git a/src/elementwise_univariate/log.c b/src/elementwise_univariate/log.c index 1315475..cea77d6 100644 --- a/src/elementwise_univariate/log.c +++ b/src/elementwise_univariate/log.c @@ -56,7 +56,5 @@ expr *new_log(expr *child) node->local_jacobian = local_jacobian; node->local_wsum_hess = local_wsum_hess; - // just for debugging, should be removed - strcpy(node->name, "log"); return node; } diff --git a/tests/wsum_hess/test_hstack.h b/tests/wsum_hess/test_hstack.h index c802193..49c22b2 100644 --- a/tests/wsum_hess/test_hstack.h +++ b/tests/wsum_hess/test_hstack.h @@ -98,8 +98,6 @@ const char *test_wsum_hess_hstack() free_expr(hstack_node); return 0; - - return 0; } const char *test_wsum_hess_hstack_matrix() @@ -209,6 +207,4 @@ const char *test_wsum_hess_hstack_matrix() free_expr(hstack_node); return 0; - - return 0; }