Skip to content

Commit 1a2b937

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 ff466b7 commit 1a2b937

21 files changed

+885
-343
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 =
@@ -1870,9 +1870,9 @@ void testMultiObjective() {
18701870
double a_value[6] = {3, 1, 1, 1, 1, 2};
18711871

18721872
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
1873-
HighsInt return_status = Highs_passLp(highs, num_col, num_row, num_nz, a_format, sense,
1874-
offset, col_cost, col_lower, col_upper,
1875-
row_lower, row_upper, a_start, a_index, a_value);
1873+
HighsInt return_status = Highs_passLp(
1874+
highs, num_col, num_row, num_nz, a_format, sense, offset, col_cost,
1875+
col_lower, col_upper, row_lower, row_upper, a_start, a_index, a_value);
18761876
assert(return_status == kHighsStatusOk);
18771877

18781878
return_status = Highs_clearLinearObjectives(highs);
@@ -1884,15 +1884,19 @@ void testMultiObjective() {
18841884
double abs_tolerance = 0;
18851885
double rel_tolerance = 0;
18861886
HighsInt priority = 10;
1887-
return_status = Highs_addLinearObjective(highs, weight, linear_objective_offset, coefficients, abs_tolerance, rel_tolerance, priority);
1887+
return_status = Highs_addLinearObjective(
1888+
highs, weight, linear_objective_offset, coefficients, abs_tolerance,
1889+
rel_tolerance, priority);
18881890
assert(return_status == kHighsStatusOk);
1889-
1891+
18901892
weight = 1e-4;
18911893
linear_objective_offset = 0;
18921894
coefficients[0] = 1;
18931895
coefficients[1] = 0;
18941896
priority = 0;
1895-
return_status = Highs_addLinearObjective(highs, weight, linear_objective_offset, coefficients, abs_tolerance, rel_tolerance, priority);
1897+
return_status = Highs_addLinearObjective(
1898+
highs, weight, linear_objective_offset, coefficients, abs_tolerance,
1899+
rel_tolerance, priority);
18961900
assert(return_status == kHighsStatusOk);
18971901

18981902
return_status = Highs_run(highs);
@@ -1902,8 +1906,7 @@ void testMultiObjective() {
19021906

19031907
Highs_writeSolutionPretty(highs, "");
19041908
double* col_value = (double*)malloc(sizeof(double) * num_col);
1905-
return_status =
1906-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1909+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19071910
assertDoubleValuesEqual("col_value[0]", col_value[0], 2);
19081911
assertDoubleValuesEqual("col_value[1]", col_value[1], 6);
19091912

@@ -1916,43 +1919,46 @@ void testMultiObjective() {
19161919
double abs_tolerance2[2] = {0, -1};
19171920
double rel_tolerance2[2] = {0, -1};
19181921
HighsInt priority2[2] = {10, 0};
1919-
return_status = Highs_passLinearObjectives(highs, 2, weight2, linear_objective_offset2, coefficients2, abs_tolerance2, rel_tolerance2, priority2);
1922+
return_status = Highs_passLinearObjectives(
1923+
highs, 2, weight2, linear_objective_offset2, coefficients2,
1924+
abs_tolerance2, rel_tolerance2, priority2);
19201925
return_status = Highs_run(highs);
19211926
assert(return_status == kHighsStatusOk);
19221927
model_status = Highs_getModelStatus(highs);
19231928
assert(model_status == kHighsModelStatusOptimal);
19241929
Highs_writeSolutionPretty(highs, "");
1925-
return_status =
1926-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1930+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19271931
assertDoubleValuesEqual("col_value[0]", col_value[0], 2);
19281932
assertDoubleValuesEqual("col_value[1]", col_value[1], 6);
19291933

19301934
// weight2[1] = 1e-5;
19311935
coefficients2[0] = 1.0001;
19321936
abs_tolerance2[0] = 1e-5;
19331937
rel_tolerance2[0] = 0.05;
1934-
return_status = Highs_passLinearObjectives(highs, 2, weight2, linear_objective_offset2, coefficients2, abs_tolerance2, rel_tolerance2, priority2);
1938+
return_status = Highs_passLinearObjectives(
1939+
highs, 2, weight2, linear_objective_offset2, coefficients2,
1940+
abs_tolerance2, rel_tolerance2, priority2);
19351941
return_status = Highs_run(highs);
19361942
assert(return_status == kHighsStatusOk);
19371943
model_status = Highs_getModelStatus(highs);
19381944
assert(model_status == kHighsModelStatusOptimal);
19391945
Highs_writeSolutionPretty(highs, "");
1940-
return_status =
1941-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1946+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19421947
assertDoubleValuesEqual("col_value[0]", col_value[0], 4.9);
19431948
assertDoubleValuesEqual("col_value[1]", col_value[1], 3.1);
19441949

19451950
if (dev_run) printf("\n***************\nLexicographic 2\n***************\n");
19461951
abs_tolerance2[0] = -1;
19471952

1948-
return_status = Highs_passLinearObjectives(highs, 2, weight2, linear_objective_offset2, coefficients2, abs_tolerance2, rel_tolerance2, priority2);
1953+
return_status = Highs_passLinearObjectives(
1954+
highs, 2, weight2, linear_objective_offset2, coefficients2,
1955+
abs_tolerance2, rel_tolerance2, priority2);
19491956
return_status = Highs_run(highs);
19501957
assert(return_status == kHighsStatusOk);
19511958
model_status = Highs_getModelStatus(highs);
19521959
assert(model_status == kHighsModelStatusOptimal);
19531960
Highs_writeSolutionPretty(highs, "");
1954-
return_status =
1955-
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
1961+
return_status = Highs_getSolution(highs, col_value, NULL, NULL, NULL);
19561962
assertDoubleValuesEqual("col_value[0]", col_value[0], 1.30069);
19571963
assertDoubleValuesEqual("col_value[1]", col_value[1], 6.34966);
19581964

@@ -1961,82 +1967,89 @@ void testMultiObjective() {
19611967
}
19621968

19631969
void testQpIndefiniteFailure() {
1964-
void* highs = Highs_create();
1965-
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
1966-
HighsInt ret;
1967-
const double inf = Highs_getInfinity(highs);
1968-
ret = Highs_addCol(highs, 0.0, 1.0, inf, 0, NULL, NULL);
1969-
assert(ret == 0);
1970-
ret = Highs_addCol(highs, 0.0, 1.0, 1.0, 0, NULL, NULL);
1971-
HighsInt start[2] = {0, 1};
1972-
HighsInt index[1] = {1};
1973-
double value[1] = {1.0};
1974-
ret = Highs_passHessian(highs, 2, 1, kHighsHessianFormatTriangular, start, index, value);
1975-
assert(ret == 0);
1976-
HighsInt run_status = Highs_run(highs);
1977-
HighsInt model_status = Highs_getModelStatus(highs);
1978-
assert(run_status == kHighsStatusError);
1979-
assert(model_status == kHighsModelStatusSolveError);
1980-
Highs_destroy(highs);
1970+
void* highs = Highs_create();
1971+
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
1972+
HighsInt ret;
1973+
const double inf = Highs_getInfinity(highs);
1974+
ret = Highs_addCol(highs, 0.0, 1.0, inf, 0, NULL, NULL);
1975+
assert(ret == 0);
1976+
ret = Highs_addCol(highs, 0.0, 1.0, 1.0, 0, NULL, NULL);
1977+
HighsInt start[2] = {0, 1};
1978+
HighsInt index[1] = {1};
1979+
double value[1] = {1.0};
1980+
ret = Highs_passHessian(highs, 2, 1, kHighsHessianFormatTriangular, start,
1981+
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);
19811988
}
19821989

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

20422055
/*

0 commit comments

Comments
 (0)