#include #include #include #include #include "interfaces/highs_c_api.h" // gcc call_highs_from_c.c -o highstest -I install_folder/include/ -L // install_folder/lib/ -lhighs void minimal_api() { // This illustrates the use of Highs_lpCall, the simple C interface to // HiGHS. It's designed to solve the general LP problem // // Min c^Tx + d subject to L <= Ax <= U; l <= x <= u // // where A is a matrix with m rows and n columns // // The scalar n is num_col // The scalar m is num_row // // The vector c is col_cost // The scalar d is offset // The vector l is col_lower // The vector u is col_upper // The vector L is row_lower // The vector U is row_upper // // The matrix A is represented in packed vector form, either // row-wise or column-wise: only its nonzeros are stored // // * The number of nonzeros in A is num_nz // // * The indices of the nonnzeros in the vectors of A are stored in a_index // // * The values of the nonnzeros in the vectors of A are stored in a_value // // * The position in a_index/a_value of the index/value of the first // nonzero in each vector is stored in a_start // // Note that a_start[0] must be zero // // After a successful call to Highs_lpCall, the primal and dual // solution, and the simplex basis are returned as follows // // The vector x is col_value // The vector Ax is row_value // The vector of dual values for the variables x is col_dual // The vector of dual values for the variables Ax is row_dual // The basic/nonbasic status of the variables x is col_basis_status // The basic/nonbasic status of the variables Ax is row_basis_status // // The status of the solution obtained is model_status // // The use of Highs_lpCall is illustrated for the LP // // Min f = x_0 + x_1 + 3 // s.t. x_1 <= 7 // 5 <= x_0 + 2x_1 <= 15 // 6 <= 3x_0 + 2x_1 // 0 <= x_0 <= 4; 1 <= x_1 // // Although the first constraint could be expressed as an upper // bound on x_1, it serves to illustrate a non-trivial packed // column-wise matrix. // // The HighsInt type is either int or long, depending on the HiGHS build const HighsInt num_col = 2; const HighsInt num_row = 3; const HighsInt num_nz = 5; // Define the optimization sense and objective offset HighsInt sense = kHighsObjSenseMinimize; const double offset = 3; // Define the column costs, lower bounds and upper bounds const double col_cost[2] = {1.0, 1.0}; const double col_lower[2] = {0.0, 1.0}; const double col_upper[2] = {4.0, 1.0e30}; // Define the row lower bounds and upper bounds const double row_lower[3] = {-1.0e30, 5.0, 6.0}; const double row_upper[3] = {7.0, 15.0, 1.0e30}; // Define the constraint matrix column-wise const HighsInt a_format = kHighsMatrixFormatColwise; const HighsInt a_start[2] = {0, 2}; const HighsInt a_index[5] = {1, 2, 0, 1, 2}; const double a_value[5] = {1.0, 3.0, 1.0, 2.0, 2.0}; double objective_value; double* col_value = (double*)malloc(sizeof(double) * num_col); double* col_dual = (double*)malloc(sizeof(double) * num_col); double* row_value = (double*)malloc(sizeof(double) * num_row); double* row_dual = (double*)malloc(sizeof(double) * num_row); HighsInt* col_basis_status = (HighsInt*)malloc(sizeof(HighsInt) * num_col); HighsInt* row_basis_status = (HighsInt*)malloc(sizeof(HighsInt) * num_row); HighsInt model_status; HighsInt run_status; run_status = Highs_lpCall(num_col, num_row, num_nz, a_format, sense, offset, col_cost, col_lower, col_upper, row_lower, row_upper, a_start, a_index, a_value, col_value, col_dual, row_value, row_dual, col_basis_status, row_basis_status, &model_status); // The run must be successful, and the model status optimal assert(run_status == kHighsStatusOk); assert(model_status == kHighsModelStatusOptimal); printf("\nRun status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); objective_value = offset; // Report the column primal and dual values, and basis status for (HighsInt i = 0; i < num_col; i++) { printf("Col%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "\n", i, col_value[i], col_dual[i], col_basis_status[i]); objective_value += col_value[i] * col_cost[i]; } // Report the row primal and dual values, and basis status for (HighsInt i = 0; i < num_row; i++) { printf("Row%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "\n", i, row_value[i], row_dual[i], row_basis_status[i]); } printf("Optimal objective value = %g\n", objective_value); // Switch the sense to maximization and solve the LP again sense = kHighsObjSenseMaximize; run_status = Highs_lpCall(num_col, num_row, num_nz, a_format, sense, offset, col_cost, col_lower, col_upper, row_lower, row_upper, a_start, a_index, a_value, col_value, col_dual, row_value, row_dual, col_basis_status, row_basis_status, &model_status); // The run must be successful, and the model status optimal assert(run_status == kHighsStatusOk); assert(model_status == kHighsModelStatusOptimal); printf("\nRun status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); // Compute the objective value objective_value = offset; for (HighsInt i = 0; i < num_col; i++) objective_value += col_value[i] * col_cost[i]; // Report the column primal and dual values, and basis status for (HighsInt i = 0; i < num_col; i++) { printf("Col%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "\n", i, col_value[i], col_dual[i], col_basis_status[i]); } // Report the row primal and dual values, and basis status for (HighsInt i = 0; i < num_row; i++) { printf("Row%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "\n", i, row_value[i], row_dual[i], row_basis_status[i]); } printf("Optimal objective value = %g\n", objective_value); // // Indicate that the optimal solution for both columns must be // integer valued and solve the model as a MIP HighsInt integrality[2] = {1, 1}; run_status = Highs_mipCall(num_col, num_row, num_nz, a_format, sense, offset, col_cost, col_lower, col_upper, row_lower, row_upper, a_start, a_index, a_value, integrality, col_value, row_value, &model_status); // The run must be successful, and the model status optimal assert(run_status == kHighsStatusOk); assert(model_status == kHighsModelStatusOptimal); printf("\nRun status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); // Compute the objective value objective_value = offset; for (HighsInt i = 0; i < num_col; i++) objective_value += col_value[i] * col_cost[i]; // Report the column primal values for (HighsInt i = 0; i < num_col; i++) { printf("Col%" HIGHSINT_FORMAT " = %lf\n", i, col_value[i]); } // Report the row primal values for (HighsInt i = 0; i < num_row; i++) { printf("Row%" HIGHSINT_FORMAT " = %lf\n", i, row_value[i]); } printf("Optimal objective value = %g\n", objective_value); free(col_value); free(col_dual); free(row_value); free(row_dual); free(col_basis_status); free(row_basis_status); } void minimal_api_qp() { // Illustrate the solution of a QP // // minimize -x_2 + (1/2)(2x_1^2 - 2x_1x_3 + 0.2x_2^2 + 2x_3^2) // // subject to x_1 + x_2 + x_3 >= 1; x>=0 const HighsInt num_col = 3; const HighsInt num_row = 1; const HighsInt num_nz = 3; // Define the optimization sense and objective offset HighsInt sense = kHighsObjSenseMinimize; const double offset = 0; // Define the column costs, lower bounds and upper bounds const double col_cost[3] = {0.0, -1.0, 0.0}; const double col_lower[3] = {0.0, 0.0, 0.0}; const double col_upper[3] = {1.0e30, 1.0e30, 1.0e30}; // Define the row lower bounds and upper bounds const double row_lower[1] = {1}; const double row_upper[1] = {1.0e30}; // Define the constraint matrix row-wise const HighsInt a_format = kHighsMatrixFormatRowwise; const HighsInt a_start[2] = {0, 3}; const HighsInt a_index[3] = {0, 1, 2}; const double a_value[3] = {1.0, 1.0, 1.0}; const HighsInt q_format = kHighsHessianFormatTriangular; const HighsInt q_num_nz = 4; const HighsInt q_start[3] = {0, 2, 3}; const HighsInt q_index[4] = {0, 2, 1, 2}; const double q_value[4] = {2.0, -1.0, 0.2, 2.0}; double objective_value; double* col_value = (double*)malloc(sizeof(double) * num_col); double* col_dual = (double*)malloc(sizeof(double) * num_col); double* row_value = (double*)malloc(sizeof(double) * num_row); double* row_dual = (double*)malloc(sizeof(double) * num_row); HighsInt* col_basis_status = (HighsInt*)malloc(sizeof(HighsInt) * num_col); HighsInt* row_basis_status = (HighsInt*)malloc(sizeof(HighsInt) * num_row); HighsInt model_status; HighsInt run_status; run_status = Highs_qpCall( num_col, num_row, num_nz, q_num_nz, a_format, q_format, sense, offset, col_cost, col_lower, col_upper, row_lower, row_upper, a_start, a_index, a_value, q_start, q_index, q_value, col_value, col_dual, row_value, row_dual, col_basis_status, row_basis_status, &model_status); // The run must be successful, and the model status optimal assert(run_status == kHighsStatusOk); assert(model_status == kHighsModelStatusOptimal); printf("\nRun status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); // Compute the objective value objective_value = offset; for (HighsInt i = 0; i < num_col; i++) objective_value += col_value[i] * col_cost[i]; for (HighsInt i = 0; i < num_col; i++) { HighsInt from_el = q_start[i]; HighsInt to_el; if (i + 1 < num_col) { to_el = q_start[i + 1]; } else { to_el = q_num_nz; } for (HighsInt el = from_el; el < to_el; el++) { HighsInt j = q_index[el]; objective_value += 0.5 * col_value[i] * col_value[j] * q_value[el]; } } // Report the column primal and dual values, and basis status for (HighsInt i = 0; i < num_col; i++) { // printf("Col%d = %lf; dual = %lf; status = %d\n", i, col_value[i], // col_dual[i], col_basis_status[i]); printf("Col%" HIGHSINT_FORMAT " = %lf; dual = %lf\n", i, col_value[i], col_dual[i]); } // Report the row primal and dual values, and basis status for (HighsInt i = 0; i < num_row; i++) { // printf("Row%d = %lf; dual = %lf; status = %d\n", i, row_value[i], // row_dual[i], row_basis_status[i]); printf("Row%" HIGHSINT_FORMAT " = %lf; dual = %lf\n", i, row_value[i], row_dual[i]); } printf("Optimal objective value = %g\n", objective_value); free(col_value); free(col_dual); free(row_value); free(row_dual); free(col_basis_status); free(row_basis_status); } void full_api() { printf("\nHiGHS version %s\n", Highs_version()); printf(" Major version %" HIGHSINT_FORMAT "\n", Highs_versionMajor()); printf(" Minor version %" HIGHSINT_FORMAT "\n", Highs_versionMinor()); printf(" Patch version %" HIGHSINT_FORMAT "\n", Highs_versionPatch()); printf(" Githash %s\n", Highs_githash()); // Compilation date is deprecated. // printf(" compilation date %s\n", Highs_compilationDate()); // This example does exactly the same as the minimal example above, // but illustrates the full C API. It first forms and solves the LP // // Min f = x_0 + x_1 + 3 // s.t. x_1 <= 7 // 5 <= x_0 + 2x_1 <= 15 // 6 <= 3x_0 + 2x_1 // 0 <= x_0 <= 4; 1 <= x_1 // // It then solves it as a maximization, then as a MIP. // const HighsInt num_col = 2; const HighsInt num_row = 3; const HighsInt num_nz = 5; // Define the optimization sense and objective offset HighsInt sense = kHighsObjSenseMinimize; const double offset = 3; // Define the column costs, lower bounds and upper bounds const double col_cost[2] = {1.0, 1.0}; const double col_lower[2] = {0.0, 1.0}; const double col_upper[2] = {4.0, 1.0e30}; // Define the row lower bounds and upper bounds const double row_lower[3] = {-1.0e30, 5.0, 6.0}; const double row_upper[3] = {7.0, 15.0, 1.0e30}; // Define the constraint matrix column-wise const HighsInt a_format = kHighsMatrixFormatColwise; const HighsInt a_start[2] = {0, 2}; const HighsInt a_index[5] = {1, 2, 0, 1, 2}; const double a_value[5] = {1.0, 3.0, 1.0, 2.0, 2.0}; HighsInt run_status; HighsInt model_status; double objective_function_value; HighsInt simplex_iteration_count; int64_t mip_node_count; HighsInt primal_solution_status; HighsInt dual_solution_status; HighsInt basis_validity; // Create a Highs instance void* highs = Highs_create(); // Pass the LP to HiGHS run_status = Highs_passLp(highs, num_col, num_row, num_nz, a_format, sense, offset, col_cost, col_lower, col_upper, row_lower, row_upper, a_start, a_index, a_value); assert(run_status == kHighsStatusOk); // Solve the incumbent model run_status = Highs_run(highs); // The run must be successful assert(run_status == kHighsStatusOk); // Get the model status - which must be optimal model_status = Highs_getModelStatus(highs); assert(model_status == kHighsModelStatusOptimal); printf("Run status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); // Get scalar information about the solution Highs_getDoubleInfoValue(highs, "objective_function_value", &objective_function_value); Highs_getIntInfoValue(highs, "simplex_iteration_count", &simplex_iteration_count); Highs_getIntInfoValue(highs, "primal_solution_status", &primal_solution_status); Highs_getIntInfoValue(highs, "dual_solution_status", &dual_solution_status); Highs_getIntInfoValue(highs, "basis_validity", &basis_validity); // The primal and dual solution status values should indicate feasibility assert(primal_solution_status == kHighsSolutionStatusFeasible); assert(dual_solution_status == kHighsSolutionStatusFeasible); // The basis status should indicate validity assert(basis_validity == kHighsBasisValidityValid); double* col_value = (double*)malloc(sizeof(double) * num_col); double* col_dual = (double*)malloc(sizeof(double) * num_col); double* row_value = (double*)malloc(sizeof(double) * num_row); double* row_dual = (double*)malloc(sizeof(double) * num_row); HighsInt* col_basis_status = (HighsInt*)malloc(sizeof(HighsInt) * num_col); HighsInt* row_basis_status = (HighsInt*)malloc(sizeof(HighsInt) * num_row); // Get the primal and dual solution Highs_getSolution(highs, col_value, col_dual, row_value, row_dual); // Get the basis Highs_getBasis(highs, col_basis_status, row_basis_status); // Report the column primal and dual values, and basis status for (HighsInt i = 0; i < num_col; i++) { printf("Col%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "; \n", i, col_value[i], col_dual[i], col_basis_status[i]); } // Report the row primal and dual values, and basis status for (HighsInt i = 0; i < num_row; i++) { printf("Row%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "; \n", i, row_value[i], row_dual[i], row_basis_status[i]); } printf("Objective value = %g; Iteration count = %" HIGHSINT_FORMAT "\n", objective_function_value, simplex_iteration_count); // Illustrate extraction of model data HighsInt check_sense; run_status = Highs_getObjectiveSense(highs, &check_sense); assert(run_status == 0); printf("LP problem has objective sense = %" HIGHSINT_FORMAT "\n", check_sense); assert(check_sense == sense); // Illustrate change of model data Highs_changeObjectiveSense(highs, kHighsObjSenseMaximize); // Solve the incumbent model run_status = Highs_run(highs); // The run must be successful assert(run_status == kHighsStatusOk); // Get the model status - which must be optimal model_status = Highs_getModelStatus(highs); assert(model_status == kHighsModelStatusOptimal); printf("Run status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); // Get scalar information about the solution Highs_getDoubleInfoValue(highs, "objective_function_value", &objective_function_value); Highs_getIntInfoValue(highs, "simplex_iteration_count", &simplex_iteration_count); Highs_getIntInfoValue(highs, "primal_solution_status", &primal_solution_status); Highs_getIntInfoValue(highs, "dual_solution_status", &dual_solution_status); Highs_getIntInfoValue(highs, "basis_validity", &basis_validity); // The primal and dual solution status values should indicate feasibility assert(primal_solution_status == kHighsSolutionStatusFeasible); assert(dual_solution_status == kHighsSolutionStatusFeasible); // The basis status should indicate validity assert(basis_validity == kHighsBasisValidityValid); // Get the primal and dual solution Highs_getSolution(highs, col_value, col_dual, row_value, row_dual); // Get the basis Highs_getBasis(highs, col_basis_status, row_basis_status); // Report the column primal and dual values, and basis status for (HighsInt i = 0; i < num_col; i++) { printf("Col%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "; \n", i, col_value[i], col_dual[i], col_basis_status[i]); } // Report the row primal and dual values, and basis status for (HighsInt i = 0; i < num_row; i++) { printf("Row%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "; \n", i, row_value[i], row_dual[i], row_basis_status[i]); } printf("Objective value = %g; Iteration count = %" HIGHSINT_FORMAT "\n", objective_function_value, simplex_iteration_count); // Now illustrate how LPs can be built within HiGHS by constructing // the same maximization problem. First clear the incumbent model Highs_clearModel(highs); // Demonstrate that the incumbent model is empty const HighsInt check_num_col = Highs_getNumCol(highs); const HighsInt check_num_row = Highs_getNumRow(highs); const HighsInt check_num_nz = Highs_getNumNz(highs); assert(check_num_col == 0); assert(check_num_row == 0); assert(check_num_nz == 0); printf("\nCleared model has %" HIGHSINT_FORMAT " columns, %" HIGHSINT_FORMAT " rows and %" HIGHSINT_FORMAT " nonzeros\n", check_num_col, check_num_row, check_num_nz); // Define the constraint matrix row-wise, as it is added to the LP // with the rows const HighsInt ar_start[3] = {0, 1, 3}; const HighsInt ar_index[5] = {1, 0, 1, 0, 1}; const double ar_value[5] = {1.0, 1.0, 2.0, 3.0, 2.0}; // Add two columns to the empty LP run_status = Highs_addCols(highs, num_col, col_cost, col_lower, col_upper, 0, NULL, NULL, NULL); assert(run_status == 0); // Add three rows to the 2-column LP run_status = Highs_addRows(highs, num_row, row_lower, row_upper, num_nz, ar_start, ar_index, ar_value); assert(run_status == 0); // By default, the optimization sense is minimization, and the // objective offset is zero, so these need to be changed Highs_changeObjectiveSense(highs, kHighsObjSenseMaximize); Highs_changeObjectiveOffset(highs, offset); // Illustrate extraction of model data run_status = Highs_getObjectiveSense(highs, &check_sense); assert(run_status == 0); printf("LP problem has objective sense = %" HIGHSINT_FORMAT "\n", check_sense); assert(check_sense == kHighsObjSenseMaximize); // Illustrate a change of option // Check what type of option value you should provide HighsInt option_type; const char* option_string = "primal_feasibility_tolerance"; run_status = Highs_getOptionType(highs, option_string, &option_type); printf("Option %s is of type %" HIGHSINT_FORMAT "\n", option_string, option_type); assert(run_status == kHighsStatusOk); assert(option_type == 2); double primal_feasibility_tolerance; Highs_getDoubleOptionValue(highs, "primal_feasibility_tolerance", &primal_feasibility_tolerance); printf("primal_feasibility_tolerance = %g: setting it to 1e-6\n", primal_feasibility_tolerance); primal_feasibility_tolerance = 1e-6; Highs_setDoubleOptionValue(highs, "primal_feasibility_tolerance", primal_feasibility_tolerance); // Illustrate how HiGHS can run quietly Highs_setBoolOptionValue(highs, "output_flag", 0); printf("Running quietly...\n"); // Solve the incumbent model run_status = Highs_run(highs); printf("Running loudly...\n"); Highs_setBoolOptionValue(highs, "output_flag", 1); assert(run_status == 0); // Get the model status - which must be optimal model_status = Highs_getModelStatus(highs); assert(model_status == kHighsModelStatusOptimal); printf("\nRun status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); // Check what type of info values are HighsInt info_type; const char* info_string = "objective_function_value"; run_status = Highs_getInfoType(highs, info_string, &info_type); printf("Info %s is of type %" HIGHSINT_FORMAT "\n", info_string, info_type); assert(run_status == kHighsStatusOk); assert(info_type == kHighsInfoTypeDouble); Highs_getDoubleInfoValue(highs, "objective_function_value", &objective_function_value); Highs_getIntInfoValue(highs, "simplex_iteration_count", &simplex_iteration_count); Highs_getIntInfoValue(highs, "primal_solution_status", &primal_solution_status); Highs_getIntInfoValue(highs, "dual_solution_status", &dual_solution_status); Highs_getIntInfoValue(highs, "basis_validity", &basis_validity); // The primal and dual solution status values should indicate feasibility assert(primal_solution_status == kHighsSolutionStatusFeasible); assert(dual_solution_status == kHighsSolutionStatusFeasible); // The basis status should indicate validity assert(basis_validity == kHighsBasisValidityValid); // Get the primal Highs_getSolution(highs, col_value, col_dual, row_value, row_dual); Highs_getBasis(highs, col_basis_status, row_basis_status); // Report the column primal and dual values, and basis status for (HighsInt i = 0; i < num_col; i++) { printf("Col%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "; \n", i, col_value[i], col_dual[i], col_basis_status[i]); } // Report the row primal and dual values, and basis status for (HighsInt i = 0; i < num_row; i++) { printf("Row%" HIGHSINT_FORMAT " = %lf; dual = %lf; status = %" HIGHSINT_FORMAT "; \n", i, row_value[i], row_dual[i], row_basis_status[i]); } printf("Objective value = %g; Iteration count = %" HIGHSINT_FORMAT "\n", objective_function_value, simplex_iteration_count); // // Indicate that the optimal solution for both columns must be // integer valued and solve the model as a MIP HighsInt integrality[2] = {1, 1}; Highs_changeColsIntegralityByRange(highs, 0, 1, integrality); // Solve the incumbent model quietly Highs_setBoolOptionValue(highs, "output_flag", 0); run_status = Highs_run(highs); Highs_setBoolOptionValue(highs, "output_flag", 1); assert(run_status == kHighsStatusOk); // Get the model status - which must be optimal model_status = Highs_getModelStatus(highs); assert(model_status == kHighsModelStatusOptimal); printf("\nRun status = %" HIGHSINT_FORMAT "; Model status = %" HIGHSINT_FORMAT "\n", run_status, model_status); // Get scalar information about the solution Highs_getDoubleInfoValue(highs, "objective_function_value", &objective_function_value); Highs_getIntInfoValue(highs, "simplex_iteration_count", &simplex_iteration_count); Highs_getInt64InfoValue(highs, "mip_node_count", &mip_node_count); Highs_getIntInfoValue(highs, "primal_solution_status", &primal_solution_status); Highs_getIntInfoValue(highs, "dual_solution_status", &dual_solution_status); Highs_getIntInfoValue(highs, "basis_validity", &basis_validity); // The primal solution status value should indicate feasibility assert(primal_solution_status == kHighsSolutionStatusFeasible); // The dual solution status value should indicate no solution assert(dual_solution_status == kHighsSolutionStatusNone); // The basis status value should indicate invalidity assert(basis_validity == kHighsBasisValidityInvalid); assert(mip_node_count == 1); // Get the primal and dual solution Highs_getSolution(highs, col_value, col_dual, row_value, row_dual); // Report the column primal values for (HighsInt i = 0; i < num_col; i++) printf("Col%" HIGHSINT_FORMAT " = %lf\n", i, col_value[i]); // Report the row primal values for (HighsInt i = 0; i < num_row; i++) printf("Row%" HIGHSINT_FORMAT " = %lf\n", i, row_value[i]); printf("Objective value = %g; Iteration count = %" HIGHSINT_FORMAT "\n", objective_function_value, simplex_iteration_count); free(col_value); free(col_dual); free(row_value); free(row_dual); free(col_basis_status); free(row_basis_status); Highs_destroy(highs); } int main() { minimal_api(); minimal_api_qp(); full_api(); return 0; }