Skip to content

Commit 2697433

Browse files
committed
Added Highs_getObjectiveBoundScaling (and Highs_getDualObjectiveValue) to C API
1 parent 0233200 commit 2697433

File tree

5 files changed

+127
-24
lines changed

5 files changed

+127
-24
lines changed

check/TestCAPI.c

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ HighsInt doubleArraysEqual(const double dim, const double* array0,
214214

215215
void assertDoubleValuesEqual(const char* name, const double is,
216216
const double should_be) {
217-
const double dl = fabs(is - should_be);
217+
const double dl = fabs(is - should_be)/(1e0 + fabs(should_be));
218218
if (dl > double_equal_tolerance) {
219219
printf("Value %s = %g differs from %g by %g but should be equal\n", name,
220220
is, should_be, dl);
@@ -2242,6 +2242,66 @@ void testIis() {
22422242
Highs_destroy(highs);
22432243
}
22442244

2245+
void testUserObjectiveBoundScaling() {
2246+
void* highs = Highs_create();
2247+
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
2248+
HighsInt ret;
2249+
double inf = Highs_getInfinity(highs);
2250+
const HighsInt num_col = 2;
2251+
const HighsInt num_row = 2;
2252+
const HighsInt num_nz = 4;
2253+
HighsInt a_format = kHighsMatrixFormatColwise;
2254+
HighsInt sense = kHighsObjSenseMinimize;
2255+
double offset = 1e-4;
2256+
2257+
// Define the column costs, lower bounds and upper bounds
2258+
double col_cost[2] = {-4e6, -7e6};
2259+
double col_lower[2] = {1e-8, 1e-8};
2260+
double col_upper[2] = {1e8, 1e8};
2261+
// Define the row lower bounds and upper bounds
2262+
double row_lower[3] = {-inf, -2e+8};
2263+
double row_upper[3] = {6e+8, inf};
2264+
// Define the constraint matrix column-wise
2265+
HighsInt a_start[2] = {0, 2};
2266+
HighsInt a_index[5] = {0, 1, 0, 1};
2267+
double a_value[5] = {1.0, 1.0, 1.0, -1.0};
2268+
2269+
HighsInt return_status =
2270+
Highs_passLp(highs, num_col, num_row, num_nz,
2271+
a_format, sense, offset,
2272+
col_cost, col_lower, col_upper, row_lower, row_upper,
2273+
a_start, a_index, a_value);
2274+
assert(return_status == kHighsStatusOk);
2275+
2276+
return_status = Highs_run(highs);
2277+
assert(return_status == kHighsStatusOk);
2278+
HighsInt model_status = Highs_getModelStatus(highs);
2279+
assert(model_status == kHighsModelStatusOptimal);
2280+
2281+
double unscaled_objective_value = Highs_getObjectiveValue(highs);
2282+
double dual_objective_value;
2283+
return_status = Highs_getDualObjectiveValue(highs, &dual_objective_value);
2284+
assert(return_status == kHighsStatusOk);
2285+
2286+
HighsInt suggested_objective_scale;
2287+
HighsInt suggested_bound_scale;
2288+
return_status = Highs_getObjectiveBoundScaling(highs,
2289+
&suggested_objective_scale,
2290+
&suggested_bound_scale);
2291+
assert(return_status == kHighsStatusOk);
2292+
2293+
Highs_setIntOptionValue(highs, "user_cost_scale", suggested_objective_scale);
2294+
Highs_setIntOptionValue(highs, "user_bound_scale", suggested_bound_scale);
2295+
2296+
Highs_clearSolver(highs);
2297+
return_status = Highs_run(highs);
2298+
assert(return_status == kHighsStatusOk);
2299+
2300+
double scaled_objective_value = Highs_getObjectiveValue(highs);
2301+
assertDoubleValuesEqual("objective_value", unscaled_objective_value, scaled_objective_value);
2302+
Highs_destroy(highs);
2303+
}
2304+
22452305
int main() {
22462306
minimalApiIllegalLp();
22472307
testCallback();
@@ -2265,7 +2325,8 @@ int main() {
22652325
testQpIndefiniteFailure();
22662326
testDualRayTwice();
22672327
testDeleteRowResolveWithBasis();
2268-
testIis();
2328+
testIis();
2329+
testUserObjectiveBoundScaling();
22692330
return 0;
22702331
}
22712332
// testSetSolution();

check/TestUserScale.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ HighsLp lp1(const double cost, const double col_lower, const double bound) {
161161
// scenario
162162
lp.num_col_ = 2;
163163
lp.num_row_ = 2;
164+
lp.offset_ = 1e-4;
164165
lp.col_cost_ = {-4 * cost, -7 * cost};
165166
lp.col_lower_ = {col_lower, col_lower};
166167
lp.col_upper_ = {10 * bound, 10 * bound};

highs/interfaces/highs_c_api.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,10 @@ double Highs_getObjectiveValue(const void* highs) {
613613
return ((Highs*)highs)->getObjectiveValue();
614614
}
615615

616+
HighsInt Highs_getDualObjectiveValue(const void* highs, double* dual_objective_value) {
617+
return (HighsInt)((Highs*)highs)->getDualObjectiveValue(*dual_objective_value);
618+
}
619+
616620
HighsInt Highs_getBasicVariables(const void* highs, HighsInt* basic_variables) {
617621
return (HighsInt)((Highs*)highs)->getBasicVariables(basic_variables);
618622
}
@@ -1354,6 +1358,14 @@ HighsInt Highs_getIis(void* highs, HighsInt* iis_num_col, HighsInt* iis_num_row,
13541358
return status;
13551359
}
13561360

1361+
HighsInt Highs_getObjectiveBoundScaling(void* highs,
1362+
HighsInt* suggested_objective_scale,
1363+
HighsInt* suggested_bound_scale) {
1364+
return (HighsInt)((Highs*)highs)->
1365+
getObjectiveBoundScaling(*suggested_objective_scale,
1366+
*suggested_bound_scale);
1367+
}
1368+
13571369
HighsInt Highs_getIisLp(const void* highs, const HighsInt a_format,
13581370
HighsInt* num_col, HighsInt* num_row, HighsInt* num_nz,
13591371
HighsInt* sense, double* offset, double* col_cost,

highs/interfaces/highs_c_api.h

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,17 @@ HighsInt Highs_getPrimalRay(const void* highs, HighsInt* has_primal_ray,
10541054
*/
10551055
double Highs_getObjectiveValue(const void* highs);
10561056

1057+
/**
1058+
* Get the dual objective function value.
1059+
*
1060+
* @param highs A pointer to the Highs instance.
1061+
* @param dual_objective_value The dual objective value
1062+
*
1063+
* @returns A `kHighsStatus` constant indicating whether the call succeeded.
1064+
*/
1065+
HighsInt Highs_getDualObjectiveValue(const void* highs,
1066+
double* dual_objective_value);
1067+
10571068
/**
10581069
* Get the indices of the rows and columns that make up the basis matrix ``B``
10591070
* of a basic feasible solution.
@@ -2384,34 +2395,47 @@ HighsInt Highs_feasibilityRelaxation(void* highs,
23842395
* an LP, QP, or the relaxation of a MIP. If no IIS is found, then the
23852396
* number of IIS columns and rows will be zero.
23862397
*
2387-
* @param highs A pointer to the Highs instance.
2388-
* @param const HighsInt iis_num_col Number of columns in the IIS.
2389-
* @param const HighsInt iis_num_row Number of rows in the IIS.
2390-
* @param const HighsInt* col_index An array of length [iis_num_col], to be
2391-
* filled with the indices of original
2392-
* variables in the IIS.
2393-
* @param const HighsInt* row_index An array of length [iis_num_col], to be
2394-
* filled with the indices of original
2395-
* constraints in the IIS.
2396-
* @param const HighsInt* col_bound An array of length [iis_num_col], to be
2397-
* filled with the bound status of variables
2398-
* in the IIS.
2399-
* @param const HighsInt* row_bound An array of length [iis_num_col], to be
2400-
* filled with the bound status of constraints
2401-
* in the IIS.
2402-
* @param const HighsInt* col_status An array of length [num_col], to be
2403-
* filled with the IIS status of all original
2404-
* variables.
2405-
* @param const HighsInt* row_status n array of length [num_col], to be
2406-
* filled with the IIS status of all original
2407-
* constraints.
2398+
* @param highs A pointer to the Highs instance.
2399+
* @param HighsInt iis_num_col Number of columns in the IIS.
2400+
* @param HighsInt iis_num_row Number of rows in the IIS.
2401+
* @param HighsInt* col_index An array of length [iis_num_col], to be
2402+
* filled with the indices of original
2403+
* variables in the IIS.
2404+
* @param HighsInt* row_index An array of length [iis_num_col], to be
2405+
* filled with the indices of original
2406+
* constraints in the IIS.
2407+
* @param HighsInt* col_bound An array of length [iis_num_col], to be
2408+
* filled with the bound status of variables
2409+
* in the IIS.
2410+
* @param HighsInt* row_bound An array of length [iis_num_col], to be
2411+
* filled with the bound status of constraints
2412+
* in the IIS.
2413+
* @param HighsInt* col_status An array of length [num_col], to be filled
2414+
* with the IIS status of all original variables.
2415+
* @param HighsInt* row_status An array of length [num_col], to be filled
2416+
* with the IIS status of all original constraints.
24082417
*
24092418
* @returns A `kHighsStatus` constant indicating whether the call succeeded.
24102419
*/
24112420
HighsInt Highs_getIis(void* highs, HighsInt* iis_num_col, HighsInt* iis_num_row,
24122421
HighsInt* col_index, HighsInt* row_index,
24132422
HighsInt* col_bound, HighsInt* row_bound,
24142423
HighsInt* col_status, HighsInt* row_status);
2424+
/**
2425+
* Identify suggested values of the options user_cost_scale and
2426+
* user_bound_scale to address extremely large or small objective
2427+
* coefficients and bound values
2428+
*
2429+
* @param highs A pointer to the Highs instance.
2430+
* @param HighsInt* suggested_objective_scale The suggested value of user_cost_scale
2431+
* @param HighsInt* suggested_bound_scale The suggested value of user_bound_scale
2432+
*
2433+
* @returns A `kHighsStatus` constant indicating whether the call succeeded.
2434+
*/
2435+
HighsInt Highs_getObjectiveBoundScaling(void* highs,
2436+
HighsInt* suggested_objective_scale,
2437+
HighsInt* suggested_bound_scale);
2438+
24152439
/**
24162440
* Releases all resources held by the global scheduler instance.
24172441
*

highs/lp_data/HighsInterface.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3030,7 +3030,12 @@ HighsStatus Highs::userScaleSolution(HighsUserScaleData& data,
30303030
}
30313031
}
30323032
if (!update_kkt) return return_status;
3033-
info_.objective_function_value *= (bound_scale_value * objective_scale_value);
3033+
// In scaling the objective function value, have to consider the offset
3034+
double objective_function_value =
3035+
info_.objective_function_value - model_.lp_.offset_;
3036+
objective_function_value *= (bound_scale_value * objective_scale_value);
3037+
objective_function_value += model_.lp_.offset_;
3038+
info_.objective_function_value = objective_function_value;
30343039
getKktFailures(options_, model_, solution_, basis_, info_);
30353040
return reportKktFailures(model_.lp_, options_, info_,
30363041
"After removing user scaling")

0 commit comments

Comments
 (0)