We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve the problem in lpsolve in different ways. This via ASCII files and from different programming languages.
Suppose a farmer has 75 acres on which to plant two crops: wheat and barley. To produce these crops, it costs the farmer (for seed, fertilizer, etc.) $120 per acre for the wheat and $210 per acre for the barley. The farmer has $15000 available for expenses. But after the harvest, the farmer must store the crops while awaiting favourable market conditions. The farmer has storage space for 4000 bushels. Each acre yields an average of 110 bushels of wheat or 30 bushels of barley. If the net profit per bushel of wheat (after all expenses have been subtracted) is $1.30 and for barley is $2.00, how should the farmer plant the 75 acres to maximize profit?
We begin by formulating the problem mathematically. First we express the objective, that is the profit, and the constraints algebraically, then we graph them, and lastly we arrive at the solution by graphical inspection and a minor arithmetic calculation.
Let x denote the number of acres allotted to wheat and y the number of acres allotted to barley. Then the expression to be maximized, that is the profit, is clearly
P = (110)(1.30)x + (30)(2.00)y = 143x + 60y.
There are three constraint inequalities, specified by the limits on expenses, storage and acreage. They are respectively:
120x + 210y <= 15000
110x + 30y <= 4000
x + y <= 75
Strictly speaking there are two more constraint inequalities forced by the fact that the farmer cannot plant a negative number of acres, namely:
x >= 0, y >= 0.
Next we graph the regions specified by the constraints. The last two say that we only need to consider the first quadrant in the x-y plane. Here's a graph delineating the triangular region in the first quadrant determined by the first inequality.
Now let's put in the other two constraint inequalities.
The black area is the solution space that holds valid solutions. This means that any point in this area fulfils the constraints.
Now let's superimpose on top of this picture a contour plot of the objective function P.
The lines give a picture of the objective function. All solutions that intersect with the black area are valid solutions, meaning that this result also fulfils the set constraints. The more the lines go to the right, the higher the objective value is. The optimal solution or best objective is a line that is still in the black area, but with an as large as possible value.
It seems apparent that the maximum value of P will occur on the level curve (that is, level
line) that passes through the vertex of the polygon that lies near (22,53).
It is the intersection of x + y = 75 and 110*x + 30*y = 4000
This is a corner point of the diagram. This is not a coincidence. The simplex algorithm, which is used
by lpsolve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:
x + y = 75 (1) 110*x + 30*y = 4000 (2)
From (1), y can be expressed in function of x:
y = 75 - x (3)
This equation can be substituted in (2):
110*x + 30*(75 - x) = 4000
Or:
80*x = 1750
Or:
x = 21.875
From (3), y can be derived:
y = 75 - 21.875 = 53.125
The acreage that results in the maximum profit is 21.875 for wheat and 53.125 for barley. In that case the profit is:
P = 143*x + 60*y
Or:
P = 143*21.875 + 60*53.125 = 6326.625That is, $6315.625.
Now, lpsolve comes into the picture to solve this linear programming problem more generally.
First let us show this problem in its mathematical format:
max(143x + 60y) s.t. 120x + 210y <= 15000 110x + 30y <= 4000 x + y <= 75 x >= 0 y >= 0
There are several ways to model a linear problem via lpsolve:
There exist a lot of formats to model an lp problem into. Almost each solver has its format on its own.
The MPS format is supported by most lp solvers and thus very universal. The model is provided to the solver via an ASCII file. This format is very old and difficult to read by humans. See MPS file format for a complete description about the format. This problem is formulated as follows in MPS format:
* model.mps NAME ROWS N R0 L R1 L R2 L R3 COLUMNS x R0 143.00000000 R1 120.00000000 x R2 110.00000000 R3 1.0000000000 y R0 60.00000000 R1 210.00000000 y R2 30.000000000 R3 1.0000000000 RHS RHS R1 15000.000000 R2 4000.0000000 RHS R3 75.000000000 ENDATA
Save this as ASCII file with name model.mps
To read this format in lpsolve, the API functions read_mps, read_freemps, read_MPS, read_freeMPS can be used. The lpsolve distribution comes with two applications that use this API call to read a model:
To read this MPS model via the lp_solve command line program and calculate the solution, enter the following command:
lp_solve -max -mps model.mps
This gives:
Value of objective function: 6315.63 Actual values of the variables: x 21.875 y 53.125
The lp_solve program has a lot of options that can be set. See lp_solve command
Under Windows, there is also a graphical IDE that can read an MPS file. See LPSolve IDE for more information.
The lp format is the native lpsolve format to provide LP models via an ASCII file to the solver. It is very readable and its syntax is very similar to the Mathematical formulation. See LP file format for a complete description about the format. This model is formulated as follows in lp-format:
/* model.lp */ max: 143 x + 60 y; 120 x + 210 y <= 15000; 110 x + 30 y <= 4000; x + y <= 75;
Save this as ASCII file with name model.lp
To read this format in lpsolve, the API functions read_lp, read_LP can be used. The lpsolve distribution comes with two applications that use this API call to read a model:
To read this lp model via the lp_solve command line program and calculate the solution, enter the following command:
lp_solve model.lp
This gives:
Value of objective function: 6315.63 Actual values of the variables: x 21.875 y 53.125
The lp_solve program has a lot of options that can be set. See lp_solve command
Under Windows, there is also a graphical IDE that can read an lp-file. See LPSolve IDE for more information.
The CPLEX lp format is another format to provide LP models via an ASCII file to the solver. It is very readable and its syntax is very similar to the Mathematical formulation. It is a format used by the CPLEX solver. See CPLEX lp files for a complete description about the format. This model is formulated as follows in CPLEX lp format:
\* model.lpt *\ Maximize +143 x +60 y Subject To +120 x +210 y <= 15000 +110 x +30 y <= 4000 +x +y <= 75 End
Save this as ASCII file with name model.lpt
lpsolve doesn't has an API call to read/write this format. However, the lpsolve distribution has an XLI that can do this. See External Language Interfaces for a description about XLIs. This uses the API call read_XLI. The xli to read/write this format is xli_CPLEX. The lpsolve distribution comes with two applications that use this API call to read a model:
To read this CPLEX lp model via the lp_solve command line program and calculate the solution, enter the following command:
lp_solve -rxli xli_CPLEX model.lpt
This gives:
Value of objective function: 6315.63 Actual values of the variables: x 21.875 y 53.125
The lp_solve program has a lot of options that can be set. See lp_solve command
Under Windows, there is also a graphical IDE that can read a CPLEX lp file via an XLI. See LPSolve IDE for more information.
The LINDO FILE format is another format to provide LP models via an ASCII file to the solver. It is very readable and its syntax is very similar to the Mathematical formulation. It is a format used by the LINDO solver. See LINDO lp files for a complete description about the format. This model is formulated as follows in LINDO FILE format:
! model.lnd MAXIMIZE +143 x +60 y SUBJECT TO +120 x +210 y <= 15000 +110 x +30 y <= 4000 +x +y <= 75 END
Save this as ASCII file with name model.lpt
lpsolve doesn't has an API call to read/write this format. However, the lpsolve distribution has an XLI that can do this. See External Language Interfaces for a description about XLIs. This uses the API call read_XLI. The xli to read/write this format is xli_LINDO. The lpsolve distribution comes with two applications that use this API call to read a model:
To read this LINDO lp model via the lp_solve command line program and calculate the solution, enter the following command:
lp_solve -rxli xli_LINDO model.lnd
This gives:
Value of objective function: 6315.63 Actual values of the variables: x 21.875 y 53.125
The lp_solve program has a lot of options that can be set. See lp_solve command
Under Windows, there is also a graphical IDE that can read a LINDO lp file via an XLI. See LPSolve IDE for more information.
The GNU MathProg format is another format to provide LP models via an ASCII file to the solver. It is very readable and its syntax is very similar to the Mathematical formulation. It is a format used by the GLPK solver and a subset of AMPL. It has also the possibility to use loops. See Modeling Language GNU MathProg This model is formulated as follows in GNU MathProg format:
/* model.mod */ var x >= 0; var y >= 0; maximize obj: +143*x +60*y; R1: +120*x +210*y <= 15000; R2: +110*x +30*y <= 4000; R3: +x +y <= 75;
Save this as ASCII file with name model.mod
lpsolve doesn't has an API call to read/write this format. However, the lp_solve distribution has an XLI that can do this. See External Language Interfaces for a description about XLIs. This uses the API call read_XLI. The xli to read/write this format is xli_MathProg. The lpsolve distribution comes with two applications that use this API call to read a model:
To read this GNU MathProg model via the lp_solve command line program and calculate the solution, enter the following command:
lp_solve -rxli xli_MathProg model.mod
This gives:
Value of objective function: 6315.63 Actual values of the variables: x 21.875 y 53.125
The lp_solve program has a lot of options that can be set. See lp_solve command
Under Windows, there is also a graphical IDE that can read a GNU MathProg file via an XLI. See LPSolve IDE for more information.
The LPFML XML format is another format to provide LP models via an ASCII file to the solver. This format is very recent and uses XML layout. It is not very readable by us, but because of the XML structure very flexible. See LPFML: A W3C XML Schema for Linear Programming for more information. This model is formulated as follows in LPFML XML format:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <mathProgram xmlns="http://FML/lpfml.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://FML/lpfml.xsd lpfml.xsd"> <linearProgramDescription> <source></source> <maxOrMin>max</maxOrMin> <numberRows>3</numberRows> <numberVars>2</numberVars> </linearProgramDescription> <linearProgramData> <rows> <row rowName="R1" rowUB="15000"/> <row rowName="R2" rowUB="4000"/> <row rowName="R3" rowUB="75"/> </rows> <columns> <col colName="x" colType="C" objVal="143"/> <col colName="y" colType="C" objVal="60"/> </columns> <amatrix> <sparseMatrix> <pntANonz> <el>3</el> <el>6</el> </pntANonz> <rowIdx> <el>0</el> <el>1</el> <el>2</el> <el>0</el> <el>1</el> <el>2</el> </rowIdx> <nonz> <el>120</el> <el>110</el> <el>1</el> <el>210</el> <el>30</el> <el>1</el> </nonz> </sparseMatrix> </amatrix> </linearProgramData> </mathProgram>
Save this as ASCII file with name model.xml
lpsolve doesn't has an API call to read/write this format. However, the lp_solve distribution has an XLI that can do this. See External Language Interfaces for a description about XLIs. This uses the API call read_XLI. The xli to read/write this format is xli_LPFML. The lpsolve distribution comes with two applications that use this API call to read a model:
To read this LPFML XML model via the lp_solve command line program and calculate the solution, enter the following command:
lp_solve -rxli xli_LPFML model.xml
This gives:
Value of objective function: 6315.63 Actual values of the variables: x 21.875 y 53.125
The lp_solve program has a lot of options that can be set. See lp_solve command
Under Windows, there is also a graphical IDE that can read a LPFML XML file via an XLI. See LPSolve IDE for more information.
There are several commercial and free Mathematical programming applications out there which can be used to solve lp problems. An lpsolve driver is made for several of them:
In several cases it is required that the solver is called from within the programming language in which an application is build. All the data is in memory and no files are created to provide data to the solver. lpsolve has a very rich, yet easy, API to do this. See lp_solve API reference for an overview of the API. lpsolve is a library of API routines. This library is called from the programming language. See Calling the lpsolve API from your application for more information. Above example is now formulated in several programming languages:
The example model can be formulated as follows in C:
/* demo.c */ #include "lp_lib.h" int demo() { lprec *lp; int Ncol, *colno = NULL, j, ret = 0; REAL *row = NULL; /* We will build the model row by row So we start with creating a model with 0 rows and 2 columns */ Ncol = 2; /* there are two variables in the model */ lp = make_lp(0, Ncol); if(lp == NULL) ret = 1; /* couldn't construct a new model... */ if(ret == 0) { /* let us name our variables. Not required, but can be useful for debugging */ set_col_name(lp, 1, "x"); set_col_name(lp, 2, "y"); /* create space large enough for one row */ colno = (int *) malloc(Ncol * sizeof(*colno)); row = (REAL *) malloc(Ncol * sizeof(*row)); if((colno == NULL) || (row == NULL)) ret = 2; } if(ret == 0) { set_add_rowmode(lp, TRUE); /* makes building the model faster if it is done rows by row */ /* construct first row (120 x + 210 y <= 15000) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 120; colno[j] = 2; /* second column */ row[j++] = 210; /* add the row to lpsolve */ if(!add_constraintex(lp, j, row, colno, LE, 15000)) ret = 3; } if(ret == 0) { /* construct second row (110 x + 30 y <= 4000) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 110; colno[j] = 2; /* second column */ row[j++] = 30; /* add the row to lpsolve */ if(!add_constraintex(lp, j, row, colno, LE, 4000)) ret = 3; } if(ret == 0) { /* construct third row (x + y <= 75) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 1; colno[j] = 2; /* second column */ row[j++] = 1; /* add the row to lpsolve */ if(!add_constraintex(lp, j, row, colno, LE, 75)) ret = 3; } if(ret == 0) { set_add_rowmode(lp, FALSE); /* rowmode should be turned off again when done building the model */ /* set the objective function (143 x + 60 y) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 143; colno[j] = 2; /* second column */ row[j++] = 60; /* set the objective in lpsolve */ if(!set_obj_fnex(lp, j, row, colno)) ret = 4; } if(ret == 0) { /* set the object direction to maximize */ set_maxim(lp); /* just out of curioucity, now show the model in lp format on screen */ /* this only works if this is a console application. If not, use write_lp and a filename */ write_LP(lp, stdout); /* write_lp(lp, "model.lp"); */ /* I only want to see important messages on screen while solving */ set_verbose(lp, IMPORTANT); /* Now let lpsolve calculate a solution */ ret = solve(lp); if(ret == OPTIMAL) ret = 0; else ret = 5; } if(ret == 0) { /* a solution is calculated, now lets get some results */ /* objective value */ printf("Objective value: %f\n", get_objective(lp)); /* variable values */ get_variables(lp, row); for(j = 0; j < Ncol; j++) printf("%s: %f\n", get_col_name(lp, j + 1), row[j]); /* we are done now */ } /* free allocated memory */ if(row != NULL) free(row); if(colno != NULL) free(colno); if(lp != NULL) { /* clean up such that all used memory by lpsolve is freed */ delete_lp(lp); } return(ret); } int main() { demo(); }
When this is run, the following is shown on screen:
/* Objective function */ max: +143 x +60 y; /* Constraints */ +120 x +210 y <= 15000; +110 x +30 y <= 4000; +x +y <= 75; Objective value: 6315.625000 x: 21.875000 y: 53.125000
Note that this example is very limited. It is also possible to set bounds on variables, ranges on constraints, define variables as integer, get more result information, changing solver options and parameters and much more. See lp_solve API reference for an overview of the API to do this.
The example model can be formulated as follows in Java:
/* demo.java */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import lpsolve.*; public class Demo { public Demo() { } public int execute() throws LpSolveException { LpSolve lp; int Ncol, j, ret = 0; /* We will build the model row by row So we start with creating a model with 0 rows and 2 columns */ Ncol = 2; /* there are two variables in the model */ /* create space large enough for one row */ int[] colno = new int[Ncol]; double[] row = new double[Ncol]; lp = LpSolve.makeLp(0, Ncol); if(lp.getLp() == 0) ret = 1; /* couldn't construct a new model... */ if(ret == 0) { /* let us name our variables. Not required, but can be useful for debugging */ lp.setColName(1, "x"); lp.setColName(2, "y"); lp.setAddRowmode(true); /* makes building the model faster if it is done rows by row */ /* construct first row (120 x + 210 y <= 15000) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 120; colno[j] = 2; /* second column */ row[j++] = 210; /* add the row to lpsolve */ lp.addConstraintex(j, row, colno, LpSolve.LE, 15000); } if(ret == 0) { /* construct second row (110 x + 30 y <= 4000) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 110; colno[j] = 2; /* second column */ row[j++] = 30; /* add the row to lpsolve */ lp.addConstraintex(j, row, colno, LpSolve.LE, 4000); } if(ret == 0) { /* construct third row (x + y <= 75) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 1; colno[j] = 2; /* second column */ row[j++] = 1; /* add the row to lpsolve */ lp.addConstraintex(j, row, colno, LpSolve.LE, 75); } if(ret == 0) { lp.setAddRowmode(false); /* rowmode should be turned off again when done building the model */ /* set the objective function (143 x + 60 y) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 143; colno[j] = 2; /* second column */ row[j++] = 60; /* set the objective in lpsolve */ lp.setObjFnex(j, row, colno); } if(ret == 0) { /* set the object direction to maximize */ lp.setMaxim(); /* just out of curioucity, now generate the model in lp format in file model.lp */ lp.writeLp("model.lp"); /* I only want to see important messages on screen while solving */ lp.setVerbose(LpSolve.IMPORTANT); /* Now let lpsolve calculate a solution */ ret = lp.solve(); if(ret == LpSolve.OPTIMAL) ret = 0; else ret = 5; } if(ret == 0) { /* a solution is calculated, now lets get some results */ /* objective value */ System.out.println("Objective value: " + lp.getObjective()); /* variable values */ lp.getVariables(row); for(j = 0; j < Ncol; j++) System.out.println(lp.getColName(j + 1) + ": " + row[j]); /* we are done now */ } /* clean up such that all used memory by lpsolve is freed */ if(lp.getLp() != 0) lp.deleteLp(); return(ret); } public static void main(String[] args) { try { new Demo().execute(); } catch (LpSolveException e) { e.printStackTrace(); } } }
When this is run, the following is shown on screen:
Objective value: 6315.625 x: 21.875000000000007 y: 53.12499999999999
And a file model.lp is created with the following contents:
/* Objective function */ max: +143 x +60 y; /* Constraints */ +120 x +210 y <= 15000; +110 x +30 y <= 4000; +x +y <= 75;
Note that this example is very limited. It is also possible to set bounds on variables, ranges on constraints, define variables as integer, get more result information, changing solver options and parameters and much more. See lp_solve API reference for an overview of the API to do this.
Also note that the API names in Java are a bit different than in the native lpsolve API and the lp argument is not there. See the lpsolve Java wrapper documentation for more details.
The example model can be formulated as follows in Delphi or Free Pascal:
program demo; {$APPTYPE CONSOLE} uses SysUtils, lpsolve; var Ncol, j, ret: integer; colno: PIntArray; row: PFloatArray; lp: THandle; begin ret := 0; colno := nil; row := nil; (* We will build the model row by row So we start with creating a model with 0 rows and 2 columns *) Ncol := 2; (* there are two variables in the model *) lp := make_lp(0, Ncol); if (lp = 0) then ret := 1; (* couldn't construct a new model... *) (* let us name our variables. Not required, but can be usefull for debugging *) set_col_name(lp, 1, 'x'); set_col_name(lp, 2, 'y'); if (ret = 0) then begin (* create space large enough for one row *) GetMem(colno, SizeOf(integer) * Ncol); GetMem(row, SizeOf(double) * Ncol); if ((colno = nil) or (row = nil)) then ret := 2; end; if (ret = 0) then begin set_add_rowmode(lp, true); (* makes building the model faster if it is done rows by row *) (* construct first row (120 x + 210 y <= 15000) *) j := 0; colno^[j] := 1; (* first column *) row^[j] := 120; j := j + 1; colno^[j] := 2; (* second column *) row^[j] := 210; j := j + 1; (* add the row to lp_solve *) if (not add_constraintex(lp, j, row, colno, LE, 15000)) then ret := 3; end; if (ret = 0) then begin (* construct second row (110 x + 30 y <= 4000) *) j := 0; colno^[j] := 1; (* first column *) row^[j] := 110; j := j + 1; colno^[j] := 2; (* second column *) row^[j] := 30; j := j + 1; (* add the row to lp_solve *) if (not add_constraintex(lp, j, row, colno, LE, 4000)) then ret := 3; end; if (ret = 0) then begin (* construct third row (x + y <= 75) *) j := 0; colno^[j] := 1; (* first column *) row^[j] := 1; j := j + 1; colno^[j] := 2; (* second column *) row^[j] := 1; j := j + 1; (* add the row to lp_solve *) if (not add_constraintex(lp, j, row, colno, LE, 75)) then ret := 3; end; if (ret = 0) then begin set_add_rowmode(lp, false); (* rowmode should be turned off again when done building the model *) (* set the objective function (143 x + 60 y) *) j := 0; colno^[j] := 1; (* first column *) row^[j] := 143; j := j + 1; colno^[j] := 2; (* second column *) row^[j] := 60; j := j + 1; (* set the objective in lp_solve *) if (not set_obj_fnex(lp, j, row, colno)) then ret := 4; end; if (ret = 0) then begin (* set the object direction to maximize *) set_maxim(lp); (* just out of curioucity, now show the model in lp format *) write_lp(lp, 'model.lp'); (* I only want to see importand messages on screen while solving *) set_verbose(lp, IMPORTANT); (* Now let lp_solve calculate a solution *) ret := solve(lp); if (ret = OPTIMAL) then ret := 0 else ret := 5; end; if (ret = 0) then begin (* a solution is calculated, now lets get some results *) (* objective value *) writeln(format('Objective value: %f', [get_objective(lp)])); (* variable values *) get_variables(lp, row); for j := 0 to Ncol-1 do writeln(format('%s: %f', [get_col_name(lp, j + 1), row^[j]])); (* we are done now *) end; (* free allocated memory *) if (row <> nil) then FreeMem(row); if (colno <> nil) then FreeMem(colno); if(lp <> 0) then begin (* clean up such that all used memory by lp_solve is freeed *) delete_lp(lp); end; end.
When this is run, the following is shown:
Objective value: 6315.63 x: 21.88 y: 53.12
And a file model.lp is created with the following contents:
/* Objective function */ max: +143 x +60 y; /* Constraints */ +120 x +210 y <= 15000; +110 x +30 y <= 4000; +x +y <= 75;
Note that a unit lpsolve.pas+lpsolve.inc is needed for this to work. This is available via the Delphi example.
Note that this example is very limited. It is also possible to set bounds on variables, ranges on constraints, define variables as integer, get more result information, changing solver options and parameters and much more. See lp_solve API reference for an overview of the API to do this.
The example model can be formulated as follows in VB or VBScript:
Option Explicit 'demo Private lpsolve As lpsolve55 Sub Main() Set lpsolve = New lpsolve55 lpsolve.Init "." Demo Set lpsolve = Nothing End Sub Private Function Demo() As Integer Dim lp As Long Dim Ncol As Long, colno() As Long Dim j As Integer, ret As Integer Dim row() As Double With lpsolve ' We will build the model row by row ' So we start with creating a model with 0 rows and 2 columns Ncol = 2 ' there are two variables in the model lp = .make_lp(0, Ncol) If lp = 0 Then ret = 1 ' couldn't construct a new model... End If If ret = 0 Then ' let us name our variables. Not required, but can be useful for debugging .set_col_name lp, 1, "x" .set_col_name lp, 2, "y" ' create space large enough for one row ReDim colno(0 To Ncol - 1) ReDim row(0 To Ncol - 1) End If If ret = 0 Then .set_add_rowmode lp, True ' makes building the model faster if it is done rows by row ' construct first row (120 x + 210 y <= 15000) j = 0 colno(j) = 1 ' first column row(j) = 120 j = j + 1 colno(j) = 2 ' second column row(j) = 210 j = j + 1 ' add the row to lpsolve If .add_constraintex(lp, j, row(0), colno(0), LE, 15000) = False Then ret = 3 End If End If If ret = 0 Then ' construct second row (110 x + 30 y <= 4000) j = 0 colno(j) = 1 ' first column row(j) = 110 j = j + 1 colno(j) = 2 ' second column row(j) = 30 j = j + 1 ' add the row to lpsolve If .add_constraintex(lp, j, row(0), colno(0), LE, 4000) = False Then ret = 3 End If End If If ret = 0 Then ' construct third row (x + y <= 75) j = 0 colno(j) = 1 ' first column row(j) = 1 j = j + 1 colno(j) = 2 ' second column row(j) = 1 j = j + 1 ' add the row to lpsolve If .add_constraintex(lp, j, row(0), colno(0), LE, 75) = False Then ret = 3 End If End If If ret = 0 Then .set_add_rowmode lp, False ' rowmode should be turned off again when done building the model ' set the objective function (143 x + 60 y) j = 0 colno(j) = 1 ' first column row(j) = 143 j = j + 1 colno(j) = 2 ' second column row(j) = 60 j = j + 1 ' set the objective in lpsolve If .set_obj_fnex(lp, j, row(0), colno(0)) = False Then ret = 4 End If End If If ret = 0 Then ' set the object direction to maximize .set_maxim lp ' just out of curioucity, now show the model in lp format on screen ' this only works if this is a console application. If not, use write_lp and a filename .write_lp lp, "model.lp" ' I only want to see important messages on screen while solving .set_verbose lp, 3 ' Now let lpsolve calculate a solution ret = .solve(lp) If ret = OPTIMAL Then ret = 0 Else ret = 5 End If End If If ret = 0 Then ' a solution is calculated, now lets get some results ' objective value Debug.Print "Objective value: " & .get_objective(lp) ' variable values .get_variables lp, row(0) For j = 1 To Ncol Debug.Print .get_col_name(lp, j) & ": " & row(j - 1) Next ' we are done now End If ' free allocated memory Erase row Erase colno If lp <> 0 Then ' clean up such that all used memory by lpsolve is freed .delete_lp lp End If Demo = ret End With End Function
When this is run, the following is shown in the debug window:
Objective value: 6315.625 x: 21.875 y: 53.125
And a file model.lp is created with the following contents:
/* Objective function */ max: +143 x +60 y; /* Constraints */ +120 x +210 y <= 15000; +110 x +30 y <= 4000; +x +y <= 75;
Note that a class lpsolve55.cls or the lpsolve55 COM object is needed for this to work. The class is available via the VB example and the COM object is also available.
Note that this example is very limited. It is also possible to set bounds on variables, ranges on constraints, define variables as integer, get more result information, changing solver options and parameters and much more. See lp_solve API reference for an overview of the API to do this.
The example model can be formulated as follows in VB.NET:
Option Strict Off Option Explicit On Module Module1 'demo Private lpsolve As lpsolve55 Public Sub Main() lpsolve = New lpsolve55 lpsolve.Init(".") Demo() lpsolve = Nothing End Sub Private Function Demo() As Integer Dim lp As Integer Dim Ncol As Integer Dim colno() As Integer Dim j, ret As Short Dim row() As Double With lpsolve ' We will build the model row by row ' So we start with creating a model with 0 rows and 2 columns Ncol = 2 ' there are two variables in the model lp = .make_lp(0, Ncol) If lp = 0 Then ret = 1 ' couldn't construct a new model... End If If ret = 0 Then ' let us name our variables. Not required, but can be useful for debugging .set_col_name(lp, 1, "x") .set_col_name(lp, 2, "y") ' create space large enough for one row ReDim colno(Ncol - 1) ReDim row(Ncol - 1) End If If ret = 0 Then .set_add_rowmode(lp, True) ' makes building the model faster if it is done rows by row ' construct first row (120 x + 210 y <= 15000) j = 0 colno(j) = 1 ' first column row(j) = 120 j = j + 1 colno(j) = 2 ' second column row(j) = 210 j = j + 1 ' add the row to lpsolve If .add_constraintex(lp, j, row(0), colno(0), lpsolve55.lpsolve_constr_types.LE, 15000) = False Then ret = 3 End If End If If ret = 0 Then ' construct second row (110 x + 30 y <= 4000) j = 0 colno(j) = 1 ' first column row(j) = 110 j = j + 1 colno(j) = 2 ' second column row(j) = 30 j = j + 1 ' add the row to lpsolve If .add_constraintex(lp, j, row(0), colno(0), lpsolve55.lpsolve_constr_types.LE, 4000) = False Then ret = 3 End If End If If ret = 0 Then ' construct third row (x + y <= 75) j = 0 colno(j) = 1 ' first column row(j) = 1 j = j + 1 colno(j) = 2 ' second column row(j) = 1 j = j + 1 ' add the row to lpsolve If .add_constraintex(lp, j, row(0), colno(0), lpsolve55.lpsolve_constr_types.LE, 75) = False Then ret = 3 End If End If If ret = 0 Then .set_add_rowmode(lp, False) ' rowmode should be turned off again when done building the model ' set the objective function (143 x + 60 y) j = 0 colno(j) = 1 ' first column row(j) = 143 j = j + 1 colno(j) = 2 ' second column row(j) = 60 j = j + 1 ' set the objective in lpsolve If .set_obj_fnex(lp, j, row(0), colno(0)) = False Then ret = 4 End If End If If ret = 0 Then ' set the object direction to maximize .set_maxim(lp) ' just out of curioucity, now show the model in lp format on screen ' this only works if this is a console application. If not, use write_lp and a filename .write_lp(lp, "model.lp") ' I only want to see important messages on screen while solving .set_verbose(lp, 3) ' Now let lpsolve calculate a solution ret = .solve(lp) If ret = lpsolve55.lpsolve_return.OPTIMAL Then ret = 0 Else ret = 5 End If End If If ret = 0 Then ' a solution is calculated, now lets get some results ' objective value System.Diagnostics.Debug.WriteLine("Objective value: " & .get_objective(lp)) ' variable values .get_variables(lp, row(0)) For j = 1 To Ncol System.Diagnostics.Debug.WriteLine(.get_col_name(lp, j) & ": " & row(j - 1)) Next ' we are done now End If ' free allocated memory Erase row Erase colno If lp <> 0 Then ' clean up such that all used memory by lpsolve is freed .delete_lp(lp) End If Demo = ret End With End Function End Module
When this is run, the following is shown in the debug window:
Objective value: 6315.625 x: 21.875 y: 53.125
And a file model.lp is created with the following contents:
/* Objective function */ max: +143 x +60 y; /* Constraints */ +120 x +210 y <= 15000; +110 x +30 y <= 4000; +x +y <= 75;
Note that a class lpsolve55.vb is needed for this to work. The class is available via the VB.NET example.
Note that this example is very limited. It is also possible to set bounds on variables, ranges on constraints, define variables as integer, get more result information, changing solver options and parameters and much more. See lp_solve API reference for an overview of the API to do this.
The example model can be formulated as follows in C#.NET:
using System.Windows.Forms; using lpsolve55; /* demo.cs */ namespace demo { public class demo { public static void Main() { lpsolve.Init("."); Demo(); } private static int Demo() { int lp; int Ncol; int[] colno; int j, ret = 0; double[] row; /* We will build the model row by row */ /* So we start with creating a model with 0 rows and 2 columns */ Ncol = 2; /* there are two variables in the model */ lp = lpsolve.make_lp(0, Ncol); if (lp == 0) ret = 1; /* couldn't construct a new model... */ if (ret == 0) { /* let us name our variables. Not required, but can be useful for debugging */ lpsolve.set_col_name(lp, 1, "x"); lpsolve.set_col_name(lp, 2, "y"); } /* create space large enough for one row */ colno = new int[Ncol]; row = new double[Ncol]; if (ret == 0) { lpsolve.set_add_rowmode(lp, true); /* makes building the model faster if it is done rows by row */ /* construct first row (120 x + 210 y <= 15000) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 120; colno[j] = 2; /* second column */ row[j++] = 210; /* add the row to lpsolve */ if (lpsolve.add_constraintex(lp, j, ref row[0], ref colno[0], lpsolve.lpsolve_constr_types.LE, 15000) == false) ret = 3; } if (ret == 0) { /* construct second row (110 x + 30 y <= 4000) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 110; colno[j] = 2; /* second column */ row[j++] = 30; /* add the row to lpsolve */ if (lpsolve.add_constraintex(lp, j, ref row[0], ref colno[0], lpsolve.lpsolve_constr_types.LE, 4000) == false) ret = 3; } if (ret == 0) { /* construct third row (x + y <= 75) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 1; colno[j] = 2; /* second column */ row[j++] = 1; /* add the row to lpsolve */ if (lpsolve.add_constraintex(lp, j, ref row[0], ref colno[0], lpsolve.lpsolve_constr_types.LE, 75) == false) ret = 3; } if (ret == 0) { lpsolve.set_add_rowmode(lp, false); /* rowmode should be turned off again when done building the model */ /* set the objective function (143 x + 60 y) */ j = 0; colno[j] = 1; /* first column */ row[j++] = 143; colno[j] = 2; /* second column */ row[j++] = 60; /* set the objective in lpsolve */ if (lpsolve.set_obj_fnex(lp, j, ref row[0], ref colno[0]) == false) ret = 4; } if (ret == 0) { lpsolve.lpsolve_return s; /* set the object direction to maximize */ lpsolve.set_maxim(lp); /* just out of curioucity, now show the model in lp format on screen */ /* this only works if this is a console application. If not, use write_lp and a filename */ lpsolve.write_lp(lp, "model.lp"); /* I only want to see important messages on screen while solving */ lpsolve.set_verbose(lp, 3); /* Now let lpsolve calculate a solution */ s = lpsolve.solve(lp); if (s == lpsolve.lpsolve_return.OPTIMAL) ret = 0; else ret = 5; } if (ret == 0) { /* a solution is calculated, now lets get some results */ /* objective value */ System.Diagnostics.Debug.WriteLine("Objective value: " + lpsolve.get_objective(lp)); /* variable values */ lpsolve.get_variables(lp, ref row[0]); for(j = 0; j < Ncol; j++) System.Diagnostics.Debug.WriteLine(lpsolve.get_col_name(lp, j + 1) + ": " + row[j]); /* we are done now */ } /* free allocated memory */ if (lp != 0) { /* clean up such that all used memory by lpsolve is freed */ lpsolve.delete_lp(lp); } return(ret); } //Demo } }
When this is run, the following is shown in the debug window:
Objective value: 6315.625 x: 21.875 y: 53.125
And a file model.lp is created with the following contents:
/* Objective function */ max: +143 x +60 y; /* Constraints */ +120 x +210 y <= 15000; +110 x +30 y <= 4000; +x +y <= 75;
Note that a class lpsolve55.cs is needed for this to work. The class is available via the CS.NET example.
Note that this example is very limited. It is also possible to set bounds on variables, ranges on constraints, define variables as integer, get more result information, changing solver options and parameters and much more. See lp_solve API reference for an overview of the API to do this.