8.4. C API¶
This section provides MindOpt C API reference. Contents of the C API are the following:
8.4.6. Examples¶
Diet problem
There are many different kinds of food, each of which can provide various nutrients. How should we make decisions regarding food intake to minimize the amount spent on purchasing food while ensuring that the daily nutritional requirements of the human body are met?
Sets
Food set \(F\)
Nutrient set \(N\)
Parameters
The content of nutrient \(i \in N\) in one unit of food \(j\) is \(a_{ij}\) .
The cost of obtaining one unit of food \(j \in F\) is \(c_j\) .
Decision Variables
\(x_j\) is the amount of food \(j \in F\) that a person consumes daily.
Objective Function
Minimize the total procurement cost of food: \(\text{minimize}~ \sum_{j \in F} c_{j} x_j\) .
Constraints
The nutritional requirement for each nutrient \(i \in N\) must lie between the minimum value \(n_{\min,i}\) and the maximum value \(n_{\max,i}\) : \(n_{\min,i} \le \sum_{j \in F} a_{ij} x_j \le n_{\max,i}, ~~\forall i \in N\) .
#include <stdio.h>
#include "Mindopt.h"
#include <stdlib.h>
#define CHECK_RESULT(code) { int res = code; if (res != 0) { fprintf(stderr, "Bad code: %d \\n", res); exit(res); } }
#define NFOOD 9
#define NNUTRITION 8
#define MODEL_NAME "diet"
#define MODEL_SENSE "ModelSense"
#define STATUS "Status"
#define OBJ_VAL "ObjVal"
#define X "X"
int main(void) {
MDOenv *env;
MDOemptyenv(&env);
MDOstartenv(env);
// Create a model
MDOmodel *m;
// Initialize data
double demand_ub[] = {MDO_INFINITY, 375, MDO_INFINITY, MDO_INFINITY, MDO_INFINITY, MDO_INFINITY, MDO_INFINITY, 75};
double demand_lb[] = {2000, 350, 55, 100, 100, 100, 100, -MDO_INFINITY};
const char *nutrition_name[] = {"Calories", "Carbohydrates", "Protein", "VitA", "VitC", "Calcium", "Iron", "Volume"};
char *food_name[] = {"Cheeseburger", "HamSandwich", "Hamburger", "FishSandwich", "ChickenSandwich", "Fries",
"SausageBiscuit", "LowfatMilk", "OrangeJuice"};
double food_price[] = {1.84, 2.19, 1.84, 1.44, 2.29, 0.77, 1.29, 0.60, 0.72};
double req_value[NFOOD][NNUTRITION] = {
{510.0, 34.0, 28.0, 15.0, 6.0, 30.0, 20.0, 4.0},
{370.0, 35.0, 24.0, 15.0, 10.0, 20.0, 20.0, 7.5},
{500.0, 42.0, 25.0, 6.0, 2.0, 25.0, 20.0, 3.5},
{370.0, 38.0, 14.0, 2.0, 0.0, 15.0, 10.0, 5.0},
{400.0, 42.0, 31.0, 8.0, 15.0, 15.0, 8.0, 7.3},
{220.0, 26.0, 3.0, 0.0, 15.0, 0.0, 2.0, 2.6},
{345.0, 27.0, 15.0, 4.0, 0.0, 20.0, 15.0, 4.1},
{110.0, 12.0, 9.0, 10.0, 120.0, 30.0, 0.0, 8.0},
{80.0, 20.0, 1.0, 2.0, 4.0, 2.0, 2.0, 12.0}};
int *cbeg, *cind, idx;
double *cval;
int i, j, status;
double obj, x;
// Add Variables while initializing model
CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, NFOOD, food_price, 0, NULL, NULL, NULL));
// Add Constraints
// Ensure that the intake of each nutrient is above the given lower bound and below the given upper bound
cbeg = (int *)malloc(sizeof(int) * NNUTRITION);
cind = (int *)malloc(sizeof(int) * NNUTRITION * (NFOOD));
cval = (double *)malloc(sizeof(double) * NNUTRITION * (NFOOD));
idx = 0;
for (i = 0; i < NNUTRITION; i++) {
// Start index of each constraint
cbeg[i] = idx;
for (j = 0; j < NFOOD; ++j) {
cind[idx] = j;
cval[idx++] = req_value[j][i];
}
}
CHECK_RESULT(MDOaddrangeconstrs(m, NNUTRITION, idx, cbeg, cind, cval, demand_lb, demand_ub, nutrition_name));
// Start Optimizing
CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MINIMIZE));
CHECK_RESULT(MDOoptimize(m));
// Print Result
CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
if (status == MDO_OPTIMAL) {
CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
printf("The total cost is %f \\n", obj);
for (i = 0; i < NFOOD; ++i) {
CHECK_RESULT(MDOgetdblattrelement(m, X, i, &x));
printf("You should buy %f unit of %s \\n", x, food_name[i]);
}
} else {
printf("No feasible solution exists \\n");
}
// Release allocated memory
free(cbeg);
free(cind);
free(cval);
MDOfreemodel(m);
MDOfreeenv(env);
return 0;
}
Facility problem
Currently, there are two shopping malls, and the locations of the malls have already been determined. There are several alternative locations for constructing warehouses, whose coordinates and construction costs are known. We assume that the transportation cost from the warehouses to the shopping malls is independent of the quantity of goods but is related to the distance between them. Please find the minimum cost scheme for warehouse construction and transportation.
Sets
Alternative Warehouses \(F\)
Shopping Malls \(M\)
Parameters
The transportation cost from warehouse \(i \in F\) to shopping mall \(j \in M\) is \(a_{ij}\) .
The cost for constructing warehouse \(i \in F\) is \(c_i\) .
The demand for goods at shopping mall \(j \in M\) is \(d_j\) .
Decision Variables
\(x_i\) indicates whether a warehouse is constructed at alternative location \(i \in F\) . It can take a value of 0 or 1, where 0 means not to build and 1 means to build.
\(y_{ij}\) represents the quantity of goods transported from warehouse \(i \in F\) to shopping mall \(j \in M\) .
Objective Function
Minimize the combined cost of warehouse construction and goods transportation:
\(\text{minimize}~ \sum_{i\in F} c_{i}x_i + \sum_{i\in F,j \in M} a_{ij}y_{ij}\)
Constraints
\(\sum_{i\in F} y_{ij} = d_{j}, ~~ \forall j\in M\)
\(x_i d_j - \sum_{k\in M} y_{ik} = 0, ~~ \forall i \in F, j \in M\)
#include <stdio.h>
#include "Mindopt.h"
#include <stdlib.h>
#include <math.h>
#define CHECK_RESULT(code) { int res = code; if (res != 0) { fprintf(stderr, "Bad code: %d \\n", res); exit(res); } }
#define FACILITY_NUM 8
#define MARKET_NUM 2
#define MODEL_NAME "facility"
#define VAR_TYPE "VType"
#define MODEL_SENSE "ModelSense"
#define STATUS "Status"
#define OBJ "Obj"
#define OBJ_VAL "ObjVal"
#define VAR_NAME "VarName"
#define X "X"
double calculate_transportation_fee(double *pos1, double *pos2, double transport_fee_per_m) {
double x1 = pos1[0] - pos2[0];
double x2 = pos1[1] - pos2[1];
return sqrt(x1 * x1 + x2 * x2) * transport_fee_per_m;
}
// The objective of this example is to find the minimum cost solution for warehouse construction and transportation
int main(void) {
MDOenv *env = NULL;
MDOemptyenv(&env);
MDOstartenv(env);
// Create a model
MDOmodel *m = NULL;
// There are two shopping malls with fixed locations at (0, 1.7) and (1.4, 2.9), requiring 100 and 200 units of goods weight.
double market_location[MARKET_NUM][2] = {
{0.0, 1.7},
{1.4, 2.9}};
int market_demand[MARKET_NUM] = {100, 200};
// Optional location and construction cost of warehouses
double facility_location[FACILITY_NUM][2] = {
{0, 1},
{0, 2},
{1, 0},
{1, 1},
{1, 2},
{2, 0},
{2, 1},
{2, 2}};
double facility_expense[FACILITY_NUM] = {3.0, 1.0, 1.5, 1.3, 1.8, 1.6, 1.1, 1.9};
const double transport_fee_per_m = 1.23;
int *cbeg, *cind, *cbeg2, *cind2, idx, col, i, j, status;
double *cval, *cval2, *rhs, *rhs2, obj, x;
char *sense, *sense2, var_name[25];
// Add Variables while initializing model
CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, FACILITY_NUM * (1 + MARKET_NUM), NULL, NULL, NULL, NULL, NULL));
// Initiailize Variables
// x represents whether a warehouse is built at this location
for (i = 0; i < FACILITY_NUM; ++i) {
CHECK_RESULT(MDOsetcharattrelement(m, VAR_TYPE, i, MDO_BINARY));
CHECK_RESULT(MDOsetdblattrelement(m, OBJ, i, facility_expense[i]));
sprintf(var_name, "Position%d", i);
CHECK_RESULT(MDOsetstrattrelement(m, VAR_NAME, i, var_name));
}
// y represents the amount of goods transported from warehouse j to shopping center i.
// The type of values is CONTINUOUS
// The lower bound of 0 represents that it is not possible to transport less than 0 units of goods from warehouse j to shopping center i
for (i = 0; i < FACILITY_NUM; ++i) {
for (j = 0; j < MARKET_NUM; j++) {
sprintf(var_name, "Transportation_%d_to_%d", i, j);
CHECK_RESULT(MDOsetstrattrelement(m, VAR_NAME, FACILITY_NUM * (1 + j) + i, var_name));
CHECK_RESULT(MDOsetdblattrelement(m, OBJ, FACILITY_NUM * (1 + j) + i,
calculate_transportation_fee(market_location[j], facility_location[i], transport_fee_per_m)));
}
}
// Add Constraints
cbeg = (int *)malloc(sizeof(int) * FACILITY_NUM * MARKET_NUM);
cind = (int *)malloc(sizeof(int) * (FACILITY_NUM * MARKET_NUM * 2));
cval = (double *)malloc(sizeof(double) * (FACILITY_NUM * MARKET_NUM * 2));
rhs = (double *)malloc(sizeof(double) * FACILITY_NUM * MARKET_NUM);
sense = (char *)malloc(sizeof(char) * FACILITY_NUM * MARKET_NUM);
printf("%d \\n", FACILITY_NUM * MARKET_NUM);
idx = 0;
// Constraint 1 : ensure that all demand of the shopping centers is satisfied
for (i = 0; i < FACILITY_NUM; i++) {
for (j = 0; j < MARKET_NUM; ++j) {
col = i * MARKET_NUM + j;
cbeg[col] = idx;
rhs[col] = 0;
sense[col] = MDO_LESS_EQUAL;
cind[idx] = FACILITY_NUM * (1 + j) + i;
cval[idx++] = 1;
cind[idx] = i;
cval[idx++] = -market_demand[j];
}
}
CHECK_RESULT(MDOaddconstrs(m, FACILITY_NUM*MARKET_NUM, idx, cbeg, cind, cval, sense, rhs, NULL));
// Constraint 2 : If this warehouse is not constructed, the amount of goods transported from this location must be 0
cbeg2 = (int *)malloc(sizeof(int) * MARKET_NUM);
cind2 = (int *)malloc(sizeof(int) * MARKET_NUM * FACILITY_NUM);
cval2 = (double *)malloc(sizeof(double) * MARKET_NUM * FACILITY_NUM);
rhs2 = (double *)malloc(sizeof(double) * MARKET_NUM);
sense2 = (char *)malloc(sizeof(char) * MARKET_NUM);
idx = 0;
for (j = 0; j < MARKET_NUM; ++j) {
cbeg2[j] = idx;
rhs2[j] = market_demand[j];
sense2[j] = MDO_EQUAL;
for (i = 0; i < FACILITY_NUM; i++) {
cind2[idx] = FACILITY_NUM * (1 + j) + i;
cval2[idx++] = 1;
}
}
CHECK_RESULT(MDOaddconstrs(m, MARKET_NUM, idx, cbeg2, cind2, cval2, sense2, rhs2, NULL));
// Start Optimizing
CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MINIMIZE));
CHECK_RESULT(MDOwrite(m, "test_c.mps"));
CHECK_RESULT(MDOoptimize(m));
CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
// Print Result
if (status == MDO_OPTIMAL) {
CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
printf("The total cost is %f \\n", obj);
for (i = 0; i < FACILITY_NUM; ++i) {
CHECK_RESULT(MDOgetdblattrelement(m, "X", i, &x));
if (x) {
printf("The No.%d warehouse should be built at (%g, %g) \\n",
i, facility_location[i][0], facility_location[i][1]);
}
}
} else {
printf("No feasible solution exists \\n");
}
free(cbeg);
free(cind);
free(cval);
free(rhs);
free(sense);
free(cbeg2);
free(cind2);
free(cval2);
free(rhs2);
free(sense2);
MDOfreemodel(m);
MDOfreeenv(env);
return 0;
}
WorkForce problem
In a week, the number of workers needed by the factory varies each day. It is currently known how much each worker earns per day and the dates on which they can attend work. The goal is to calculate how to schedule the workers in order to meet the factory’s operational requirements while minimizing wage costs.
Sets:
Days of the week \(D = 1, 2, 3, \ldots, 7\)
Number of workers needed by the factory \(N\)
Workers \(S\)
Parameters:
The number of workers needed by the factory on day \(i \in D\) is \(n_i\) .
The daily wage of worker \(j \in S\) is \(s_j\) .
A sequence indicating the available working times for workers, totaling \(T\) pairs of (worker, day) denoted as \((d_i, t_i)\) , where \(d_i \in S\) and \(t_i \in D\) , for \(i = 1, 2, 3, \ldots, T\) .
Objective Function:
Minimize the total wages paid: \(\text{minimize}~ \sum_{i=1}^{T} x_i s_{d_i}\)
Decision Variables:
\(x_i (i = 1, 2, 3, \ldots, T)\) indicates whether the worker in the available working time sequence shows up on that day. Its values must be 0 or 1, where 0 indicates the worker does not attend, and 1 indicates the worker does attend.
Constraints:
\(\sum_{d_i=r} x_i = n_{r}, ~~\forall r\in D\)
#include <stdio.h>
#include "Mindopt.h"
#include <stdlib.h>
#define CHECK_RESULT(code) { int res = code; if (res != 0) { fprintf(stderr, "Bad code: %d \\n", res); exit(res); } }
#define MODEL_NAME "workforce"
#define MODEL_SENSE "ModelSense"
#define STATUS "Status"
#define OBJ_VAL "ObjVal"
#define X "X"
#define WORKERS_NUM 7
#define DAY_NUM 7
int main(void) {
MDOenv *env = NULL;
MDOemptyenv(&env);
MDOstartenv(env);
MDOmodel *m = NULL;
int id = 0;
char var_name[20];
int i, j;
// Number of required workers for each day
const char *day_name[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
double workers_per_day[] = {3, 1, 4, 2, 1, 3, 3};
// Daily wage of each worker
char *workers_name[] = {"Xiaoming", "Huahua", "HongHong", "Dahua", "Lihua", "Niuniu", "Gouzi"};
double workers_pay[] = {13, 10, 11, 8, 9, 14, 14};
// Available days for each worker
int availability[WORKERS_NUM][DAY_NUM];
int non_zero_num = 32;
int non_zero_col[] = {0, 0, 0, 0, 1, 1, 1, 1, 2,2, 2,
2, 3, 3, 3, 3, 4,4, 4, 4, 4,
4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6};
int non_zero_row[] = {1, 2, 4, 6, 0, 1, 4, 5, 2, 3, 4,
6, 1, 2, 4, 5, 0, 1, 2, 3, 4,
6, 0, 1, 2, 5, 0, 1, 2, 4, 5, 6};
for (j = 0; j < non_zero_num; ++j) {
availability[non_zero_col[j]][non_zero_row[j]] = 1;
}
int *cbeg, *cind, idx, status;
double *cval, *rhs, obj, x;
char *sense;
// Add Variables while initializing model
CHECK_RESULT(MDOnewmodel(env, &m, MODEL_NAME, 0, NULL, NULL, NULL, NULL, NULL));
// Initialize Variables and its coefficient in the objective function
for (j = 0; j < DAY_NUM; ++j) {
for (i = 0; i < WORKERS_NUM; ++i) {
if (availability[i][j]) {
sprintf(var_name, "%s.%s", workers_name[i], day_name[j]);
CHECK_RESULT(MDOaddvar(m, 0, NULL, NULL, workers_pay[i], 0, 1, MDO_BINARY, (const char*)var_name));
id++;
}
}
}
// Add Constraints
// Constraint : ensure that each day has enough workforce
cbeg = (int *)malloc(sizeof(int) * DAY_NUM);
cind = (int *)malloc(sizeof(int) * id);
cval = (double *)malloc(sizeof(double) * id);
rhs = (double *)malloc(sizeof(double) * DAY_NUM);
sense = (char *)malloc(sizeof(char) * DAY_NUM);
idx = 0;
id = 0;
for (i = 0; i < DAY_NUM; ++i) {
cbeg[i] = idx;
rhs[i] = workers_per_day[i];
sense[i] = MDO_EQUAL;
for (j = 0; j < WORKERS_NUM; ++j) {
if (availability[j][i]) {
cind[idx] = id;
cval[idx++] = 1;
id++;
}
}
}
CHECK_RESULT(MDOaddconstrs(m, DAY_NUM, idx, cbeg, cind, cval, sense, rhs, day_name));
// Start Optimizing
CHECK_RESULT(MDOsetintattr(m, MODEL_SENSE, MDO_MINIMIZE));
CHECK_RESULT(MDOoptimize(m));
CHECK_RESULT(MDOwrite(m, "test_c.mps"));
CHECK_RESULT(MDOgetintattr(m, STATUS, &status));
// Print Result
if (status == MDO_OPTIMAL) {
CHECK_RESULT(MDOgetdblattr(m, OBJ_VAL, &obj));
printf("The total cost is %f \\n", obj);
for (j = 0; j < WORKERS_NUM; ++j) {
char *worker_name = workers_name[j];
for (i = 0; i < DAY_NUM; ++i) {
CHECK_RESULT(MDOgetdblattrelement(m, X, i, &x));
if (x == 1) {
printf("%s should work at %s \\n", worker_name, day_name[i]);
}
}
}
} else {
printf("No feasible solution exists \\n");
}
// Release allocated memory
free(cbeg);
free(cind);
free(cval);
free(rhs);
free(sense);
MDOfreemodel(m);
MDOfreeenv(env);
return 0;
}