Skip to content

Commit a354c04

Browse files
committed
* rolled back C API breaking changes - except: user_solution memory is now managed by HiGHS instead of the user
* added `setSolution` and `repairSolution` members that can accept partial solutions and find feasible solutions * added kHighsCallbackCallbackMipUserSolution to C API * changed C++ API to support both C API and new `HighsCallbackOutput`/`HighsCallbackInput` classes that manage memory * Updated C/C++/highspy unit tests * Updated highspy callback interface. All callback arrays use numpy with read_only pointers, but contents can be changed safely. * Some formatting changes (to conform with build checks)
1 parent 99432f9 commit a354c04

21 files changed

+884
-342
lines changed

check/TestCAPI.c

Lines changed: 110 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
const HighsInt dev_run = 0;
1313
const double double_equal_tolerance = 1e-5;
1414

15-
void checkGetCallbackDataOutPointer(const HighsCCallbackDataOut* data_out,
15+
void checkGetCallbackDataOutPointer(const HighsCallbackDataOut* data_out,
1616
const char* name, HighsInt valid) {
1717
const void* name_p = Highs_getCallbackDataOutItem(data_out, name);
1818
if (valid) {
@@ -28,7 +28,7 @@ void checkGetCallbackDataOutPointer(const HighsCCallbackDataOut* data_out,
2828
}
2929
}
3030

31-
void checkGetCallbackDataOutHighsInt(const HighsCCallbackDataOut* data_out,
31+
void checkGetCallbackDataOutHighsInt(const HighsCallbackDataOut* data_out,
3232
const char* name, HighsInt value) {
3333
const void* name_p = Highs_getCallbackDataOutItem(data_out, name);
3434
if (!name_p) {
@@ -46,7 +46,7 @@ void checkGetCallbackDataOutHighsInt(const HighsCCallbackDataOut* data_out,
4646
}
4747
}
4848

49-
void checkGetCallbackDataOutInt(const HighsCCallbackDataOut* data_out,
49+
void checkGetCallbackDataOutInt(const HighsCallbackDataOut* data_out,
5050
const char* name, int value) {
5151
const void* name_p = Highs_getCallbackDataOutItem(data_out, name);
5252
if (!name_p) {
@@ -64,7 +64,7 @@ void checkGetCallbackDataOutInt(const HighsCCallbackDataOut* data_out,
6464
}
6565
}
6666

67-
void checkGetCallbackDataOutInt64(const HighsCCallbackDataOut* data_out,
67+
void checkGetCallbackDataOutInt64(const HighsCallbackDataOut* data_out,
6868
const char* name, int64_t value) {
6969
const void* name_p = Highs_getCallbackDataOutItem(data_out, name);
7070
if (!name_p) {
@@ -82,7 +82,7 @@ void checkGetCallbackDataOutInt64(const HighsCCallbackDataOut* data_out,
8282
}
8383
}
8484

85-
void checkGetCallbackDataOutDouble(const HighsCCallbackDataOut* data_out,
85+
void checkGetCallbackDataOutDouble(const HighsCallbackDataOut* data_out,
8686
const char* name, double value) {
8787
const void* name_p = Highs_getCallbackDataOutItem(data_out, name);
8888
if (!name_p) {
@@ -101,8 +101,8 @@ void checkGetCallbackDataOutDouble(const HighsCCallbackDataOut* data_out,
101101
}
102102

103103
static void userCallback(const int callback_type, const char* message,
104-
const HighsCCallbackDataOut* data_out,
105-
HighsCCallbackDataIn* data_in,
104+
const HighsCallbackDataOut* data_out,
105+
HighsCallbackDataIn* data_in,
106106
void* user_callback_data) {
107107
// Extract the double value pointed to from void* user_callback_data
108108
const double local_callback_data =
@@ -1877,9 +1877,9 @@ void testMultiObjective() {
18771877
HighsInt integrality[2] = {kHighsVarTypeInteger, kHighsVarTypeInteger};
18781878

18791879
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
1880-
HighsInt return_status = Highs_passLp(highs, num_col, num_row, num_nz, a_format, sense,
1881-
offset, col_cost, col_lower, col_upper,
1882-
row_lower, row_upper, a_start, a_index, a_value);
1880+
HighsInt return_status = Highs_passLp(
1881+
highs, num_col, num_row, num_nz, a_format, sense, offset, col_cost,
1882+
col_lower, col_upper, row_lower, row_upper, a_start, a_index, a_value);
18831883
assert(return_status == kHighsStatusOk);
18841884

18851885
return_status = Highs_clearLinearObjectives(highs);
@@ -1891,15 +1891,19 @@ void testMultiObjective() {
18911891
double abs_tolerance = 0;
18921892
double rel_tolerance = 0;
18931893
HighsInt priority = 10;
1894-
return_status = Highs_addLinearObjective(highs, weight, linear_objective_offset, coefficients, abs_tolerance, rel_tolerance, priority);
1894+
return_status = Highs_addLinearObjective(
1895+
highs, weight, linear_objective_offset, coefficients, abs_tolerance,
1896+
rel_tolerance, priority);
18951897
assert(return_status == kHighsStatusOk);
1896-
1898+
18971899
weight = 1e-4;
18981900
linear_objective_offset = 0;
18991901
coefficients[0] = 1;
19001902
coefficients[1] = 0;
19011903
priority = 0;
1902-
return_status = Highs_addLinearObjective(highs, weight, linear_objective_offset, coefficients, abs_tolerance, rel_tolerance, priority);
1904+
return_status = Highs_addLinearObjective(
1905+
highs, weight, linear_objective_offset, coefficients, abs_tolerance,
1906+
rel_tolerance, priority);
19031907
assert(return_status == kHighsStatusOk);
19041908

19051909
return_status = Highs_run(highs);
@@ -1909,8 +1913,7 @@ void testMultiObjective() {
19091913

19101914
Highs_writeSolutionPretty(highs, "");
19111915
double* col_value = (double*)malloc(sizeof(double) * num_col);
1912-
return_status =
1913-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1916+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19141917
assertDoubleValuesEqual("col_value[0]", col_value[0], 2);
19151918
assertDoubleValuesEqual("col_value[1]", col_value[1], 6);
19161919

@@ -1923,43 +1926,46 @@ void testMultiObjective() {
19231926
double abs_tolerance2[2] = {0, -1};
19241927
double rel_tolerance2[2] = {0, -1};
19251928
HighsInt priority2[2] = {10, 0};
1926-
return_status = Highs_passLinearObjectives(highs, 2, weight2, linear_objective_offset2, coefficients2, abs_tolerance2, rel_tolerance2, priority2);
1929+
return_status = Highs_passLinearObjectives(
1930+
highs, 2, weight2, linear_objective_offset2, coefficients2,
1931+
abs_tolerance2, rel_tolerance2, priority2);
19271932
return_status = Highs_run(highs);
19281933
assert(return_status == kHighsStatusOk);
19291934
model_status = Highs_getModelStatus(highs);
19301935
assert(model_status == kHighsModelStatusOptimal);
19311936
Highs_writeSolutionPretty(highs, "");
1932-
return_status =
1933-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1937+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19341938
assertDoubleValuesEqual("col_value[0]", col_value[0], 2);
19351939
assertDoubleValuesEqual("col_value[1]", col_value[1], 6);
19361940

19371941
// weight2[1] = 1e-5;
19381942
coefficients2[0] = 1.0001;
19391943
abs_tolerance2[0] = 1e-5;
19401944
rel_tolerance2[0] = 0.05;
1941-
return_status = Highs_passLinearObjectives(highs, 2, weight2, linear_objective_offset2, coefficients2, abs_tolerance2, rel_tolerance2, priority2);
1945+
return_status = Highs_passLinearObjectives(
1946+
highs, 2, weight2, linear_objective_offset2, coefficients2,
1947+
abs_tolerance2, rel_tolerance2, priority2);
19421948
return_status = Highs_run(highs);
19431949
assert(return_status == kHighsStatusOk);
19441950
model_status = Highs_getModelStatus(highs);
19451951
assert(model_status == kHighsModelStatusOptimal);
19461952
Highs_writeSolutionPretty(highs, "");
1947-
return_status =
1948-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1953+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19491954
assertDoubleValuesEqual("col_value[0]", col_value[0], 4.9);
19501955
assertDoubleValuesEqual("col_value[1]", col_value[1], 3.1);
19511956

19521957
if (dev_run) printf("\n***************\nLexicographic 2\n***************\n");
19531958
abs_tolerance2[0] = -1;
19541959

1955-
return_status = Highs_passLinearObjectives(highs, 2, weight2, linear_objective_offset2, coefficients2, abs_tolerance2, rel_tolerance2, priority2);
1960+
return_status = Highs_passLinearObjectives(
1961+
highs, 2, weight2, linear_objective_offset2, coefficients2,
1962+
abs_tolerance2, rel_tolerance2, priority2);
19561963
return_status = Highs_run(highs);
19571964
assert(return_status == kHighsStatusOk);
19581965
model_status = Highs_getModelStatus(highs);
19591966
assert(model_status == kHighsModelStatusOptimal);
19601967
Highs_writeSolutionPretty(highs, "");
1961-
return_status =
1962-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1968+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19631969
assertDoubleValuesEqual("col_value[0]", col_value[0], 1.30069);
19641970
assertDoubleValuesEqual("col_value[1]", col_value[1], 6.34966);
19651971

@@ -1968,82 +1974,89 @@ void testMultiObjective() {
19681974
}
19691975

19701976
void testQpIndefiniteFailure() {
1971-
void* highs = Highs_create();
1972-
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
1973-
HighsInt ret;
1974-
const double inf = Highs_getInfinity(highs);
1975-
ret = Highs_addCol(highs, 0.0, 1.0, inf, 0, NULL, NULL);
1976-
assert(ret == 0);
1977-
ret = Highs_addCol(highs, 0.0, 1.0, 1.0, 0, NULL, NULL);
1978-
HighsInt start[2] = {0, 1};
1979-
HighsInt index[1] = {1};
1980-
double value[1] = {1.0};
1981-
ret = Highs_passHessian(highs, 2, 1, kHighsHessianFormatTriangular, start, index, value);
1982-
assert(ret == 0);
1983-
HighsInt run_status = Highs_run(highs);
1984-
HighsInt model_status = Highs_getModelStatus(highs);
1985-
assert(run_status == kHighsStatusError);
1986-
assert(model_status == kHighsModelStatusSolveError);
1987-
Highs_destroy(highs);
1977+
void* highs = Highs_create();
1978+
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
1979+
HighsInt ret;
1980+
const double inf = Highs_getInfinity(highs);
1981+
ret = Highs_addCol(highs, 0.0, 1.0, inf, 0, NULL, NULL);
1982+
assert(ret == 0);
1983+
ret = Highs_addCol(highs, 0.0, 1.0, 1.0, 0, NULL, NULL);
1984+
HighsInt start[2] = {0, 1};
1985+
HighsInt index[1] = {1};
1986+
double value[1] = {1.0};
1987+
ret = Highs_passHessian(highs, 2, 1, kHighsHessianFormatTriangular, start,
1988+
index, value);
1989+
assert(ret == 0);
1990+
HighsInt run_status = Highs_run(highs);
1991+
HighsInt model_status = Highs_getModelStatus(highs);
1992+
assert(run_status == kHighsStatusError);
1993+
assert(model_status == kHighsModelStatusSolveError);
1994+
Highs_destroy(highs);
19881995
}
19891996

19901997
void testDualRayTwice() {
1991-
void* highs = Highs_create();
1992-
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
1993-
int ret;
1994-
double INF = Highs_getInfinity(highs);
1995-
ret = Highs_changeObjectiveOffset(highs, 0.0);
1996-
assert(ret == 0);
1997-
ret = Highs_setStringOptionValue(highs, "presolve", "off");
1998-
assert(ret == 0);
1999-
ret = Highs_addCol(highs, 0.0, 0.0, 0.0, 0, NULL, NULL);
2000-
assert(ret == 0);
2001-
ret = Highs_addCol(highs, 0.0, 0.0, 0.0, 0, NULL, NULL);
2002-
assert(ret == 0);
2003-
ret = Highs_addCol(highs, -1.0, 0.0, INF, 0, NULL, NULL);
2004-
assert(ret == 0);
2005-
ret = Highs_addCol(highs, -1.0, 0.0, INF, 0, NULL, NULL);
2006-
assert(ret == 0);
2007-
HighsInt index[2] = {2, 3};
2008-
double value[2] = {1.0, -1.0};
2009-
ret = Highs_addRow(highs, 0.0, 0.0, 2, index, value);
2010-
assert(ret == 0);
2011-
index[0] = 2; index[1] = 3;
2012-
value[0] = 1.0; value[1] = 1.0;
2013-
ret = Highs_addRow(highs, 1.0, INF, 2, index, value);
2014-
assert(ret == 0);
2015-
index[0] = 0; index[1] = 2;
2016-
value[0] = -2.0; value[1] = 1.0;
2017-
ret = Highs_addRow(highs, -INF, 0.0, 2, index, value);
2018-
assert(ret == 0);
2019-
index[0] = 1; index[1] = 3;
2020-
value[0] = -3.0; value[1] = 1.0;
2021-
ret = Highs_addRow(highs, -INF, 0.0, 2, index, value);
2022-
assert(ret == 0);
2023-
ret = Highs_run(highs);
2024-
assert(ret == 0);
2025-
HighsInt has_dual_ray = 0;
2026-
double dual_ray_value[4] = {0.0, 0.0, 0.0, 0.0};
2027-
ret = Highs_getDualRay(highs, &has_dual_ray, dual_ray_value);
2028-
assert(ret == 0);
2029-
assertIntValuesEqual("has_dual_ray", has_dual_ray, 1);
2030-
assertDoubleValuesEqual("dual_ray_value[0]", dual_ray_value[0], 0.0);
2031-
assertDoubleValuesEqual("dual_ray_value[1]", dual_ray_value[1], 1.0);
2032-
assertDoubleValuesEqual("dual_ray_value[2]", dual_ray_value[2], -1.0);
2033-
assertDoubleValuesEqual("dual_ray_value[3]", dual_ray_value[3], -1.0);
2034-
ret = Highs_changeColBounds(highs, 1, 1.0, 1.0);
2035-
assert(ret == 0);
2036-
ret = Highs_run(highs);
2037-
assert(ret == 0);
2038-
ret = Highs_getDualRay(highs, &has_dual_ray, dual_ray_value);
2039-
assert(ret == 0);
2040-
assertIntValuesEqual("has_dual_ray", has_dual_ray, 1);
2041-
assertDoubleValuesEqual("dual_ray_value[0]", dual_ray_value[0], 1.0);
2042-
assertDoubleValuesEqual("dual_ray_value[1]", dual_ray_value[1], 1.0);
2043-
assertDoubleValuesEqual("dual_ray_value[2]", dual_ray_value[2], -2.0);
2044-
assertDoubleValuesEqual("dual_ray_value[3]", dual_ray_value[3], 0.0);
2045-
Highs_destroy(highs);
2046-
return;
1998+
void* highs = Highs_create();
1999+
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
2000+
int ret;
2001+
double INF = Highs_getInfinity(highs);
2002+
ret = Highs_changeObjectiveOffset(highs, 0.0);
2003+
assert(ret == 0);
2004+
ret = Highs_setStringOptionValue(highs, "presolve", "off");
2005+
assert(ret == 0);
2006+
ret = Highs_addCol(highs, 0.0, 0.0, 0.0, 0, NULL, NULL);
2007+
assert(ret == 0);
2008+
ret = Highs_addCol(highs, 0.0, 0.0, 0.0, 0, NULL, NULL);
2009+
assert(ret == 0);
2010+
ret = Highs_addCol(highs, -1.0, 0.0, INF, 0, NULL, NULL);
2011+
assert(ret == 0);
2012+
ret = Highs_addCol(highs, -1.0, 0.0, INF, 0, NULL, NULL);
2013+
assert(ret == 0);
2014+
HighsInt index[2] = {2, 3};
2015+
double value[2] = {1.0, -1.0};
2016+
ret = Highs_addRow(highs, 0.0, 0.0, 2, index, value);
2017+
assert(ret == 0);
2018+
index[0] = 2;
2019+
index[1] = 3;
2020+
value[0] = 1.0;
2021+
value[1] = 1.0;
2022+
ret = Highs_addRow(highs, 1.0, INF, 2, index, value);
2023+
assert(ret == 0);
2024+
index[0] = 0;
2025+
index[1] = 2;
2026+
value[0] = -2.0;
2027+
value[1] = 1.0;
2028+
ret = Highs_addRow(highs, -INF, 0.0, 2, index, value);
2029+
assert(ret == 0);
2030+
index[0] = 1;
2031+
index[1] = 3;
2032+
value[0] = -3.0;
2033+
value[1] = 1.0;
2034+
ret = Highs_addRow(highs, -INF, 0.0, 2, index, value);
2035+
assert(ret == 0);
2036+
ret = Highs_run(highs);
2037+
assert(ret == 0);
2038+
HighsInt has_dual_ray = 0;
2039+
double dual_ray_value[4] = {0.0, 0.0, 0.0, 0.0};
2040+
ret = Highs_getDualRay(highs, &has_dual_ray, dual_ray_value);
2041+
assert(ret == 0);
2042+
assertIntValuesEqual("has_dual_ray", has_dual_ray, 1);
2043+
assertDoubleValuesEqual("dual_ray_value[0]", dual_ray_value[0], 0.0);
2044+
assertDoubleValuesEqual("dual_ray_value[1]", dual_ray_value[1], 1.0);
2045+
assertDoubleValuesEqual("dual_ray_value[2]", dual_ray_value[2], -1.0);
2046+
assertDoubleValuesEqual("dual_ray_value[3]", dual_ray_value[3], -1.0);
2047+
ret = Highs_changeColBounds(highs, 1, 1.0, 1.0);
2048+
assert(ret == 0);
2049+
ret = Highs_run(highs);
2050+
assert(ret == 0);
2051+
ret = Highs_getDualRay(highs, &has_dual_ray, dual_ray_value);
2052+
assert(ret == 0);
2053+
assertIntValuesEqual("has_dual_ray", has_dual_ray, 1);
2054+
assertDoubleValuesEqual("dual_ray_value[0]", dual_ray_value[0], 1.0);
2055+
assertDoubleValuesEqual("dual_ray_value[1]", dual_ray_value[1], 1.0);
2056+
assertDoubleValuesEqual("dual_ray_value[2]", dual_ray_value[2], -2.0);
2057+
assertDoubleValuesEqual("dual_ray_value[3]", dual_ray_value[3], 0.0);
2058+
Highs_destroy(highs);
2059+
return;
20472060
}
20482061

20492062
/*

0 commit comments

Comments
 (0)