diff --git a/include/PSLP/PSLP_API.h b/include/PSLP/PSLP_API.h index b9c348f3..4dcd65d6 100644 --- a/include/PSLP/PSLP_API.h +++ b/include/PSLP/PSLP_API.h @@ -16,11 +16,9 @@ * limitations under the License. */ -/* Public header containing the outward facing API. It includes all the - input/output data structs and the API functions. Make sure this file is - somewhere appropriate and then use `#include ` to access the - public API. */ +/* Public header containing the outward facing API. Together with the other + files in the folder "PSLP", it includes the input/output data structs + and the API functions. */ #ifndef PRESOLVER_H #define PRESOLVER_H @@ -29,8 +27,8 @@ extern "C" { #endif -#include "PresolveStatus.h" -#include "Sol.h" +#include "PSLP_sol.h" +#include "PSLP_status.h" #include /* forward declaration */ @@ -69,13 +67,21 @@ extern "C" double *rhs; double *c; - // variable bounds bounds[k].lb <= x_k <= bounds[k].ub - // Bound *bounds; + // variable bounds lbs <= x <= ubs double *lbs; double *ubs; } PresolvedProblem; - /* struct corresponding to the presolver*/ + /* struct corresponding to the presolver: + - 'stats' contains statistics about the presolving process + - 'stgs' contains the settings used for presolving + - 'prob' contains the internal problem representation used during + presolving + - 'reduced_prob' contains the presolved problem after running + 'run_presolver' + - 'sol' contains the solution to the original problem after running + 'postsolve' + */ typedef struct { struct PresolveStats *stats; @@ -85,8 +91,7 @@ extern "C" Solution *sol; } Presolver; - /* The user is responsible for freeing the settings struct using standard free. - */ + /* The user is responsible for freeing the settings using 'free_settings'. */ Settings *default_settings(); void free_settings(Settings *stgs); void set_settings_true(Settings *stgs); @@ -94,7 +99,7 @@ extern "C" /* Initialize presolver, allocate memory, and build internal data structures. The presolver maintains internal deep copies of Ax, Ai, Ap, lhs, rhs, lbs, - ubs, and c. The user is responsible for freeing this memory using + ubs, and c. The user is responsible for freeing the presolver using 'free_presolver'. If the allocation fails, the function returns NULL. */ Presolver *new_presolver(const double *Ax, const int *Ai, const int *Ap, int m, int n, int nnz, const double *lhs, const double *rhs, @@ -104,13 +109,14 @@ extern "C" /* Free the memory allocated for the presolver. */ void free_presolver(Presolver *presolver); - /* Runs the presolver. At completion, the 'problem' field of the presolver - contains the presolved problem. */ + /* Runs the presolver. At completion, the 'reduced_prob' field of the + presolver contains the presolved problem. */ PresolveStatus run_presolver(Presolver *presolver); /* Postsolve the problem given the primal-dual solution (x, y, z) of the reduced problem. The optimal value of the reduced problem is 'obj'. - The function populates presolver->sol. */ + The function populates presolver->sol, so if you're looking for the + solution to the original problem, you should look there. */ void postsolve(Presolver *presolver, const double *x, const double *y, const double *z, double obj); diff --git a/include/PSLP/PSLP_infs.h b/include/PSLP/PSLP_infs.h deleted file mode 100644 index 6fe4a7d2..00000000 --- a/include/PSLP/PSLP_infs.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PSLP_PSLP_INFS_H -#define PSLP_PSLP_INFS_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define PSLP_INF 1e20 -#define IS_POS_INF(x) ((x) >= PSLP_INF) -#define IS_NEG_INF(x) ((x) <= -PSLP_INF) -#define IS_ABS_INF(x) (IS_POS_INF(x) || IS_NEG_INF(x)) - -#ifdef __cplusplus -} -#endif - -#endif /* PSLP_PSLP_INFS_H */ diff --git a/include/PSLP/Sol.h b/include/PSLP/PSLP_sol.h similarity index 100% rename from include/PSLP/Sol.h rename to include/PSLP/PSLP_sol.h diff --git a/include/PSLP/PresolveStatus.h b/include/PSLP/PSLP_status.h similarity index 100% rename from include/PSLP/PresolveStatus.h rename to include/PSLP/PSLP_status.h diff --git a/include/core/CoreTransformations.h b/include/core/CoreTransformations.h index 40996369..3904c4c8 100644 --- a/include/core/CoreTransformations.h +++ b/include/core/CoreTransformations.h @@ -19,8 +19,8 @@ #ifndef CORE_TRANSFORMATIONS_H #define CORE_TRANSFORMATIONS_H +#include "PSLP_status.h" #include "Postsolver.h" -#include "PresolveStatus.h" #include "Tags.h" #include "debug_macros.h" #include "glbopts.h" diff --git a/include/core/Postsolver.h b/include/core/Postsolver.h index 785b5fc2..e045bc09 100644 --- a/include/core/Postsolver.h +++ b/include/core/Postsolver.h @@ -22,7 +22,7 @@ #include #include -#include "Sol.h" +#include "PSLP_sol.h" #include "Tags.h" struct u16Vec; diff --git a/include/core/glbopts.h b/include/core/glbopts.h index 30bd5da6..1ce87f1f 100644 --- a/include/core/glbopts.h +++ b/include/core/glbopts.h @@ -45,6 +45,6 @@ #define SIZE_INACTIVE_ROW -1 #define SIZE_INACTIVE_COL -1 #define MAX_RATIO_PIVOT 1e3 -#define CVX_PRESOLVE_VERSION "0.0.1" +#define PSLP_presolve_VERSION "0.0.1" #endif diff --git a/include/data_structures/iVec.h b/include/data_structures/iVec.h index ffe780bf..1760090d 100644 --- a/include/data_structures/iVec.h +++ b/include/data_structures/iVec.h @@ -26,6 +26,7 @@ // This macro defines a vector of integers. DEFINE_VECTOR(int, i) +/* __attribute__((unused)) static void print_ivec(iVec *vec) { for (size_t i = 0; i < vec->len; ++i) @@ -34,5 +35,5 @@ __attribute__((unused)) static void print_ivec(iVec *vec) } printf("\n"); } - +*/ #endif // IVEC_H diff --git a/include/data_structures/u16Vec.h b/include/data_structures/u16Vec.h index b85c150e..bc5b1461 100644 --- a/include/data_structures/u16Vec.h +++ b/include/data_structures/u16Vec.h @@ -21,6 +21,7 @@ // This macro defines a vector of uint16_t. DEFINE_VECTOR(uint16_t, u16) +/* __attribute__((unused)) static void print_u16Vec(const u16Vec *vec) { for (int i = 0; i < vec->len; ++i) @@ -29,3 +30,4 @@ __attribute__((unused)) static void print_u16Vec(const u16Vec *vec) } printf("\n"); } +*/ diff --git a/include/explorers/DTonsEq.h b/include/explorers/DTonsEq.h index b6088f7f..77ddf1af 100644 --- a/include/explorers/DTonsEq.h +++ b/include/explorers/DTonsEq.h @@ -19,7 +19,7 @@ #ifndef DTONS_EQ_H #define DTONS_EQ_H -#include "PresolveStatus.h" +#include "PSLP_status.h" struct Matrix; struct Problem; struct PostsolveInfo; diff --git a/include/explorers/Parallel_cols.h b/include/explorers/Parallel_cols.h index ded88080..a12a5cc9 100644 --- a/include/explorers/Parallel_cols.h +++ b/include/explorers/Parallel_cols.h @@ -19,7 +19,7 @@ #ifndef PARALLEL_COLS_H #define PARALLEL_COLS_H -#include "PresolveStatus.h" +#include "PSLP_status.h" // forward declaration struct Problem; diff --git a/include/explorers/Parallel_rows.h b/include/explorers/Parallel_rows.h index 4dac7bad..3350c5d7 100644 --- a/include/explorers/Parallel_rows.h +++ b/include/explorers/Parallel_rows.h @@ -19,7 +19,7 @@ #ifndef PARALLEL_ROWS_H #define PARALLEL_ROWS_H -#include "PresolveStatus.h" +#include "PSLP_status.h" #include "Tags.h" // forward declarations diff --git a/include/explorers/Primal_propagation.h b/include/explorers/Primal_propagation.h index 9c82f2af..a11e49ed 100644 --- a/include/explorers/Primal_propagation.h +++ b/include/explorers/Primal_propagation.h @@ -21,7 +21,7 @@ #include -#include "PresolveStatus.h" +#include "PSLP_status.h" #include "Tags.h" struct Constraints; diff --git a/include/explorers/SimpleReductions.h b/include/explorers/SimpleReductions.h index 87d8f327..927ab09c 100644 --- a/include/explorers/SimpleReductions.h +++ b/include/explorers/SimpleReductions.h @@ -19,7 +19,7 @@ #ifndef SIMPLEREDUCTIONS_H #define SIMPLEREDUCTIONS_H -#include "PresolveStatus.h" +#include "PSLP_status.h" #include "Tags.h" // forward declarations diff --git a/include/explorers/Simple_dual_fix.h b/include/explorers/Simple_dual_fix.h index 98805745..6493a367 100644 --- a/include/explorers/Simple_dual_fix.h +++ b/include/explorers/Simple_dual_fix.h @@ -19,7 +19,7 @@ #ifndef SIMPLE_DUAL_FIX_H #define SIMPLE_DUAL_FIX_H -#include "PresolveStatus.h" +#include "PSLP_status.h" // forward declaration struct Problem; diff --git a/include/explorers/StonCols.h b/include/explorers/StonCols.h index 37b8a7fa..c57de077 100644 --- a/include/explorers/StonCols.h +++ b/include/explorers/StonCols.h @@ -19,7 +19,7 @@ #ifndef STONCOLS_HPP #define STONCOLS_HPP -#include "PresolveStatus.h" +#include "PSLP_status.h" // forward declaration struct Problem; diff --git a/src/core/Presolver.c b/src/core/Presolver.c index e38ff971..5fc4cd21 100644 --- a/src/core/Presolver.c +++ b/src/core/Presolver.c @@ -81,7 +81,7 @@ Settings *default_settings() stgs->parallel_cols = true; stgs->primal_propagation = true; stgs->dual_fix = true; - stgs->clean_small_coeff = true; + stgs->clean_small_coeff = false; stgs->finite_bound_tightening = true; stgs->relax_bounds = true; stgs->max_shift = 10; @@ -336,6 +336,7 @@ static inline bool update_termination(int nnz_after_cycle, int nnz_before_cycle, if (GET_ELAPSED_SECONDS(outer_timer) >= max_time) { + printf("Maximum time limit of %.2f seconds reached.\n", max_time); return true; } @@ -370,6 +371,7 @@ static inline Complexity update_complexity(Complexity curr_complexity, { assert(false); } + return FAST; // to suppress compiler warning } @@ -409,7 +411,6 @@ static inline PresolveStatus run_trivial_explorers(Problem *prob, assert(prob->constraints->state->ston_rows->len == 0); assert(prob->constraints->state->empty_rows->len == 0); assert(prob->constraints->state->empty_cols->len == 0); - return UNCHANGED; } @@ -437,12 +438,10 @@ static inline PresolveStatus run_fast_explorers(Problem *prob, const Settings *s if (stgs->dton_eq) { status |= remove_dton_eq_rows(prob, stgs->max_shift); - // after removing doubleton equality rows, there can be new empty rows, // new singleton rows, and new empty columns status |= run_trivial_explorers(prob, stgs); } - return status; } @@ -557,7 +556,7 @@ static inline void print_start_message(const PresolveStats *stats) { printf("\n\t PSLP v%s - LP presolver \n\t(c) Daniel " "Cederberg, Stanford University, 2025\n", - CVX_PRESOLVE_VERSION); + PSLP_presolve_VERSION); printf("Original problem: %d rows, %d columns, %d nnz\n", stats->n_rows_original, stats->n_cols_original, stats->nnz_original); } diff --git a/src/explorers/DtonsEq.c b/src/explorers/DtonsEq.c index e218cc4a..7b9a992f 100644 --- a/src/explorers/DtonsEq.c +++ b/src/explorers/DtonsEq.c @@ -236,9 +236,9 @@ static inline void modify_bounds(Constraints *constraints, int i, double aij, #ifndef TESTING static inline #endif - Old_and_new_coeff - update_row_A_dton(Matrix *A, int i, int q, int j, int k, double aij, double aik, - int *row_size, PostsolveInfo *postsolve_info) + Old_and_new_coeff update_row_A_dton(Matrix *A, int i, int q, int j, int k, + double aij, double aik, int *row_size, + PostsolveInfo *postsolve_info) { int ii, start, end, insertion; double old_val = 0.0; diff --git a/src/explorers/StonCols.c b/src/explorers/StonCols.c index 01943d47..c58630f3 100644 --- a/src/explorers/StonCols.c +++ b/src/explorers/StonCols.c @@ -617,8 +617,6 @@ PresolveStatus remove_ston_cols__(Problem *prob) { printf("debug warning: large coefficient when eliminating col ston\n"); } - // This happens on map10 (miplib) - // assert(!IS_HUGE(Aik) && !IS_HUGE(1 / Aik) && "Be aware of this!"); #endif // If two column singletons appear in the same constraint, the diff --git a/tests/test_ston.h b/tests/test_ston.h index 90398c96..9fa8ec62 100644 --- a/tests/test_ston.h +++ b/tests/test_ston.h @@ -1066,6 +1066,96 @@ static char *test_13_ston() return 0; } +static char *test_14_ston() +{ + double Ax[] = {1, 1, 2, 1, 1}; + int Ai[] = {0, 1, 2, 1, 2}; + int Ap[] = {0, 3, 5}; + int nnz = 5; + int n_rows = 2; + int n_cols = 3; + + double lhs[] = {1, -INF}; + double rhs[] = {6, 5}; + double lbs[] = {0, 0, 0}; + double ubs[] = {INF, INF, INF}; + double c[] = {-1, 1, 1}; + + Settings *stgs = default_settings(); + Presolver *presolver = new_presolver(Ax, Ai, Ap, n_rows, n_cols, nnz, lhs, rhs, + lbs, ubs, c, stgs, true); + + Problem *prob = presolver->prob; + Constraints *constraints = prob->constraints; + Matrix *A = constraints->A; + remove_ston_cols(prob); + problem_clean(prob, true); + + mu_assert("error", + CHECK_ROW_SIZES(constraints->A, constraints->state->row_sizes)); + mu_assert("error", + CHECK_COL_SIZES(constraints->AT, constraints->state->col_sizes)); + + // check that new A is correct + double Ax_correct[] = {1, 2, 1, 1}; + int Ai_correct[] = {0, 1, 0, 1}; + int Ap_correct[] = {0, 2, 4}; + mu_assert("error Ax", ARRAYS_EQUAL_DOUBLE(Ax_correct, A->x, 4)); + mu_assert("error Ai", ARRAYS_EQUAL_INT(Ai_correct, A->i, 4)); + CHECK_ROW_STARTS(A, Ap_correct); + + PS_FREE(stgs); + DEBUG(run_debugger(constraints, false)); + free_presolver(presolver); + + return 0; +} + +static char *test_15_ston() +{ + double Ax[] = {-1, 1, 2, 1, 1}; + int Ai[] = {0, 1, 2, 1, 2}; + int Ap[] = {0, 3, 5}; + int nnz = 5; + int n_rows = 2; + int n_cols = 3; + + double lhs[] = {1, -INF}; + double rhs[] = {6, 5}; + double lbs[] = {0, 0, 0}; + double ubs[] = {INF, INF, INF}; + double c[] = {-1, 1, 1}; + + Settings *stgs = default_settings(); + Presolver *presolver = new_presolver(Ax, Ai, Ap, n_rows, n_cols, nnz, lhs, rhs, + lbs, ubs, c, stgs, true); + + Problem *prob = presolver->prob; + Constraints *constraints = prob->constraints; + Matrix *A = constraints->A; + remove_ston_cols(prob); + problem_clean(prob, true); + + mu_assert("error", + CHECK_ROW_SIZES(constraints->A, constraints->state->row_sizes)); + mu_assert("error", + CHECK_COL_SIZES(constraints->AT, constraints->state->col_sizes)); + + // check that new A is correct + double Ax_correct[] = {1, 2, 1, 1}; + int Ai_correct[] = {0, 1, 0, 1}; + int Ap_correct[] = {0, 2, 4}; + mu_assert("error Ax", ARRAYS_EQUAL_DOUBLE(Ax_correct, A->x, 4)); + mu_assert("error Ai", ARRAYS_EQUAL_INT(Ai_correct, A->i, 4)); + CHECK_ROW_STARTS(A, Ap_correct); + + PS_FREE(stgs); + DEBUG(run_debugger(constraints, false)); + free_presolver(presolver); + + return 0; +} + static const char *all_tests_ston() { mu_run_test(test_01_ston, counter_ston); // (✓) @@ -1080,6 +1170,8 @@ static const char *all_tests_ston() mu_run_test(test_10_ston, counter_ston); // (✓) mu_run_test(test_12_ston, counter_ston); // (✓) mu_run_test(test_13_ston, counter_ston); // (✓) + mu_run_test(test_14_ston, counter_ston); // (✓) + mu_run_test(test_15_ston, counter_ston); // (✓) return 0; }