./000777 000000 000000 00000000000 13772706472 007404 5ustar00000000 000000 ./.DS_Store000666 000000 000000 00000116004 11203010516 011037 0ustar00000000 000000 Bud1``  0 ;t_lowb get_lowbo.htmIlocblobe is_debug.htmIlocblobprint_solution.htmIlocblob5 set_mat.htmIlocblobeput_bb_nodefunc.htmIlocblobZput_logfunc.htmIlocblobput_msgfunc.htmIlocblob Python.htmIlocblobZI  @ @ @ @3 set_maxim.htmIlocblobZset_maxpivot.htmIlocblob set_minim.htmIlocblobset_mip_gap.htmIlocblobZ set_negrange.htmIlocblob set_obj_bound.htmIlocblob set_obj_fn.htmIlocblobZ yset_obj_in_basis.htmIlocblob yset_output.htmIlocblob yset_pivoting.htmIlocblobZ set_preferdual.htmIlocblob set_presolve.htmIlocblob set_print_sol.htmIlocblobZ!1 set_rh.htmIlocblob!1set_rh_range.htmIlocblob!1set_rh_vec.htmIlocblobZ! set_row.htmIlocblob!set_row_name.htmIlocblob!set_scalelimit.htmIlocblobZ!set_scaling.htmIlocblob!set_semicont.htmIlocblob! set_sense.htmIlocblobZ"Eset_simplextype.htmIlocblob"Eset_solutionlimit.htmIlocblob"Eset_timeout.htmIlocblobZ" set_trace.htmIlocblob"set_unbounded.htmIlocblob" set_upbo.htmIlocblobZ"set_use_names.htmIlocblob"set_var_branch.htmIlocblob"set_var_weights.htmIlocblobZ#Yset_verbose.htmIlocblob#Y set_XLI.htmIlocblob#Ysimpletree.cssIlocblobZ#simpletreemenu.jsIlocblob# solve.htmIlocblob#SOS.htmIlocblobZ$!SpecialOrderedSetsOfTypeOne_filesIlocblob$!SpecialOrderedSetsOfTypeTwo_filesIlocblob$ Sysquake.htmIlocblobZ$mtime_elapsed.htmIlocblob$m unscale.htmIlocblob$mWin32IlocblobZ$write_basis.htmIlocblob$ write_lp.htmIlocblob$ write_mps.htmIlocblobZ%%write_params.htmIlocblob%% write_XLI.htmIlocblob%%XLI.htmIlocblobZ%Xpress-format.htmIlocblob% Zimpl.htmIlocblob%Fa.batIlocblobZ! absolute.htmIlocblob!add_column.htmIlocblob!add_constraint.htmIlocblobZ}add_lag_con.htmIlocblob} add_SOS.htmIlocblob}AMPL.htmIlocblobZarvIlocblobBAK.sqIlocblobBAK2.sqIlocblobZ5BAK3.sqIlocblob5bas-format.htmIlocblob5BFP.htmIlocblobZ Build.htmIlocblob BuildLog.htmIlocblob changes5.htmIlocblobZ changes55.htmIlocblob closed.gifIlocblobcolumn_in_lp.htmIlocblobZI contents.htmIlocblobI copy_lp.htmIlocblobICPLEX-format.htmIlocblobZdefault_basis.htmIlocblobdel_column.htmIlocblobdel_constraint.htmIlocblobZ delete_lp.htmIlocblobdimacs_asn.gifIlocblobDIMACS_asn.htmIlocblobZ]dimacs_maxf.gifIlocblob]DIMACS_maxf.htmIlocblob]dimacs_mcf.gifIlocblobZDIMACS_mcf.htmIlocblobdistribIlocblob distrib.batIlocblobZdistribution.htmIlocblob download.htmIlocblobdualize_lp.htmIlocblobZq Euler.htmIlocblobq Euler1.jpgIlocblobq Euler2.jpgIlocblobZ Euler3.jpgIlocblobFAQ.htmIlocblobfold.gifIlocblobZ) formulate.htmIlocblob)free.htmIlocblob) free_lp.htmIlocblobZ FreeMat.htmIlocblobgen.batIlocblobget_anti_degen.htmIlocblobZ get_basis.htmIlocblobget_basiscrash.htmIlocblobget_bb_depthlimit.htmIlocblobZ=get_bb_floorfirst.htmIlocblob=get_bb_rule.htmIlocblob=get_bounds_tighter.htmIlocblobZget_break_at_value.htmIlocblobget_col_name.htmIlocblobget_column.htmIlocblobZget_constr_type.htmIlocblobget_constr_value.htmIlocblobget_constraints.htmIlocblobZQ get_epsb.htmIlocblobQ get_epsd.htmIlocblobQ get_epsel.htmIlocblobZget_epsint.htmIlocblobget_epsperturb.htmIlocblobget_epspivot.htmIlocblobZ get_improve.htmIlocblob get_infinite.htmIlocblob get_lambda.htmIlocblobZe>get_lp_index.htmIlocblobeget_lp_name.htmIlocblobZ get_Lrows.htmIlocblob get_mat.htmIlocblobget_max_level.htmIlocblobZ get_maxpivot.htmIlocblob get_mip_gap.htmIlocblob get_nameindex.htmIlocblobZ yget_Ncolumns.htmIlocblob yget_negrange.htmIlocblob yget_nonzeros.htmIlocblobZ get_Norig_columns.htmIlocblob get_Norig_rows.htmIlocblob get_Nrows.htmIlocblobZ 1get_obj_bound.htmIlocblob 1get_objective.htmIlocblob 1get_orig_index.htmIlocblobZ get_pivoting.htmIlocblob get_presolve.htmIlocblob get_presolveloops.htmIlocblobZ get_primal_solution.htmIlocblob get_print_sol.htmIlocblob get_rh.htmIlocblobZ Eget_rh_range.htmIlocblob E get_row.htmIlocblob Eget_row_name.htmIlocblobZ get_scalelimit.htmIlocblob get_scaling.htmIlocblob get_sensitivity_obj.htmIlocblobZ get_sensitivity_rhs.htmIlocblob get_simplextype.htmIlocblob get_solutioncount.htmIlocblobZ Yget_solutionlimit.htmIlocblob Yget_status.htmIlocblob Yget_statustext.htmIlocblobZ get_timeout.htmIlocblob get_total_iter.htmIlocblob get_total_nodes.htmIlocblobZ  get_upbo.htmIlocblob get_var_branch.htmIlocblob get_var_priority.htmIlocblobZ mget_variables.htmIlocblob mget_verbose.htmIlocblob mget_working_objective.htmIlocblobZ guess_basis.htmIlocblob has_BFP.htmIlocblob has_XLI.htmIlocblobZ%HTMLHelp.vcprojIlocblob%'HTMLHelp.vcproj.penohomevista.peno.userIlocblob%$HTMLHelp.vcproj.PENOHOMEXP.peno.userIlocblobZIDEIlocblobIDE.htmIlocblob index.htmIlocblobZ index.htmlIlocblobInfeasible.htmIlocblob integer.htmIlocblobZ9 Intro.htmIlocblob9is_add_rowmode.htmIlocblob9is_anti_degen.htmIlocblobZ is_binary.htmIlocblobis_break_at_first.htmIlocblobis_constr_type.htmIlocblobZda.htmIlocblobZeDis_feasible.htmIlocblobis_infinite.htmIlocblobZM is_int.htmIlocblobMis_integerscaling.htmIlocblobMis_lag_trace.htmIlocblobZ is_maxim.htmIlocblobis_nativeBFP.htmIlocblobis_nativeXLI.htmIlocblobZis_negative.htmIlocblobis_obj_in_basis.htmIlocblobis_piv_mode.htmIlocblobZais_piv_rule.htmIlocblobais_presolve.htmIlocblobais_scalemode.htmIlocblobZis_scaletype.htmIlocblobis_semicont.htmIlocblobis_SOS_var.htmIlocblobZ is_trace.htmIlocblobis_unbounded.htmIlocblobis_use_names.htmIlocblobZuJavaIlocblobuJava.htmIlocblobu lag_solve.htmIlocblobZLGPL.htmIlocblobLINDO-format.htmIlocblob links.htmIlocblobZ-list.gifIlocblob- lp-format.htmIlocblob- lp_solve.hhcIlocblobZ lp_solve.hhkIlocblob lp_solve.hhpIlocblob lp_solve.htmIlocblobZlp_solve_5.5.0.12.chwIlocbloblp_solve_5.5.0.13.chwIlocbloblp_solve_5.5.0.14.chmIlocblobZAlp_solve_5.5.0.14.chwIlocblobAlp_solve_5.5_doc.tar.gzIlocblobAlp_solve_version.htmIlocblobZlp_solveAPIreference.htmIlocblob LPBasics.htmIlocblob make_lp.htmIlocblobZman.ncbIlocblobman.slnIlocblobman.suoIlocblobZU MathProg.htmIlocblobU MATLAB.htmIlocblobU MATLAB1.jpgIlocblobZ MATLAB2.jpgIlocblob MATLAB3.jpgIlocblobmps-format.htmIlocblobZ O-Matrix.htmIlocblob O-Matrix1.jpgIlocblob O-Matrix2.jpgIlocblobZi O-Matrix3.jpgIlocblobi Octave.htmIlocblobi Octave1.jpgIlocblobZ Octave2.jpgIlocblob Octave3.jpgIlocblobopen.gifIlocblobZ!pe.cfgIlocblob!PHP.htmIlocblob! Presolve.htmIlocblobZ}print_constraints.htmIlocblob}print_debugdump.htmIlocblob}print_duals.htmIlocblobZ print_lp.htmIlocblobprint_objective.htmIlocblobprint_scales.htmIlocblobZ5da.htmIlocblobZe< print_str.htmIlocblob5print_tableau.htmIlocblobZput_abortfunc.htmIlocblobput_bb_branchfunc.htmIlocblobput_bb_nodefunc.htmIlocblobZput_logfunc.htmIlocblobput_msgfunc.htmIlocblob Python.htmIlocblobZIquickstart.htmIlocblobIR.htmIlocblobI ratio.htmIlocblobZread_basis.htmIlocblob read_lp.htmIlocblob read_mps.htmIlocblobZread_params.htmIlocblob read_XLI.htmIlocblobreset_basis.htmIlocblobZ]reset_params.htmIlocblob] resize_lp.htmIlocblob]Sage.htmIlocblobZ scaling.htmIlocblob Scilab.htmIlocblob Scilab1.jpgIlocblobZ Scilab2.jpgIlocblob Scilab3.jpgIlocblob search.htmIlocblobZq semi-cont.htmIlocblobqSemi-ContinuousVariables_filesIlocblobqsensitivity.htmIlocblobZset_add_rowmode.htmIlocblobset_anti_degen.htmIlocblob set_basis.htmIlocblobZ)set_basiscrash.htmIlocblob)set_basisvar.htmIlocblob)set_bb_depthlimit.htmIlocblobZset_bb_floorfirst.htmIlocblobset_bb_rule.htmIlocblob set_BFP.htmIlocblobZset_binary.htmIlocblobset_bounds.htmIlocblobset_bounds_tighter.htmIlocblobZ=set_break_at_first.htmIlocblob=set_break_at_value.htmIlocblob=set_col_name.htmIlocblobZset_column.htmIlocblobset_constr_type.htmIlocblob set_debug.htmIlocblobZ set_epsb.htmIlocblob set_epsd.htmIlocblob set_epsel.htmIlocblobZQset_epsint.htmIlocblobQset_epslevel.htmIlocblobQset_epsperturb.htmIlocblobZset_epspivot.htmIlocblobset_improve.htmIlocblobset_infinite.htmIlocblobZ set_int.htmIlocblob set_lag_trace.htmIlocblob set_lowbo.htmIlocblobZeset_lp_name.htmIlocblobeprint_debugdump.htmIlocblob}print_duals.htmIlocblobZ print_lp.htmIlocblobprint_objective.htmIlocblobprint_scales.htmIlocblobZ5da.htmIlocblobZe` E  0 @ P DSDB `hp @ @locblob Scilab1.jpgIlocblobZ Scilab2.jpgIlocblob Scilab3.jpgIlocblob search.htmIlocblobZq semi-cont.htmIlocblobqSemi-ContinuousVariables_filesIlocblobqsensitivity.htmIlocblobZset_add_rowmode.htmIlocblobset_anti_degen.htmIlocblob set_basis.htmIlocblobZ)set_basiscrash.htmIlocblob)set_basisvar.htmIlocblob)./absolute.htm000666 000000 000000 00000037265 10555651642 011743 0ustar00000000 000000 Absolute values

Absolute values

Constraints

Linear constraints are of the form:

a1 x1 + a2 x2 + a3 x3 + ... <= maximum
a1 x1 + a2 x2 + a3 x3 + ... >= minimum

Where minimum and maximum are constants.

lp_solve can only handle these kind of Linear equations. So what if absolute values must be formulated:

abs(a1 x1 + a2 x2 + a3 x3) = 0
abs(a1 x1 + a2 x2 + a3 x3) <= maximum
abs(a1 x1 + a2 x2 + a3 x3) >= minimum

= 0 (or <= 0)

This is the easiest case. If abs(X) must be equal to zero, then this can only be fulfilled if X is zero. So the condition can also be written as:

a1 x1 + a2 x2 + a3 x3 = 0

<= maximum

This is a bit more complicated, but still quite easy.

Let's first represent a1 x1 + a2 x2 + a3 x3 by X. So the condition becomes:

abs(X) <= maximum

What is in fact abs(X) ?

It is X if X is positive or 0 and it is -X if X is negative.

This also implies that maximum is always bigger than or equal to zero. Else the constraint would always be impossible (mathematical impossible with real numbers).

The geometric representation of this is:

----+===============+----
-maximum    0    +maximum

The section between -maximum and +maximum fulfils the constraint.

So if X is positive, the restriction becomes:

 X <= maximum

If X is negative, the restriction becomes:

-X <= maximum

And the fortunate thing is that if we need the one restriction that the other is always redundant. If X is positive, then -X is negative and thus always less than maximum (which is always positive, remember) and thus the second equation is then redundant. If X is negative, then it is always less than maximum (which is always positive, remember) and thus the first equation is then redundant. This can also be seen easily from the graphical representation. So just add the following two equations:

 X <= maximum
-X <= maximum

And the abs(X) <= maximum condition is fulfilled.

And what if the condition is

abs(X) + Y <= maximum

With Y any linear combination.

It is easy to see that the same reasoning can be used to become:

 X + Y <= maximum
-X + Y <= maximum

With the original definition of X this becomes:

 a1 x1 + a2 x2 + a3 x3 + Y <= maximum
-a1 x1 - a2 x2 - a3 x3 + Y <= maximum
Special case 1
abs(x1) + abs(x2) + ... <= maximum;
First consider each abs(xi) value. From above, consider the following:
xiabs >= xi;
xiabs >= -xi;
This makes xiabs >= abs(xi)
Greater than or equal, but as is, not for sure equal.
However, in combination with other constraints, this can become equal. If following constraint is added, and when active, then each xiabs will represent the absolute value of xi:
x1abs + x2abs + ... <= maximum;
So, for each abs(xi) variable in the constraint, add a new variable xiabs and add two extra constraints for it. Then replace abs(xi) by xiabs in the constraint and the condition is fulfilled.
Note that the objective may be minimization or maximization, it doesn't matter.
Note that the variables may have an extra coefficient, but not negative! If the sign would be negative, then xiabs will not have the intention to become as small as possible, but as large as possible and the result would be that xiabs would not be equal to abs(xi). It could become larger.

Example:
max: x1 + 2x2 - 4x3 -3x4;
x1 + x2 <= 5;
2x1 - x2 >= 0;
-x1 + 3x2 >= 0;
x3 + x4 >= .5;
x3 >= 1.1;
x3 <= 10;

abs(x2) + abs(x4) <= 1.5; /* Note that this is not a valid expression. It will be converted. */

free x2, x4;
The converted model becomes:
max: x1 + 2x2 - 4x3 -3x4;
x1 + x2 <= 5;
2x1 - x2 >= 0;
-x1 + 3x2 >= 0;
x3 + x4 >= .5;
x3 >= 1.1;
x3 <= 10;

x2abs >= x2;
x2abs >= -x2;

x4abs >= x4;
x4abs >= -x4;

x2abs + x4abs <= 1.5;

free x2, x4;
The result is:
Value of objective function: 2.6

Actual values of the variables:
x1                           3.75
x2                           1.25
x3                            1.1
x4                          -0.25
x2abs                        1.25
x4abs                        0.25

>= minimum

Let's first represent a1 x1 + a2 x2 + a3 x3 by X. So the condition becomes:

abs(X) >= minimum

What is in fact abs(X) ?

It is X if X is positive or 0 and it is -X if X is negative.

This also implies that minimum should always be bigger than zero. Else the constraint would always be fulfilled and there is no point in having the constraint.

The geometric representation of this is:

====+---------------+====
-minimum    0    +minimum

The section not between -minimum and +minimum fulfils the constraint.

So if X is positive, the restriction becomes:

 X >= minimum

If X is negative, the restriction becomes:

-X >= minimum

Unfortunately, the trick as for a maximum cannot be used here. If X is positive, then -X is not greater than minimum, in contrary ...

It can also be seen from the graphical representation that this restriction is discontinue. This has as effect that it is not possible to convert this into a set of linear equations.

A possible approach to overcome this is making use of integer variables. In particular by using a binary variable B:

 X + M * B >= minimum
-X + M * (1 - B) >= minimum

M is a large enough constant. See later.
The binary variable B takes care of the discontinuity. It can be either 0 or 1. With M large enough, this makes one or the other constraint obsolete.

If B is 0, then the equations can be written as:

 X >= minimum
-X + M >= minimum

So in this case, the restriction X >= minimum is active. X must be positive and larger than minimum. With M large enough, the second constraint is always fulfilled.

If B is 1, then the equations can be written as:

 X + M >= minimum
-X >= minimum

So in this case, the restriction -X >= minimum is active. X must be negative and -X be larger than minimum. With M large enough, the first constraint is always fulfilled.

It is important to use a realistic value for M. Don't use for example 1e30 for it. This creates numerical instabilities and even if not then tolerances will give problem. Because of tolerances, B may not be zero, but actually for example 1e-20. This multiplied with 1e30 gives not zero, but 1e10! This results in X + 1e10 >= minimum instead of X >= minimum. Not what was mathematically formulated!

So how big must M be?
Well, we can make a prediction.
Either -X + M >= minimum (X >= minimum) or X + M >= minimum (X <= -minimum) must always be TRUE.
That comes to -abs(X) + M >= minimum.
Or M >= minimum + abs(X)

If we can predict how large X can become (absolutely), then we can predict a maximum value needed for M for this to work. If abs(X) cannot be larger than maximum, then M can be minimum+maximum.

In most cases, it is possible to determine a reasonable upper bound for X.

In lp-format, the needed equations are:

X + M * B >= minimum;
X + M * B <= M - minimum;

B <= 1;

int B;

And what if the condition is

abs(X) + Y >= minimum

With Y any linear combination.

It is easy to see that the same reasoning can be used to become:

 X + M * B + Y >= minimum
-X + M * (1 - B) + Y >= minimum

With M >= minimum - Y + abs(X)

In lp-format:

X + M * B + Y >= minimum;
X + M * B - Y <= M - minimum

B <= 1;

int B;

Objective function

The objective function is of the form:

min or max: a1 x1 + a2 x2 + a3 x3 + ...

What if there is an absolute value in the objective:

abs(a1 x1 + a2 x2 + a3 x3) + a4 x4 + a5 x5

Let's first represent a1 x1 + a2 x2 + a3 x3 by X and a4 x4 + a5 x5 by Y. Then the objective becomes:

abs(X) + Y

Depending on the sign before the abs and the objective direction, there is an easy and a harder way to solve this.

minimization and sign is positive or maximization and sign is negative.

min: abs(X) + Y
or
max: -abs(X) + Y

In these two situations, abs(X) will be as small as possible, ideally zero. We can use that fact. Add one variable X' and two constraints to the model:

 X <= X'
-X <= X'

And replace in the objective abs(X) with X':

min: X' + Y
or
max: -X' + Y

That is all. So how does this work? There are 3 cases to consider:

X > 0

In this case, -X is negative and the second constraint -X <= X' is always fulfilled because X' is implicitly >= 0. The first constraint X <= X' is however different. Because X is positive, X' must be at least as large as X. But because X' is in the objective in such a way that is tends to be as small as possible, X' will be equal to X. So X' is abs(X) in this case.

X < 0

In this case, X is negative and the first constraint X <= X' is always fulfilled because X' is implicitly >= 0. The second constraint -X <= X' is however different. Because X is negative (-X positive), X' must be at least as large as -X. But because X' is in the objective in such a way that is tends to be as small as possible, X' will be equal to -X. So X' is abs(X) in this case.

X = 0

In this case, both constraints are always fulfilled because X' is implicitly >= 0. Because X' is in the objective in such a way that is tends to be as small as possible, X' will be equal to X, in this case 0. So X' is abs(X).

So in all cases, X' equals abs(X)

With the original definition of X and Y this becomes:

min: X' + a4 x4 + a5 x5
or
max: -X' + a4 x4 + a5 x5

 a1 x1 + a2 x2 + a3 x3 <= X'
-a1 x1 - a2 x2 - a3 x3 <= X'

minimization and sign is negative or maximization and sign is positive.

min: -abs(X) + Y
or
max: abs(X) + Y

This is a different story. abs(X) now tends to be as large as possible. So the previous trick cannot be used now.

A possible approach to overcome this is making use of integer variables. In particular by using a binary variable B and adding a variable X'. Add following constraints to the model:

 X + M * B >= X'
-X + M * (1 - B) >= X'
 X <= X'
-X <= X'

And replace in the objective abs(X) with X':

min: -X' + Y
or
max: X' + Y

That is all. So how does this work? In fact this is a combination of a maximum and minimum constraint on an absolute expression. X' represents the absolute expression and is used in the objective.

M is a large enough constant. See later.
The binary variable B can be either 0 or 1. With M large enough, this makes one or the other constraint obsolete.

If B is 0, then the equations can be written as:

 X >= X'
-X + M >= X'
 X <= X'
-X <= X'

So in this case, the restriction X >= X' is active. X must be positive and larger than X'. With M large enough, the second constraint is always fulfilled. The third constraint says that X <= X'. The forth constraint is always fulfilled. In fact the first and third constraint have as result that X' equals X, which is positive in this case.

If B is 1, then the equations can be written as:

 X + M >= X'
-X >= X'
 X <= X'
-X <= X'

So in this case, the restriction -X >= X' is active. X must be negative and -X be larger than X'. With M large enough, the first constraint is always fulfilled. The third constraint is always fulfilled. The forth constraint says that -X < X'. In fact the second and forth constraint have as result that X' equals -X, which is positive in this case.

It is important to use a realistic value for M. Don't use for example 1e30 for it. This creates numerical instabilities and even if not then tolerances will give problem. Because of tolerances, B may not be zero, but actually for example 1e-20. This multiplied with 1e30 gives not zero, but 1e10! This results in X + 1e10 >= X' instead of X >= X'. Not what was mathematically formulated!

So how big must M be?
Well, we can make a prediction.
Either -X + M >= X' (X >= X') or X + M >= X' (X <= -X') must always be TRUE.
That comes to -abs(X) + M >= X'.
or -abs(X) + M >= abs(X).
Or M >= 2 * abs(X)

If we can predict how large X can become (absolutely), then we can predict a maximum value needed for M for this to work. If abs(X) cannot be larger than maximum, then M can be 2 * maximum.

In most cases, it is possible to determine a reasonable upper bound for X.

In lp-format, the needed equations are:

max: X' + Y;

 X + M * B - X' >= 0;
 X + M * B + X' <= M;
 X <= X'
-X <= X'

B <= 1;

int B;
./add_column.htm000666 000000 000000 00000013454 10351225350 012207 0ustar00000000 000000 add_column, add_columnex, str_add_column

add_column, add_columnex, str_add_column

Add a column to the lp.

unsigned char add_column(lprec *lp, REAL *column);

unsigned char add_columnex(lprec *lp, int count, REAL *column, int *rowno);

unsigned char str_add_column(lprec *lp, char *col_string);

Return Value

add_column, add_columnex, and str_add_column return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

count

Number of elements in column and rowno.

column

An array with 1+get_Nrows (count for add_columnex, if rowno is different from NULL) elements that contains the values of the column.

rowno

A zero-based array with count elements that contains the row numbers of the column. However this variable can also be NULL. In that case element i in the variable column is row i.

col_string

A string with row elements that contains the values of the column. Each element must be separated by space(s).

Remarks

The add_column, add_columnex, str_add_column functions add a column to the model (at the end) and sets all values of the column at once.

Note that for add_column (and add_columnex when rowno is NULL) element 0 of the array is the value of the objective function for that column. Column 1 is element 1, column 2 is element 2, ...

str_add_column should only be used in small or demo code since it is not performant and uses more memory.

add_columnex has the possibility to specify only the non-zero elements. In that case rowno specifies the row numbers of the non-zero elements. Both column and rowno are then zero-based arrays. This will speed up building the model considerably if there are a lot of zero values. In most cases the matrix is sparse and has many zero value. Note that add_columnex behaves the same as add_column when rowno is NULL.
For add_columnex, column and rowno can both be NULL. In that case an empty column is added.

Thus it is almost always better to use add_columnex instead of add_column. add_columnex is always at least as performant as add_column.

Note that if you have to add many columns, performance can be improved by a call to resize_lp.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL column[1+3];     /* must be 1 more than number of rows ! */
  REAL sparsecolumn[3]; /* must be the number of non-zero values */
  int rowno[3];

  /* Create a new LP model */
  lp = make_lp(3, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  column[0] = 1.0; /* the objective value */
  column[1] = 2.0;
  column[2] = 0.0;
  column[3] = 3.0;
  add_column(lp, column);
  
  rowno[0] = 0; sparsecolumn[0] = 1.0; /* the objective value */
  rowno[1] = 1; sparsecolumn[1] = 2.0;
  rowno[2] = 3; sparsecolumn[2] = 3.0;
  add_columnex(lp, 3, sparsecolumn, rowno);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, set_column, set_columnex, del_column, set_add_rowmode, is_add_rowmode, resize_lp, add_constraint, add_constraintex, str_add_constraint, set_row, set_rowex, get_column, get_columnex, get_row, get_rowex, get_mat, column_in_lp

./add_constraint.htm000666 000000 000000 00000016237 10351225302 013075 0ustar00000000 000000 add_constraint, add_constraintex, str_add_constraint

add_constraint, add_constraintex, str_add_constraint

Add a constraint to the lp.

unsigned char add_constraint(lprec *lp, REAL *row, int constr_type, REAL rh);

unsigned char add_constraintex(lprec *lp, int count, REAL *row, int *colno, int constr_type, REAL rh);

unsigned char str_add_constraint(lprec *lp, char *row_string, int constr_type, REAL rh);

Return Value

add_constraint, add_constraintex and str_add_constraint return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

count

Number of elements in row and colno.

row

An array with 1+get_Ncolumns (count for add_constraintex, if colno is different from NULL) elements that contains the values of the row.

colno

A zero-based array with count elements that contains the column numbers of the row. However this variable can also be NULL. In that case element i in the variable row is column i and values start at element 1.

row_string

A string with column elements that contains the values of the row. Each element must be separated by space(s).

constr_type

The type of the constraint. Can by any of the following values:

LE (1) Less than or equal (<=)
EQ (3) Equal (=)
GE (2) Greater than or equal (>=)

rh

The value of the right hand side (RHS).

Remarks

The add_constraint, add_constraintex, str_add_constraint functions add a row to the model (at the end) and sets all values of the row at once.

Note that for add_constraint (and add_constraintex when colno is NULL) element 0 of the array is not considered (i.e. ignored). Column 1 is element 1, column 2 is element 2, ...

str_add_constraint should only be used in small or demo code since it is not performant and uses more memory.

add_constraintex has the possibility to specify only the non-zero elements. In that case colno specifies the column numbers of the non-zero elements. Both row and colno are then zero-based arrays. This will speed up building the model considerably if there are a lot of zero values. In most cases the matrix is sparse and has many zero value.
Note that add_constraintex behaves the same as add_constraint when colno is NULL.

Thus it is almost always better to use add_constraintex instead of add_constraint. add_constraintex is always at least as performant as add_constraint.

Note that it is advised to set the objective function (via set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj) before adding rows. This especially for larger models. This will be much more performant than adding the objective function afterwards.

Note that these routines will perform much better when set_add_rowmode is called before adding constraints.

Note that if you have to add many constraints, performance can be improved by a call to resize_lp.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL row[1+3];     /* must be 1 more than number of columns ! */
  REAL sparserow[2]; /* must be the number of non-zero values */
  int colno[2];

  /* Create a new LP model */
  lp = make_lp(0, 3);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_add_rowmode(lp, TRUE);

  row[1] = 1.0;
  row[2] = 0.0; /* also zero elements must be provided */
  row[3] = 2.0;
  add_constraint(lp, row, GE, 3.0); /* constructs the row: +v_1 +2 v_3 >= 3 */

  colno[0] = 1; sparserow[0] = 1.0; /* column 1 */
  colno[1] = 3; sparserow[1] = 2.0; /* column 3 */
  add_constraintex(lp, 2, sparserow, colno, GE, 3.0); /* constructs the row: +v_1 +2 v_3 >= 3 */

  set_add_rowmode(lp, FALSE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_row, set_rowex, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, set_add_rowmode, is_add_rowmode, resize_lp, get_constr_type, is_constr_type, del_constraint, add_column, add_columnex, str_add_column, set_column, set_columnex, get_column, get_columnex, get_row, get_rowex, get_mat

./add_lag_con.htm000666 000000 000000 00000010756 11022427726 012325 0ustar00000000 000000 add_lag_con, str_add_lag_con

add_lag_con, str_add_lag_con

Add a Lagrangian constraint to the lp.

The Lagrangian solver does not work. Do not use this call.

unsigned char add_lag_con(lprec *lp, REAL *row, int con_type, REAL rhs);

unsigned char str_add_lag_con(lprec *lp, char *row_string, int con_type, REAL rhs);

Return Value

add_lag_con and str_add_lag_con returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

An array with column elements that contains the values of the row.

row_string

A string with column elements that contains the values of the row. Each element must be separated by space(s).

con_type

The type of the constraint. Can by any of the following values:

LE (1) Less than or equal (<=)
EQ (3) Equal (=)
GE (2) Greater than or equal (>=)

rhs

The value of the right hand side (RHS).

Remarks

The Lagrangian solver does not work. Do not use this call.

The add_lag_con, str_add_lag_con functions adds a Lagrangian row to the model (at the end) and sets all values of the row at once.
Note that element 0 of the array is not considered (i.e. ignored). Column 1 is element 1, column 2 is element 2, ...

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL row[1+2]; /* must be 1 more then number of columns ! */

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  row[1] = 1.0;
  row[2] = 1.0;
  add_lag_con(lp, row, LE, 1.0); /* constructs the Lagrangian row: +v_1 +v_2 <= 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_constraint, add_constraintex, str_add_constraint, set_row, set_rowex, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, get_constr_type, del_constraint, add_column, add_columnex, str_add_column, set_column, set_columnex, get_column, get_columnex, get_row, get_rowex, get_mat, lag_solve, get_Lrows

./add_SOS.htm000666 000000 000000 00000006333 10237106452 011360 0ustar00000000 000000 add_SOS

add_SOS

Add a SOS (Special Ordered Sets) constraint.

int add_SOS(lprec *lp, char *name, int sostype, int priority, int count, int *sosvars, REAL *weights);

Return Value

add_SOS returns the list index of the new SOS if the operation was successful. A return value of 0 indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

name

The name of the SOS constraint.

sostype

The type of the SOS constraint. Must be >= 1

priority

Priority of the SOS constraint in the SOS set.

count

The number of variables in the SOS list.

sosvars

An array specifying the count variables (their column numbers).

weights

An array specifying the count variable weights. May also be NULL. In that case, lp_solve will weight the variables in the order they are specified.

Remarks

The add_SOS function adds an SOS constraint.
See Special Ordered Sets for a description about SOS variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int vars[2];
  double weights[2];

  /* Create a new LP model */
  lp = make_lp(0, 4);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  vars[0] = 2; vars[1] = 3;
  weights[0] = 1.0; weights[1] = 2.0;
  add_SOS(lp, "SOS", 1, 1, sizeof(vars)/sizeof(*vars), vars, weights);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_SOS_var

./AMPL.htm000666 000000 000000 00000057642 13772705350 010657 0ustar00000000 000000 Using lpsolve from AMPL

Using lpsolve from AMPL

AMPL?

AMPL (A Mathematical Programming Language) is a high-level language for describing mathematical programs. AMPL allows a mathematical programming model to be specified independently of the data used for a specific instance of the model. AMPL's language for describing mathematical programs closely follows that used by humans to describe mathematical programs to each other. For this reason, modellers may spend more time improving the model and less time on the tedious details of data manipulation and problem solution.
To start, AMPL needs a mathematical programming model, which describes variables, objectives and relationships without referring to specific data. AMPL also needs an instance of the data, or a particular data set. The model and one (or more) data files are fed into the AMPL program. AMPL works like a compiler: the model and input are put into an intermediate file that can be read by a solver. The solver actually finds an optimal solution to the problem by reading in the intermediate file produced by AMPL and applying an appropriate algorithm. The solver outputs the solution as a text file, which can be viewed directly and cross-referenced with the variables and constraints specified in the model file.

We will not discuss the specifics of AMPL here but instead refer the reader to AMPL (A Mathematical Programming Language) at the University of Michigan Documentation and the AMPL website http://www.ampl.com.

AMPL and lpsolve

One of the possible solvers that can be used by AMPL is lpsolve. However note that AMPL allows also defining non-linear models. These are not solvable by lpsolve because lpsolve can only handle MILP models. A message will be given if the AMPL model results in a model that cannot be handled by lpsolve.

To make this possible, a driver program is needed: lpsolve(.exe). This program must be put in the AMPL directory and AMPL can call the lpsolve solver. The newer versions of the lpsolve(.exe) driver call lpsolve via the shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux). This has the advantage that the lpsolve driver program doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the path. That is all.

Solve a model from AMPL via lpsolve

In the following text, ampl: before the AMPL commands is the AMPL prompt. Only the text after the : must be entered.

To select the lpsolve solver, the following command must be executed in AMPL:

ampl: option solver lpsolve;

To solve the model, the following command must be executed in AMPL:

ampl: solve;

Options can be passed to lpsolve. For example to enable scaling, the following command must be executed in AMPL:

ampl: option lpsolve_options 'scale';

Multiple options can be specified by separating them with at least one space:

ampl: option lpsolve_options 'scale scalemode=7 verbose';

A list of all options is given at the end of this document.

An example

ampl: model diet.mod;
ampl: data diet.dat;
ampl: option solver lpsolve;
ampl: option lpsolve_options 'scale scalemode=7';
ampl: solve;

This gives as result:

LP_SOLVE 5.5.2.11: scale
scalemode=7
LP_SOLVE 5.5.2.11: optimal, objective 88.2
1 simplex iterations

solve_result_num

AMPL has a parameter that is used to indicate the outcome of the optimisation process. It is used as follows

ampl: display solve_result_num

solve_result_num can take the values shown in following table which also presents a short explanation for each value.

Interpretation of solve_result_num.
Value Message
0 the solution is optimal
100 suboptimal solution
200 infeasible problem
300 unbounded problem
500 solution status is unknown
501 failure
502 integer programming failure

Restart

This is also new with version 5. Before, when lpsolve was used from AMPL, the model was each time completely resolved at each AMPL solve command. The last base was not used to do further iterations. This is specific to AMPL because lpsolve is called as a seperate program each time a solve is done and to make restart possible the last base must be provided again to lpsolve to start from there again. From version 5 on this is now implemented by default. This means if a solve is done immediately after a previous solve that no iterations are needed and the solution can be given immediately. This can be shown via an example:
ampl: model diet.mod;
ampl: data diet.dat;
ampl: option solver lpsolve;
ampl: solve;

This gives as result:

LP_SOLVE 5.5.2.11: optimal, objective 88.2
3 simplex iterations

Note that 3 iterations were needed to solve the model. Now solve the model again:

ampl: solve;

This gives as result:

LP_SOLVE 5.5.2.11: optimal, objective 88.2
0 simplex iterations

Note now that no iterations are needed to solve the model. This because the result of the previous solve is used as a starting point for the new solve. It is even allowed to add or deleted variables and constraints in the model, lpsolve will still try to start from the last result to continue.

If, for some reason, you don't want this and let lpsolve resolve the model from scratch, there are two possibilities to let lpsolve ignore the starting base. Either via an lpsolve option or an AMPL option.

The lpsolve option that can be set is:

ampl: option lpsolve_options 'coldstart';

The AMPL option that can be set is:

ampl: option send_statuses 0;

One of both is enough.

Now solve the model again:
ampl: solve;

This gives as result:

LP_SOLVE 5.5.2.11: coldstart
LP_SOLVE 5.5.2.11: optimal, objective 88.2
3 simplex iterations

Note that again 3 iterations are needed to solve the model.

Special considerations for integer models. From the moment that a model contains integer variables, the B&B algorithm must be used to solve this. This algorithm must go trough a tree of possible solutions each time a solve is done. The last base of the best integer solution can not be used as a starting base for a resolve. This is not an lpsolve limitation, but a B&B algorithm property...
For this reason, by default, AMPL doesn't provide a starting to the solver and solve is done from scratch. By default... However, a compromise can be implemented by the solver. And this is also done in lpsolve. Solving integer models is always started with solving the non-integer model. When this is done, the non-integer variables are made integer via the B&B algorithm. lpsolve returns the base of the non-integer model and this base is used as a starting base for the model at the next solve. As said, this is a compromise because it results in a fast solve of the non-integer model, but the B&B algorithm must still be executed. So even if no modifications are done to the model and solve is done again, there will be iterations needed by the B&B algorithm to solve the integers. Because this must be explicitly implemented in the solver, AMPL doesn't provide the starting base by default for integer models. It must explicitly be activated:

ampl: option send_statuses 2;

Only then, lpsolve will get a starting base when there are integers.

Example:

ampl: model multmip3.mod;
ampl: data multmip3.dat;
ampl: option solver lpsolve;
ampl: solve;

This gives as result:

LP_SOLVE 5.5.2.11: optimal, objective 235625
1986 simplex iterations
592 branch & bound nodes: depth 21

Note that 1986 iterations were needed to solve the model. Now solve the model again:

ampl: solve;

This gives as result:

LP_SOLVE 5.5.2.11: optimal, objective 235625
1986 simplex iterations
592 branch & bound nodes: depth 21

The same as above. So no restart was done. Now activate the starting base for integer models and solve again:

ampl: option send_statuses 2;
ampl: solve;

This gives as result:

LP_SOLVE 5.5.2.11: optimal, objective 235625
1922 simplex iterations
592 branch & bound nodes: depth 21

Note that less iterations are needed, but not 0 as in non-integer models. These are the iterations needed for the B&B algorithm.

lpsolve options

lpsolve accepts a lot of options. Some options are just on/off switches and for there you just specify the option keyword (for example scale). Other options need a value and this is specified by an equal (=) sign after the option keyword and then the value (for example scalemode=7). Multiple options can be specified by separating them by a space (for example scale scalemode=7).

These options can be displayed from the command line by entering the following:

lpsolve -=

Here is a list of the possible lpsolve options:

bb=...           branch-and-bound rule: one of
  		    0 (default) for lowest indexed non-integer variable
  		    1 for selection based on distance from the current bounds
  		    2 for selection based on the largest current bound
  		    3 for selection based on largest fractional value
  		    4 for simple, unweighted pseudo-cost of a variable
  		    5 this is an extended pseudo-costing strategy based on
                      minimizing the number of integer infeasibilities
  		    6 this is an extended pseudo-costing strategy based on
                      maximizing the normal pseudo-cost divided by the
                      number of infeasibilities
  	       plus
  		    8 for weight reverse mode
                   16 when cauto is used, select the oposite direction that
                      autoselect had chosen
  		   32 for greedy mode
  		   64 for pseudo cost mode
  		  128 select the node that has already been selected before
                      the most number of times
  		  256 for randomize mode
  		 1024 when mode 128 is selected, switch off this mode when
                      a first solution is found
  		 2048 for restart mode
  		 4096 select the node that has been selected before the
                      fewest number of times or not at all
bfp=...          set basis factorization package
cauto            in IPs, algorithm decides which branch being taken first
cfirst           in IPs, take ceiling branch first
coldstart        ignore starting base
crash=...        determines a starting base: one of
  		    0 (default) none
  		    2 most feasible basis
debug            debug mode
degen            perturb degeneracies
degenx=...       anti-degen handling: one of
  		    0 (default) no anti-degeneracy handling
  		    1 check if there are equality slacks in the basis and
                      try to drive them out in order to reduce chance of
                      degeneracy in Phase 1
                    2 ColumnCheck
                    4 Stalling
                    8 NumFailure
                   16 LostFeas
                   32 Infeasible
                   64 Dynamic
                  128 During BB
depth=...        set branch-and-bound depth limit
dual             prefer the dual simplex for both phases
eps=...          tolerance for rounding to integer
epsb=...         minimum tolerance for the RHS
epsd=...         minimum tolerance for reduced costs
epsel=...        minimum tolerance for rounding values to zero
epsp=...         value that is used as perturbation scalar for
               degenerative problems
f                specifies that branch-and-bound algorithm stops at first
               found solution
ga=...           specifies the absolute MIP gap for branch-and-bound
gr=...           specifies the relative MIP gap for branch-and-bound
improve=...      the iterative improvement level: one of
  		    0 improve none
  		    1 Running accuracy measurement of solved equations based on
                      Bx=r (primal simplex), remedy is refactorization.
  		    2 Improve initial dual feasibility by bound flips
                      (highly recommended, and default)
  		    4 Low-cost accuracy monitoring in the dual, remedy is refactorization
                    8 By default there is a check for primal/dual feasibility at optimum
                      only for the relaxed problem, this also activates the test at the node level
n=...            specify which solution number to return
o=...            specifies that branch-and-bound algorithm stops when
               objective value is better than value
objno=...        objective number: 0 = none, 1 (default) = first
obound=...       a lower bound for the objective function
               may speed up the calculations
parse_only       parse input file but do not solve
piv=...          simplex pivot rule: one of
  		    0 select first
  		    1 select according to Dantzig
  		    2 (default) select Devex pricing from Paula Harris
  		    3 select steepest edge
piva             temporarily use first index if cycling is detected
pivf             in case of Steepest Edge, fall back to DEVEX in primal
pivla            scan entering/leaving columns alternatingly left/right
pivll            scan entering/leaving columns left rather than right
pivm             multiple pricing
pivr             adds a small randomization effect to the selected pricer
presolve         presolve problem before start optimizing
presolvel        also eliminate linearly dependent rows
presolver        if the phase 1 solution process finds that a constraint is
               redundant then this constraint is deleted
prim             prefer the primal simplex for both phases
printsol=...     print solution: one of
  		    0 (default) print nothing
  		    1 only objective value
  		    2 obj value+variables
  		    3 obj value+variables+constraints
  		    4 obj value+variables+constraints+duals
  		    5 obj value+variables+constraints+duals+lp model
  		    6 obj value+variables+constraints+duals+lp model+scales
  		    7 obj value+variables+constraints+duals+lp model+scales+
                      lp tableau
prlp             print the LP
psols            print (intermediate) feasible solutions
psolsa           print (intermediate) feasible solutions (non-zeros)
r=...            max nbr of pivots between a re-inversion of the matrix
rparname=...     parameter file to read options from
rparoptions=...  options parameter file
scale            scale the problem
scalemode=...    scale mode:  one of
  		    1 for scale to convergence using largest absolute value
  		    2 for scale based on the simple numerical range
  		    3 (default) for numerical range-based scaling
  		    4 for geometric scaling
  		    7 for Curtis & Reid scaling
  	       plus
  		   16 for scale to convergence using logarithmic mean
                      of all values
  		   32 for also do Power scaling
  		   64 to make sure that no scaled number is above 1
  		  128 to scale integer variables
simplexdd        set Phase1 Dual, Phase2 Dual
simplexdp        set Phase1 Dual, Phase2 Primal
simplexpd        set Phase1 Primal, Phase2 Dual
simplexpp        set Phase1 Primal, Phase2 Primal
timeout=...      timeout after sec seconds when not solution found
trace            trace pivot selections
trej=...         minimum pivot value
verbose          verbose mode
version          report version details
wafter           write model after solve (usefull if presolve used)
wantsol=...      solution report without -AMPL: sum of
		1 ==> write .sol file
		2 ==> print primal variable values
		4 ==> print dual variable values
		8 ==> do not print solution message
wfmps=...        write to MPS file in free format
wlp=...          write to LP filename
wmps=...         write to MPS file in fixed format
wparname=...     parameter file to write options to
wparoptions=...  options parameter file
wxli=...         write file with xli library
wxliname=...     xli library
wxliopt=...      options for xli library

lpsolve command line options

Normally, the lpsolve program is called from AMPL. However the program can also be called stand-alone. When the command is invoked without an option or with the option -?, a list of the possible options is shown:

usage: lpsolve [options] stub [-AMPL] [<assignment> ...]

Options:
        --  {end of options}
        -=  {show name= possibilities}
        -?  {show usage}
        -e  {suppress echoing of assignments}
        -s  {write .sol file (without -AMPL)}
        -v  {just show version}

stub and the -AMPL option is used when the program is called from AMPL.
The -v option shows the version of lpsolve.
The -= option shows all the options that can be passed to lpsolve from within AMPL.
These options can also be specified in an environment variable lpsolve_options.

To call the lpsolve command to solve a model, you first must have a stub file that can be read by lpsolve. This stub file can be created by AMPL as follows:

ampl: model models\diet.mod;
ampl: data models\diet.dat;
ampl: write bdiet;
ampl: quit

This created a binary file diet.nl. As an alternative the command write gdiet; can be used. This creates an ascii file that also can be read. However it is somewhat slower to read, especially when the models are larger.

This creates a file diet.nl in the current directory. This file is the stub file needed by lpsolve:

lpsolve lpsolve diet.nl

This gives:

LP_SOLVE 5.5.2.11: optimal, objective 88.19999999999999
3 simplex iterations

Options can be passed to lpsolve via the environment variable lpsolve_options:

set lpsolve_options=scale scalemode=7 verbose

Then the result of the previous lpsolve command is:

scale
scalemode=7
verbose
Model name:  '' - run #1
Objective:   Minimize(R0)

Submitted:
Model size:        4 constraints,       8 variables,           39 non-zeros.
Constraints:       0 equality,          0 GUB,                  0 SOS.
Variables:         0 integer,           0 semi-cont.,           0 SOS.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.

Optimal solution with dual simplex at iteration          1

lp_solve solution         88.2 final at iteration        1,       0 nodes explor
ed

Excellent numeric accuracy ||*|| = 1.13687e-013

 Memo: Largest [etaPFI v1.0] inv(B) had 0 NZ entries, 0.0x largest basis.
      In the total iteration count 1, 0 (0.0%) were minor/bound swaps.
      There were 0 refactorizations, 0 triggered by time and 0 by density.
             ... on average 1.0 major pivots per refactorization.
      Total solver time was 0.000 seconds.
LP_SOLVE 5.5.2.11: optimal, objective 88.19999999999999
1 simplex iterations

In this mode, the lpsolve option wantsol shows the solution:

set lpsolve_options=wantsol=2
lpsolve diet.nl

This gives:

wantsol=2
LP_SOLVE 5.5.2.11: optimal, objective 88.19999999999999
3 simplex iterations

variable  value
_svar[1]  0
_svar[2]  0
_svar[3]  0
_svar[4]  0
_svar[5]  46.666666666666664
_svar[6]  0
_svar[7]  -3.552713678800501e-15
_svar[8]  0

The -e option results in not echoing the options passed to lpsolve:

set lpsolve_options=wantsol=2
lpsolve -e diet.nl

This gives:

LP_SOLVE 5.5.2.11: optimal, objective 88.19999999999999
3 simplex iterations

variable  value
_svar[1]  0
_svar[2]  0
_svar[3]  0
_svar[4]  0
_svar[5]  46.666666666666664
_svar[6]  0
_svar[7]  -3.552713678800501e-15
_svar[8]  0

lpsolve options can also be passed at the command line, they don't overrule the lpsolve_options environment variable, they are added:

set lpsolve_options=wantsol=2
lpsolve diet.nl "verbose scale"

This gives:

wantsol=2
verbose
scale
Model name:  '' - run #1
Objective:   Minimize(R0)

Submitted:
Model size:        4 constraints,       8 variables,           39 non-zeros.
Constraints:       0 equality,          0 GUB,                  0 SOS.
Variables:         0 integer,           0 semi-cont.,           0 SOS.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.

Optimal solution with dual simplex at iteration          1

lp_solve solution         88.2 final at iteration        1,       0 nodes explor
ed

Excellent numeric accuracy ||*|| = 1.13687e-013

 Memo: Largest [etaPFI v1.0] inv(B) had 0 NZ entries, 0.0x largest basis.
      In the total iteration count 1, 0 (0.0%) were minor/bound swaps.
      There were 0 refactorizations, 0 triggered by time and 0 by density.
             ... on average 1.0 major pivots per refactorization.
      Total solver time was 0.000 seconds.
LP_SOLVE 5.5.2.11: optimal, objective 88.19999999999997
1 simplex iterations

variable  value
_svar[1]  0
_svar[2]  0
_svar[3]  0
_svar[4]  0
_svar[5]  46.66666666666666
_svar[6]  0
_svar[7]  0
_svar[8]  0

Compile the AMPL driver

Besides the specific lpsolve files, you also need the AMPL solvers files that must be linked with it. These AMPL solvers files can be downloaded from various locations. The easiest way is via http://netlib.sandia.gov/cgi-bin/netlib/netlibfiles.tar?filename=netlib/ampl/solvers. untar them in directory lp_solve_5.5/extra/AMPL. This will put the files in lp_solve_5.5/extra/AMPL/solvers. Then in the solvers directory, gunzip all the files with extension .gz.
Then, still in the solvers directory, execute the appropriate Makefile.
For example under Windows:
nmake /f makefile.vc
Under Unix this would be:
make -f makefile.u
This will generate amplsolv.lib under Windows and amplsolver.a under Unix systems. However, Under windows, you must first create a file details.c by hand. It must contain the following single line:
char sysdetails_ASL[] = "MS VC++ 6.0";
See README for more information how to build the AMPL solvers files.

Then install the files from archive lp_solve_5.5_AMPL_source.tar.gz
When this is done, goto the lpsolve directory and execute the appropriate makefile. There are two possibilities: generate a driver that links lpsolve statically and one that links lpsolve dynamically. When linked dynamically, the lpsolve dll or shared library is used at runtime. When linked statically, the lpsolve static library is linked at compile time with the AMPL lpsolve driver. For example:
nmake /f makefile5dyn.vc
Under Unix this would be:
make -f makefile5dyn.u
This will generate lpsolve.exe (Windows) or lpsolve (Unix). Put this in the AMPL directory.

./bas-format.htm000666 000000 000000 00000012342 10616065036 012137 0ustar00000000 000000 MPS bas file format

MPS bas file format

The MPS format can also be used to specify some predefined basis for an LP problem, i.e. to specify which rows and columns are basic and which are non-basic.

As in the MPS format, a number of fields are defined on fixed column positions:

Field:    1           2          3         4         5         6
Columns:  2-3        5-12      15-22     25-36     40-47     50-61

The order of a basis file in the MPS format is:

Any line with an asterisk (*) in Column 1 is treated as a comment.

The NAME card can have anything you want, starting in column 15.
lp_solve sets the number of iterations, the number of rows and number of columns of the model to the NAME record.

The eight character names used to specify variables and constraints entities are fixed format. Names are not automatically justified, so blanks are treated just like other characters. For example "ROW1 " is not the same as " ROW1 ". (Note that some optimisers do not permit blanks in names.) No case conversion is performed, so "row1 " is different from "ROW1 ".

Each data card specifies either a pair "basic column--non-basic row" or a non-basic column. All the data cards have the following format.

'XL' in the field 1 means that a column, whose name is given in the field 2, is basic, and a row, whose name is given in the field 3, is non-basic and placed on its lower bound.

'XU' in the field 1 means that a column, whose name is given in the field 2, is basic, and a row, whose name is given in the field 3, is non-basic and placed on its upper bound.

'LL' in the field 1 means that a column, whose name is given in the field 3, is non-basic and placed on its lower bound.

'UL' in the field 1 means that a column, whose name is given in the field 3, is non-basic and placed on its upper bound.

The field 2 contains a column name.

If the indicator given in the field 1 is 'XL' or 'XU', the field 3 contains a row name. Otherwise, if the indicator is 'LL' or 'UL', the field 3 is not used and should be empty.

The field 4, 5, and 6 are not used and should be empty.

ValueStatus
XUVariable 1 is basic; variable 2 is nonbasic at its upper bound
XLVariable 1 is basic; variable 2 is nonbasic at its lower bound
ULVariable 1 is nonbasic and is at its upper bound
LLVariable 1 is nonbasic and is at its lower bound

Field 1: Indicator specifying status of the named variables in Fields 2 and 3.

Field 2: Variable 1 identifier

Field 3: Variable 2 identifier (ignored if Field 1 is UL or LL)

Variable 1 specifies a structural variable identifier which has entered the basis. By convention, this structural variable must displace one of the row variables. Variable 2 is a row variable that has left the basis. No relationship between structural variables entering the basis and row variables leaving the basis is implied within the BAS file.

A basis file in the MPS format acts like a patch: it doesn't specify a basis completely, instead that it is just shows in what a given basis differs from the "standard" basis, where all rows (auxiliary variables) are assumed to be basic and all columns (structural variables) are assumed to be non-basic.

A basis defines a list of basic structural variables and row variables. A structural variable is one of the variables (columns) defined in the MPS problem file. A row variable is actually the slack, surplus, or artificial variable associated with a row. The total number of basic variables-both structural and row-is equal to the number of rows in the constraint matrix. Additionally, the number of basic structural variables is equal to the number of nonbasic row variables. By convention, an MPS basis file is built on the assumption that all row variables are basic and that all structural variables are nonbasic with values at their lower bound. The data records in a BAS file list structural and row variables that violate this assumption. This convention minimizes the size of the BAS file.

Example:

*000000001111111111222222222233333333334444444444555555555566
*234567890123456789012345678901234567890123456789012345678901
NAME          TESTPROB Iterations 0 Rows 3 Cols 3
 XL ZTHREE    LIM2
 UL XONE
ENDATA
./BFP.htm000666 000000 000000 00000014704 10237412444 010515 0ustar00000000 000000 Basis Factorization Packages

Basis Factorization Packages

Basis Factorization Package (shortened as BFP) is a unique lp_solve feature. Considerable effort has been put in this new feature and we have big expectations for this. BFP is a generic interface model and users can develop their own implementations based on the provided templates. We are very interested in providing as many different BFPs as possible to the community.

Until version 4, lp_solve always used the product form of the inverse (etaPFI) to perform its matrix pivot changes. However there are other methods like LU decomposition. Each method has its advantages and disadvantages. Some are faster/slower, other are numerical more/less stable. The speed and stability of a solver depends considerably on the BFP. One model will be solved better with one BFP and another with another BFP.
The following is a personal comment on the different BFPs by Kjell Eikland:

"Personally, I go for numerical robustness and size capability LUSOL is the one to beat. The LUSOL code has tremendous features for tackling even the toughest models, balancing accuracy and fill-in to a phenomenal extent. I have experimented with a maximum update limit before refactorization of 1500, and even at that level LUSOL was much more reliable than etaPFI!LUSOL does extremely well with some classes of very tough models, such as the PILOT models. For simple, not too large network-like models with little fill-in, etaPFI can be extremely fast and maintain accuracy if the numerics are not too bad. etaPFI v2 is typically both faster and numerically more robust and can handle much more challenging models than v1. The main reason is that v2 typically has quite a bit less fill-in and better pivot management, which automatically leads to better speed and accuracy. GLPK has an LU implementation model that is conceptually/numerically inferior to LUSOL, but updating and btran can be faster.For medium size models of a higher than average toughness, GLPK is definitely a good choice. However, in my experience GLPK is not robust from the perspective of memory management.With some unusually hard models prone to fill-in it simply bombs, which is not good in a production environment.Accuracy management is limited to refactorization (just like etaPFI)."

lp_solve version 5.5 has the LUSOL engine built in as default. In addition two other BFPs are included for both Windows and Linux: bfp_LUSOL.dll, bfp_etaPFI.dll for Windows and libbfp_LUSOL.so, libbfp_etaPFI.so for Linux. The standalone bfp_etaPFI is v2.0 and includes advanced column ordering using the COLAMD library, as well as better pivot management for stability. For complex models, however, the LU factorization approach is much better, and lp_solve now includes LUSOL as one of the most stable engines available anywhere. LUSOL was originally developed by Prof. Saunders at Stanford, and it has now been ported to C and enhanced by Kjell Eikland.

These BFPs are not statically linked, but are dynamically loaded when requested (except for the default LUSOL engine). It is even possible for people to write their own BFP. Under Windows, a BFP is provided as DLL (bfp_*.dll), under UNIX/LINUX as a dynamic linked library (libbfp_*.so).
To change the BFP with lp_solve, use the option -bfp <filename>. Via the API, use set_BFP. filename is the name of the dynamic linked library. It is possible to provide a path to this name to be sure that the BFP from the specified location is used. If no path is given, then it depends on the OS where it will be searched.

Under Windows, the following search order is used:

  1. Current directory.
  2. A semi-colon-separated (;) list of directories in the user's PATH environment variable.

Under Unix/Linux, following search order is used:

  1. A colon-separated (:) list of directories in the user's LD_LIBRARY_PATH environment variable.
  2. The list of libraries specified in /etc/ld.so.cache (which is generated from /etc/ld.so.conf).
  3. /lib, followed by /usr/lib. Note the order here; this is the reverse of the order used by the old a.out loader. The old a.out loader, when loading a program, first searched /usr/lib, then /lib (see the man page ld.so(8)). This shouldn't normally matter, since a library should only be in one or the other directory (never both), and different libraries with the same name are a disaster waiting to happen.

Under Unix/Linux it is standard that a library has the lib prefix and a .so postfix. Under Windows there is no prefix and a .dll postfix.
To make the calling structure for BFPs uniform across different types of OS, lp_solve automatically adds the prefix and postfix if not provided. So the following commands are valid for both Windows and Unix/Linux:

lp_solve -bfp bfp_LUSOL input.lp
lp_solve -bfp ./bfp_LUSOL input.lp

The latter makes sure that the BFP is searched in the current directory, especially for Unix/Linux.

A third BFP based on GLPK may be included later, but license issues must first be resolved. In the interim, you may experiment with the working sample BFP interface files for GLPK.

If you compile BFPs yourself, make sure that under Windows, you use __stdcall convention and use 8 byte alignments. This is needed for the BFPs to work correctly with the general distribution of lp_solve and also to make sharing BFPs as uncomplicated as possible.

./Build.htm000666 000000 000000 00000070357 13772705350 011163 0ustar00000000 000000 Calling the lpsolve API from your application

Calling the lpsolve API from your application

There are two ways to call the lpsolve API from an application:

  • Dynamically
  • Statically

Dynamically means that the lpsolve code is dynamically linked to your code. This means that it is linked to your program when the executable is started or even only when you make calls to the lpsolve library. The lpsolve library is then not linked with the executable and is provided in a separate file. Under Windows this is a dll (lpsolve55.dll), under Unix/Linux this is a shared library (liblpsolve55.so). You must distribute this separate library with your program to make it work. The library must be located on a place that can be found by the program. There are several advantages of this way of working. Almost all programming languages have a way to call dynamic libraries or even can only call libraries that way. One example is VB6. Another advantage is that it is easier to update the package. The program doesn't have to be recompiled/relinked. You only have to provide a new lpsolve library.

Statically means that the lpsolve code is statically linked to the code. This means that the program does not need extra files to be able to call lpsolve since the code is already contained in the executable. The executable will thus be larger. This can only be done if you have the source code of your program and you can recompile it and link it with the lpsolve code. Not all programming languages have the possibility to statically link code. For example VB6 does not have a way to do that. The advantage of this way of calling the lpsolve library is that you don't have to provide extra files with your executable since the library is already in the exe. The disadvantage is that you must recompile (or at least link) the program with the lpsolve code when an update of lpsolve is needed. There are two ways to link your application with lpsolve. The first way is add the needed lpsolve source code to the project and compile it together as one unit. This is most probably only possible when the code is also written in C/C++ (however not always since for example .NET allows to link for example C# code with C code). The disadvantage of this way of working is that you have to revise your project when you use a new version of lpsolve since there could be files added or removed in the lpsolve package. Also you may have to define some defines. A better way of working is making use of the lpsolve library. Under DOS/Windows this is called liblpsolve55.lib (liblpsolve55d.lib in debug mode), under Unix/Linux liblpsolve55.a. The advantages are that other languages (like Pascal) can also link with such a library, your project is not overloaded with the lpsolve source files and also not unimportant, the linker only takes the code from the library that you really use resulting in a smaller executable. One disadvantage is that you cannot debug and step trough the lpsolve code then, if you would want to do that.

So what method to choose to call lpsolve from your application?

  1. Dynamically link your application with lpsolve
    1. Implicit linking with the lpsolve dynamic library
    2. Explicit linking with the lpsolve dynamic library
  2. Statically link your application with lpsolve
    1. Implicit linking with the lpsolve static library
    2. Link your code with the lpsolve source code

Dynamically link your application with lpsolve

lpsolve is separated from the application. So there are two separate compilations. One of the application and one of the lpsolve library. Most people will not compile the lpsolve library themselves since it is provided for several popular platforms. The files are in lp_solve_5.5.2.11_dev.zip for Windows and lp_solve_5.5_dev.gz for Linux. Therefore it is first explained how to access the lpsolve library in your application. This depends on the OS and the calling language. The most common are described here.

There are two ways of linking a dynamic library to the application: Implicit and Explicit linking. It depends on the programming language which way of linking is supported. Some support only one of the two, some can do both ways.
Implicit linking with the lpsolve dynamic library

With Implicit Linking, the shared library file gets loaded into memory as soon as we execute the client program. If implicitly linked, the library is not removed from memory unless the application is terminated. However, if there are other applications in memory that are using the library, it is not removed from memory till the last of these applications is terminated.

If Implicit Linking is used, a link (or import) library must be provided to the linker to resolve the symbols. In the code, the function calls are made as if all symbols are available.

Explicit linking with the lpsolve dynamic library

If we want, we can defer the loading of the library till the time a call to the exported function in the library is not made. This is known as Explicit Linking. Explicit linking is more appropriate for interpreted languages such as Visual Basic, but it can also be used from C/C++ if we need to.

If Explicit Linking is used, the library is explicitly loaded in memory via a special API call and the routines are also explicitly called via API calls. It should be clear that Explicit linking requires more coding than Implicit linking, but it allows you do load the library only when you need it and even decide at runtime from which library to call the routines.

Some may see Implicit linking as 'early binding' and Explicit linking as 'late binding'. Although it is not exactly the same, the analogy is true. Just like 'early binding', with Implicit linking, the symbols are resolved and checked at compile (actually link) time. There is strong type checking and less chance to pass wrong arguments. Just like 'late binding', with Explicit linking, the symbols are resolved and checked at runtime. The type checking is loose and there is chance that wrong parameters are passed to the function with possible disastrous results. But with the flexibility to dynamically load and call functions.
For Windows, there is a good article explaining all this: DLLs for Beginners

WINDOWS: Call the lpsolve dll from C/C++

Microsoft Visual C/C++ and GNU gcc support both Implicit and Explicit linking. In both cases, some header files are also needed. They are included with the archive where the libraries are also in lp_solve_5.5.2.11_dev.zip and lp_solve_5.5_dev.gz. Only lp_lib.h must be included in your source code. The other header files are included by this master include file.

Implicit linking

In implicit linking, the linker matches the symbols of the library via a .lib file (the import library). Note the extension of the file. This is the same as for a static library. This may be confusing. There is a big difference between a static library and an import library. It is unfortunate that Microsoft has used the same extension for both. A static library contains code and it is statically linked to the executable. An import library only contains symbol definitions so that the linker can resolve the symbols. An import library will thus be much smaller in size than a static library. This file is provided with the lpsolve dll and is called lpsolve55.lib (both in archive lp_solve_5.5.2.11_dev.zip). It depends on the environment and the version how to do this. Via the link.exe command, this is done by just specifying the lpsolve55.lib file at the command line. Via the .NET environment, this can be done via: Project, Properties, Linker, Input, Additional Dependencies. Optionally it is possible to also specify a link path via Project, Properties, Linker, General, Additional Library Directories. In Visual studio 6, this can be done via: Project, Settings, Link, Category General, Object/library modules. Optionally it is possible to also specify a link path via Project, Settings, Link, Category Input, Additional library path.
After this is done, the lpsolve functions can be called just like the lpsolve functions are linked to the program.

Example:

#include <stdio.h>

#include "lp_lib.h"

main()
{
  lprec *lp;

  lp = make_lp(0,4);

  /* ... */

  delete_lp(lp);
}
Explicit linking

In explicit linking we don't use the .lib file. Instead we call the Win32 LoadLibrary( ) function, specifying the DLL's pathname as a parameter. The LoadLibrary( ) function returns an HINSTANCE parameter. This parameter is used in a call to the GetProcAddress( ) function to fetch the address of the function to be called. This address is a pointer to a function. Through this pointer the function is finally called. As can be seen in the following example, this requires some extra coding.

Example:

#include <stdio.h>

#include "lp_lib.h"

main()
{
  lprec *lp;
  HINSTANCE lpsolve;
  make_lp_func *_make_lp;
  delete_lp_func *_delete_lp;

  lpsolve = LoadLibrary("lpsolve55.dll");

  if (lpsolve == NULL) {
    printf("Unable to load lpsolve shared library\n");
    return(FALSE);
  }
  _make_lp = (make_lp_func *) GetProcAddress(lpsolve, "make_lp");
  _delete_lp = (delete_lp_func *) GetProcAddress(lpsolve, "delete_lp");

  lp = _make_lp(0,4);

  /* ... */

  _delete_lp(lp);

  FreeLibrary(lpsolve);
}

Note that the prototype definitions of the lpsolve functions (ex make_lp_func) are already defined in lp_lib.h. This same code also works with the Windows gnu gcc compiler. The only thing that must be done at compile time is defining the WIN32 macro. This will make sure that the calling convention will be __stdcall as required.

The C demo example (lp_solve_5.5_c.tar.gz) demonstrates both implicit and explicit linking.

The following batch/script files can be used to compile the demo's from the command line:

cvc6.bat Compile the demo with the Microsoft Visual C compiler. It generates demoi.exe, demoe.exe, demos.exe. These are Dynamic Implicit linked, Dynamic Explicit linked and Static linked versions of the same demo.
cgcc.bat Compile the demo with the GNU gcc compiler. It generates demoi.exe, demoe.exe, demos.exe. These are Dynamic Implicit linked, Dynamic Explicit linked and Static linked versions of the same demo. Also note that the lpsolve55.dll file must also be compiled with gcc for this to work.

The following VC.NET project files can be used to compile the demo's from the IDE:

DemoDynamicImplicit.sln, DemoDynamicImplicit.vcproj Generates a Dynamic Implicit linked exe.
DemoDynamicExplicit.sln, DemoDynamicExplicit.vcproj Generates a Dynamic Explicit linked exe.

WINDOWS: Call the lpsolve dll from VB (also VBS Excel, Word, Access)
These environments support only Explicit linking. However it is much easier than in C. Via a DECLARE statement, the API routines are declared and can immediately be called. The LoadLibrary/GetProcAddress API calls are done by VB and are invisible to you. To make things even easier, a class file is made to access the lpsolve library. It is called lpsolve55.cls. See the VB/Excel demos to see how it works (lp_solve_5.5_vb.zip, lp_solve_5.5_excel.zip).

WINDOWS: Call the lpsolve dll from VB.NET, C#

This is analogue as for VB. These environments probably also allow to use implicit linking, but this is not investigated. The demos use implicit linking. There is a class library made to call the lpsolve library. It is called lpsolve55.vb and lpsolve55.cs
See the demos for how it works (lp_solve_5.5_vb.net.zip and lp_solve_5.5_cs.net.zip).

LINUX/UNIX: Call the lpsolve shared library from C/C++
Not yet documented. See lp_solve_5.5_c.tar.gz

ccc Compile the demo under Linux/Unix. It generates demoi, demoe, demos. These are Dynamic Implicit linked, Dynamic Explicit linked and Static linked versions of the same demo.

Statically link your application with lpsolve

lpsolve is linked with the application. The application is most likely a C/C++ application. It must at least be a programming environment with a linker such that the lpsolve code can be linked with your code. Some header files are also needed. They are included with the archive where the libraries are also in lp_solve_5.5.2.11_dev.zip and lp_solve_5.5_dev.gz. Only lp_lib.h must be included in your source code. The other header files are included by this master include file.

There are two ways to link lpsolve statically with your application: Implicit linking with the lpsolve static library and link your code with the lpsolve source code.
Implicit linking with the lpsolve static library

The lpsolve code is in a library file. The files are in lp_solve_5.5.2.11_dev.zip for Windows and lp_solve_5.5_dev.gz for Linux. Under Windows with the Microsoft compiler, this is in a .lib file. Under Unix and under Windows with the cygwin gcc compiler, this is in a .a file. Note for the Microsoft compiler the extension of the file. This is the same as for a dynamic library with implicit linking. This may be confusing. There is a big difference between a static library and an import library. It is unfortunate that Microsoft has used the same extension for both. A static library contains code and it is statically linked to the executable. An import library only contains symbol definitions so that the linker can resolve the symbols. An import library will thus be much smaller in size than a static library.
The static library file is provided with the lpsolve distribution and is called liblpsolve55.lib (liblpsolve55d.lib for debugging) for the Microsoft compiler and liblpsolve55.a under Linux and with the cygwin gnu compiler under Windows. It depends on the environment and the version how to link the static library with your code. For Linux and with the cygwin gnu compiler, just specify the .a file to the compile command line:

cc pgr.c liblpsolve55.a

For the Microsoft visual C compiler it can be done as follows: Via the link.exe command this is done by just specifying the liblpsolve55.lib file at the command line. Via the .NET environment, this can be done via: Project, Properties, Linker, Input, Additional Dependencies. Optionally it is possible to also specify a link path via Project, Properties, Linker, General, Additional Library Directories. In Visual studio 6, this can be done via: Project, Settings, Link, Category General, Object/library modules. Optionally it is possible to also specify a link path via Project, Settings, Link, Category Input, Additional library path.
After this is done, the lpsolve functions can be called just like the lpsolve functions are linked to the program.

Example:

#include <stdio.h>

#include "lp_lib.h"

main()
{
  lprec *lp;

  lp = make_lp(0,4);

  /* ... */

  delete_lp(lp);
}

The C demo example (lp_solve_5.5_c.tar.gz) demonstrates static linking. The following batch/script files can be used to compile the demo's from the command line:

cvc6.bat Compile the demo with the Microsoft Visual C compiler. It generates demoi.exe, demoe.exe, demos.exe. These are Dynamic Implicit linked, Dynamic Explicit linked and Static linked versions of the same demo. Note that the static linked version is much larger than the dynamic linked versions.
cgcc.bat Compile the demo with the GNU gcc compiler. It generates demoi.exe, demoe.exe, demos.exe. These are Dynamic Implicit linked, Dynamic Explicit linked and Static linked versions of the same demo. Note that the static linked version is much larger than the dynamic linked versions. Also note that the lpsolve55.dll file must also be compiled with gcc for this to work.
ccc Compile the demo under Linux/Unix. It generates demoi, demoe, demos. These are Dynamic Implicit linked, Dynamic Explicit linked and Static linked versions of the same demo. Note that the static linked version is much larger than the dynamic linked versions.

The following VC.NET project files can be used to compile the demo from the IDE:

DemoStaticImplicit.sln, DemoStaticImplicit.vcproj Generates a Static linked exe.
Link your code with the lpsolve source code

The lpsolve source code is linked with your code. The lpsolve source code is contained in archive lp_solve_5.5_source.tar.gz. This is the most complex method and should only be used when the others don't work.

One note in advance. Your C/C++ compiler must know 64 bit integers. Most today compilers support this trough the data type long long. lp_solve uses a define LLONG for this. If your compiler doesn't support long long, but it supports 64 bit integers trough another name, then you can define LLONG to this type at the compiler command line. For example -DLLONG=int64. Also some older (versions of) compilers only support long long via an additional switch. For example previous gcc compilers need the switch -std=c99 at the gcc compile command to enable ISO C99. Without this switch a warning is given like "warning: ISO C90 does not support `long long'".

The following source files must at least be added to your project:

bfp/bfp_LUSOL/lp_LUSOL.c
bfp/bfp_LUSOL/LUSOL/lusol.c
colamd/colamd.c
ini.c
shared/commonlib.c
shared/mmio.c
shared/myblas.c
lp_crash.c
lp_Hash.c
lp_lib.c
lp_matrix.c
lp_MDO.c
lp_mipbb.c
lp_MPS.c
lp_params.c
lp_presolve.c
lp_price.c
lp_pricePSE.c
lp_report.c
lp_scale.c
lp_simplex.c
lp_SOS.c
lp_utils.c
lp_wlp.c

All header (.h) files from lpsolve must be accessible. Most compilers use the directive -Ipath with path the location to the header files. Note that the colamd, bfp and bfp/bfp_etaPFI directories also contain header files that must be included.

If you also need the lp parser to read an lp model (read_lp, read_LP) then you must also include the files lp_rlp.c and yacc_read.c and define the symbol PARSER_LP. Most compilers use the directive -DPARSER_LP to do that. If you forget to define this symbol then the linker will give a link error saying that the symbols read_lp, read_LP are already defined. Also define the symbol YY_NEVER_INTERACTIVE (-DYY_NEVER_INTERACTIVE). This to disable the interactive mode of the lex parser and remove the dependency on isatty() routine which not available in all environments.

Note that lp_rlp.c, lp_rlp.h may give you some warnings when they are compiled. This is 'normal'. These files are not human-written, but generated from yacc/bison/lex tools from the corresponding .y and .l files. These tools don't seem to care much in generating code that is fully Ansi compliant and without warnings. Normally they can be ignored.

Note that there are more .c files in the lpsolve directory. You don't have to (even may not) include these in your project also. This because there files are either automatically included by the other source files or are needed for other functionality.

With the Windows Microsoft compiler, the compilation command could be:

cl -Ic:\lp_solve_5.5 -Ic:\lp_solve_5.5\bfp -Ic:\lp_solve_5.5\bfp\bfp_etaPFI -Ic:\lp_solve_5.5\colamd /Zp8 -DWIN32 %src% -o MyExe.exe

With the Windows gnu compiler, the command could be:

gcc -Ic:\lp_solve_5.5 -DBFP_CALLMODEL=__stdcall %src% -o MyExe.exe

Under Unix/Linux, the command could be:

cc -I/lp_solve_5.5 -I/lp_solve_5.5/bfp -I/lp_solve_5.5/bfp/bfp_etaPFI -I/lp_solve_5.5/colamd $src -o MyExe.exe -lm -ldl

%src% / $src is an environment variable containing all source files (above lpsolve source files plus your sources). Note the /Zp8 option with the Windows c compiler. This is also important. It ensures 8-bit alignment. This is required when you make use of the BPF functionality (see Basis Factorization Packages) and the XLI functionality (see External Language Interfaces). It doesn't matter which calling convention is used. __cdecl or __stdcall or any other calling convention is ok, even if you make use of the BFP functionality. Note the -DBFP_CALLMODEL=__stdcall option with the non-Microsoft compiler. This is to define a macro for the BFP to make sure its routines are called via the __stdcall calling convention. This is required if you want to make use of the BFP functionality. If your compiler doesn't provide a way to specify the __stdcall calling convention, then you can drop this, but the BFP functionality will then probably not work (even crash). With the Microsoft compiler this option doesn't have to be specified because it is automatically set by the lpsolve header files via the WIN32 macro. Under Unix/Linux the -lm option must be added to link with the math library and the option -ldl is used to link with the shared library. Not all Unix systems have this functionality. In that case you can drop the -ldl option but then you have to add -DLoadInverseLib=0 -DLoadLanguageLib=0 in which case you will not be able to use the BFP functionality (see Basis Factorization Packages) and also not the XLI functionality (see External Language Interfaces).

The compiler commands to compile the package with also the lp (lpsolve and CPLEX) parser functionality:
With the Windows Microsoft compiler, the command could be:

cl -Ic:\lp_solve_5.5 -Ic:\lp_solve_5.5\bfp -Ic:\lp_solve_5.5\bfp\bfp_etaPFI -Ic:\lp_solve_5.5\colamd /Zp8 -DWIN32 -DYY_NEVER_INTERACTIVE -DPARSER_LP %src% -o MyExe.exe

With the Windows gnu compiler, the command could be:

gcc -Ic:\lp_solve_5.5 -Ic:\lp_solve_5.5\bfp -Ic:\lp_solve_5.5\bfp\bfp_etaPFI -Ic:\lp_solve_5.5\colamd -DBFP_CALLMODEL=__stdcall -DYY_NEVER_INTERACTIVE -DPARSER_LP %src% -o MyExe.exe

Under Unix/Linux, the command could be:

cc -I/lp_solve_5.5 -I/lp_solve_5.5/bfp -I/lp_solve_5.5/bfp/bfp_etaPFI -I/lp_solve_5.5/colamd -DYY_NEVER_INTERACTIVE -DPARSER_LP $src -o MyExe.exe -lm -ldl

And for Unix/Linux without the possibility to use the BFP and XLI functionality:

cc -I/lp_solve_5.5 -I/lp_solve_5.5/bfp -I/lp_solve_5.5/bfp/bfp_etaPFI -I/lp_solve_5.5/colamd -DYY_NEVER_INTERACTIVE -DPARSER_LP -DLoadInverseLib=0 -DLoadLanguageLib=0 $src -o MyExe.exe -lm

Note that I used here the command prompt commands to compile the sources. It is of course also possible to use the graphical interfaces with their project files to build it. The principle stays however the same.

In the lp_solve folder, there are also some batch/script files to build the lp_solve application. This may be a good start to begin. Note that lp_solve.c is here the application. It only contains this one source file. Or you could also look at the demo program in the demo directory. Here the application is demo.c

./changes5.htm000666 000000 000000 00000132600 10553431002 011567 0ustar00000000 000000 Changes from version 4 to version 5.1

Changes from version 4 to version 5.1

Main features and changes to v5.1 compared to v4

Overall, the v5 code is faster and more robust than v4. This robustness is for example proven by the fact that many more models can now be solved even without scaling. However, scaling should still be considered. The API has also routine to do a crash of basis (determine a starting point so that solving goes faster). The lp_solve program has been extended with options to handle the new functionality. It now also has options to write the model in the different file formats.
  • The modularization started in v4 has been significantly enhanced.
  • Internal logic and naming is much more in compliance with conventional usage.
  • Advanced pricing using Devex and Steepest Edge for both primal and dual simplexes.
  • Scaling behavior is made more consistent and many more options are available.
  • Presolve has been radically expanded.
  • A crash basis routine has been added to determine a starting point. This can improve solving time.
  • It is now possible to select desired combinations of primal and dual phases 1 and 2.
  • The native etaPFI/inverse has been improved with optimization of column ordering.
  • Alternative inverse/re-factorization libraries can be used by lp_solve. See Basis Factorization Packages
  • Alternative model readers and writers possible via the XLI implementation. See External Language Interfaces
  • B&B code has been made non-recursive (no more stack overflows!).
  • MIP contains many more variable selection and branching strategies, including pseudo-costs.
  • SOS and SC handling is faster (more branches avoided).
  • LP file support is expanded and now also includes full CPLEX LP format support.
  • Building the model via the API interface row by row can be improved spectacular by calling the new API call set_add_rowmode.

Changes in lp_solve program

The lp_solve program has many new options to make use of as many as possible possibilities of lpsolve. There are several extra options, some are extended and some are removed because they are obsolete. See lp_solve for a list of all possible options. Note that on this link there is also a reference to the API call(s) that are used for this option. There you can find more information on the option. See the list above for some of the new features.

What happened with lp2mps, mps2lp ?

These programs are removed. But don't panic, there is another way to convert from one format to another. This via the lp_solve program. This is done because of the support of a new format: The CPLEX-format. Because there are now 3 formats supported, it would have required 6 programs to convert from one format to another. Instead of doing this, lp_solve has new parameters to be able to write the model to a file, and that in all formats. So, lp_solve can read the model in any format and write it back in any format. In that case, it is most likely not whished to also calculate the model and therefore the parameter -parse_only can be used. Here some examples how to convert from one format to another:

lp to mps: lp_solve -parse_only -lp lpfile -wmps mpsfile
mps to lp: lp_solve -parse_only -mps mpsfile -wlp lpfile

It is even possible to generate several formats at the same time:
lp to all formats: lp_solve -parse_only -lp lpfile -wlp lpfile -wmps mpsfile

Changes in API calls

The API is not that much changed, but has been expanded to handle new functionality. Some simplification has taken place, for example in scaling, and a call to auto_scale is not necessary any more.
However the changes in some routines is big enough to break compatibility with version 4. Be aware of this. You must review your source code for the mentioned functions. Especially those with a (!) behind are very important to check. That is also the reason why the Windows dll will be called lpsolve51.dll compared to lpsolve.dll for version 4. Don't just rename this dll and expect that your program will work then.

Changed API calls

  • add_column, str_add_column
    • Return value is now unsigned char instead of int

  • add_constraint, str_add_constraint (!)
    • Return value is now unsigned char instead of int
    • Variable constr_type is now int instead of short
    • The constant LE has now value 1 instead of 0
      The constant EQ has now value 3 instead of 1

  • add_lag_con, str_add_lag_con (!)
    • Return value is now unsigned char instead of int
    • Variable constr_type is now int instead of short
    • The constant LE has now value 1 instead of 0
      The constant EQ has now value 3 instead of 1

  • add_sos (!)
    • Variable sostype is now int instead of short

  • column_in_lp (!)
    • Return value is now int instead of unsigned char

  • del_column
    • Return value is now unsigned char instead of int

  • del_constraint
    • Return value is now unsigned char instead of int

  • get_basis (!)
    • An extra variable is added to the argument list: nonbasic

  • get_bb_floorfirst (!)
    • This function is renamed. Before it was called get_floor_first
    • Return value is now int instead of short

  • get_bb_rule (!)
    • Return value is now int instead of short
    • The function returns different constants for different rules.

  • get_bounds_tighter
    • Return value is now unsigned char instead of int

  • get_col_name
    • When no name is set, the function now returns Cx instead of v_x

  • get_column
    • Return value is now unsigned char instead of int

  • get_constr_type (!)
    • The constant LE has now value 1 instead of 0
      The constant EQ has now value 3 instead of 1

  • get_constraints, get_ptr_constraints
    • Return value is now unsigned char instead of int

  • get_improve (!)
    • Return value is now int instead of short
    • Constant IMPROVE_FULL is renamed to IMPROVE_SOLVE
    • New constant IMPROVE_INVERSE

  • get_infinite (!)
    • The new default infinite value is 1e30 instead of 1e24

  • get_lambda, get_ptr_lambda
    • Return value is now unsigned char instead of int

  • get_maxpivot
    • This function is renamed. Before it was called get_max_num_inv

  • get_mip_gap (!)
    • An extra variable is added to the argument list: absolute

  • get_pivoting (!)
    • This function is renamed. Before it was called get_piv_rule
    • Return value is now int instead of short
    • The function returns different constants for different rules.

  • get_presolve (!)
    • This function is renamed. Before it was called is_do_presolve
    • Return value is now int instead of short
    • The function now returns constants instead of FALSE or TRUE.

  • get_primal_solution, get_ptr_primal_solution
    • Return value is now unsigned char instead of int

  • get_print_sol (!)
    • This function is renamed. Before it was called is_print_sol
    • Return value is now int instead of short
    • The function now also returns the constant AUTOMATIC.

  • get_rh_range (!)
    • The new default range value is 1e30 instead of 1e24

  • get_row
    • Return value is now unsigned char instead of int

  • get_row_name
    • When no name is set, the function now returns Rx instead of r_x

  • get_scaling (!)
    • This function is renamed. Before it was called get_scalemode
    • Return value is now int instead of short
    • The function returns different constants.

  • get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex (!)
    • Return value is now unsigned char instead of int
    • If there are integer variables, then these functions only work if set_presolve is called with parameter PRESOLVE_SENSDUALS before solve.

  • get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution (!)
    • Return value is now unsigned char instead of int
    • If there are integer variables, then these functions only work if set_presolve is called with parameter PRESOLVE_SENSDUALS before solve.
    • get_dual_solution is renamed. Before it was called get_reduced_costs
    • get_ptr_dual_solution is renamed. Before it was called get_ptr_reduced_costs

  • get_upbo (!)
    • The new default upper bound is 1e30 instead of 1e24

  • get_var_branch
    • Return value is now int instead of short

  • get_var_priority (!)
    • This function is renamed. Before it was called get_varpriority

  • get_variables, get_ptr_variables
    • Return value is now unsigned char instead of int

  • get_verbose (!)
    • Return value is now int instead of short
    • Return value can now also be NEUTRAL

  • is_anti_degen (!)
    • Return value is now unsigned char instead of short
    • An extra variable is added to the argument list: testmask

  • is_break_at_first
    • Return value is now unsigned char instead of short

  • is_debug
    • Return value is now unsigned char instead of short

  • is_feasible (!)
    • Return value is now unsigned char instead of int
    • An extra variable is added to the argument list: threshold

  • is_int
    • Return value is now unsigned char instead of int

  • is_lag_trace
    • Return value is now unsigned char instead of short

  • is_presolve (!)
    • This function is renamed. Before it was called is_do_presolve
    • Return value is now unsigned char instead of short
    • An extra variable is added to the argument list: testmask

  • is_SOS_var
    • Return value is now unsigned char instead of int

  • is_trace
    • Return value is now unsigned char instead of short

  • print_constraints (!)
    • An extra variable is added to the argument list: columns

  • print_solution (!)
    • An extra variable is added to the argument list: columns

  • read_lp, read_LP
    • Variable verbose is now int instead of short

  • read_mps, read_MPS
    • Variable verbose is now int instead of short

  • set_anti_degen (!)
    • Variable anti_degen is now int instead of short. Instead of FALSE/TRUE it takes new constants.

  • set_basis (!)
    • An extra variable is added to the argument list: nonbasic

  • set_bb_floorfirst (!)
    • This function is renamed. Before it was called set_floor_first
    • Variable branch_mode is now int instead of short

  • set_bb_rule (!)
    • Variable bb_rule is now int instead of short
    • Variable bb_rule now takes other constants.

  • set_bounds
    • Return value is now unsigned char instead of int

  • set_bounds_tighter
    • Variable tighten is now unsigned char instead of int

  • set_break_at_first
    • Variable break_at_first is now unsigned char instead of short

  • set_col_name
    • Return value is now unsigned char instead of int

  • set_constr_type (!)
    • Return value is now unsigned char instead of int
    • Variable constr_type is now int instead of short
    • The constant LE has now value 1 instead of 0
      The constant EQ has now value 3 instead of 1

  • set_debug
    • Variable debug is now unsigned char instead of short

  • set_epsint (!)
    • This function is renamed. Before it was called set_epsilon

  • set_improve (!)
    • Variable improve is now int instead of short
    • Constant IMPROVE_FULL is renamed to IMPROVE_SOLVE
    • New constant IMPROVE_INVERSE

  • set_int
    • Return value is now unsigned char instead of int
    • Variable must_be_int is now unsigned char instead of short

  • set_lag_trace
    • Variable lag_trace is now unsigned char instead of short

  • set_lowbo
    • Return value is now unsigned char instead of int

  • set_lp_name
    • Return value is now unsigned char instead of int

  • set_mat
    • Return value is now unsigned char instead of int

  • set_maxpivot
    • This function is renamed. Before it was called set_max_num_inv

  • set_mip_gap (!)
    • An extra variable is added to the argument list: absolute

  • set_obj_fn, str_set_obj_fn
    • Return value is now unsigned char instead of int

  • set_outputstream, set_outputfile (!)
    • The function set_outputfile is renamed. Before it was called print_file
    • Variable lp is added. Output is now set per lp.
    • The function set_outputstream is new

  • set_pivoting (!)
    • This function is renamed. Before it was called set_piv_rule
    • Variable pivot_rule is now int instead of short
    • The function uses different constants for different rules.

  • set_presolve (!)
    • This function is renamed. Before it was called set_do_presolve
    • Variable do_presolve is now int instead of short
    • The function uses different constants for different rules.

  • set_print_sol (!)
    • Variable print_sol is now int instead of short
    • Variable print_sol now also takes the value AUTOMATIC.

  • set_rh
    • Return value is now unsigned char instead of int

  • set_rh_range
    • Return value is now unsigned char instead of int

  • str_set_rh_vec
    • Return value is now unsigned char instead of int

  • set_row_name
    • Return value is now unsigned char instead of int

  • set_scaling (!)
    • This function is renamed. Before it was called set_scalemode
    • Variable scalemode is now int instead of short
    • The function uses different constants for different rules

  • set_semicont
    • Return value is now unsigned char instead of int
    • Variable must_be_sc is now unsigned char instead of short

  • set_trace (!)
    • Variable trace is now unsigned char instead of short

  • set_upbo
    • Return value is now unsigned char instead of int

  • set_var_branch
    • Return value is now unsigned char instead of int
    • Variable branch_mode is now int instead of short

  • set_var_weights (!)
    • This function is renamed. Before it was called set_varweights
    • Return value is now unsigned char instead of int

  • set_verbose (!)
    • Variable verbose is now int instead of short
    • Variable verbose can now also be NEUTRAL.

  • solve (!)
    • The return values of this function have changed.

  • write_lp, write_LP
    • Return value is now unsigned char instead of int

  • write_mps, write_MPS
    • Return value is now unsigned char instead of int

New API calls

Removed API calls

./changes55.htm000666 000000 000000 00000023055 10272452436 011673 0ustar00000000 000000 Changes from version 5.1 to version 5.5

Changes from version 5.1 to version 5.5

Main features and changes to v5.5 compared to v5.1

Why a jump from version numbers 5.1 to 5.5 ? This is done to indicate that this is more than just another update. The solver engine was revised and optimised in such a way that performance has improved considerably. Numerical stability is also better resulting in more models that can be solved. The LUSOL bfp is now also the default. In the past, the etaPFI bfp package was the default, but for larger models this leads faster to numerical instabilities and performance problems.

Overall, the v5.5 code is faster and more robust than v5.1. This robustness is for example proven by the fact that many more models can now be solved even without scaling.

The API hasn't changed very much. There are a couple of new routines and one routine has an extra argument. Some constants got new values.

  • Fundamental internal change to the solver engine resulting in better performance and numerical stability. Both the LP solver and the B&B solvers are enhanced.
  • Optimised MILP branch truncation, with reduced cost fixing.
  • LUSOL bfp is now the default.
  • Presolve is improved in functionality and performance.
  • Better handling of degeneracy, with more options.
  • Store and read options from a file make it easier to set options.
    See read_params and write_params
  • Partial pricing for the primal simplex now works.
  • Full support for xli_ZIMPL v2.0.3.
  • The objective function is no longer stored as part of the constraint matrix.
  • Dual-long step code is in place, but not fully activated yet.
  • General code cleanup.
  • Added OBJSENSE and OBJNAME headers in the free MPS format (See MPS file format).
  • The MathProg xli driver has now the ability to generate a model.
  • New API routines, see further.

Note the store and read options from a file. This can be a very nice new feature. lp_solve has a lot of options and with this new addition it is much easier to set these options. People can start looking for the best options that work for their models very easily and it could help to find even better default options.

Changed API calls

  • get_basis
    • Return value is now unsigned char instead of void

  • get_total_iter
    • Return value is now long long instead of long

  • get_total_nodes
    • Return value is now long long instead of long

  • put_abortfunc
    • Argument newctrlc is now from type lphandle_intfunc instead of ctrlcfunc

  • put_logfunc
    • Argument newlog is now from type lphandlestr_func instead of logfunc

  • put_msgfunc
    • Argument newmsg is now from type lphandleint_func instead of msgfunc

  • set_anti_degen
    • New constants are added: ANTIDEGEN_RHSPERTURB, ANTIDEGEN_BOUNDFLIP

  • set_basiscrash
    • New constant added: CRASH_LEASTDEGENERATE

  • set_bb_rule
    • Constant NODE_GUBMODE was not documented.
    • New constants are added: NODE_RCOSTFIXING, NODE_STRONGINIT

  • set_improve (!)
    • Constants are deleted: IMPROVE_FTRAN, IMPROVE_BTRAN, IMPROVE_SOLVE, IMPROVE_INVERSE
    • New constants are added: IMPROVE_SOLUTION, IMPROVE_DUALFEAS, IMPROVE_THETAGAP, IMPROVE_BBSIMPLEX

  • set_pivoting (!)
    • Constants are deleted: PRICE_AUTOPARTIALCOLS, PRICE_AUTOPARTIALROWS, PRICE_AUTOMULTICOLS, PRICE_AUTOMULTIROWS
    • New constants added: PRICE_AUTOPARTIAL, PRICE_AUTOMULTIPLE, PRICE_HARRISTWOPASS, PRICE_TRUENORMINIT

  • set_presolve (!)
    • There is a new third argument: maxloops
    • PRESOLVE_DUALS has a new value. Before it was 128, now it is 524288
    • PRESOLVE_SENSDUALS has a new value. Before it was 256, now it is 1048576
    • New constants are added: PRESOLVE_KNAPSACK, PRESOLVE_ELIMEQ2, PRESOLVE_IMPLIEDFREE, PRESOLVE_REDUCEGCD, PRESOLVE_PROBEFIX, PRESOLVE_PROBEREDUCE, PRESOLVE_ROWDOMINATE, PRESOLVE_COLDOMINATE, PRESOLVE_MERGEROWS, PRESOLVE_IMPLIEDSLK, PRESOLVE_COLFIXDUAL, PRESOLVE_BOUNDS

New API calls

Removed API calls

./closed.gif000666 000000 000000 00000000555 11034075772 011340 0ustar00000000 000000 GIF89a  0( @80P@@PP@`PP``Pp`Ppp`p x p`xp pА И Р 0000P@@PP``p`pppӿ؀!, @_E$|Ȥep1KIeY֕vCv6N$?oeةU־,J# Hz875}c&#!6d~!H)63 H4&  >A;./column_in_lp.htm000666 000000 000000 00000005541 10351212654 012561 0ustar00000000 000000 column_in_lp

column_in_lp

Check if a column is already present in the lp.

int column_in_lp(lprec *lp, REAL *column);

Return Value

column_in_lp returns the (first) column number if the column is already in the lp and 0 if not.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

An array with 1+get_Nrows elements that are checked against the existing columns in the lp.

Remarks

The column_in_lp functions checks if a column is already present in the lp.
It does not look at bounds and types, only at matrix values.
The first matched column is returned. If there is no column match, then 0 is returned.
Note that element 0 is the objective function value. Element 1 is column 1, and so on.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL column[1+2]; /* must be 1 more then number of rows ! */
  int ret;

  /* Create a new LP model */
  lp = make_lp(2, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  column[0] = 0.0;
  column[1] = 0.0;
  column[2] = 0.0;
  ret = column_in_lp(lp, column); /* Will return 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_column, add_columnex, str_add_column, set_column, set_columnex, del_column

./contents.htm000666 000000 000000 00000057661 13772705350 011764 0ustar00000000 000000 Contents

lp_solve 5.5.2.11 index

./copy_lp.htm000666 000000 000000 00000004662 10550150146 011551 0ustar00000000 000000 copy_lp

copy_lp

Copy an existing lprec structure to a new lprec structure.

lprec *copy_lp(lprec *lp);

Return Value

Returns a pointer to a new lprec structure. This must be provided to almost all lp_solve functions.
A NULL return value indicates an error. Specifically not enough memory available to setup an lprec structure.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The copy_lp function constructs a new LP from an existing lp structure. The new structure is independent from the original one.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp, *lpcopy;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /*
  .
  .
  .
  */

  lpcopy = copy_lp(lp);

  /*
  .
  .
  .
  */

  delete_lp(lp);
  delete_lp(lpcopy);

  return(0);
}

lp_solve API reference

See Also make_lp, delete_lp, free_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

./CPLEX-format.htm000666 000000 000000 00000043202 11127326156 012245 0ustar00000000 000000 CPLEX lp files

CPLEX lp files

The CPLEX LP file format provides a facility for entering a problem in a natural, algebraic LP formulation from the keyboard. The problem can be modified and saved from within lpsolve. This procedure is one way to create a file in a format that lpsolve can read. An alternative technique is to create a similar file using a standard text editor and to read it into lpsolve.

The CPLEX LP format is provided as an input alternative to the MPS file format. An LP format file may be easier to generate than an MPS file if your problem already exists in an algebraic format or if you have an application that generates the problem file more readily in algebraic format (such as a C application).

Note that the CPLEX LP format is not the same as the lpsolve LP format. See LP file format for a description about the native lpsolve lp format. To read/write this format from lpsolve, you need an XLI (see External Language Interfaces). The XLI for the CPLEX format is called xli_CPLEX.

Options

The XLI accepts several options:

Reading

  -objconst      Allow constants in the objective (default).
  -noobjconst    Don't allow constants in the objective.

Note that CPLEX doesn't allow constants in the objective (until at least v10). However, the lp_solve XLI does allow it by default. Use the option -noobjconst if these should not be allowed. The parser will then give an error.

Writing

  -objconst      Allow constants in the objective.
  -noobjconst    Don't use constants in the objective (default).

Note that CPLEX doesn't allow constants in the objective (until at least v10). However, the lp_solve XLI does allow it when the option -objconst is used. By default or when the option -noobjconst is used, a constant in the objective is translated to a variable objconst_term with a bound equal to the constant set to it. So no error is generated when there is a constant.

Example

lp_solve -rxli xli_CPLEX input.lpt
lp_solve -mps input.mps -wxli xli_CPLEX output.lpt -wxliopt "-objconst"

Syntax Rules of LP File Format

lpsolve will accept any problem saved in an ASCII file provided that it adheres to the following syntax rules.

  1. Anything that follows a backslash (\) is a comment and is ignored until a return is encountered. Blank lines are also ignored. Blank and comment lines may be placed anywhere and as frequently as you want in the file.

  2. In general, white space between characters is irrelevant as it is skipped when a file is read. However, white space is not allowed in the keywords used to introduce a new section, such as MAX, MIN, ST, or BOUNDS. Also the keywords must be separated by white space from the rest of the file and must be at the beginning of a line. The maximum length for any name is 255. The maximum length of any line of input is 510.

Skipping spaces may cause lpsolve to misinterpret (and accept) an invalid entry, such as the following:

 x1 x2 = 0

If the user intended to enter that example as a nonlinear constraint, lpsolve would instead interpret it as a constraint specifying that one variable named x1x2 must be equal to zero.

  1. The problem statement must begin with the word MINIMIZE or MAXIMIZE, MINIMUM or MAXIMUM, or the abbreviations MIN or MAX, in any combination of upper- and lower-case characters. The word introduces the objective function section.

  2. Variables can be named anything provided that the name does not exceed 255 characters, all of which must be alphanumeric (a-z, A-Z, 0-9) or one of these symbols: ! " # $ % & ( ) / , . ; ? @ _ ` ' { } | ~. Longer names are truncated to 255 characters. A variable name cannot begin with a number or a period.

The letter E or e, alone or followed by other valid symbols, or followed by another E or e, should be avoided as this notation is reserved for exponential entries. Thus, variables cannot be named e9, E-24, E8cats, or other names that could be interpreted as an exponent. Even variable names such as eels or example can cause a read error, depending on their placement in an input line.

Also, the following characters are not valid in variable names (in order to allow for quadratic objective information): ^, *, [ and ].

  1. The objective function definition must follow MINIMIZE or MAXIMIZE. It may be entered on multiple lines as long as no variable, constant, or sense indicator is split by a return. For example, this objective function 1x1 + 2x2 +3x3 can be entered like this:

    1x1 + 2x2
    + 3x3
    
    
    but not like this:

    1x1 + 2x
    2 + 3x3         \ a bad idea
    
    

    because the second style splits the variable name x2 with a return.

  1. The objective function may be named by typing a name and a colon before the objective function. The objective function name and the colon must appear on the same line. Objective function names must conform to the same guidelines as variable names (Rule 4).

  2. The constraints section is introduced by the keyword SUBJECT TO. This expression can also appear as such that, st, S.T., or ST. in any mix of upper- and lower-case characters. One of these expressions must precede the first constraint and be separated from it by at least one space.

  3. Each constraint definition must begin on a new line. A constraint may be named by typing a name and a colon before the constraint. The constraint name and the colon must appear on the same line. Constraint names must adhere to the same guidelines as variable names (Rule 4). If no constraint names are specified, lpsolve assigns the names R1, R2, R3, etc.

  4. The constraints are entered in the same way as the objective function; however, a constraint must be followed by an indication of its sense and a right-hand side coefficient. The right-hand side coefficient must be typed on the same line as the sense indicator. Acceptable sense indicators are <, <=, =<, >, >=, =>, and =. These are interpreted as <=, <=, <=, >=, >=, >= and =, respectively.

    For example, here is a named constraint:

    time: x1 + x2 <= 10
    
    

  1. The optional BOUNDS section follows the mandatory constraint section. It is preceded by the word bounds or bound in any mix of lower- and upper-case characters.

  2. Each bound definition must begin on a new line. The format for a bound is ln <= xn <= un except in the following cases:

    Upper and lower bounds may also be entered separately as:

    ln <= xn
    xn <= un

    with the default lower bound of 0 (zero) and the default upper bound of +infinite remaining in effect until the bound is explicitly changed.

    Bounds that fix a variable can be entered as simple equalities.
    For example, x5 = 5.6 is equivalent to 5.6 <= x5 <= 5.6.

    The bounds positive infinity and negative infinity must be entered as words: +infinity, -infinity, +inf, -inf.

    A variable with a negative infinity lower bound and positive infinity upper bound may be entered as free, in any mix of upper- and lower-case characters, with a space separating the variable name and the word free.
    For example, x7 free is equivalent to -infinity <= x7 <= +infinity.

  1. The file must end with the word end in any combination of upper- and lower-case characters, alone on a line. This word is not required for files that are read in to lpsolve, but it is strongly recommended. Files that have been corrupted can frequently be detected by a missing last line.

  2. To specify any of the variables as general integer variables, add a GENERAL section; to specify any of the variables as binary integer variables, add a BINARY section. The GENERAL and BINARY sections follow the BOUNDS section, if one is present; otherwise, they follow the constraints section. Either of the GENERAL or BINARY sections can precede the other. The GENERAL section is preceded by the word GENERAL, GENERALS, or GEN in any mix of upper- and lower-case characters which must appear alone. The following line or lines should list the names of all variables which are to be restricted to general integer values, separated by at least one space. The BINARY section is preceded by the word BINARY, BINARIES, or BIN in any mix of upper- and lower-case characters which must appear alone on a line. The following line or lines should list the names of all variables which are to be restricted to binary integer values, separated by at least one space. Binary variables are automatically given bounds of 0 (zero) and 1 (one), unless alternative bounds are specified in the BOUNDS section, in which case a warning message is issued.

    Here is an example of a problem formulation in LP format where x4 is a general integer:

    Maximize
     obj: x1 + 2 x2 + 3 x3 + x4
    Subject To
     c1: - x1 + x2 + x3 + 10 x4 <= 20
     c2: x1 - 3 x2 + x3 <= 30
     c3: x2 - 3.5 x4 = 0
    Bounds
     0 <= x1 <= 40
     2 <= x4 <= 3
    General
     x4
    End
    
    

  1. To specify any of the variables as semi-continuous variables, that is as variables that may take the value 0 or values between the specified lower and upper bounds, use a SEMI-CONTINUOUS section. This section must follow the BOUNDS, GENERALS, and BINARIES sections. The SEMI-CONTINUOUS section is preceded by the keyword SEMI-CONTINUOUS, SEMI, or SEMIS. The following line or lines should list the names of all the variables which are to be declared semi-continuous, separated by at least one space.
  2. Semi-continuous
    x1 x2 x3
    

  3. To specify special ordered sets, use a SOS section, which is preceded by the SOS keyword. The SOS section should follow the Bounds, General, Binaries and Semi-Continuous sections. Special ordered sets of type 1 require that, of the variables in the set, one at most may be non-zero. Special ordered sets of type 2 require that at most two variables in the set may be non-zero, and if there are two non-zeros, they must be adjacent. Adjacency is defined by the weights, which must be unique within a set given to the variables. The sorted weights define the order of the special ordered set. For MIP branch and cut, the order is used to determine how the variables are branched upon. The set is specified by an optional set name followed by a colon and then either of the S1 or S2 keywords (specifying the type) followed by a double colon. The set member names are listed on this line or lines, with their weights. Variable names and weights are separated by a colon, for example:
  4. SOS
      set1: S1:: x1:10 x2:13
    

./csharp.css000666 000000 000000 00000001255 11413072144 011357 0ustar00000000 000000 .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } ./datastructures.htm000666 000000 000000 00000003267 11224057724 013170 0ustar00000000 000000 Data structures

Datastructures

A-matrix

The A-matrix is stored in the lp structure in element matA and is defined in structure MATrec. Only the non-zero elements of this matrix are stored. This is called a sparse matrix. In MATrec, the following elements are of importance in the matrix data:

  • rows
  • columns
  • col_end
  • row_mat
  • row_end
  • col_mat_colnr
  • col_mat_rownr
  • col_mat_value

Elements are stored per column, then per row. col_mat_value containts the values. So first a[1][1], then a[2][1], then a[3][1], ..., a[2][1], a[2][2], ...

./default_basis.htm000666 000000 000000 00000004625 10472052734 012717 0ustar00000000 000000 default_basis

default_basis

Sets the starting base to an all slack basis (the default simplex starting basis).

void default_basis(lprec *lp);

Return Value

None

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The default_basis function sets the starting base to an all slack basis (the default simplex starting basis).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  default_basis(lp);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_basiscrash, set_basiscrash, get_basis, set_basis, read_basis, write_basis, guess_basis

./delete_lp.htm000666 000000 000000 00000003412 10237106746 012042 0ustar00000000 000000 delete_lp

delete_lp

Deletes an lprec structure.

void delete_lp(lprec *lp);

Return Value

None

Parameters

lp

lprec structure to delete.

Remarks

The delete_lp function frees all memory allocated to the lp structure. 

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /*
  .
  .
  .
  */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

./del_column.htm000666 000000 000000 00000005544 10351225702 012225 0ustar00000000 000000 del_column

del_column

Remove a column from the lp.

unsigned char del_column(lprec *lp, int column);

Return Value

del_column returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
An error occurs when column is not between 1 and the number of columns in the lp.
Note that row entry mode must be off, else this function also fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column to delete. Must be between 1 and the number of columns in the lp.

Remarks

The del_column function deletes a column from the model. The column is effectively deleted, so all columns after this column shift one left.
Note that column 0 (the right hand side (RHS)) cannot be deleted. There is always a RHS.

Note that if you can also delete multiple columns by a call to resize_lp.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h" 

int main(void) 
{
  lprec *lp;

  /* Create a new LP model */ 
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  del_column(lp, 1);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also resize_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_column, add_columnex, str_add_column

./del_constraint.htm000666 000000 000000 00000005576 10351225714 013124 0ustar00000000 000000 del_constraint

del_constraint

Remove a constraint from the lp.

unsigned char del_constraint(lprec *lp, int del_row);

Return Value

del_constraint returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
An error occurs when del_row is not between 1 and the number of rows in the lp.
Note that row entry mode must be off, else this function also fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

del_row

The row to delete. Must be between 1 and the number of rows in the lp.

Remarks

The del_constraint function deletes a row from the model. The row is effectively deleted, so all rows after this row shift one up.
Note that row 0 (the objective function) cannot be deleted. There is always an objective function.

Note that if you can also delete multiple constraints by a call to resize_lp.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  del_constraint(lp, 1);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also resize_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_constraint, add_constraintex, str_add_constraint

./dimacs_asn.gif000666 000000 000000 00000011147 10425406750 012164 0ustar00000000 000000 GIF87a`*U****U***UU*UUUUU*U*U*UԪ****U**********U*******U*U**UU*U*U*U****U*******U*******U**Ԫ*UU*UUUUUU*U**U*UU*U*U*UUUU*UUUUUUUUUUU*UUUUUUU*UUUUUUU*UUUUԪU*U****U***UU*UUUUU*U*U*UԪԪ*UԪ****U***ԪUU*UUUUUԪ*UԪ*UԪ*UԪ*U****U***UU*UUUUU*UԪԪ*ԪUԪԪԪ*UԪ &&&333???LLLYYYfffrrr𠠤,` H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۩}KnBshWl_y _`&6xc3l__fW2ØiυSw U.Bէ ^tlڣst}pۛcWm ?Yݡ77 :VבK7n0;a..g/W2qY3nvuQ}p1[j ^h!G)ȝRE~a`|E(jtvXt)(4h8<@)DiH|I6Y9)PV9U~XvYז`z)``9RPlSQJĦo֩I|]z}f Z"VYhYFx_V>R袜bjW4kz)٪hm9٬&lKBdԬA z:~6E,tފ,e^{U/nk)?.Ƥ=ۮZ*zV{Y*/⺚, Ǚ0'ZflźNiǨ|\lFz<+粕{2Lˀ\Qn!lE5m,wFP1nnoJB[I/8wyw;x_#ٵZ:2iUXJcmP6oíj yvWmm݃Nw(EE^~RgL1:.:NG-lBYNS':cEH(㎔*"prÙ'7/rя|snG%+v{yϗb?TzN7<ѯ~[II2@&e\x@0\JH Z0& TBX z.^[vZI*usvAI׹ݭnvzν yEZh .|J`\^+ӔlK*;}!\Z<8șnͬ$ ȍvscPzսq%hCBw/+M3wʁIzfӼE;fMzՂ/M}Jz HͰHيJ!2u|XUv[c; }{jsL\bWTuG|efc/W"~]lX&_{N0_T.VnR pw/?%Dr6ȇ{5HbJh|䱵$?Q|/:ŸW.`r|2Rrozʃ6/u~ja.Ҥ톽hArkm׉T!ۙfU^|;1ҥ|lw\Nr~qZÉ_x|ݎh]61Wf]ӓ܌%PϞ i]|(7Dׇ( _n[!Mk >-'~3ch-eiCJf?uU]{˹m ^sѶЅ?)غ+˲:M7/*zˊpJ=軼z4'I[*U4$מ h} [(6k鉇͛ 8ᛗ5K# ۾e;KI; $0<\| ';./DIMACS_asn.htm000666 000000 000000 00000034602 10427370332 011706 0ustar00000000 000000 DIMACS assignment problems

DIMACS assignment problems

DIMACS (Center for Discrete Mathematics and Theoretical Computer Science (see http://dimacs.rutgers.edu/)) has formulated some 'challenges' for some specific problem instances (see http://dimacs.rutgers.edu/Challenges/). One of these challenges is network flows and matching - the first DIMACS implementation challenge.

One of these network flows are assignment problems:

There are a number of agents and a number of tasks. Any agent can be assigned to perform any task, incurring some cost that may vary depending on the agent-task assignment. It is required to perform all tasks by assigning exactly one agent to each task in such a way that the total cost of the assignment is minimized.

Network Structure

  • A network is a directed graph with n nodes and m arcs.
  • Nodes are identified by integers 1...n.
  • Graphs do not have to be symmetric: if an arc (v,w) is in the graph, the reverse arc (w,v) does not have to be in the graph.
  • Parallel arcs are not allowed.
  • Self-loops are not allowed.
  • Arc capacities are 32-bit signed integers.
  • The source and the sink are distinct.
  • The sink may be unreachable from the source.

There is a specific file format available for these kinds of problems:

The following information makes up a DIMACS assignment problem input file:

  • comment lines
  • problem line
  • node descriptors
  • arc descriptors

As noted above, information is collected into lines, which begin with one-character designators. We describe each type of information line in turn.

  1. Comment Lines: Comment lines give human-readable information about the file and are ignored by programs. Comment lines can appear anywhere in the file. Each comment line begins with a lower-case character c.
        c This is an example of a comment line.
  2. Problem Line: There is one problem line per input file. The problem line must appear before any node or arc descriptor lines. For assignment problem instances the problem line has the following format:
        p asn NODES ARCS

    The lower-case character p signifies that this is a problem line. The three-character problem designator asn identifies the file as containing specification information for an assignment problem. The NODES field contains an integer value specifying n, the number of nodes in the network. The ASCS field contains an integer value specifying m, the number of arcs in the network.

  3. Node Descriptors: All node descriptor lines must appear before all arc descriptor lines. For assignment problem instances, the node descriptor lines describe supply nodes. That is, only nodes with nonzero node supply values appear. There is one node descriptor line for each such node, with the following format.
        n ID

    The lower-case character n signifies that this is a node descriptor line. The ID field gives a node identification number, an integer between 1 and n.

  4. Arc Descriptors: There is one arc descriptor line for each arc in the network. For an assignment problem instance, arc descriptor lines are of the following form.
        a SRC DST COST

    The lower-case character a signifies that this is an arc descriptor line. For a directed arc (v,w) the SRC field gives the identification number for the source vertex v, and the DST field gives the destination vertex w. Identification numbers are integers between 1 and n. The COST field contains the per-unit cost of flow sent along arc (v,w).

Input File Example :

Consider the table below which shows the cost of allocating 5 jobs to 5 machines.

         Machine
      6  7  8  9  10
Job 1 22 30 26 16 25
    2 27 29 28 20 32
    3 33 25 21 29 23
    4 24 24 30 19 26
    5 30 33 32 37 31

Which jobs should be allocated to which machines so as to minimise the total cost?

  • each source (job) can supply one unit
  • each sink (machine) demands one unit
  • each arc has a capacity of one unit of flow and a cost taken from the table above.

Assignment model graph

Problems of this type are called assignment problems since they involve the assignment of n (in this case n=5) distinct entities to another n distinct entities. For example in the area of production planning we might be interested in assigning operators to machines, or in assigning operators to jobs, or (as above) in assigning jobs to machines.

c This is a simple example file to demonstrate the DIMACS
c input file format for assignment problems.
c
c Problem line (resources+tasks) (resources*tasks)
p asn 10 25
c
c Node descriptor lines (indeces of assignable resources only)
n 1
n 2
n 3
n 4
n 5
c
c Arc descriptor lines (tasks over each resource and "score")
a 1  6 22
a 1  7 30
a 1  8 26
a 1  9 16
a 1 10 25
a 2  6 27
a 2  7 29
a 2  8 28
a 2  9 20
a 2 10 32
a 3  6 33
a 3  7 25
a 3  8 21
a 3  9 29
a 3 10 23
a 4  6 24
a 4  7 24
a 4  8 30
a 4  9 19
a 4 10 26
a 5  6 30
a 5  7 33
a 5  8 32
a 5  9 37
a 5 10 31
c
c End of file

lp_solve can read/write and solve these models via the xli_DIMACS XLI driver (see External Language Interfaces). It reads such a model in above format and solves it via linear programming. The xli can also generate a DIMACS formatted file.

For example:

lp_solve -rxli xli_DIMACS assignment.net

This gives as result:

Value of objective function: 118

Actual values of the variables:
C1                              1
C2                              0
C3                              0
C4                              0
C5                              0
C6                              0
C7                              0
C8                              0
C9                              1
C10                             0
C11                             0
C12                             0
C13                             1
C14                             0
C15                             0
C16                             0
C17                             1
C18                             0
C19                             0
C20                             0
C21                             0
C22                             0
C23                             0
C24                             0
C25                             1

Also from within the IDE, this XLI can be used. However, some entries must be added in LpSolveIDE.ini (in the folder where the IDE is installed).

In the [XLI] section the following must be added:

lib6=xli_DIMACS

And a new section for the DIMACS XLI must also be added:

[xli_DIMACS]
extension=.net
language=DIMACS

Then make sure that the xli_DIMACS.dll is available for the IDE. This must be done by placing this dll in the IDE folder or in the Windows system32 folder.

Solution :

The solution vector of above example is [1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1]
This must be interpreted as follows:
There are as many variables as there are arc descriptor lines in the input file and they appear in the same order. So:

C1 specifies how much flow there is for the first arc definition, in this case from 1 -> 6
C2 specifies how much flow there is for the second arc definition, in this case from 1 -> 7
...

This means there is a flow from node 1 to 6, a flow from node 2 to 9, a flow from node 3 to 8, a flow from node 4 to 7, a flow from node 5 to 10
This gives a total cost of 22 + 20 + 21 + 24 + 31 = 118
The value of the objective is the cost of the flow: 118

Output :

The solution of the model can also be written in a DIMACS format:

  • comment lines
  • solution lines
  • flow assignments

For each network problem, the solution is an integer-valued flow assignment. The output file should list the solution and flow assignment for all arcs in the graph. As noted above, information is collected into lines, which begin with one-character designators. We describe each type of information line in turn.

  1. Comment Lines: Comment lines give human-readable information about the file and are ignored by programs. Comment lines can appear anywhere in the file. Each comment line begins with a lower-case character c.
        c This is an example of a comment line.
  2. Solution line. The solution line contains the flow value and has the following format:
        s VALUE

    The lower-case character s signifies that this is a solution line. The VALUE field contains the value of the objective.

  3. Flow assignments. There is one flow assignment line for each arc in the input network. These lines have the following format:
        f SRC DST FLOW
    The lower-case character f signifies that this is a flow assignment line. For arc (u,v), the SRC and DST fields give v and w, respectively. The FLOW field gives the amount of flow assigned to arc (u,v).

lp_solve can generate a solution file via the xli_DIMACS XLI driver (see External Language Interfaces).

For example:

lp_solve -rxli xli_DIMACS assignment.net -wxlisol xli_DIMACS assignment.sol

This generates the following solution contents:

c assignment.net
c
c Dimacs-format network assignment result file
c generated by lp_solve
c
c Solution
s 118
c
c SRC DST FLOW
f 1 6 1
f 1 7 0
f 1 8 0
f 1 9 0
f 1 10 0
f 2 6 0
f 2 7 0
f 2 8 0
f 2 9 1
f 2 10 0
f 3 6 0
f 3 7 0
f 3 8 1
f 3 9 0
f 3 10 0
f 4 6 0
f 4 7 1
f 4 8 0
f 4 9 0
f 4 10 0
f 5 6 0
f 5 7 0
f 5 8 0
f 5 9 0
f 5 10 1
c
c End of file

lp_solve can also generate a solution file with only non-zero values.

For example:

lp_solve -rxli xli_DIMACS assignment.net -wxlisol xli_DIMACS assignment.sol -wxlisolopt "-nz"

This generates the following solution contents:

c assignment.net
c
c Dimacs-format network assignment result file
c generated by lp_solve
c
c Solution
s 118
c
c Only non-zero flows are written
c SRC DST FLOW
f 1 6 1
f 2 9 1
f 3 8 1
f 4 7 1
f 5 10 1
c
c End of file

See Also DIMACS minimum cost flow problems, DIMACS maximum flow problems

./dimacs_maxf.gif000666 000000 000000 00000016306 10410001320 012312 0ustar00000000 000000 GIF89a999SSShhhzzzsuT `V! D `p;``O;xH~`; p`p`l D0 ڷb `R@h >H D` Ǥ D| D;B`H Dh} \`  BG Dh}P0B`;Bn[ D[` Dak0gԈ0Ԉ*  D§ D!0 hm hm pj D DkHHZ D)1T`lT`(XF,3H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷p=Kݻx˷߿ ᐃ+^̸c#K8wʖ3k^ysΞCo-"Ҩ Np5k]V({o̭V14TZp ^h#pث^(A@3(z!xݭ;ΞD?~h}T-tEx@T@x0 gנ@0T,^~":`A͉7 D0ߏD'ҷ c!qP dPV``!b,0:7^aO  d$HdB dA5B6f(r|xQ@jrҩ*^T~\e9_rbƊ::1A,-d5z*Ƞ y @f9!j⋞)T1_S2EEp. \7tU\OrZE$:x FAL<I;s[1MӠ̯!$0?P}9b@r6|Ngz?jB,e :jRN!%EǶdwIC2=x ܣLGfɲ{2f %[8=!KY jM,):L2?\*oł 1ќZ-/9:zm}.͖ZDrJRD멏baQXVIAA`*Ɋ)[bOsKHC; ѯv_VgI3ظqR6thO4s"eoNNh9Qa;ly+5KPK<73Sh]8y^n|84XEzK[كlS!遵Kͪ3D3_NW*ev읁ɻ!= UCq0"nŖu4ҳްySlH!x!_L ;<.]뤎G#9F.ri\r;\ vj~Qn^4\'ʆSE 1z e^?;L޶0Hz}闇<[2<'Yc/ ܁r$':=σޔ'G2;jUWh"|Z2Km8w*G2_oINGkDAxB7 Z̷텱V~|(Dh{| mKwN_(gS]Bz|]*yO]q#`KEpGXp'@'CYQQ7KQQG|"<`0~H~S,dW/:wI+hNT6GYeuw}8_ 4G۷l6tF}Ã?XHL؄!=pwV暈GxA^dfIgOR3peWdžkdBDnä|p]xJ=5%GTWVtDg|YbY8+F7buEKoX) VA!s1D'Ud!s(A#8 !>d!3un" b8xAj[5CoEU_D8cs6'@Qe})!2S_0]CBQ[2262/"4%ZU !@Q,5's$D?hx+C4943!It4$av,0b!)l7P!O )x>(I*hP~x3@I&\+arW@5i*A!s4Xc*Ƀ_{'!I$u"0&D. w i\[t\3pq+F&_g+Q2r:=H '+و2d0D0ٗ~f'#1 r&<0 W h3S"I3q@; 3!ɚ;UL(>54<#Џ,6⁔jbr!v):Qٙ1q+Ȝyҹ`6dRI*H!9?J+]"(6뉗6e/)iU!+H)7 %0"@ o`nEa-dBٕ "%,iȸRd4s5 0RxъoȍinHER!dL Uq?idŋlʥfQYcuDҊ6_:T3XmZF#eCe=ÝUd@2{jqb:T|6_8*RDAyb3l SE(S:A!Aaz,77Jz6cX@_vz6ęlvQv`si*\:Έ"&3 s1j1ê%q˺Gф>Y R'ҧRm0[h0H ('7۪9PJ1|풪o [ߖQ?kd!_Dk'`evBb1񦂅oFխfA+Bƺ#5ge\'8r2q:ǚFZ UTk-VtۻȪd8 Dgek~b-tvk+x!_IkȽ1*qhH)H~裃fGԾƾ$;ye%R wv܆>ۨr}$-w>^~ꨞꪾ>^~븞뺾~!0A%0]D6Q1+5R킥W}=Q鼴30q~_n% l7#r4 jb> 3!2Ar^q" #aUi#/P@N#%Bo )ϑe"ug #Dr9T+tgt#P)_"+6? &6b;OI(6!^fGes!{i#Ƒ)WuD{I; e]0=Cc/7nsQݱ $+uJ(66)¹}_LQ[ ~"I"I*@P\)xC"å(L+3cx,U&pJ*-~o'|J@pW_1ksFFO""`?&o3J!M_bv1ݭ' z)*ѕD!C f `Z0:X"*@`H%MDRJ-]SlY4Xس 5@ Ғ",:0i BӃC=KV-¬ln:a > Il{k,sR(1 Dnk-ؑd4(qD/?ViΦ_guӱ2}\p8ߒd FuXsJrPk'Jh9ͫv\Ϋ92S`X0g?hH" ; < cp3*8FZ5Ƣ ><(W$E_1ƒ$Bb. x[+=皫 OZ< n GtAN3q@#C  z;O-ծD 1n$2"83Is;*6eD4QE5̉bDh-R6DK ZkTI)mGdqBGrҸrM5tL0`pk=`)vAY &R cy$LM Ԃ: z/ 6L͑<-b.8OS뀽n@ "_Khtĉ\rʉ}gG_q& +p)Hƀ&.p "LHv}2ul݉ 9I2pi5XHows׾|-HsT]sӕϓ 8K?'ڧ,=bcD CrghI# 2>#ʵB!-Rˬ% /ؠ@(hBҵЅ/j`8CEQ7auCsɐ? 8D"ш8%6щO"pt(yZE.vы_c8F2ьgDcոF6эoc8G:юwcG>яd 9HBҐDd"HF6ґd$%9IJV2;./DIMACS_maxf.htm000666 000000 000000 00000032060 10427367644 012070 0ustar00000000 000000 DIMACS maximum flow problems

DIMACS maximum flow problems

DIMACS (Center for Discrete Mathematics and Theoretical Computer Science (see http://dimacs.rutgers.edu/)) has formulated some 'challenges' for some specific problem instances (see http://dimacs.rutgers.edu/Challenges/). One of these challenges is network flows and matching - the first DIMACS implementation challenge.

One of these network flows are maximum flow problems:

The maximum flow problem is structured on a network. Here the arc capacities, or upper bounds, are the only relevant parameters. The problem is to find the maximum flow possible from some given source node to a given sink node. All arc costs are zero. Since the goal of the optimization is to minimize cost, the maximum flow possible is delivered to the sink node. Applications of this problem include finding the maximum flow of orders through a job shop, the maximum flow of water through a storm sewer system, and the maximum flow of product through a product distribution system, among others.

Network Structure

  • A network is a directed graph with n nodes and m arcs.
  • Nodes are identified by integers 1...n.
  • Graphs do not have to be symmetric: if an arc (v,w) is in the graph, the reverse arc (w,v) does not have to be in the graph.
  • Parallel arcs are not allowed.
  • Self-loops are not allowed.
  • Arc capacities are 32-bit signed integers.
  • The source and the sink are distinct.
  • The sink may be unreachable from the source.

The following information makes up a DIMACS maximum flow input file:

  • comment lines
  • problem line
  • node descriptors
  • arc descriptors

As noted above, information is collected into lines, which begin with one-character designators. We describe each type of information line in turn.

  1. Comment Lines: Comment lines give human-readable information about the file and are ignored by programs. Comment lines can appear anywhere in the file. Each comment line begins with a lower-case character c.
        c This is an example of a comment line.
  2. Problem Line: There is one problem line per input file. The problem line must appear before any node or arc descriptor lines. For maximum flow network instances the problem line has the following format:
        p max NODES ARCS

    The lower-case character p signifies that this is a problem line. The three-character problem designator max identifies the file as containing specification information for a maximum flow problem. The NODES field contains an integer value specifying n, the number of nodes in the network. The ARCS field contains an integer value specifying m, the number of arcs in the network.

  3. Node Descriptors: All node descriptor lines must appear before all arc descriptor lines. Node descriptors are of the form:
        n ID WHICH

    where ID is the node id and WHICH is s for the source and t for the sink. Two node descriptors, one for the source and one for the sink, must appear between the problem line and the arc descriptor lines.

  4. Arc Descriptors: There is one arc descriptor line for each arc in the network. For a maximum flow instance, arc descriptor lines are of the following form.
        a SRC DST CAP

    The lower-case character a signifies that this is an arc descriptor line. For a directed arc (v,w) the SRC field gives the identification number for the source vertex v, and the DST field gives the destination vertex w. Identification numbers are integers between 1 and n. The CAP field gives the arc capacity.

Input File Example :

The example network pictured here is followed by a corresponding DIMACS maximum flow input file.

Maximum Flow model graph

c This is a simple example file to demonstrate the DIMACS
c input file format for maximum flow problems. The solution
c vector is [5,10,5,0,5,5,10,5] with cost at 15.
c Problem line (nodes, links)
p max 6 8
c source
n 1 s
c sink
n 6 t
c Arc descriptor lines (from, to, capacity)
a 1 2 5
a 1 3 15
a 2 4 5
a 2 5 5
a 3 4 5
a 3 5 5
a 4 6 15
a 5 6 5
c
c End of file

lp_solve can read/write and solve these models via the xli_DIMACS XLI driver (see External Language Interfaces). It reads such a model in above format and solves it via linear programming. The xli can also generate a DIMACS formatted file.

For example:

lp_solve -rxli xli_DIMACS maxflow.net

This gives as result:

Value of objective function: 45

Actual values of the variables:
C1                              5
C2                             10
C3                              5
C4                              0
C5                              5
C6                              5
C7                             10
C8                              5

Also from within the IDE, this XLI can be used. However, some entries must be added in LpSolveIDE.ini (in the folder where the IDE is installed).

In the [XLI] section the following must be added:

lib6=xli_DIMACS

And a new section for the DIMACS XLI must also be added:

[xli_DIMACS]
extension=.net
language=DIMACS

Then make sure that the xli_DIMACS.dll is available for the IDE. This must be done by placing this dll in the IDE folder or in the Windows system32 folder.

Solution :

The solution vector of above example is [5, 10, 5, 0, 5, 5, 10, 5]
This must be interpreted as follows:
There are as many variables as there are arc descriptor lines in the input file and they appear in the same order. So:

C1 specifies how much flow there is for the first arc definition, in this case from A -> B
C2 specifies how much flow there is for the second arc definition, in this case from A -> C
...

This means there is a flow of 5 from node A to B, a flow of 10 from node A to C, ...
The value of the objective of lp_solve doesn't give you much information. It is the sum of all variables used.

Output :

The solution of the model can also be written in a DIMACS format:

  • comment lines
  • solution lines
  • flow assignments

For each network problem, the solution is an integer-valued flow assignment. The output file should list the solution and flow assignment for all arcs in the graph. As noted above, information is collected into lines, which begin with one-character designators. We describe each type of information line in turn.

  1. Comment Lines: Comment lines give human-readable information about the file and are ignored by programs. Comment lines can appear anywhere in the file. Each comment line begins with a lower-case character c.
        c This is an example of a comment line.
  2. Solution line. The solution line contains the flow value and has the following format:
        s VALUE

    The lower-case character s signifies that this is a solution line. The VALUE field contains the value of the objective.

  3. Flow assignments. There is one flow assignment line for each arc in the input network. These lines have the following format:
        f SRC DST FLOW
    The lower-case character f signifies that this is a flow assignment line. For arc (u,v), the SRC and DST fields give v and w, respectively. The FLOW field gives the amount of flow assigned to arc (u,v).

lp_solve can generate a solution file via the xli_DIMACS XLI driver (see External Language Interfaces).

For example:

lp_solve -rxli xli_DIMACS maxflow.net -wxlisol xli_DIMACS maxflow.sol

This generates the following solution contents:

c maxflow.net
c
c Dimacs-format maximum flow result file
c generated by lp_solve
c
c Solution
s 15
c
c SRC DST FLOW
f 1 2 5
f 1 3 10
f 2 4 5
f 2 5 0
f 3 4 5
f 3 5 5
f 4 6 10
f 5 6 5
c
c End of file

lp_solve can also generate a solution file with only non-zero values.

For example:

lp_solve -rxli xli_DIMACS maxflow.net -wxlisol xli_DIMACS maxflow.sol -wxlisolopt "-nz"

This generates the following solution contents:

c maxflow.net
c
c Dimacs-format maximum flow result file
c generated by lp_solve
c
c Solution
s 15
c
c Only non-zero flows are written
c SRC DST FLOW
f 1 2 5
f 1 3 10
f 2 4 5
f 3 4 5
f 3 5 5
f 4 6 10
f 5 6 5
c
c End of file

A testset of models can be found at the dimacs ftp site: ftp://dimacs.rutgers.edu/pub/netflow

See Also DIMACS minimum cost flow problems, DIMACS assignment problems

./dimacs_mcf.gif000666 000000 000000 00000015200 10407511334 012135 0ustar00000000 000000 GIF87aFj679:<C:<7.8 !&(-.# rHP$T/% <8L4LGO`xp4'4PT#0|0+!(?|(+ 3*\OverwGrOiXte xi+s!ting f$lSe '/fils/ho%md e/ow7enj$dima cs_m. c.g7f+'pf?$ PT(7+p= a+h!7p0 ah $\uf s7p{X,Fj+(@*\ȰÇ#JHŋ3jȱǏ C9Q  ˗0cʜI͛8s4H@%2pAԃG*]ʴӧPJJիXjʵׯ`ÊKٳhr DȝKݻx˷߿ LÈ+^̸ǐ# ۸3k̹ϠCM]ʖ^ͺװc˞˴sͻȓ+_wjУKN:c瘭kνwؿOyϫ_Ͼ˟O8>( ` & ^.`Vhr^ΖaUvs$F,(b](#sZ"|+6\B{cLFd!)PV)ۓVFKfjX~ٖIEhrfuir H杍cn&֣{j*֧@(a.Zؙ:*)&7d.饜h}miifꨱv ksͪ)+:ŠIl"K> h^.-Բim16-^d"*[).>+[工,r[L ()0Gl҆;mũN|r/3.̩|x C)zu)'ۦnj˜cs<2|i.J]MГBz 2tSKTwh50ge\wג~-e}])bh$vmalv[w.d6)`R6KN]7gɹYyߣXzϱ;ykt{(%:e-6V"/|c7||C)=b1N. =fC8G/6fO)[Þ@/ %!= K3' h,]o4A`B$\M K8Fh* L Qf*"3@T 1u80J91bЮXD *6S܏us3J'թ^JnT9d.YvxNQ::G27dHd|$_"6g"vjhL$rOܑ^:T"FҀuGXzs;2el\>G7C})u X$faY] ,f#Lid!I~!͔&- e3&mi&,x BNxslg0/S=AI)1^EVIjch%-tكLӡ5DEJ5 5i]9̏)ӿH+]D O}#."u%rӆfD!M1%RQd22iR9Ѡn,܅nǒje&?qukU*GCȽK;Zվ54D'WΩVVJR5]XЬTUD ͐~$0I;XԚh5DQal;?["qEGlSzٻ bd^2Ne!r[i jhUKDm;D%1소*%y$RwF;Lڗ0z,cle0xE灅tq:뢸:7d쩵ÿ 8|2b% ۨi<~,%4D6|OR9TS/ * 8c&3ʒܵVEevJ5R&3R&%4ʠc,*%b vs3[GNP:GQpX}=X/Σ5liW&u3e-3]e*;qG~m.5Vmiku}OI-W)yx߬OyyA#zwuJ~`}ܳ]'ybwuĀ31e;M၏y1t~ }p-fY;4hi"44^ZXxrzG]7Y_Ce'c|,2фuNs&VWis.jT7[LOT0L:i".|fh2dXxIW&}s-T}VX~Z\TRo"+i~Vc"tňeDCxs~Ԇ (|b._KDwd(fG~W`x؋X>"^b5o08XX2Sh*}Ŋ!ȈDH]1F0x$YasÉӍw؅1珟DWWȎqcͧiAtW]Œh=ȏ]&@$_9" 1GY uNS G7wR=ÒQ"cxɈ~:Տ63Fk5؂4PY~aEW)J_nWȄ1"ǖ|./RǕW,u)b c}I7nVchG7e/N7T4 mgdn92pܴ<1vk旙w^#yCeٚp9T7gwg0ɛ}|E{sЙGnWkY@%FqEi+י\9sg^3dy7)jI w Yi3]gk),I :9-iݦ%֠QndkeWH)Bi+F5ǝoFXǟr6l#wi]2JB?l=I<'S, :>7᡹ QTSg]K)?TCjn⤑c#7ʥuDƦpNVy%J#Yhtr^ :9ZlަrUgꩇUsPiZ䧳Ƶ^z##?&SBuq$R7r:j1ĬFfHzQ"LsT8+ֵ^[dKdb vfx*ZشLU+KF.n[_xK=&:WFõp[ NAc) "bgkEb)gE˹kVK]Reqk ܕUY &n wN@!a-/n6Ӂ IiPb76ԣYD ÇED;P#cꤽE9Q&7,L񍎤<m4,c'}+/R=p]~mn!&y[v4' VǨ݈-nt6y=MZ.K]u=&'?;r &.޺+}k N5'۩}gD ˿m<_HL{dRi.uC$G>ɤ?EY_+RV|jheN"/5,"%^qWLUTU4 tU]$0WAH ծmJԬӣIśW^e(IP*`2X.UR!S=]rhVGe7g m}0gMeH5s.\𽷉#lu:]u,^'|vݑ{[<\65ݯ^|ͯN_w>@A0B cpB /0C 7.81DG$ KD1EWd[1FgEo1GqG2ȵzH#D "dI'cBxJ+18K/,45dM7߄3N9|N;3O=O?4PA%PCE4:9"@RK`K7SO?5TQG%TSOE5UUWeUW_5VYgV[= ( :VcE6YeeYg6e;./DIMACS_mcf.htm000666 000000 000000 00000034463 10427367414 011706 0ustar00000000 000000 DIMACS minimum cost flow problems

DIMACS minimum cost flow problems

DIMACS (Center for Discrete Mathematics and Theoretical Computer Science (see http://dimacs.rutgers.edu/)) has formulated some 'challenges' for some specific problem instances (see http://dimacs.rutgers.edu/Challenges/). One of these challenges is network flows and matching - the first DIMACS implementation challenge.

One of these network flows are minimum cost flow problems:

Given a directed network with upper and lower capacities on each of its arcs, and given a set of external flows (positive or negative) that need to be routed through this network, find the minimal cost routing of the given flows through this network. Here, the cost per unit of flow on each arc is assumed to be known.

Network Structure

  • A network is a directed graph with n nodes and m arcs.
  • Nodes are identified by integers 1...n.
  • Graphs do not have to be symmetric: if an arc (v,w) is in the graph, the reverse arc (w,v) does not have to be in the graph.
  • Parallel arcs are not allowed.
  • Self-loops are not allowed.
  • Arc capacities are 32-bit signed integers.
  • The source and the sink are distinct.
  • The sink may be unreachable from the source.

There is a specific file format available for these kinds of problems:

The DIMACS minimum-cost flow format requires that bounds on feasible arc flows be integer-valued (the LOW and CAP fields described below). All files contain only ASCII characters with information collected on each line, as described below. A line is terminated with an end-of-line character. Fields in each line are separated by at least one blank space. Each line begins with a one-character designator to identify the line type.

The following information makes up a DIMACS minimum-cost flow input file:

  • comment lines
  • problem line
  • node descriptors
  • arc descriptors

As noted above, information is collected into lines, which begin with one-character designators. We describe each type of information line in turn.

  1. Comment Lines: Comment lines give human-readable information about the file and are ignored by programs. Comment lines can appear anywhere in the file. Each comment line begins with a lower-case character c.
        c This is an example of a comment line.
  2. Problem Line: There is one problem line per input file. The problem line must appear before any node or arc descriptor lines. For minimum-cost flow network instances the problem line has the following format:
        p min NODES ARCS

    The lower-case character p signifies that this is a problem line. The three-character problem designator min identifies the file as containing specification information for a minimum-cost flow problem. The NODES field contains an integer value specifying n, the number of nodes in the network. The ARCS field contains an integer value specifying m, the number of arcs in the network.

  3. Node Descriptors: All node descriptor lines must appear before all arc descriptor lines. For minimum-cost flow instances, the node descriptor lines describe supply and demand nodes, but not transshipment nodes. That is, only nodes with nonzero node supply values appear. There is one node descriptor line for each such node, with the following format.
        n ID FLOW

    The lower-case character n signifies that this is a node descriptor line. The ID field gives a node identification number, an integer between 1 and n. The FLOW field gives the amount of supply at node ID.

  4. Arc Descriptors: There is one arc descriptor line for each arc in the network. For a minimum-cost flow instance, arc descriptor lines are of the following form.
        a SRC DST LOW CAP COST

    The lower-case character a signifies that this is an arc descriptor line. For a directed arc (v,w) the SRC field gives the identification number for the source vertex v, and the DST field gives the destination vertex w. Identification numbers are integers between 1 and n. The LOW field specifies the minimum abount of flow that can be sent along arc (v,w), and the CAP field gives the maximum amount of flow that can be sent along arc (v,w) in a feasible flow. The COST field contains the per-unit cost of flow sent along arc (v,w).

Input File Example :

The example network pictured here is followed by a corresponding DIMACS minimum-cost flow input file. Items listed in the lower-right of the graphic represent fields described above.

Minimum Cost Flow model graph

c This is a simple example file to demonstrate the DIMACS
c input file format for minimum cost flow problems. The solution
c vector is [2,2,2,0,4] with cost at 14.
c
c Problem line (nodes, links)
p min 4 5
c
c Node descriptor lines (supply+ or demand-)
n 1 4
n 4 -4
c
c Arc descriptor lines (from, to, minflow, maxflow, cost)
a 1 2 0 4 2
a 1 3 0 2 2
a 2 3 0 2 1
a 2 4 0 3 3
a 3 4 0 5 1
c
c End of file

lp_solve can read/write and solve these models via the xli_DIMACS XLI driver (see External Language Interfaces). It reads such a model in above format and solves it via linear programming. The xli can also generate a DIMACS formatted file.

For example:

lp_solve -rxli xli_DIMACS mincostflow.net

This gives as result:

Value of objective function: 14

Actual values of the variables:
C1                              2
C2                              2
C3                              2
C4                              0
C5                              4

Also from within the IDE, this XLI can be used. However, some entries must be added in LpSolveIDE.ini (in the folder where the IDE is installed).

In the [XLI] section the following must be added:

lib6=xli_DIMACS

And a new section for the DIMACS XLI must also be added:

[xli_DIMACS]
extension=.net
language=DIMACS

Then make sure that the xli_DIMACS.dll is available for the IDE. This must be done by placing this dll in the IDE folder or in the Windows system32 folder.

Solution :

The solution vector of above example is [2, 2, 2, 0, 4]
This must be interpreted as follows:
There are as many variables as there are arc descriptor lines in the input file and they appear in the same order. So:

C1 specifies how much flow there is for the first arc definition, in this case from 1 -> 2
C2 specifies how much flow there is for the second arc definition, in this case from 1 -> 3
C3 specifies how much flow there is for the third arc definition, in this case from 2 -> 3
C4 specifies how much flow there is for the fourth arc definition, in this case from 2 -> 4
C5 specifies how much flow there is for the fifth arc definition, in this case from 3 -> 4

This means there is a flow of 2 from node 1 to 2, a flow of 2 from node 1 to 3, a flow of 2 from node 2 to 3, a flow of 0 from node 2 to 4 and a flow of 4 from node 3 to 4.
The value of the objective is the cost of the flow: 2 * 2 + 2 * 2 + 2 * 1 + 0 * 3 + 4 * 1 = 14

Output :

The solution of the model can also be written in a DIMACS format:

  • comment lines
  • solution lines
  • flow assignments

For each network problem, the solution is an integer-valued flow assignment. The output file should list the solution and flow assignment for all arcs in the graph. As noted above, information is collected into lines, which begin with one-character designators. We describe each type of information line in turn.

  1. Comment Lines: Comment lines give human-readable information about the file and are ignored by programs. Comment lines can appear anywhere in the file. Each comment line begins with a lower-case character c.
        c This is an example of a comment line.
  2. Solution line. The solution line contains the flow value and has the following format:
        s VALUE

    The lower-case character s signifies that this is a solution line. The VALUE field contains the value of the objective.

  3. Flow assignments. There is one flow assignment line for each arc in the input network. These lines have the following format:
        f SRC DST FLOW
    The lower-case character f signifies that this is a flow assignment line. For arc (u,v), the SRC and DST fields give v and w, respectively. The FLOW field gives the amount of flow assigned to arc (u,v).

lp_solve can generate a solution file via the xli_DIMACS XLI driver (see External Language Interfaces).

For example:

lp_solve -rxli xli_DIMACS mincostflow.net -wxlisol xli_DIMACS mincostflow.sol

This generates the following solution contents:

c mincostflow.net
c
c Dimacs-format minimum cost flow result file
c generated by lp_solve
c
c Solution
s 14
c
c SRC DST FLOW
f 1 2 2
f 1 3 2
f 2 3 2
f 2 4 0
f 3 4 4
c
c End of file

lp_solve can also generate a solution file with only non-zero values.

For example:

lp_solve -rxli xli_DIMACS mincostflow.net -wxlisol xli_DIMACS mincostflow.sol -wxlisolopt "-nz"

This generates the following solution contents:

c mincostflow.net
c
c Dimacs-format minimum cost flow result file
c generated by lp_solve
c
c Solution
s 14
c
c Only non-zero flows are written
c SRC DST FLOW
f 1 2 2
f 1 3 2
f 2 3 2
f 3 4 4
c
c End of file

A testset of models can be found at http://elib.zib.de/pub/Packages/mp-testdata/mincost/
Also see the dimacs ftp site: ftp://dimacs.rutgers.edu/pub/netflow

See Also DIMACS maximum flow problems, DIMACS assignment problems

./distribution.htm000666 000000 000000 00000073370 13772705351 012642 0ustar00000000 000000 lpsolve distributed files

lpsolve distributed files

lpsolve is distributed as several separate archive files. It is most unlikely that you need them all for your purpose. This text describes each archive's contents.

There are two kind of archive files:

  • ziped files (.zip)
  • gziped tar files (.tar.gz)

Ziped files are basically binaries (executables/libraries) for the Windows platform.

gziped tar files can be divided into two categories:

  • binaries (executables, libraries) for the Linux/Mac OSX platform.
  • source files that are operating system independent.

lpsolve library

Most of the links from lpsolve to other software need the lpsolve library lpsolve55.dll (Windows) or lpsolve55.so (Unix/Linux/Mac). This library is in general not included in the archives. It must be installed separately. It is contained in archive lp_solve_5.5.2.11_dev_win*.zip (Windows) / lp_solve_5.5.2.11_dev_ux*.tar.gz (Linux) / lp_solve_5.5.2.11_dev_osx*.tar.gz
This library must be put in a path known by the system. That is:

Under Windows, the following search order is used:

  1. Current directory.
  2. A semi-colon-separated (;) list of directories in the user's PATH environment variable. windows\system32 is a common folder that is normally defined in this environment variable. This folder is a good place to put the dll.

Under Unix/Linux, following search order is used:

  1. A colon-separated (:) list of directories in the user's LD_LIBRARY_PATH environment variable.
  2. The list of libraries specified in /etc/ld.so.cache (which is generated from /etc/ld.so.conf).
  3. /lib, followed by /usr/lib. Note the order here; this is the reverse of the order used by the old a.out loader. The old a.out loader, when loading a program, first searched /usr/lib, then /lib (see the man page ld.so(8)). This shouldn't normally matter, since a library should only be in one or the other directory (never both), and different libraries with the same name are a disaster waiting to happen.

List of archives

Archive Contents See also
Executables
lp_solve_5.5.2.11_IDE_Setup.exe LPSolve IDE (Integrated Development Interface) for Windows.
A user-friendly interface to lpsolve to formulate your model. At this moment only available for Windows.
lp_solve_5.5.2.11_exe_win32.zip 32 bit lp_solve stand-alone program and bfp/xli libraries for Windows.

lp_solve_5.5.2.11_exe_win64.zip 64 bit lp_solve stand-alone program and bfp/xli libraries for Windows.

lp_solve_5.5.2.11_exe_ux32.tar.gz 32 bit lp_solve stand-alone program and bfp/xli libraries for ubuntu linux.

lp_solve_5.5.2.11_exe_ux64.tar.gz 64 bit lp_solve stand-alone program and bfp/xli libraries for ubuntu linux.

lp_solve_5.5.2.11_exe_osx32.tar.gz 32 bit lp_solve stand-alone program and bfp/xli libraries for Mac OSX (Intel).

Libraries
lp_solve_5.5.2.11_dev_win32.zip 32 bit lpsolve libraries for Windows.
The libraries are needed by many of the examples and when you statically or dynamically link the lpsolve library with your application.
lp_solve_5.5.2.11_dev_win64.zip 64 bit lpsolve libraries for Windows.
The libraries are needed by many of the examples and when you statically or dynamically link the lpsolve library with your application.
lp_solve_5.5.2.11_dev_ux32.tar.gz 32 bit lpsolve libraries for ubuntu linux.
The libraries are needed by many of the examples and when you statically or dynamically link the lpsolve library with your application.
lp_solve_5.5.2.11_dev_ux64.tar.gz 64 bit lpsolve libraries for ubuntu linux.
The libraries are needed by many of the examples and when you statically or dynamically link the lpsolve library with your application.
lp_solve_5.5.2.11_dev_osx32.tar.gz 32 bit lpsolve libraries for Mac OSX (Intel based).
The libraries are needed by many of the examples and when you statically or dynamically link the lpsolve library with your application.
Documentation
lp_solve_5.5.2.11_doc.tar.gz lp_solve reference guide in HTML format.
For use under Unix/Linux. Can also be used under Windows, however lp_solve_5.5.2.11.chm is handier under that platform.
http://lpsolve.sourceforge.net/5.5/
lp_solve_5.5.2.11.chm lp_solve reference guide in HTML HELP (Windows) format http://lpsolve.sourceforge.net/5.5/
Sources
lp_solve_5.5.2.11_source.tar.gz lp_solve library & stand-alone program source for all platforms.
lp_solve_5.5.2.11_IDE_source.zip LPSolve IDE (Integrated Development Interface) sources.
BFP packages
lp_solve_5.5.2.11_bfp_etaPFI_source.tar.gz etaPFI BFP source.
Can be compiled under Windows or Linux to generate the etaPFI 2.0 bfp
lp_solve_5.5.2.11_bfp_GLPK_source.tar.gz GLPK BFP source.
Can be compiled under Windows or Linux to generate the GLPK bfp.
lp_solve_5.5.2.11_bfp_LUSOL_source.tar.gz LUSOL BFP source.
Can be compiled under Windows or Linux to generate the LUSOL bfp.
XLI packages
lp_solve_5.5.2.11_xli_MPS_source.tar.gz MPS XLI reader/writer source.
Can be compiled under Windows or Linux to generate the MPS xli interface.

lp_solve_5.5.2.11_xli_CPLEX_source.tar.gz CPLEX XLI reader/writer source.
Can be compiled under Windows or Linux to generate the CPLEX xli interface.

lp_solve_5.5.2.11_xli_Xpress_source.tar.gz Xpress XLI reader/writer source.
Can be compiled under Windows or Linux to generate the Xpress xli interface.

lp_solve_5.5.2.11_xli_LINDO_source.tar.gz LINDO XLI reader/writer source.
Can be compiled under Windows or Linux to generate the LINDO xli interface.
lp_solve_5.5.2.11_xli_LPFML_source.tar.gz LPFML (XML) XLI reader/writer source.
Can be compiled under Windows to generate the XML xli interface.
lp_solve_5.5.2.11_xli_MathProg_source.tar.gz MathProg XLI reader source.
Can be compiled under Windows or Linux to generate the MathProg xli interface. Note that you also need GLPK source to do this.
lp_solve_5.5.2.11_xli_DIMACS_source.tar.gz DIMACS XLI reader/writer source.
Can be compiled under Windows or Linux to generate the DIMACS xli interface.


Call lpsolve from another programming language or environment
lp_solve_5.5.2.11_AMPL_exe_win32.zip 32 bit AMPL lpsolve executable driver for Windows
lp_solve_5.5.2.11_AMPL_exe_ux32.tar.gz 32 bit AMPL lpsolve executable driver for ubuntu linux
lp_solve_5.5.2.11_AMPL_exe_osx32.tar.gz 32 bit AMPL lpsolve executable driver for Mac OSX (Intel)
lp_solve_5.5.2.11_AMPL_source.tar.gz AMPL lpsolve driver source
lp_solve_5.5.2.11_c.tar.gz example calling lp_solve API from C.
A starting point if you want to use the lpsolve API from C.
lp_solve_5.5.2.11_COM.zip lpsolve COM object (COM interface to lpsolve55 dll) + VB example
A COM interface to the lpsolve API
lp_solve_5.5.2.11_Delphi.zip example calling lp_solve API from Delphi.
A starting point if you want to use the lpsolve API from Delphi/Pascal.
lp_solve_5.5.2.11_access.zip example calling lp_solve API from Access.
A starting point if you want to use the lpsolve API from Access.
lp_solve_5.5.2.11_excel.zip example calling lp_solve API from EXCEL.
A starting point if you want to use the lpsolve API from EXCEL.
lp_solve_5.5.2.11_java.zip java wrapper for lpsolve, java documentation and examples
lp_solve_5.5.2.11_MATLAB_exe_win32.zip 32 bit MATLAB driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_MATLAB_exe_win64.zip 64 bit MATLAB driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_MATLAB_exe_ux32.tar.gz 32 bit MATLAB driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_MATLAB_exe_ux64.tar.gz 64 bit MATLAB driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_MATLAB_exe_osx32.tar.gz 32 bit MATLAB driver to lpsolve for Mac OSX (Intel) and examples
lp_solve_5.5.2.11_MATLAB_source.tar.gz MATLAB driver source to lpsolve with examples
lp_solve_5.5.2.11_OMATRIX_exe_win32.zip 32 bit O-MATRIX driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_OMATRIX_source.tar.gz O-MATRIX driver source to lpsolve with examples
lp_solve_5.5.2.11_Sysquake_exe_win32.zip 32 bit Sysquake driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_Sysquake_exe_ux32.tar.gz 32 bit Sysquake driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_Sysquake_exe_osx32.tar.gz 32 bit Sysquake driver to lpsolve for Mac OSX (Intel) and examples
lp_solve_5.5.2.11_Sysquake_source.tar.gz Sysquake driver source to lpsolve with examples
lp_solve_5.5.2.11_scilab_exe_win32.zip 32 bit Scilab driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_scilab_exe_win64.zip 64 bit Scilab driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_scilab_exe_ux32.tar.gz 32 bit Scilab driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_scilab_exe_ux64.tar.gz 64 bit Scilab driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_scilab_exe_osx32.tar.gz 32 bit Scilab driver to lpsolve for Mac OSX (Intel) and examples
lp_solve_5.5.2.11_scilab_source.tar.gz Scilab driver source to lpsolve with examples
lp_solve_5.5.2.11_octave_exe_win32.zip 32 bit octave driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_octave_exe_ux32.tar.gz 32 bit octave driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_octave_exe_ux64.tar.gz 64 bit octave driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_octave_exe_osx32.tar.gz 32 bit octave driver to lpsolve for Mac OSX (Intel) and examples
lp_solve_5.5.2.11_octave_source.tar.gz octave driver source to lpsolve with examples
lp_solve_5.5.2.11_FreeMat_exe_win32.zip 32 bit FreeMat driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_FreeMat_exe_ux32.tar.gz 32 bit FreeMat driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_FreeMat_exe_ux64.tar.gz 64 bit FreeMat driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_FreeMat_exe_osx32.tar.gz 32 bit FreeMat driver to lpsolve for Mac OSX (Intel) and examples
lp_solve_5.5.2.11_FreeMat_source.tar.gz FreeMat driver source to lpsolve with examples
lp_solve_5.5.2.11_Euler_exe_win32.zip Euler driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_Euler_source.tar.gz Euler driver source to lpsolve with examples
lp_solve_5.5.2.11_Python2.4_exe_win32.zip 32 bit Python 2.4 driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_Python2.5_exe_win32.zip 32 bit Python 2.5 driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_Python2.6_exe_win32.zip 32 bit Python 2.6 driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_Python2.6_exe_win64.zip 64 bit Python 2.6 driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_Python2.5_exe_ux32.tar.gz 32 bit Python 2.5 driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_Python2.5_exe_ux64.tar.gz 64 bit Python 2.5 driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_Python2.3_exe_osx32.tar.gz 32 bit Python 2.5 driver to lpsolve for Mac OSX (Intel) and examples
lp_solve_5.5.2.11_Python_source.tar.gz Python driver source to lpsolve with examples
lp_solve_5.5.2.11_PHP_exe_win32.zip 32 bit PHP driver to lpsolve for Windows and examples
lp_solve_5.5.2.11_PHP_exe_ux32.tar.gz 32 bit PHP driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_PHP_exe_ux64.tar.gz 64 bit PHP driver to lpsolve for ubuntu linux and examples
lp_solve_5.5.2.11_PHP_source.tar.gz PHP driver source to lpsolve with examples
lp_solve_5.5.2.11_MSF_exe_win32.zip 32 bit MSF driver to lpsolve for Windows
lp_solve_5.5.2.11_MSF_source.zip MSF driver source to lpsolve
lp_solve_5.5.2.11_MSF_demo.zip MSF demo to lpsolve
lp_solve_5.5.2.11_cs.net.zip example calling lp_solve API from C#.
A starting point if you want to use the lpsolve API from C# (.NET).
lp_solve_5.5.2.11_vb.net.zip example calling lp_solve API from VB.NET.
A starting point if you want to use the lpsolve API from VB.NET).
lp_solve_5.5.2.11_vb.zip example calling lp_solve API from VB6.
A starting point if you want to use the lpsolve API from VB6.
./download.htm000666 000000 000000 00000001416 11246753120 011711 0ustar00000000 000000 Download

Download

All needed files can be downloaded from sourceforge on the following location: http://sourceforge.net/projects/lpsolve/

./dualize_lp.htm000666 000000 000000 00000004067 10310576304 012235 0ustar00000000 000000 dualize_lp

dualize_lp

Create the dual of the current model.

unsigned char dualize_lp(lprec *lp);

Return Value

Returns TRUE if succeeded.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /*
  .
  .
  .
  */

  dualize_lp(lp);

  /*
  .
  .
  .
  */

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, delete_lp, free_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

./Euler.htm000666 000000 000000 00000341105 13772705351 011171 0ustar00000000 000000 Using lpsolve from Euler

Using lpsolve from Euler

Euler?

The Euler Mathematical Toolbox is a powerful, versatile, and open source software for numerical and symbolic computations written and maintained by R. Grothmann from the University of Eichsttt. Euler is similar to MATLAB, but uses an own style and an own syntax. Euler supports symbolic mathematics using the open algebra system Maxima.

The most recent version of Euler runs in Windows (98/XP/Vista), or under Linux in Wine. The native Linux version is currently outdated.

We will not discuss the specifics of Euler here but instead refer the reader to the Euler website.

Euler and lpsolve

lpsolve is callable from Euler via a dynamic linked DLL function. As such, it looks like lpsolve is fully integrated with Euler. Matrices can directly be transferred between Euler and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for Euler (especially for matrix support). So you have full control to the complete lpsolve functionality via the eulpsolve Euler driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level Euler files that can make things a lot easier. See further in this article.

Quickstart

Compile and build eulpsolve:
----------------------------

1. Under Windows, the Microsoft Visual C/C++ compiler must be installed
   and the environment variables must be active do that when a command prompt
   is opened, the cl and nmake commands can be executed.

2. Go to directory lp_solve_5.5\extra\Euler

3. Edit cvc.bat and change the path of the Eulerpath environment variable to your path.

4. To compile and build eulpsolve, enter the following command:
      cvc

Load the eulpsolve driver in the Euler memory space:
-------------------------------------------------------

1. Under Windows, make sure that the lpsolve55.dll file is somewhere in the path
   (archive lp_solve_5.5.2.11_dev.zip)

2. A precompiled library is provided for Windows (eulpsolve.dll).

3. Start Euler

4. Enter the following command in Euler:
      >dll("<path>/eulpsolve.dll", "eulpsolve", -1)

      Or if this fails (because you use version an Euler version 7.0 or older):

      >dll("<path>/eulpsolve.dll", "eulpsolve", 0)
      >dll("<path>/eulpsolve.dll", "eulpsolve", 1);
      >dll("<path>/eulpsolve.dll", "eulpsolve", 2);
      >dll("<path>/eulpsolve.dll", "eulpsolve", 3);
      >dll("<path>/eulpsolve.dll", "eulpsolve", 4);
      >dll("<path>/eulpsolve.dll", "eulpsolve", 5);
      >dll("<path>/eulpsolve.dll", "eulpsolve", 6);
      >dll("<path>/eulpsolve.dll", "eulpsolve", 7);
   For <path> use the path where the eulpsolve.dll is located.
   These commands can be put in a file, for example loadlpsolve.en, with a regular editor like notepad.
   They can then be opened as a notebook in Euler and executed.

Euler is ideally suited to handle linear programming problems. These are problems in which you have a quantity, depending linearly on several variables, that you want to maximize or minimize subject to several constraints that are expressed as linear inequalities in the same variables.If the number of variables and the number of constraints are small, then there are numerous mathematical techniques for solving a linear programming problem. Indeed these techniques are often taught in high school or university level courses in finite mathematics.But sometimes these numbers are high, or even if low, the constants in the linear inequalities or the object expression for the quantity to be optimized may be numerically complicated in which case a software package like Euler is required to effect a solution.

Installation

To make this possible, a driver program is needed: eulpsolve (eulpsolve.dll under Windows). This driver must be loaded in Euler and Euler can call the eulpsolve solver.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows). This has the advantage that the eulpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the Windows path.

So note the difference between the Euler lpsolve driver that is called eulpsolve and the lpsolve library that implements the API that is called lpsolve55.

There are also some Euler notebooks (.en) as a quick start.

The first thing that must be done, each time Euler is restarted and you want to use lpsolve is load the eulpsolve driver into the Euler workspace. This is done via the dll command. Suppose that eulpsolve.dll is installed in c:\Program Files\Euler\dll, then the following command must be used to load the driver:

>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", -1)

Note that this command is only accepted from Euler version 7.1 or newer. On older Euler versions, -1 is not accepted on the third argument. There is however a work-around for this. You can then use the following commands (all together):

>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 0)
>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 1);
>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 2);
>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 3);
>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 4);
>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 5);
>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 6);
>dll("c:/Program Files/Euler/dll/eulpsolve.dll", "eulpsolve", 7);

These commands can be put in a file, for example loadlpsolve.en or loadlpsolve.e, with a regular editor like notepad. The .en file can then be opened as a notebook in Euler and executed. The .e file can be loaded and executed via the load statement.

That is basically all you need to do. From now on, you can use the library. This until Euler is restarted. Then this command must be given again to reload the library.

To test if everything is installed correctly, enter eulpsolve(); in the Euler command prompt. If it gives the following, then everything is ok:

>eulpsolve();
eulpsolve Euler Interface version 5.5.0.7
using lpsolve version 5.5.2.11

Usage: [ret1, ret2, ...] = eulpsolve("functionname", arg1, arg2, ...)

However, if you get a message box with the following:

eulpsolve no function or variable, or wrong argument number!

Then either the dll command that was previous given was unsuccessful (or not given at all) or something was misspelled after the ,

Check the dll command again. If it gives a message box with the following message:

---------------------------
euler.exe - Unable To Locate Component
---------------------------
This application has failed to start because lpsolve55.dll was not found. Re-installing the application may fix this problem.
---------------------------
OK
---------------------------

And then in Euler:

 Could not open the DLL library!
 Could not find the function!
 error in :
 dll("<path>/eulpsolve.dll", "eulpsolve", 0)

Then Euler can find the eulpsolve driver program, but the driver program cannot find the lpsolve library that contains the lpsolve implementation. This library is called lpsolve55.dll and should be on your system in a directory that in the PATH environment variable. This path can be shown via the command line command PATH.

The lpsolve55.dll files must be in one of these specified directories. It is common to place this in the WINDOWS\system32 folder.

If the message in Euler is shown without a message box of a missing lpsolve55.dll file then eulpsolve.dll cannot be found.

All this is developed and tested with Euler versions 7.0 and 7.1 beta. This is the minimum supported release. Older releases are unsupported. Only from version 7.1 on, it is possible to print something in the Euler window from the external library. So on older versions, when something must be printed, it will be shown in a messagebox. If you are working with a lower version than 7.1 it is best that the verbose level of the set_verbose API call is less than or equal to 3. Otherwise too much messageboxes will be given and it is unpractical to work with this. If you need this verbose level, then use at least version 7.1

Solve an lp model from Euler via eulpsolve

In the following text, > before the Euler commands is the Euler command line. Only the text after > must be entered.

To call an lpsolve function, the following syntax must be used:

>{ret1, ret2, ...} = eulpsolve("functionname", arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between double quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra Euler specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in Euler, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the Euler functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from Euler, nothing must be dimensioned in advance. The eulpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to eulpsolve. Never as argument to the routine. This can be a single value as for get_objective (although Euler stores this in a 1x1 matrix) or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

An example

(Note that you can execute this example by entering command per command as shown below or by opening and executing notebook example1.en)

>lp=eulpsolve("make_lp", 0, 4);
>eulpsolve("set_verbose", lp, 3);
>eulpsolve("set_obj_fn", lp, [1, 3, 6.24, 0.1]);
>eulpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], 2, 92.3);
>eulpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);
>eulpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], 2, 4);
>eulpsolve("set_lowbo", lp, 1, 28.6);
>eulpsolve("set_lowbo", lp, 4, 18);
>eulpsolve("set_upbo", lp, 4, 48.98);
>eulpsolve("set_col_name", lp, 1, "COLONE");
>eulpsolve("set_col_name", lp, 2, "COLTWO");
>eulpsolve("set_col_name", lp, 3, "COLTHREE");
>eulpsolve("set_col_name", lp, 4, "COLFOUR");
>eulpsolve("set_row_name", lp, 1, "THISROW");
>eulpsolve("set_row_name", lp, 2, "THATROW");
>eulpsolve("set_row_name", lp, 3, "LASTROW");
>eulpsolve("write_lp", lp, "a.lp");
>eulpsolve("get_mat", lp, 1, 2)

                 78.26

>eulpsolve("solve", lp)

                     0

>eulpsolve("get_objective", lp)

        31.78275862069

>eulpsolve("get_variables", lp)

                  28.6
                     0
                     0
         31.8275862069

>eulpsolve("get_constraints", lp)

                  92.3
                 6.864
        391.2928275862

Note that there are some commands that return an answer. To see the answer, the command was not terminated with a semicolon (;). If the semicolon is put at the end of a command, the answer is not shown. However it is also possible to write the answer in a variable. For example:

>obj=eulpsolve("get_objective", lp)

        31.78275862069

Or:

>obj=eulpsolve("get_objective", lp);

Both will write the result in variable obj. Without the semicolon, the result is also shown on screen. get_variables and get_constraints return a vector with the result. This can also be put in a variable:

>x=eulpsolve("get_variables", lp);
>b=eulpsolve("get_constraints", lp);

It is always possible to show the contents of a variable by just giving it as command:

>x

                  28.6
                     0
                     0
         31.8275862069

Don't forget to free the handle and its associated memory when you are done:

>eulpsolve("delete_lp", lp);

Note that for larger and/or complex models, solving time can be long. If this must be interrupt then the ESC key can be pressed. Euler shows this also in the status bar. lp_solve checks regularly if this key is pressed and if so, solve is interrupted. If verbose level is set then this is also shown on screen. Anyway, the return status will indicate that solve was aborted.

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
>lp=eulpsolve("make_lp", 0, 4);
>eulpsolve("set_lp_name", lp, "mymodel");
>eulpsolve("set_verbose", "mymodel", 3);
>eulpsolve("set_obj_fn", "mymodel", [1, 3, 6.24, 0.1]);
>eulpsolve("add_constraint", "mymodel", [0, 78.26, 0, 2.9], 2, 92.3);
>eulpsolve("add_constraint", "mymodel", [0.24, 0, 11.31, 0], 1, 14.8);
>eulpsolve("add_constraint", "mymodel", [12.68, 0, 0.08, 0.9], 2, 4);
>eulpsolve("set_lowbo", "mymodel", 1, 28.6);
>eulpsolve("set_lowbo", "mymodel", 4, 18);
>eulpsolve("set_upbo", "mymodel", 4, 48.98);
>eulpsolve("set_col_name", "mymodel", 1, "COLONE");
>eulpsolve("set_col_name", "mymodel", 2, "COLTWO");
>eulpsolve("set_col_name", "mymodel", 3, "COLTHREE");
>eulpsolve("set_col_name", "mymodel", 4, "COLFOUR");
>eulpsolve("set_row_name", "mymodel", 1, "THISROW");
>eulpsolve("set_row_name", "mymodel", 2, "THATROW");
>eulpsolve("set_row_name", "mymodel", 3, "LASTROW");
>eulpsolve("write_lp", "mymodel", "a.lp");
>eulpsolve("get_mat", "mymodel", 1, 2)

                 78.26

>eulpsolve("solve", "mymodel")

                     0

>eulpsolve("get_objective", "mymodel")

        31.78275862069

>eulpsolve("get_variables", "mymodel")

                  28.6
                     0
                     0
         31.8275862069

>eulpsolve("get_constraints", "mymodel")

                  92.3
                 6.864
        391.2928275862

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific Euler routine to get the handle from the model name: get_handle.
For example:

>eulpsolve("get_handle", "mymodel")

                     0

Don't forget to free the handle and its associated memory when you are done:

>eulpsolve("delete_lp", "mymodel");

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

In Euler, all numerical data is stored in matrices; even a scalar variable. Euler also supports complex numbers. eulpsolve can only work with real numbers. For example:
>eulpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);

Most of the time, variables are used to provide the data:

>eulpsolve("add_constraint", lp, a1, 1, 14.8);

Where a1 is a matrix variable.

Matrices with too few or too much elements gives an 'invalid vector.' error.

Most of the time, eulpsolve needs vectors (rows or columns). In all situations, it doesn't matter if the vectors are row or column vectors. The driver accepts them both. For example:

>eulpsolve("add_constraint", lp, [0.24; 0; 11.31; 0], 1, 14.8);

Which is a column vector, but it is also accepted.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the Euler interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the Euler matrix.

Maximum usage of matrices with eulpsolve

Because Euler is all about matrices, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the eulpsolve Euler driver to also work with matrices. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The eulpsolve Euler driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = eulpsolve("set_int", lp, column, must_be_int). The matrix version of this call is: return = eulpsolve("set_int", lp, [must_be_int]). The API call to return the integer status of a variable is: return = eulpsolve("is_int", lp, column). The matrix version of this call is: [is_int] = eulpsolve("is_int", lp)
Also note the get_mat and set_mat routines. In Euler these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by opening and executing notebook example2.en)

>lp=eulpsolve("make_lp", 0, 4);
>eulpsolve("set_verbose", lp, 3);
>eulpsolve("set_obj_fn", lp, [1, 3, 6.24, 0.1]);
>eulpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], 2, 92.3);
>eulpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);
>eulpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], 2, 4);
>eulpsolve("set_lowbo", lp, [28.6, 0, 0, 18]);
>eulpsolve("set_upbo", lp, [1.0e30, 1.0e30, 1.0e30, 48.98]);
>eulpsolve("set_col_name", lp, 1, "COLONE");
>eulpsolve("set_col_name", lp, 2, "COLTWO");
>eulpsolve("set_col_name", lp, 3, "COLTHREE");
>eulpsolve("set_col_name", lp, 4, "COLFOUR");
>eulpsolve("set_row_name", lp, 1, "THISROW");
>eulpsolve("set_row_name", lp, 2, "THATROW");
>eulpsolve("set_row_name", lp, 3, "LASTROW");
>eulpsolve("write_lp", lp, "a.lp");
>eulpsolve("get_mat", lp)

                     0               78.26                   0                 2.9
                  0.24                   0               11.31                   0
                 12.68                   0                0.08                 0.9

>eulpsolve("solve", lp)

                     0

>eulpsolve("get_objective", lp)

        31.78275862069

>eulpsolve("get_variables", lp)

                  28.6
                     0
                     0
         31.8275862069

>eulpsolve("get_constraints", lp)

                  92.3
                 6.864
        391.2928275862

Note the usage of 1.0e30 in set_upbo. This stands for "infinity". Meaning an infinite upper bound. It is also possible to use -1.0e30 to express minus infinity. This can for example be used to create a free variable.

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example:

>A=eulpsolve("get_mat", lp);
>X=eulpsolve("get_variables", lp);
>B = A . X

                  92.3
                 6.864
        391.2928275862

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

>eulpsolve("get_constraints", lp)

                  92.3
                 6.864
        391.2928275862

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

>C=eulpsolve("get_obj_fn", lp);
>X=eulpsolve("get_variables", lp);
>obj = C . X

        31.78275862069

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

>eulpsolve("get_objective", lp)

        31.78275862069

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
>lp=eulpsolve("make_lp", 0, 4);
>eulpsolve("set_verbose", lp, 3);
>eulpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], 2, 92.3);
>eulpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);
>eulpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], 2, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One could define all the possible constants in Euler and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

>lp=eulpsolve("make_lp", 0, 4);
>eulpsolve("set_verbose", lp, "IMPORTANT");
>eulpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], "GE", 92.3);
>eulpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], "LE", 14.8);
>eulpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], "GE", 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

>eulpsolve("set_verbose", lp, "blabla");

  eulpsolve returned an error:
  BLABLA: Unknown.

>eulpsolve("set_verbose", lp, "GE");

  eulpsolve returned an error:
  GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. "LE", "GE" and "EQ" in add_constraint and is_constr_type can also be "<", "<=", ">", ">=", "=". When returned however, "GE", "LE", "EQ" will be used.

Some constants can be a combination of multiple constants. For example set_scaling:

>eulpsolve("set_scaling", lp, 3+128);

With the string version of constants this can be done as following:

>eulpsolve("set_scaling", lp, "SCALE_MEAN|SCALE_INTEGERS");

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

>eulpsolve("set_scaling", lp, "SCALE_MEAN|SCALE_RANGE");

  eulpsolve returned an error:
  SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

>eulpsolve("get_scaling", lp)
                  131

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

>eulpsolve("return_constants", 1);

From now on, all returned constants are returned as string:

>eulpsolve("get_scaling", lp)
  SCALE_MEAN|SCALE_INTEGERS

This for all routines until return_constants is again called with 0:

>eulpsolve("return_constants", 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

>eulpsolve("return_constants", 1)
                    1

To get the value without setting it, don't provide the second argument:

>eulpsolve("return_constants")
                    1

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

Notebooks and Euler files

Euler can execute a sequence of statements stored in files. There are two types. Notebooks and Euler files.

Notebooks contains a number of Euler statements that are stored in a file. They should have the extension *.en and are first loaded in the text window of Euler and then executed. There are some notebook examples with the distribution of lpsolve.

Euler files. If you want to develop longer and more complicated programs, it becomes useful to put all function definitions and all commands into external Euler files. These files should have the extension *.e, and can be loaded into Euler with the load command. Files in the current directory will be found using the name alone. The current directory is the directory, where the current notebook is loaded from or saved to. Otherwise, use the full path the file, or include the directory of the file into the Euler path. Euler files often contain support functions (subroutines) that can be used in your code.

You can also edit these files with your favourite text editor (or notepad).

loadlpsolve.en

Loads the eulpsolve driver in Euler. Also loads Euler files lpsolve.e and lpmaker.e. See further for their usage.

To execute and also see which commands are executed in the debug window, use following commands:

File, Open notebook...
Open loadlpsolve.en
File, Run all Commands in this Notebook

example1.en

Contains the commands as shown in the first example of this article.

example2.en

Contains the commands as shown in the second example of this article.

example3.en

Contains the commands of a practical example. See further in this article.

example4.en

Contains the commands of a practical example. See further in this article.

example5.en

Contains the commands of a practical example. See further in this article.

example6.en

Contains the commands of a practical example. See further in this article.

lpsolve.e

This Euler file uses the API to create a higher-level function called lpsolve. This function accepts as arguments some matrices and options to create and solve an lp model. See the beginning of the file or enter help lpsolve to see its usage:

>load "lpsolve"
>help lpsolve
 LPSOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: {obj,x,duals} = lpsolve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'.x
                a.x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

>load "lpsolve"
>{obj, x}=lpsolve([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2]);
>obj

                     3

>x

                     1
                     2

lpmaker.e

This Euler file is analog to the lpsolve Euler file and also uses the API to create a higher-level function called lpmaker. This function accepts as arguments some matrices and options to create an lp model. Note that this Euler file only creates a model and returns a handle. See the beginning of the file or enter help lpmaker to see its usage:

>load "lpmaker"
>help lpmaker
 LPMAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lpmaker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'.x
          a.x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

>load "lpmaker"
>lp=lpmaker([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])

                     0

To solve the model and get the solution:

>eulpsolve("solve", lp)

                     0

>eulpsolve("get_objective", lp)

                     3

>eulpsolve("get_variables", lp)

                     1
                     2

Don't forget to free the handle and its associated memory when you are done:

>eulpsolve("delete_lp", lp);

lpdemo.en

Contains several examples to build and solve lp models.

ex.en

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

>X = 0.1:0.05:125;
>Y1 = (15000. - 120*X)/210;
>plot2d(X,Y1,bar=1);
>insimg;

Source

Now let's put in the other two constraint inequalities.

>X = 0.1:0.05:38;
>Y1 = (15000. - 120*X)/210;
>Y2 = max((4000 - 110.*X)./30, 0);
>Y3 = max(75 - X, 0.);
>Ytop = min(min(Y1, Y2), Y3);
>plot2d(X,Ytop,bar=1);
>insimg;

Source

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.

>X = 0.1:0.05:38;
>Y1 = (15000. - 120*X)/210;
>Y2 = max((4000 - 110.*X)./30, 0);
>Y3 = max(75 - X, 0.);
>Ytop = min(min(Y1, Y2), Y3);
>plot2d(X,Ytop,bar=1);
>n=(1000:1000:9000)';
>plot2d("(n-143*x)/60", add=1, color=2);
>insimg;

Source

The red 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 lp_solve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:

>x = [1 1; 110 30] \ [75; 4000]

                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 60] . x

              6315.625

That is, $6315.625.

Note that these command are in notebook example3.en

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level Euler file lpmaker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lpmaker:

 LPMAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lpmaker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'.x
          a.x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

>f = [143, 60];
>A = [120, 210; 110, 30; 1, 1];
>b = [15000; 4000; 75];
>lp = lpmaker(f, A, b, [-1, -1, -1], [], [], [], 1, 0);
>solvestat = eulpsolve("solve", lp);
>eulpsolve("get_objective", lp)

              6315.625

>eulpsolve("get_variables", lp)

                21.875
                53.125

>eulpsolve("delete_lp", lp);

Note that these command are in notebook example4.en

With the higher-level Euler file lpmaker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimentions, but beyound that it is all very theorethical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

>f = [143, 60, 195];
>A = [120, 210, 150.75; 110, 30, 125; 1, 1, 1];
>b = [15000; 4000; 75];
>lp = lpmaker(f, A, b, [-1, -1, -1], [], [], [], 1, 0);
>solvestat = eulpsolve("solve", lp);
>eulpsolve("get_objective", lp)

        6986.842105263

>eulpsolve("get_variables", lp)

                     0
        56.57894736842
        18.42105263158

>eulpsolve("delete_lp", lp);

Note that these command are in notebook example5.en

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that Euler can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like Euler is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
>f = [110*1.3, 30*2.0, 125*1.56, 75*1.8, 95*.95, 100*2.25, 50*1.35];
>A = [120,210,150.75,115,186,140,85; 110,30,125,75,95,100,50; 1,1,1,1,1,1,1; 1,-1,0,0,0,0,0; 0,0,1,0,-2,0,0; 0,0,0,-1,0,-1,1];
>b = [55000; 40000; 400; 0; 0; 0];
>lp = lpmaker(f, A, b, [-1,-1,-1,-1,-1,-1],[10,10,10,10,20,20,20],[100,1.0e30,50,1.0e30,1.0e30,250,1.0e30],[],1,0);
>solvestat = eulpsolve("solve", lp);
>eulpsolve("get_objective", lp)

        75398.04347826

>eulpsolve("get_variables", lp)

                    10
                    10
                    40
        45.65217391304
                    20
                   250
                    20

>eulpsolve("delete_lp", lp);

Note that these command are in notebook example6.en

Note that we have used in this formulation the vlb and vub arguments of lpmaker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that Inf is used for variables that have no upper limit. This stands for Infinity.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using Euler:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into Euler format we get:

f = [4, 2, 1]
A = [2, 1, 0; 1, 0, 2; 1, 1, 1]
b = [1; 2; 1]

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0, 0, 0]
u = [ 1, 1, 2]

Now lets enter this in Euler:

>f = [4, 2, 1];
>A = [2, 1, 0; 1, 0, 2; 1, 1, 1];
>b = [1; 2; 1];
>l = [ 0, 0, 0];
>u = [ 1, 1, 2];

Now solve the linear program using Euler: Type the commands

>lp = lpmaker(f, A, b, [-1, -1, -1], l, u, [], 1, 0);
>solvestat = eulpsolve("solve", lp);
>eulpsolve("get_objective", lp)

                   2.5

>eulpsolve("get_variables", lp)

                   0.5
                     0
                   0.5

>eulpsolve("delete_lp", lp);

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the Euler command:

>l = [];

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -1.0e30 as lower bounds:

>l = [-1.0e30, -1.0e30, -1.0e30];

Solve this and you get a different result:

>lp = lpmaker(f, A, b, [-1, -1, -1], l, u, [], 1, 0);
>solvestat = eulpsolve("solve", lp);
>eulpsolve("get_objective", lp)

        2.666666666667

>eulpsolve("get_variables", lp)

       0.6666666666667
      -0.3333333333333
       0.6666666666667

>eulpsolve("delete_lp", lp);

Overview of API routines

Note that everwhere where lp is used as argument that this can be a handle (lp_handle) or the models name.

  • add_column, add_columnex
    • return = eulpsolve("add_column", lp, [column])
    • return = eulpsolve("add_columnex", lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = eulpsolve("add_constraint", lp, [row], constr_type, rh)
    • return = eulpsolve("add_constraintex", lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = eulpsolve("add_SOS", lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in Euler since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = eulpsolve("column_in_lp", lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = eulpsolve("copy_lp", lp)
    • No special considerations.
  • default_basis
    • eulpsolve("default_basis", lp)
    • No special considerations.
  • del_column
    • return = eulpsolve("del_column", lp, column)
    • No special considerations.
  • del_constraint
    • return = eulpsolve("del_constraint", lp, del_row)
    • No special considerations.
  • delete_lp
    • eulpsolve("delete_lp", lp)
    • No special considerations.
  • free_lp
    • eulpsolve("free_lp", lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = eulpsolve("get_anti_degen", lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = eulpsolve("get_basis", lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in Euler. If not provided, then 0 is used.
  • get_basiscrash
    • return = eulpsolve("get_basiscrash", lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = eulpsolve("get_bb_depthlimit", lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = eulpsolve("get_bb_floorfirst", lp)
    • No special considerations.
  • get_bb_rule
    • return = eulpsolve("get_bb_rule", lp)
    • No special considerations.
  • get_bounds_tighter
    • return = eulpsolve("get_bounds_tighter", lp)
    • No special considerations.
  • get_break_at_value
    • return = eulpsolve("get_break_at_value", lp)
    • No special considerations.
  • get_col_name
    • name = eulpsolve("get_col_name", lp, column)
    • column must be provided and is as such not optional. As such no array of names can be returned. This because Euler has no possibility to return string matrices.
  • get_column get_columnex
    • [column, return] = eulpsolve("get_column", lp, col_nr)
    • [column, return] = eulpsolve("get_columnex", lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = eulpsolve("get_constr_type", lp, row)
    • [constr_type] = eulpsolve("get_constr_type", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_constr_value
    • return = eulpsolve("get_constr_value", lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = eulpsolve("get_constraints", lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = eulpsolve("get_dual_solution", lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Euler, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = eulpsolve("get_epsb", lp)
    • No special considerations.
  • get_epsd
    • return = eulpsolve("get_epsd", lp)
    • No special considerations.
  • get_epsel
    • return = eulpsolve("get_epsel", lp)
    • No special considerations.
  • get_epsint
    • return = eulpsolve("get_epsint", lp)
    • No special considerations.
  • get_epsperturb
    • return = eulpsolve("get_epsperturb", lp)
    • No special considerations.
  • get_epspivot
    • return = eulpsolve("get_epspivot", lp)
    • No special considerations.
  • get_improve
    • return = eulpsolve("get_improve", lp)
    • No special considerations.
  • get_infinite
    • return = eulpsolve("get_infinite", lp)
    • No special considerations.
  • get_lowbo
    • return = eulpsolve("get_lowbo", lp, column)
    • [return] = eulpsolve("get_lowbo", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_lp_index
    • return = eulpsolve("get_lp_index", lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = eulpsolve("get_lp_name", lp)
    • No special considerations.
  • get_mat
    • value = eulpsolve("get_mat", lp, row, col)
    • [matrix, return] = eulpsolve("get_mat", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix in the first return value. The return code of the call is the second return value.
  • get_max_level
    • return = eulpsolve("get_max_level", lp)
    • No special considerations.
  • get_maxpivot
    • return = eulpsolve("get_maxpivot", lp)
    • No special considerations.
  • get_mip_gap
    • return = eulpsolve("get_mip_gap", lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = eulpsolve("get_nameindex", lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = eulpsolve("get_Ncolumns", lp)
    • No special considerations.
  • get_negrange
    • return = eulpsolve("get_negrange", lp)
    • No special considerations.
  • get_nonzeros
    • return = eulpsolve("get_nonzeros", lp)
    • No special considerations.
  • get_Norig_columns
    • return = eulpsolve("get_Norig_columns", lp)
    • No special considerations.
  • get_Norig_rows
    • return = eulpsolve("get_Norig_rows", lp)
    • No special considerations.
  • get_Nrows
    • return = eulpsolve("get_Nrows", lp)
    • No special considerations.
  • get_obj_bound
    • return = eulpsolve("get_obj_bound", lp)
    • No special considerations.
  • get_objective
    • return = eulpsolve("get_objective", lp)
    • No special considerations.
  • get_orig_index
    • return = eulpsolve("get_orig_index", lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = eulpsolve("get_origcol_name", lp, column)
    • [names] = eulpsolve("get_origcol_name", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_origrow_name
    • name = eulpsolve("get_origrow_name", lp, row)
    • As such no array of names can be returned. This because Euler has no possibility to return string matrices.
  • get_pivoting
    • return = eulpsolve("get_pivoting", lp)
    • No special considerations.
  • get_presolve
    • return = eulpsolve("get_presolve", lp)
    • No special considerations.
  • get_presolveloops
    • return = eulpsolve("get_presolveloops", lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = eulpsolve("get_primal_solution", lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = eulpsolve("get_print_sol", lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = eulpsolve("get_rh", lp, row)
    • [rh] = eulpsolve("get_rh", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_rh_range
    • return = eulpsolve("get_rh_range", lp, row)
    • [rh_ranges] = eulpsolve("get_rh_range", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_row get_rowex
    • [row, return] = eulpsolve("get_row", lp, row_nr)
    • [row, return] = eulpsolve("get_rowex", lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Euler, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = eulpsolve("get_row_name", lp, row)
    • [names] = eulpsolve("get_row_name", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_scalelimit
    • return = eulpsolve("get_scalelimit", lp)
    • No special considerations.
  • get_scaling
    • return = eulpsolve("get_scaling", lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = eulpsolve("get_sensitivity_obj", lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = eulpsolve("get_sensitivity_objex", lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that Euler allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = eulpsolve("get_sensitivity_obj", lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, Euler always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = eulpsolve("get_sensitivity_rhs", lp)
    • [duals, dualsfrom, dualstill, return] = eulpsolve("get_sensitivity_rhsex", lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that Euler allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = eulpsolve("get_sensitivity_rhs", lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = eulpsolve("get_simplextype", lp)
    • No special considerations.
  • get_solutioncount
    • return = eulpsolve("get_solutioncount", lp)
    • No special considerations.
  • get_solutionlimit
    • return = eulpsolve("get_solutionlimit", lp)
    • No special considerations.
  • get_status
    • return = eulpsolve("get_status", lp)
    • No special considerations.
  • get_statustext
    • return = eulpsolve("get_statustext", lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = eulpsolve("get_timeout", lp)
    • No special considerations.
  • get_total_iter
    • return = eulpsolve("get_total_iter", lp)
    • No special considerations.
  • get_total_nodes
    • return = eulpsolve("get_total_nodes", lp)
    • No special considerations.
  • get_upbo
    • return = eulpsolve("get_upbo", lp, column)
    • [upbo] = eulpsolve("get_upbo", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_var_branch
    • return = eulpsolve("get_var_branch", lp, column)
    • [var_branch] = eulpsolve("get_var_branch", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_var_dualresult
    • return = eulpsolve("get_var_dualresult", lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = eulpsolve("get_var_primalresult", lp, index)
    • No special considerations.
  • get_var_priority
    • return = eulpsolve("get_var_priority", lp, column)
    • [var_priority] = eulpsolve("get_var_priority", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • get_variables
    • [var, return] = eulpsolve("get_variables", lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = eulpsolve("get_verbose", lp)
    • No special considerations.
  • get_working_objective
    • return = eulpsolve("get_working_objective", lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = eulpsolve("guess_basis", lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In Euler, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In Euler, there is no unused element in the matrix.
  • has_BFP
    • return = eulpsolve("has_BFP", lp)
    • No special considerations.
  • has_XLI
    • return = eulpsolve("has_XLI", lp)
    • No special considerations.
  • is_add_rowmode
    • return = eulpsolve("is_add_rowmode", lp)
    • No special considerations.
  • is_anti_degen
    • return = eulpsolve("is_anti_degen", lp, testmask)
    • No special considerations.
  • is_binary
    • return = eulpsolve("is_binary", lp, column)
    • [binary] = eulpsolve("is_binary", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • is_break_at_first
    • return = eulpsolve("is_break_at_first", lp)
    • No special considerations.
  • is_constr_type
    • return = eulpsolve("is_constr_type", lp, row, mask)
    • No special considerations.
  • is_debug
    • return = eulpsolve("is_debug", lp)
    • No special considerations.
  • is_feasible
    • return = eulpsolve("is_feasible", lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = eulpsolve("is_free", lp, column)
    • return = eulpsolve("is_unbounded", lp, column)
    • [free] = eulpsolve("is_free", lp)
    • [free] = eulpsolve("is_unbounded", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • is_infinite
    • return = eulpsolve("is_infinite", lp, value)
    • No special considerations.
  • is_int
    • return = eulpsolve("is_int", lp, column)
    • [int] = eulpsolve("is_int", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • is_integerscaling
    • return = eulpsolve("is_integerscaling", lp)
    • No special considerations.
  • is_maxim
    • return = eulpsolve("is_maxim", lp)
    • No special considerations.
  • is_nativeBFP
    • return = eulpsolve("is_nativeBFP", lp)
    • No special considerations.
  • is_nativeXLI
    • return = eulpsolve("is_nativeXLI", lp)
    • No special considerations.
  • is_negative
    • return = eulpsolve("is_negative", lp, column)
    • [negative] = eulpsolve("is_negative", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • is_piv_mode
    • return = eulpsolve("is_piv_mode", lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = eulpsolve("is_piv_rule", lp, rule)
    • No special considerations.
  • is_presolve
    • return = eulpsolve("is_presolve", lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = eulpsolve("is_scalemode", lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = eulpsolve("is_scaletype", lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = eulpsolve("is_semicont", lp, column)
    • [semicont] = eulpsolve("is_semicont", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • is_SOS_var
    • return = eulpsolve("is_SOS_var", lp, column)
    • [SOS_var] = eulpsolve("is_SOS_var", lp)
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Euler matrix.
  • is_trace
    • return = eulpsolve("is_trace", lp)
    • No special considerations.
  • is_use_names
    • return = eulpsolve("is_use_names", lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = eulpsolve("lp_solve_version")
    • The eulpsolve API routine returns the version information in 4 provided argument variables while the Euler version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = eulpsolve("make_lp", rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • eulpsolve("print_constraints", lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
    • The same information can also be obtained via eulpsolve("get_constraints", lp). This shows the result on screen.
  • print_debugdump
    • return = eulpsolve("print_debugdump", lp, filename)
    • No special considerations.
  • print_duals
    • eulpsolve("print_duals", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
    • The same information can be obtained via eulpsolve("get_dual_solution", lp). This shows the result on screen.
  • print_lp
    • eulpsolve("print_lp", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
  • print_objective
    • eulpsolve("print_objective", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
    • The same information can be obtained via eulpsolve("get_objective", lp). This shows the result on screen.
  • print_scales
    • eulpsolve("print_scales", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
  • print_solution
    • eulpsolve("print_solution", lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
    • The same information can also be obtained via eulpsolve("get_variables", lp). This shows the result on screen.
  • print_str
    • eulpsolve("print_str", lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
  • print_tableau
    • eulpsolve("print_tableau", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Euler (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the eulpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows Euler) to the command window of Euler. As such, all reported output can be seen in Euler. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines. Note that at least Euler version 5.8 is needed to see this information on the command window. Older versions will not print information on the command window.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = eulpsolve("read_basis", lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = eulpsolve("read_freemps", filename {, options})
    • lp_handle = eulpsolve("read_freeMPS", filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In Euler it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = eulpsolve("read_lp", filename {, verbose {, lp_name}})
    • lp = eulpsolve("read_LP", filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In Euler it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ("").
  • read_mps, read_MPS
    • lp_handle = eulpsolve("read_mps", filename {, options})
    • lp_handle = eulpsolve("read_MPS", filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In Euler it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = eulpsolve("read_params", lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = eulpsolve("read_XLI", xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, "" (NULL) is taken. "" is taken as NULL.
    • options is optional. When not provided, "" is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • eulpsolve("set_basisvar", lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = eulpsolve("set_add_rowmode", lp, turnon)
    • No special considerations.
  • set_anti_degen
    • eulpsolve("set_anti_degen", lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = eulpsolve("set_basis", lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In Euler, there is no unused element in the matrix.
  • set_basiscrash
    • eulpsolve("set_basiscrash", lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • eulpsolve("set_bb_depthlimit", lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • eulpsolve("set_bb_floorfirst", lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • eulpsolve("set_bb_rule", lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = eulpsolve("set_BFP", lp, filename)
    • No special considerations.
  • set_binary
    • return = eulpsolve("set_binary", lp, column, must_be_bin)
    • return = eulpsolve("set_binary", lp, [must_be_bin])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = eulpsolve("set_bounds", lp, column, lower, upper)
    • return = eulpsolve("set_bounds", lp, [lower], [upper])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • eulpsolve("set_bounds_tighter", lp, tighten)
    • No special considerations.
  • set_break_at_first
    • eulpsolve("set_break_at_first", lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • eulpsolve("set_break_at_value", lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = eulpsolve("set_col_name", lp, column, name)
    • No special considerations.
  • set_column, set_columnex
    • return = eulpsolve("set_column", lp, col_no, [column])
    • return = eulpsolve("set_columnex", lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = eulpsolve("set_constr_type", lp, row, con_type)
    • return = eulpsolve("set_constr_type", lp, [con_type])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • eulpsolve("set_debug", lp, debug)
    • No special considerations.
  • set_epsb
    • eulpsolve("set_epsb", lp, epsb)
    • No special considerations.
  • set_epsd
    • eulpsolve("set_epsd", lp, epsd)
    • No special considerations.
  • set_epsel
    • eulpsolve("set_epsel", lp, epsel)
    • No special considerations.
  • set_epsint
    • eulpsolve("set_epsint", lp, epsint)
    • No special considerations.
  • set_epslevel
    • eulpsolve("set_epslevel", lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • eulpsolve("set_epsperturb", lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • eulpsolve("set_epspivot", lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = eulpsolve("set_free", lp, column)
    • return = eulpsolve("set_unbounded", lp, column)
    • No special considerations.
  • set_improve
    • eulpsolve("set_improve", lp, improve)
    • No special considerations.
  • set_infinite
    • eulpsolve("set_infinite", lp, infinite)
    • No special considerations.
  • set_int
    • return = eulpsolve("set_int", lp, column, must_be_int)
    • return = eulpsolve("set_int", lp, [must_be_int])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = eulpsolve("set_lowbo", lp, column, value)
    • return = eulpsolve("set_lowbo", lp, [values])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = eulpsolve("set_lp_name", lp, name)
    • In Euler, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = eulpsolve("set_mat", lp, row, column, value)
    • return = eulpsolve("set_mat", lp, [matrix])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. The matrix must be two-dimentional.
  • set_maxim
    • eulpsolve("set_maxim", lp)
    • No special considerations.
  • set_maxpivot
    • eulpsolve("set_maxpivot", max_num_inv)
    • No special considerations.
  • set_minim
    • eulpsolve("set_minim", lp)
    • No special considerations.
  • set_mip_gap
    • eulpsolve("set_mip_gap", lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • eulpsolve("set_negrange", negrange)
    • No special considerations.
  • set_obj
    • return = eulpsolve("set_obj", lp, column, value)
    • return = eulpsolve("set_obj", lp, [values])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • eulpsolve("set_obj_bound", lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = eulpsolve("set_obj_fn", lp, [row])
    • return = eulpsolve("set_obj_fnex", lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In Euler, there is no unused element in the matrix.
  • set_outputfile
    • return = eulpsolve("set_outputfile", lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In Euler under Windows, output to stdout it not shown. However it results in closing the file. Use "" to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • eulpsolve("set_pivoting", lp, pivoting)
    • No special considerations.
  • set_preferdual
    • eulpsolve("set_preferdual", lp, dodual)
    • No special considerations.
  • set_presolve
    • eulpsolve("set_presolve", lp, do_presolve {, maxloops})
    • The maxloops argument is optional in Euler. If not provided, then infinite is used.
  • set_print_sol
    • eulpsolve("set_print_sol", lp, print_sol)
    • No special considerations.
  • set_rh
    • return = eulpsolve("set_rh", lp, row, value)
    • return = eulpsolve("set_rh", lp, [values])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = eulpsolve("set_rh_range", lp, row, deltavalue)
    • return = eulpsolve("set_rh_range", lp, [deltavalues])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • eulpsolve("set_rh_vec", lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In Euler, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = eulpsolve("set_row", lp, row_no, [row])
    • return = eulpsolve("set_rowex", lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In Euler, there is no unused element in the matrix.
  • set_row_name
    • return = eulpsolve("set_row_name", lp, row, name)
    • No special considerations.
  • set_scalelimit
    • eulpsolve("set_scalelimit", lp, scalelimit)
    • No special considerations.
  • set_scaling
    • eulpsolve("set_scaling", lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = eulpsolve("set_semicont", lp, column, must_be_sc)
    • return = eulpsolve("set_semicont", lp, [must_be_sc])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • eulpsolve("set_sense", lp, maximize)
    • No special considerations.
  • set_simplextype
    • eulpsolve("set_simplextype", lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • eulpsolve("set_solutionlimit", lp, simplextype)
    • No special considerations.
  • set_timeout
    • eulpsolve("set_timeout", lp, sectimeout)
    • No special considerations.
  • set_trace
    • eulpsolve("set_trace", lp, trace)
    • No special considerations.
  • set_upbo
    • return = eulpsolve("set_upbo", lp, column, value)
    • return = eulpsolve("set_upbo", lp, [values])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • eulpsolve("set_use_names", lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = eulpsolve("set_var_branch", lp, column, branch_mode)
    • return = eulpsolve("set_var_branch", lp, [branch_mode])
    • In Euler, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = eulpsolve("set_var_weights", lp, [weights])
    • No special considerations.
  • set_verbose
    • eulpsolve("set_verbose", lp, verbose)
    • No special considerations.
  • set_XLI
    • return = eulpsolve("set_XLI", lp, filename)
    • No special considerations.
  • solve
    • result = eulpsolve("solve", lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = eulpsolve("time_elapsed", lp)
    • No special considerations.
  • unscale
    • eulpsolve("unscale", lp)
    • No special considerations.
  • write_basis
    • eulpsolve("write_basis", lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = eulpsolve("write_freemps", lp, filename)
    • return = eulpsolve("write_freeMPS", lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In Euler it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = eulpsolve("write_lp", lp, filename)
    • return = eulpsolve("write_LP", lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In Euler it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = eulpsolve("write_mps", lp, filename)
    • return = eulpsolve("write_MPS", lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In Euler it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = eulpsolve("write_XLI", lp, filename {, options {, results}})
    • No special considerations.

Extra Euler routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = eulpsolve("get_col_names", lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = eulpsolve("get_constr_types", lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = eulpsolve("get_int", lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = eulpsolve("get_no_cols", lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = eulpsolve("get_no_rows", lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = eulpsolve("get_objective_name", lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = eulpsolve("get_obj_fn", lp)
    [row_vec, return] = eulpsolve("get_obj_fun", lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = eulpsolve("get_problem_name", lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = eulpsolve("get_reduced_costs", lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = eulpsolve("get_row_names", lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = eulpsolve("get_solution", lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = eulpsolve("mat_elm", lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = eulpsolve("print_handle")
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = eulpsolve("read_lp_file", filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = eulpsolve("get_handle", lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = eulpsolve("return_constants"[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the eulpsolve driver

Under Windows, the eulpsolve Euler driver is a dll: eulpsolve.dll
Under Unix/Linux, the eulpsolve Euler driver is a shared library.: eulpsolve.so
This driver is an interface to the lpsolve library lpsolve55.dll/liblpsolve55.so that contains the implementation of lp_solve. lpsolve55.dll/liblpsolve55.so is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). The eulpsolve Euler driver is just a wrapper between Euler and lp_solve to translate the input/output to/from Euler and the lp_solve library.

Compilation

The eulpsolve Euler driver is written in C. To compile this code, under Windows the Microsoft visual C compiler is needed and under Unix/Linux the standard cc compiler.
The needed commands are in a batch file/script.
Under Windows it is called cvc.bat, under Unix/Linux ccc.
In a command prompt/shell, go to the lpsolve Euler directory and enter cvc.bat/sh ccc and the compilation is done. The result is eulpsolve.dll/eulpsolve.so.

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./Euler1.jpg000666 000000 000000 00000106735 11164353450 011242 0ustar00000000 000000 JFIFExifII*1&i.Picasa0220 !|f4720895c6592c130000000000000000R980100 (HHJFIFC  !"$"$C" P  !14AQT$27BCRSVaqsu"#3bUrd5E<  !1r"4AQRaq$2#Sbs ?ܻ;IzL}Lfii,-M  8^Slz/Pl4OVUaqլ 럺*bWkv]qzCAJrSG+c$NWNN?k,9U$/ No&% sdb@NcJ5`糍#k(?;en~Rb5qƪh[G lĜɭ30% N5e5&ˍ2]a0l]Yc]Psi9DXIԫ:6> g ǝmq])5S2x5丠^YIėX$%'7L֪2yZ6\u.4JB F9xq*k3V4k; Nx;5Ӊ ,u5AG[m|,}T[u9u<([dQ?; 'Gk:p*r2(*qR'4`iߋ3wcX~dl~ᪧZ=m6kl%3@kOk.YB3/:aw ֬4X81,!u9tSyZFJ00};n Jq٭i>ܸ uڭmn-EkR%J'II $`?{Z ,\_`1Z-Ll A'A Qhc U:Nq+Z}\2p”n&RNH=jqsT)yKn| QhoVϛ:k7hȷ/sί[?Z,M)V**uUeU@i@l5;@i*K!2)֐I8X&\7VFֈ #7HQSu*j E )'ZO|o͵2eeT|R8anqCu ۨn)~r{C:p4RoT)L62PSjŌUX\AENʵe72U8oV hȹ+ONZ[y9^BU6ARRH F;Hd~&U't:7mˆ^\q%z"cR{%\q%z"M_UE2I.JIgRã(~3ItQfϻ!VL+d|P$C&R\,߂O=$$x  ÕjͲ.ʧ7Jl8 JNPG)$pB&diIGO=ݡ%%$!snOcxDxAvvcPE]69#%R__OFvcPB\uc~}:ݡ%%$ \R_O3ǔgf8[Č|mI}iI}P%%$!,:AX"I;BKKIBdddq|xO63cDd1| 0OH 7_> ?qcL7:m.)/'\R_O3ǔgf8[,/I>*vfmZm EhK:cxO(~rg#rg#.LmduOVz=CLr&yɍc>entALrɟ SELk!{ȕ91cW+7{mK?"/@V=㑽KFS1}\q%z"g=j1 KlDQ&N^] yN,b1ÇXsv͖Ϋ*%)WIk]&KEGQt%j in+x9<:uf/"5^dQgĶwX$D/%nZkEr(.N-L7%$5e_6[aheQDX!xy?3qW>~01f=i0av}pUϼ HdI<s' uݬsY}0&{q1{<{\|\+wFy*O Uϼ**fceTCos"+uxU鈍JhTAz s7>cKlD{q?bp=,-uu@&eTI)ը( F9 }m\ݨeʇdr{va0WIG`ARnQj -ZVI~JzQ#Nla=ObZ[Z2Crxd1>t8U91g8 H"-~Mt!-d&eXjRTŒ[=3O{5t\q%z"K]S# 99Xb1FKڋ6[:|G gk]&ݯEtDq, E(A@ױd &Õk,zAJlڝ^:`퍜6r^Y5 -oi:RGG!qsףj&f0id 'I,M o-<#̟Y1|n({jS/Sa8xg:ƏxtGH1u >ބn73<]< rcintALtɞ.SELlmw?_r%sLgXtg*DFwи"c9_KFS1}\q%z"g=j1 KlDN2N!' _7+i.7j,l겡YݯEtD>vaİ4XA@AANV~ZgOӪ2iU ut:dme,Rm`NrY;hJljT}EW_Lc!{ȕ.g:зW+7{m2Ҕ+@%#)Ϙr>Œ[=3O5t\q%z"M]n} % #8>nPi.7j,l겡YݯEtL>vaİ4XA@AAA cv%1iVʯѧ) tb=j5VmM Vg2t2}b:Ac#7|髻f񜤾gio8C/!xjXFu2՚ee 7\~UxvNCA&[/?*{\¦}?YDDo`ng~D_jqF^/i|p=,艜{٫2{Y/uFgJyr- 7T;dxhItQfgU YݯEtD[%*o8rLt$~zQ9İ5EN-%SaKE2\^I ɾtj޲KW=*tlz-_Nli"ԈT($ͧAU TPE$~zQ9uZ=(Eekf6XVH[O%.iP<#F>#wD@PEQkqlh !26ZDWJ%JJp_*lz-_Nli6&jiDY}G{n*H.Z; ie ;#:S} N$8r[ dģ/. (Hj#C-_Nl{ǫ--Oy-ҭ;*b@J[$Rwu&{ȨhvUTͲĤSJBS:1f*eMR͸jDRknI2Jh rt1"4g>o#.f.uvjStYYjsM˓ )W Zx=f:8QU]G̗l:_t u~~PyЂV路c-،uf?(   %# , #&'*)-0-($%)(  !#%  %%%V  !1"2Aq$5TUu#34Bt%QRaSVe6EFA 1Q2!3R"4ASqa#BT$br ?m޽VREa͓%J(ҠFI.4h3fy__q3߃mc(Ef th\41Q3WޏJ>J/ƬO>U?I>5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J5=Z>J1cS>U?IcV}Z>J5=Z>J5=*V1%iHCϕh+O@z՟hV$Oiʴ| = jǴZ>J5=*V1*V1U?IcV}Z>L5=*f1uGʴ| = j]Q&gHCT|Gəƥ*f1uGʴ| = j]Q&gHCT|Gəƥ*f1uGʴ| = j]SḭNM׫PN(JRZSE8E7C*qc"i*ߓ) U,hDմPnӹlwK<ՖYUpkMQ?[SM5GHsSA&_9cVfjf)Ifٰ̳m YME]5E7?,X6MgQK(9y٫/jtY؂ѫ7F4xIO8jʙh[kg)cvganqA:H~wTlXz'#Iy䤏BTjvjjS_1 /Q0)f޽oLRw(i"1p lz8&~˲QoOы,tWrŦ( gsl$E$WX1?C "m(~m?M1GL>_#]߽+_ź容 ӶOE1i{\XW TWsIZ6:*Ԥ.MFeِU7FUa/Ot fFߩ*eRTЮs4qeRXXEZMqt/bn|+iS]JӣMԩRD"):ffPU j.Ʃ*/3c\gn[UU4k7pt.TJIE$e%mڜtM&,9qE^ÊmR)d)3֛&Ҽ(aŰWOpGJԖ5IZPTUJ:d4dFF9? a{nM=~ֈ dӡULj($g8Bfc_v\tTqt9x{LRj8Vdn2c1Miobv{H ,kL!ᕝӭQ*rޡ-4BI&dvk˵pUtgXWiut^`[,!EKhULΝQoi·INju~YTEt~,ѱU6*bфJdI}*bn\vsE9kCozn~^a[ӣUg4(oR:^LPe!ii쪢/ }5HApG ?\#.Ap{*]*ӄc OPwJVdE]_|Vuw*RqJ b/|Z E vyD<8wn6JʩzmR hݓ][_ oankpf~MS!uQPm]5hB5ZI>͊j_GS1w:{oE1}Q8yTBa3_R]] ЕQIvnRA FG2%b &fq/}_)8Y1r,w{QR|2JK \?L]|-WmQ{yuUfuQnn4gYcXU4DgiKcڍ ߾9tWZ.]dງGUST8NcfsfrS‹^Tv)N.Is4T˄;OݲZrxvw3^oLDUtc:ݛbѴ[lBZ^ ѻ4G Kiv_ o}[gMSMXv0chҫ9¶7sS@=jij$BT⯊-k9t]W."R+c"]Ɗl;T 2T-h5H (?n*hOOG1gZc8{#nޯ}Um*㴈!|ogkgi]=n/|]tS==m.mڵE/v],T ST % PGLظ7hfX&mʺk󈹮0}eIj[=9hSH?qZfdFyX-uQՆס͵vZiSYҵJ\w٩ RHݙs\YZsL^.|6VS~:ol{PUGjaYȿ`RjgLVT(2";Kz(tbg,wmQ\⛯{<`XNaձ bUjԫT&dJ |VkWDE|]_M4]6kgi\ٽSiWݑ֫JI4^Ud2YcWUXYqD}Si1~wx1,I(WbXiO ,e *EPyVj2W%4e9g୪bTMf#?GMcu0qyƱ*NX鄫4j,}cV6;,DLtnvDCAwɢ(C)lӆTpj÷ꤔr+g#O+zfMMm=1u1; pMسe\op߹dIY]T \>)#FZJffn鋢J, jc`0c6 UrI iTFFdЌ}|opߎ,._7+=? ;.UB WruJF҃eƤuf8#EVh+tt]GbS;މSh1ߝjWf%(S kpTs%MAi0C ڢOXeTxT^~Kkj7*HjvwI['"sm[U3TEX0ʨW,KC,.*?]z#idDfJ(3YpfEqm.xvbAa6ƭx!f Uti!]i$5E31S[Uvv8.7߯^ڬ)h浚P ʫQdٴQ]UZa1n  f]3p.?A nc71at f]6wcPh}QGG/"97*?ٰX d',ԬYҊtR$X#%g38[lW}7vl Ƿ-Wk p+MHQT9.-cګ(xܭiO䕆շ Enur0߶SWZplN"΅Z}JiWCY/k4M1 .6E66M1uD|fTU70F-4ijlQd^&h&fki}SmmmMu1LU&t|U4S1_3sW`;1i}}5U.7U9E Bֳ#|pT tMDwρ_lzr]_F1B *0vePE#{l%\E̲UFv%Nv:뙣ۑo _<s]: QQ :bD_g~gW/kp5||mߙrl] ۿ3ػ^zCn~׆(96.ׄS|mߙrl] ۿ31M?6[ws7Fyɱv$5͖ P&k}-9^M?6[ws7Ck>lxo96.ׄS|mߙ&{}-9^<ػ^=Moe~g?k9ɱv'zCn~׆(96.ׄ=͖ Qrl] 1k}e~g?k9ɱv'zG6;ws7Ck>lvXo96.ׄS[|ߙڰrl= ۿ3aػ^=Moc~g?j9ɰ'zCn~Ն(saxIk}9VM?6;ws7Cjۿ3a{^=Ooc~g?j9ɱv'zGٯsT*ZkJ$ՠȔNUEUu-& |Պw.۔!(N d 4$QOb vO͎ Q\ػ^O>lvXo96ׄS|ߙڰrl] ۿ3ػSzCn~׆(sbxOS[h|ߙr] ۿ3ػ^=Mmc~g?k9˱v'zCn~׆(sbxO5͎ P.km9^]?6;ws7Ck>lvxo9v.ׄS[h|ߙr] !s-&,M s- Ai2̌oEUMKe[ՊM30ϫvEG/V}k䶽['aN^Sȭ;/S}J ԙw1=wgqLvs9q,o\Wt]wB9Ӌ=-ڲf#O?*cIk~jUa]K<ӱa*J&ÓI4҂BH%$DDEd>Sf,tG)v+=п} Oõb;` H}58?v iN=9gt ªn1f4$(VQLFZzoڬo:>1_vvn?اxy6}OwwpOuƞo{CuϢݱO؞6}Lpn}<FA5?]}Т"&IQΑm-pfkmhe{pmqW8y>1WXCzy>1WXCzy>1WXF1WϋC. 4k%xuC&Sy,Z }1݇{pmqW8y>1WXCzy>1WXCzy>1WǼ 1 u|_&x7Z:aYV*'ê/G74b+bҹy>V*g}!ý†*1;;\|(bC}!ý†*1;;\|(bC}!ý†*1|]b8Jߪ'USLnET1Uq/}cC{k^㯳!ýŒC}!ý†*1;;\|(bC}!ý†*1;;\|(bC}!ý†*1|i=_RJ9R~"УĔ]\W}|_~Ǽ +Z3XCzy>1WXCzy>1WXCzy>1WC. 4k%xuEqnSJ-`s}1݇{pmqW8y>1WXCzy>1WXCzy>1WǼ 1 u_&x7Z:aYV*'ê/G74b+c&)b>/}cC{k^㯲=mY7Yu2TLg*Sz?@7ہ|:?اxOwyXP"ծIS]jӯ浟}!1TxWM|9Ƴf3S#9M<W2l]u}Yg7{nWi&FI*);։ 9SMy&!VWMڳrns[N'T*g8D S]]6BbZGBuLg(4RPU\ɲtUueީ]rM&3,&}$E5Bt?@ۑx|mkslSov'ex7~~AjD>U/\22Ϙ,է_k}!1TxWM|9Ƴf3S#9M<W2l]u}Yg7{nWi&FI*);։ 9SMy&!VWMڳrns[N'T*g8D S]]6BbZGBuLg(4RPU\ɲtUueީ]rM&3,&}$E5Bt?@ۑx|mkslSwv'ex7~~AjDǶ}7)vEkFRyZz;ZϿ6&* ]o88bw*c9Dg)Mu3,Om=DӒh0Re[E'u3uAG:{"ssVI$*VnUm1Rq~ziꙅL4Rk+׈L]u HYNܩX`J 6U\Ί=+NI$ea;o{݆V~~Dr`MP]gkr~i]:pQXC8d1|(5xm]*stÇIy/.sG*"@69aä9B#UҧDr` TH^\TC  ^AWJ]0ui ˜!ʈa h*S+:N!ysd"9Q 0`h*S+:N!ysd#Q 0xK 7QʷУR]:9ǩ+;fvi.MEɫh*S+:N!ysd"9Qt']搼ϲ0@69aä9B#UҧDr` TH^\TC  ^AWJ]0ui ˜!ʈa!c,(nd7=l2t3OBDL\苓Tʜ]0ui ˜!ʈ0xm]*stÇIy/.sG*! TH^\TC  ^AWJ]0ui ˜!ʈa h*S+:N!ysd"9Q 0`xm]*stÇIy/.sG*! / Nxp:4}D0ohfFt3̋|Zo2Ii& h*S+:N!ysd"9Qt']搼ϲ0@69aä9B#UҧDr` TH^\TC  ^AWJ]0ui ˜!ʈa h*S+:N!ysd"9Q 0`&(.5? ȝ:qc Es/t']搼ϲ  TH^\TC  ^AWJ]0ui ˜!ʈa h*S+:N!ysd"9Q 0`xm]*stÇIy/.sG*! / Nxp:4}D0/ Nxp:4}D0D!,(TdF*3BIti22v?/bxY'ww`q鲸_P}ᲊϘ,.kz[`vWV4k"ԔuiV%I2̔FRFYzFPrö*L\馓w$*e5";Th<W2l]u}Yg7{nWi&FI*);։ 9SMy&!VWMڳrns[N'T*g8D S]]6BbZGBuLg(4RPU\ɲtUueީ]rM&3,&}$E5B?@ہx|:?اxOz>&87~~AW+#yP}ᲊϘ /Ĭˮ'zޅ9@;nڕᴎIk0|1yR L_7铖UtZn(T4v`J 6U\Ί=+NI$JCŕmkDjHW)Y&R+[YUDJ9뭧f3"sKBb^!1u-#sf!:gr3Fr)`(x*dW]s:*oTܮM9&Ceai"vw!Y][^zPsrlSov'e_s +MB}B}ᲊϘ,.kz[`"jhT.kSrk*JQ)2fGXV\Z ߰]GoZU- jT&xj2223I6PU\ɲtUueީ]rM& P,hZ&nWH(OdNzBNj5BY^7jʭ&*Q/]m8S0&XMwt isk1 c;13K CUs&ʺU_wՖszvi4dz`̳,>x COp[c Ǎ=n?h뛗Db}b,.kz[``]6sauNJJ:nfFu&87~~A`S2kVUfX}6膞",arߏzkw~7.v?/bxY1;\y*>|u`"dF4^2Anb J>bQFbpŭte=0Ye>•ZE Ш4ԦGL#"?SiV*-@ ;㖆3jqLAXzQmqe~kVچi4Uh3QfJ vĦbg⵸%*5OURN3iY B)DT,\I2;6#5JSM3)ӖnK^i4/QD˧R[GtD˧R[GtD˧Rm\>sN筒F]eAd_Esb +J樛Mq7fa k;&U"guUӨx3tBZIqzt]:hS7D% 4}W;NӨx3tBZIqzt]:hS7D% 4}W;NӨx3tBZIqzt]:hS7D% 4}W;NӪ)KrE坧ʉ2boN(L[Gt&87~~AW+"v9Q[%eǟ1NY~%f]q;V)ȶ[-ݯZ]W*Ul<ʙnKQ2QgaR 3X>2p2]n^gM5-Qs&R%ʀ*);։ 9SMy&!VWMڳrns[N'T*g8D S]]6BbZGBuLg(4RPU\ɲtUueީ]rM&3,&}$E5BO@ہx|:;اxOwyX\zlBrEK+>b,.kz[`pg7yTiGt雒]FNm%ܓ9###,`FGtlkpzNYO(]#pv ȏEA*);։ 9SMy&!VWMڳrns[N'T*g8D S]]6BbZGBuLg(4RPU\ɲtUueީ]rM&3,&}$E5BO@ہx|:?اxOz>&87~~AW+"v9Q[%eǟ1NY~%f]q;V)ȶCq)|CqU"ֱU^\DǐȞ]ܰQ(vIhU m"5G92LveURw[7Ys'=!\5dL!JB nfV(箶NTpE, ºmx[എ951ʘQhહe]u믻9SrOQ42L=fYcM!H-k܅gwƞo{CuˢݱO؞6}Lpn}<=6W FN9Q[%eǟ1L_Y\N5ս r-hzԫЫV5ZjJU:DfJ#)#,Z="hnZSZ9*5Nd]9%29#\BaiCŕmkDjHW)Y&R+[YUDJ9뭧f3"sKBb^!1u-#sf!:gr3Fr)`(x*dW]s:*oTܮM9&Ceai"vw!Y][^zPsrlSov'e_s 4'>Ʃ|I{c8a6I(;E%"*j* :pjI4b=K'/*lnK(uEh*D?'(YD~%[krTurfjETq_45Q""#ZJJnJ`UbLh +UukѠIZH (m-M3881J')̨)噰FJ TT\닓PL\0ҴiϐẻPpx)stwJy#>CG2%* RHF|(dK^%A7J\0Ҵiϐẻb Ĩ&KV!l9,Pcx)stwJy#>CG2% p/.xnnZo4g}DA|J*'2"הD^\Q|"kPJnai!#Xx^%A7J\0Ҵiϐẻb Ĩ&KV!l9,Pcx)stwJy#>CG2% p/.xnnZo4g}DATt +M搌QȖ(1Jnai!#8BiP*ψ[dT]TD Dޕ.bQJnai!#Xx^%A7J\0Ҵiϐẻb Ĩ&KV!l9,Pcx)stwJy#>CG2% p/.xnnZo4g}DATt +M搌QȖ(1Tt +M搌QH(bk<'M}AE5FW]yܩfw i.Mɕ1*J%7t7B3>G"jjMp&}$M&rߏzkw~7.v?/bxY1;\`XB/Wc/\6Q\yeuC][Ч"Gum'uwEG n'u"8֚w]ݓM!tC.nU֦JkO)#Rd+sVH&B U:rns[N'T*g8D S]L isk1 c;13K ,DM7\Ί=+NI$eRlwD4 e v;.x-v{^/{_(stO)|7;޲ϿɎ ߯߇uǦa]TVpEqS_Y\N5ս r-حŶaE]PJΝB%IOQhdF L^]`VΕ1dE'jH5.gr%FeG%je@B nfV(箶NTpE, ºmx[എ951ʘQhહe]u믻9SrOQ42L=fYcM!H-k܅gwƞo{CuˢݱO؞6}Lpn}<=6W FN9Q[%eǟ1L_Y\N5ս r-G5֥^Z\ѬkQRեXJ%$2Q`.'p.?-8moRSN!VM).yBgiNPX+[YUDJ9뭧f3"sKBb^!1u-#sf!:gr3Fr)`(x*dW]s:*oTܮM9&Ceai"vw!Y][^zPsrlSov'e_s +MB}B}ᲊϘ,.kz[` _ǓU J[-Vm3D,EqAr9**ҬڵVZRZ&Q)&YLH P+[YUDJ9뭧f3"sKBb^!1u-#sf!:gr3Fr)`(x*dW]s:*oTܮM9&Ceai"vw!Y][^zPsrlSov'e_s 0 eQnPUӮ5|K5TprRȍ2F'6ESuPQmE$&ZF̔rdd%dF_ZukTju^1yJz_lQK5#;SPJ3,28;T >tqL.YBШMvNgI###4L` 5n՛[tLT_q:aS9'8M&* ]o88bw*c9Dg)Mu3,Om=DӒh0>fX}6膞",arߏzkw~7.v?/bxY1;\sƷϯz񓫒LMRpUPi-ͦy%&j%(҄D' lZwFN&;+)Ut[b M MJhdtJ22+˳+Nb-*]QF6=]ׄ }]iUj)Q$$U| "%*$̠ bW_tk".] rѶ25&SPԢ9uMӫ[GtTI3|tbqGJb8; k;&U"guUӨx3tBZIqzt]:hS7D% 4}W;NӨx3tBZIqzt]:hS7D% 4}W;NӨx3tBZIqzt]:hS7D% 4}W;NӪFY%-".VZIEq AKzS7Jb8; k;&U"guUӨx3tBZIqzt]:hS7D% 4}W;NӨx3tBZIqzt]:hS7D% 4}W;NӨx3tBZIqzt]:hS7% 4}Wx]:NxKjdD4(]SZǩSYܮDfYi4viW2Toa*Z*+ҋ44 }<7pٞRQEJކ1+*i4hpfdGL3\h nfV(箶NTpE, ºmx[എ951ʘQhહe]u믻9SrOQ42L=fYcM!H-k܅guƞo#{CuˢݱO؞6}Lpn}<=6W E rEK+>bJ̺wSm ?3#x ڗ,͓lf*\&3]"N,GQCt1zڌS]]6BbZGBuLg(4RPU\ɲtUueީ]rM&3,&}$E5BO@ہx|:?اxOz>&87~~AW+#yP}ᲊϘ /Ĭˮ'zޅ9{b;(Ql@a:kU)(4vpF24 c8v*ž!uDЯJmZf4ԔFFFGFFFDd`2!1TxWM|9Ƴf3S#9M<W2l]u}Yg7{nWi&FI 2wD4 e v;.x-v{^/{_(stO)|7;޲ϿɎ ߯߇uǦ}BrEK+>bJ̺wSm WtdSεZYRa5j,:IIGkBS "#L/Os>1[*BUۧLܒ)j;nI(IS$ Bb^!1u-#sf!:gr3Fr)`(x*dW]s:*oTܮM9&Ceai"vw!Y][^zPsrlSov'e_s 9S2UJ5N WoGzƒRYt -5(̭3|&fY/wqN^Tݘ7\QTN~O5P32KC/|Eҩc 1CG2% p/.xnnZo4g}DATt +M搌QȖ(1Tt +M搌QH(bk<'M}f5UnǩS(AT\+*bT)sKnZo4g}D cM!H-M+?K4 ݸ׋_n]~_ 񷬳cww`q鲸_P}ᲊϘ,.kz[`vWV4k"TuiV%I29%`-pޑtuJ{:i*&ʤMEb,.kz[`w ,>ٺrޛjT;I%tGfIJ .V1|ޛN[&87~~AW+"v9Q[%eǟ1NY~%f]q;V)ȶK1wJ>\ܷ8eJE*UeL#%A !x;m^,ᵕUw$DVmTRӼU#ȏ#)#%b:S-RPU\ɲtUueީ]rM&3,&}$E5BO@ہx}|:?اxOz>&87~~AW+#yP}ᲊϘ /Ĭˮ'zޅ96k}(]mӪRRD3ddFFJ$1wJ>ƛ\8eJYd*U}<ȏ"4 AҀ CUs&ʺU_wՖszvi4dz`̳,>x COp[c Ǎ=nG?h뛗Db}fX}6膞",ar׏z܏kw~7.v?/bxY1;\Ȩ@Zb&&R5RlLWd5ص# :LWgR\B钔ddWg^s4ZUzY.!QYW6ꔴSJzTEw滒*Q&%37I[8UVui.%I=ّ#̎k*N]:hS7D% 4}W;NӨx3tBZIqzt]:hS7% 4}Wx]:NxKjdD4(]SZǩSYܮDfYi4viW2T&87~~AW+#yP}ᲊϘ /Ĭˮ'zޅ9{wF6K'zҭ >47#<.'jHI&GtlkpzNYO(]#pv ȏEAMu3,Om=DӒh0>fX}6膞",arߏzkw~7.v?/{bxY1;_,!+ʊ.(خ?6 7ŏ5Na:ViputάDęAI3}v 66CE=.?PCkiUo%8v$c4UנiYU5tJJo B3"Sznס1x %Q 'u9BiRd57ʹ@\Ŗx٪&?~?׏cwV7.v?/bxY1;O@ہx|:?اxOz>&87~~AT~<__3sf>t}W>M|^ُom|^٧G9u}6͚~t}Zvm|^٧G9ucM1{i8sfot}W>m|^ُo֝6͘]_cM1{i8sfo֝4p|g.}&9:>˫xIf/m?lΏr'mOÛ1ӱ}&9OΏrNljkbp|g.}&9:>˫xIf/mWÇ6cG9u}6͘]i>m|^ُo֝6͘]i>m|^ُo֝6͚~t}W>M|^ُo֝6͘]_cM1{i8sf>t}W>m|^ُom|^ُom|^٧G9u}6͘]_cM1{i8sf>t}W>m|^٧G9u}4͚~t}W>m|^٧G9ucM1{i8sfo֝6͚~t}Zvt}W>m|^ُot}Zv<\.ڇ^!z&ڝ-טQs6:o扮JL\./Euler2.jpg000666 000000 000000 00000070141 11164353542 011234 0ustar00000000 000000 JFIFExifII*1&i.Picasa0220 !|bc75d17a889150ae0000000000000000R980100 (HHJFIFC  !"$"$C" O  !1AQTVa"2357BSqrtu#$C4RUbs%d=  !14Qqr"ARa$23#Sbs ?ܻ;IzL}Lfii,-M  84wk `p8Zih3zA.6%EMԪL2ۏkƻɕIR)s3F[tPC4(ۆa o=VP8 [z)t7צXhq) bNҿyR1 C{GEYZ}תrj: @Pv9")XV't876^Œ[=4A] KlDaDk]Qw 0Ӏ*?fq%}:W%&t2ZG'Gl -/'ҙL*iKOBb4P1ͬNvݑ[tu!TGՇcS`}4e$yDDGwk -/' a%%$#q1@Ӫ':ۣ Ę\QHkWIKzKIF]cگgoc$q$$5sٍyAQ:KzKIF9"?xc;1(# f=~QES.ޒ~[_O9ocgf7naDq$$`KQIA S<`g93~iɌYQ~(6cf`Lr3>A Sh]V+ŲIfFU1+"e_ "]&)TtD!x,艴q_z"p>,E]kmRһI@0rJن[sxgUq%kcN7+]=qTB !B]uBx)me`:ڸG#Ktoc鶢vBqqHPRT O!bjًV?Zw*IKX^o  wL~lGuN?F=x17#uuEL؋u]jhV"b^b^Js?;1dDM+ODBnŒ[=($['TAN''+-uQ^ͳʇr߉Xs1NzÞ8*!@B!#˨u!AIRN$lwcmһ*} EJɗ#.hq`w60ݛgǕy3]y6\䒾b.FPFO䪍U83%6z];ظ'h 393~Lt**g=x?_Ls;<+UB+ȽĽ~wWb{-Lw'!7b{-վU7cΨa1l}E7+ٶuYPWBֻ9{4r߉Xs1eD!BB !PM8u٥+%E+#*qvwV ȧENѪujldCe %C@=[b.B4&A&Zv6!CC's>EW12hiED.gȵ!WVng+!| Y/eiDD&| Y/e#XU-}vtHcNWۄ[sxgUq%kcN7+]=qTB !BB ԝ{݅0'V9UReh'? Cr=3i:\miZJq xP.Y`j *Cd 5: % Jw h"{9$(~ iJA}s-e%Dg>KlDc= KlD㌡2Nڳ.$QdxlE{6PW>ֻ9{4j*S-Rhēz-_ (*TE$|4sgIjiD@:iW֦AjJ&BtctnuZQ95:lz-_ (uZQ90ЋY51,Q(APB%^*V`6cCQm`[I`9.J<F>c m3TЋcIjiDC҉͞N[KWJ'6z4uZiZMPMɾB1P|ԪUj*.S-E=g  BR7 +IjiDC҉͞»eI"j΅KO2cph[jdcc/s"#6] ] *Tm-Gʔe-''Ax'r;al_LV!ԥ,)J% J轗D}s7wT{TʝKSm\M ؗugPyЄ#^Mn(zV͗lIhYt!՞yAB՗5{6!՞yABYt!d՗5:l͈5΄s՞yABMY;s^؇V{ugPyЄ!VN\נ6#W:VkB5dEz3bYt!՞yABMY;s^؇V{5΄! wMgPyЇV{B5dEz3bYt"5zWv+TkD-"d-e0RV.Y` J(5ڽ1#pD"http://ns.adobe.com/xap/1.0/       )' $1$'+"#/#36+-*)!#"  !-"'!"%!'!!!&!(!%!!"!%"!!!!!"!!!!!!!!"!!!!!!!!%%%!!U !1"3b24AQRSUcqt#5Tsua$BCd%EV? Q12!3Rq"ASa#$TbB4 ?iNğvKZsm͕FcNJ;=zȏ-wڻ@hm]W}4_ g}^|z"׀cDQLU~|g3$Q~c?I!Fgt՟$8($1V|3:jπcf|MY ~CϘ>HpQ5g1I 3>c?I!Fgt՟$8($1V|3:jπcf|MY ~CϘ>HpQ5g1I 3Ot՟$8($1V|3:jπcf|MY ~CϘ>HpQ5g1I 3>c?I!Fgt՟$8($1V|3:jπcf|MY ~CϘ>HpQ5g1I 3>g?I!Fgt՟$8($1V|3:jπcf|MY ~CϘ>HpQ5g1I 3>c?I!Fgt՟$8($3,uhf]ydmJRܡKHΜUOB]St3JTrOs a6uyj68Oq_ X8^ZHvz&,{¥wI%lګ7ɒ1LSwڧŇꚬ-G /%0r^ZLN'กmg /'h)lJ7 R:u4d?36f)BZ#8ᏍXvO'!bTfP5k.[}St'Č1QDH62SmD2"25YWuuM8苫>]vsg 93 QGw.*caw|(ix6F_V42+ZwR8)ܘ>=]AER[ MPu6.7M7BA%$>jҦ779AQ_鴍ciFQDL~ۿtZk*1#^mEYZvZ.5VS~*.k5NΛ2_Y8٫HcDO!lwYgViܻ4:j;9`BbDIr5nkKNcI]^c%*m-&)^TW4s_E ֬uw,}v'YYEn4ZD(P$AH^ӭXSl*Y6Ԟ=YӥYLF>&ʮ`8K`&c!CYBҦ-\.Z6hb6Xq|]͟%Z4Ex'kyΎ`LyFc *IqmH5vӧDf)mͭGb5o"7%14m,ĕ).6eSSTt_~v7L6^AF1[Gs[&\7WfF=dc^YQM44M.d*z&e`XJi$d]eJLό[;6hl-"fӱ 雦S(]Rwm֔e)֣C,;jf9*ltC0/JᵉJ:Z=-z:y)*07]M͸ЪX^"J#ƐF섲l$gdTTG~a:m3TDтtzn:V!bϔf]֥3n%$'Y+2J#1^6K-:S?v,m>8£"J-7zQ!iT_N߬dǤhXtID&;tqYI(mɰٕ+f#-ۯ]&&nٛFh륎,Szdda^iJI#VlZSWl6(Ө_2bGtϤ. #y_n8,qxL| wb7)|!F7qFfE)%٨;|ڇV}l]1-y.W%*cIRaHB5q.9WXEi5E a5 Sΰm6q6!5Q/V͢VUMTg隳eT}ij%#ˈSNȌ&Wd֜TMT3tCa9ߐXeIꌈi6TMul&lK YT'9Nse4Cp̌DBRfEF< cmku\?[nvElbĖ^TI)jRW EiJUT>mXLboN˚a\t/ .$u9ڊqL_2l& mɰ' ,MKKcҥNQ,HqY23#̿ki:m뾹hWiU4Zs7t~Tds#QuvEÅ鞎M:%Si9N$l)d+F9q˷VݺmUpxLuhwCN5a)#EJˌ[;2iv4TL:/F pP\ApP\ApP\6 ULJb;|y?羟CkCcŶbXD[;ReOpT7鱦!UK7tU1S~4jtTfN'-d%NhA8htkVE7ycT-<Dw2!R2=m'_-4oLDLM?1}ôtrÿ׀6?^?ū5Lf"[6ԗu 9iB~3}D):Vp>!cyv[)qFIIo̒;b]5iJێ;t ~:Yh9iQ]_ZgcTӽSOY5xKwIΓ[MkW S6ZƪcGFģxOV%MR$0qfZVQcMm8[px0t[zficEhrL2-i/=ФQVy'UE^:%SLU=1}8:m<(b9)0!cmF4mMmY2HgVZKjw6xDKsDJdzĕ-N[vJu-Zb$j4ҨV͕4ULDL]~sV4 sTOLX3ȉ:"\V%{KeO5⨳$Jwn蚾κtֶҨg&KI xqRS[è7k4jIeV>ՊV34݇-*/sO<iF8{s8Z2-)lܐҐY̲$WEѭ(mm*n|}3SLOL1 RR{-ʇ\ߍL>2I.YuًQj=+kJ&ݷgO4hTv$c䃀)0^ZFE}ZMeFWdZyZEz[ޚk2Dgw\WVǚu%ݴo94Ցgp6vsOED}nlXMU]QӲ[#kzr\p͙bʊMK=DVD-fEyj& 8/ݍ2ʛI܃3IpPI SPk1\i2*# [Un*iv7_|5e&l)n0 jΊO4kIgTZcպ4UwKmв mOIKP%aFL7,=OIu]Iھ9Y]]3OL3w{1SXtB+%6Ņ+L{J4So+q $Qfl][} Mge=vދճ1v1:"O,⦡M8 }7Q$DM̕{Xݯ@k8owlj DN|cbJj7iDa(\o>$fi"+5'QҶjպ EuSta{ѥu=(9:,v񒐣Ad񈐷T䵒I(#ǡ4kKh&Zzޚj[3dGQJ;ɐ٥ٗH}c "KL4rmI3WxjXF=z"L2eK,K2nމdt[.kƬҢ3OYݍQ|JI:Q=ʨ6Dj44{\DvEm4f/t–Z]Q/KHWJ5kBun[&ҭFk=]\Z辮OUJ)i#iHXaM6=Y$ 4ZŧV5e~ΓcMuU~J،6,U xrZ<5fvkQ(;ׯmҏQC7`ãX[mJ,HnRbn6!I c疷Ņ!S:&VY\W)v=]&.t->M0ُ/ eۦ']f̎Ì0]ih|KVԴeTv-mlbg2咩"\W)O=%rImxmm&[ɫ5SDLD3s菎kliWS_h}^ S"5QskZ3i`mMEo??p(ձZikEW[xu04GEjx\nL%&3?utZ+]s4}::0hrރȝYoNZ~ yJΪ|C=;i\o/kH6>qhr>qhr>qhr>qhr>qhr>qhsCzI6FZw49$l-;q\o$l-;q\o$l-;q\o$l-;q\o$l-;q\o$l-;q\o$l-;q\o%פm~}iߋ<^rMGю/ph}I9&#NZ~84>פmc~-?jkNI1ӿE '%[d}ߋOڢ>tŧQ~`sCzIVF:w09$l;iT_S$l;iT_^rUGю/ph}I9&'~]Q<'Xy$d[ddtvQk jpW7tEkrKiL$\c:B.W-c~-?j%^J1ӿE '%[d}ߋOڢ>tŧq~`sCOm>tŧq~`sCzJy&#NZ~84>פmc~-?kkNI1ӿ '$d}ߋOm>tŧq~`sCzI6F:w09$l;i\_^rMGю/ph}I9&#NZ~84>פmCވ--2Ë:lZ##I|֓#22VAhWնubL_MC/E/;,?*[ZױViIѨ=iҝ6:l!4ۊă?.lR.cb"\+Oms1U1W±D?^G Ǿ\b#y+OmsኬUp{=*1W±D?^G Ǿ\b#y+OmsኬUp{=*1W±D?^G Ǿ\b#y+OmsኬUkn6Q"[+ܥq[ -K-8b"w}^+OmsqUqW±D?^G Ǿ\b#y+OmsኬUp{=*1W±D?^G Ǿ\b#y+OmsኬUp{=*1W±D?^G Ǿ\b#y+OmsኬUn! +'ܥ2/X"{k}'pVF*8V=HYX"{k Udb#ct\1U}'pVF*8V=HYX"{k Udb#ct\1U}'pVF*8V=HY#DDZ['ZI-fytB&6"k#w±D?'Y'y+OmsኬUp{=*1W±D?^G Ǿ\b#y+OmsኬUp{=*1W±D?^G Ǿ\b#y+OmsኬU䗅ߙbn]4^l:1jjEX9nނ|u׹˓??+>]__bn[ HV1WK*22"DUQ]xfMVs);vk̪V6XaW3I<ٳ▼~|Zv+Nıe1%R/4W&PUyzNlVd,a(+F;19tgF+]E]Z9rXE~'߳+]z V-aކ*eFFPH+Vl~ue'nyX*KX00[,*fi'6|Rכ:ϙ^s+Niؖ,&$Ad :{/_q]i֭ձ, DX8>H1CwJtoAo:EUi[s%~$W}?ºz9gbܶj,bzTdeD\f͗:[vRvיUme U¯6fyg-y=Vb"bJ_h6M󧻲֝jح[Y`J%юÃ|4Yn9tgF+]E]Z9rXE~'߳+]z COy +[eNKYdF!$Y7-#Dp+sY^$6IԨa=.X~_W.o3 uoyR1y~KU%GDUftVJº.?Hch w56Uxj0XXXXvEw*͛/7mI۳^eV6ʑRYr,,,,,aW3I<ٳΫWӱKe 1%/4W&Q󧻲֝jح[ŒX$ b%aVE,arWz .J߭m{,C".=@"vtۮ췙ЧY6ڐABSytD%5\Kj>\IFFBbJ"32*ArUor@,#HțK'L÷1 + ˾suU kWy^"ٲSGUnNݚ*U,`"ajXUO6l6u_2Vӱ,Y`LIT;ɵ^tv^ӭ[bY ,DZ1p}K-c܇>ނ|uҷ[^.K8H~?u~~ rPInXIhD=+ =m;fzDkFIfUt qV #Ju*3|rA$)jԝtAwh?C%Нq;ۨ^I=ifmi2AQҬGK4%`Dl͙lqK^l>eyh;bXw+͓k*}uZ+VIJX1bc+_ "[c}+ѽQWoֶ\!qt_7 `垠Wn)k͝W̯9bKXU sEymuW=ݗVjؖB"Q,VvEkRvw!ϻ{:7_~*4׹˒??+>]__R[LJ_Ɩ@YM?%x/;eբLĪEH+3f4?tN4EIBL(%;FQ\{h00[,*fi'6|Rכ:ϙ^s+Niؖ,&$Ad :{/_q]i֭ձ, DX8>H1CwJtoAo:EUi[s%~$W}?ºz9gi ̉qlF7j R8ohgnK峂~t[33'F\R7'5Vh\DU7lrЕnQ-Mts)aΨٸJR7:MrZ顛)Dj)XyM3ZRRZF3<ˁn9İCN*R);uQo.6Z9"ɒTuU)5g򝼅망|_9 <5ƬSt󲯜!RgWT՟vvU|*\NBʾr/ːWQU]RV)^yWHrEfa>N4Uk%w>:(f3vĥKWQU]RV)^yf{!RgWT՟vvU|*\NBʾr/KWQU]RV)^yWEr 3ʫS\j;y O;*Ⱦr.A]FyUuJkYo!ze_9B+*Mq?/]<"TuU)5g򝼅망|_9 <5ƬSt󲯜!RgWT՟vvU|*\NBʾr/qI,wS͑83}mUې_|djbLݱ)RgWT՟vv[_9&TuU)5g򝼅망|!RgWT՟vvU|*\NBʾr/KWQU]RV)^yWEr 3ʫS\j;y O;*Ⱦr.A]FyUuJkYo!ze_9B+*Mq?/]<"TuU)5g򝼅망|_9 TgWTվyNBʙ39"aVEla[s^΍-W_M+~rÏOgWWW,꿱n,H/'Z(h΂RUIؤZ vv>LQt?LY#^|f54f* C:$h,s $7Ǡ/q v4E9zFi00[,*fi'6|Rכ:ϙ^s+Niؖ,&$Ad :{/_q]i֭ձ, DX8>H1CwJtoAo:EUi[s%~$W}?ºz9gUv,$t^WO\ 3ןeZ$b]xQ &Ǐ{,.jYўB IaW3I<ٳ▼~|Zv+Nıe1%R/4W&PUyzNlVd,b%haVE,arWz .J߭m{,C".=@%xi`9$ۢ=4 S]-DgXs98inΓfGf֪2~^ q C ܖ؄"l3QU8eŵ$B".^~%Ch fDv-: .ęѤF IU sEymuW=ݗVjؖB"Q,VvEkRvw!ϻ{:7_~*4׹˒??+>]__R[LJ_Ɩ@eJ L0kCNR $դF`:7#Gt̥>rR˓<{ZlѝweY 1QDw+͓k*}uZ+VIJX1bc+_ "[c}+ѽQWoֶ\!qt_ `垠 .2K){ QgזYM&VeqoiwHW2pUt*t+;16^etiҢ2:={ Z&&&&r KL-led/!FۭFFK%Q]ޅzzggRPĭQ1zjjj̺JҭfdfrU sEymuW=ݗVjؖB"Q,VvEkRvw!ϻ{:7_~*4׹˒??+F]__`d9N*I-L).SqުK>1vneKTۦ 4\IFFBbJ"32*Bb.RMS{G"zSk PJ34=R2eQj.)db%TIu%%-}'.t*$n>r̺s.DwR^MRZ'^yٗNeӘKɻK\[YO;2̺sAIy7uIkyk9zf]9NbH;/&-qo?g/Q<˧2TIu%%-}'t]9 żOD.˧4\R3,r̺sMӘKɻK\[YO;2̺sAIy7uIkyk9zf]9NbH;/&-qo?g/Q<˧2TIu%%-}'t]9 żOD.˧1Q$ԗwTveәt*$n>r̺s.ĐyKɻK\[]__R[LJ_Ɩ@Z'/ 2k*en]__R[LJ_Ɩ@vF=2XT?μ@#+ GiIeam*Gy~6ΞWZublK!e(+F;)e v;ҽuwVkkbI~ޯvY4znb73dRYf3!ebFFIȦb*b؋ٟt\_teN!ĤKT9&dDguZ&b5L9hJ A¦!)dlK ^pxݧR%+)XvOqn;ٟ?=M([ Ę+{wQV|=m P+`-Gu[3uGɶ(1@I'ul&ؠ& wU?7_$~{O|b Ę+{wQV|=m P+`-Gu[3uGɶ(1@I'ul&ؠ& wU?7_$~{O|b Ę,Oqn;پsuGɴF;+e CwJtoAo:EUi[s%~$W}?ºz9gQUv,$M=A'i+7qdiM";I%Z]o1q"U sEymuW=ݗVjؖB (/F;)e v;ҽuwVkkbI~ޯvY)-cݯK =#I}) e(uHdJ#+ЯOQF31+TLAgޚ3.Ҵj5Y܀DĕH#\^l]AUOwe+:ձZ%KZi݆;s^΍-W_M+~rÏOgWWW,꿱nBҰY6[SBmI.*gI1l=DXq ahz;'Yy 'q"2Y(Lw+͓k*}uZ+VIJX1bc+_ "[c}+ѽQWoֶ\!qt_ `垠W DoGYȒ)kb/UHK`>ҒNb8ۉ2Z(DZĢb&plgΊ%]i23##23###2Zqx1wnLSq/9RNٙȌҤ LIT;ɵ^tv^ӭ[bY ,DZ1p}K-c܇>ނ|uҷ[^.K8H~?u~~ rPљNS$䧣?*L/gJUoZ芈ЛdDjUh?USG? Geɟ,I%-D] uՊ+ Tkt舼>ia&.fC5FhH<ͨYLҊ0a*$n>rNhsE#?Sy#-n]-Vw:jJTMU&J żODZ7NbH;/&-qo?g/Q<˧49 żOD.˧1Q$ԗwTveәt*$n>r̺s.DwR^MRZ'^yٗNeӘKɻK\[YO;2̺sAIy7uIkyk9zf]9NbH;/&-qo?g/Q<˧2\IŽvd扉F;+e CwJtoAo~*4׹˒??+>]__R[LJ_Ɩ@vF=2XT?μ@#+ GiIeahbJ_h6M󧻲֝jح[Y`J%юÃ|4Yn9tgF+]E]Z9rXE~'߳+]z Ku_7krH ވv1kޤZĆ Z/ZȌ;3aC!.Nh󤖛qm(r;I]i֭ձ!e(+F;)e v;ҽuwVkkbI~ޯvY)-cݯK ._'Ҝ;}/E:KjkwĞU3Q6D%Q;T_J%юÃ|4Yn9tgF+]E]Z9rXE~'߳+]z Ku_7krH)xօc0W1""CFmC+RT$ivX"Q,VvEkRvw!ϻ{:7_~*4׹˒??+>]__h4AtLɄ1elW(q. ޵SG$5l:&Yl6ޮwEuI)vTJHCfDFwZŢo*TÖܺlEhҷ 0박WFemM"305hLTqO6ˏ4T%DRL3#+EuɺqCXvOqn;ٟ?=MAbL=Żf~nH6(0Wd#{V$][gilPbXvOqn;ٟ?=MAbL=Żf~nH6(0Wd#{^$f{wQV󛯒?=MD1p}[-VrWz .J߭m{,C".=@%xi`9$MnbڛVH1CwJtoAo:EUi[s%~$W}?ºz9gUv,$c87ŰtU>*VIeqq=e,\IM!I(A)#3qYL]b%haVE,arWz .J߭m{,C".=@%xi`9$S"0|E2%i#bdDI ڇQZ( vvKZi݆;s^΍-W_M+~rÏOgWWW,꿱nmǢ_ 0vK5$k-Yj$MsvDZ1p}K-c܇>ނ|uҷ[^.K8H~?u~~ rP xHzJ"lIxA4EJ%Z!)ԏ).4*Ӎ%h8ҌJ-FZĢb&mlG fhZZM& ޚVe^# Ǡ΋'2 kJ-m)v+:Qvd DX8>H1CwJtoAo~*4׹˒??+>]__koLc`*)*-FQPZ}"iwFSG? Geɟ,I%-D] uՊ+ TvnqaزW -%M$W$RKDEFTL"aՊ żODEӚ.DwR^MRZ'^yٗNeӘKɻK\[YO;2̺sAIy7uIkyk9zf]9NbH<%%-OD&'4LNh1p}[-VrWz @QWoֶ\!qt_ `垠Wނ|uҷ[^.K8H~?u~~ rPInXIh'G~m1M2ܘ*Sfe+#"RPtu@; "eJ*ؓDR3DedFHKZi݆;s^΍-W_M+~rÏOgWWW,꿱n"nh,լ^ tJȥ:lԔ3Qvi#1bc+_ "[c}+ѽQWoֶ\!qt_ `垠W) @ DX8>H1CwJtoAo:EUi[s%~$W}?ºz9gi>(hʘiD,Α;H[֢Z3[U7Bt1.{ :IKFRFH%2"a|ӆ- Pbt舌LkZpi-BvVJ2B30w;?Q>#xI)(q %l #%%H6FGc?nނ|uڋѷ[^.K8H~?u~~ rP҆LrԶ^Ɍ.$J$J,ef]d0pM,$,oJm]__sF^΍-WWO6߭m{,C".=@4nނ|uzm/EhKoዔҢN>=}o]6f+`7ݺ'c{x}WT_8}Sj/}@sz>y}9_cꛋ}?ޏ_sW:O7Ǘ=N,!8}Sn/=Hsz>y}9_cꛋ}?ޏ_sW:O7Ǘ=N-!GuMooGݏ/x}Sn/=Hsz>y}9_cꛋ}?ޏ_tqT_{}rǩ7Ş 9v<=N-/m?ޏ_sW:O7Ǘ=N-!8}Sn/}Hsz>y}9_cꚋ}?ޏ_tqT_}W:O7Ǘ=N-/m?ޏ_sW:O7Ǘ=N-!8}Sn/}Hsz>y}9_cꛋ}?ޏ_tqT_}W:O7Ǘ=N-!8}Sn/}Hsz>y}9_cꛋ}?ޏ_sW:O7Ǘ=N-!GuMooGݏ/+zSq|[Cc9_cꛋ}?ޏ_sW:O7Ǘ=N-!8}Sn/}Hsz>y}9_cꛋ}?ޏ_sW:O7Ǘ=N,8}Sn/}Hsz>y}+zSq|[CcqT_}W:O7Ǘ=N-!8}Sn/}Hsz>y}+zSq|[Cc9_cꛋ}?ޏ_sW:O7Ǘ=N-!8}Sn/}Hsz>y}+z:~.X mo<ٲz%bos Ux../Euler3.jpg000666 000000 000000 00000136051 11164374160 011237 0ustar00000000 000000 JFIF>ExifII*1&i.Picasa0220 !|d898fa02ad5e40c10000000000000000R980100 (HHJFIFC  !"$"$C" Q !1AQa"237RVqu#BTbr$5CSt4%&Us= 1!4AQqr"Ra23#$Sbs ?J=&v&zZnj`4E J+\AӲ>5CIYVmC}@nUP*,-R F3NB;uߜle:9_RI2?'Ht0D+ѻ 4Ҭ6VrԹ;@ Nˋ+:krSFґfk(=k؝, -ʕd+T{AGSʝho!9[^% k]{aᚓieƙZX .[~v8 8{.1vu.]di:Ā'Gԫpt֙RBRr66ryǜ|OceaW|a\Pz,KC$ܗֲI!)7cx"4)ZFO#qBRR/{ m,SzЗT+ֳ{8>VOۉK,u5۰!LjCC%KkSS…MmOml]ּ́pudlLLÁHXRBJs>q{̞[`kl4vz+@^x#ǹ-Afq.DfA@7U4eRkXf ګgd6`a FBryƁ0.VZ ,A`Dh7%EMԪL2d>;&LJk~vHs ue(QG3Swuk cz)t7צXhq) #03^+ne Tpt+Oz-V윃!*l)$q}׎9 p&U}'t976]дc z-Muw+!z1DJkOY$L6u ` *?E27,Yl겡^ %Se%MsG4JJH<`ʬٵgrN[pzi |ИM+U&&+U F-7S:n.P}]:ɷᢡI#FKdd.' 3)5FR%VB" ON@;Iˁ>cyWn!4\Č^L aaJq2}?m~{s@S=hnVy#6񆀨ް'Tt2ҒR ifG e!f>,~C@Ut\rm6-9"I~Oy"iԴn{|Pw;.moJ`f:p:r&~/.ۨ͵I:ͼq6mvnܣ|M`?mrXyx->pX6ޓ~0.a%IO5j4[mɱe:`s +:ͪWQG(28 šui K6蔛.$VJ9:Kdd2e+d pAG %fv:~Z' /K} һM3jCifHsMyY ҺBjq)c z-w^g$gmr <‡J;` JmQE-VT<ugFh3\oI9Ѝ꫅ #XƳw-nt8ͯ%;7"_zY>YQ^ütM\L |v+(e*RTAL-՗q1=5mgTHbyŘÕ&$SdrN W6c@![(wi4u0~->ORfs\!\Nbb#y'J "迫B(d4@EIڪNo[=cFRY.:ܔ!K/rs2ܦym֧㘆kd(\cX>Pwnr_&C{hWIMw}҂oG2`M˸iPAet.]iօ vHTg%ˊK̨6;n#WM*Im:gjM8?)3t}F첄>.dҬt6J 5bƼϥV ZSYnRgO-KZXt̐HUkSn-.x?ƞ_r%sm;0J RNl#(i=S*5M&t_hl8yc{./2>| a/Eiz"KlDQ$`~S))8QEuYPXBֿlN01˅r II; +3F5qfyl6v<(#.n5rRN!:H Am[yjBHP`%. #@9 0֤()&@&6 '53'2Ԥòﴭfie+ABZZtjU^#) ! Md$FYa[QNv[\P9&r4 L$X:3P.34iG5*(GI\F 9$4cc A ABJyVkd ]eSꗋh"vEfZ98$l3G}7P.O7,HPܤqCRA3E,^<2漦Rݭ # y}HT$ou< Nz#};vrX@&~{g.!+BpA#:9JT̂RTl,ޤG7V k%BAXɹw]X=k-.<)>ƎV )$!˂7rXD+J:>ƪSAh`ߴsoe%FS`~x%z"m1WODBtc z-UTJMJߋ!@\_VNmubŝVT<"Ǯ4Xix>}8 lV2~ _) )P2tsh0F\  ͫ熭 BT,D6({AJJdnfմplNiPD[P֦լp #wiڮ,A #Oxsk[n%Ԥ$&{WjwI}(zSԛ4n՚n̰~0Poy[]"Hu%oSmSIJM`ΑǦԺg$irn7;NzJl=p)7H&ÿalz(P4&MԐ;88+_'?sӎ3d n߾h:PpwsnҤ,` `Pu A/i[p6v5$E*1\=jI"PD2 ӉܹA߽'mV6 D[Pp9)'b˭vqpNAI9)'a c"X'F!|bN`i(p~a) ڶ0z-JvWSf-;$uPRT<^F_ugS/0(ٗ*\8^%t9,B roQ;@N͆IPIw%Dlt{{^h"T^tDJL"[Gxնʹ?qVRr@s!ͻybi%)>/ 9oe%F3a;@>0艬y_= %z"QW2uRPnEmW[mubgUEuUI[k'|oUSOۼk]%H7dq^ rHhsƼd  Ug@퇍9 A͖2Bc퀨@ 18!$.c[AYZuKNP;x IJdAD=Un q3KIO"/s@BYJ5s.k!Y)'|' h:ͫaypF\Ը#Y I'_Nú0C~eiÕU&^n*#[WZq A}8ޥw*<}:tQ4 $.fPdܷ~iO=u^I]?oE4zqȖ4EYdp 1 xNfV{g,me%FS`~x%z"m1WODBtc z-ۜq&I֛W(rI퀶l1QEbs>V֦լp #k=U'_|c: 8ۭIzjU7Uo}(mub׬1 =b8zZZ?Td꜏ZbAD@>@'5$oGy}F85J ULRU{$NWۭFzbTmEfz ‹`QN+/sLt_ГiDgg@IخcP)$Abu%xc ;*DJabd*6[!roj@U4CV!OkUQk?BLW՞b-(R'B86 al*ŢXeD^iY3}FXB1M1@*DՖ[o9tk!]`IUƗhoM>e{!\I)#1dBLW՞%%Q W[*N>UFt*Zy"S. ھRUq_af<OB/96f.tHJ"iCH"NGwGtц1~}2[R(Y(^d7(r?<~t>2貳y&@Sj0Gvg_ZG=Mn(w.0$]Wք.+B(6W܅ٟE~^P}hB͢/(>!BmY{zafnF;3hf}yA 3jދ{3r1ٟE~^P}hF{3PVN^uٛ+BfmyA 3jދ{3r3ٟE~^PhBϢ/(>!BmY;zafnB͢/(>#Wք(Pͫ'z/U:f}yA >Ѕ dE꽇] 6Ј֔j1>G&&)HKYAĘPI]2Qhkj     &$$$ *'#* $    ^  !1"24A35BTUaqt#$Qsu6rv%RDVdFSbeEC 1!2Q3ASq"4RraB#$TbcC ?v2_i$DĬ) Pq  eyvy5YdViN3Sim:ul-? zٿ_3+Z1vV(Ag M[o%toy^S[XQ{)N!mcE[_ܥ8zmr>!^S[XQ{)N!mcE[_ܥ8zmr>!^S[XQ{)N!mcE[_ܥ8zmr>!^S[XQ{)N!mcE[_ܥ8zmp>!~S[_o={޶J!mq [-q N!mɟ?z)-7:?6kc]/_M$kQ_g\T;rvS(=mAz=o)gLQ(9Ka',oI l:AN9%GO>vgaJ]>:TUG/FvQOPL)9M,.1nM~YdtU~n4m]%2ffzZtGk#ZDrkY&mJLk~'Z%Zb$֢>zrxZur\BWs jY3vjQZ)(K.ݙ i]ƙ-6T `L,2ee(Ң{Z;XdS4.\_Cg{oi{Io+l"^+ XV3ݔ2n:ɩ:Ki}UIrZoJY5ex3`:_SVWӅ䶑MFHHe;[42FAC(W[Rk<SrX1_1Rm@6T~*P (ߊoJR}NnЭs1ޚ3?Gu3M_V-z>*9>N=;KCݲ?zh~9[i2MH$oΎ1.U8~:BEֶwV $8c.5n/b<_yo8dMEr{Vlj7Jn,t/[H.g"O Ԉ@hPLzvAkn/)Iׅ?wKlhX8ofN&itɗ_Z!c?9QD[@Ŝ#УHIlM<>MGc3b2;Qy HM/~Y/:)u6~PɡD&gTk{|vRk*tYi-巅.\Tfrv0I&tWJm!ey/)Eh;/QY_턶#ƬV a1 ` `zYjl'_Ɗ(lg5Oivkfٵ˭ k7 Axr8avOͰQJ.,RI׾XƷ_C#u%Яl.ݢ0g͢ll294W(Ƹz )M'A (o{9ibVcX"`p9AZ۫'eݚoGYL!)):UGf;aY/eeu~A5Z]Ost[p$hrɗ.ys :fV!UirEVge7"խ|Hv,iO٥]đcsŖ>ɻ/LƳ.[K֥zv'jWA(MI[%!%5f6и(Pcld~5%F;_sdSSU^BZlWs )o幽 D  +ӖBjߋm^UUUM\ qw_YpNӠ׵km审yakk5,CMPʹ2IE<ϖZdV(zV=}],i)]Z k5P]˲j-$sGy.$W.IԶ5_PJSCv+|[n"F~m]@[[[[c8'h,\\)hk=5ъ=Nrìgֻ<לK.EmLWgL-\ғH+,ӕ(q&]UhڭUWw3kgW鯡v[;e7t=f,K!khz O\+(r|Sw)W\z0I 'baM іA KyuM9bI=Icm6ܢWRʬl)*NYxGj@[]06[/wWL4RYB5i+ °nKCeZ-.m4[~YV{f6[3p+C ӕTZ?u4VvJSWoKwsyOxWo WMzM=5  rU,ɛ ߳4kMh~˗e6v=T>mM}aC,Rqŏ Q0xJ!?)D8(bC&AUGA^lvO(TޣUV>9&qvyŸ]g:Ak$2Ok>?֮S`P?ZSayN?ρoά?+l|Nuf_?֧:rQ~Y9?M9՛~Ð?ρoά+l|Nuf_,`s~js7O!7k>?֧:rQxs~js7O!eSY~W9 (?ZSaYFg7VoCvo|Nuf_,`>ZY~W9 (yg7ռSaYFg7՜SaYNg7ռSaYNg7՜SaYNg7VnCvo|[ά?+|Nuf_,`vsvjs7O,`vsvjuf_|[ά?+l+Z,jv̛ԣbX k]}N/e29^$xF{T1 G d]aŒE'~O3eS#=ρo՛~rS~Y9;Mg:wrS~Y9;Mo:rQ~Y9;M9כ~Ð=߁oiμ?+7=߁oiμ?+lNu_,`vs~Zs7O!e{ӝy~W9 (?ݭVSaYFo7^oB6k~?է:rQ~[9?M9כ~Ð=߁oiμ?+l$XzvU-n]{:::2\0egR?Cp6ٻ9:Yf|JQDh?f>Mbz^G*S/5ަ:<2Y'Z}Ob$<\[MO7oݻܩo]u))M2a4f2Oȿvf>Կ_n]RY'S/ ^?SoS4N4ldi(#$`E ` Ww.Y^t_&#!74>}7O?U̷aާ}h8? rAp)8eRHާIխ^d[h&ޒJt,eNY|vY'+`ꓦ ~Oc޾ o~MF[%tC5kx P~.?.:V]̬F$J8Gn\I0P @(xoYVVV *@ pxnʰSZiTZ`P @(O6 U0J`(taT4HP @(#_?ی2VGT*Q# aцARU50P @({KqWU*ʘ%J0d`q:0*NT֚$V(P @(^~̷]}~Vw=N Jo`-Nee 2 3A AR;ϋ=sVIv,w$M` <6|V.79{+o>5ox}%qZ^Ӽx>Kټ_wսaiz{7N㚷l>/Of~5ox}%qZ^Ӽ5ox}%qZ^ӼymmMOx[6I\}֗xi9{+o>9{+o>+=[T([ ƒ/RGw*zELm&n26VjJWy>9{+o> mY KnP,nQ1,mE/Of~++#6FPAR9e+Dwy#5ox}%qZټN㚷l>/Of~5ox}%qZ^Ӽx>Kټ_wx>Kټ_wtmC-pbٻv,jw`gp*+ѩwS.o DyYWOf~ o~MB%t Z=@(gH/p׉xq@C xK[̡fV p0A;)KB>d6a# 7pU7Q$@ђJPI7RZ. @(W$Hn-ʑ &Ոs '*cS-g΃~.MԛdGnR"[9`p`Lqd84uP @(k4 ЬwB,B2V@ B@ ȒcE]LjqFYCx%fBB u`J$ hc!诺ٷn'vɻ?{`L0&U(k4 ЬwB,B2V@ BA$Ƌ'I㼁g:xค%IGE$NJ7] u@(!϶%;qh3gusd8y-3D ZwMeETP f!cT(H #mђjaK4-7*$4l ANӣ$V(P< x~{S#9ۛ?ٖkGtg߬jxkYwKМկioP}o^' Mxwi^7xepSSA*|lK"f*1j}J 6boÕd#r`gk+6QO P @(,XH7WVy m ' Ws˻+RF`N?4&%\N;(x71O,(Rв@8dlA ReIPZHP @Z=.C +h%aK0$ P dI1.HH,x<[̡Yepr :%JN4&V d=Z[6۠ݿvcS~7g3 ʢX%k%#7vQBUUP(F )hjaK4-7*$4l AN4ӣ$V(=Yħv-wl]ޙqo%x< a,@ʋzV@B*H #mtMQ/⹉f%YY5ԆtdP< x~{S#9ۛ?ٖkGtgjxkYwKМկioP}o^' MxwP5]+Xwmr~x4yT} FvYQQ4<tW)Swsn[~rd}VL `@euRbQ?5 њ Tbnۄ߻og\ 8bȋɹ,zcݣ"^FrVT Y @9Y% DYQ4N;x(/,Oky^ NTx\AېH:DBfkIFh EJ׶KGn*-YUUP(F )e&7\³B}RHlFPARڑ%M Kfݻtjwo&`hhh*3@3ARc,0ʋ|VEf!cUT$ 6^$p%dedbFc`6VVR @ ֧Rd3ZeFhhZNZ ]Ds390KD"oA4kMd-䴹twЮm \g*23+(z4MQ{{%HE928qɁuG73AQyǁjtߘ}BW;Dr~~̷]}~Vw<ܫ3/7?U}nS^˺^{OWРR7+w#㎆ĆTea 3<cjObYv/FGkidJcRJ @Jɶ6$Pm S4>?\q[{,7&3{~@lŸwH1p6&"6ᑢE,p}ox⽿nXzlvS;GoOs#nj\Lq%stx\B3MSq ,]*!\9Jŷx%   t"2[^o*Hqj0(Y%bmk|6q<:mJmۈ>n\wgwK?wlxSj}&&ݖn.g~Ӧ. LM-qݜ]/0gMM\D+M2'?`{ujT~q!d1VD`2k16{vqwt_8}N6Ǐ%6]Ie;۳tn\wgwK?wlxSj}&&ݖn.g~Ӧ."ש-5͘nއG˼pEr6K:5vD(-/ .8tW +, rc b>SnsNLM-qݜ]/0gMMqqbmk|6q<:mJm\B!k:d\,]{u*1<`ڋS8*8*In.g~Ӧݸ_Ie;۳trLBpX:R˴V6%Ydd$^ܔtJ'rMuݚEGbmk|6q<:mJm\F\AvZ㽻8_/a'NcǒW16{vqwt_8}N6Ǐ%6!qICe;󋻥t>7ۜdgLP_3^ pmݶ{la<煋"8mYbP `l|T[E b9UU@r@`#hd'_s oJ21I#1 ++)BH kS 4 @(38`Y$턊WPUe*P$20`\⨴g$I bYm VFVF)$f6eee(@  tA:2E P @( %ż|ql%]ƥ7rZKأ^lI%d w2oqѤ:IG$l$Gï&s 0>ؔŠUK;91 '0U(M>GGGi/,R-%Q6$]{;whX$DY#6#&s 0P< x~{S#9ۛOٖkGte߬jxiYwKМկioP.eNXA"6j:~ra?FATOIŷ֜'6uY#|cz8Tau*Y(Pn)`Z99qW? BS)ZL!uI~B=A N42NzAjq˼o-Y߅oW>"xwaqf  hݕQ]]Pt3$h%ctcOaC5y GÖx sF]be=甴RQBP a,@ʋzV@B*H #m֎\ijB}RHlFPARDӣ$V(C_unݺNf5;vNOS0`@m䴹R*ZIH7Td(fVQ$&wNG4i,NG",IdpɁuD5B P @( %ż|sl%^Yƥ7rZKأ^lI%d w2oqѤ:IG$l$Gï&sNZ ]Ds390KL9`,P @(dOm䴑KHԻKI{k͉$<^`tNKKhThɣ9[v"ȁv0,6 P -#z\<%iWq$'k< ?c~ci \uQwͧpggz#ʺ2N}SZwj5<5,Nj״7|A @( Z.*%(S ,sr~@ Ѕ+-#>ShC+ 뒒!$z IhP$P @(%(S ,sr~A VZ:F]Luj0V%$BH A5:(СZ@?N(IYe\3C)~ P tFm)? k,\&vJf(S:. A遒@r qo&##i#vqwܖ(כIgyY.y G4i,NE",IdpɁuD5B z+m۷A ݻ~Ƨvn)f Eqo&##i#wܖ(כIgyY.| G4i,NE",GGï&s֐ 0P @(1^Zܣl/m}KV:n"W}?-#nVFfT+$P @(ڏ?ʿ>~8u?oǧ+^&Z;NOJc6 nm?f[?+?nUw꟪~QIe/BsVhP@k"[_m$F]GWHԴѬR6QίI84TNƲ^^rjz[ #8mP3a[Q4%'wjbktL3б,W )Yhu2իDXnG\ 8'#A@dBiP @(66F`& pd;G=09 uWYr0Ar`A ֧R%FS$P @f݅eg^[u;kTi.:kFӭıl[6]67 2h?в8=k)» 9^{9Hڻm1rN޽Şj/t녫d m|? C@|\+ wM^oKaN[=并I.gurgg>&X^2;Q$%tRrvViK DĊHtu~.qD">y!' سln׽fAׇ\yyba سln׽fAׇ\yyf=v,mcuqqٕ{Cu [? 2jLG! v|˷G{f !)] سln׽fAׇ\yyeU.aw :88ڽnŝcv0ֽlc28#;2`-[>Inm.wK8|Y\aXƬW([4]՚HİK4NH[7d"f!qwRCrN>aw :88U2aw :88U سln׽fAׇ\yyf=v,mcuqqٕ{=v,mcuqqٵ{l}0݋;a{xdxqǜGwe^z[zƣ2Ekq%M 0O?{&m')%nDŦR+2|(EBv#w7 bmu75z{Y67ck:88aʲaw :88U سln׽fAׇ\yyf=v,mcuqqٕ{=v,mcuqqٵ{l}0݋;a{xdxqǜGwe^y}0݋;a{xdxqǜGwm^z[L7bᱻ{^61^}qW^.dVS ).|(E;!;DBTzsXiNOJX#j#.o DyWOf~ o~MF%t Z=@(( ˵:&\! !mXx2H1B9BZGXI?D{w8 zA aɁG\ZH\]J@(op s͂LJ9I#ђG -udqn9GaH V 90 kS"Qqte*Evgzt]ōm[y qdIx.LZ8ɍ)2 N3o(y,R{gZw`$bwzvGD]7b7 qhLz0/RNoVb̄ؔŠUK;91 '0U `O_N]~P< x~{S#9ۛOٖkGte߬jxkYwKМկioPW+a ]U@({(la$T͔I=ikc%%v^{w8 zA aɁG\ZH\]J@(op s͂L$J9I#ђG -SJ:JJ쿒5Ża= X0#ANJ..ZHP _7wLެvp-ʍ:MhuhNC-.5G>&\Dr],O.&HF%Cz^k}wVW6\lv4daׯU"UPj?d)u{=Yħv-wl]ޙqo%x< @( ?ˌnIa Iw>p# $u_c;ڝ76PQ5~~̷]}~Vw<ܫ3/7?UfS^˺^{OWР[N@({(l`$T͔I=ijQ2M]#[NQc UL :DU@([fPaaf==?(`P _7wHGܶ< Ȓ4NxYH0<(OQoTfo2G %<^7m-2C(lq$@gTP h IG!KyZ_b>ؔŠUK;91 '0U()[4oE"4rG"IWB jt-i%˼:gy#xX쥑$Ig j^bP< x~{S#9ۛOٖkGte߬jxkwKМկio/;_^.@,m엶v#yaɩq;+jSFi M&ӱ=6ھk ezq^B+ `Z &qŻa= X0#ANJ..ZHP @OEQ,3 ,,ǧr Nd H)*VzUCP |r-ˆ!ePaaf==?x.֒$Is+2IYN6osߴ{NWe=v/.;cG>osޣ.K^\.w k3ď|<翼c1D9ۛOٖkGte߬jxkYwKМկioPW+-jt"(BUa c9'jj3++XATrj P @( ȷ #@Xfb@I욚!I#2e%YXJT>h`P @OEQ,3 ,,ǧr NdHVRU  ZNM4ϊ(FFVRUVRC+A(jt&)0U@ ZeQJz9!'JjTq;+ ]+ ;7xw]ikYK4QbxIo챨^EP @(N9cxD)9:H nL$c㡩д[IȖ.ZH]w!cFĒ&>VB7ip-Q;V|Bv-wl]ޙqo%< @(;xHFHPૡFF>: Fq%ݻg.b^E26[w{ėX'#ArW$^`51v:agek3]?x'y75t]'5kx -jtPnG! *e 1傓55FB6Fee*J!G&|@(p9YTf +(XYO@,ɩ23+)VRU  95C @(>w\w;$ P 9YIVRYI AtН]B,U$pkCbVinmJT}V7ERMpYE.vIؾk]6xıFGhY:! $0H@()[4oG"4rG"IWBɁ|t5:Ԗ og<$7Vi/!3oa#<8+)c!V stF^QHP @G&e$ded`$R6VU`  V4ldӪ X_ez}쪢ު)fʪJ."ʼn2MUsּOjtߘ}BW;DrG3]si2wYވr̼TVO zK.z< _{BP @xjel?˵:>9Dr @VP0X)8STd)#dfVR+XATrj P @( _G*,u5~~̷]}~Vw<ܫ3/7?UfS^˺^{OWР[N@( {:@# )zm/A?QŞP @(='{˜'Tq<P @{@Oϝ8Ny@(W=2Pp2ïVdi|zz_\0ޗ&˾rʍwbVchn@(!϶%;qh3guc'9iOW143&i 3#+#A"ѲTAHɭ(a,o Kz2*( 'M&QP @(#s2oH H4l@jU(;ڝ76PQl5~~̷]}~Vw<ܫ3/7?UfS^˺^{OWР}kI ]2L^*VwDy7S KsOU5Wv%` BZq"!ϣ8 eTki{Zs;W.p;tQP @(?w\v;$ P {~tbB}ώB`TqP @(dee%YHee$29҆C2>އkZs:Olou=BzՔ+]i "FQ vMԬ,&6ᵻeuS8qy2ь}բ][鼎6q{:Rn^BDťyl :u<ܾVwen;K8twwgMq'{$txr XbH|aqqn C8 #fdt`ދ$NjNPڴKwvqitG8wNwG)7]]PԧHg9$-`д,ekrs-qRuD.yE;PZ݋+XڲJ]ls%Z.ϫDťyl :uwwgMq'{$txr}Z%ݕ-.gNIӮ&/K+qݜZ]70`]M_Gj[鼎6q{:Rn5@Dw:om>*lu>9ۛOٖkGte߬jxkYwKМկiob]?AkS8P @{@Oϝ8Ny@(;W.p;tQP @() V :PM5S$`, M  ʣs#BNVQ(PQJHe`r# NR%zFݚ(cӌȠ]cYF1IDcf@#JJڣ(((ZmNvqh3gusd8y-MH\̛}̌9CFʬAPA Ƒ4bimĘ$!U|r%fDDf0V+.2-J)Ȼ⨁9ǁjtߘ}BW;Dr~~̷]}~Vw<ܫ3/7?UfS^˺^{OWР[N@(='{˜'Tq<P @{@t ̞( pV8a׫tݲVұ-G@(FFVRUVRC+A(jt&I)0U@ ZeQJz9!'JjQP @(>e!GJT:iwuv@:b7?dts玱3iRҍTs>ؔŠUK;91 '0U(T#+q,Bo22a!H*XjT#隤Civ;и( w SubHd $ucy (Z@c;ڝ76PQ5~~̷]}~Vw<ܫ3/7?UfS^˺^{OWР[N@(:Gs1)w>@@g]}!Y0K~W[P @(UVRC+A(jt&I)0U@ ZeQJz9!'JjTqP @(dee%YHee$29҆Bd™#ePZhTeU=$p:G@(=G=Sƪʲ7hƜ6KGG@LRї.w= N|vwSXKuУiOl"#!yq)Z4%{FATs=Yħv-wl]ޙqo%x< @(S#+q,Bo22q!H*Xhʄ}/Sm.GyXnRn I,$. o!3e]+Hc;ڝ76PQ5~~̷]}~Vw<ܫ3/7?UfS^˺^{OWРоpB ׭vBXB3Ͻ8HʌjqD3#+XAZcTtg P @}##+)*C+)! 5:$n *Be-2%=吓ե5U(PQJHe`r# N#[2FʠШY@L:zIOG29d$uiMU*"P @() V :PL56@Ш5/ N<uPVCW@8@(V$[HeR"4\TJmI-ʸ, rfӪ:BX%[+#eUQK4eTUUbP)u )OjzNZ ]Ds:qZg*P GuV/X'eVeb CT8MG9 $wpP*0Đ22IB *QEҴ@CX1YNOJcV nm?f[?+?nU꟪~QIe/BsVhP ݨBܱ dwsߒ%.9+*F8?69{%KItLԙ:`A?i4i}aGG#Pz(P^\u;$ P 9YIVRYI AtЙ$kpHYT+(iGOI)G,)QP @(>e!GJ F dAiPTtdrIҚ UEP }!AHjFN.qn!CLy@ѐ-C.QM^!UP UIk{k #r6#!PfH?DOiAQ-f;C:7!eeT~a|)#ѱm:a,o Kz2*( /ܶUDYħv-wl]ޙqo%< @(=OKK±x7xi;NOJDNOѣ.o DyWOf^ o~MF%t Z=@(<5 _ڝT;ڿoysۤ*'P @(dee%YHee$29҆Bd5D{uQ䌀 :h:y^D P }!AHjFN.qn!CLy@ѐ-C.QM^!UP }!AHh.-D30hrI`O6RHdKb}LE5z>(TrP @wWцw7]WůToۼ@.s2KeR%ͱLb[yd!Hʡ냸J%'tLm.%j\aJ1$ PH1MuTHP @[]+X]\߳~$MGj#;TˍSCiIh-f9VL2>+&v!Y]W+Ɗjtߘ}BTX#j#.o DyWOf^ o~MF%t Z=@(<5 _ڝTaKWv>K`}I-G@(op8t8a@ e*y0 A+Q$\[gaF8$ldKbt˔SWUG!@(op8t8a@ e*y0 A+Q$\[gaF8$ldKbt˔SWUG!@(op8t8a@ e*y0 A+Q$^۩xG[he rNN@szbB9 @(vZg5(uM.nYWFmdFڼ*!HKKMXjRf&#[U(Pdey-3]=2;Xo `"kyY 3 AARt#障Civ;и( w SubHd $` zt P @(-,oq fH<2> FvYQdEB?c~ci Qcagek3]?x'75]'5kx -jtP @}G##+*C+)! 5::l™#fPZhTeU=$p:G@(op8t8a@ e*y0 A+*2quDt (`$͔}؟S.QM^!UP D}!AHjFN.qn!CLe$ r[\QP @(+4LHFIJ>@sȂ TʅKU &9NA<&pzq3eD9@(<=Te7<SZGC,#h1p%TLQE=2;±x7C *PDJP>ڭ&6լd6E##yVלbTJm@^)€6}S#+q,Bo22e,5R*4NC! h\laHSubHd $` 6QEδ@(x,M%sG+ Ds?߷6-{_}7* ?OiYפ9^({}0ɆMx6NB,% (8l&5cb~`k5wv%` BZq"!ͣ8 e-cvM#kNbP @}G##+)*C+)! 5:dn *Be-2%=吓ե5T@8@([{á C)SɁ\XJ]Q"?"C($f+*rr\'˜SQP @(+4LHFIJ>@sȂ TʅKU &9NA<&Hn@zq3gD9@({[2)" By@#1PujDВб<'  *qDJESRI9-5"qfimAQ @p"ߴ6DO b {"HFJDNwnjM}}_Vwen;K8twwgMq'{$txr}Z%ݕ-.gNIӮ&/K+qݜZ]70`]M_Gj[鼎6q{:Rn5@Dw:om>*lu>9ۛOٖkGte߬jxkYwKМկiob]?AkS8P @(IVRYI AtЙ,kEűm7ʲ`qQY03 꺄M+F(` <#x-M%sG,Qwͧpggz#ʺ2O}SZoj5<5,Nj״7|A @( Ik %uiӵ-ϗT8 @([{á C)SɁ\XJ]Q"$C< 1Ƈ$ e$ r[\B9 @({[2)" By@#1PujDВб<'  *qDJP @Wh+ ! |0@#q VM - sxxM܁!f*G1@(iwܬ|q#3pN#$hNׇɞqW0`LNҰ#V(p5*P$Ke(A3$PPvC.-u(OAE Osf܇swdPy րP5]+Xwmr~x4yT}@CX1YNOJcV nm?f[?+?nU꟪~QIe/BsVhP @h/ ;/:ee$2dGJN7fSqx( e 9mv m+FҒHG@(op8t8a@ e*y0 A+Q$\[gaF8$ldKbt˔SWUG!@(kt1 V]%$BA(@@#XJTPhIhX l| B.&TֈG1@(iwܬHd<8 d29AƎ4<ݧk+q!<91a$)`F9@(KeC&8vop' 4t.8{Y[ Ɍgܥ} 0A$M+5iP hx@sȂ TʅKUF-o!c <ѱї*'6Ұ"UP Mr!|q#3pN#$hNӇɞqW0`LNҰ#V(Pm.{ Gg 7G0H8en$2g&1cr 22<2p@(M^MKG_+ &Ѡ[Ù/:Fy.U= @(k4 ФwB,B2V@ B@ ȒcE]LFYCx%fBB u`J$IhL=  ?c~ci \uQuŧpggz#ʺ2O}SZoj5<5,Nj״7|A @@~XSז B+yՕF +*PtH~-2X$MvH䍃fד9Lj0op8t8a@ e*y0 A+Q$\[gaF8$ldKbt˔SWUG!@(op8t8a@ e*y0 A+Q$\ۣRXOG lAlO(GąTrP @( 6|=ĆLq#3`N#$h C]p3Ó1J_`IšVjӘP @IV^$2cqgk 2p GHNӇɞqW0`LNҰ#VP ]Ҡ)1L|`2RP#rwȖΐOuj0V%$BH A5:(СZH/}}Y{FvR3%KSBԇG  $iu6T}E=pٕ^6.F@(l ФwB,B2V@ B@ ȒcE2u2cJo2f)$*J hCw:om>+8Xj#.o DyWOf^ o~MF%t Z=@( Vr.kJR{ ,F+en2 |˟H ,5ZkJv[)iM8 #P~̝ۜdJ;IߓӎH[{á C)SɁ\XQ$\[gaF8$l3ܖrj|Q (Pn&$l)" By@#1*]ZQ4$,qr 6>BCrІ 8u%QP @($]+/1ď83{8o`q'MwiHdLc8+de~0y &dM+5iP @(&YxɁ$yq0|ds!:hx^pd#09R2pUG P @(%(S ,sr~A VZ:F]Luj0V%$BH A5:(СZ@7wt:k ZIeRZ-](D(L92GnH}F4d=v/.;cG>os4{Iv0lc1H{{E״=v/.;cG>osߴ{Emc1݋˅a-{c=8ϛǜu jZbRXH m'(468bZneN{SQl5^Z~̷]}~Vw<ܫ3/7?U}fS^˺^{OWР[N@( M ɔgk$RD8Y":ƪ\'uԩujDВб<' 0\Lǭ*bP @(^b@ 66JHPDjT*]Z4$,qr 6>C@=`Z"UP Mr!H;X7a :Btv=ĆL3nRFW bp(Pn)`Z99qW? BS)ZL!uI~B=A N4(V(Pn)`Z99qW? yBS)ZL!uI~B=A N4(V(p`D붗$P^Hȷ1Jl #cRO8@jP zǁjtߘ}BW;DrG3]{qi2wYވr̼TVO zK.z< _{BP @xjel?˵:{[2)" By@#1PujDВб<'  *qDJP @Wh+ ! |0@#q VM - sxxM܁!fhTsP @( vWJH0IBDcdg"Z:BTwVpr:䤈I?! S% +HP @( vJ0- x8eyBS)ZL!rRD$ApAFB@(ktL3б,W )Yhu2իDXnG\ 8'#A@dBiWau}fW^7|w6Y!e52$0 m?GR [kY8[KӉk,2lpr΀@(k< ?c~ci \uQwͧpggz#ʺ2O}SZwj5<5,Nj״7|A @( Z.*P DĀXmtl A cU*2RB%cx/O 7 @=`RZ"UP DĀXm%$BA(@"`F4\eBW-T#҄&LHJTsP @( v$Z2p$Yd %:\9Tt4<NVC&xrc7)_p#+N' iXNbP @(.BfcX/s @ )Yhu2իDXnG\ 8'#A@LBi"P @(66F`& pd;G=09 uWYr0Ar`A ֧R%FR$_UU4]褬(a˨YD#Bɸ$:P< x~{S#9ۛOٖkGte߬jxkYwKМկioPW+a ]U@(kt1 V]%$BA(@"`F5R*.T(Z89!!!}ENhTsP @( 6|=ĆLq#3`N#$hNӇɞqW0`LNҰ#V(Pm.{ Gg 7G0H8en$2g&1cr 22<2p@(ktL3б,W )Yh u2C#%O5pOP":8t(V(op s͂LJ9I#ђG -SJ:Id{w8 zA aɁG\ZH\]ܶ< Ȓ4NxYH0<+I?F}GRVmݸ\ZQ$R5 ͹NȠ = cǁgw:om>+9Xj#.o DyWOf^ o~MF%t Z=@( 'lu,,9 Ō&k-o ]_[3(tU_&Nc ҧy<+9/{^JemPXMl]Q&ǵ1@(gw,w*L,? 0?!:hx NV Ɍgܥ} 0A$̜)`F P @($]+/1ď83{8o`q'MwiHdLc8+de~0y &' iXNbP @(h |=1Čg 7G0H8.8{Y[ Ɍgܥ} 0A$̜)`F P @(&$ Fx3`$lHdK]h)+#[NQc UL :Ȕ\]JPPP @( "'8Q $I$)$=${Z:JJq `Ó :(3fxІWF %Hv)$iekx3e]?x'75]'5kx P @(\} 7koĉ@gjUq*hx&H ",Xa"z7B0SR Etg c6K훁=n$ Iȼef_~'~nJ"whكHXlj },t%2 @(,Oq fH<*> FvYQ*2^idx|^n!"ʡ.7cp$) 9+Z`PƥkzotqD=wdcb"C'#/LZޝ;)Q5+k)SS[ Qyv/e;t(J$jvw/H'nQ(6z}֯I$[U"!M= @OTƧ 7G(E>Vx7) LlHɈ֐ʔP @(h ZwMݘeETP f!cUT$ 6(tRMQzәjVYZS@yP/I&t|N{^4 I~m='ꌡծ=̫\ŦGx\ejFIn('y֚N69:P `l|T[E b9UU@r@`#hE$w9@(Oekx3]?x'75]'5kx P @(P @(P @(P @(P @(P @(Pwͧggz#ʺ2O}SZoj5<5,Nj״7|A @(P @(P @(P @(P @(P @(P @(9;ۛ?ٖkGtԓծ۳\)ƺKua ov`s}^GϹ9qjW~arkKK I֦p--z𹨻u~ Ny >osN=q >?w4ۯ+i #zsN=q >?w4ۯ+i #zsN=q >?w4ۯ+i #zsN=q >?w4ۯ+i #zsN=q >?w4ۯ+i #zsN=q >?w4ۯ+i #zsN=q >?w4ۯ+i &9y_ NxpmIӚqוPa9y_ NxpmIӚqוPa9y_ NxpmIӚqוPa9y_ NxpmI78(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg~868(Zv{o0Hޜӏnrg^vĶNv.9<9~{voCbU lIZ^q./FAQ.htm000666 000000 000000 00000063272 13751324310 010517 0ustar00000000 000000 lp_solve Frequently Asked Questions

lp_solve Frequently Asked Questions

- Where can I find the latest version of lp_solve?
There is a google group (https://groups.google.com/g/lp_solve) that bundles all activities of the lp_solve community. You have to register but this is for free. You will find there the latest sources, examples and manuals.

- Can I use lp_solve in commercial code?
Yes you can. However read the GNU LESSER GENERAL PUBLIC LICENSE which you can find in LGPL.txt

- Please explain what this LGPL license exactly means. I don't understand it.
The LGPL is as clear as fog on what is allowed, what is not, and what is commercial. We use the following structure for determining the applicability of LGPL for a particular setting (which nobody has disagreed with yet):

The LGPL "decision tree/truth table" essentially consists of the following structure:

               lp_solve used
                as compiled
                 library?
                 Yes    No
                -----------
lp_solve   Yes |  B1 |  B2 |
code was       |-----|-----|
modified?   No |  A  |  B3 |
                -----------

A: "Work that uses the library"
B: "Work based on the library"

Case A: Since no lp_solve code has been changed and it is used purely as a library based on distributed original code, only conspicuously placed copyright/citation information and the reference to where the source may be obtained is necessary. No part of your own code has to be provided and it can be protected and licensed as you wish.

Case B1: The full code of the modified lp_solve library has to be distributed or made very easily available with full credits and license information (optionally LGPL or GPL). Your own source code does *not* have to be included and it can be protected and licensed as you wish.

Case B2: The full code of the modified lp_solve library has to be distributed or made very easily available with full credits and license information (optionally LGPL or GPL). Your own code *has* to be made public/reverse engineer-able and be licensed under either LGPL or GPL.

Case B3: Since no lp_solve code has been changed and it is used as a linked-in library based on distributed original code, only conspicuously placed copyright information and the reference to where the source may be obtained is necessary. Your own code *has* to be made public/reverse engineer-able and be licensed under either LGPL or GPL.

You have to make a judicious determination based on this. If your code falls under the categories B2 or B3, and the terms are unacceptable to you (or the company you represent), then our interpretation of the LGPL is that you have to find a suitable commercial arrangement/licensing with the copyright holders of lp_solve. If this is applicable to you, then you can address any mail about licensing/copyrights to us we will resolve this.

- But how much does lp_solve costs me?

lp_solve is totally free - gratis - if you follow the rules of the LGPL. You may of course ask money for code you have developed or added, but only for that part, and the openness provisions of the LGPL have to be respected. If you are not willing to respect this, then the only recourse is that you seek an agreement with the copyright holders of the appropriate parts of lp_solve.

- How should lp_solve be cited when I use it?

lpsolve citation data
----------------------
Description     : Open source (Mixed-Integer) Linear Programming system
Language        : Multi-platform, pure ANSI C / POSIX source code, Lex/Yacc based parsing
Official name   : lp_solve (alternatively lpsolve)
Release data    : Version 5.1.0.0 dated 1 May 2004
Co-developers   : Michel Berkelaar, Kjell Eikland, Peter Notebaert
Licence terms   : GNU LGPL (Lesser General Public Licence)
Citation policy : General references as per LGPL
                  Module specific references as specified therein
This text is also in citations.txt

- What are the default bounds on variables?
As all (at least, simplex) lp solvers, the default lower bound on a variable is 0 and the default upper bound is unlimited.

- Is it possible to set negative bounds on variables?
Yes, this is perfectly possible.

- Is it possible to set a minus infinite lower bound on a variable?
Yes, this is possible. In the lp format, use as lower bound -Inf. In the mps format, in the BOUNDS section use FR
If you use the API interface, use get_infinite(lp)
Note that lp_solve splits this variable in 2 if there is a positive or no upper bound. This is done automatically by lp_solve. Because of this, the model becomes larger and thus can take some more time to solve, so only put a minus infinity lower bound on a variable when it is needed.

- What is the layout of the lp/mps/CPLEX format?
See the help file

- When I call the API call solve(), several messages are printed on screen. How can I disable those messages?
Use the set_verbose API call. The default is NORMAL (4). Changing this to IMPORTANT (3) already disables a lot of messages.

- lp_solve fails to solve my model or it takes a very long time to solve my model. What can I do?
lp_solve has a lot of options. Consider to use the following:

  1. Use the LUSOL bfp. See Basis Factorization Packages. This will improve speed and numerical stability considerably. This bfp will probably be the default in a later lp_solve version.
  2. Use scaling. See scaling and set_scaling. This will improve numerical stability and even performance considerably.
  3. Use presolve. Presolve eliminates variables and constraints where possible. This makes the model smaller so that it is solved faster. But presolve also takes some time, so it depends on the model if the total time is faster or even slower.
  4. If the model has integer variables, look at branching options and tolerance gaps. Especially, look at the following API calls: set_mip_gap, set_break_at_first set_break_at_value set_bb_floorfirst set_bb_depthlimit set_solutionlimit set_bb_rule
If you use the lp_solve command line program, each of these options can be set via a command line option. See lp_solve -h or lp_solve command.

- Can lp_solve handle non-linear equations?
No, lp_solve can only handle linear constraints. However it also supports integer and semi-continuous variables and special ordered sets. This can be a help to simulate non-linearity.

- Can lp_solve handle ratios?
Ratios can be converted to linear equations. See the help file.

- I get a parse error on my lp-file, but I don't see any error in the formulation I have done. What is wrong here?
Have you entered your model via Word? Then the problem will probably be that some characters have ascii codes that are not recognised by lp_solve. For example, Word changes the minus sign (-) to another character that also looks like a minus sign, but it is a bit longer. The ascii code of this character is different from the ascii code of the real minus sign and lp_solve has problem with it. However you see a - on screen. The solution is not to use Word to enter your lp-model. Notepad should be ok. Better is to use the LPSolve IDE.

- lp_solve prints the output on screen. Can I have the output also in a file?
Yes, you can use standard redirection for that. Use the > before the filename to do that.
For example:
lp_solve input.lp >output.txt

- I have a constraint saying that x < 2, but lp_solve comes with a solution of 2, how comes?
< is the same as as <=
also > is the same as >=
This makes more than sense. Mathematically, 1.99999999999999999999999999999999999999999999999999 is smaller than 2, but what is the practical difference with 2? You always have to consider rounding errors also... If the variable is defined as integer then just say x <= 1

- When I solve my model, I get a stack overflow error/core dump/protection error. What is wrong?
If your model has integer/binary/semi-cont/SOS variables then version 5 can solve your problem. In version 4, the implemented branch-and-bound algorithm puts its branches on the stack and that can result in a stack overflow when it is a tough model. Version 5 doesn't put the branches on the stack anymore and because of that, this error is solved.

- Version 4 solves my models slower than version 3 did. What can I do?
Some models are indeed slower with version 4. Version 5 has several enhancements and is faster and more stable. Also version 4 always calculates the sensitivity information while older versions did not have this feature. This also takes some time. Version 5 only calculates the sensitivity when this information is specifically asked that makes it again faster.

- It takes a long time to build the model via the API interface. Especially add_constraint, add_constraintex, str_add_constraint seems to be slow. How can it be made faster?
Version 5 has a new API call set_add_rowmode that makes add_constraint, str_add_constraint spectacular faster.
If the model is build column by column, then it is strongly suggested to use add_columnex instead of add_column because add_columnex gives the possibility to only supply the non-zero elements and that speeds up building the model considerably, especially if the matrix is sparse (a lot of zero elements).
If the model is build row by row, then it is strongly suggested to use add_constraintex instead of add_constraint because add_constraintex gives the possibility to only supply the non-zero elements and that speeds up building the model considerably, especially if the matrix is sparse (a lot of zero elements).

- Can lp_solve give me the 'simplex tableau' of the model?
Version 5 has a new routine (print_tableau) to give you this information.

- Is there documentation about the API interface?
Yes, there are html (help) files. See the Files section in the google group.

- What is the maximum number of rows/columns that lp_solve can handle?
There is no fixed limit. Only available memory is a limit.

- I use a programming language that is not listed as supported or for which there are no examples. Can lp_solve be called from this language?
If this language allows calling functions from a C-dll, then it is possible. It is not because there is no example provided (yet) that it is not possible. The lp_solve community is always interested in your interface to call the lp_solve library. It doesn't have to be perfect.

- The Windows examples don't work. I get an error running them. Some dll cannot be found.
The examples call a dll that contains the lp_solve routines. This dll is called lpsolve*.dll and must be on the system either in the directory of the application or somewhere in the path.
This dll is contained in the windows binaries archive in the files section.

- Does lp_solve supports the mps free format?
This is possible from version 5.0.10.0. Before it was not possible. See read_freeMPS or the -fmps and -wfmps options to the lp_solve program. There is also a utility LPx2D that allows to convert this format. See the Files section.

- Does the lp_solve lp format support comments?
Yes it does. Put the comments between /* */
It can be anywhere in the text, even over multiple lines. Just like in C
lp_solve 4.0.1.11 and newer also supports the C++ line comment //

- I want to compile lp_solve myself, but I get link errors. Also what should I do with lp.y, lex.l, lp_rlp.y, lp_rlp.l?
The .y files are yacc files. They can be translated to C via the bison or yacc commands.
The .l files are lex files. They can be translated to C via the flex or lex commands.
lp.y/lex.l were used in version 4. Version 5 use the names lp_rlp.y/lp_rlp.l All unix environments have these commands. There are also windows versions available.
For example at http://unxutils.sourceforge.net/
Also only include lp.c in your compile project, not lex.c. lex.c is automatically #included by lp.c
Version 5 doesn't use the .c extension for the translated lex file. Instead it uses the .h extension. That way there is no confusion. So you don't have to (and may not) include it yourself again in the project.
To compile lp_solve, you must use make or gmake and a Makefile. There are several example makefiles in the source included like Makefile.linux, Makefile.msc. Enter make or gmake -f makefile. Note that for WINDOWS, you must use gnu make because MS make hasn't enough functionality. You can find gmake at http://unxutils.sourceforge.net/

- I compile lp_solve myself, but I get link errors saying that main (or _main) is already defined.
demo.c, mps2lp.c, lp2mps.c, lp_solve.c may never be in the same project. You must use one of these with the other C source files (except lex.c, see above) to make either demo.exe, mps2lp.exe, lp2mps.exe, lp_solve.exe

- I want to use the lpsolve dll, but when I compile my C/C++ program, I get link errors. He doesn't find any of the lpsolve API routines. What am I doing wrong?
Each function that you use in a C/C++ application must be defined. The compiler gives a warning if he doesn't find a definition of a function and the linker gives an error if he doesn't find an implementation for each used function. The implementation of a function can be in your source code, in another source file or in a library. If the function is in the same source code and defined before it is called, then you get no compiler warning because it is declared implicitly. If the function is after you call it, in another source file or in a library, then your source code must have a definition of this function or the compiler will give a warning. This is because the compiler wants to check if the function is correctly called (correct number of arguments, correct return code, should there be done some implicit conversion, ...). It is common to define these declarations in a header (.h) file. That is the reason why you include stdio.h, stdlib.h, string.h, windows.h and so on. For lpsolve, this library is lp_lib.h (lpkit.h in version 4 and before). Because lp_lib.h and lpkit.h also include other header files, you need these also. Including these source files do not guarantee that the linker will not give an error. This because the linker not only wants the definition of the functions, it also needs the implementation of it. So all routine calls that you do must be found somewhere by the linker. These can be in one of your source files and if they are not static defined then it is ok for the linker, or they are in a library. For example the function printf is a function from a library. This library can be linked statically or dynamically with your program. In Visual C, for the standard libraries this is defined via one of the compiler options /MT, /MD, /ML (in .NET via project, properties, C/C++, Code generation, Runtime Library. In VC6 via Project, settings, C/C++, category code generation, use runtime library). This results in using one of the libraries LIBC*.lib or MSVCRT*.lib. If you use static linking, then these routines are linked at link time with your program so that this program runs without the need of any other file. So these routines are then in LIBC.lib (the static libraries). If you use dynamic linking (MSVCRT.lib), then this library contains minimal code (not the implementation of this function) to call a library (a dll) at runtime. For example MSVCRT.DLL. So this dll must be on the system when you *run* the application. You will see that the resulting exe is smaller when dynamically linked compared to statically linked. This is logical because the implementation of the routine is in the DLL. The advantage of a DLL is that you can have a new implementation of it and use it in your application without having to rebuild your application. This because the DLL is linked at runtime with your program. Off course, the interface should stay the same for that. Also see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_c_run.2d.time_libraries.asp for an explanation on the VC runtime libraries.
Now besides the standard libraries there are also additional libraries. For example odbc32.lib is one that provides an API to access ODBC, or ws2_32.lib that contains the winsock/TCP/IP API calls and so on. These are all dynamic linked libraries, so the implementation is in a DLL. You must specify the library to the linker so that he knows how to call the implemented DLL (how it is called, ...).

Now if you want to use the lpsolve dll, you must also specify the lpsolve library to the linker so that you don't get the link errors. For version 5, this library is called lpsolve51.lib. You must specify it via Project, Properties, Linker, Input, Additional Dependencies (.NET) or Project, Settings, Link, Category General, Object Library Modules (VC6). There you add lpsolve51.lib (if there are already other libraries, just add at the end, separated via a space). You can specify the path where this file is located or you can specify via Project, Properies, Linker, General, Additional Library Directories (.NET) or Project, Settings, Link, Category Input, Additional library path, the paths where libraries can be found (separated by ,). Basically that is it. Also see Calling the lpsolve API from your application for more information.

- lp.c and lex.c that are generated on my system are different from the versions that can be found in the support folder in the files section. Are the latest versions of these files on your site?
Depending on the platform, the command used and the version of the command, these files are indeed different. That is not a problem. You can compare this with a compiler. The same source code generates totally different binaries, depending on the compiler used and its version, but the programs react the same (at least, they should ...).

- When I start the lp_solve program, nothing happens. I just get a blinking cursor. If I enter a command like lp1 = make_lp(0,4), I get a parse error. What is wrong here? How do I use the program?
lp_solve is a library with a set of routines with purpose to solve a MIP model. These routines are sometimes referred as the API (Application Programming Interface). These routines can be used in a C-program to solve MIP models. This is for example demonstrated in the demo program. Under Windows there is also a dll available that can be used by other programming languages to call the API functions. There are demos in VB and .NET available, but the principle is the same. The lp_solve program is basically another 'demo' program of this api. This program reads the MIP model from standard input or from a file and outputs the result back to the console or to a file. There are two possible input formats: the 'lp' format and the 'mps' format. This has nothing to do with the API. So lp1 = make_lp(0,4) is a totally wrong input for the lp_solve program. The lp-format is a 'readable' format of a MIP model.
For example:

max: -x1 + 2 x2;
C1: 2x1 + x2 <= 5;
-4 x1 + 4 x2 <= 5;

int x2,x1;

This lp-format is the default format of the lp_solve program.

The other format is mps format. This is a totally different format and used by many MIP solvers. This format is not very readable for us humans. The same example as above in mps format looks like this:

ROWS
 N  r_0
 L  C1
 L  r_2
COLUMNS
    MARK0000  'MARKER'                 'INTORG'
    x1        r_0                  1   C1                   2
    x1        r_2                 -4
    x2        r_0                 -2   C1                   1
    x2        r_2                  4
    MARK0001  'MARKER'                 'INTEND'
RHS
    RHS       C1                   5   r_2                  5
ENDATA

To enable this input format in the lp_solve program, use the -mps option.

The lp_solve program has many other options to control many other things like the amount of data to output, if scaling must be used and so on.

There are two other 'demo' programs: lp2mps and mps2lp. They convert model files from one format to the other.

The lp_solve, lp2mps and mps2lp programs all use API calls of the lp_solve library to perform their actions.

If lp_solve is started without an input file, then it gives a blinking cursor and waits for input. It is now possible to enter the model in the specified format (lp by default). But this is not very handy. You must enter the whole model each time you want to solve it and must be careful that you don't type any errors. To stop input mode, press Ctrl Z.
However it is much better to write your model in a disk file with your favourite editor (make sure it is in text format) and then provide this file to lp_solve. For example:

lp_solve input.lp

It is also possible to use input redirection:

lp_solve <input.lp

Or more sophisticated constructs like:

gen_model | lp_solve

gen_model is here a user written program that outputs the model to standard output and via the pipe character (|) this output is redirected to lp_solve. So no intermediate file is needed in this case.

- Is there no more user-friendly interface than the lp_solve command line program?
Yes there is, thanks to Henri Gourvest. For version 5 there is now the LPSolve IDE, a Windows interface to the lpsolve library. See LPSolve IDE for more information.

./fold.gif000666 000000 000000 00000000167 10031030130 010761 0ustar00000000 000000 GIF89a!,@ Formulation of an lp problem in lpsolve

Formulation of an lp problem in lpsolve

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.

Source

Now let's put in the other two constraint inequalities.

Source

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.

Source

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.625

That 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

Formulate an lp problem with lpsolve

There are several ways to model a linear problem via lpsolve:

Read the model from an ASCII file.

There exist a lot of formats to model an lp problem into. Almost each solver has its format on its own.

MPS file format

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:

lp_solve command line program

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

IDE

Under Windows, there is also a graphical IDE that can read an MPS file. See LPSolve IDE for more information.

lp file format

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:

lp_solve command line program

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

IDE

Under Windows, there is also a graphical IDE that can read an lp-file. See LPSolve IDE for more information.

CPLEX lp file format

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:

lp_solve command line program

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

IDE

Under Windows, there is also a graphical IDE that can read a CPLEX lp file via an XLI. See LPSolve IDE for more information.

LINDO lp file format

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:

lp_solve command line program

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

IDE

Under Windows, there is also a graphical IDE that can read a LINDO lp file via an XLI. See LPSolve IDE for more information.

GNU MathProg file format

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:

lp_solve command line program

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

IDE

Under Windows, there is also a graphical IDE that can read a GNU MathProg file via an XLI. See LPSolve IDE for more information.

LPFML XML file format

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:

lp_solve command line program

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

IDE

Under Windows, there is also a graphical IDE that can read a LPFML XML file via an XLI. See LPSolve IDE for more information.

Construct the model from a Mathematical Programming Language.

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:

Construct the model from a Programming Language.

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:

C/C++

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.

Java

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.

Delphi, Free Pascal

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.

VB, VBScript

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.

VB.NET

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.

C#.NET

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.

./free.htm000666 000000 000000 00000006642 10546445552 011042 0ustar00000000 000000 Free variables

free variables

Free variables are variables that have no lower or upper bound. By default, variables don't have an upper bound, but they do have a lower bound of zero. So they can only take positive values. Free variables can also become negative until -infinite.

lp_solve supports free variables since a long time. Internally, these variables are split in a positive and negative part. So the result of using free variables is that the number of columns increases. However this is transparent to the user. The API call set_unbounded can be used to define a variable as free.

In the mps format, free variables can be specified in the BOUNDS section. See mps-format.

Example:

NAME
ROWS
 N  R0
 L  R1
 G  R2
 G  R3
 G  R4
COLUMNS
    x1        R0        -1.000000000   R1        1.0000000000
    x1        R2        2.0000000000   R3        -1.000000000
    x2        R0        -2.000000000   R1        1.0000000000
    x2        R2        -1.000000000   R3        3.0000000000
    x3        R0        4.0000000000   R4        1.0000000000
    x4        R0        3.0000000000   R4        1.0000000000
RHS
    RHS       R1        5.0000000000   R4        0.5000000000
BOUNDS
 FR BND       x2
 UP BND       x3        10.000000000
 LO BND       x3        1.1000000000
 FR BND       x4
ENDATA
The red lines specify that variables x2 and x4 are free variables.

In the lp format, free variables can be specified in the free section. See lp-format.

Example:

max: x1 + 2x2 - 4x3 -3x4;
x1 + x2 <= 5;
2x1 - x2 >= 0;
-x1 + 3x2 >= 0;
x3 + x4 >= .5;
x3 >= 1.1;
x3 <= 10;

free x2, x4;

The red line specifies that variables x2 and x4 are free variables. The solution of this model is:
Value of objective function: 5.73333

Actual values of the variables:
x1                        1.66667
x2                        3.33333
x3                            1.1
x4                           -0.6

As can be seen, the value of x4 is -0.6, a negative value. If the variable would not be set as free, it would not be negative.

./FreeMat.htm000666 000000 000000 00000335777 13772705351 011462 0ustar00000000 000000 Using lpsolve from FreeMat

Using lpsolve from FreeMat

FreeMat?

FreeMat is a free environment for rapid engineering and scientific prototyping and data processing. It is similar to commercial systems such as MATLAB from Mathworks, and IDL from Research Systems, but is Open Source. FreeMat is available under the GPL license.

In addition to supporting many MATLAB functions and some IDL functionality, it features a codeless interface to external C, C++, and Fortran code, further parallel distributed algorithm development (via MPI), and has plotting and 3D visualization capabilities.

We will not discuss the specifics of FreeMat here but instead refer the reader to the FreeMat website, documentation, FreeMat Google Discussions and the FreeMat primer overthere.

FreeMat and lpsolve

lpsolve is callable from FreeMat via an external interface or Import. As such, it looks like lpsolve is fully integrated with FreeMat. Matrices can directly be transferred between FreeMat and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for FreeMat (especially for matrix support). So you have full control to the complete lpsolve functionality via the fmlpsolve FreeMat driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level script files that can make things a lot easier. See further in this article.

FreeMat is ideally suited to handle linear programming problems. These are problems in which you have a quantity, depending linearly on several variables, that you want to maximize or minimize subject to several constraints that are expressed as linear inequalities in the same variables.If the number of variables and the number of constraints are small, then there are numerous mathematical techniques for solving a linear programming problem. Indeed these techniques are often taught in high school or university level courses in finite mathematics.But sometimes these numbers are high, or even if low, the constants in the linear inequalities or the object expression for the quantity to be optimized may be numerically complicated in which case a software package like FreeMat is required to effect a solution.

Installation

To make this possible, a driver program is needed: fmlpsolve (fmlpsolve.dll under Windows, fmlpsolve.so under Unix/Linux). This driver must be put in a directory known to FreeMat and FreeMat can call the fmlpsolve solver.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux) (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). This has the advantage that the fmlpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the Windows/Unix/Linux path.

So note the difference between the FreeMat lpsolve driver that is called fmlpsolve and the lpsolve library that implements the API that is called lpsolve55.

There are also some FreeMat script files (.m) as a quick start.

To test if everything is installed correctly, enter fmlpsolve in the FreeMat command window. If it gives the following, then everything is ok:

fmlpsolve FreeMat Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: ret = fmlpsolve(functionname, arg1, arg2, ...)

If you get the following (Windows):

In base(base) on line 0
In docli(built in) on line 0
In Eval(fmlpsolve) on line 2
In Z:/lp_solve_5.5/extra/FreeMat/fmlpsolve(fmlpsolve) on line 195
Error: Unable to find file fmlpsolve.dll on the current path!

Or (Unix/Linux):

In base(base) on line 0
In docli(built in) on line 0
In Eval(fmlpsolve) on line 2
In fmlpsolve(fmlpsolve) on line 195
Error: Unable to find file fmlpsolve.so on the current path!

Then FreeMat can find the fmlpsolve.m file, but not the fmlpsolve.so/fmlpsolve.dll file. This library should be in the same directory as the .m file.

Error: Undefined function or variable fmlpsolve.

Then FreeMat cannot find the fmlpsolve.* files. Use the Path tool (Tools, Path tool) to add the path where the fmlpsolve.m script file is located and put the library fmlpsolve.dll/fmlpsolve.so in the appropriate directory. Under Windows, c:\windows\system32 is a common location and under Unix/Linux, /lib or /usr/lib is common.

If you get the following (Windows):

In base(base) on line 0
In docli(built in) on line 0
In Eval(fmlpsolve) on line 2
In Z:/lp_solve_5.5/extra/FreeMat/fmlpsolve(fmlpsolve) on line 195
Error: Unable to open module: Z:/lp_solve_5.5/extra/FreeMat/fmlpsolve.dll

Or (Unix/Linux):

In base(base) on line 0
In docli(built in) on line 0
In Eval(fmlpsolve) on line 2
In fmlpsolve(fmlpsolve) on line 195
Error: Unable to open module: /lp_solve/lp_solve_5.5/extra/FreeMat/fmlpsolve.so, operating system reported error: liblpsolve55.so: cannot open shared object file: No such file or directory

Then FreeMat can find the fmlpsolve driver program, but the driver program cannot find the lpsolve library that contains the lpsolve implementation. This library is called lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux.
Under Windows, the lpsolve55.dll file must be in a directory that in the PATH environment variable. This path can be shown via the following command at a command prompt: PATH
It is common to place this in the WINDOWS\system32 folder.

Under Unix/Linux, the liblpsolve55.so shared library must be either in the directories /lib or /usr/lib or in a directory specified by the LD_LIBRARY_PATH environment variable.

Note that it may also be necessary to restart FreeMat after having put the files in the specified directory.

Also note that there is an fmlpsolve.dll/fmlpsolve.so library and an fmlpsolve.m script file. Both are needed. In theory it is possible to call the library directly from FreeMat without the script, but this is strongly unadvised and not supported.

All this is developed and tested with FreeMat version 3.6.

Solve an lp model from FreeMat via fmlpsolve

In the following text, --> before the FreeMat commands is the FreeMat prompt. Only the text after --> must be entered.

To call an lpsolve function, the following syntax must be used:

--> [ret1, ret2, ...] = fmlpsolve('functionname', arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between single quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra FreeMat specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in FreeMat, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the FreeMat functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from FreeMat, nothing must be dimensioned in advance. The fmlpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to fmlpsolve. Never as argument to the routine. This can be a single value as for get_objective (although FreeMat stores this in a 1x1 matrix) or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

Note that you can get an overview of the available functionnames and their arguments by entering the following in FreeMat:

--> help fmlpsolve

An example

(Note that you can execute this example by entering command per command as shown below or by just entering example1. This will execute example1.m. You can see its contents by entering type example1.m)

--> lp=fmlpsolve('make_lp', 0, 4);
--> fmlpsolve('set_verbose', lp, 3);
--> fmlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
--> fmlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
--> fmlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
--> fmlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
--> fmlpsolve('set_lowbo', lp, 1, 28.6);
--> fmlpsolve('set_lowbo', lp, 4, 18);
--> fmlpsolve('set_upbo', lp, 4, 48.98);
--> fmlpsolve('set_col_name', lp, 1, 'COLONE');
--> fmlpsolve('set_col_name', lp, 2, 'COLTWO');
--> fmlpsolve('set_col_name', lp, 3, 'COLTHREE');
--> fmlpsolve('set_col_name', lp, 4, 'COLFOUR');
--> fmlpsolve('set_row_name', lp, 1, 'THISROW');
--> fmlpsolve('set_row_name', lp, 2, 'THATROW');
--> fmlpsolve('set_row_name', lp, 3, 'LASTROW');
--> fmlpsolve('write_lp', lp, 'a.lp');
--> fmlpsolve('get_mat', lp, 1, 2)

ans =

   78.2600

--> fmlpsolve('solve', lp)

ans =

 0

--> fmlpsolve('get_objective', lp)

ans =

   31.7828

--> fmlpsolve('get_variables', lp)

ans =

   28.6000
         0
         0
   31.8276

--> fmlpsolve('get_constraints', lp)

ans =

   1.0e+02 *

    0.9230
    0.0686
    3.9129

Note that there are some commands that return an answer. To see the answer, the command was not terminated with a semicolon (;). If the semicolon is put at the end of a command, the answer is not shown. However it is also possible to write the answer in a variable. For example:

--> obj=fmlpsolve('get_objective', lp)

obj =

   31.7828

Or without echoing on screen:

--> obj=fmlpsolve('get_objective', lp);

The last command will only write the result in variable obj without showing anything on screen. get_variables and get_constraints return a vector with the result. This can also be put in a variable:

--> x=fmlpsolve('get_variables', lp);
--> b=fmlpsolve('get_constraints', lp);

It is always possible to show the contents of a variable by just giving it as command:

--> x

x =
  28.6000
        0
        0
  31.8276

Don't forget to free the handle and its associated memory when you are done:

--> fmlpsolve('delete_lp', lp);

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
--> lp=fmlpsolve('make_lp', 0, 4);
--> fmlpsolve('set_lp_name', lp, 'mymodel');
--> fmlpsolve('set_verbose', 'mymodel', 3);
--> fmlpsolve('set_obj_fn', 'mymodel', [1, 3, 6.24, 0.1]);
--> fmlpsolve('add_constraint', 'mymodel', [0, 78.26, 0, 2.9], 2, 92.3);
--> fmlpsolve('add_constraint', 'mymodel', [0.24, 0, 11.31, 0], 1, 14.8);
--> fmlpsolve('add_constraint', 'mymodel', [12.68, 0, 0.08, 0.9], 2, 4);
--> fmlpsolve('set_lowbo', 'mymodel', 1, 28.6);
--> fmlpsolve('set_lowbo', 'mymodel', 4, 18);
--> fmlpsolve('set_upbo', 'mymodel', 4, 48.98);
--> fmlpsolve('set_col_name', 'mymodel', 1, 'COLONE');
--> fmlpsolve('set_col_name', 'mymodel', 2, 'COLTWO');
--> fmlpsolve('set_col_name', 'mymodel', 3, 'COLTHREE');
--> fmlpsolve('set_col_name', 'mymodel', 4, 'COLFOUR');
--> fmlpsolve('set_row_name', 'mymodel', 1, 'THISROW');
--> fmlpsolve('set_row_name', 'mymodel', 2, 'THATROW');
--> fmlpsolve('set_row_name', 'mymodel', 3, 'LASTROW');
--> fmlpsolve('write_lp', 'mymodel', 'a.lp');
--> fmlpsolve('get_mat', 'mymodel', 1, 2)

ans =

   78.2600

--> fmlpsolve('solve', 'mymodel')

ans =

 0

--> fmlpsolve('get_objective', 'mymodel')

ans =

   31.7828

--> fmlpsolve('get_variables', 'mymodel')

ans =

   28.6000
         0
         0
   31.8276

--> fmlpsolve('get_constraints', 'mymodel')

ans =

   1.0e+02 *

    0.9230
    0.0686
    3.9129

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific FreeMat routine to get the handle from the model name: get_handle.
For example:

--> fmlpsolve('get_handle', 'mymodel')

ans =

 0

Don't forget to free the handle and its associated memory when you are done:

--> fmlpsolve('delete_lp', 'mymodel');

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

In FreeMat, all numerical data is stored in matrices; even a scalar variable. FreeMat also supports complex numbers (a + b * i with i=SQRT(-1)). fmlpsolve can only work with real numbers. FreeMat also supports sparse matrices. Sparse matrices are matrices where only the non-zero elements are provided and stored. This results in both less storage and faster calculation if there are a sufficient number of zero values in the matrix and there usually are. The fmlpsolve driver supports both dense and sparse matrices and their use is totally transparent to the user. Everywhere a matrix can be provided, it can be dense or sparse. In the above example all matrices were dense. For example:
--> fmlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);

In sparse matrix notation, this can be written:

--> fmlpsolve('add_constraint', lp, sparse([0.24, 0, 11.31, 0]), 1, 14.8);

Most of the time, variables are used to provide the data:

--> fmlpsolve('add_constraint', lp, a1, 1, 14.8);

Where a1 is a matrix variable that can be dense or sparse.

The fmlpsolve driver sees all provided matrices as sparse matrices. fmlpsolve also uses sparse matrices internally and data can be provided sparse via the ex routines. For example add_constraintex. The fmlpsolve driver always uses the ex routines to provide the data to lpsolve. Even if you call from FreeMat the routine names that would require a dense matrix (for example add_constraint), the fmlpsolve driver will always call the sparse version of the routine (for example add_constraintex). This results in the most performing behaviour. Note that if a dense matrix is provided, the dimension must exactly match the dimension that is expected by fmlpsolve. Matrices with too few or too much elements gives an 'invalid vector.' error. Sparse matrices can off course provide less elements (the non provided elements are seen as zero). However if too many elements are provided or an element with a too large index, again an 'invalid vector.' error is raised.

Most of the time, fmlpsolve needs vectors (rows or columns). In all situations, it doesn't matter if the vectors are row or column vectors. The driver accepts them both. For example:

--> fmlpsolve('add_constraint', lp, [0.24; 0; 11.31; 0], 1, 14.8);

Which is a column vector, but it is also accepted.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the FreeMat interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the FreeMat matrix.

Maximum usage of matrices/sets with fmlpsolve

Because FreeMat is all about matrices, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the fmlpsolve FreeMat driver to also work with matrices. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The fmlpsolve FreeMat driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = fmlpsolve('set_int', lp, column, must_be_int). The matrix version of this call is: return = fmlpsolve('set_int', lp, [must_be_int]). The API call to return the integer status of a variable is: return = fmlpsolve('is_int', lp, column). The matrix version of this call is: [is_int] = fmlpsolve('is_int', lp)
Also note the get_mat and set_mat routines. In FreeMat these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by just entering example2. This will execute example2.m. You can see its contents by entering type example2.m)

--> lp=fmlpsolve('make_lp', 0, 4);
--> fmlpsolve('set_verbose', lp, 3);
--> fmlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
--> fmlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
--> fmlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
--> fmlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
--> fmlpsolve('set_lowbo', lp, [28.6, 0, 0, 18]);
--> fmlpsolve('set_upbo', lp, [1.0e30, 1.0e30, 1.0e30, 48.98]);
--> fmlpsolve('set_col_name', lp, 1, 'COLONE');
--> fmlpsolve('set_col_name', lp, 2, 'COLTWO');
--> fmlpsolve('set_col_name', lp, 3, 'COLTHREE');
--> fmlpsolve('set_col_name', lp, 4, 'COLFOUR');
--> fmlpsolve('set_row_name', lp, 1, 'THISROW');
--> fmlpsolve('set_row_name', lp, 2, 'THATROW');
--> fmlpsolve('set_row_name', lp, 3, 'LASTROW');
--> fmlpsolve('write_lp', lp, 'a.lp');
--> fmlpsolve('get_mat', lp)

ans =

         0   78.2600         0    2.9000
    0.2400         0   11.3100         0
   12.6800         0    0.0800    0.9000

--> fmlpsolve('solve', lp)

ans =

 0

--> fmlpsolve('get_objective', lp)

ans =

   31.7828

--> fmlpsolve('get_variables', lp)

ans =

   28.6000
         0
         0
   31.8276

--> fmlpsolve('get_constraints', lp)

ans =

   1.0e+02 *

    0.9230
    0.0686
    3.9129

Note the usage of 1.0e30 in set_upbo. This stands for 'infinity'. Meaning an infinite upper bound. It is also possible to use -1.0e30 to express minus infinity. This can for example be used to create a free variable.

Starting from driver version 5.5.0.3, get_mat can also return the matrix in sparse format. By default the function returns it in dense format for backwards compatibility. However if a 3rd argument is provided that is non-zero, the returned matrix is sparse:

--> fmlpsolve('get_mat', lp, 1)

ans =
 Matrix is sparse with 7 nonzeros

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example:

--> A=fmlpsolve('get_mat', lp);
--> X=fmlpsolve('get_variables', lp);
--> B = A * X

B =

   1.0e+02 *

    0.9230
    0.0686
    3.9129

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

--> fmlpsolve('get_constraints', lp)

ans =

   1.0e+02 *

    0.9230
    0.0686
    3.9129

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

--> C=fmlpsolve('get_obj_fn', lp);
--> X=fmlpsolve('get_variables', lp);
--> obj = C * X

obj =

   31.7828

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

--> fmlpsolve('get_objective', lp)

ans =

   31.7828

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
--> lp=fmlpsolve('make_lp', 0, 4);
--> fmlpsolve('set_verbose', lp, 3);
--> fmlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
--> fmlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
--> fmlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One could define all the possible constants in FreeMat and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

--> lp=fmlpsolve('make_lp', 0, 4);
--> fmlpsolve('set_verbose', lp, 'IMPORTANT');
--> fmlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 'GE', 92.3);
--> fmlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 'LE', 14.8);
--> fmlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 'GE', 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

--> fmlpsolve('set_verbose', lp, 'blabla');
BLABLA: Unknown.

--> fmlpsolve('set_verbose', lp, 'GE');
GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. 'LE', 'GE' and 'EQ' in add_constraint and is_constr_type can also be '<', '<=', '>', '>=', '='. When returned however, 'GE', 'LE', 'EQ' will be used.

Some constants can be a combination of multiple constants. For example set_scaling:

--> fmlpsolve('set_scaling', lp, 3+128);

With the string version of constants this can be done as following:

--> fmlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_INTEGERS');

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

--> fmlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_RANGE');
SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

--> fmlpsolve('get_scaling', lp)

ans =

 131

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

--> fmlpsolve('return_constants', 1);

From now on, all returned constants are returned as string:

--> fmlpsolve('get_scaling', lp)

ans =

 SCALE_MEAN|SCALE_INTEGERS

This for all routines until return_constants is again called with 0:

--> fmlpsolve('return_constants', 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

--> fmlpsolve('return_constants', 1)

ans =

 1

To get the value without setting it, don't provide the second argument:

--> fmlpsolve('return_constants')

ans =

 1

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

Script files

FreeMat can execute a sequence of statements stored in diskfiles. Such files are called "Script files". They must have the file type of ".m" as the last part of their filename (extension). Much of your work with FreeMat will be in creating and refining script files. Script files are usually created using your local editor.

Script files can be compared with batch files or scripts. You can put FreeMat commands in them and execute them at any time. The Script file is executed like any other command, by entering its name (without the .m extension).

The fmlpsolve FreeMat distribution contains some example Script files to demonstrate this.

You can edit these files with your favourite text editor (or notepad).

example1.m

Contains the commands as shown in the first example of this article.

example2.m

Contains the commands as shown in the second example of this article.

example3.m

Contains the commands of a practical example. See further in this article.

example4.m

Contains the commands of a practical example. See further in this article.

example5.m

Contains the commands of a practical example. See further in this article.

example6.m

Contains the commands of a practical example. See further in this article.

lp_solve.m

This script uses the API to create a higher-level function called lp_solve. This function accepts as arguments some matrices and options to create and solve an lp model. See the beginning of the file or type help lp_solve or just lp_solve to see its usage:

 --> help lp_solve
 LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

--> [obj, x]=lp_solve([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])
obj =

 3

x =

 1
 2

lp_maker.m

This script is analog to the lp_solve script and also uses the API to create a higher-level function called lp_maker. This function accepts as arguments some matrices and options to create an lp model. Note that this scripts only creates a model and returns a handle. See the beginning of the file or type help lp_maker or just lp_maker to see its usage:

 --> help lp_maker

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

--> lp=lp_maker([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])

lp =

 0

To solve the model and get the solution:

--> fmlpsolve('solve', lp)

ans =

 0

--> fmlpsolve('get_objective', lp)

ans =

 3

--> fmlpsolve('get_variables', lp)

ans =

 1
 2

Don't forget to free the handle and its associated memory when you are done:

--> fmlpsolve('delete_lp', lp);

lpdemo.m

Contains several examples to build and solve lp models.

ex.m

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

Source

Now let's put in the other two constraint inequalities.

Source

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.

Source

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 lp_solve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:

--> x = [1 1; 110 30] \ [75; 4000]

x =

   21.8750
   53.1250

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 60] * x

P =

 6.3156e+03

That is, $6315.63.

Note that these command are in script example3.m

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

--> help lp_maker

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

--> f = [143 60];
--> A = [120 210; 110 30; 1 1];
--> b = [15000; 4000; 75];
--> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
--> solvestat = fmlpsolve('solve', lp)

solvestat =

 0

--> obj = fmlpsolve('get_objective', lp)

obj =

 6.3156e+03

--> x = fmlpsolve('get_variables', lp)

x =

   21.8750
   53.1250

--> fmlpsolve('delete_lp', lp);

Note that these command are in script example4.m

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimentions, but beyound that it is all very theorethical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

--> f = [143 60 195];
--> A = [120 210 150.75; 110 30 125; 1 1 1];
--> b = [15000; 4000; 75];
--> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
--> solvestat = fmlpsolve('solve', lp)

solvestat =

 0

--> obj = fmlpsolve('get_objective', lp)

obj =

 6.9868e+03

--> x = fmlpsolve('get_variables', lp)

x =

         0
   56.5789
   18.4211

--> fmlpsolve('delete_lp', lp);

Note that these command are in script example5.m

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that FreeMat can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like FreeMat is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
--> f = [110*1.3 30*2.0 125*1.56 75*1.8 95*.95 100*2.25 50*1.35];
--> A = [120 210 150.75 115 186 140 85;
        110 30 125 75 95 100 50;
        1 1 1 1 1 1 1;
        1 -1 0 0 0 0 0;
        0 0 1 0 -2 0 0;
        0 0 0 -1 0 -1 1];

--> b = [55000;40000;400;0;0;0];
--> lp = lp_maker(f, A, b, [-1; -1; -1; -1; -1; -1], [10 10 10 10 20 20 20], [100 1.0e30 50 1.0e30 1.0e30 250 1.0e30], [], 1, 0);
--> solvestat = fmlpsolve('solve', lp)

solvestat =

 0

--> obj = fmlpsolve('get_objective', lp)

obj =

 7.5398e+04

--> x = fmlpsolve('get_variables', lp)

x =

   1.0e+02 *

    0.1000
    0.1000
    0.4000
    0.4565
    0.2000
    2.5000
    0.2000

--> fmlpsolve('delete_lp', lp);

Note that these command are in script example6.m

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that 1.0e30 is used for variables that have no upper limit. This stands for Infinity.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using FreeMat:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into FreeMat format we get:

f = [4 2 1]
A = [2 1 0; 1 0 2; 1 1 1]
b = [1; 2; 1]

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0 0 0]
u = [ 1 1 2]

Now lets enter this in FreeMat:

--> f = [4 2 1];
--> A = [2 1 0; 1 0 2; 1 1 1];
--> b = [1; 2; 1];
--> l = [ 0 0 0];
--> u = [ 1 1 2];

Now solve the linear program using FreeMat: Type the commands

--> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
--> solvestat = fmlpsolve('solve', lp)

solvestat =

 0

--> obj = fmlpsolve('get_objective', lp)

obj =

    2.5000

--> x = fmlpsolve('get_variables', lp)

x =

    0.5000
         0
    0.5000

--> fmlpsolve('delete_lp', lp);

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the FreeMat command:

--> l = [];

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -1.0e30 as lower bounds:

--> l = [-1.0e30 -1.0e30 -1.0e30];

Solve this and you get a different result:

--> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
--> solvestat = fmlpsolve('solve', lp)

solvestat =

 0

--> obj = fmlpsolve('get_objective', lp)

obj =

    2.6667

--> x = fmlpsolve('get_variables', lp)

x =

    0.6667
   -0.3333
    0.6667

--> fmlpsolve('delete_lp', lp);

Overview of API routines

Note again that the FreeMat command 'help fmlpsolve' gives an overview of all functions that can be called via fmlpsolve with their arguments and return values.

Note that everwhere where lp is used as argument that this can be a handle (lp_handle) or the models name.

  • add_column, add_columnex
    • return = fmlpsolve('add_column', lp, [column])
    • return = fmlpsolve('add_columnex', lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = fmlpsolve('add_constraint', lp, [row], constr_type, rh)
    • return = fmlpsolve('add_constraintex', lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = fmlpsolve('add_SOS', lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in FreeMat since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = fmlpsolve('column_in_lp', lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = fmlpsolve('copy_lp', lp)
    • No special considerations.
  • default_basis
    • fmlpsolve('default_basis', lp)
    • No special considerations.
  • del_column
    • return = fmlpsolve('del_column', lp, column)
    • No special considerations.
  • del_constraint
    • return = fmlpsolve('del_constraint', lp, del_row)
    • No special considerations.
  • delete_lp
    • fmlpsolve('delete_lp', lp)
    • No special considerations.
  • free_lp
    • fmlpsolve('free_lp', lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = fmlpsolve('get_anti_degen', lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = fmlpsolve('get_basis', lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in FreeMat. If not provided, then 0 is used.
  • get_basiscrash
    • return = fmlpsolve('get_basiscrash', lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = fmlpsolve('get_bb_depthlimit', lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = fmlpsolve('get_bb_floorfirst', lp)
    • No special considerations.
  • get_bb_rule
    • return = fmlpsolve('get_bb_rule', lp)
    • No special considerations.
  • get_bounds_tighter
    • return = fmlpsolve('get_bounds_tighter', lp)
    • No special considerations.
  • get_break_at_value
    • return = fmlpsolve('get_break_at_value', lp)
    • No special considerations.
  • get_col_name
    • name = fmlpsolve('get_col_name', lp, column)
    • column must be provided and is as such not optional. As such no array of names can be returned. This because FreeMat has no possibility to return sets via the import interface.
  • get_column get_columnex
    • [column, return] = fmlpsolve('get_column', lp, col_nr)
    • [column, return] = fmlpsolve('get_columnex', lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = fmlpsolve('get_constr_type', lp, row)
    • [constr_type] = fmlpsolve('get_constr_type', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • get_constr_value
    • return = fmlpsolve('get_constr_value', lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = fmlpsolve('get_constraints', lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = fmlpsolve('get_dual_solution', lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = fmlpsolve('get_epsb', lp)
    • No special considerations.
  • get_epsd
    • return = fmlpsolve('get_epsd', lp)
    • No special considerations.
  • get_epsel
    • return = fmlpsolve('get_epsel', lp)
    • No special considerations.
  • get_epsint
    • return = fmlpsolve('get_epsint', lp)
    • No special considerations.
  • get_epsperturb
    • return = fmlpsolve('get_epsperturb', lp)
    • No special considerations.
  • get_epspivot
    • return = fmlpsolve('get_epspivot', lp)
    • No special considerations.
  • get_improve
    • return = fmlpsolve('get_improve', lp)
    • No special considerations.
  • get_infinite
    • return = fmlpsolve('get_infinite', lp)
    • No special considerations.
  • get_lowbo
    • return = fmlpsolve('get_lowbo', lp, column)
    • [return] = fmlpsolve('get_lowbo', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • get_lp_index
    • return = fmlpsolve('get_lp_index', lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = fmlpsolve('get_lp_name', lp)
    • No special considerations.
  • get_mat
    • value = fmlpsolve('get_mat', lp, row, col)
    • [matrix, return] = fmlpsolve('get_mat', lp[, sparse])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix in the first return value. If sparse is different from zero then the returned matrix is a sparse matrix. The return code of the call is the second return value.
  • get_max_level
    • return = fmlpsolve('get_max_level', lp)
    • No special considerations.
  • get_maxpivot
    • return = fmlpsolve('get_maxpivot', lp)
    • No special considerations.
  • get_mip_gap
    • return = fmlpsolve('get_mip_gap', lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = fmlpsolve('get_nameindex', lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = fmlpsolve('get_Ncolumns', lp)
    • No special considerations.
  • get_negrange
    • return = fmlpsolve('get_negrange', lp)
    • No special considerations.
  • get_nonzeros
    • return = fmlpsolve('get_nonzeros', lp)
    • No special considerations.
  • get_Norig_columns
    • return = fmlpsolve('get_Norig_columns', lp)
    • No special considerations.
  • get_Norig_rows
    • return = fmlpsolve('get_Norig_rows', lp)
    • No special considerations.
  • get_Nrows
    • return = fmlpsolve('get_Nrows', lp)
    • No special considerations.
  • get_obj_bound
    • return = fmlpsolve('get_obj_bound', lp)
    • No special considerations.
  • get_objective
    • return = fmlpsolve('get_objective', lp)
    • No special considerations.
  • get_orig_index
    • return = fmlpsolve('get_orig_index', lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = fmlpsolve('get_origcol_name', lp, column)
    • column must be provided and is as such not optional. As such no array of names can be returned. This because FreeMat has no possibility to return sets via the import interface.
  • get_origrow_name
    • name = fmlpsolve('get_origrow_name', lp, row)
    • row must be provided and is as such not optional. As such no array of names can be returned. This because FreeMat has no possibility to return sets via the import interface.
  • get_pivoting
    • return = fmlpsolve('get_pivoting', lp)
    • No special considerations.
  • get_presolve
    • return = fmlpsolve('get_presolve', lp)
    • No special considerations.
  • get_presolveloops
    • return = fmlpsolve('get_presolveloops', lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = fmlpsolve('get_primal_solution', lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = fmlpsolve('get_print_sol', lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = fmlpsolve('get_rh', lp, row)
    • [rh] = fmlpsolve('get_rh', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • get_rh_range
    • return = fmlpsolve('get_rh_range', lp, row)
    • [rh_ranges] = fmlpsolve('get_rh_range', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • get_row get_rowex
    • [row, return] = fmlpsolve('get_row', lp, row_nr)
    • [row, return] = fmlpsolve('get_rowex', lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = fmlpsolve('get_row_name', lp, row)
    • row must be provided and is as such not optional. As such no array of names can be returned. This because FreeMat has no possibility to return sets via the import interface.
  • get_scalelimit
    • return = fmlpsolve('get_scalelimit', lp)
    • No special considerations.
  • get_scaling
    • return = fmlpsolve('get_scaling', lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = fmlpsolve('get_sensitivity_obj', lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = fmlpsolve('get_sensitivity_objex', lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that FreeMat allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = fmlpsolve('get_sensitivity_obj', lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, FreeMat always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = fmlpsolve('get_sensitivity_rhs', lp)
    • [duals, dualsfrom, dualstill, return] = fmlpsolve('get_sensitivity_rhsex', lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that FreeMat allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = fmlpsolve('get_sensitivity_rhs', lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = fmlpsolve('get_simplextype', lp)
    • No special considerations.
  • get_solutioncount
    • return = fmlpsolve('get_solutioncount', lp)
    • No special considerations.
  • get_solutionlimit
    • return = fmlpsolve('get_solutionlimit', lp)
    • No special considerations.
  • get_status
    • return = fmlpsolve('get_status', lp)
    • No special considerations.
  • get_statustext
    • return = fmlpsolve('get_statustext', lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = fmlpsolve('get_timeout', lp)
    • No special considerations.
  • get_total_iter
    • return = fmlpsolve('get_total_iter', lp)
    • No special considerations.
  • get_total_nodes
    • return = fmlpsolve('get_total_nodes', lp)
    • No special considerations.
  • get_upbo
    • return = fmlpsolve('get_upbo', lp, column)
    • [upbo] = fmlpsolve('get_upbo', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • get_var_branch
    • return = fmlpsolve('get_var_branch', lp, column)
    • [var_branch] = fmlpsolve('get_var_branch', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • get_var_dualresult
    • return = fmlpsolve('get_var_dualresult', lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = fmlpsolve('get_var_primalresult', lp, index)
    • No special considerations.
  • get_var_priority
    • return = fmlpsolve('get_var_priority', lp, column)
    • [var_priority] = fmlpsolve('get_var_priority', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • get_variables
    • [var, return] = fmlpsolve('get_variables', lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = fmlpsolve('get_verbose', lp)
    • No special considerations.
  • get_working_objective
    • return = fmlpsolve('get_working_objective', lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = fmlpsolve('guess_basis', lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
  • has_BFP
    • return = fmlpsolve('has_BFP', lp)
    • No special considerations.
  • has_XLI
    • return = fmlpsolve('has_XLI', lp)
    • No special considerations.
  • is_add_rowmode
    • return = fmlpsolve('is_add_rowmode', lp)
    • No special considerations.
  • is_anti_degen
    • return = fmlpsolve('is_anti_degen', lp, testmask)
    • No special considerations.
  • is_binary
    • return = fmlpsolve('is_binary', lp, column)
    • [binary] = fmlpsolve('is_binary', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • is_break_at_first
    • return = fmlpsolve('is_break_at_first', lp)
    • No special considerations.
  • is_constr_type
    • return = fmlpsolve('is_constr_type', lp, row, mask)
    • No special considerations.
  • is_debug
    • return = fmlpsolve('is_debug', lp)
    • No special considerations.
  • is_feasible
    • return = fmlpsolve('is_feasible', lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = fmlpsolve('is_free', lp, column)
    • return = fmlpsolve('is_unbounded', lp, column)
    • [free] = fmlpsolve('is_free', lp)
    • [free] = fmlpsolve('is_unbounded', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • is_infinite
    • return = fmlpsolve('is_infinite', lp, value)
    • No special considerations.
  • is_int
    • return = fmlpsolve('is_int', lp, column)
    • [int] = fmlpsolve('is_int', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • is_integerscaling
    • return = fmlpsolve('is_integerscaling', lp)
    • No special considerations.
  • is_maxim
    • return = fmlpsolve('is_maxim', lp)
    • No special considerations.
  • is_nativeBFP
    • return = fmlpsolve('is_nativeBFP', lp)
    • No special considerations.
  • is_nativeXLI
    • return = fmlpsolve('is_nativeXLI', lp)
    • No special considerations.
  • is_negative
    • return = fmlpsolve('is_negative', lp, column)
    • [negative] = fmlpsolve('is_negative', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • is_piv_mode
    • return = fmlpsolve('is_piv_mode', lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = fmlpsolve('is_piv_rule', lp, rule)
    • No special considerations.
  • is_presolve
    • return = fmlpsolve('is_presolve', lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = fmlpsolve('is_scalemode', lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = fmlpsolve('is_scaletype', lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = fmlpsolve('is_semicont', lp, column)
    • [semicont] = fmlpsolve('is_semicont', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • is_SOS_var
    • return = fmlpsolve('is_SOS_var', lp, column)
    • [SOS_var] = fmlpsolve('is_SOS_var', lp)
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a FreeMat matrix.
  • is_trace
    • return = fmlpsolve('is_trace', lp)
    • No special considerations.
  • is_use_names
    • return = fmlpsolve('is_use_names', lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = fmlpsolve('lp_solve_version')
    • The fmlpsolve API routine returns the version information in 4 provided argument variables while the FreeMat version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = fmlpsolve('make_lp', rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • fmlpsolve('print_constraints', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
    • The same information can also be obtained via fmlpsolve('get_constraints', lp). This shows the result on screen.
  • print_debugdump
    • return = fmlpsolve('print_debugdump', lp, filename)
    • No special considerations.
  • print_duals
    • fmlpsolve('print_duals', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
    • The same information can be obtained via fmlpsolve('get_dual_solution', lp). This shows the result on screen.
  • print_lp
    • fmlpsolve('print_lp', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
  • print_objective
    • fmlpsolve('print_objective', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
    • The same information can be obtained via fmlpsolve('get_objective', lp). This shows the result on screen.
  • print_scales
    • fmlpsolve('print_scales', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
  • print_solution
    • fmlpsolve('print_solution', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
    • The same information can also be obtained via fmlpsolve('get_variables', lp). This shows the result on screen.
  • print_str
    • fmlpsolve('print_str', lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
  • print_tableau
    • fmlpsolve('print_tableau', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under FreeMat (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the fmlpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows FreeMat) to the command window of FreeMat. As such, all reported output can be seen in FreeMat. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = fmlpsolve('read_basis', lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = fmlpsolve('read_freemps', filename {, options})
    • lp_handle = fmlpsolve('read_freeMPS', filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In FreeMat it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = fmlpsolve('read_lp', filename {, verbose {, lp_name}})
    • lp_handle = fmlpsolve('read_LP', filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In FreeMat it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ('').
  • read_mps, read_MPS
    • lp_handle = fmlpsolve('read_mps', filename {, options})
    • lp_handle = fmlpsolve('read_MPS', filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In FreeMat it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = fmlpsolve('read_params', lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = fmlpsolve('read_XLI', xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, '' (NULL) is taken. '' is taken as NULL.
    • options is optional. When not provided, '' is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • fmlpsolve('set_basisvar', lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = fmlpsolve('set_add_rowmode', lp, turnon)
    • No special considerations.
  • set_anti_degen
    • fmlpsolve('set_anti_degen', lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = fmlpsolve('set_basis', lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
  • set_basiscrash
    • fmlpsolve('set_basiscrash', lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • fmlpsolve('set_bb_depthlimit', lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • fmlpsolve('set_bb_floorfirst', lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • fmlpsolve('set_bb_rule', lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = fmlpsolve('set_BFP', lp, filename)
    • No special considerations.
  • set_binary
    • return = fmlpsolve('set_binary', lp, column, must_be_bin)
    • return = fmlpsolve('set_binary', lp, [must_be_bin])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = fmlpsolve('set_bounds', lp, column, lower, upper)
    • return = fmlpsolve('set_bounds', lp, [lower], [upper])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • fmlpsolve('set_bounds_tighter', lp, tighten)
    • No special considerations.
  • set_break_at_first
    • fmlpsolve('set_break_at_first', lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • fmlpsolve('set_break_at_value', lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = fmlpsolve('set_col_name', lp, column, name)
    • column must be provided and is as such not optional. As such no array of names can be provided. This because FreeMat has no possibility to provide sets via the import interface.
  • set_column, set_columnex
    • return = fmlpsolve('set_column', lp, col_no, [column])
    • return = fmlpsolve('set_columnex', lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = fmlpsolve('set_constr_type', lp, row, con_type)
    • return = fmlpsolve('set_constr_type', lp, [con_type])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • fmlpsolve('set_debug', lp, debug)
    • No special considerations.
  • set_epsb
    • fmlpsolve('set_epsb', lp, epsb)
    • No special considerations.
  • set_epsd
    • fmlpsolve('set_epsd', lp, epsd)
    • No special considerations.
  • set_epsel
    • fmlpsolve('set_epsel', lp, epsel)
    • No special considerations.
  • set_epsint
    • fmlpsolve('set_epsint', lp, epsint)
    • No special considerations.
  • set_epslevel
    • fmlpsolve('set_epslevel', lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • fmlpsolve('set_epsperturb', lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • fmlpsolve('set_epspivot', lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = fmlpsolve('set_free', lp, column)
    • return = fmlpsolve('set_unbounded', lp, column)
    • No special considerations.
  • set_improve
    • fmlpsolve('set_improve', lp, improve)
    • No special considerations.
  • set_infinite
    • fmlpsolve('set_infinite', lp, infinite)
    • No special considerations.
  • set_int
    • return = fmlpsolve('set_int', lp, column, must_be_int)
    • return = fmlpsolve('set_int', lp, [must_be_int])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = fmlpsolve('set_lowbo', lp, column, value)
    • return = fmlpsolve('set_lowbo', lp, [values])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = fmlpsolve('set_lp_name', lp, name)
    • In FreeMat, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = fmlpsolve('set_mat', lp, row, column, value)
    • return = fmlpsolve('set_mat', lp, [matrix])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. Consider using a FreeMat sparse matrix for maximum performance and least memory usage. The matrix must be two-dimentional.
  • set_maxim
    • fmlpsolve('set_maxim', lp)
    • No special considerations.
  • set_maxpivot
    • fmlpsolve('set_maxpivot', max_num_inv)
    • No special considerations.
  • set_minim
    • fmlpsolve('set_minim', lp)
    • No special considerations.
  • set_mip_gap
    • fmlpsolve('set_mip_gap', lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • fmlpsolve('set_negrange', negrange)
    • No special considerations.
  • set_obj
    • return = fmlpsolve('set_obj', lp, column, value)
    • return = fmlpsolve('set_obj', lp, [values])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • fmlpsolve('set_obj_bound', lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = fmlpsolve('set_obj_fn', lp, [row])
    • return = fmlpsolve('set_obj_fnex', lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
  • set_outputfile
    • return = fmlpsolve('set_outputfile', lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In FreeMat under Windows, output to stdout it not shown. However it results in closing the file. Use '' to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • fmlpsolve('set_pivoting', lp, pivoting)
    • No special considerations.
  • set_preferdual
    • fmlpsolve('set_preferdual', lp, dodual)
    • No special considerations.
  • set_presolve
    • fmlpsolve('set_presolve', lp, do_presolve {, maxloops})
    • The maxloops argument is optional in FreeMat. If not provided, then infinite is used.
  • set_print_sol
    • fmlpsolve('set_print_sol', lp, print_sol)
    • No special considerations.
  • set_rh
    • return = fmlpsolve('set_rh', lp, row, value)
    • return = fmlpsolve('set_rh', lp, [values])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = fmlpsolve('set_rh_range', lp, row, deltavalue)
    • return = fmlpsolve('set_rh_range', lp, [deltavalues])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • fmlpsolve('set_rh_vec', lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = fmlpsolve('set_row', lp, row_no, [row])
    • return = fmlpsolve('set_rowex', lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In FreeMat, there is no unused element in the matrix.
  • set_row_name
    • return = fmlpsolve('set_row_name', lp, row, name)
    • row must be provided and is as such not optional. As such no array of names can be provided. This because FreeMat has no possibility to provide sets via the import interface.
  • set_scalelimit
    • fmlpsolve('set_scalelimit', lp, scalelimit)
    • No special considerations.
  • set_scaling
    • fmlpsolve('set_scaling', lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = fmlpsolve('set_semicont', lp, column, must_be_sc)
    • return = fmlpsolve('set_semicont', lp, [must_be_sc])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • fmlpsolve('set_sense', lp, maximize)
    • No special considerations.
  • set_simplextype
    • fmlpsolve('set_simplextype', lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • fmlpsolve('set_solutionlimit', lp, simplextype)
    • No special considerations.
  • set_timeout
    • fmlpsolve('set_timeout', lp, sectimeout)
    • No special considerations.
  • set_trace
    • fmlpsolve('set_trace', lp, trace)
    • No special considerations.
  • set_upbo
    • return = fmlpsolve('set_upbo', lp, column, value)
    • return = fmlpsolve('set_upbo', lp, [values])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • fmlpsolve('set_use_names', lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = fmlpsolve('set_var_branch', lp, column, branch_mode)
    • return = fmlpsolve('set_var_branch', lp, [branch_mode])
    • In FreeMat, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = fmlpsolve('set_var_weights', lp, [weights])
    • No special considerations.
  • set_verbose
    • fmlpsolve('set_verbose', lp, verbose)
    • No special considerations.
  • set_XLI
    • return = fmlpsolve('set_XLI', lp, filename)
    • No special considerations.
  • solve
    • result = fmlpsolve('solve', lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = fmlpsolve('time_elapsed', lp)
    • No special considerations.
  • unscale
    • fmlpsolve('unscale', lp)
    • No special considerations.
  • write_basis
    • fmlpsolve('write_basis', lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = fmlpsolve('write_freemps', lp, filename)
    • return = fmlpsolve('write_freeMPS', lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In FreeMat it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = fmlpsolve('write_lp', lp, filename)
    • return = fmlpsolve('write_LP', lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In FreeMat it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = fmlpsolve('write_mps', lp, filename)
    • return = fmlpsolve('write_MPS', lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In FreeMat it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = fmlpsolve('write_XLI', lp, filename {, options {, results}})
    • No special considerations.

Extra FreeMat routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [constr_type] = fmlpsolve('get_constr_types', lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = fmlpsolve('get_int', lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = fmlpsolve('get_no_cols', lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = fmlpsolve('get_no_rows', lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = fmlpsolve('get_objective_name', lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = fmlpsolve('get_obj_fn', lp)
    [row_vec, return] = fmlpsolve('get_obj_fun', lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = fmlpsolve('get_problem_name', lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = fmlpsolve('get_reduced_costs', lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [obj, x, duals, return] = fmlpsolve('get_solution', lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = fmlpsolve('mat_elm', lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = fmlpsolve('print_handle')
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = fmlpsolve('read_lp_file', filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = fmlpsolve('get_handle', lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = fmlpsolve('return_constants'[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the fmlpsolve driver

Under Windows, the fmlpsolve FreeMat driver is a dll: fmlpsolve.dll
Under Unix/Linux, the fmlpsolve FreeMat driver is a shared library.: fmlpsolve.so
This driver is an interface to the lpsolve library lpsolve55.dll/liblpsolve55.so that contains the implementation of lp_solve. lpsolve55.dll/liblpsolve55.so is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). The fmlpsolve FreeMat driver is just a wrapper between FreeMat and lp_solve to translate the input/output to/from FreeMat and the lp_solve library.

Compilation

The fmlpsolve FreeMat driver is written in C. To compile this code, under Windows the Microsoft visual C compiler is needed and under Unix/Linux the standard cc compiler.
The needed commands are in a batch file/script.
Under Windows it is called cvc.bat, under Unix/Linux ccc.
In a command prompt/shell, go to the lpsolve FreeMat directory and enter cvc.bat/sh ccc and the compilation is done. The result is fmlpsolve.dll/fmlpsolve.so.

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./free_lp.htm000666 000000 000000 00000003524 10074503754 011524 0ustar00000000 000000 free_lp

free_lp

Deletes an lprec structure and initialise the plp variable.

void free_lp(lprec **plp);

Return Value

None

Parameters

plp

lprec structure to delete. After the call, *plp will be set to NULL.

Remarks

The free_lp function frees all memory allocated to the lp structure and initialises the *plp variable.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /*
  .
  .
  .
  */

  free_lp(&lp);
  return(0);
}

lp_solve API reference

See Also delete_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

./get_accuracy.htm000666 000000 000000 00000004263 12673526152 012546 0ustar00000000 000000 get_accuracy

get_accuracy

Returns the accuracy of bounds and constraints.

REAL get_accuracy(lprec *lp);

Return Value

get_accuracy returns the accuracy.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

This value should be as close as possible to 0.
The accuracy is the largest relative deviation of a bound or constraint.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL accuracy;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  accuracy = get_accuracy(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_break_numeric_accuracy, set_break_numeric_accuracy

./get_anti_degen.htm000666 000000 000000 00000010271 10246260716 013040 0ustar00000000 000000 get_anti_degen

get_anti_degen

Returns the used degeneracy rule.

int get_anti_degen(lprec *lp);

Return Value

get_anti_degen returns the used degeneracy rule. Can be a combination of any of the following values:

ANTIDEGEN_NONE (0) No anti-degeneracy handling
ANTIDEGEN_FIXEDVARS (1) Check if there are equality slacks in the basis and try to drive them out in order to reduce chance of degeneracy in Phase 1
ANTIDEGEN_COLUMNCHECK (2)  
ANTIDEGEN_STALLING (4)  
ANTIDEGEN_NUMFAILURE (8)  
ANTIDEGEN_LOSTFEAS (16)  
ANTIDEGEN_INFEASIBLE (32)  
ANTIDEGEN_DYNAMIC (64)  
ANTIDEGEN_DURINGBB (128)  
ANTIDEGEN_RHSPERTURB (256) Perturbation of the working RHS at refactorization
ANTIDEGEN_BOUNDFLIP (512) Limit bound flips that can sometimes contribute to degeneracy in some models

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_anti_degen function returns the used degeneracy rule.
The default is ANTIDEGEN_INFEASIBLE + ANTIDEGEN_STALLING + ANTIDEGEN_FIXEDVARS (37)

Example

#include
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int anti_degen;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }
  anti_degen= get_anti_degen(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_anti_degen, is_anti_degen

./get_basis.htm000666 000000 000000 00000011237 11107451754 012050 0ustar00000000 000000 get_basis

get_basis

Returns the basis of the lp.

unsigned char get_basis(lprec *lp, int *bascolumn, unsigned char nonbasic);

Return Value

get_basis returns TRUE if a basis could be returned, else FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

bascolumn

An array with 1+get_Nrows or 1+get_Nrows+get_Ncolumns elements that will contain the basis after the call.

nonbasic

If FALSE, then bascolumn must have 1+get_Nrows elements and only contains the basic variables. If TRUE, then bascolumn must have 1+get_Nrows+get_Ncolumns elements and will also contain the non-basic variables.

Remarks

The get_basis function returns the basis of the lp.
This can only be done after a successful solve. If the model is not successively solved then the function will return FALSE.
The array receives the basic variables and if nonbasic is TRUE, then also the non-basic variables. If an element is less then zero then it means on lower bound, else on upper bound.
Element 0 of the array is set to 0.
The default initial basis is bascolumn[x] = -x.
Each element represents a basis variable. If the absolute value is between 1 and get_Nrows, it represents a slack variable and if it is between get_Nrows+1 and get_Nrows+get_Ncolumns then it represents a regular variable. If the value is negative, then the variable is on its lower bound. If positive it is on its upper bound.
Setting an initial basis can speed up the solver considerably. It is the starting point from where the algorithm continues to find an optimal solution.
When a restart is done, lp_solve continues at the last basis, except if set_basis, default_basis, guess_basis or read_basis is called.

Example


#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int bascolumn[1+2]; /* must be 1 more then number of rows ! */

  /* Create a new LP model */
  lp = make_lp(2, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* build model
     .
     .
     .
  */

  solve(lp);
  get_basis(lp, bascolumn, FALSE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_basis, default_basis, read_basis, write_basis, guess_basis, get_basiscrash, set_basiscrash

./get_basiscrash.htm000666 000000 000000 00000007165 10472052420 013065 0ustar00000000 000000 get_basiscrash

get_basiscrash

Determines a starting base.

int get_basiscrash(lprec *lp);

Return Value

Specifies which basis crash mode is used. Can by any of the following values:

CRASH_NONE (0) No basis crash
CRASH_MOSTFEASIBLE (2) Most feasible basis
CRASH_LEASTDEGENERATE (3) Construct a basis that is in some measure the "least degenerate"

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_basiscrash function returns which basis crash mode must be used. Default is CRASH_NONE.

When no base crash is done (the default), the initial basis from which lp_solve starts to solve the model is the basis containing all slack or artificial variables that is automatically associates with each constraint.

When base crash is enabled, a heuristic ``crash procedure'' is executed before the first simplex iteration to quickly choose a basis matrix that has fewer artificial variables. This procedure tends to reduce the number of iterations to optimality since a number of iterations are skipped. lp_solve starts iterating from this basis until optimality.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int basiscrash;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  basiscrash = get_basiscrash(lp);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_basiscrash, default_basis, get_basis, set_basis, read_basis, write_basis, guess_basis

./get_bb_depthlimit.htm000666 000000 000000 00000005735 10255022624 013554 0ustar00000000 000000 get_bb_depthlimit

get_bb_depthlimit

Returns the maximum branch-and-bound depth.

int get_bb_depthlimit(lprec *lp);

Return Value

get_bb_depthlimit returns the maximum branch-and-bound depth.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_bb_depthlimit function returns the maximum branch-and-bound depth.
This is only useful if there are integer, semi-continious or SOS variables in the model so that the branch-and-bound algorithm must be used to solve them. The branch-and-bound algorithm will not go deeper than this level. When 0 then there is no limit to the depth. Limiting the depth will speed up solving time, but there is a chance that the found solution is not the most optimal one. Be aware of this. It can also result in not finding a solution at all. A positive value means that the depth is absoluut. A negative value means a relative B&B depth limit. The "order" of a MIP problem is defined to be 2x the number of binary variables plus the number of SC and SOS variables.A relative value of -x results in a maximum depth of x times the order of the MIP problem.
The default is -50.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int bb_maxlevel;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  bb_maxlevel = get_bb_depthlimit(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_bb_depthlimit

./get_bb_floorfirst.htm000666 000000 000000 00000006040 10244102342 013562 0ustar00000000 000000 get_bb_floorfirst

get_bb_floorfirst

Returns which branch to take first in branch-and-bound algorithm.

int get_bb_floorfirst(lprec *lp);

Return Value

get_bb_floorfirst returns which branch to take first in branch-and-bound algorithm. Can by any of the following values:

BRANCH_CEILING (0) Take ceiling branch first
BRANCH_FLOOR (1) Take floor branch first
BRANCH_AUTOMATIC (2) Algorithm decides which branch being taken first

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_bb_floorfirst function returns which branch to take first in branch-and-bound algorithm. This can influence solving times considerably. Depending on the model one rule can be best and for another model another rule.
The default is BRANCH_AUTOMATIC (2).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int floor_first;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  floor_first = get_bb_floorfirst(lp); /* Will return 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_bb_floorfirst, set_var_branch, get_var_branch, set_var_weights, get_var_priority

./get_bb_rule.htm000666 000000 000000 00000013672 10534546656 012377 0ustar00000000 000000 get_bb_rule

get_bb_rule

Returns the branch-and-bound rule.

int get_bb_rule(lprec *lp);

Return Value

get_bb_rule returns the branch-and-bound rule. Can by any of the following values:

NODE_FIRSTSELECT (0) Select lowest indexed non-integer column
NODE_GAPSELECT (1) Selection based on distance from the current bounds
NODE_RANGESELECT (2) Selection based on the largest current bound
NODE_FRACTIONSELECT (3) Selection based on largest fractional value
NODE_PSEUDOCOSTSELECT (4) Simple, unweighted pseudo-cost of a variable
NODE_PSEUDONONINTSELECT (5) This is an extended pseudo-costing strategy based on minimizing the number of integer infeasibilities
NODE_PSEUDORATIOSELECT (6) This is an extended pseudo-costing strategy based on maximizing the normal pseudo-cost divided by the number of infeasibilities. Effectively, it is similar to (the reciprocal of) a cost/benefit ratio
NODE_USERSELECT (7)  

One of these values may be or-ed with one or more of the following values:

NODE_WEIGHTREVERSEMODE (8) Select by criterion minimum (worst), rather than criterion maximum (best)
NODE_BRANCHREVERSEMODE (16) In case when get_bb_floorfirst is BRANCH_AUTOMATIC, select the oposite direction (lower/upper branch) that BRANCH_AUTOMATIC had chosen.
NODE_GREEDYMODE (32)  
NODE_PSEUDOCOSTMODE (64) Toggles between weighting based on pseudocost or objective function value
NODE_DEPTHFIRSTMODE (128) Select the node that has already been selected before the most number of times
NODE_RANDOMIZEMODE (256) Adds a randomization factor to the score for any node candicate
NODE_GUBMODE (512)  
NODE_DYNAMICMODE (1024) When NODE_DEPTHFIRSTMODE is selected, switch off this mode when a first solution is found.
NODE_RESTARTMODE (2048) Enables regular restarts of pseudocost value calculations
NODE_BREADTHFIRSTMODE (4096) Select the node that has been selected before the fewest number of times or not at all
NODE_AUTOORDER (8192) Create an "optimal" B&B variable ordering. Can speed up B&B algorithm.
NODE_RCOSTFIXING (16384) Do bound tightening during B&B based of reduced cost information
NODE_STRONGINIT (32768) Initialize pseudo-costs by strong branching

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_bb_rule function returns the branch-and-bound rule for choosing which non-integer variable is to be selected. This rule can influence solving times considerably. Depending on the model one rule can be best and for another model another rule.
The default is NODE_PSEUDONONINTSELECT + NODE_GREEDYMODE + NODE_DYNAMICMODE + NODE_RCOSTFIXING (17445).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int bb_rule;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  bb_rule = get_bb_rule(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_bb_rule, put_bb_nodefunc

./get_bounds_tighter.htm000666 000000 000000 00000006011 11127334142 013752 0ustar00000000 000000 get_bounds_tighter

get_bounds_tighter

Returns if set bounds may only be tighter or also less restrictive.

unsigned char get_bounds_tighter(lprec *lp);

Return Value

get_bounds_tighter returns if bounds may only be tighter or also less restrictive.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_bounds_tighter function returns if bounds may only be tighter or also less restrictive. If set to TRUE then bounds may only be tighter. This means that when set_lowbo or set_lowbo is used to set a bound and the bound is less restrictive than an already set bound, then this new bound will be ignored. If FALSE, the new bound is accepted. This functionality is useful when several bounds are set on a variable and at the end you want the most restrictive ones. By default, this setting is FALSE. Note that this setting does not affect set_bounds.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int tighter;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  tighter = get_bounds_tighter(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_bounds_tighter, set_upbo, get_upbo, set_lowbo, get_lowbo, set_bounds, set_unbounded, is_unbounded, is_negative

./get_break_at_value.htm000666 000000 000000 00000005531 10237106452 013706 0ustar00000000 000000 get_break_at_value

get_break_at_value

Returns the value at which the branch-and-bound algorithm stops when the object value is better than this value.

REAL get_break_at_value(lprec *lp);

Return Value

get_break_at_value returns the value to break on.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_break_at_value function returns the value at which the branch-and-bound algorithm stops when the object value is better than this value. Stopping at a given object value can be useful if you are only interested for a solution that has an object value which is at least a given value, but not necessarily (and most probably) the most optimal solution.
The default value is (-) infinity.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL break_at_value;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  break_at_value = get_break_at_value(lp); /* Will return -1e30 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_break_at_value, set_break_at_first, is_break_at_first, set_obj_bound, get_obj_bound, set_mip_gap, get_mip_gap

./get_break_numeric_accuracy.htm000666 000000 000000 00000004331 12673675340 015434 0ustar00000000 000000 get_break_numeric_accuracy

get_break_numeric_accuracy

Returns the accuracy values when solve should fail.

REAL get_break_numeric_accuracy(lprec *lp);

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_break_numeric_accuracy function returns the minimal accuracy for a successful solve. An accuracy that is worse than this value will result in a failing solve return code ACCURACYERROR. The default value is 5e-7.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL accuracy;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  accuracy = get_break_numeric_accuracy(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_accuracy, set_break_numeric_accuracy

./get_column.htm000666 000000 000000 00000011220 10553430310 012221 0ustar00000000 000000 get_column

get_column, get_columnex

Get all (get_column) or only the non-zero (get_columnex) column elements from the matrix.

unsigned char get_column(lprec *lp, int col_nr, REAL *column);
int get_columnex(lprec *lp, int col_nr, REAL *column, int *nzrow);

Return Value

get_column returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
get_columnex returns the number of non-zero elements returned in column and nzrow. If an error occurs, then -1 is returned.
An error occurs when col_nr is not between 1 and the number of columns in the lp.
Note that row entry mode must be off, else these functions also fail. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

col_nr

Column number of the matrix. Must be between 1 and number of columns in the lp.

column

Array in which the values are returned. For get_column, the array must be dimensioned with at least 1get_Nrows elements in the lp. For get_columnex, the array must be dimentioned with at least the number of non-zero elements in the column. If that is unknown, then use 1+get_Nrows in the lp. The return value of the function indicates how many non-zero elements there are.

nzrow

Array in which the row numbers are returned. The array must be dimentioned with at least the number of non-zero elements in the column. If that is unknown, then use 1+get_Nrows in the lp. The return value of the function indicates how many non-zero elements there are.

Remarks

get_column retrieves all values for the given column.
Element 0 of the column array will contain the value of the objective function, element 1 will contain the value for column 1, Element 2 the value for column 2, ...
get_columnex retrieves only the non-zero values for a given column.
Returned values in column and nzrow start from element 0.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL column[1+2]; /* must be 1 greater than number of rows ! */

  /* Create a new LP model */
  lp = make_lp(2, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  get_column(lp, 1, column);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_mat, get_row, get_rowex, set_row, set_rowex, set_rh, set_rh_vec, str_set_rh_vec, add_constraint, add_constraintex, str_add_constraint, add_column, add_columnex, str_add_column, set_column, set_columnex

./get_col_name.htm000666 000000 000000 00000007035 10466367042 012530 0ustar00000000 000000 get_col_name, get_origcol_name

get_col_name, get_origcol_name

Gets the name of a column in the lp.

char *get_col_name(lprec *lp, int column);

char *get_origcol_name(lprec *lp, int column);

Return Value

get_col_name and get_origcol_name return the name of the specified column. A return value of NULL indicates an error. The difference between get_col_name and get_origcol_name is only visible when a presolve (set_presolve) was done. Presolve can result in deletion of columns in the model. In get_col_name, column specifies the column number after presolve was done. In get_origcol_name, column specifies the column number before presolve was done, ie the original column number. If presolve is not active then both functions are equal.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column for which the name must be retrieved. Must be between 1 and the number of columns in the lp. In get_col_name, column specifies the column number after presolve was done. In get_origcol_name, column specifies the column number before presolve was done, ie the original column number.

Remarks

The get_col_name and get_origcol_name functions return the name of the column.
Column names are optional. If no column name was specified, the function returns Cx with x the column number.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  char *name;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  name = get_col_name(lp, 1); /* will be C1 since no column name was set */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_col_name, set_row_name, get_row_name, get_origrow_name, get_nameindex

./get_constraints.htm000666 000000 000000 00000011404 10237124734 013310 0ustar00000000 000000 get_constraints, get_ptr_constraints

get_constraints, get_ptr_constraints

Returns the values of the constraints.

unsigned char get_constraints(lprec *lp, REAL *constr);

unsigned char get_ptr_constraints(lprec *lp, REAL **ptr_constr);

Return Value

get_constraints, get_ptr_constraints returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

constr

An array that will contain the values of the constraints.

ptr_constr

The address of a pointer that will point to an array that will contain the values of the constraints.

Remarks

The get_constraints, get_ptr_constraints functions retrieve the values of the constraints.
These values are only valid after a successful solve or lag_solve. Function get_constraints needs an array that is already dimensioned with get_Nrows elements. get_ptr_constraints returns a pointer to an array already dimensioned by lp_solve. Element 0 will contain the value of the first row, element 1 of the second row, ...
Note that when set_presolve was called with parameter PRESOLVE_LINDEP that this can result in deletion of rows (the linear dependent ones). get_constraints, get_ptr_constraints will then return only the values of the rows that are kept and the values of the deleted rows are not known anymore.

Note that get_ptr_constraints returns a pointer to memory allocated and maintained by lp_solve. Be careful what you do with it. Don't modify its contents or free the memory. Unexpected behaviour would occur. Also note that this memory pointer is only guaranteed to remain constant until a next lp_solve API call is done. You should call this function again to make sure you have again the correct pointer. Otherwise, this pointer could point to invalid memory. This should not be a problem since this call is very efficient.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL constr[2], *ptr_constr;

  /* Create a new LP model */
  lp = make_lp(2, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  get_constraints(lp, constr);
  get_ptr_constraints(lp, &ptr_constr);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_feasible, get_objective, get_working_objective, get_variables, get_ptr_variables, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_constr_value, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex,

./get_constr_type.htm000666 000000 000000 00000005745 10237124576 013331 0ustar00000000 000000 get_constr_type

get_constr_type

Gets the type of a constraint.

int get_constr_type(lprec *lp, int row);

Return Value

get_constr_type returns the type of the constraint on row row. Can by any of the following values:

LE (1) Less than or equal (<=)
EQ (3) Equal (=)
GE (2) Greater than or equal (>=)

If there is an error then the function returns -1.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the constraint type must be retrieved. Must be between 1 and number of rows in the lp.

Remarks

The get_constr_type function returns the constraint type for the specified row.
The default constraint type is LE.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int constr;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  constr = get_constr_type(lp, 1); /* will be 1 (LE) */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_constr_type, set_constr_type, add_constraint, add_constraintex, str_add_constraint, del_constraint

./get_constr_value.htm000666 000000 000000 00000007574 10242077654 013466 0ustar00000000 000000 get_constr_value

get_constr_value

Gets the value of a constraint according to provided variable values.

REAL get_constr_value(lprec *lp, int row, int count, REAL *primsolution, int *nzindex);

Return Value

get_constr_value returns the value of the constraint as calculated with the provided variable values.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the constraint value must be calculated. Must be between 1 and number of rows in the lp.

count

The number of items in primsolution and nzindex.

primsolution

The values of the variables.

nzindex

The variable indexes.

Remarks

The get_constr_value function returns the value of a constraint according to provided variable values.
If primsolution is NULL, then the solution of the last solve is taken. count and nzindex are then ignored.
If primsolution is not NULL, and nzindex is NULL, then the variable values are taken from primsolution and element i must specify the value for variable i. Element 0 is not used and thus data starts from element 1. The variable must then contain 1+get_Ncolumns elements. count is ignored in that case.
If primsolution is not NULL, and nzindex is not NULL, then the variable values are taken from primsolution. nzindex contains the indexes of the variables and count specifies how many elements there are in primsolution and nzindex. So the data is then provided in a sparse vector. Elements start from index 0 in that case.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int constr;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  printf("%f\n", get_constr_value(lp, 0, 0, NULL, NULL));

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_constraints, get_ptr_constraints, get_variables, get_ptr_variables, get_primal_solution, get_ptr_primal_solution, get_var_primalresult

./get_epsb.htm000666 000000 000000 00000005630 10237106452 011673 0ustar00000000 000000 get_epsb

get_epsb

Returns the value that is used as a tolerance for the Right Hand Side (RHS) to determine whether a value should be considered as 0.

REAL get_epsb(lprec *lp);

Return Value

get_epsb returns the value of epsb.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_epsb function returns the value that is used as a tolerance for the Right Hand Side (RHS) to determine whether a value should be considered as 0.
The default value for epsb is 1e-10

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL epsb;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  epsb = get_epsb(lp); /* will return 1e-10 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_epsb, set_infinite, get_infinite, is_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./get_epsd.htm000666 000000 000000 00000005612 10237106454 011677 0ustar00000000 000000 get_epsd

get_epsd

Returns the value that is used as a tolerance for the reduced costs to determine whether a value should be considered as 0.

REAL get_epsd(lprec *lp);

Return Value

get_epsd returns the value of epsd.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_epsd function returns the value that is used as a tolerance for the reduced costs to determine whether a value should be considered as 0.
The default value for epsd is 1e-9

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL epsd;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  epsd = get_epsd(lp); /* will return 1e-9 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_epsd, set_infinite, is_infinite, get_infinite, set_epsint, get_epsint, set_epsb, get_epsb, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./get_epsel.htm000666 000000 000000 00000005646 10237106454 012063 0ustar00000000 000000 get_epsel

get_epsel

Returns the value that is used as a tolerance for rounding values to zero.

REAL get_epsel(lprec *lp);

Return Value

get_epsel returns the value of epsel.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_epsel function returns the value that is used for rounding values to zero.
epsel is used on all other places where epsint, epsb, epsd, epspivot, epsperturb are not used.
The default value for epsel is 1e-12

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL epsel;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  epsel = get_epsel(lp); /* will return 1e-12 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_epsel, set_infinite, get_infinite, is_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsb, get_epsb, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./get_epsint.htm000666 000000 000000 00000005377 10237106454 012256 0ustar00000000 000000 get_epsint

get_epsint

Returns the tolerance that is used to determine whether a floating-point number is in fact an integer.

REAL get_epsint(lprec *lp);

Return Value

get_epsint returns the value of epsint.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_epsint function returns the tolerance that is used to determine whether a floating-point number is in fact an integer.
The default value for epsint is 1e-7

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL epsint;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  epsint = get_epsint(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_epsint, set_infinite, is_infinite, get_infinite, set_epsb, get_epsb, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb

./get_epsperturb.htm000666 000000 000000 00000005141 10237106454 013134 0ustar00000000 000000 get_epsperturb

get_epsperturb

Returns the value that is used as perturbation scalar for degenerative problems.

REAL get_epsperturb(lprec *lp);

Return Value

get_epsperturb returns the perturbation scalar.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The default epsperturb value is 1e-5

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL epsperturb;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  epsperturb = get_epsperturb(lp); /* Returns 1e-5 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_epsperturb, set_infinite, get_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_mip_gap, get_mip_gap

./get_epspivot.htm000666 000000 000000 00000006376 10237106454 012625 0ustar00000000 000000 get_epspivot

get_epspivot

Returns epspivot.

REAL get_epspivot(lprec *lp);

Return Value

get_epspivot returns the value of epspivot.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_epspivot function returns the value that is used as a tolerance for the pivot element to determine whether a value should be considered as 0.
Floating-point calculations always result in loss of precision and rounding errors. Therefore a very small value (example 1e-99) could be the result of such errors and should be considered as 0 for the algorithm. epspivot specifies the tolerance to determine if a pivot element should be considered as 0. If abs(value) is less than this epspivot value it is considered as 0 and at first instance rejected as pivot element. Only when no larger other pivot element can be found and the value is different from 0 it will be used as pivot element.
The default epspivot value is 2e-7

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL epspivot;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  epspivot = get_epspivot(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_epspivot, set_infinite, get_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsel, get_epsel, get_epsperturb, set_epsperturb, set_mip_gap, get_mip_gap

./get_improve.htm000666 000000 000000 00000005777 10244104152 012430 0ustar00000000 000000 get_improve

get_improve

Returns the iterative improvement level.

int get_improve(lprec *lp);

Return Value

get_improve returns the iterative improvement level. Can by any of the following values:

IMPROVE_NONE (0) improve none
IMPROVE_SOLUTION (1) Running accuracy measurement of solved equations based on Bx=r (primal simplex), remedy is refactorization.
IMPROVE_DUALFEAS (2) Improve initial dual feasibility by bound flips (highly recommended, and default)
IMPROVE_THETAGAP (4) Low-cost accuracy monitoring in the dual, remedy is refactorization
IMPROVE_BBSIMPLEX (8) By default there is a check for primal/dual feasibility at optimum only for the relaxed problem, this also activates the test at the node level

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

improve


Remarks

The default is IMPROVE_DUALFEAS + IMPROVE_THETAGAP (6).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int improve;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  improve = get_improve(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_improve

./get_infinite.htm000666 000000 000000 00000005366 10237106454 012557 0ustar00000000 000000 get_infinite

get_infinite

Returns the value of "infinite".

REAL get_infinite(lprec *lp);

Return Value

get_infinite returns the value of "infinite".

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_infinite function returns the practical value for "infinite". This value is used for very big numbers. For example the upper bound of a variable without an upper bound.
The default is 1e30

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL infinite;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  infinite = get_infinite(lp); /* will return 1.0e30 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_infinite, is_infinite, set_epsint, get_epsint, set_epsb, get_epsb, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb

./get_lambda.htm000666 000000 000000 00000011006 10351212722 012147 0ustar00000000 000000 get_lambda, get_ptr_lambda

get_lambda, get_ptr_lambda

Returns the Lamdba vectors (Lagrangian optimization).

unsigned char get_lambda(lprec *lp, REAL *lambda);

unsigned char get_ptr_lambda(lprec *lp, REAL **ptr_lambda);

Return Value

get_lambda, get_ptr_lambda returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

lambda

An array that will contain the values of the Lamdba vectors.

ptr_lambda

The address of a pointer that will point to an array that will contain the values of the Lamdba vectors.

Remarks

The get_lambda, get_ptr_lambda functions retrieve the Lamdba vectors.
These values are only valid after a successful lag_solve. Function get_lambda needs an array that is already dimensioned with get_Lrows elements. get_ptr_lambda returns a pointer to an array already dimensioned by lp_solve.

Note that get_ptr_lambda returns a pointer to memory allocated and maintained by lp_solve. Be careful what you do with it. Don't modify its contents or free the memory. Unexpected behaviour would occur. Also note that this memory pointer is only guaranteed to remain constant until a next lp_solve API call is done. You should call this function again to make sure you have again the correct pointer. Otherwise, this pointer could point to invalid memory. This should not be a problem since this call is very efficient.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;
  REAL row[1+2]; /* must be 1 more than number of columns ! */
  REAL *ptr_lambda, lambda[1];

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  row[1] = 1.0;
  row[2] = 1.0;
  add_lag_con(lp, row, LE, 1.0);

  ret = lag_solve(lp, 0, 30, FALSE);

  get_lambda(lp, lambda);
  get_ptr_lambda(lp, &ptr_lambda);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_feasible, get_objective, get_working_objective, get_variables, get_ptr_variables, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex, get_constraints, get_ptr_constraints, get_constr_value, lag_solve

./get_lowbo.htm000666 000000 000000 00000005732 11127334154 012070 0ustar00000000 000000 get_lowbo

get_lowbo

Gets the lower bound of a variable.

REAL get_lowbo(lprec *lp, int column);

Return Value

get_lowbo returns the lower bound on the specified variable. If no bound was set, it returns 0, the default lower bound.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable. It must be between 1 and the number of columns in the lp.

Remarks

The get_lowbo function returns the lower bound on the variable identified by column.
Setting a bound on a variable is the way to go instead of adding an extra constraint (row) to the model. Setting a bound doesn't increase the model size that means that the model stays smaller and will be solved faster.
Note that the default lower bound of each variable is 0. So variables will never take negative values if no negative lower bound is set.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL a;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  a = get_lowbo(lp, 1); /* will return 0 since no lower bound was set */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_lowbo, set_upbo, get_upbo, set_bounds, set_unbounded, is_unbounded, is_negative

./get_lp_index.htm000666 000000 000000 00000006636 10351213010 012535 0ustar00000000 000000 get_lp_index

get_lp_index

Returns the index in the lp of the original row/column.

int get_lp_index(lprec *lp, int orig_index);

Return Value

get_lp_index returns the index in the lp of the original row/column.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

orig_index

Original constraint or column number. If orig_index is between 1 and get_Norig_rows then the index is a constraint (row) number. If orig_index is between 1+get_Norig_rows and get_Norig_rows + get_Norig_columns then the index is a column number.

Remarks

The get_lp_index function returns the index in the lp of the original row/column.
Note that the number of constraints (get_Nrows) and columns (get_Ncolumns) can change when a presolve is done or when negative variables are split in a positive and a negative part. get_lp_index returns the position of the constraint/variable in the lp. If orig_index is not a legal index or the constraint/column is deleted, the return value is 0.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int index;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  str_add_constraint(lp, "0 1", LE, 1.0);

  index = get_lp_index(lp, 1); /* Will return 1 */

  set_presolve(lp, PRESOLVE_COLS);
  solve(lp);

  index = get_lp_index(lp, 1); /* Will return 0 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_orig_index, get_Ncolumns, get_Norig_columns, get_Nrows, get_Norig_rows, get_Lrows, set_presolve

./get_lp_name.htm000666 000000 000000 00000004136 10237106454 012357 0ustar00000000 000000 get_lp_name

get_lp_name

Gets the name of the lp.

char *get_lp_name(lprec *lp);

Return Value

get_lp_name returns the name of the lp.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_lp_name returns the name of the lp.
Giving the lp a name is optional. The default name is "Unnamed".

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  char *name;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  name = get_lp_name(lp); /* will be "Unnamed" since no name was set */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_lp_name

./get_Lrows.htm000666 000000 000000 00000005420 11022430052 012032 0ustar00000000 000000 get_Lrows

get_Lrows

Returns the number of Lagrangian rows in the lp.

The Lagrangian solver does not work. Do not use this call.

int get_Lrows(lprec *lp);

Return Value

get_Lrows returns the number of Lagrangian rows in the lp.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The Lagrangian solver does not work. Do not use this call.

The get_Lrows function returns the number of Lagrangian rows in the lp.
A Lagrangian row is added via add_lag_con.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL row[1+2];
  int Lrows;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  row[1] = 1.0;
  row[2] = 1.0;
  add_lag_con(lp, row, LE, 1.0);

  Lrows = get_Lrows(lp); /* Will return 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_Nrows, get_Norig_rows, get_Ncolumns, get_Norig_columns, get_orig_index, get_lp_index, add_lag_con, lag_solve

./get_mat.htm000666 000000 000000 00000006205 10242041600 011507 0ustar00000000 000000 get_mat

get_mat

Get a single element from the matrix.

REAL get_mat(lprec *lp, int row, int column);

Return Value

get_mat returns the value of the element on row row, column column. If no value was set for this element, the function returns 0.
Note that row entry mode must be off, else this function also fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

Row number of the matrix. Must be between 0 and number of rows in the lp. Row 0 is objective function.

column

Column number of the matrix. Must be between 1 and number of columns in the lp.

Remarks

This function is not efficient if many values are to be retrieved. Consider to use get_row, get_rowex, get_column, get_columnex.
If row and/or column are outside the allowed range, the function returns 0.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL a;

  /* Create a new LP model */
  lp = make_lp(2, 3);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  a = get_mat(lp, 1, 2); /* will return 0 because this element isn't created */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_row, get_rowex, get_column, get_columnex, set_column, set_columnex, set_mat, set_row, set_rowex

./get_maxpivot.htm000666 000000 000000 00000005045 10553431710 012610 0ustar00000000 000000 get_maxpivot

get_maxpivot

Returns the maximum number of pivots between a re-inversion of the matrix.

int get_maxpivot(lprec *lp);

Return Value

get_maxpivot returns the maximum number of pivots between a re-inversion of the matrix.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_maxpivot function returns the maximum number of pivots between a re-inversion of the matrix.
For stability reasons, lp_solve re-inverts the matrix on regular times. max_num_inv determines how frequently this inversion is done. This can influence numerical stability. However, the more often this is done, the slower the solver becomes.
The default is 250 for the LUSOL bfp and 42 for the other BFPs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int max_num_inv;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  max_num_inv = get_maxpivot(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_maxpivot

./get_max_level.htm000666 000000 000000 00000004402 10237106454 012714 0ustar00000000 000000 get_max_level

get_max_level

Returns the deepest Branch-and-bound level of the last solution.

int get_max_level(lprec *lp);

Return Value

get_max_level returns the deepest Branch-and-bound level of the last solution.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_max_level function returns the deepest Branch-and-bound level of the last solution.
Is only applicable if the model contains integer variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int max_level;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  max_level = get_max_level(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLIget_total_nodes, get_total_iter

./get_mip_gap.htm000666 000000 000000 00000006443 10237106454 012363 0ustar00000000 000000 get_mip_gap

get_mip_gap

Returns the MIP gap value.

REAL get_mip_gap(lprec *lp, unsigned char absolute);

Return Value

get_mip_gap returns the MIP gap value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

absolute

If TRUE then the absolute MIP gap is returned, else the relative MIP gap.

Remarks

The get_mip_gap function returns the MIP gap that specifies a tolerance for the branch and bound algorithm. This tolerance is the difference between the best-found solution yet and the current solution. If the difference is smaller than this tolerance then the solution (and all the sub-solutions) is rejected. This can result in faster solving times, but results in a solution which is not the perfect solution. So be careful with this tolerance.
The default mip_gap value is 1e-11

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL mip_gap;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  mip_gap = get_mip_gap(lp, TRUE); /* Will return 1e-9 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_mip_gap, get_epsd, set_epsd, set_infinite, get_infinite, set_epsint, get_epsint, set_epsb, get_epsb, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb

./get_nameindex.htm000666 000000 000000 00000006271 10467104454 012721 0ustar00000000 000000 get_nameindex

get_nameindex

Gets the index of a given column or row name in the lp.

int get_nameindex(lprec *lp, char *name, unsigned char isrow);

Return Value

get_nameindex returns the index (column/row number) of the given column/row name. A return value of -1 indicates that the name does not exist. Note that the index is the original index number. So if presolve is active, it has no effect. It is the original column/row number that is returned.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

name

The name of the column or row for which the index (column/row number) must be retrieved.

isrow

Set to FALSE (0) if column information is needed and TRUE (1) if row information is needed.

Remarks

The get_nameindex function returns the index (column/row number) of the given column/row name. Note that this index starts from 1. Some API routines expect zero-based indexes and thus this value must then be corrected with -1.
This routine is new from version 5.1.1.1.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int column;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_row_name(lp, 1, "col1");

  column = get_nameindex(lp, "col1", TRUE); /* will return 1 */
  column = get_nameindex(lp, "col", TRUE); /* will return -1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_row_name, get_row_name, get_origrow_name, set_col_name, get_col_name, get_origcol_name

./get_Ncolumns.htm000666 000000 000000 00000005310 10237106454 012535 0ustar00000000 000000 get_Ncolumns

get_Ncolumns

Returns the number of columns (variables) in the lp.

int get_Ncolumns(lprec *lp);

Return Value

get_Ncolumns returns the number of columns (variables) in the lp.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_Ncolumns function returns the number of columns (variables) in the lp.
Note that the number of columns can change when a presolve is done or when negative variables are split in a positive and a negative part.
Therefore it is advisable to use this function to determine how many columns there are in the lp instead of relying on an own count.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int Ncolumns;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  Ncolumns = get_Ncolumns(lp); /* Will return 1 */

  set_presolve(lp, PRESOLVE_COLS);
  solve(lp);

  Ncolumns = get_Ncolumns(lp); /* Will return 0 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_Norig_columns, get_Nrows, get_Norig_rows, get_orig_index, get_lp_index, get_Lrows

./get_negrange.htm000666 000000 000000 00000005001 10237106454 012522 0ustar00000000 000000 get_negrange

get_negrange

Returns the negative value below which variables are split into a negative and a positive part.

REAL get_negrange(lprec *lp);

Return Value

get_negrange returns the negative value below which variables are split into a negative and a positive part.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_negrange function returns the negative value below which variables are split into a negative and a positive part. This value is always zero or negative.
In some cases, negative variables must be split in a positive part and a negative part. This is when a negative lower or upper bound is set on a variable. If a bound is less than this value, it is possibly split. The default is -1e6.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL negrange;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  negrange = get_negrange(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_negrange

./get_nonzeros.htm000666 000000 000000 00000004024 10237106454 012615 0ustar00000000 000000 get_nonzeros

get_nonzeros

Returns the number of non-zero elements in the matrix.

int get_nonzeros(lprec *lp);

Return Value

get_nonzeros returns the number of non-zero elements in the matrix.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_nonzeros function returns the number of non-zeros in the matrix.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int nonzeros;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  nonzeros = get_nonzeros(lp); /* Will return 0 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

./get_Norig_columns.htm000666 000000 000000 00000005552 10237106454 013565 0ustar00000000 000000 get_Norig_columns

get_Norig_columns

Returns the number of original columns (variables) in the lp.

int get_Norig_columns(lprec *lp);

Return Value

get_Norig_columns returns the number of original columns (variables) in the lp.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_Norig_columns function returns the number of original columns (variables) in the lp.
Note that the number of columns (get_Ncolumns) can change when a presolve is done or when negative variables are split in a positive and a negative part. get_Norig_columns does not change and thus returns the original number of columns in the lp.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int Norig_columns;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  Norig_columns = get_Norig_columns(lp); /* Will return 1 */

  set_presolve(lp, PRESOLVE_COLS);
  solve(lp);

  Norig_columns = get_Norig_columns(lp); /* Will return 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_Ncolumns, get_Nrows, get_Norig_rows, get_orig_index, get_lp_index, get_Lrows

./get_Norig_rows.htm000666 000000 000000 00000005253 10237106454 013075 0ustar00000000 000000 get_Norig_rows

get_Norig_rows

Returns the number of original rows (constraints) in the lp.

int get_Norig_rows(lprec *lp);

Return Value

get_Norig_rows returns the number of original rows (constraints) in the lp.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_Norig_rows function returns the number of original rows (constraints) in the lp.
Note that the number of rows (get_Nrows) can change when a presolve is done. get_Norig_rows does not change and thus returns the original number of rows in the lp.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int Norig_rows;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  Norig_rows = get_Norig_rows(lp); /* Will return 1 */

  set_presolve(lp, PRESOLVE_ROWS);
  solve(lp);

  Norig_rows = get_Norig_rows(lp); /* Will return 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_Nrows, get_Lrows, get_Ncolumns, get_Norig_columns, get_orig_index, get_lp_index

./get_Nrows.htm000666 000000 000000 00000005162 10237106454 012054 0ustar00000000 000000 get_Nrows

get_Nrows

Returns the number of rows (constraints) in the lp.

int get_Nrows(lprec *lp);

Return Value

get_Nrows returns the number of rows (constraints) in the lp.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_Nrows function returns the number of rows (constraints) in the lp.
Note that the number of rows can change when a presolve is done.
Therefore it is advisable to use this function to determine how many rows there are in the lp instead of relying on an own count.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int Nrows;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  Nrows = get_Nrows(lp); /* Will return 1 */

  set_presolve(lp, PRESOLVE_ROWS);
  solve(lp);

  Nrows = get_Nrows(lp); /* Will return 0 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_Norig_rows, get_Lrows, get_Ncolumns, get_Norig_columns, get_orig_index, get_lp_index

./get_objective.htm000666 000000 000000 00000005563 10237125060 012715 0ustar00000000 000000 get_objective

get_objective

Returns the value of the objective function.

REAL get_objective(lprec *lp);

Return Value

get_objective returns the value of the objective.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_objective function returns the value of the objective of the last solve.
This value is only valid after a successful solve or lag_solve.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL obj;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  obj = get_objective(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_feasible, get_variables, get_ptr_variables, get_working_objective, get_constraints, get_ptr_constraints, get_constr_value, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

./get_obj_bound.htm000666 000000 000000 00000005414 10237106454 012705 0ustar00000000 000000 get_obj_bound

get_obj_bound

Returns initial "at least better than" guess for objective function.

REAL get_obj_bound(lprec *lp);

Return Value

get_obj_bound returns the initial "at least better than" guess for objective function.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_obj_bound function returns the initial "at least better than" guess for objective function. This is only used in the branch-and-bound algorithm when integer variables exist in the model. All solutions with a worse objective value than this value are immediately rejected. This can result in faster solving times, but it can be difficult to predict what value to take for this bound. Also there is the chance that the found solution is not the most optimal one.
The default is infinite.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL obj_bound;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  obj_bound = get_obj_bound(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_obj_bound, set_break_at_value, get_break_at_value, set_mip_gap, get_mip_gap

./get_orig_index.htm000666 000000 000000 00000006550 10351213002 013056 0ustar00000000 000000 get_orig_index

get_orig_index

Returns the original row/column where a constraint/variable was before presolve.

int get_orig_index(lprec *lp, int lp_index);

Return Value

get_orig_index returns the original row/column where a constraint/variable was before presolve.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

lp_index

constraint or column number. If lp_index is between 1 and get_Nrows then the index is a constraint (row) number. If lp_index is between 1+get_Nrows and get_Nrows + get_Ncolumns then the index is a column number.

Remarks

The get_orig_index function returns the original row/column where a constraint/variable was before presolve.
Note that the number of constraints (get_Nrows) and columns (get_Ncolumns) can change when a presolve is done or when negative variables are split in a positive and a negative part. get_orig_index returns the original position of the constraint/variable. If lp_index is not a legal index, the return value is 0.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int index;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  index = get_orig_index(lp, 1); /* Will return 1 */

  set_presolve(lp, PRESOLVE_COLS);
  solve(lp);

  index = get_orig_index(lp, 1); /* Will return 0 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_lp_index, get_Ncolumns, get_Norig_columns, get_Nrows, get_Norig_rows, get_Lrows, get_lp_index

./get_pivoting.htm000666 000000 000000 00000012333 13555461512 012606 0ustar00000000 000000 get_pivoting

get_pivoting

Returns the pivot rule and mode.

int get_pivoting(lprec *lp);

Return Value

get_pivoting returns the pivot rule and mode. Can be one of the following rules:

PRICER_FIRSTINDEX (0) Select first
PRICER_DANTZIG (1) Select according to Dantzig
PRICER_DEVEX (2) Devex pricing from Paula Harris
PRICER_STEEPESTEDGE (3) Steepest Edge

Some of these values can be combined with any (ORed) of the following modes:

PRICE_PRIMALFALLBACK (4) In case of Steepest Edge, fall back to DEVEX in primal
PRICE_MULTIPLE (8) Preliminary implementation of the multiple pricing scheme.This means that attractive candidate entering columnsfrom one iteration may be used in the subsequent iteration, avoiding full updating of reduced costs. In the current implementation, lp_solve only reuses the 2nd best entering column alternative
PRICE_PARTIAL (16) Enable partial pricing
PRICE_ADAPTIVE (32) Temporarily use alternative strategy if cycling is detected
PRICE_RANDOMIZE (128) Adds a small randomization effect to the selected pricer
PRICE_AUTOPARTIAL (256) Indicates automatic detection of segmented/staged/blocked models.It refers to partial pricing rather than full pricing. With full pricing, all non-basic columns are scanned, but with partial pricing only a subset is scanned for every iteration. This can speed up several models
PRICE_AUTOMULTIPLE (512) Automatically select multiple pricing (primal simplex)
PRICE_LOOPLEFT (1024) Scan entering/leaving columns left rather than right
PRICE_LOOPALTERNATE (2048) Scan entering/leaving columns alternatingly left/right
PRICE_HARRISTWOPASS (4096) Use Harris' primal pivot logic rather than the default
PRICE_TRUENORMINIT (16384) Use true norms for Devex and Steepest Edge initializations

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_pivoting function returns the pivot rule (rule for selecting row and column entering/leaving) and mode. The rule is an exclusive option and the mode is a modifier to the rule. This rule/mode can influence solving times considerably. Depending on the model one rule/mode can be best and for another model another rule/mode.
The default is PRICER_DEVEX | PRICE_ADAPTIVE (34).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int pivoting;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  pivoting = get_pivoting(lp); /* will return 18 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_piv_rule, set_pivoting, is_piv_mode

./get_presolve.htm000666 000000 000000 00000020075 11301707650 012601 0ustar00000000 000000 get_presolve

get_presolve

Returns if a presolve must be done before solving.

int get_presolve(lprec *lp);

Return Value

get_presolve returns the current presolve setting. Can by the combination (OR) of any of the following values:

PRESOLVE_NONE (0) No presolve at all
PRESOLVE_ROWS (1) Presolve rows
PRESOLVE_COLS (2) Presolve columns
PRESOLVE_LINDEP (4) Eliminate linearly dependent rows
PRESOLVE_SOS (32) Convert constraints to SOSes (only SOS1 handled)
PRESOLVE_REDUCEMIP (64) If the phase 1 solution process finds that a constraint is redundant then this constraint is deleted
PRESOLVE_KNAPSACK (128) Simplification of knapsack-type constraints through addition of an extra variable, which also helps bound the OF
PRESOLVE_ELIMEQ2 (256) Direct substitution of one variable in 2-element equality constraints; this requires changes to the constraint matrix. Elimeq2 simply eliminates a variable by substitution when you have 2-element equality constraints. This can sometimes cause fill-in of the constraint matrix, and also be a source of rounding errors which can lead to problems in the simplex.
PRESOLVE_IMPLIEDFREE (512) Identify implied free variables (releasing their explicit bounds)
PRESOLVE_REDUCEGCD (1024) Reduce (tighten) coefficients in integer models based on GCD argument. Reduce GCD is for mixed integer programs where it is possible to adjust the constraint coefficies due to integrality. This can cause the dual objective ("lower bound") to increase and may make it easier to prove optimality.
PRESOLVE_PROBEFIX (2048) Attempt to fix binary variables at one of their bounds
PRESOLVE_PROBEREDUCE (4096) Attempt to reduce coefficients in binary models
PRESOLVE_ROWDOMINATE (8192) Idenfify and delete qualifying constraints that are dominated by others, also fixes variables at a bound
PRESOLVE_COLDOMINATE (16384) Deletes variables (mainly binary), that are dominated by others (only one can be non-zero)
PRESOLVE_MERGEROWS (32768) Merges neighboring >= or <= constraints when the vectors are otherwise relatively identical into a single ranged constraint
PRESOLVE_IMPLIEDSLK (65536) Converts qualifying equalities to inequalities by converting a column singleton variable to slack. The routine also detects implicit duplicate slacks from inequality constraints, fixes and removes the redundant variable.This latter removal also tends to reduce the risk of degeneracy.The combined function of this option can have a dramatic simplifying effect on some models. Implied slacks is when, for example, there is a column singleton (with zero OF) in an equality constraint. In this case, the column can be deleted and the constraint converted to a LE constraint.
PRESOLVE_COLFIXDUAL (131072) Variable fixing and removal based on considering signs of the associated dual constraint. Dual fixing is when the (primal) variable can be fixed due to the implied value of the dual being infinite.
PRESOLVE_BOUNDS (262144) Does bound tightening based on full-row constraint information. This can assist in tightening the OF bound, eliminate variables and constraints. At the end of presolve, it is checked if any variables can be deemed free, thereby reducing any chance that degeneracy is introduced via this presolve option.
PRESOLVE_DUALS (524288) Calculate duals
PRESOLVE_SENSDUALS (1048576) Calculate sensitivity if there are integer variables

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_presolve function returns if a presolve must be done before solving. Presolve looks at the model and tries to simplify it so that solving times are shorter. For example a constraint on only one variable is converted to a bound on this variable (and the constraint is deleted). Note that the model dimensions can change because of this, so be careful with this. Both rows and columns can be deleted by the presolve.
The default is not (PRESOLVE_NONE) doing a presolve.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int presolve;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  presolve = get_presolve(lp); /* returns the current presolve level */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_presolveloops, set_presolve, is_presolve

./get_presolveloops.htm000666 000000 000000 00000004711 10237117512 013654 0ustar00000000 000000 get_presolveloops

get_presolveloops

Returns the number of times presolve is done.

int get_presolveloops(lprec *lp);

Return Value

get_presolveloops returns the number of times presolve is done.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_presolveloops function returns the number of times presolve is done. After a presolve is done, another presolve can again result in elimination of extra rows and/or columns. This number specifies the maximum number of times this process is repeated. By default this is until presolve has nothing to do anymore.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int presolveloops;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  presolveloops = get_presolveloops(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_presolve, get_presolve, get_presolveloops

./get_primal_solution.htm000666 000000 000000 00000014000 10351212750 014145 0ustar00000000 000000 get_primal_solution, get_ptr_primal_solution, get_var_primalresult

get_primal_solution, get_ptr_primal_solution, get_var_primalresult

Returns the solution of the model.

unsigned char get_primal_solution(lprec *lp, REAL *pv);

unsigned char get_ptr_primal_solution(lprec *lp, REAL **ptr_pv);

REAL get_var_primalresult(lprec *lp, int index);

Return Value

get_primal_solution, get_ptr_primal_solution return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
get_var_primalresult returns the value for index.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

pv

An array that will contain the value of the objective function (element 0), values of the constraints (elements 1 till Nrows), and the values of the variables (elements Nrows+1 till Nrows+NColumns).

ptr_pv

The address of a pointer that will point to an array that will contain the value of the objective function (element 0), values of the constraints (elements 1 till Nrows), and the values of the variables (elements Nrows+1 till Nrows+NColumns).

index

index of the constraint/variable.

Remarks

The get_primal_solution, get_ptr_primal_solution, get_var_primalresult functions retrieve the values of the objective function, constraints and variables.
These values are only valid after a successful solve or lag_solve. Function get_primal_solution needs an array that is already dimensioned with 1+get_Nrows + get_Ncolumns elements. get_ptr_primal_solution returns a pointer to an array already dimensioned by lp_solve. Element 0 is the value of the objective function, elements 1 till Nrows the values of the constraints and elements Nrows+1 till Nrows+NColumns the values of the variables. get_var_primalresult requires no array. index is the array element number of the above functions and returns the value for this array element.
Special considerations when presolve was done. When set_presolve is called before solve, then presolve can have deleted both rows and columns from the model because they could be eliminated. This influences get_primal_solution and get_ptr_primal_solution. These functions only report the values of the remaining variables and constraints. However get_var_primalresult returns all values, also the deleted ones by presolve. So index is the original index number as known by the caller.

Note that get_ptr_primal_solution returns a pointer to memory allocated and maintained by lp_solve. Be careful what you do with it. Don't modify its contents or free the memory. Unexpected behaviour would occur. Also note that this memory pointer is only guaranteed to remain constant until a next lp_solve API call is done. You should call this function again to make sure you have again the correct pointer. Otherwise, this pointer could point to invalid memory. This should not be a problem since this call is very efficient.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL pv[1+2+3], *ptr_pv;

  /* Create a new LP model */
  lp = make_lp(3, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  get_primal_solution(lp, pv);
  get_ptr_primal_solution(lp, &ptr_pv);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_feasible, get_objective, get_working_objective, get_variables, get_ptr_variables, get_constraints, get_ptr_constraints, get_constr_value, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

./get_print_sol.htm000666 000000 000000 00000005376 10246267450 012770 0ustar00000000 000000 get_print_sol

get_print_sol

Returns a flag if all intermediate valid solutions must be printed while solving.

int get_print_sol(lprec *lp);

Return Value

get_print_sol returns the debug print status. Can by any of following values: Can be any of the following values:

FALSE (0) No printing
TRUE (1) Print all values
AUTOMATIC (2) Print only non-zero values

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_print_sol function returns a flag if all intermediate valid solutions must be printed while solving. Can give you useful solutions even if the total run time is too long. This function is mend for debugging purposes. The default is not to print (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int doprint;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  doprint = get_print_sol(lp); /* Will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_print_sol

./get_rh.htm000666 000000 000000 00000006247 10242041624 011353 0ustar00000000 000000 get_rh

get_rh

Gets the value of the right hand side (RHS) vector (column 0) for one row.

REAL get_rh(lprec *lp, int row);

Return Value

get_rh returns the value of the RHS for the specified row. If row is out of range it returns 0. If no previous value was set, then it also returns 0, the default RHS value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the RHS value must be retrieved. Must be between 0 and number of rows in the lp.

value

The value of the RHS.

Remarks

The get_rh function returns the value of the RHS vector (column 0) for the specified row.
Note that row can also be 0 with this function. In that case it returns the initial value of the objective function.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL a;

  /* Create a new LP model */
  lp = make_lp(2, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  a = get_rh(lp, 1); /* will return 0 since no value was previously set */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_rh, set_rh_vec, str_set_rh_vec, add_constraint, add_constraintex, str_add_constraint, get_column, get_columnex, add_column, add_columnex, str_add_column, set_column, set_columnex, get_row, get_rowex, get_mat

./get_rh_range.htm000666 000000 000000 00000006063 10237106456 012534 0ustar00000000 000000 get_rh_range

get_rh_range

Gets the range on a constraint.

REAL get_rh_range(lprec *lp, int row);

Return Value

get_rh_range returns the range set on the constraint specified by row.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row number of the constraint from which the range must be retrieved. It must be between 1 and the number of rows in the lp.

Remarks

The get_rh_range function gets the range on the constraint (row) identified by row.
Setting a range on a row is the way to go instead of adding an extra constraint (row) to the model. Setting a range doesn't increase the model size that means that the model stays smaller and will be solved faster.
If the row has a less than constraint then the range means setting a minimum on the constraint that is equal to the RHS value minus the range. If the row has a greater than constraint then the range means setting a maximum on the constraint that is equal to the RHS value plus the range.
Note that the range value is the difference value and not the absolute value.
If no range was set then get_rh_range returns a very big number, the value of get_infinite.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL a;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  a = get_rh_range(lp, 1);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_rh_range

./get_row.htm000666 000000 000000 00000011121 10351213156 011536 0ustar00000000 000000 get_row, get_rowex

get_row, get_rowex

Get all (get_row) or only the non-zero (get_rowex) row elements from the matrix.

unsigned char get_row(lprec *lp, int row_nr, REAL *row);
int get_rowex(lprec *lp, int row_nr, REAL *row, int *colno);

Return Value

get_row returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
get_rowex returns the number of non-zero elements returned in row and colno. If an error occurs, then -1 is returned.
An error occurs when row_nr is not between 0 and the number of rows in the lp.
Note that row entry mode must be off, else these functions also fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row_nr

Row number of the matrix. Must be between 0 and number of rows in the lp. Row 0 is objective function.

row

Array in which the values are returned. For get_row, the array must be dimensioned with at least 1+get_Ncolumns elements in the lp. For get_rowex, the array must be dimentioned with at least the number of non-zero elements in the row. If that is unknown, then use the number of columns in the lp. The return value of the function indicates how many non-zero elements there are.

colno

Array in which the column numbers are returned. The array must be dimentioned with at least the number of non-zero elements in the row. If that is unknown, then use the number of columns in the lp. The return value of the function indicates how many non-zero elements there are.

Remarks

get_row retrieves all values for the given row.
Element 0 of the row array is not filled. Element 1 will contain the value for column 1, Element 2 the value for column 2, ...
get_rowex retrieves only the non-zero values for a given row.
Returned values in row and colno start from element 0.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL row[1+2]; /* must be 1 greater than number of columns ! */

  /* Create a new LP model */
  lp = make_lp(1, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  get_row(lp, 1, row);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_row, set_rowex, get_mat, get_column, get_columnex, set_column, set_columnex, set_mat, set_rh, set_rh_vec, str_set_rh_vec, add_constraint, add_constraintex, str_add_constraint, add_column, add_columnex, str_add_column

./get_row_name.htm000666 000000 000000 00000006777 10466367250 012577 0ustar00000000 000000 get_row_name, get_origrow_name

get_row_name, get_origrow_name

Gets the name of a constraint (row) in the lp.

char *get_row_name(lprec *lp, int row);

char *get_origrow_name(lprec *lp, int row);

Return Value

get_row_name and get_origrow_name return the name of the specified row. A return value of NULL indicates an error. The difference between get_row_name and get_origrow_name is only visible when a presolve (set_presolve) was done. Presolve can result in deletion of rows in the model. In get_row_name, row specifies the row number after presolve was done. In get_origrow_name, row specifies the row number before presolve was done, ie the original row number. If presolve is not active then both functions are equal.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the name must be retrieved. Must be between 0 and the number of rows in the lp. In get_row_name, row specifies the row number after presolve was done. In get_origrow_name, row specifies the row number before presolve was done, ie the original row number.

Remarks

The get_row_name and get_origrow_name functions return the name of the row.
Row names are optional. If no row name was specified, the function returns Rx with x the row number. row 0 is the objective function.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  char *name;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  name = get_row_name(lp, 1); /* will be R1 since no row name was set */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_row_name, set_col_name, get_col_name, get_origcol_name, get_nameindex

./get_scalelimit.htm000666 000000 000000 00000005103 10237106456 013067 0ustar00000000 000000 get_scalelimit

get_scalelimit

Sets the relative scaling convergence criterion for the active scaling mode.

REAL get_scalelimit(lprec *lp);

Return Value

get_scalelimit returns the relative scaling convergence criterion for the active scaling mode; the integer part specifies the maximum number of iterations.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

scalelimit

maximum number of iterations

Remarks

The get_scalelimit function the relative scaling convergence criterion for the active scaling mode; the integer part specifies the maximum number of iterations (default is 5).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL scalelimit;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  scalelimit = get_scalelimit(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_scalelimit, set_scaling, get_scaling, is_integerscaling

./get_scaling.htm000666 000000 000000 00000015051 10246631510 012356 0ustar00000000 000000 get_scaling

get_scaling

Specifies which scaling algorithm is used.

int get_scaling(lprec *lp);

Return Value

get_scaling returns which scaling algorithm is used. Can by any of the following values:

SCALE_NONE (0) No scaling
SCALE_EXTREME (1) Scale to convergence using largest absolute value
SCALE_RANGE (2) Scale based on the simple numerical range
SCALE_MEAN (3) Numerical range-based scaling
SCALE_GEOMETRIC (4) Geometric scaling
SCALE_CURTISREID (7) Curtis-reid scaling

Additionally, the value can be OR-ed with any combination of one of the following values:

SCALE_QUADRATIC (8)  
SCALE_LOGARITHMIC (16) Scale to convergence using logarithmic mean of all values
SCALE_USERWEIGHT (31) User can specify scalars
SCALE_POWER2 (32) also do Power scaling
SCALE_EQUILIBRATE (64) Make sure that no scaled number is above 1
SCALE_INTEGERS (128) also scaling integer variables
SCALE_DYNUPDATE (256) dynamic update
SCALE_ROWSONLY (512) scale only rows
SCALE_COLSONLY (1024) scale only columns

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_scaling function returns which scaling algorithm is used. This can influence numerical stability considerably. It is advisable to always use some sort of scaling.
set_scaling must be called before solve is called.
SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC, SCALE_CURTISREID are the possible scaling algorithms. SCALE_QUADRATIC, SCALE_LOGARITHMIC, SCALE_USERWEIGHT, SCALE_POWER2, SCALE_EQUILIBRATE, SCALE_INTEGERS are possible additional scaling parameters.
SCALE_POWER2 results in creating a scalar of power 2. May improve stability.
SCALE_INTEGERS results also in scaling Integer columns. Default they are not scaled.
SCALE_DYNUPDATE is new from version 5.1.1.0
It has always been so that scaling is done only once on the original model. If a solve is done again (most probably after changing some data in the model), the scaling factors aren't computed again. The scalars of the original model are used. This is not always good, especially if the data has changed considerably. One way to solve this was/is call unscale before a next solve. In that case, scale factors are recomputed.
From version 5.1.1.0 on, there is another way to make sure that scaling factors are recomputed and this is by settings SCALE_DYNUPDATE. In that case, the scaling factors are recomputed also when a restart is done. Note that they are then always recalculated with each solve, even when no change was made to the model, or a change that doesn't influence the scaling factors like changing the RHS (Right Hand Side) values or the bounds/ranges. This can influence performance. It is up to you to decide if scaling factors must be recomputed or not for a new solve, but by default it still isn't so. It is possible to set/unset this flag at each next solve and it is even allowed to choose a new scaling algorithm between each solve. Note that the scaling done by the SCALE_DYNUPDATE is incremental and the resulting scalarsare typically different from scalars recomputed from scratch.
The default is SCALE_GEOMETRIC + SCALE_EQUILIBRATE + SCALE_INTEGERS (196).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int scalemode;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  scalemode = get_scaling(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_scaling, set_scalelimit, get_scalelimit, is_integerscaling, is_scalemode, is_scaletype

./get_sensitivity_obj.htm000666 000000 000000 00000015676 11272242654 014206 0ustar00000000 000000 get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

Returns the sensitivity of the objective function.

unsigned char get_sensitivity_obj(lprec *lp, REAL *objfrom, REAL *objtill);

unsigned char get_sensitivity_objex(lprec *lp, REAL *objfrom, REAL *objtill, REAL *objfromvalue, REAL *objtillvalue);

unsigned char get_ptr_sensitivity_obj(lprec *lp, REAL **ptr_objfrom, REAL **ptr_objtill);

unsigned char get_ptr_sensitivity_objex(lprec *lp, REAL **ptr_objfrom, REAL **ptr_objtill, REAL **ptr_objfromvalue, REAL **ptr_objtillvalue);

Return Value

get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

objfrom

An array that will contain the values of the lower limits on the objective function.

ptr_objfrom

The address of a pointer that will point to an array that will contain the values of the lower limits of the objective function.

objtill

An array that will contain the values of the upper limits of the objective function.

ptr_objtill

The address of a pointer that will point to an array that will contain the values of the upper limits of the objective function.

objfromvalue

An array that will contain the values of the variables at their lower limit. Only applicable when the value of the variable is 0 (rejected).

objtillvalue

Not used at this time.

ptr_objfromvalue

The address of a pointer that will point to an array that will contain the values of the variables at their lower limit. Only applicable when the value of the variable is 0 (rejected).

ptr_objtillvalue

Not used at this time.

Remarks

The get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex functions return the sensitivity of the objective function.
These values are only valid after a successful solve and if there are integer variables in the model then only if set_presolve is called before solve with parameter PRESOLVE_SENSDUALS. Functions get_sensitivity_obj, get_sensitivity_objex need arrays that are already dimensioned with get_Ncolumns elements. get_ptr_sensitivity_obj, get_ptr_sensitivity_objex returns a pointer to an array already dimensioned by lp_solve. Element 0 will contain the value of the first variable, element 1 of the second variable, ...
The meaning of these limits are the following. As long as the value of the coefficient of the objective function stays between the lower limit (objfrom) and the upper limit (objtill), the solution stays the same. Only the objective value itself changes with a value equal to the difference multiplied by the amount of this variable. If there is no lower/upper limit, then these values are (-)infinity.

Note that get_ptr_sensitivity_obj and get_ptr_sensitivity_objex return a pointer to memory allocated and maintained by lp_solve. Be careful what you do with it. Don't modify its contents or free the memory. Unexpected behaviour would occur. Also note that this memory pointer is only guaranteed to remain constant until a next lp_solve API call is done. You should call this function again to make sure you have again the correct pointer. Otherwise, this pointer could point to invalid memory. This should not be a problem since this call is very efficient.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL objfrom[1+2], objtill[1+2], *ptr_objfrom, *ptr_objtill;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  str_set_obj_fn(lp, "1 1");
  str_add_constraint(lp, "2 4", GE, 10);
  set_lowbo(lp, 1, 1);

  solve(lp);

  get_sensitivity_obj(lp, objfrom, objtill);
  get_ptr_sensitivity_obj(lp, &ptr_objfrom, &ptr_objtill);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_feasible, get_objective, get_working_objective, get_variables, get_ptr_variables, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_rhs, get_ptr_sensitivity_rhs,

./get_sensitivity_rhs.htm000666 000000 000000 00000020643 10516355706 014221 0ustar00000000 000000 get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult

get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult

Returns the sensitivity of the constraints and the variables.

unsigned char get_sensitivity_rhs(lprec *lp, REAL *duals, REAL *dualsfrom, REAL *dualstill);

unsigned char get_ptr_sensitivity_rhs(lprec *lp, REAL **ptr_duals, REAL **ptr_dualsfrom, REAL **ptr_dualstill);

unsigned char get_dual_solution(lprec *lp, REAL *duals);

unsigned char get_ptr_dual_solution(lprec *lp, REAL **ptr_duals);

REAL get_var_dualresult(lprec *lp, int index);

Return Value

get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
get_var_dualresult returns the reduced cost.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

duals

An array that will contain the values of the dual variables aka reduced costs.

ptr_duals

The address of a pointer that will point to an array that will contain the values of the dual variables aka reduced costs.

dualsfrom

An array that will contain the values of the lower limits on the dual variables aka reduced costs.

ptr_dualsfrom

The address of a pointer that will point to an array that will contain the values of the lower limits of the dual variables aka reduced costs.

dualstill

An array that will contain the values of the upper limits on the dual variables aka reduced costs.

ptr_dualstill

The address of a pointer that will point to an array that will contain the values of the upper limits of the dual variables aka reduced costs.

index

The column of the variable for which the reduced cost is required. Note that this is the column number before presolve was done, if active. If index is 0, then the value of the objective function is returned by get_var_dualresult

Remarks

The get_sensitivity_rhs, get_ptr_sensitivity_rhs functions return the values of the dual variables aka reduced costs and their limits.
The get_dual_solution, get_ptr_dual_solution, get_var_dualresult functions return only the value(s) of the dual variables aka reduced costs.
These values are only valid after a successful solve and if there are integer variables in the model then only if set_presolve is called before solve with parameter PRESOLVE_SENSDUALS.
Function get_sensitivity_rhs needs an array that is already dimensioned with get_Nrows+get_Ncolumns elements.
Function get_dual_solution needs an array that is already dimensioned with 1+get_Nrows+get_Ncolumns elements.
get_ptr_sensitivity_rhs and get_ptr_dual_solution return a pointer to an array already dimensioned by lp_solve.

For functions get_sensitivity_rhs and get_ptr_sensitivity_rhs, Element 0 will contain the value of the first row, element 1 of the second row, ... Element get_Nrows contains the value for the first variable, element get_Nrows+1 the value for the second variable and so on.

For functions get_dual_solution and get_ptr_dual_solution the index starts from 1 and element 0 is not used. The first get_Nrows elements contain the duals of the constraints, the next get_Ncolumns elements contain the duals of the variables.

The dual values or reduced costs values indicate that the objective function will change with the value of the reduced cost if the restriction is changed with 1 unit. There will only be a reduced cost if the value is bounded by the restriction, else it is zero. Note that the sign indicates if the objective function will increase or decrease. The reduced costs remains constant as long as the restriction stays within the lower/upper range also provided with these functions (dualsfrom, dualstill). If there is no reduced cost, or no lower/upper limit, then these values are (-)infinity.

Note that get_ptr_sensitivity_rhs and get_ptr_dual_solution return a pointer to memory allocated and maintained by lp_solve. Be careful what you do with it. Don't modify its contents or free the memory. Unexpected behaviour would occur. Also note that this memory pointer is only guaranteed to remain constant until a next lp_solve API call is done. You should call this function again to make sure you have again the correct pointer. Otherwise, this pointer could point to invalid memory. This should not be a problem since this call is very efficient.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL duals[1+2], dualsfrom[1+2], dualstill[1+2], *ptr_duals, *ptr_dualsfrom, *ptr_dualstill;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  str_set_obj_fn(lp, "1 1");
  str_add_constraint(lp, "2 4", GE, 10);
  set_lowbo(lp, 1, 1);

  solve(lp);

  get_sensitivity_rhs(lp, duals, dualsfrom, dualstill);
  get_ptr_sensitivity_rhs(lp, &ptr_duals, &ptr_dualsfrom, &ptr_dualstill);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_feasible, get_objective, get_working_objective, get_variables, get_ptr_variables, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex,

./get_simplextype.htm000666 000000 000000 00000005537 10246270350 013332 0ustar00000000 000000 get_simplextype

get_simplextype

Returns the desired combination of primal and dual simplex algorithms.

int get_simplextype(lprec *lp);

Return Value

get_simplextype returns the desired combination of primal and dual simplex algorithms.
Can be any of the following values:

SIMPLEX_PRIMAL_PRIMAL (5) Phase1 Primal, Phase2 Primal
SIMPLEX_DUAL_PRIMAL (6) Phase1 Dual, Phase2 Primal
SIMPLEX_PRIMAL_DUAL (9) Phase1 Primal, Phase2 Dual
SIMPLEX_DUAL_DUAL (10) Phase1 Dual, Phase2 Dual

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_simplextype function returns the desired combination of primal and dual simplex algorithms. The default is SIMPLEX_DUAL_PRIMAL (6).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int primal_dual;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  primal_dual = get_simplextype(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_simplextype, set_preferdual

./get_solutioncount.htm000666 000000 000000 00000005015 10237106456 013670 0ustar00000000 000000 get_solutioncount

get_solutioncount

Returns the number of equal solutions.

int get_solutioncount(lprec *lp);

Return Value

get_solutioncount returns the number of equal solutions. This is only valid if there are integer, semi-continious or SOS variables in the model so that the branch-and-bound algoritm is used. This count gives the number of solutions with the same optimal objective value. If there is only one optimal solution, this value is 1.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_solutioncount function returns the number of equal solutions up to get_solutionlimit.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int solutioncount;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  solutioncount = get_solutioncount(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_solutionlimit, set_solutionlimit

./get_solutionlimit.htm000666 000000 000000 00000005113 10237106456 013655 0ustar00000000 000000 get_solutionlimit

get_solutionlimit

Returns the solution number that must be returned.

int get_solutionlimit(lprec *lp);

Return Value

get_solutionlimit returns the solution number that must be returned. This value gives the number of the solution that must be returned.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

This is only valid if there are integer, semi-continious or SOS variables in the model so that the branch-and-bound algoritm is used. If there are more solutions with the same objective value, then this number specifies which solution must be returned. This can be used to retrieve all possible solutions. Start with 1 till get_solutioncount

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int solutionlimit;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  solutionlimit = get_solutionlimit(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_solutionlimit, get_solutioncount

./get_status.htm000666 000000 000000 00000004447 10237106746 012300 0ustar00000000 000000 get_status

get_status

Returns an extra status after a call to a function.

int get_status(lprec *lp);

Return Value

Extra status which indicates type of problem after call to function.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_status function returns an extra status after a call to a function. Some functions return FALSE when they have failed. To have more information on the reason of the failure, this routine can be used to get an extended error code.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int spx_status;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /*
  .
  .
  .
  */

  spx_status = get_status(lp);

  return(0);
}

lp_solve API reference

See Also free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

./get_statustext.htm000666 000000 000000 00000004675 10237106746 013210 0ustar00000000 000000 get_statustext

get_statustext

Returns the description of a returncode of the solve function.

char *get_statustext(lprec *lp, int statuscode);

Return Value

The description of a returncode of the solve function

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

statuscode

Returncode of solve

Remarks

The get_statustext function returns a comprehensible description of a returncode of the solve function.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /*
  .
  .
  .
  */

  ret = solve(lp);

  printf("%s\n", get_statustext(lp, ret));
  return(0);
}

lp_solve API reference

See Also free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, solve

./get_timeout.htm000666 000000 000000 00000004676 10237106456 012445 0ustar00000000 000000 get_timeout

get_timeout

Gets the timeout.

long get_timeout(lprec *lp);

Return Value

get_timeout returns the number of seconds after which a timeout occurs.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_timeout function returns a timeout in seconds. The solve and lag_solve functions may not last longer than this time or the routines return with a timeout. There is no valid solution at this time. The default timeout is 0, resulting in no timeout.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  long timeout;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  timeout = get_timeout(lp); /* will return 0 since no timeout was set */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_timeout, time_elapsed, solve, lag_solve

./get_total_iter.htm000666 000000 000000 00000004671 10616310602 013107 0ustar00000000 000000 get_total_iter

get_total_iter

Returns the total number of iterations.

long long get_total_iter(lprec *lp);

Return Value

get_total_iter returns the total number of iterations.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

If the model contains integer variables then it returns the number of iterations to find a relaxed solution plus the number of iterations in the B&B process.
If the model contains no integer variables then it returns the number of iterations to find a solution.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  long long total_iter;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  total_iter = get_total_iter(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_max_level, get_total_nodes

./get_total_nodes.htm000666 000000 000000 00000004500 10237117744 013256 0ustar00000000 000000 get_total_nodes

get_total_nodes

Returns the total number of nodes processed in branch-and-bound.

long long get_total_nodes(lprec *lp);

Return Value

get_total_nodes returns the total number of nodes processed in branch-and-bound of the last solution.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_total_nodes function returns the total number of nodes processed in branch-and-bound of the last solution.
Is only applicable if the model contains integer variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int total_nodes;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  total_nodes = get_total_nodes(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_max_level, get_total_iter

./get_upbo.htm000666 000000 000000 00000006061 11127334162 011706 0ustar00000000 000000 get_upbo

get_upbo

Gets the upper bound of a variable.

REAL get_upbo(lprec *lp, int column);

Return Value

get_upbo returns the upper bound on the specified variable. If no bound was set, it returns a very big number, the value of get_infinite, the default upper bound.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable. It must be between 1 and the number of columns in the lp.

Remarks

The get_upbo function returns the upper bound on the variable identified by column.
Setting a bound on a variable is the way to go instead of adding an extra constraint (row) to the model. Setting a bound doesn't increase the model size that means that the model stays smaller and will be solved faster.
The default upper bound of a variable is infinity (well not quite. It is a very big number, the value of get_infinite).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL a;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  a = get_upbo(lp, 1); /* will return 1e30 since no upper bound was set */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_upbo, set_lowbo, get_lowbo, set_bounds, set_unbounded, is_unbounded, is_negative

./get_variables.htm000666 000000 000000 00000010574 10237125100 012704 0ustar00000000 000000 get_variables, get_ptr_variables

get_variables, get_ptr_variables

Returns the values of the variables.

unsigned char get_variables(lprec *lp, REAL *var);

unsigned char get_ptr_variables(lprec *lp, REAL **ptr_var);

Return Value

get_variables, get_ptr_variables returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

var

An array that will contain the values of the variables.

ptr_var

The address of a pointer that will point to an array that will contain the values of the variables.

Remarks

The get_variables, get_ptr_variables functions retrieve the values of the variables.
These values are only valid after a successful solve or lag_solve. Function get_variables needs an array that is already dimensioned with get_Ncolumns elements. get_ptr_variables returns a pointer to an array already dimensioned by lp_solve. Element 0 will contain the value of the first variable, element 1 of the second variable, ...

Note that get_ptr_variables returns a pointer to memory allocated and maintained by lp_solve. Be careful what you do with it. Don't modify its contents or free the memory. Unexpected behaviour would occur. Also note that this memory pointer is only guaranteed to remain constant until a next lp_solve API call is done. You should call this function again to make sure you have again the correct pointer. Otherwise, this pointer could point to invalid memory. This should not be a problem since this call is very efficient.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL var[2], *ptr_var;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  get_variables(lp, var);
  get_ptr_variables(lp, &ptr_var);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_feasible, get_objective, get_working_objective, get_constraints, get_ptr_constraints, get_constr_value, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

./get_var_branch.htm000666 000000 000000 00000007466 10237106456 013064 0ustar00000000 000000 get_var_branch

get_var_branch

Returns, for the specified variable, which branch to take first in branch-and-bound algorithm.

int get_var_branch(lprec *lp, int column);

Return Value

get_var_branch returns which branch to take first in branch-and-bound algorithm.

Can by any of the following values:

BRANCH_CEILING (0) Take ceiling branch first
BRANCH_FLOOR (1) Take floor branch first
BRANCH_AUTOMATIC (2) Algorithm decides which branch being taken first

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable on which the mode must be returned. It must be between 1 and the number of columns in the lp. If it is not within this range, the return value is the value of get_bb_floorfirst

Remarks

The get_var_branch function returns which branch to take first in branch-and-bound algorithm. This can influence solving times considerably. Depending on the model one rule can be best and for another model another rule.
When no value was set via set_var_branch, the return value is the value of get_bb_floorfirst. It also returns the value of get_bb_floorfirst when set_var_branch was called with branch mode BRANCH_DEFAULT (3).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int branch_mode;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  branch_mode = get_var_branch(lp, 1); /* will return BRANCH_FLOOR (1), the default branch mode */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_var_branch, set_bb_floorfirst, get_bb_floorfirst, set_var_weights, get_var_priority

./get_var_priority.htm000666 000000 000000 00000006002 10237106456 013471 0ustar00000000 000000 get_var_priority

get_var_priority

Returns, for the specified variable, the priority the variable has in the branch-and-bound algorithm.

int get_var_priority(lprec *lp, int column);

Return Value

get_var_priority returns the priority of the variable.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable on which the priority must be returned. It must be between 1 and the number of columns in the lp. If it is not within this range, the return value is 0

Remarks

The get_var_priority function returns the priority the variable has in the branch-and-bound algorithm. This priority is determined by the weights set by set_var_weights. The default priorities are the column positions of the variables in the model.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL weights[2];
  int priority;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  weights[0] = 2;
  weights[1] = 1;

  set_var_weights(lp, weights);

  priority = get_var_priority(lp, 1); /* will return 2 */
  priority = get_var_priority(lp, 2); /* will return 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_var_weights, get_var_branch, set_var_branch, set_bb_floorfirst, get_bb_floorfirst

./get_verbose.htm000666 000000 000000 00000007411 10255022576 012412 0ustar00000000 000000 get_verbose

get_verbose

Returns the verbose level.

int get_verbose(lprec *lp);

Return Value

get_verbose returns the current verbose level. Can be one of the following values:

NEUTRAL (0) Only some specific debug messages in de debug print routines are reported.
CRITICAL (1) Only critical messages are reported. Hard errors like instability, out of memory, ...
SEVERE (2) Only severe messages are reported. Errors.
IMPORTANT (3) Only important messages are reported. Warnings and Errors.
NORMAL (4) Normal messages are reported. This is the default.
DETAILED (5) Detailed messages are reported. Like model size, continuing B&B improvements, ...
FULL (6) All messages are reported. Useful for debugging purposes and small models.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_verbose function returns the verbose level.
lp_solve reports information back to the user. How much information is reported depends on the verbose level. The default verbose level is NORMAL. lp_solve determines how verbose a given message is. For example specifying a wrong row/column index values is considered as a SEVERE error. verbose determines how much of the lp_solve message are reported. All messages equal to and below the set level are reported.
The default reporting device is the console screen. It is possible to set a used defined reporting routine via put_logfunc.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int verbose;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  verbose = get_verbose(lp); /* Will return 4 (NORMAL) */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_verbose, put_logfunc

./get_working_objective.htm000666 000000 000000 00000006077 10237125210 014453 0ustar00000000 000000 get_working_objective

get_working_objective

Returns the value of the objective function.

REAL get_working_objective(lprec *lp);

Return Value

get_working_objective returns the current value of the objective while solving the model.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The get_working_objective function returns the current value of the objective while solving the model.
This value can be retrieved while solving in a callback function.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int msgfunction(lprec *lp, void *userhandle, char *buf)
{

 printf("%f\n", get_working_objective(lp));

 return(0);
}

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  put_msgfunc(lp, msgfunction, NULL, 0);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_working_objective, is_feasible, get_variables, get_ptr_variables, get_constraints, get_ptr_constraints, get_constr_value, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

./guess_basis.htm000666 000000 000000 00000007306 10474062744 012424 0ustar00000000 000000 guess_basis

guess_basis

Create a starting base from the provided guess vector.

unsigned char guess_basis(lprec *lp, REAL *guessvector, int *basisvector);

Return Value

guess_basis returns TRUE if a valid base could be termined and FALSE if not.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

guessvector

A vector that must contain a feasible solution vector. It must contain at least 1+get_Ncolumns elements. Element 0 is not used.

basisvector

When successful, this vector contains a feasible basis corresponding to guessvector. The array must already be dimentioned for at least 1+get_Nrows+get_Ncolumns elements. When the routine returns successful, basisvector is filled with the basis. This array can be provided to set_basis.

Remarks

This routine is ment to find a basis based on provided variable values. This basis can be provided to lp_solve via set_basis. This can result in getting faster to an optimal solution. However the simplex algorithm doesn't guarantee you that.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;
  REAL guessvector[1 + 2];
  int basis[1 + 2 + 2];

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_maxim(lp);
  str_add_constraint(lp, "1 0", LE, 3);
  str_add_constraint(lp, "0 1", LE, 3);

  guessvector[1] = 3;
  guessvector[2] = 3;

  ret = guess_basis(lp, guessvector, basis);
  set_basis(lp, basis, TRUE);
  set_print_sol(lp, TRUE);

  solve(lp); /* notice that the number of iterations is NULL because we provided a base that is immediately optimal */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_basis, set_basis, default_basis, get_basiscrash set_basiscrash

./has_BFP.htm000666 000000 000000 00000004436 10237106456 011354 0ustar00000000 000000 has_BFP

has_BFP

Returns if there is a basis factorization package (BFP) available.

unsigned char has_BFP(lprec *lp);

Return Value

has_BFP returns TRUE if there is a BFP available, else FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

There should always be a BFP available, else lpsolve can not solve. Normally lpsolve is compiled with a default BFP. See Basis Factorization Packages for a complete description on BFPs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char hasBFP;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  hasBFP = has_BFP(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_nativeBFP, set_BFP

./has_XLI.htm000666 000000 000000 00000004266 10237106456 011402 0ustar00000000 000000 has_XLI

has_XLI

Returns if there is an external language interface (XLI) set.

unsigned char has_XLI(lprec *lp);

Return Value

has_XLI returns TRUE if there is an XLI set, else FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

See External Language Interfaces for a complete description on XLIs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char hasXLI;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  hasXLI = has_XLI(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, write_XLI, is_nativeXLI, set_XLI

./IDE/000777 000000 000000 00000000000 13751300671 007771 5ustar00000000 000000 ./IDE.htm000666 000000 000000 00000010067 13772705351 010516 0ustar00000000 000000 LPSolve IDE

LPSolve IDE

The LPSolve IDE (Integrated Development Interface) is a very user friendly Windows interface to the lpsolve API. All functionality of lpsolve can be accessed via a graphical and very user friendly application.

Many thanks to Henri Gourvest for making this nice interface to lpsolve and making it available to the community.

Here is a list of some of the features of the IDE:

  • Everything is graphical and mouse controled
  • Enter your lp model in all supported formats and even via an XLI interface (See External Language Interfaces)
  • Convert your lp model from any supported format to another supported format and even via an XLI interface (See External Language Interfaces)
  • Very user friendly editor to enter/change the model with syntax highlight.
  • Syntax checking of the model
  • Solve the model
  • See the results in grids
  • Control every possible lpsolve option (tolerances, presolve, scaling, ...)
  • View the matrix in grids
  • Export model to HTML, RTF, LaTeX output
  • Export matrix to CSV, HTML, RTF output
  • Export results to CSV, HTML, RTF output
  • Show statistics about the model.
  • ...

Here are some screen shorts:

Source

Results

Matrix

Options


Installation

Download the setup lp_solve_5.5.2.11_IDE_Setup.exe and run the setup, that is all.
Note that it needs the lpsolve dll (lpsolve55.dll) to do its job. For your convenience, a dll is provided with this archive, but it is not guaranteed to be the most recent one. To get the most recent lpsolve dll, extract if from the lp_solve_5.5.2.11_dev.zip archive and put it in the folder where you installed the IDE files in. Also note that the IDE also puts some messages on the console. This may be changed in the future. When started from a command prompt, the messages are shown in this screen, when started from Windows, a console screen will also be created. If you are looking for a message not shown in the IDE, maybe it is shown on the console window...

Usage

The IDE is very easy to use and doesn't need much explanations. When you start it, you get an editor window where a model file must be entered. By default this in the lp format. Initially, you will see the following:
/* Objective function */
min: ;

/* Variable bounds */
As an example, clear this and enter the following:
max: 143 x + 60 y;

120 x + 210 y <= 15000;
110 x + 30 y <= 4000;
x + y <= 75;
Now press the F9 button or click the green arrow (Solve) in the toolbar to solve this model. In the result tab you see the result of this model. Note that this is the model presented in Formulation of an lp problem in lpsolve. The model is formulated in the lp format. See lp-format for a description of it.
./index.htm000666 000000 000000 00000003153 13772705351 011222 0ustar00000000 000000 lp_solve reference guide (5.5.2.11) <body> <a href="contents.htm">contents</a> </body> ./index.html000666 000000 000000 00000001216 10740117166 011365 0ustar00000000 000000 lp_solve reference guide <body> You browser does not support frames.<br> Click <a href="menu.htm">here</a> to load menu </body> ./Infeasible.htm000666 000000 000000 00000012762 10471636030 012150 0ustar00000000 000000 Infeasible models

Infeasible models

A linear program is infeasible if there exists no solution that satisfies all of the constraints -- in other words, if no feasible solution can be constructed. Since any real operation that you are modelling must remain within the constraints of reality, infeasibility most often indicates an error of some kind. Simplex-based LP software like lp_solve efficiently detects when no feasible solution is possible.

The source of infeasibility is often difficult to track down. It may stem from an error in specifying some of the constraints in your model, or from some wrong numbers in your data. It can be the result of a combination of factors, such as the demands at some customers being too high relative to the supplies at some warehouses.

Upon detecting infeasibility, LP codes typically show you the most recent infeasible solution that they have encountered. Sometimes this solution provides a good clue as to the source of infeasibility. If it fails to satisfy certain capacity constraints, for example, then you would do well to check whether the capacity is sufficient to meet the demand; perhaps a demand number has been mistyped, or an incorrect expression for the capacity has been used in the capacity constraint, or the model simply lacks any provision for coping with increasing demands. More often, unfortunately, LP codes respond to an infeasible problem by returning a meaninglessly infeasible solution, such as one that violates material balances. lp_solve is behaving also as such.

lp_solve currently doesn't provide analysis routines to detect infeasible constraints however that doesn't mean that it stops there.

A useful approach is to forestall meaningless infeasibilities by explicitly modelling those sources of infeasibility that you view as realistic. As a simple example, you could add a new "slack" variable on each capacity constraint, having a very high penalty cost. Then infeasibilities in your capacities would be signalled by positive values for these slacks at the optimal solution, rather than by a mysterious lack of feasibility in the linear program as a whole. Modelling approaches that use this technique are called sometimes "elastic programming" or "elastic filter".

So in practice, if a constraint is a < constraint, add a variable to the model and give it for that constraint a -1 coefficient for that variable. In the objective you give it a relative large cost. If a constraint is a > constraint, add a variable to the model and give it for that constraint a +1 coefficient for that variable. In the objective you give it a relative large cost. If a constraint is an equal constraint, add two variables to the model and give it for that constraint respectively a -1 and +1 coefficient for that variable. In the objective you give them a relative large cost. Or you only add one variable and give it an -infinite lower bound.

This will result in an automatic relaxation of the constraint(s) when needed (if that constraint would make the model infeasible). To make sure that these added variables only get non-zero values when the constraint is violating, the value in the objective must be relative large. Like that this variable gets a penalty cost and it will only become non-zero when really needed. Note that the signs of these objective coefficients must be positive when minimizing and negative when maximizing. Don't make these costs too big also because that introduces instabilities. If none of these added variables have a non-zero value then the model was initially feasible. When at least one is non-zero then the original model is infeasible. Note that the objective value will then not be very useful. However you could subtract the cost * value of all these variables from the objective to obtain the objective value of the relaxed model.

Note that a model can also become infeasible because of bounds set on variables. Above approach doesn't relax these.

Example:

min: x + y;
c1: x >= 6;
c2: y >= 6;
c3: x + y <= 11;

This model is clearly infeasible. Now introduce extra variables to locate the infeasibility:

min: x + y + 1000 e1 + 1000 e2 + 1000 e3;
c1: x + e1 >= 6;
c2: y + e2 >= 6;
c3: x + y - e3 <= 11;

The result of this model is:

Value of objective function: 1011

Actual values of the variables:
x                               5
y                               6
e1                              1
e2                              0
e3                              0

With this simple example model, multiple solutions were possible. Here, the first constraint was relaxed since e1 is non-zero. Only this one constraint had to be relaxed to make the model feasible. The objective value of 1011 isn't saying very much. However if we subtract 1000 e1 + 1000 e2 + 1000 e3 from it, then it becomes 11 which is the value of the original objective function (x + y).

./integer.htm000666 000000 000000 00000015720 11317376002 011541 0ustar00000000 000000 Integer variables

integer variables

Integer variables are variables that must take an integer value (0, 1, 2, ...). A special kind of integer variables is binary variables. Binary variables can only take the value 0 or 1. They are integer variables with a maximum of 1 on them (and don't forget there is always an implicit minimum of 0 on each variable). If all variables are integer then it is a pure integer model, else it is a mixed-integer model, sometimes denoted as MIP (Mixed Integer Programming).

There are many practical uses of such variables. Binary variables for example are used to specify that something may be used or not. Integer variables say that a variable must take a multiple of a given value. For example if you want that a given variable must be a multiple of 25 then you can construct following equation:

var - 25 i = 0

with i the integer variable and var the variable that must be a multiple of 25. So an extra variable and an extra constraint is needed. This is ok if only a limited number of such variables are in the model, but if there are alot then the model dimensions will increase considerably. As an alternative you can also do a substitution of the variable:

var = 25 i

Everywhere where variable var is used, substitute it by 25 i. This in the objective function, the constraints and bounds. So variable var is removed from the model and replaced by i. i can be defined as integer. The objective value of this substituted model will be the same as the original one. However to obtain the value of variable var, you must multiply the returned variable i with 25.

There is however one drawback on integer variables. These models are harder to solve and solution time can increment exponentially. The more integer variables there are the more time it takes to solve the model. A model without the integer variables may for example be solved in 0.1 seconds while the same model with some of the variables integer can take several minutes to solve. Be aware of this. Also try to limit the solution as much as possible. If you know some extra bounds on variables then it can be very good for the solution time to set them because this limits the number of combinations the algorithm has to examine. Another negative site on integer variables is the inaccurate sensitivity analysis when integer variables are used. See Inaccurate sensitivity analysis in a model with integer variables

The integer solution is searched via the so-called 'branch-and-bound' algorithm. The model is first solved without the integer restrictions. Then it is investigated which of the integer variables are non-integer. When such a variable is found the model is split in two sub models. A first one with a minimum restriction on this variable that has the ceiling integer value and a second one with a maximum restriction on this variable that has the floor integer value. Both these sub models are optimised again and now this variable will have an integer value (if there is a solution). The algorithm then looks again if there are still (other) integer variables that have a non-integer value and if so the process is done again. This until a solution is found where are integer variables have integer values. This solution is then remembered as the best-until-now solution and the algorithm continues until it finds again an integer solution and if it is better it takes this one as the best-until-now solution. The more integer variables there are, the more combinations must be investigated and the more time it takes to solve the model.

lp_solve supports integer variables since a long time. The API call set_int can be used to define a variable as integer. The API call set_binary can be used to define a variable as binary.

In the mps format, integer variables can be specified in the COLUMNS section. See mps-format .

Example:

ROWS
 N  r_0
 L  r_1
 G  r_2
 G  r_3
 G  r_4
COLUMNS
    x1        r_0                 -1   r_1                  1
    x1        r_2                  2   r_3                 -1
    x2        r_0                 -2   r_1                  1
    x2        r_2                 -1   r_3                  3
    MARK0000  'MARKER'                 'INTORG'
    x3        r_0                0.1   r_4                  1
    MARK0001  'MARKER'                 'INTEND'
    x4        r_0                  3   r_4                  1
RHS
    RHS       r_1                  5   r_4                0.5
BOUNDS
 LO BND       x3                 1.1
ENDATA
The red lines are two lines that specify that variable x3 is an integer variable. It also has a lower bound of 1.1 set on it. The solution of this model is:
Value of objective function: -8.13333

Actual values of the variables:
x1                   1.66667
x2                   3.33333
x3                   2
x4                   0

As can be seen, the value of x3 is 2, an integer value. If the integer restrictions would not be set on x3 then the value would be 1.1.

In the lp-format, variables can be specified as integer by putting them in the int section. See lp-format. The above mps example would be in lp-format:

min: -x1 -2 x2 +0.1 x3 +3 x4;
r_1: +x1 +x2 <= 5;
r_2: +2 x1 -x2 >= 0;
r_3: -x1 +3 x2 >= 0;
r_4: +x3 +x4 >= 0.5;
x3 >= 1.1;

int x3;

In the lp-format, variables can be specified as binary by putting them in the bin section. See lp-format. For example:

min: -x1 -2 x2 +0.1 x3 +3 x4;
r_1: +x1 +x2 <= 5;
r_2: +2 x1 -x2 >= 0;
r_3: -x1 +3 x2 >= 0;
r_4: +x3 +x4 >= 0.5;

bin x3;
./Intro.htm000666 000000 000000 00000023214 13772705351 011206 0ustar00000000 000000 Introduction

Introduction to lp_solve 5.5.2.11

What is lp_solve and what is it not? The simple answer is, lp_solve is a Mixed Integer Linear Programming (MILP) solver.

And what is Linear Programming? See "What is Linear Programming?" and "Oh, and we also want to solve it as an integer program." for a brief description. Also see Formulation of an lp problem in lpsolve.

lp_solve is a free (see LGPL for the GNU lesser general public license) linear (integer) programming solver based on the revised simplex method and the Branch-and-bound method for the integers.
It contains full source, examples and manuals.
lp_solve solves pure linear, (mixed) integer/binary, semi-continuous and special ordered sets (SOS) models. Note the word linear. This means that equations must be of the first order. 5 * x - 3 * y is an example. However x * y is not linear and cannot be handled by lp_solve. Both the objective function and the constraints have this restriction. Also see Ratios.
Via the Branch-and-bound algorithm, it can handle integer variables (see integer variables), semi-continuous variables (see semi-continuous variables) and Special Ordered Sets (see Special Ordered Sets (SOS)).
lp_solve has no limit on model size and accepts standard both lp or mps input files, but even that can be extended. Note however that some models could give lp_solve a hard time and will even fail to solve. The larger the model the likely the chance for that. But even commercial solvers have problems with that.
It can also be called as a library from different languages like C, VB, .NET, Delphi, Excel, Java, ...
It can also be called from AMPL, MATLAB, O-Matrix, Scilab, Octave, R via a driver program. lp_solve is written in ANSI C and can be compiled on many different platforms like linux and WINDOWS.

lp_solve has its own community via the Google group https://groups.google.com/g/lp_solve. There you can find the latest sources, executables for the common platforms, examples, manuals and a message board where people can share their thoughts on lp_solve.

lp_solve was originally developed by Michel Berkelaar at Eindhoven University of Technology. The work of Jeroen Dirks made the transition from the basic version 1.5 to the full version 2.0 possible. He contributed the procedural interface, a built-in MPS reader, and many fixes and enhancements to the code. At that point there was also a Java port of lp_solve 2.0. This was not a Java native interface (JNI) to the C library, but rather a translation of the algorithm (ver 2.0) from C into Java. It was also very limited This meant that it did not keep up with lp_solve as it evolved. Starting at version 3.0, lp_solve is released under the LGPL license. Before the code could only be used for non-commercial purposes. Many other people also contributed to lp_solve, but there was no track of them. Sorry if you are not mentioned. Development was stagnated for some time at version 3.2, but now it is again alive and well via the new developers Kjell Eikland and Peter Notebaert. But also other people help to improve the product. For example the new Java interface to lp_solve was made by Juergen Ebert. It is a JNI interface that supports the full functionality of lp_solve. He did a great job. We encourage other people to participate in the development of lp_solve.
First a version 4 was introduced that had already several enhancements and improvements and now with version 5 this enhancement continues resulting is faster solving times, more stability and able to solver larger models and new functionality. See Changes from version 4 to version 5.1 for the changes done to version 5 and Changes from version 5.1 to version 5.5 for the changes done to version 5.5.

Basically, lp_solve is a library, a set of routines, called the API that can be called from almost any programming language to solve MILP problems. There are several ways to pass the data to the library:

  • Via the API
  • Via input files
  • Via an IDE

Via the API

The API is a set of routines that can be called from a programming language to build the model in memory, solve it and return the results. There are many API routines to perform many possible tasks and set several options. See lp_solve API reference for an overview.

Via input files

Standard, lp_solve supports several input files types. The common known MPS format (see mps-format) is supported by most solvers, but it is not very readable for humans. Another format is the lp format (see lp-format) that is more readable. lp_solve has the unique ability to use user-written routines to input the model (see External Language Interface). See read_mps, read_freemps, read_MPS, read_freeMPS and read_lp, read_LP for the API calls to read the model from file.

There is also a driver program called lp_solve that uses the API to provide a command line application to solve models. See lp_solve for its usage. With this program you don't have to know anything of API or computer programming languages. You can just provide your model via file to the program and it will solve the model and give you the result.

Via an IDE

Thanks to Henri Gourvest, there is now also an IDE program called LPSolve IDE that uses the API to provide a Windows application to solve models. See LPSolve IDE for its usage. With this program you don't have to know anything of API or computer programming languages. You can just provide your model to the program and it will solve the model and give you the result.

As already stated, lp_solve can be called from many programming language. Among them are C, C++, Pascal, Delphi, Java, VB, C#, VB.NET, Excel. But let this list not be a limitation. Any programming language capable of calling external libraries (DLLs under Windows, Shared libraries (.so) under Unix/Linux) can call lp_solve.

Here is a list of some key features of lp_solve:

  • Mixed Integer Linear Programming (MILP) solver
  • Basically no limit on model size
  • It is free and with sources
  • Supports Integer variables, Semi-continuous variables and Special Ordered Sets
  • Can read model from MPS, LP or user written format
  • Models can be build in-memory without the use of files
  • Has a powerful API interface
  • Easy callable from other programming languages
  • Advanced pricing using Devex and Steepest Edge for both primal and dual simplexes
  • Provides different scaling methods to make the model more numerical stable
  • Has presolve capabilities to tighten constraints/make the model smaller and faster to solve
  • Has a base crashing routine to determine a starting point
  • Allows restart after making changes to the model. Solve continues from the last found solution
  • Possible to select desired combinations of primal and dual phases 1 and 2
  • Possible to set several solver parameters like tolerances
  • Alternative (and faster) inverse/re-factorisation libraries are provided for. See Basis Factorization Packages
  • Alternative model readers and writers possible via the XLI implementation. See External Language Interfaces
  • Has the possibility to convert one model format to another format
  • Provides post-optimal sensitivity analysis. See Sensitivity
  • ...
./is_add_rowmode.htm000666 000000 000000 00000010040 10237106456 013055 0ustar00000000 000000 is_add_rowmode

is_add_rowmode

Returns a flag which of the add routines perform best.

unsigned char is_add_rowmode(lprec *lp);

Return Value

is_add_rowmode returns TRUE or FALSE. If FALSE, then add_column, add_columnex, str_add_column performs best. If TRUE, then add_constraint, add_constraintex, str_add_constraint performs best.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

Default, this is FALSE, meaning that add_column, add_columnex, str_add_column performs best. If the model is build via add_constraint, add_constraintex, str_add_constraint calls, then these routines will be much faster if this routine is called with turnon set on TRUE. This is also called row entry mode. The speed improvement is spectacular, especially for bigger models, so it is advisable to call this routine to set the mode. Normally a model is build either column by column or row by row.
Note that there are several restrictions with this mode:
Only use this function after a make_lp call. Not when the model is read from file. Also, if this function is used, first add the objective function via set_obj_fn, set_obj_fnex, str_set_obj_fn and after that add the constraints via add_constraint, add_constraintex, str_add_constraint. Don't call other API functions while in row entry mode. No other data matrix access is allowed while in row entry mode. After adding the contraints, turn row entry mode back off. Once turned of, you cannot switch back to row entry mode. So in short:
- turn row entry mode on
- set the objective function
- create the constraints
- turn row entry mode off

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char rowmode;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  rowmode = is_add_rowmode(lp); /* Will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_add_rowmode, set_add_rowmode, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, add_column, add_columnex, str_add_column, add_constraint, add_constraintex, str_add_constraint

./is_anti_degen.htm000666 000000 000000 00000010440 10237145524 012671 0ustar00000000 000000 is_anti_degen

is_anti_degen

Returns if the degeneracy rule specified in testmask is active.

unsigned char is_anti_degen(lprec *lp, int testmask);

Return Value

is_anti_degen returns TRUE or FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

testmask

ANTIDEGEN_NONE (0) No anti-degeneracy handling
ANTIDEGEN_FIXEDVARS (1) Check if there are equality slacks in the basis and try to drive them out in order to reduce chance of degeneracy in Phase 1
ANTIDEGEN_COLUMNCHECK (2)  
ANTIDEGEN_STALLING (4)  
ANTIDEGEN_NUMFAILURE (8)  
ANTIDEGEN_LOSTFEAS (16)  
ANTIDEGEN_INFEASIBLE (32)  
ANTIDEGEN_DYNAMIC (64)  
ANTIDEGEN_DURINGBB (128)  
ANTIDEGEN_RHSPERTURB (256) Perturbation of the working RHS at refactorization
ANTIDEGEN_BOUNDFLIP (512) Limit bound flips that can sometimes contribute to degeneracy in some models

Remarks

The is_anti_degen function returns a flag if the degeneracy rule specified in testmask is active.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char anti_degen;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  anti_degen = is_anti_degen(lp, ANTIDEGEN_FIXEDVARS | ANTIDEGEN_PERTURB); /* Will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_anti_degen, get_anti_degen

./is_binary.htm000666 000000 000000 00000005621 10237106456 012066 0ustar00000000 000000 is_binary

is_binary

Gets the type of the variable. Binary integer or floating point.

unsigned char is_binary(lprec *lp, int column);

Return Value

is_binary returns TRUE (1) if the variable is set as binary, FALSE (0) otherwise.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be checked. It must be between 1 and the number of columns in the lp.

Remarks

The is_binary function returns if a variable must be binary or not. Default a variable is not binary. A binary variable is an integer variable with lower bound 0 and upper bound 1. From the moment there is at least one integer variable in the model, the Branch and Bound algorithm is used to make these variables integer. Note that solving times can be considerably larger when there are integer variables. See integer variables for a description about integer variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int binary;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  binary = is_binary(lp, 1); /* will return 0 since the variable is not set as binary at this point */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_binary, is_int, set_int

./is_break_at_first.htm000666 000000 000000 00000005460 10237106456 013562 0ustar00000000 000000 is_break_at_first

is_break_at_first

Returns if the branch-and-bound algorithm stops at first found solution.

unsigned char is_break_at_first(lprec *lp);

Return Value

is_break_at_first returns if the branch-and-bound algorithm stops at first found solution.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The is_break_at_first function returns if the branch-and-bound algorithm stops at the first found solution or not. Stopping at the first found solution can be useful if you are only interested for a solution, but not necessarily (and most probably) the most optimal solution.
The default is not (FALSE) stop at first found solution.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char break_at_first;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  break_at_first = is_break_at_first(lp); /* Will return 0 (FALSE) */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_break_at_first, set_break_at_value, get_break_at_value, set_obj_bound, get_obj_bound, set_mip_gap, get_mip_gap

./is_constr_type.htm000666 000000 000000 00000005705 10237106460 013151 0ustar00000000 000000 is_constr_type

is_constr_type

Returns if constraint type specified in mask is active.

unsigned char is_constr_type(lprec *lp, int row, int mask);

Return Value

is_constr_type returns TRUE or FALSE

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the constraint type must be retrieved. Must be between 1 and number of rows in the lp.

mask

Any of the following values:
LE (1) Less than or equal (<=)
EQ (3) Equal (=)
GE (2) Greater than or equal (>=)

Remarks

The is_constr_type function returns a flag if constraint type specified in mask is active.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char constr;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  constr = is_constr_type(lp, 1, LE); /* will be TRUE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_constr_type, set_constr_type, add_constraint, add_constraintex, str_add_constraint, del_constraint

./is_debug.htm000666 000000 000000 00000004442 10237106460 011663 0ustar00000000 000000 is_debug

is_debug

Returns a flag if all intermediate results and the branch-and-bound decisions must be printed while solving.

unsigned char is_debug(lprec *lp);

Return Value

is_debug returns TRUE or FALSE. Debug or do not debug.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The is_debug function returns a flag if all intermediate results and the branch-and-bound decisions must be printed while solving. This function is mend for debugging purposes. The default is not to debug (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char dodebug;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  dodebug = is_debug(lp); /* Will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_debug

./is_feasible.htm000666 000000 000000 00000007411 10242077034 012346 0ustar00000000 000000 is_feasible

is_feasible

Checks if provided solution is a feasible solution.

unsigned char is_feasible(lprec *lp, REAL *values, REAL threshold);

Return Value

is_feasible returns FALSE (0) or TRUE (1) that indicates if provided solution is feasible.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

values

An array of row/column values that are checked against the bounds and ranges.
The array must have get_Nrows+get_Ncolumns elements. Element 0 is not used.

threshold

A tolerance value. The values may differ that much. Recommended to use get_epsint for this value.

Remarks

The is_feasible function checks if provided solution is a feasible solution. All values of the values array must be between the bounds and ranges to be a feasible solution.
This value is only valid after a successful solve or lag_solve.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL values[1+2];
  unsigned char feasible;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  values[0] = 0.0;
  values[1] = 1.0;
  values[2] = 2.0;
  feasible = is_feasible(lp, values, 0); /* Will return TRUE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_objective, get_working_objective, get_variables, get_ptr_variables, get_constraints, get_ptr_constraints, get_constr_value, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

./is_infinite.htm000666 000000 000000 00000005577 10237106460 012414 0ustar00000000 000000 is_infinite

is_infinite

Checks if the provided absolute of the value is larger or equal to "infinite".

unsigned char is_infinite(lprec *lp, REAL value);

Return Value

is_infinite returns TRUE if the value is equal or larger to "infinite".

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

value

The value to check against "infinite".

Remarks

Note that the absolute of the provided value is checked against the value set by set_infinite.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char infinite;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  infinite = is_infinite(lp, 1.0e31); /* will return TRUE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_infinite, get_infinite, set_epsint, get_epsint, set_epsb, get_epsb, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb

./is_int.htm000666 000000 000000 00000005456 10553431044 011375 0ustar00000000 000000 is_int

is_int

Gets the type of the variable. Integer or floating point.

unsigned char is_int(lprec *lp, int column);

Return Value

is_int returns TRUE (1) if the variable is set as integer, FALSE (0) otherwise.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be checked. It must be between 1 and the number of columns in the lp.

Remarks

The is_int function returns if a variable must be integer or not. Default a variable is not integer. From the moment there is at least one integer variable in the model, the Branch and Bound algorithm is used to make these variables integer. Note that solving times can be considerably larger when there are integer variables. See integer variables for a description about integer variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int integer;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  integer = is_int(lp, 1); /* will return 0 since the variable is not set as integer at this point */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_int, is_binary, set_binary

./is_integerscaling.htm000666 000000 000000 00000005031 10237106460 013566 0ustar00000000 000000 is_integerscaling

is_integerscaling

Returns if integer scaling is active.

unsigned char is_integerscaling(lprec *lp);

Return Value

is_integerscaling returns if integer scaling is active (SCALE_INTEGERS set in get_scalelimit)

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The is_integerscaling function returns if integer scaling is active (SCALE_INTEGERS set in get_scalelimit). By default integers are not scaled. set_scaling must be called to active this feature.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int integerscaling;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  integerscaling = is_integerscaling(lp); /* Will return 0 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_scaling, set_scaling, set_scalelimit, get_scalelimit

./is_lag_trace.htm000666 000000 000000 00000004365 10237106460 012522 0ustar00000000 000000 is_lag_trace

is_lag_trace

Returns a flag if Lagrangian progression must be printed while solving.

unsigned char is_lag_trace(lprec *lp);

Return Value

is_lag_trace returns TRUE or FALSE. Print or do not print.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The is_lag_trace function returns a flag if Lagrangian progression must be printed while solving. This function is mend for debugging purposes. The default is not to print (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char lag_trace;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  lag_trace = is_lag_trace(lp); /* Will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_lag_trace

./is_maxim.htm000666 000000 000000 00000004345 10237106460 011712 0ustar00000000 000000 is_maxim

is_maxim

Returns objective function direction.

unsigned char is_maxim(lprec *lp);

Return Value

is_maxim returns a boolean value indicating if the objective direction is maximize (TRUE) or minimize (FALSE).

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The default of lp_solve is to minimize, except for read_lp, read_LP where the default is to maximize.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  ret = is_maxim(lp); /* will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_maxim, set_minim, set_sense

./is_nativeBFP.htm000666 000000 000000 00000004453 10237106460 012415 0ustar00000000 000000 is_nativeBFP

is_nativeBFP

Returns if the native (build-in) basis factorization package (BFP) is used, or an external package.

unsigned char is_nativeBFP(lprec *lp);

Return Value

is_nativeBFP returns TRUE if the native (build-in) BFP is used, else FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The is_nativeBFP function checks if an external BFP is set or not. See Basis Factorization Packages for a complete description on BFPs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char nativeBFP;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  nativeBFP = is_nativeBFP(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, has_BFP, set_BFP

./is_nativeXLI.htm000666 000000 000000 00000004503 10237106460 012436 0ustar00000000 000000 is_nativeXLI

is_nativeXLI

Returns if a build-in External Language Interfaces (XLI) is available or not.

unsigned char is_nativeXLI(lprec *lp);

Return Value

is_nativeXLI returns TRUE if a build-in XLI is available, FALSE if not.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

At this moment, this routine always returns FALSE since no build-in XLI is available. See External Language Interfaces for a complete description on XLIs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char nativeXLI;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  nativeXLI = is_nativeXLI(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, write_XLI, has_XLI, set_XLI

./is_negative.htm000666 000000 000000 00000005462 11127334176 012410 0ustar00000000 000000 is_negative

is_negative

Returns if the variable is negative.

unsigned char is_negative(lprec *lp, int column);

Return Value

is_negative returns TRUE (1) if the variable is defined as negative, FALSE (0) otherwise.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be checked. It must be between 1 and the number of columns in the lp.

Remarks

The is_negative function returns if a variable is negative or not. Negative means a lower and upper bound that are both negative. Default a variable is not free because default it has a lower bound of 0 (and an upper bound of +infinity).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int negative;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  negative = is_negative(lp, 1); /* will return 0 since the variable is not set as negative at this point */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_upbo, set_upbo, set_lowbo, get_lowbo, set_bounds, is_unbounded, set_unbounded

./is_obj_in_basis.htm000666 000000 000000 00000005547 10621546252 013231 0ustar00000000 000000 is_obj_in_basis

is_obj_in_basis

Returns if the objective is in the matrix or not.

unsigned char is_obj_in_basis(lprec *lp);

Return Value

is_obj_in_basis returns if the objective is in the matrix or not.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The is_obj_in_basis function returns if the objective is in the matrix or not.
The default is that the objective is in the matrix (TRUE).

By default, the objective function is stored as the top row in the constraint matrix When this function is called with obj_in_basis = FALSE then it is moved out into separate storage. When out of the basis, the computation of reduced costs is somewhat slower. In the late versions of v5.5, there is now the option to calculate reduced cost in the textbook way, i.e. completely independently of the basis.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char obj_in_basis;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  obj_in_basis = is_obj_in_basis(lp); /* Will return 1 (TRUE) */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_obj_in_basis

./is_piv_mode.htm000666 000000 000000 00000011051 13555461610 012400 0ustar00000000 000000 is_piv_mode

is_piv_mode

Returns if pivot mode specified in testmask is active.

unsigned char is_piv_mode(lprec *lp, int testmask);

Return Value

is_piv_mode returns TRUE or FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

testmask

PRICE_PRIMALFALLBACK (4) In case of Steepest Edge, fall back to DEVEX in primal
PRICE_MULTIPLE (8) Preliminary implementation of the multiple pricing scheme.This means that attractive candidate entering columnsfrom one iteration may be used in the subsequent iteration, avoiding full updating of reduced costs. In the current implementation, lp_solve only reuses the 2nd best entering column alternative
PRICE_PARTIAL (16) Enable partial pricing
PRICE_ADAPTIVE (32) Temporarily use alternative strategy if cycling is detected
PRICE_RANDOMIZE (128) Adds a small randomization effect to the selected pricer
PRICE_AUTOPARTIAL (256) Indicates automatic detection of segmented/staged/blocked models.It refers to partial pricing rather than full pricing. With full pricing, all non-basic columns are scanned, but with partial pricing only a subset is scanned for every iteration. This can speed up several models
PRICE_AUTOMULTIPLE (512) Automatically select multiple pricing (primal simplex)
PRICE_LOOPLEFT (1024) Scan entering/leaving columns left rather than right
PRICE_LOOPALTERNATE (2048) Scan entering/leaving columns alternatingly left/right
PRICE_HARRISTWOPASS (4096) Use Harris' primal pivot logic rather than the default
PRICE_TRUENORMINIT (16384) Use true norms for Devex and Steepest Edge initializations

Remarks

The is_piv_mode function checks if the pivot mode specified in testmask is active. The pivot mode is an extra modifier to the pivot rule. Any combination (OR) of the defined values is possible.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char piv_mode;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  piv_mode = is_piv_mode(lp, PRICE_ADAPTIVE); /* Will return TRUE, because this is the default */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_pivoting, get_pivoting, is_piv_rule

./is_piv_rule.htm000666 000000 000000 00000005711 10237106460 012422 0ustar00000000 000000 is_piv_rule

is_piv_rule

Checks if the specified pivot rule is active.

unsigned char is_piv_rule(lprec *lp, int rule);

Return Value

is_piv_rule returns TRUE if the specified pivot rule is active, else FALSE

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

rule

Can be one of the following values:
PRICER_FIRSTINDEX (0) Select first
PRICER_DANTZIG (1) Select according to Dantzig
PRICER_DEVEX (2) Devex pricing from Paula Harris
PRICER_STEEPESTEDGE (3) Steepest Edge

Remarks

This rule can influence solving times considerably. Depending on the model one rule can be best and for another model another rule.
The default is PRICER_DEVEX (2).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char piv_rule;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  piv_rule = is_piv_rule(lp, PRICER_FIRSTINDEX);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_pivoting, set_pivoting, is_piv_mode

./is_presolve.htm000666 000000 000000 00000020632 11301707636 012440 0ustar00000000 000000 is_presolve

is_presolve

Returns if presolve level specified in testmask is active.

unsigned char is_presolve(lprec *lp, int testmask);

Return Value

is_presolve returns TRUE or FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

testmask

PRESOLVE_NONE (0) No presolve at all
PRESOLVE_ROWS (1) Presolve rows
PRESOLVE_COLS (2) Presolve columns
PRESOLVE_LINDEP (4) Eliminate linearly dependent rows
PRESOLVE_SOS (32) Convert constraints to SOSes (only SOS1 handled)
PRESOLVE_REDUCEMIP (64) If the phase 1 solution process finds that a constraint is redundant then this constraint is deleted. This is no longer active since it is very rare that this is effective, and also that it adds code complications and delayed presolve effects that are not captured properly.
PRESOLVE_KNAPSACK (128) Simplification of knapsack-type constraints through addition of an extra variable, which also helps bound the OF
PRESOLVE_ELIMEQ2 (256) Direct substitution of one variable in 2-element equality constraints; this requires changes to the constraint matrix. Elimeq2 simply eliminates a variable by substitution when you have 2-element equality constraints. This can sometimes cause fill-in of the constraint matrix, and also be a source of rounding errors which can lead to problems in the simplex.
PRESOLVE_IMPLIEDFREE (512) Identify implied free variables (releasing their explicit bounds)
PRESOLVE_REDUCEGCD (1024) Reduce (tighten) coefficients in integer models based on GCD argument. Reduce GCD is for mixed integer programs where it is possible to adjust the constraint coefficies due to integrality. This can cause the dual objective ("lower bound") to increase and may make it easier to prove optimality.
PRESOLVE_PROBEFIX (2048) Attempt to fix binary variables at one of their bounds
PRESOLVE_PROBEREDUCE (4096) Attempt to reduce coefficients in binary models
PRESOLVE_ROWDOMINATE (8192) Idenfify and delete qualifying constraints that are dominated by others, also fixes variables at a bound
PRESOLVE_COLDOMINATE (16384) Deletes variables (mainly binary), that are dominated by others (only one can be non-zero)
PRESOLVE_MERGEROWS (32768) Merges neighboring >= or <= constraints when the vectors are otherwise relatively identical into a single ranged constraint
PRESOLVE_IMPLIEDSLK (65536) Converts qualifying equalities to inequalities by converting a column singleton variable to slack. The routine also detects implicit duplicate slacks from inequality constraints, fixes and removes the redundant variable.This latter removal also tends to reduce the risk of degeneracy.The combined function of this option can have a dramatic simplifying effect on some models. Implied slacks is when, for example, there is a column singleton (with zero OF) in an equality constraint. In this case, the column can be deleted and the constraint converted to a LE constraint.
PRESOLVE_COLFIXDUAL (131072) Variable fixing and removal based on considering signs of the associated dual constraint. Dual fixing is when the (primal) variable can be fixed due to the implied value of the dual being infinite.
PRESOLVE_BOUNDS (262144) Does bound tightening based on full-row constraint information. This can assist in tightening the OF bound, eliminate variables and constraints. At the end of presolve, it is checked if any variables can be deemed free, thereby reducing any chance that degeneracy is introduced via this presolve option.
PRESOLVE_DUALS (524288) Calculate duals
PRESOLVE_SENSDUALS (1048576) Calculate sensitivity if there are integer variables

Remarks

The is_presolve function returns a flag if the presolve level specified in testmask is active. Presolve looks at the model and tries to simplify it so that solving times are shorter. For example a constraint on only one variable is converted to a bound on this variable (and the constraint is deleted). Note that the model dimensions can change because of this, so be careful with this. Both rows and columns can be deleted by the presolve.
The default is not (FALSE) doing a presolve.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int presolve;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  presolve = is_presolve(lp, PRESOLVE_ROWS | PRESOLVE_COLS); /* Will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_presolve, get_presolve, get_presolveloops

./is_scalemode.htm000666 000000 000000 00000014724 10246631624 012542 0ustar00000000 000000 is_scalemode

is_scalemode

Returns if scaling mode specified in testmask is active.

unsigned char is_scalemode(lprec *lp, int testmask);

Return Value

is_scalemode returns if scaling mode specified in testmask is active.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

testmask

SCALE_EXTREME (1) Scale to convergence using largest absolute value
SCALE_RANGE (2) Scale based on the simple numerical range
SCALE_MEAN (3) Numerical range-based scaling
SCALE_GEOMETRIC (4) Geometric scaling
SCALE_CURTISREID (7) Curtis-reid scaling

Additionally, the value can be OR-ed with any combination of one of the following values:

SCALE_QUADRATIC (8)  
SCALE_LOGARITHMIC (16) Scale to convergence using logarithmic mean of all values
SCALE_USERWEIGHT (31) User can specify scalars
SCALE_POWER2 (32) also do Power scaling
SCALE_EQUILIBRATE (64) Make sure that no scaled number is above 1
SCALE_INTEGERS (128) also scaling integer variables
SCALE_DYNUPDATE (256) dynamic update
SCALE_ROWSONLY (512) scale only rows
SCALE_COLSONLY (1024) scale only columns

Remarks

The is_scalemode function returns if scaling mode specified in testmask. This can influence numerical stability considerably. It is advisable to always use some sort of scaling.
set_scaling must be called before solve is called.
SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC, SCALE_CURTISREID are the possible scaling algorithms. SCALE_QUADRATIC, SCALE_LOGARITHMIC, SCALE_USERWEIGHT, SCALE_POWER2, SCALE_EQUILIBRATE, SCALE_INTEGERS are possible additional scaling parameters.
SCALE_POWER2 results in creating a scalar of power 2. May improve stability.
SCALE_INTEGERS results also in scaling Integer columns. Default they are not scaled.
SCALE_DYNUPDATE is new from version 5.1.1.0
It has always been so that scaling is done only once on the original model. If a solve is done again (most probably after changing some data in the model), the scaling factors aren't computed again. The scalars of the original model are used. This is not always good, especially if the data has changed considerably. One way to solve this was/is call unscale before a next solve. In that case, scale factors are recomputed.
From version 5.1.1.0 on, there is another way to make sure that scaling factors are recomputed and this is by settings SCALE_DYNUPDATE. In that case, the scaling factors are recomputed also when a restart is done. Note that they are then always recalculated with each solve, even when no change was made to the model, or a change that doesn't influence the scaling factors like changing the RHS (Right Hand Side) values or the bounds/ranges. This can influence performance. It is up to you to decide if scaling factors must be recomputed or not for a new solve, but by default it still isn't so. It is possible to set/unset this flag at each next solve and it is even allowed to choose a new scaling algorithm between each solve. Note that the scaling done by the SCALE_DYNUPDATE is incremental and the resulting scalarsare typically different from scalars recomputed from scratch.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int scalemode;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  scalemode = is_scalemode(lp, SCALE_MEAN);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_scaling, get_scaling, set_scalelimit, get_scalelimit, is_integerscaling, is_scaletype

./is_scaletype.htm000666 000000 000000 00000007067 10237106460 012574 0ustar00000000 000000 is_scaletype

is_scaletype

Returns if scaling type specified in scaletype is active.

unsigned char is_scaletype(lprec *lp, int scaletype);

Return Value

is_scaletype returns if scaling mode specified in scaletype is active.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

scaletype

SCALE_EXTREME (1) Scale to convergence using largest absolute value
SCALE_RANGE (2) Scale based on the simple numerical range
SCALE_MEAN (3) Numerical range-based scaling
SCALE_GEOMETRIC (4) Geometric scaling
SCALE_CURTISREID (7) Curtis-reid scaling

Remarks

The is_scaletype function returns if scaling mode specified in scaletype. This can influence numerical stability considerably. It is advisable to always use some sort of scaling.
set_scaling must be called before solve is called.
SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC, SCALE_CURTISREID are the possible scaling algorithms.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int scaletype;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  scaletype = is_scaletype(lp, SCALE_MEAN);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_scaling, get_scaling, set_scalelimit, get_scalelimit, is_integerscaling, is_scalemode

./is_semicont.htm000666 000000 000000 00000005070 10237106460 012414 0ustar00000000 000000 is_semicont

is_semicont

Gets the type of the variable. semi-continuous or not.

unsigned char is_semicont(lprec *lp, int column);

Return Value

is_semicont returns TRUE (1) if the variable is set as semi-continuous, FALSE (0) otherwise.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be checked. It must be between 1 and the number of columns in the lp.

Remarks

The is_semicont function returns if a variable must be semi-continuous or not. Default a variable is not semi-continuous. See semi-continuous variables for a description about semi-continuous variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char sc;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  sc = is_semicont(lp, 1); /* will return 0 since the variable is not set as semi-continuous at this point */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_semicont

./is_SOS_var.htm000666 000000 000000 00000005076 10237106460 012115 0ustar00000000 000000 is_SOS_var

is_SOS_var

Returns if the variable is SOS (Special Ordered Set) or not.

unsigned char is_SOS_var(lprec *lp, int column);

Return Value

is_SOS_var returns TRUE (1) if the variable is a SOS var, FALSE (0) if not.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be checked. It must be between 1 and the number of columns in the lp.

Remarks

The is_SOS_var function returns if a variable is a SOS variable or not. Default a variable is not SOS. A variable becomes a SOS variable via add_SOS. See Special Ordered Sets for a description about SOS variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int isSOS;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  isSOS = is_SOS_var(lp, 1); /* will return 0 since the variable is not an SOS var at this point */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_SOS

./is_trace.htm000666 000000 000000 00000004277 10237106460 011701 0ustar00000000 000000 is_trace

is_trace

Returns a flag if pivot selection must be printed while solving.

unsigned char is_trace(lprec *lp);

Return Value

is_trace returns TRUE or FALSE. Print or do not print.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The is_trace function returns a flag if pivot selection must be printed while solving. This function is mend for debugging purposes. The default is not to print (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  unsigned char trace;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  trace = is_trace(lp); /* Will return FALSE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_trace

./is_unbounded.htm000666 000000 000000 00000005642 11127334210 012556 0ustar00000000 000000 is_unbounded

is_unbounded

Returns if the variable is free.

unsigned char is_unbounded(lprec *lp, int column);

Return Value

is_unbounded returns TRUE (1) if the variable is defined as free, FALSE (0) otherwise.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be checked. It must be between 1 and the number of columns in the lp.

Remarks

The is_unbounded function returns if a variable is free or not. Free means a lower bound of -infinity and an upper bound of +infinity. Default a variable is not free because default it has a lower bound of 0 (and an upper bound of +infinity). See free variables for a description about free variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int free;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  free = is_unbounded(lp, 1); /* will return 0 since the variable is not set as free at this point */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_upbo, set_upbo, set_lowbo, get_lowbo, set_bounds, set_unbounded, is_negative

./is_use_names.htm000666 000000 000000 00000005560 10242071674 012562 0ustar00000000 000000 is_use_names

is_use_names

Returns if variable or constraint names are used.

unsigned char is_use_names(lprec *lp, unsigned char isrow);

Return Value

is_use_names returns a boolean value indicating if variable or constraint names are used.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

isrow

Set to FALSE (0) if column information is needed and TRUE (1) if row information is needed.

Remarks

When a model is read from file or created via the API, variables and constraints can be named. These names are used to report information or to save the model in a given format. However, sometimes it is required to ignore these names and to use the internal names of lp_solve. This is for example the case when the names do not comply to the syntax rules of the format that will be used to write the model to.
Names are used by default.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  ret = is_use_names(lp); /* will return TRUE */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_use_names, set_col_name, get_col_name, set_row_name, get_row_name

./Java/000777 000000 000000 00000000000 13751176712 010260 5ustar00000000 000000 ./Java.htm000666 000000 000000 00000004155 10762471754 011002 0ustar00000000 000000 Using lpsolve from Java

Using lpsolve from Java

Java?

Java is a programming language originally developed by Sun Microsystems and released in 1995 as a core component of Sun's Java platform. The language derives much of its syntax from C and C++ but has a simpler object model and fewer low-level facilities. Java applications are typically compiled to bytecode which can run on any Java virtual machine (JVM) regardless of computer architecture.

The original and reference implementation Java compilers, virtual machines, and class libraries were developed by Sun from 1995. As of May 2007, in compliance with the specifications of the Java Community Process, Sun made available most of their Java technologies as free software under the GNU General Public License. Others have also developed alternative implementations of these Sun technologies, such as the GNU Compiler for Java and GNU Classpath.

Java and lpsolve

Java is an object oriented programming language. The lpsolve API is not object oriented. However there is a wrapper created by Juergen Ebert that is object oriented. All lpsolve API is available via this wrapper but in an object oriented way and in the case as used by Java. For example lpsolve API call make_lp is accessed as makeLP in Java. The general rule of renamed API names is that a name begins in lower case, each underscore is removed and the letter after the underscore is in upper case.
See C - Java function reference for the translation of calls.
An introduction of using lpsolve with Java is given in the document Using lp_solve 5.5 in Java programs
The Java object model is described in the document Java api

./lag_solve.htm000666 000000 000000 00000011350 11022427566 012057 0ustar00000000 000000 lag_solve

lag_solve

Solve the model via Lagrangian relaxation.

The Lagrangian solver does not work. Do not use this call.

int lag_solve(lprec *lp, REAL start_bound, int num_iter, short verbose);

Return Value

TIMEOUT (-2) A timeout occurred. A timeout was set via set_timeout
USERABORT (-3) The abort routine returned TRUE. See put_abortfunc
OPTIMAL (0) An optimal solution was obtained
INFEASIBLE (2) The model is infeasible
FEAS_FOUND (6) An feasible solution was obtained, but num_iter was reached
NO_FEAS_FOUND (7) No feasible solution found

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

start_bound

Initial bound.

num_iter

Maximum number of iterations.

verbose

Not used. Still included for backwards compatibility. Use set_lag_trace to set the verbose level.

Remarks

The Lagrangian solver does not work. Do not use this call.

The lag_solve function solves the model via Lagrangian relaxation. Gives the ability to find an integer solution without the branch-and-bound algorithm.
At least 1 Lagrangian constraint must be added via add_lag_con, str_add_lag_con before lag_solve can be used.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;
  REAL row[1+2]; /* must be 1 more then number of columns ! */

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  row[1] = 1.0;
  row[2] = 1.0;
  add_lag_con(lp, row, LE, 1.0);

  ret = lag_solve(lp, 0, 30, FALSE);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, solve, get_statustext, is_feasible, get_objective, get_working_objective, get_variables, get_ptr_variables, get_constraints, get_ptr_constraints, get_constr_value, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex, add_lag_con, get_Lrows

./LGPL.htm000666 000000 000000 00000065162 10056304674 010654 0ustar00000000 000000 GNU LESSER GENERAL PUBLIC LICENSE

GNU LESSER GENERAL PUBLIC LICENSE

		       Version 2.1, February 1999

 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

  This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it.  You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

  When we speak of free software, we are referring to freedom of use,
not price.  Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

  To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights.  These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

  For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you.  You must make sure that they, too, receive or can get the source
code.  If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it.  And you must show them these terms so they know their rights.

  We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

  To protect each distributor, we want to make it very clear that
there is no warranty for the free library.  Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

  Finally, software patents pose a constant threat to the existence of
any free program.  We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder.  Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

  Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License.  This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License.  We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

  When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library.  The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom.  The Lesser General
Public License permits more lax criteria for linking other code with
the library.

  We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License.  It also provides other free software developers Less
of an advantage over competing non-free programs.  These disadvantages
are the reason we use the ordinary General Public License for many
libraries.  However, the Lesser license provides advantages in certain
special circumstances.

  For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard.  To achieve this, non-free programs must be
allowed to use the library.  A more frequent case is that a free
library does the same job as widely used non-free libraries.  In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

  In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software.  For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

  Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

  The precise terms and conditions for copying, distribution and
modification follow.  Pay close attention to the difference between a
"work based on the library" and a "work that uses the library".  The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

		  GNU LESSER GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

  A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

  The "Library", below, refers to any such software library or work
which has been distributed under these terms.  A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language.  (Hereinafter, translation is
included without limitation in the term "modification".)

  "Source code" for a work means the preferred form of the work for
making modifications to it.  For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

  Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it).  Whether that is true depends on what the Library does
and what the program that uses the Library does.

  1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

  You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

  2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) The modified work must itself be a software library.

    b) You must cause the files modified to carry prominent notices
    stating that you changed the files and the date of any change.

    c) You must cause the whole of the work to be licensed at no
    charge to all third parties under the terms of this License.

    d) If a facility in the modified Library refers to a function or a
    table of data to be supplied by an application program that uses
    the facility, other than as an argument passed when the facility
    is invoked, then you must make a good faith effort to ensure that,
    in the event an application does not supply such function or
    table, the facility still operates, and performs whatever part of
    its purpose remains meaningful.

    (For example, a function in a library to compute square roots has
    a purpose that is entirely well-defined independent of the
    application.  Therefore, Subsection 2d requires that any
    application-supplied function or table used by this function must
    be optional: if the application does not supply it, the square
    root function must still compute square roots.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library.  To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License.  (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.)  Do not make any other change in
these notices.

  Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

  This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

  4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

  If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

  5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library".  Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

  However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library".  The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

  When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library.  The
threshold for this to be true is not precisely defined by law.

  If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work.  (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

  Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

  6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

  You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License.  You must supply a copy of this License.  If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License.  Also, you must do one
of these things:

    a) Accompany the work with the complete corresponding
    machine-readable source code for the Library including whatever
    changes were used in the work (which must be distributed under
    Sections 1 and 2 above); and, if the work is an executable linked
    with the Library, with the complete machine-readable "work that
    uses the Library", as object code and/or source code, so that the
    user can modify the Library and then relink to produce a modified
    executable containing the modified Library.  (It is understood
    that the user who changes the contents of definitions files in the
    Library will not necessarily be able to recompile the application
    to use the modified definitions.)

    b) Use a suitable shared library mechanism for linking with the
    Library.  A suitable mechanism is one that (1) uses at run time a
    copy of the library already present on the user's computer system,
    rather than copying library functions into the executable, and (2)
    will operate properly with a modified version of the library, if
    the user installs one, as long as the modified version is
    interface-compatible with the version that the work was made with.

    c) Accompany the work with a written offer, valid for at
    least three years, to give the same user the materials
    specified in Subsection 6a, above, for a charge no more
    than the cost of performing this distribution.

    d) If distribution of the work is made by offering access to copy
    from a designated place, offer equivalent access to copy the above
    specified materials from the same place.

    e) Verify that the user has already received a copy of these
    materials or that you have already sent this user a copy.

  For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it.  However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

  It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system.  Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

  7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

    a) Accompany the combined library with a copy of the same work
    based on the Library, uncombined with any other library
    facilities.  This must be distributed under the terms of the
    Sections above.

    b) Give prominent notice with the combined library of the fact
    that part of it is a work based on the Library, and explaining
    where to find the accompanying uncombined form of the same work.

  8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License.  Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License.  However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

  9. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Library or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

  10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

  11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all.  For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded.  In such case, this License incorporates the limitation as if
written in the body of this License.

  13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number.  If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation.  If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

  14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission.  For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this.  Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

			    NO WARRANTY

  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

		     END OF TERMS AND CONDITIONS

           How to Apply These Terms to Your New Libraries

  If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change.  You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

  To apply these terms, attach the following notices to the library.  It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

    <one line to give the library's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  library `Frob' (a library for tweaking knobs) written by James Random Hacker.

  <signature of Ty Coon>, 1 April 1990
  Ty Coon, President of Vice

That's all there is to it!
./LINDO-format.htm000666 000000 000000 00000037525 10611670542 012250 0ustar00000000 000000 LINDO lp files

LINDO lp files

The LINDO LP file format provides a facility for entering a problem in a natural, algebraic LP formulation from the keyboard. The problem can be modified and saved from within lpsolve. This procedure is one way to create a file in a format that lpsolve can read. An alternative technique is to create a similar file using a standard text editor and to read it into lpsolve.

The LINDO FILE format is provided as an input alternative to the MPS file format. An LP format file may be easier to generate than an MPS file if your problem already exists in an algebraic format or if you have an application that generates the problem file more readily in algebraic format (such as a C application).

Note that the LINDO FILE format is not the same as the lpsolve LP format. See LP file format for a description about the native lpsolve lp format. To read/write this format from lpsolve, you need an XLI (see External Language Interfaces). The XLI for the LINDO format is called xli_LINDO.

Options

The XLI accepts no options at this time.

Example

lp_solve -rxli xli_LINDO input.lpt
lp_solve -mps input.mps -wxli xli_LINDO output.lpt

Syntax Rules of the LINDO FILE Format

lpsolve will accept any problem saved in an ASCII file provided that it adheres to the following syntax rules.

The MPS file format is a column-oriented format. If a row-oriented format is more convenient, then the LINDO file format is of interest. The list of rules is rather short and easy to learn.

Flow of Control

The objective function must always be at the start of the model and is initiated with any of the following keywords:

MAX MIN
MAXIMIZE MINIMIZE
MAXIMISE MINIMISE

The end of the objective function and the beginning of the constraints are signified with any of the following keywords:

SUBJECT TO
SUCH THAT
S.T.
ST

The end of the constraints is signified with the word END.

Formatting

Variable names are limited to eight characters. Names must begin with an alphabetic character (A to Z), which may then be followed by up to seven additional characters. These additional characters may include anything with the exception of the following: ! ) + - = < >. As an example, the following names are valid:

XYZMY_VARA12SHIP.LA

whereas the following are not:

THISONEISTOOLONGA-HYPHEN1INFRONT

The first example contains more than eight characters, the second contains a forbidden hyphen, and the last example does not begin with an alphabetic character.

You may, optionally, name constraints in a model. Constraint names must follow the same conventions as variable names. To name a constraint, you must start the constraint with its name terminated with a right parenthesis. After the right parenthesis, you enter the constraint as before. As an example, the following constraint is given the name XBOUND:

    XBOUND) X < 10

Only five operators are recognized: plus (+), minus (-), greater than (>), less than (<), and equals (=). When you enter the strict inequality operators greater than (>) and less than (<), they will be interpreted as the loose inequality operators greater-than-or-equal-to () and less-than-or-equal-to (), respectively. This is because many keyboards do not have the loose inequality operators. Even for systems having the loose operators, they will not be recognized. However, if you prefer, you may enter ">=" (and "<=") in place of ">" (and "<").

Parentheses as indicators of a preferred order of precedence are not accepted. All operations are ordered from left to right.

Comments may be placed anywhere in a model. A comment is denoted by an exclamation mark. Anything following an exclamation mark on the current line will be considered a comment. For example:

    MAX 10 STD + 15 DLX   ! Max profit
    SUBJECT TO
    ! Here are our factory capacity constraints
    ! for Standard and Deluxe computers
        STD < 10
        DLX < 12
    ! Here is the constraint on labor availability
        STD + 2 DLX < 16
    END

Comments are allowed, but they will not be stored with the model. Therefore, if later an equivalent model will be written, the comments will be removed.

Constraints and the objective function may be split over multiple lines or combined on single lines. You may split a line anywhere except in the middle of a variable name or a coefficient. The following would be mathematically equivalent to our example (although not quite as easy to read):

    MAX
        10
        STD  + 15 DLX  SUBJECT TO
    STD
    <
    10
    DLX < 12  STD + 2
    DLX < 16 END

However, if the objective function appeared as follows:

    MAX 10 ST
    D + 1
    5 DLX
    SUBJECT TO

then an error would be returned because the variable STD is split between lines and the coefficient 15 is also.

Only constant values--not variables--are permitted on the right-hand side of a constraint equation. Thus, an entry such as:

    X > Y

would be rejected. Such an entry could be written as:

    X - Y > 0

Conversely, only variables and their coefficients are permitted on the left-hand side of constraints. For instance, the constraint:

    3X + 4Y - 10 = 0

is not permitted because of the constant term of -10 on the left-hand side. The constraint may be recast as:

    3X + 4Y = 10

By default, all variables have lower bounds of zero and upper bounds of infinity.

Optional Modeling Statements

In addition to the three required model components of an objective function, variables, and constraints, a number of other optional modeling statements may appear in a model following the END statement. These statements and their functions appear in the table below:

Model Statement Function
FREE <Variable> Removes all bounds on <Variable>, allowing <Variable> to take on any real value, positive or negative.
GIN <Variable> Makes <Variable> a general integer (i.e., restricts it to the set of nonnegative integers).
INT <Variable> Makes <Variable> binary (i.e., restricts it to be either 0 or 1).
SLB <Variable> <Value> Places a simple lower bound on <Variable> of <Value>.Use in place of constraints of form X = r.
SUB <Variable> <Value> Places a simple upper bound on <Variable> of <Value>.Use in place of constraints of form X = r.
TITLE <Title> Makes <Title> the title of the model.

Next, we will briefly illustrate the use of each of these statements.

FREE Statement

The default lower bound for a variable is 0. In other words, unless you specify otherwise, variables are not allowed to be negative. The FREE statement allows you to remove all bounds on a variable, so it may take on any real value, positive or negative.

The following small example illustrates the use of the FREE statement:

    MIN 5X + Y
    ST
        X+Y>5
        X-Y>7
    END
    FREE Y

Had we not set Y to be a free variable in this example, the optimal solution of X = 6 and Y = -1 would not have been found. Instead, given the default lower bound of 0 on Y, the solution X = 7 and Y = 0 would be returned.

GIN Statement

By default, all variables are assumed to be continuous. In other words, unless told otherwise, variables are assumed to be any nonnegative fractional number. In many applications, fractional values may be of little use (e.g., 2.5 employees). In these instances, you will want to make use of the general integer statement, GIN. The GIN statement followed by a variable name restricts the value of the variable to the nonnegative integers (0,1,2,...).

The following small example illustrates the use of the GIN statement:

    MAX 11X + 10Y
    ST
        2X + Y < 12
        X - 3Y > 1
    END
    GIN X
    GIN Y

Had we not specified X and Y to be general integers in this model, the optimal solution of X = 6 and Y = 0 would not have been found. Instead, X and Y would have been treated as continuous and returned the solution of X = 5.29 and Y = 1.43.

Note also that simply rounding the continuous solution to the nearest integer values does not yield the optimal solution in this example. In general, rounded continuous solutions may be nonoptimal and, at worst, infeasible. Based on this, one can imagine that it can be very time consuming to obtain the optimal solution to a model with many integer variables. In general, this is true, and you are best off utilizing the GIN feature only when absolutely necessary.

INT Statement

Using the INT statement restricts a variable to being either 0 or 1. These variables are often referred to as binary variables. In many applications, binary variables can be very useful in modeling all-or-nothing situations. Examples might include such things as taking on a fixed cost, building a new plant, or buying a minimum level of some resource to receive a quantity discount.

The following small example illustrates the use of the INT statement:

    MAX -100X + 20A + 12B
    ST
        A - 10X < 0
        A + B < 11
        B < 7
    END
    INT X     !Make X 0/1

Had we not specified X to be binary in this example, a solution of X = .4, A = 4, and B = 7 for an objective value of 124 would not have been returned. Forcing X to be binary, you might guess that the optimal solution would be for X to be 0 because .4 is closer to 0 than it is to 1. If we round X to 0 and optimize for A and B, we get an objective of 84. In reality, a considerably better solution is obtained at X = 1, A = 10, and B = 1 for an objective of 112.

In general, rounded continuous solutions may be nonoptimal and, at worst, infeasible. Based on this, one can imagine that it can be very time consuming to obtain the optimal solution to a model with many binary variables. In general, this is true and you are best off utilizing the INT feature only when absolutely necessary.

SUB and SLB Statements

If you do not specify otherwise, LINDO API assumes variables are continuous (bounded below by zero and unbounded from above). That is, variables can be any positive fractional number increasing indefinitely. In many applications, this assumption may not be realistic. Suppose your facilities limit the quantity produced of an item. In this case, the variable that represents the quantity produced is bounded from above. Or, suppose you want to allow for backordering in a system. An easy way to model this is to allow an inventory variable to go negative. In which case, you would like to circumvent the default lower bound of zero. The SUB and SLB statements are used to alter the bounds on a variable. SLB stands for Simple Lower Bound and is used to set lower bounds. Similarly, SUB stands for Simple Upper Bound and is used to set upper bounds.

The following small example illustrates the use of the SUB and SLB:

    MAX 20X + 30Y
    ST
        X + 2Y < 120
    END
    SLB X 20
    SUB X 50
    SLB Y 40
    SUB Y 70

In this example, we could have just as easily used constraints to represent the bounds. Specifically, we could have entered our small model as follows:

    MAX 20X + 30X
    ST
        X + 2Y < 120
        X > 20
        X < 50
        Y > 40
        Y < 70
    END

This formulation would yield the same results, but there are two points to keep in mind. First, SUBs and SLBs are handled implicitly by the solver, and, therefore, are more efficient from a performance point of view than constraints. Secondly, SUBs and SLBs do not count against the constraint limit, allowing you to solve larger models within that limit.

TITLE Statement

This statement is used to associate a title with a model. The title may be any alphanumeric string of up to 74 characters in length. Unlike all the other statements that must appear after the END statement, the TITLE statement may appear before the objective or after the END statement of a model.

Here is an example of a small model with a title:

    TITLE Your Title Here
    MAX 20X + 30Y
    ST
        X < 50
        Y < 60
        X + 2Y < 120
    END
./links.htm000666 000000 000000 00000014354 13751324317 011234 0ustar00000000 000000 Usefull links

Usefull links

A Tour of Linear Programming Entries in the Mathematical Programming Glossary
AMPL
Advanced linear programming
Alternate Optimal Solutions, Degeneracy, Unboudedness, Infeasibility
BAS File Format
Benchmarks for Optimization Software
Communication Networks
Cycling and Resolution
Cycling in the Simplex Method: Example from Chvatal's Text.
Decision Tree for Optimization Software
Practical Optimization: A Gentle Introduction
Linear Solver for OpenOffice.org
Linear Programming
Linear Programming
Linear Programming Frequently Asked Questions
MATLAB
Matlab Clones
MIPLIB 3.0
MPS Format
What is MPS format?
MP-TESTDATA - The NETLIB Problems for MADLIB
Michels site where you can also find older versions
NETLIB LP Test Problems
O-Matrix
Practical Integer Programming
Practical Optimization: A Gentle Introduction
Scilab
The Mechanics of the Simplex Method
The MPS file format
The NETLIB LP Test Problem Set
The Simplex Method
The Simplex Method: Solving Standard Maximization Problems
Tutorials, Books and a Dictionary
NEOS server for optimization
Lp_solve link to Excel
lpsolve reference guide
lp_solve Google group
Linear programming - Wikipedia
Web page simplex tool
Integer Programming
Logical Constraints in Integer Programs
./list.gif000666 000000 000000 00000000261 10031030130 011003 0ustar00000000 000000 GIF89a{{{{{! ,^0I$8kK@ U|' 䅢Hi扳dPA.a" b)jXDSAB DDަBv^^. ;./lp-format.htm000666 000000 000000 00000025134 10723016334 012004 0ustar00000000 000000 LP file format

LP file format

The lp-format is lpsolves native format to read and write lp models.
Note that this format is not the same as the CPLEX LP format (see CPLEX lp files)
or the Xpress LP format (see Xpress lp files)
The lp-format input syntax is a set of algebraic expressions and "free", "int", "bin", "sec", "sos"
declarations in the following order:

<objective function>
<constraint>*
<declaration>*

where:

- <objective function> is a linear combination of optional variables and
  constants, ending with a semicolon, optionally preceded by "max: " or "min: "
  to indicate whether you want it to be minimized or maximized. The case
  is not important, "Max:" or "MAX:" will work as well. Maximization
  is the default. Alternatives are minimise, minimize, maximise, Maximize.
  The objective function is required, but can be empty.

- <constraint> is an optional constraint name followed by a colon plus
  a linear combination of variables and constants or (just one)
  constraint name followed by a colon (a range) or (just one) variable
  name without a colon (a bound), followed by a relational operator,
  followed again by a linear combination of variables and constants,
  ending with a semicolon. The relational operator can be any of the
  following: "<" "<=" "=" ">" ">=". There is no semantic difference
  between "<" and "<=" nor between ">" and ">=" (even for integer
  variables!).

- <declaration> is of one of the forms:
  To define variables as integer:
   "int"
   var [","] var [","] var ... ";"

  To define variables as binary:
   "bin"|"binary"
   var [","] var [","] var ... ";"

  To define variables as semi-cont:
   "sec"
   var [","] var [","] var ... ";"

  To define variables as free:
   "free"
   var [","] var [","] var ... ";"

  To define Special Ordered Sets (SOS):
   "sos"
   [sosdescr:] [","] var[:weight] [","] var[:weight] [","] var[:weight] ... "<[=]" sostype[:sosorder] ";" ...
  or:
   "sosx"
   [sosdescr:] var[:weight] [","] var[:weight] [","] var[:weight] ... ";" ...

- A var must start with a letter (either upper or lower case), and may
  contain any number of additional letters, numerals, or characters
  from this list: _[]{}/.&#$%~'@^

- Comments can be used with the /* */ syntax, just like in C.
  It can be put anywhere in the file and even over multiple lines.
  lp_solve 4.0.1.11 and newer also supports the C++ line comment //.

- Empty lines are also allowed.

EXAMPLES
      The simple problem:

      x1 >= 1
      x2 >= 1
      x1 + x2 >= 2
      minimize x1 + x2 (= maximize -(x1 + x2)), with x1 integer

      Can be written as follows in lp-format:

      -x1 -x2;
      /* or min: x1 + x2; */
      x1 >= 1;
      x2 >= 1;
      x1 + x2 >= 2;
      int x1;

The correct result for (x1, x2) is of course (1, 1).

If you want to give a name to a restriction then begin the line with the name and a colon.

For example:

      min: x1 + x2;
      x1 >= 1;
      x2 >= 1;
      myrow: x1 + x2 >= 2;
      int x1;

The objective function may also be empty, but it must be there:

      min: ;
      x1 >= 1;
      x2 >= 1;
      myrow: x1 + x2 >= 2;
      int x1;

Also constants may be put in the objective function:

      min: x1 + x2 + 3;
      x1 >= 1;
      x2 >= 1;
      myrow: x1 + x2 >= 2;
      int x1;

Or even the following is ok. The constants will be added to one constant value:

      min: 2 + x1 + 3 + x2 + 4;
      x1 >= 1;
      x2 >= 1;
      myrow: x1 + x2 >= 2;
      int x1;

This will lead to the same solution as without the constant(s),
but the objective value will be increased with this value.


Note that for bounds on variables, you should not put labels before them.
This is because lp_solve then makes this an extra restriction.
If you don't put a label before single variables then lp_solve doesn't have to create
an extra row for bounds on variables, resulting in better performance.

So it is better to write:

      x1 >= 1;

than

      r_x1: x1 >= 1;

Note that this is only for single variables, so

	  myrow: x1 + x2 >= 2;

performs as well as

	  x1 + x2 >= 2;

In addition, the variable can have a constant, without performance penalty.
For example:

      2 x1 >= 2;

is automatically translated to

      x1 >= 1;

by lp_solve, so this is not a restriction, but a (better performing) bound.
The moment there is more than one variable in a constraint, lp_solve can only
create a restriction (extra row) for this.


Sometimes there is a lower and upper bound on a variable. This can be written in several ways:

      x1 >= 1;
      x1 <= 3;

It doesn't matter if the lower bound comes first or not. They are also not required to be together.

Another way to write this is:

      1 <= x1 <= 3;

Or

      3 >= x1 >= 1;

These bounds on variables are handled by lp_solve in a special way so that no extra restrictions
(rows) are created, which will lead to better performance.


Also on restrictions there can be both a lower and upper value. They are called ranges.
For example:

      myrow: x1 + x2 >= 2;

Suppose that the same restriction should also be <= 6, then this could be written as:

      myrowmin: x1 + x2 >= 2;
      myrowmax: x1 + x2 <= 6;

However, then there are two rows in the model which makes it larger and harder to solve.
lp_solve can handle this in one row so that the model is smaller and it will solve more quickly.
This will only be done if the modeling is done in one of the following ways:

      myrow: x1 + x2 >= 2;
      myrow: <= 6;

Or

      myrow: x1 + x2 <= 6;
      myrow: >= 2;

Or

      myrow: 6 >= x1 + x2 >= 2;

Or

      myrow: 2 <= x1 + x2 <= 6;

Or

      6 >= x1 + x2 >= 2;

Or

      2 <= x1 + x2 <= 6;


Note that there must be a row label if the construction
label: op constant
is used. This requirement does not count if the min and max restriction is put on one line.
Also the range must come after the constraint definition.


Example with integer variables:

	min: -x1 -2 x2 +0.1 x3 +3 x4;
	r_1: +x1 +x2 <= 5;
	r_2: +2 x1 -x2 >= 0;
	r_3: -x1 +3 x2 >= 0;
	r_4: +x3 +x4 >= 0.5;
	x3 >= 1.1;

	int x3, x4;

See integer variables for a description about integer variables.

Example with binary variables:

	min: -x1 -2 x2 +0.1 x3 +3 x4;
	r_1: +x1 +x2 <= 5;
	r_2: +2 x1 -x2 >= 0;
	r_3: -x1 +3 x2 >= 0;
	r_4: +x3 +x4 >= 0.5;

	bin x3, x4;

See integer variables for a description about integer and binary variables.

Example with semi-continuous variables:

	max: x1 + 2x2 - 4x3 -3x4;
	x1 + x2 <= 5;
	2x1 - x2 >= 0;
	-x1 + 3x2 >= 0;
	x3 + x4 >= .5;
	x3 >= 1.1;
	x3 <= 10;

	sec x3, x4;

See semi-continuous variables for a description about semi-continuous variables.


Example with free variables:

        max: x1 + 2x2 - 4x3 -3x4;
        x1 + x2 <= 5;
        2x1 - x2 >= 0;
        -x1 + 3x2 >= 0;
        x3 + x4 >= .5;
        x3 >= 1.1;
        x3 <= 10;

        free x2, x4;

See free variables for a description about free variables.


Examples with Special Ordered Sets (SOS):

	min: -x1 -x2 -3 x3 -2 x4 -2 x5;
	c1: -x1 -x2 +x3 +x4 <= 30;
	c2: +x1 +x3 -3 x4 <= 30;
	x1 <= 40;
	x2 <= 1;
	x5 <= 1;

	sos
	SOS1: x1, x2, x3, x4 <= 2;
	SOS2: x2, x3, x4, x5 <= 3;


Alternative:

	min: -x1 -x2 -3 x3 -2 x4 -2 x5;
	c1: -x1 -x2 +x3 +x4 <= 30;
	c2: +x1 +x3 -3 x4 <= 30;
	x1 <= 40;
	x2 <= 1;
	x5 <= 1;

	sos2
	SOS1: x1, x2, x3, x4;
	SOS2: x2, x3, x4, x5;


With SOS weights:

  	min: -x1 -x2 -3 x3 -2 x4 -2 x5;
	c1: -x1 -x2 +x3 +x4 <= 30;
	c2: +x1 +x3 -3 x4 <= 30;
	x1 <= 40;
	x2 <= 1;
	x5 <= 1;

	sos
	SOS1: x1:5, x2:9, x3:12, x4:17 <= 2:3;
	SOS2: x2:9, x3:12, x4:17, x5:21 <= 2:3;

See Special Ordered Sets (SOS) for a description about Special Ordered Sets.


Peculiarities of the lp format:

Note that some strange effects can occur.
Exponents:
Consider the following lp: min: d1 + e1; -0.5 d1 + e1 <= 3; d1 + e1 >= 6; 3 d1 - 2 e1 <= 16; This works as expected. d1 and e1 are always seen as variables. Now consider this: min: d1 + e1; -0.5 d1 + e1 <= 3; d1 + e1 >= 6; 3d1 - 2e1 <= 16; You would expect that this is exactly the same model as before. And for variable d1, this is also the case. However, e1 in the last constraint is a problem. Here lp_solve doesn't recognise 2e1 as two times variable e1, but as the constant value 2.0e1 (20). It sees the e1 as an exponent! There is no problem when there is at least one space between 2 and e1. In that case lp_solve knows that it is two times variables e1 because there may not be any spaces in numbers.
Operators
Consider the following constraint: +3 x + 2 y <= 16; The + sign is optional. So above equation can also be written as: 3 x + 2 y <= 16; But also as: 3 x 2 y <= 16; This may look somewhat strange and can even lead to confusion. Consider the equation without the factor 2: 3 x y <= 16; This is still considered as: 3 x + y <= 16; And not as 3 x * y <= 16; as could be thought... Also, lp_solve allows adjacent operators. Consider the following constraint: +3 x - 2 y <= 16; This may also be written as: +3 x + -2 y <= 16; or +3 x +- 2 y <= 16; or +3 x - +2 y <= 16; And the constraint +3 x + 2 y <= 16; may also be written as: +3 x + +2 y <= 16; or +3 x + + 2 y <= 16; and even: +3 x - -2 y <= 16; Note that the lp-format does not allow parentheses () to make things clearer ... So the following is not allowed: +3 x - (-2) y <= 16; In fact, there is no limit on the number of operators that are placed next to each other, separated with as many or as few spaces as desired... For example - -- -- is seen as -, while ---- -- is seen as +.
./LPBasics.htm000666 000000 000000 00000021355 11050261154 011540 0ustar00000000 000000 Linear programming basics

Linear programming basics

A short explanation is given what Linear programming is and some basic knowledge you need to know.

A linear programming problem is mathematically formulated as follows:

  • A linear function to be maximized or minimized
e.g.
maximize c1 x1 + c2 x2
  • Problem constraints of the following form
e.g.
a11 x1 + a12 x2 <= b1
a21 x1 + a22 x2 <= b2
a31 x1 + a32 x2 <= b3
  • Default lower bounds of zero on all variables.

The problem is usually expressed in matrix form, and then becomes:

     maximize     CT x
     subject to   A x <= B
                  x >= 0

So a linear programming model consists of one objective which is a linear equation that must be maximized or minimized. Then there are a number of linear inequalities or constraints.

cT, A and B are constant matrixes. x are the variables (unknowns). All of them are real, continue values.

Note the default lower bounds of zero on all variables x. People tend to forget this build-in default. If no negative (or negative infinite) lower bound is explicitely set on variables, they can and will take only positive (zero included) values.

The inequalities can be <=, >= or =
Because all numbers are real values, <= is the same as < and >= is the same as >

Also note that both objective function and constraints must be linear equations. This means that no variables can be multiplied with each other.

This formulation is called the Standard form. It is the usual and most intuitive form of describing a linear programming problem.

Example:

     minimize     3 x1 - x2
     subject to    -x1 + 6 x2 - x3   + x4 >= -3
                         7 x2      + 2 x4  =  5
                    x1 +   x2 + x3         =  1
                                x3 +   x4 <=  2

Sometimes, these problems are formulated in the canonical form. All inequalities are converted to equalities by adding an extra variable where needed:

     maximize     CT x
     subject to   A x = B
                  x >= 0

Above example can then be written as:

     minimize     3 x1 - x2
     subject to    -x1 + 6 x2 - x3   + x4 - s = -3
                         7 x2      + 2 x4     =  5
                    x1 +   x2 + x3            =  1
                                x3 +   x4 + t =  2

So everywhere an equality was specified, an extra variable is introduced and subtracted (if it was >) or added (if it was <) to the constraint. These variables also only take positive (or zero) values only. These extra variables are called slack or surplus variables.

lp_solve add's these variables automatically to its internal structure. The formulator doesn't have to do it and it is even better not to. There will be fewer variables in the model and thus quicker to solve.

See Formulation of an lp problem in lpsolve for a practical example.

The right hand side (RHS), the B-vector, must be a constant matrix. Some people see this as a problem, but it isn't The RHS can always be brought to the left by a simple operation:

     A x <= B
Is equal to:
     A x - B <= 0
So if B is not constant, just do that.

Basic mathematics also states that if a constraint is multiplied by a negative constant, that the inequality changes from direction. For example:

     5 x1 - 2 x2 >= 3
If multiplied by -1, it becomes:
    -5 x1 + 2 x2 <= -3

If the objective is multiplied by -1, then maximization becomes minimization and the other way around. For example:

    minimize     3 x1 - x2
Can also be written as:
    maximize     -3 x1 + x2

The result will be the same, but changed from sign.

Bounds

Minima and maxima on single variables are special cases of restrictions. They are called bounds. The optimization algorithm can handle these bounds more effeciently than other restrictions. They consume less memory and the algorithm is faster with them. As already specified, there is by default an implicit lower bound of zero on each variable. Only when explicitly another lower bound is set, the default of 0 is overruled. This other bound can be negative also. There is no default upper bound on variables. Almost all solvers support bounds on variables. So does lp_solve.

Ranges

Frequently, it happens that on the same equation a less than and a greater than restriction must be set. Instead of adding two extra restrictions to the model, it is more performant and less memory consument to only add one restiction with either the less than or greater than restriction and put the other inequality on that same constraint by means of a range. Not all solvers support this feature but lp_solve does.

Integer and binary variables

By default, all variables are real. Sometimes it is required that one or more variables must be integer. It is not possible to just solve the model as is and then round to the nearest solution. At best, this result will maybe furfill all constraints, but you cannot be sure of. As you cannot be sure of the fact that this is the most optimal solution. Problems with integer variables are called integer or descrete programming problems. If all variables are integer it is called a pure integer programming problem, else it is a mixed integer programming problem. A special case of integer variables are binary variables. These are variables that can only take 0 or 1 as value. They are used quite frequently to program discontinue conditions. lp_solve can handle integer and binary variables. Binary variables are defined as integer variables with a maximum (upper bound) of 1 on them. See integer variables for a description on them.

Semi-continuous variables

Semi-continuous variables are variables that must take a value between their minimum and maximum or zero. So these variables are treated the same as regular variables, except that a value of zero is also accepted, even if there is a minimum bigger than zero is set on the variable. See semi-continuous variables for a description on them.

Special ordered sets (SOS)

A specially ordered set of degree N is a collection of variables where at most N variables may be non-zero. The non-zero variables must be contiguous (neighbours) sorted by the ascending value of their respective unique weights. In lp_solve, specially ordered sets may be of any cardinal type 1, 2, and higher, and may be overlapping. The number of variables in the set must be equal to, or exceed the cardinal SOS order. See Special ordered sets (SOS) for a description on them.

lp_solve uses the simplex algorithm to solve these problems. To solve the integer restrictions, the branch and bound (B&B) method is used.

Other resources

Another very usefull and free paper about linear programming fundamentals and advanced features plus several problems being discussed and modeled is Applications of optimization with Xpress-MP. It describes linear programming and modeling with the commercial solver Xpress-MP, but is as usefull for other solvers like lp_solve. In case that this link would not work anymore, try this via google search.

./LPFML.htm000666 000000 000000 00000021346 11430456326 010763 0ustar00000000 000000 LPFML

LPFML

LPFML is a modeling format in XML structure. It started as its own project but is now part of the bigger COIN-OR OSlL project

See https://www.coin-or.org/OS/OSlL.html for the home page of this tool and examples.

lp_solve can read/write and solve these LPFML models directly via the xli_LPFML XLI driver (see External Language Interfaces).

Reading LPFML models

It reads such a model in above format and can solve it then.

For example:
lp_solve -rxli xli_LPFML parinc.xml

This gives as result:

Value of objective function: 7667.94172245

Actual values of the variables:
x1                        539.984
x2                        252.011
Options

none

Generating LPFML models

The XLI can also create a LPFML model.

For example:

lp_solve model.lp -wxli xli_LPFML model.xml

This gives as model.xml:

<?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>4</numberRows>
    <numberVars>2</numberVars>
  </linearProgramDescription>

  <linearProgramData>
    <rows>
      <row rowName="cutanddye" rowUB="630"/>
      <row rowName="sewing" rowUB="600"/>
      <row rowName="finishing" rowUB="708"/>
      <row rowName="inspectandpack" rowUB="135"/>
    </rows>
    <columns>
      <col colName="x1" colType="C" objVal="10"/>
      <col colName="x2" colType="C" objVal="9"/>
    </columns>
    <amatrix>
      <sparseMatrix>
        <pntANonz>
          <el>4</el>
          <el>8</el>
        </pntANonz>
        <rowIdx>
          <el>0</el>
          <el>1</el>
          <el>2</el>
          <el>3</el>
          <el>0</el>
          <el>1</el>
          <el>2</el>
          <el>3</el>
        </rowIdx>
        <nonz>
          <el>0.7</el>
          <el>0.5</el>
          <el>1</el>
          <el>0.1</el>
          <el>1</el>
          <el>0.8333</el>
          <el>0.6667</el>
          <el>0.25</el>
        </nonz>
      </sparseMatrix>
    </amatrix>
  </linearProgramData>

</mathProgram>
Options

The XLI accepts several options:

  -b64
  -comp          Compress.
  -can           Canonical.

API

Use the lpsolve API call read_XLI to read a model and write_XLI to write a model. See also External Language Interfaces.

IDE

Also from within the IDE, this XLI can be used. However, some entries must be added in LpSolveIDE.ini (in the folder where the IDE is installed).

In the [XLI] section the following must be added:

lib4=xli_LPFML

And a new section for the LPFML XLI must also be added:

[xli_LPFML]
extension=.xml
language=XML

Then make sure that the xli_LPFML.dll is available for the IDE. This must be done by placing this dll in the IDE folder or in the Windows system32 folder. There are also 2 extra dlls needed: Xalan-C_1_6_0.dll and xerces-c_2_3_0.dll. It is advised to put these in the system32 folder

Example models

parinc.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Sample XML file generated by XMLSPY v5 U (http://www.xmlspy.com)-->
<!-- $Id: parinc.xml,v 1.8 2003/08/08 19:50:04 kipp Exp $ -->
<mathProgram xmlns="http://FML/lpfml.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://FML/lpfml.xsd
http://gsbkip.uchicago.edu/fml/testproblems/lpfml.xsd">

	<linearProgramDescription>
		<source>Par Inc. Problem from Anderson, Sweeny, and Williams</source>
	<maxOrMin>max</maxOrMin>
		<objConstant>0.</objConstant>
		<numberRows>4</numberRows>
		<numberVars>2</numberVars>
	</linearProgramDescription>
	<linearProgramData>
		<rows>
			<row rowName="cutanddye"  rowUB="630" />
			<row rowName="sewing" rowUB="600"/>
			<row rowName="finishing" rowUB="708"/>
			<row rowName="inspectandpack" rowUB="135" />
		</rows>
		<columns>
			<col objVal="10.0" colName="x1" colType="C" colLB="0.0" />
			<col objVal="9" colName="x2" colType="C" colLB="0.0" />
		</columns>
		<amatrix>
			<sparseMatrix>
				<pntANonz>
					<el>4</el>
					<el>8</el>
				</pntANonz>
				<rowIdx>
					<el>0</el>
					<el>1</el>
					<el>2</el>
					<el>3</el>
					<el>0</el>
					<el>1</el>
					<el>2</el>
					<el>3</el>
				</rowIdx>
				<nonz>
					<el>.7</el>
					<el>.5</el>
					<el>1.0</el>
					<el>0.1</el>
					<el>1.0</el>
					<el>0.8333</el>
					<el>0.6667</el>
					<el>0.25</el>
				</nonz>
			</sparseMatrix>
		</amatrix>
	</linearProgramData>
	<linearProgramSolution>
		<primalSolution>
			<sol idx="1" name="x1" val="540"/>
			<sol idx="2" name="x2" val="252"/>
		</primalSolution>
		<dualSolution>
			<sol idx="1" name="cutanddye" val="4.37457"/>
			<sol idx="3" name="finishing" val="6.9378"/>
		</dualSolution>
		<optimalValue>7667.94</optimalValue>
		<status statusId="optimalSolutionFound">Put in here any other status message desired</status>
		<solverMessage>This was solved using LINDO from LINDO Systems, Inc.</solverMessage>
	</linearProgramSolution>
</mathProgram>
model.lp
/* Objective function */
max: +10 x1 +9 x2;

/* Constraints */
cutanddye: +0.7 x1 +x2 <= 630;
sewing: +0.5 x1 +0.8333 x2 <= 600;
finishing: +x1 +0.6667 x2 <= 708;
inspectandpack: +0.1 x1 +0.25 x2 <= 135;
./lp_solve.htm000666 000000 000000 00000056403 13772705351 011744 0ustar00000000 000000 lp_solve command

lp_solve command

The lp_solve program is a command line application that can use as good as all functionality of the library.

Installation

There is no installation procedure for this application. There is no need for it. You only need one file: lp_solve.exe under Windows or lp_solve under Unix/Linux. It can be found in the archive lp_solve_5.5.2.11_exe.zip (Windows) or lp_solve_5.5.2.11_exe.tar.gz (Unix/Linux). Just extract the file and you can use it. Note for Windows users, that you can not just run the lp_solve program by double clicking on it from Windows Explorer. The program needs arguments and this is best done from the command line (cmd.exe / command.com) or via batch files. lp_solve has many options as shown further.

Usage

This program reads the MIP model from standard input or from a file and outputs the result back to the console or to a file. There are several possible input formats: The 'lp' format (See lp-format), and the 'mps' format (See mps-format) are build in, but other formats are also supported via the XLI functionality (See external language interface). For example a MathProg interface is developed via the XLI functionality (See external language interface for an example). These input formats have nothing to do with the API. So lp1 = make_lp(0,4) is a totally wrong input for the lp_solve program. The lp format is the default. Optionaly you can use the -lp option for it. To enable the mps format, use the -mps option. To enable the XLI, use the -rxli option. If lp_solve is started without an input file, then it gives a blinking cursor and waits for input. It is then possible to enter the model in the specified format (lp by default). But this is not very handy. You must enter the whole model each time you want to solve it and must be careful that you don't type any errors. To stop input mode, press Ctrl Z.
However it is much better to write your model in a disk file with your favourite editor (make sure it is in text format) and then provide this file to lp_solve. For example:

lp_solve input.lp

It is also possible to use input redirection:

lp_solve <input.lp

Or more sophisticated constructs like:

gen_model | lp_solve

gen_model is here a user written program that outputs the model to standard output and via the pipe character (|) this output is redirected to lp_solve. So no intermediate file is needed in this case.

Examples:

lp_solve input.lp

lp_solve -s input.lp

lp_solve -s input.lp >output.txt

lp_solve -s -mps input.mps >output.txt

lp_solve -s -S4 -mps input.mps >output.txt

lp_solve -s -S4 -mps input.mps -wpar par.ini -wparopt "-HMyPar" >output.txt

A list of all options is given by entering the following command:

lp_solve -h

This gives:

Usage of lp_solve version 5.5.2.11:
lp_solve [options] [[<]input_file]
List of options:
-h              prints this message
-lp             read from LP file (default) See read_LP, See lp-format
-mps            read from MPS file, default in fixed format See read_MPS, See mps-format
-mps_free		use free format See read_MPS, See mps-format
-mps_ibm		interprete integers accoring to ibm format See read_MPS, See mps-format
-mps_negobjconst	negate objective constant See read_MPS, See mps-format
-fmps           read from MPS file in free format See read_freeMPS, See mps-format
-rpar filename  read parameters from filename. See read_params
-rparopt options
                options for parameter file:
                 -H headername: header name for parameters. By default 'Default'
-rxli xliname filename
                read file with xli library See external language interface
-rxlidata datafilename
                data file name for xli library. See external language interface
-rxliopt options
                options for xli library. See external language interface
-rbas filename  read basis from filename. See read_basis, See mps bas file format
-gbas filename	guess basis with variables from filename. See guess_basis
-plp		print model. See print_lp
-wlp filename   write to LP file See write_lp, See lp-format
-wmps filename  write to MPS file in fixed format See write_mps, See mps-format
-wfmps filename write to MPS file in free format See write_freemps, See mps-format
-wxli xliname filename
                write file with xli library See external language interface
-wxliopt options
                options for xli library. See external language interface
-wxlisol xliname filename
                write solution file with xli library See external language interface
-wxlisolopt options
                options for xli library. See external language interface
-wbas filename  write basis to filename. See write_basis, See mps bas file format
-wpar filename  write parameters to filename. See write_params
-wparopt options
                options for parameter file:
                 -H headername: header name for parameters. By default 'Default'
-wafter         Write model after solve (useful if presolve used).
-parse_only     parse input file but do not solve
-nonames        Ignore variables and constraint names See set_use_names
-norownames     Ignore constraint names See set_use_names
-nocolnames     Ignore variable names See set_use_names

-min            Minimize the lp problem (overrules setting in file) See set_minim
-max            Maximize the lp problem (overrules setting in file) See set_maxim
-r <value>      specify max nbr of pivots between a re-inversion of the matrix See set_maxpivot
-piv <rule>     specify simplex pivot rule See set_pivoting
         -piv0: Select first
         -piv1: Select according to Dantzig
         -piv2: Select Devex pricing from Paula Harris (default)
         -piv3: Select steepest edge
These pivot rules can be combined with any of the following:
-pivf           In case of Steepest Edge, fall back to DEVEX in primal. See set_pivoting
-pivm           Multiple pricing. See set_pivoting
-piva           Temporarily use First Index if cycling is detected.  See set_pivoting
-pivr           Adds a small randomization effect to the selected pricer. See set_pivoting
-pivll          Scan entering/leaving columns left rather than right. See set_pivoting
-pivla          Scan entering/leaving columns alternatingly left/right. See set_pivoting
-pivh           Use Harris' primal pivot logic rather than the default. See set_pivoting
-pivt           Use true norms for Devex and Steepest Edge initializations. See set_pivoting
-o0             Don't put objective in basis. See set_obj_in_basis
-o1             Put objective in basis (default). See set_obj_in_basis
-s <mode> <scaleloop>   use automatic problem scaling. See set_scaling
         -s0: No scaling
         -s1: Geometric scaling (default)
         -s2: Curtis-reid scaling
         -s3: Scale to convergence using largest absolute value
          -s:
         -s4: Numerical range-based scaling
         -s5: Same as -s4 -sl
         -s6: Scale based on the simple numerical range
         -s7: Same as -s4 -sq
These scaling rules can be combined with any of the following:
         -sp: also do power scaling.
         -si: also do integer scaling (default).
         -se: also do equilibration to scale to the -1..1 range (default).
         -sq: also do quadratic scaling.
         -sl: Scale to convergence using logarithmic mean of all values.
         -sd: Dynamic update.
         -sr: Scale only rows.
         -sc: Scale only columns.
-presolve       presolve problem before start optimizing (rows+columns) See set_presolve
-presolverow    presolve problem before start optimizing (rows only) See set_presolve
-presolvecol    presolve problem before start optimizing (columns only) See set_presolve
-presolvel      also eliminate linearly dependent rows See set_presolve
-presolves      also convert constraints to SOSes (only SOS1 handled) See set_presolve
-presolver      If the phase 1 solution process finds that a constraint is
                redundant then this constraint is deleted See set_presolve
-presolvek      Simplification of knapsack-type constraints through
                addition of an extra variable, which also helps bound the OF See set_presolve
-presolveq      Direct substitution of one variable in 2-element equality
                constraints; this requires changes to the constraint matrix See set_presolve
-presolvem	Merge rows See set_presolve
-presolvefd	COLFIXDUAL See set_presolve
-presolvebnd	Presolve bounds See set_presolve
-presolved	Presolve duals See set_presolve
-presolvef      Identify implied free variables (releasing their expl. bounds) See set_presolve
-presolveslk	IMPLIEDSLK See set_presolve
-presolveg      Reduce (tighten) coef. in integer models based on GCD argument See set_presolve
-presolveb      Attempt to fix binary variables at one of their bounds See set_presolve
-presolvec      Attempt to reduce coefficients in binary models See set_presolve
-presolverowd   Idenfify and delete qualifying constraints that
                are dominated by others, also fixes variables at a bound See set_presolve
-presolvecold   Deletes variables (mainly binary), that are dominated
                by others (only one can be non-zero) See set_presolve
-C <mode>       basis crash mode See set_basiscrash
         -C0: No crash basis
         -C2: Most feasible basis
         -C3: Least degenerate basis
-prim           Prefer the primal simplex for both phases. See set_preferdual
-dual           Prefer the dual simplex for both phases. See set_preferdual
-simplexpp      Set Phase1 Primal, Phase2 Primal. See set_simplextype
-simplexdp      Set Phase1 Dual, Phase2 Primal. See set_simplextype
-simplexpd      Set Phase1 Primal, Phase2 Dual. See set_simplextype
-simplexdd      Set Phase1 Dual, Phase2 Dual. See set_simplextype
-degen          use perturbations to reduce degeneracy,
                can increase numerical instability See set_anti_degen
-degenc         use column check to reduce degeneracy See set_anti_degen
-degend         dynamic check to reduce degeneracy See set_anti_degen
-degenf         anti-degen fixedvars See set_anti_degen
-degens         anti-degen stalling See set_anti_degen
-degenn         anti-degen numfailure See set_anti_degen
-degenl         anti-degen lostfeas See set_anti_degen
-degeni         anti-degen infeasible See set_anti_degen
-degenb         anti-degen B&B See set_anti_degen
-degenr         anti-degen Perturbation of the working RHS at refactorization See set_anti_degen
-degenp         anti-degen Limit bound flips See set_anti_degen
-trej <Trej>    set minimum pivot value See set_epspivot
-epsd <epsd>    set minimum tolerance for reduced costs See set_epsd
-epsb <epsb>    set minimum tolerance for the RHS See set_epsb
-epsel <epsel>  set tolerance for rounding values to zero See set_epsel
-epsp <epsp>    set the value that is used as perturbation scalar for
                degenerative problems See set_epsperturb
-improve <level>        iterative improvement level See set_improve
         -improve0: none
         -improve1: Running accuracy measurement of solved equations on Bx=r
         -improve2: Improve initial dual feasibility by bound flips (default)
         -improve4: Low-cost accuracy monitoring in the dual
         -improve8: check for primal/dual feasibility at the node level
-timeout <sec>  Timeout after sec seconds when not solution found. See set_timeout
-ac <accuracy>  Fail when accuracy is less then specified value.
-bfp <filename> Set basis factorization package. See set_BFP

-noint          Ignore integer restrictions
-e <number>     specifies the tolerance which is used to determine whether a
                floating point number is in fact an integer.
                Should be < 0.5 See set_epsint
-g <number>
-ga <number>    specifies the absolute MIP gap for branch-and-bound. See set_mip_gap
                This specifies the absolute allowed tolerance
                on the object function. Can result in faster solving times.
-gr <number>    specifies the relative MIP gap for branch-and-bound. See set_mip_gap
                This specifies the relative allowed tolerance
                on the object function. Can result in faster solving times.
-f              specifies that branch-and-bound algorithm stops at first found
                solution See set_break_at_first
-b <bound>      specify a lower bound for the objective function See set_obj_bound
                to the program. If close enough, may speed up the
                calculations.
-o <value>      specifies that branch-and-bound algorithm stops when objective
                value is better than value See set_break_at_value
-c
-cc             during branch-and-bound, take the ceiling branch first See set_bb_floorfirst
-cf             during branch-and-bound, take the floor branch first See set_bb_floorfirst
-ca             during branch-and-bound, the algorithm chooses branch See set_bb_floorfirst
-depth <limit>  set branch-and-bound depth limit See set_bb_depthlimit
-n <solnr>      specify which solution number to return See set_solutionlimit
-B <rule>       specify branch-and-bound rule See set_bb_rule
         -B0: Select Lowest indexed non-integer column (default)
         -B1: Selection based on distance from the current bounds
         -B2: Selection based on the largest current bound
         -B3: Selection based on largest fractional value
         -B4: Simple, unweighted pseudo-cost of a variable
         -B5: This is an extended pseudo-costing strategy based on minimizing
              the number of integer infeasibilities
         -B6: This is an extended pseudo-costing strategy based on maximizing
              the normal pseudo-cost divided by the number of infeasibilities.
              Similar to (the reciprocal of) a cost/benefit ratio
These branch-and-bound rules can be combined with any of the following:
-Bw             WeightReverse branch-and-bound See set_bb_rule
-Bb             BranchReverse branch-and-bound See set_bb_rule
-Bg             Greedy branch-and-bound See set_bb_rule
-Bp             PseudoCost branch-and-bound See set_bb_rule
-BR             Extended PseudoCost branch-and-bound See set_bb_rule
-Bf             DepthFirst branch-and-bound See set_bb_rule
-Br             Randomize branch-and-bound See set_bb_rule
-BG             GubMode branch-and-bound See set_bb_rule
-Bd             Dynamic branch-and-bound See set_bb_rule
-Bs             RestartMode branch-and-bound See set_bb_rule
-BB             BreadthFirst branch-and-bound See set_bb_rule
-Bo             Order variables to improve branch-and-bound performance See set_bb_rule
-Bc             Do bound tightening during B&B based of reduced cost info See set_bb_rule
-Bi             Initialize pseudo-costs by strong branching See set_bb_rule

-time           Print CPU time to parse input and to calculate result. See time_elapsed
-v <level>      verbose mode, gives flow through the program. See set_verbose
                 if level not provided (-v) then -v4 (NORMAL) is taken.
         -v0: NEUTRAL
         -v1: CRITICAL
         -v2: SEVERE
         -v3: IMPORTANT (default)
         -v4: NORMAL
         -v5: DETAILED
         -v6: FULL
-t              trace pivot selection See set_trace
-d              debug mode, all intermediate results are printed,
                and the branch-and-bound decisions See set_debug
-R              report information while solving the model See put_msgfunc See get_working_objective
-Db <filename>  Do a generic readable data dump of key lp_solve model variables
                before solve. See print_debugdump
                Principally for run difference and debugging purposes
-Da <filename>  Do a generic readable data dump of key lp_solve model variables
                after solve. See print_debugdump
                Principally for run difference and debugging purposes
-i              print all intermediate valid solutions. See set_print_sol
                Can give you useful solutions even if the total run time
                is too long
-ia             print all intermediate (only non-zero values) valid solutions. See set_print_sol
                Can give you useful solutions even if the total run time
                is too long
-stat		Print model statistics
-S <detail>     Print solution. If detail omitted, then -S2 is used.
         -S0: Print nothing
         -S1: Only objective value See print_objective See get_objective
         -S2: Obj value+variables (default) See print_solution See get_variables, get_ptr_variables
         -S3: Obj value+variables+constraints See print_constraints See get_constraints
         -S4: Obj value+variables+constraints+duals
              See print_duals
              See get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult,
              See get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex
         -S5: Obj value+variables+constraints+duals+lp model See print_lp
         -S6: Obj value+variables+constraints+duals+lp model+scales See print_scales
         -S7: Obj value+variables+constraints+duals+lp model+scales+lp tableau See print_tableau

A practical example

Enter the following in your favorite text editor (Windows users, don't use Word or Wordpad, that won't work. If you don't have an editor, use notepad).

max: 143 x + 60 y;

120 x + 210 y <= 15000;
110 x + 30 y <= 4000;
x + y <= 75;

Save this on your hard disk with name model.lp (don't forget in which directory/folder you save it).

Now enter the following:

lp_solve -S3 model.lp

This gives:

Value of objective function: 6315.63

Actual values of the variables:
x                          21.875
y                          53.125

Actual values of the constraints:
R1                        13781.2
R2                           4000
R3                             75

Note that this is the model presented in Formulation of an lp problem in lpsolve. The model is formulated in the lp format. See lp-format for a description of it.

./lp_solveAPIreference.htm000666 000000 000000 00000074234 12673521030 014144 0ustar00000000 000000 lp_solve API reference

lp_solve API reference

Alfabetical index

add_column, add_columnex, str_add_column
add_constraint, add_constraintex, str_add_constraint
add_lag_con, str_add_lag_con
add_SOS
column_in_lp
copy_lp
default_basis
del_column
del_constraint
delete_lp
dualize_lp
free_lp
get_accuracy
get_anti_degen
get_basis
get_basiscrash
get_bb_depthlimit
get_bb_floorfirst
get_bb_rule
get_bounds_tighter
get_break_at_value
get_break_numeric_accuracy
get_col_name, get_origcol_name
get_column, get_columnex
get_constr_type
get_constr_value
get_constraints, get_ptr_constraints
get_epsb
get_epsd
get_epsel
get_epsint
get_epsperturb
get_epspivot
get_improve
get_infinite
get_lambda, get_ptr_lambda, get_lambda, get_ptr_lambda
get_lowbo
get_lp_index
get_lp_name
get_Lrows
get_mat
get_max_level, get_max_level
get_maxpivot
get_mip_gap
get_Ncolumns
get_nameindex
get_negrange
get_nonzeros
get_Norig_columns
get_Norig_rows
get_Nrows
get_obj_bound
get_objective
get_orig_index
get_pivoting
get_presolve
get_presolveloops
get_primal_solution, get_ptr_primal_solution, get_var_primalresult
get_print_sol
get_rh
get_rh_range
get_row, get_rowex
get_row_name, get_origrow_name
get_scalelimit
get_scaling
get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex
get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult
get_simplextype
get_solutioncount
get_solutionlimit
get_status
get_statustext
get_timeout
get_total_iter
get_total_nodes
get_upbo
get_var_branch
get_var_priority, get_var_priority
get_variables, get_ptr_variables
get_verbose
get_working_objective
guess_basis
has_BFP
has_XLI
is_add_rowmode
is_anti_degen
is_binary
is_break_at_first
is_constr_type
is_debug
is_feasible
is_unbounded
is_infinite
is_int
is_integerscaling
is_lag_trace
is_maxim
is_nativeBFP
is_nativeXLI
is_negative
is_obj_in_basis
is_piv_mode
is_piv_rule
is_presolve
is_scalemode
is_scaletype
is_semicont
is_SOS_var
is_trace
is_use_names
lag_solve
lp_solve_version
make_lp
print_constraints
print_debugdump
print_duals
print_lp
print_objective
print_scales
print_solution
print_str
print_tableau
put_abortfunc
put_bb_branchfunc
put_bb_nodefunc
put_logfunc
put_msgfunc
read_basis
read_lp, read_LP
read_mps, read_freemps, read_MPS, read_freeMPS
read_params
read_XLI
reset_basis
reset_params
resize_lp
set_add_rowmode
set_anti_degen, get_anti_degen
set_basis
set_basiscrash
set_basisvar
set_bb_depthlimit
set_bb_floorfirst
set_bb_rule
set_BFP
set_XLI
set_binary
set_bounds
set_bounds_tighter
set_break_at_first
set_break_at_value
set_break_numeric_accuracy
set_column, set_columnex
set_col_name
set_constr_type
set_debug
set_epsb
set_epsd
set_epsel
set_epsint
set_epsperturb
set_epspivot
set_epslevel
set_unbounded
set_improve
set_infinite
set_int
set_lag_trace
set_lowbo
set_lp_name
set_mat
set_maxim
set_maxpivot
set_minim
set_mip_gap
set_negrange
set_obj_bound
set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj
set_obj_in_basis
set_outputstream, set_outputfile
set_pivoting
set_preferdual
set_presolve
set_print_sol
set_rh
set_rh_range
set_rh_vec, str_set_rh_vec
set_row, set_rowex
set_row_name
set_scalelimit
set_scaling
set_semicont
set_sense
set_simplextype
set_solutionlimit
set_timeout
set_trace
set_upbo
set_use_names
set_var_branch
set_var_weights
set_verbose
solve
time_elapsed
unscale
write_basis
write_lp, write_LP, write_lpex
write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex
write_params
write_XLI

Functional index

Create/destroy model

copy_lp
make_lp
read_lp, read_LP
read_mps, read_freemps, read_MPS, read_freeMPS
read_XLI
delete_lp
free_lp

Build model

add_column, add_columnex, str_add_column, set_column, set_columnex, get_column, get_columnex
add_constraint, add_constraintex, str_add_constraint, set_row, set_rowex
add_lag_con, str_add_lag_con
add_SOS, is_SOS_var
del_column
del_constraint, get_row, get_rowex
get_nameindex
is_infinite
is_negative
resize_lp
set_add_rowmode, is_add_rowmode
set_binary, is_binary
set_bounds
set_bounds_tighter, get_bounds_tighter
set_col_name, get_col_name, get_origcol_name
set_constr_type, get_constr_type, is_constr_type
set_unbounded, is_unbounded
set_infinite, get_infinite
set_int, is_int
set_lowbo, get_lowbo
set_lp_name, get_lp_name
set_mat, get_mat
set_obj_bound, get_obj_bound
set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj
set_rh, get_rh
set_rh_range, get_rh_range
set_rh_vec, str_set_rh_vec
set_row_name, get_row_name, get_origrow_name
set_semicont, is_semicont
set_upbo, get_upbo
set_var_branch, get_var_branch
set_var_weights

Solver settings

default_basis
read_basis
reset_basis
write_basis
guess_basis
read_params, write_params
reset_params
set_anti_degen, is_anti_degen
set_basis, get_basis
set_basiscrash, get_basiscrash
set_bb_depthlimit, get_bb_depthlimit
set_bb_floorfirst, get_bb_floorfirst
set_bb_rule, get_bb_rule
set_BFP, has_BFP, is_nativeBFP
set_break_at_first, is_break_at_first
set_break_at_value, get_break_at_value
set_epsb, get_epsb
set_epsd, get_epsd
set_epsel, get_epsel
set_epsint, get_epsint
set_epsperturb, get_epsperturb
set_epspivot, get_epspivot
set_epslevel
set_improve, get_improve
set_maxim, is_maxim
set_maxpivot, get_maxpivot
set_minim
set_mip_gap, get_mip_gap
set_negrange, get_negrange
set_obj_in_basis, is_obj_in_basis
set_pivoting, get_pivoting, is_piv_mode, is_piv_rule
set_preferdual
set_presolve, get_presolve, get_presolveloops, is_presolve
set_scalelimit, get_scalelimit
set_scaling, get_scaling, is_integerscaling, is_scalemode, is_scaletype
set_sense
set_simplextype, get_simplextype
set_solutionlimit, get_solutionlimit
set_timeout, get_timeout
set_use_names, is_use_names
unscale

Callback routines

put_abortfunc
put_bb_branchfunc
put_bb_nodefunc
put_logfunc
put_msgfunc

Solve

solve
lag_solve

Solution

get_constraints, get_ptr_constraints
get_constr_value get_objective
get_primal_solution, get_ptr_primal_solution, get_var_primalresult
get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex
get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult
get_solutioncount
get_total_iter
get_total_nodes
get_variables, get_ptr_variables
get_working_objective
is_feasible

Debug/print settings

set_debug, is_debug
set_lag_trace, is_lag_trace
set_outputstream, set_outputfile
set_print_sol, get_print_sol
set_trace, is_trace
set_verbose, get_verbose

Debug/print

print_constraints
print_debugdump
print_duals
print_lp
print_objective
print_scales
print_solution
print_str
print_tableau

Write model to file

write_lp, write_LP, write_lpex
write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex
write_XLI, set_XLI, has_XLI, is_nativeXLI

Miscellaneous routines

column_in_lp
dualize_lp
get_lp_index
get_Lrows
get_Ncolumns
get_nonzeros
get_Norig_columns
get_Norig_rows
get_Nrows
get_orig_index
get_statustext
get_statustext
lp_solve_version
set_basisvar
time_elapsed
./lp_solve_5.5.0.12.chw000666 000000 000000 00000100563 11034153540 012662 0ustar00000000 000000 ITSF` |{ "|{ "`8`T s.!"T Uncompressed MSCompressed{7FC28940-9D31-11D0LZXC Cd;)X44 $/'absolute valuesadd_column add_columnexadd_constraint'add_constraintex4add_lag_con Aadd_SOS NBasis Factorization Packages[Calling the lpsolve API from your applicationhChanges from version 4 to version 5.1uChanges from version 5.1 to version 5.5column_in_lp copy_lp CPLEX lp filesdefault_basis del_columndel_constraintdelete_lpDIMACS maximum flow problemsDIMACS minimum assignment problemsDIMACS minimum cost flow problemsDownloaddualize_lpExternal Language Interfaces+Formulation of an lp model in lpsolve8free variablesEfree_lpRFrequently Asked Questions_get_anti_degenlget_basisy%get_basiscrashget_bb_depthlimitget_bb_floorfirstget_bb_ruleget_bounds_tighterget_break_at_valueget_col_nameget_columnget_columnexget_constr_typeget_constr_valueget_constraintsget_dual_solution "get_epsb!/get_epsd"<get_epsel#Iget_epsint$Vget_epsperturb%cget_epspivot&pget_improve'}get_infinite(get_lambda)get_lowbo*get_lp_index+get_lp_name,get_Lrows-get_mat.get_max_level/get_maxpivot0get_mip_gap1get_nameindex2 get_Ncolumns3get_negrange4&get_nonzeros53get_Norig_columns6@get_Norig_rows7Mget_Nrows8Z!get_obj_bound9gget_objective:tget_orig_index;get_origcol_nameget_origrow_name<get_pivoting=get_presolve>get_presolveloops?get_primal_solution@get_print_solAget_ptr_constraintsget_ptr_dual_solution get_ptr_lambda)get_ptr_primal_solution@get_ptr_sensitivity_objBget_ptr_sensitivity_objexB*get_ptr_sensitivity_rhs 7get_ptr_variablesCDget_rhDQget_rh_rangeE^get_rowFkget_row_name<xget_rowexFget_scalelimitGget_scalingHget_sensitivity_objBget_sensitivity_objexBget_sensitivity_rhs get_simplextypeIget_solutioncountJget_solutionlimitKget_statusLget_statustextM8Z$get_timeoutNget_total_iterO!get_total_nodesP.get_upboQ;get_var_branchRHget_var_dualresult Uget_var_primalresult@bget_var_prioritySoget_variablesC|get_verboseTget_working_objectiveUGNU LESSER GENERAL PUBLIC LICENSEGNU MathProgguess_basisVhas_BFPWhas_XLIXInfeasible modelsinteger variablesIntroductionis_add_rowmodeY is_anti_degenZis_binary[%is_break_at_first\2is_constr_type]?is_debug^Lis_feasible_Yis_infiniteafis_intbsis_integerscalingcis_lag_tracedis_maximeis_nativeBFPfis_nativeXLIgis_negativehis_obj_in_basisiis_piv_modej#is_piv_rulekis_presolvelis_scalemodemis_scaletypenis_semicontois_SOS_varp)is_traceq6is_unbounded`Cis_use_namesrPlag_solves]LINDO lp filesjLinear programming basicswLinear Programming FAQlp file formatlp_solve API referencelp_solve commandlp_solve Yahoo grouplp_solve_versiontlpsolve distributed filesLPSolve IDEmake_lpumps bas file formatmps file formatMPS_writefileexvPresolve print_constraintsw-print_debugdumpx:print_dualsyGprint_lpzTprint_objective{aprint_scales|nprint_solution}{print_str~print_tableauput_abortfuncj*%put_bb_branchfuncput_bb_nodefuncput_logfuncput_msgfuncQuick startratio'sread_basisread_freemps read_freeMPS read_lp$ read_LP1 read_mps> read_MPSK read_paramsX read_XLIe reset_basisr reset_params resize_lp scaling semi-continuous variables sensitivity set_add_rowmode set_anti_degen set_basis set_basiscrash set_basisvar set_bb_depthlimit set_bb_floorfirst set_bb_rule set_BFP( set_binary5 set_boundsB set_bounds_tighterO set_break_at_first\ set_break_at_valuei set_col_namev set_column j 'set_columnex set_constr_type set_debug set_epsb set_epsd set_epsel set_epsint set_epslevel set_epsperturb set_epspivot set_improve set_infinite set_int, set_lag_trace9 set_lowboF set_lp_nameS set_mat` set_maximm set_maxpivotz set_minim set_mip_gap set_negrange set_obj set_obj_bound set_obj_fn set_obj_fnex set_obj_in_basis set_outputfile set_outputstream set_pivoting set_preferdual set_presolve# set_print_sol0 set_rh= set_rh_rangeJ set_rh_vecW set_rowd set_row_nameq set_rowex~ j&!set_scalelimit set_scaling set_semicont set_sense set_simplextype set_solutionlimit set_timeout set_trace set_unbounded set_upbo set_use_names set_var_branch set_var_weights' set_verbose4 set_XLIA solveN special ordered sets[ str_add_columnh str_add_constraintu str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Java Using lpsolve from MATLAB Using lpsolve from Octave Using lpsolve from O-MatrixUsing lpsolve from PythonUsing lpsolve from RUsing lpsolve from Scilab+~ j write_basis8write_freempsvEwrite_freeMPSvRwrite_lp_write_LPlwrite_lpexywrite_mpsvwrite_MPSvwrite_paramswrite_XLIXpress lp filesZimplar_branch set_var_weights' set_verbose4 set_XLIA solveN special ordered sets[ str_add_columnh str_add_constraintu str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Java Using lpsolve from MATLAB Using lpsolve from Octave Using lpsolve from O-MatrixUsing lpsolve from PythonUsing lpsolve from RUsing lpsolve from Scilab+~ jZget_basiscrashget_obj_bound9get_timeoutNis_piv_rulekput_bb_branchfuncset_columnexset_scalelimitwrite_basis $bFVOf/'ITSPT  j].!"TPMGL^/ /$HHTitleMapR! /$OBJINSTJ4/$WWAssociativeLinks//$WWAssociativeLinks/PROPERTY:/$WWKeywordLinks//$WWKeywordLinks/BTREE^L/$WWKeywordLinks/DATA T/$WWKeywordLinks/MAP>J/$WWKeywordLinks/PROPERTY* ::DataSpace/NameList4<(::DataSpace/Storage/MSCompressed/Content,::DataSpace/Storage/MSCompressed/ControlData)::DataSpace/Storage/MSCompressed/SpanInfo/::DataSpace/Storage/MSCompressed/Transform/Listp&_::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/i::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTablealp_solve_5.5.0.12mm ./lp_solve_5.5.0.13.chw000666 000000 000000 00000100600 11122436210 012647 0ustar00000000 000000 ITSF`BlZ |{ "|{ "`8 aT .!"T Uncompressed MSCompressed{7FC28940-9D31-11D0LZXC Cd;)X44 %/'absolute valuesadd_column add_columnexadd_constraint'add_constraintex4add_lag_con Aadd_SOS NBasis Factorization Packages[Calling the lpsolve API from your applicationhChanges from version 4 to version 5.1uChanges from version 5.1 to version 5.5column_in_lp copy_lp CPLEX lp filesdefault_basis del_columndel_constraintdelete_lpDIMACS maximum flow problemsDIMACS minimum assignment problemsDIMACS minimum cost flow problemsDownloaddualize_lpExternal Language Interfaces+Formulation of an lp model in lpsolve8free variablesEfree_lpRFrequently Asked Questions_get_anti_degenlget_basisy%get_basiscrashget_bb_depthlimitget_bb_floorfirstget_bb_ruleget_bounds_tighterget_break_at_valueget_col_nameget_columnget_columnexget_constr_typeget_constr_valueget_constraintsget_dual_solution "get_epsb!/get_epsd"<get_epsel#Iget_epsint$Vget_epsperturb%cget_epspivot&pget_improve'}get_infinite(get_lambda)get_lowbo*get_lp_index+get_lp_name,get_Lrows-get_mat.get_max_level/get_maxpivot0get_mip_gap1get_nameindex2 get_Ncolumns3get_negrange4&get_nonzeros53get_Norig_columns6@get_Norig_rows7Mget_Nrows8Z!get_obj_bound9gget_objective:tget_orig_index;get_origcol_nameget_origrow_name<get_pivoting=get_presolve>get_presolveloops?get_primal_solution@get_print_solAget_ptr_constraintsget_ptr_dual_solution get_ptr_lambda)get_ptr_primal_solution@get_ptr_sensitivity_objBget_ptr_sensitivity_objexB*get_ptr_sensitivity_rhs 7get_ptr_variablesCDget_rhDQget_rh_rangeE^get_rowFkget_row_name<xget_rowexFget_scalelimitGget_scalingHget_sensitivity_objBget_sensitivity_objexBget_sensitivity_rhs get_simplextypeIget_solutioncountJget_solutionlimitKget_statusLget_statustextM8Z$get_timeoutNget_total_iterO!get_total_nodesP.get_upboQ;get_var_branchRHget_var_dualresult Uget_var_primalresult@bget_var_prioritySoget_variablesC|get_verboseTget_working_objectiveUGNU LESSER GENERAL PUBLIC LICENSEGNU MathProgguess_basisVhas_BFPWhas_XLIXInfeasible modelsinteger variablesIntroductionis_add_rowmodeY is_anti_degenZis_binary[%is_break_at_first\2is_constr_type]?is_debug^Lis_feasible_Yis_infiniteafis_intbsis_integerscalingcis_lag_tracedis_maximeis_nativeBFPfis_nativeXLIgis_negativehis_obj_in_basisiis_piv_modej#is_piv_rulekis_presolvelis_scalemodemis_scaletypenis_semicontois_SOS_varp)is_traceq6is_unbounded`Cis_use_namesrPlag_solves]LINDO lp filesjLinear programming basicswLinear Programming FAQlp file formatlp_solve API referencelp_solve commandlp_solve Yahoo grouplp_solve_versiontlpsolve distributed filesLPSolve IDEmake_lpumps bas file formatmps file formatMPS_writefileexvPresolve print_constraintsw-print_debugdumpx:print_dualsyGprint_lpzTprint_objective{aprint_scales|nprint_solution}{print_str~print_tableauput_abortfuncj*%put_bb_branchfuncput_bb_nodefuncput_logfuncput_msgfuncQuick startratio'sread_basisread_freemps read_freeMPS read_lp$ read_LP1 read_mps> read_MPSK read_paramsX read_XLIe reset_basisr reset_params resize_lp scaling semi-continuous variables sensitivity set_add_rowmode set_anti_degen set_basis set_basiscrash set_basisvar set_bb_depthlimit set_bb_floorfirst set_bb_rule set_BFP( set_binary5 set_boundsB set_bounds_tighterO set_break_at_first\ set_break_at_valuei set_col_namev set_column j 'set_columnex set_constr_type set_debug set_epsb set_epsd set_epsel set_epsint set_epslevel set_epsperturb set_epspivot set_improve set_infinite set_int, set_lag_trace9 set_lowboF set_lp_nameS set_mat` set_maximm set_maxpivotz set_minim set_mip_gap set_negrange set_obj set_obj_bound set_obj_fn set_obj_fnex set_obj_in_basis set_outputfile set_outputstream set_pivoting set_preferdual set_presolve# set_print_sol0 set_rh= set_rh_rangeJ set_rh_vecW set_rowd set_row_nameq set_rowex~ j,!set_scalelimit set_scaling set_semicont set_sense set_simplextype set_solutionlimit set_timeout set_trace set_unbounded set_upbo set_use_names set_var_branch set_var_weights' set_verbose4 set_XLIA solveN special ordered sets[ str_add_columnh str_add_constraintu str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Java Using lpsolve from MATLAB Using lpsolve from Octave Using lpsolve from O-MatrixUsing lpsolve from PHPUsing lpsolve from PythonUsing lpsolve from R+x~ jH Using lpsolve from Scilab8write_basisEwrite_freempsvRwrite_freeMPSv_write_lplwrite_LPywrite_lpexwrite_mpsvwrite_MPSvwrite_paramswrite_XLIXpress lp filesZimpl' set_verbose4 set_XLIA solveN special ordered sets[ str_add_columnh str_add_constraintu str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Java Using lpsolve from MATLAB Using lpsolve from Octave Using lpsolve from O-MatrixUsing lpsolve from PHPUsing lpsolve from PythonUsing lpsolve from R+x~ j>get_basiscrashget_obj_bound9get_timeoutNis_piv_rulekput_bb_branchfuncset_columnexset_scalelimitUsing lpsolve from Scilab $bFVOf/'ITSPT  j].!"TPMGL^/ /$HHTitleMap_! /$OBJINSTW4/$WWAssociativeLinks//$WWAssociativeLinks/PROPERTY:/$WWKeywordLinks//$WWKeywordLinks/BTREEkL/$WWKeywordLinks/DATA a/$WWKeywordLinks/MAP>J/$WWKeywordLinks/PROPERTY7 ::DataSpace/NameList4<(::DataSpace/Storage/MSCompressed/Content,::DataSpace/Storage/MSCompressed/ControlData)::DataSpace/Storage/MSCompressed/SpanInfo/::DataSpace/Storage/MSCompressed/Transform/Listp&_::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/i::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTablealp_solve_5.5.0.13 ./lp_solve_5.5.0.14.chw000666 000000 000000 00000100664 11204517466 012700 0ustar00000000 000000 ITSF`59] |{ "|{ "`8?aT .!"T Uncompressed MSCompressed{7FC28940-9D31-11D0LZXC Cd;)X44 )/'absolute valuesadd_column add_columnexadd_constraint'add_constraintex4add_lag_con Aadd_SOS NBasis Factorization Packages[Calling the lpsolve API from your applicationhChanges from version 4 to version 5.1uChanges from version 5.1 to version 5.5column_in_lp copy_lp CPLEX lp filesdefault_basis del_columndel_constraintdelete_lpDIMACS maximum flow problemsDIMACS minimum assignment problemsDIMACS minimum cost flow problemsDownloaddualize_lpExternal Language Interfaces+Formulation of an lp model in lpsolve8free variablesEfree_lpRFrequently Asked Questions_get_anti_degenlget_basisy%get_basiscrashget_bb_depthlimitget_bb_floorfirstget_bb_ruleget_bounds_tighterget_break_at_valueget_col_nameget_columnget_columnexget_constr_typeget_constr_valueget_constraintsget_dual_solution "get_epsb!/get_epsd"<get_epsel#Iget_epsint$Vget_epsperturb%cget_epspivot&pget_improve'}get_infinite(get_lambda)get_lowbo*get_lp_index+get_lp_name,get_Lrows-get_mat.get_max_level/get_maxpivot0get_mip_gap1get_nameindex2 get_Ncolumns3get_negrange4&get_nonzeros53get_Norig_columns6@get_Norig_rows7Mget_Nrows8Z!get_obj_bound9gget_objective:tget_orig_index;get_origcol_nameget_origrow_name<get_pivoting=get_presolve>get_presolveloops?get_primal_solution@get_print_solAget_ptr_constraintsget_ptr_dual_solution get_ptr_lambda)get_ptr_primal_solution@get_ptr_sensitivity_objBget_ptr_sensitivity_objexB*get_ptr_sensitivity_rhs 7get_ptr_variablesCDget_rhDQget_rh_rangeE^get_rowFkget_row_name<xget_rowexFget_scalelimitGget_scalingHget_sensitivity_objBget_sensitivity_objexBget_sensitivity_rhs get_simplextypeIget_solutioncountJget_solutionlimitKget_statusLget_statustextM8Z$get_timeoutNget_total_iterO!get_total_nodesP.get_upboQ;get_var_branchRHget_var_dualresult Uget_var_primalresult@bget_var_prioritySoget_variablesC|get_verboseTget_working_objectiveUGNU LESSER GENERAL PUBLIC LICENSEGNU MathProgguess_basisVhas_BFPWhas_XLIXInfeasible modelsinteger variablesIntroductionis_add_rowmodeY is_anti_degenZis_binary[%is_break_at_first\2is_constr_type]?is_debug^Lis_feasible_Yis_infiniteafis_intbsis_integerscalingcis_lag_tracedis_maximeis_nativeBFPfis_nativeXLIgis_negativehis_obj_in_basisiis_piv_modej#is_piv_rulekis_presolvelis_scalemodemis_scaletypenis_semicontois_SOS_varp)is_traceq6is_unbounded`Cis_use_namesrPlag_solves]LINDO lp filesjLinear programming basicswLinear Programming FAQlp file formatlp_solve API referencelp_solve commandlp_solve Yahoo grouplp_solve_versiontlpsolve distributed filesLPSolve IDEmake_lpumps bas file formatmps file formatMPS_writefileexvPresolve print_constraintsw-print_debugdumpx:print_dualsyGprint_lpzTprint_objective{aprint_scales|nprint_solution}{print_str~print_tableauput_abortfuncj*%put_bb_branchfuncput_bb_nodefuncput_logfuncput_msgfuncQuick startratio'sread_basisread_freemps read_freeMPS read_lp$ read_LP1 read_mps> read_MPSK read_paramsX read_XLIe reset_basisr reset_params resize_lp scaling semi-continuous variables sensitivity set_add_rowmode set_anti_degen set_basis set_basiscrash set_basisvar set_bb_depthlimit set_bb_floorfirst set_bb_rule set_BFP( set_binary5 set_boundsB set_bounds_tighterO set_break_at_first\ set_break_at_valuei set_col_namev set_column j 'set_columnex set_constr_type set_debug set_epsb set_epsd set_epsel set_epsint set_epslevel set_epsperturb set_epspivot set_improve set_infinite set_int, set_lag_trace9 set_lowboF set_lp_nameS set_mat` set_maximm set_maxpivotz set_minim set_mip_gap set_negrange set_obj set_obj_bound set_obj_fn set_obj_fnex set_obj_in_basis set_outputfile set_outputstream set_pivoting set_preferdual set_presolve# set_print_sol0 set_rh= set_rh_rangeJ set_rh_vecW set_rowd set_row_nameq set_rowex~ j"!set_scalelimit set_scaling set_semicont set_sense set_simplextype set_solutionlimit set_timeout set_trace set_unbounded set_upbo set_use_names set_var_branch set_var_weights' set_verbose4 set_XLIA solveN special ordered sets[ str_add_columnh str_add_constraintu str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Euler Using lpsolve from FreeMat Using lpsolve from Java Using lpsolve from MATLABUsing lpsolve from OctaveUsing lpsolve from O-MatrixUsing lpsolve from PHP+~ jUsing lpsolve from Python8Using lpsolve from REUsing lpsolve from SageRUsing lpsolve from Scilab_Using lpsolve from Sysquakelwrite_basisywrite_freempsvwrite_freeMPSvwrite_lpwrite_LPwrite_lpexwrite_mpsvwrite_MPSvwrite_paramswrite_XLIXpress lp filesZimplonstraintu str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Euler Using lpsolve from FreeMat Using lpsolve from Java Using lpsolve from MATLABUsing lpsolve from OctaveUsing lpsolve from O-MatrixUsing lpsolve from PHP+~ j>get_basiscrashget_obj_bound9get_timeoutNis_piv_rulekput_bb_branchfuncset_columnexset_scalelimitUsing lpsolve from Python $bFVOf/'ITSPT  j].!"TPMGL^/ /$HHTitleMap! /$OBJINST 4/$WWAssociativeLinks//$WWAssociativeLinks/PROPERTY:/$WWKeywordLinks//$WWKeywordLinks/BTREEL/$WWKeywordLinks/DATA /$WWKeywordLinks/MAP>J/$WWKeywordLinks/PROPERTYk ::DataSpace/NameList4<(::DataSpace/Storage/MSCompressed/Content,::DataSpace/Storage/MSCompressed/ControlData)::DataSpace/Storage/MSCompressed/SpanInfo/::DataSpace/Storage/MSCompressed/Transform/Listp&_::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/i::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTablealp_solve_5.5.0.14@F@F ./lp_solve_5.5.0.15.chw000666 000000 000000 00000100701 11247735762 012701 0ustar00000000 000000 ITSF`cc |{ "|{ "`8LaT .!"T Uncompressed MSCompressed{7FC28940-9D31-11D0LZXC Cd;)X44 */'absolute valuesadd_column add_columnexadd_constraint'add_constraintex4add_lag_con Aadd_SOS NBasis Factorization Packages[Calling the lpsolve API from your applicationhChanges from version 4 to version 5.1uChanges from version 5.1 to version 5.5column_in_lp copy_lp CPLEX lp filesdefault_basis del_columndel_constraintdelete_lpDIMACS maximum flow problemsDIMACS minimum assignment problemsDIMACS minimum cost flow problemsDownloaddualize_lpExternal Language Interfaces+Formulation of an lp model in lpsolve8free variablesEfree_lpRFrequently Asked Questions_get_anti_degenlget_basisy%get_basiscrashget_bb_depthlimitget_bb_floorfirstget_bb_ruleget_bounds_tighterget_break_at_valueget_col_nameget_columnget_columnexget_constr_typeget_constr_valueget_constraintsget_dual_solution "get_epsb!/get_epsd"<get_epsel#Iget_epsint$Vget_epsperturb%cget_epspivot&pget_improve'}get_infinite(get_lambda)get_lowbo*get_lp_index+get_lp_name,get_Lrows-get_mat.get_max_level/get_maxpivot0get_mip_gap1get_nameindex2 get_Ncolumns3get_negrange4&get_nonzeros53get_Norig_columns6@get_Norig_rows7Mget_Nrows8Z!get_obj_bound9gget_objective:tget_orig_index;get_origcol_nameget_origrow_name<get_pivoting=get_presolve>get_presolveloops?get_primal_solution@get_print_solAget_ptr_constraintsget_ptr_dual_solution get_ptr_lambda)get_ptr_primal_solution@get_ptr_sensitivity_objBget_ptr_sensitivity_objexB*get_ptr_sensitivity_rhs 7get_ptr_variablesCDget_rhDQget_rh_rangeE^get_rowFkget_row_name<xget_rowexFget_scalelimitGget_scalingHget_sensitivity_objBget_sensitivity_objexBget_sensitivity_rhs get_simplextypeIget_solutioncountJget_solutionlimitKget_statusLget_statustextM8Z$get_timeoutNget_total_iterO!get_total_nodesP.get_upboQ;get_var_branchRHget_var_dualresult Uget_var_primalresult@bget_var_prioritySoget_variablesC|get_verboseTget_working_objectiveUGNU LESSER GENERAL PUBLIC LICENSEGNU MathProgguess_basisVhas_BFPWhas_XLIXInfeasible modelsinteger variablesIntroductionis_add_rowmodeY is_anti_degenZis_binary[%is_break_at_first\2is_constr_type]?is_debug^Lis_feasible_Yis_infiniteafis_intbsis_integerscalingcis_lag_tracedis_maximeis_nativeBFPfis_nativeXLIgis_negativehis_obj_in_basisiis_piv_modej"#is_piv_rulekis_presolvelis_scalemodemis_scaletypenis_semicontois_SOS_varp)is_traceq6is_unbounded`Cis_use_namesrPlag_solves]LINDO lp filesjLinear programming basicswLinear Programming FAQlp file formatlp_solve API referencelp_solve commandlp_solve Yahoo grouplp_solve_versiontLPFMLlpsolve distributed filesLPSolve IDEmake_lpumps bas file formatmps file formatMPS_writefileexv Presolve-print_constraintsw:print_debugdumpxGprint_dualsyTprint_lpzaprint_objective{nprint_scales|{print_solution}print_str~print_tableaudej$%put_abortfuncput_bb_branchfuncput_bb_nodefuncput_logfuncput_msgfuncQuick startratio'sread_basis read_freemps read_freeMPS$ read_lp1 read_LP> read_mpsK read_MPSX read_paramse read_XLIr reset_basis reset_params resize_lp scaling semi-continuous variables sensitivity set_add_rowmode set_anti_degen set_basis set_basiscrash set_basisvar set_bb_depthlimit set_bb_floorfirst set_bb_rule( set_BFP5 set_binaryB set_boundsO set_bounds_tighter\ set_break_at_firsti set_break_at_valuev set_col_name dej 'set_column set_columnex set_constr_type set_debug set_epsb set_epsd set_epsel set_epsint set_epslevel set_epsperturb set_epspivot set_improve set_infinite, set_int9 set_lag_traceF set_lowboS set_lp_name` set_matm set_maximz set_maxpivot set_minim set_mip_gap set_negrange set_obj set_obj_bound set_obj_fn set_obj_fnex set_obj_in_basis set_outputfile set_outputstream set_pivoting set_preferdual# set_presolve0 set_print_sol= set_rhJ set_rh_rangeW set_rh_vecd set_rowq set_row_name~ <!set_rowex set_scalelimit set_scaling set_semicont set_sense set_simplextype set_solutionlimit set_timeout set_trace set_unbounded set_upbo set_use_names set_var_branch' set_var_weights4 set_verboseA set_XLIN solve[ special ordered setsh str_add_columnu str_add_constraint str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Euler Using lpsolve from FreeMat Using lpsolve from JavaUsing lpsolve from MATLABUsing lpsolve from OctaveUsing lpsolve from O-Matrix+t_row_name~ Using lpsolve from PHP8Using lpsolve from PythonEUsing lpsolve from RRUsing lpsolve from Sage_Using lpsolve from ScilablUsing lpsolve from Sysquakeywrite_basiswrite_freempsvwrite_freeMPSvwrite_lpwrite_LPwrite_lpexwrite_mpsvwrite_MPSvwrite_paramswrite_XLIXpress lp filesZimpl str_add_lag_con  str_set_obj_fn str_set_rh_vec time_elapsed unscale Usefull links Using lpsolve from AMPL Using lpsolve from Euler Using lpsolve from FreeMat Using lpsolve from JavaUsing lpsolve from MATLABUsing lpsolve from OctaveUsing lpsolve from O-Matrix+t_row_name~ Zget_basiscrashget_obj_bound9get_timeoutNis_piv_rulekput_abortfuncset_columnset_rowexUsing lpsolve from PHP $bFVOf/'ITSPT  j].!"TPMGL^/ /$HHTitleMap ! /$OBJINST4/$WWAssociativeLinks//$WWAssociativeLinks/PROPERTY:/$WWKeywordLinks//$WWKeywordLinks/BTREE,L/$WWKeywordLinks/DATA "/$WWKeywordLinks/MAP>J/$WWKeywordLinks/PROPERTYx ::DataSpace/NameList4<(::DataSpace/Storage/MSCompressed/Content,::DataSpace/Storage/MSCompressed/ControlData)::DataSpace/Storage/MSCompressed/SpanInfo/::DataSpace/Storage/MSCompressed/Transform/Listp&_::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/i::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTablealp_solve_5.5.0.15ff ./lp_solve_version.htm000666 000000 000000 00000003403 10054657260 013474 0ustar00000000 000000 lp_solve_version

lp_solve_version

Returns the full version number of lp_solve.

void lp_solve_version(int *majorversion, int *minorversion, int *release, int *build);

Return Value

lp_solve_version has no return value.

Parameters

majorversion

major version number.

minorversion

minor version number.

release

release number.

build

build number.

Remarks

The lp_solve_version function returns the full version number of lp_solve.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  int majorversion, minorversion, release, build;

  lp_solve_version(&majorversion, &minorversion, &release, &build);

  return(0);
}

lp_solve API reference

See Also

./make_lp.htm000666 000000 000000 00000005621 10351225442 011511 0ustar00000000 000000 make_lp

make_lp

Create and initialise a new lprec structure.

lprec *make_lp(int rows, int columns);

Return Value

Returns a pointer to a new lprec structure. This must be provided to almost all lp_solve functions.
A NULL return value indicates an error. Specifically not enough memory available to setup an lprec structure.

Parameters

rows

Initial number of rows. Can be 0 as new rows can be added via add_constraint, add_constraintex, str_add_constraint

columns

Initial number of columns. Can be 0 as new columns can be added via add_column, add_columnex, str_add_column

Remarks

The make_lp function constructs a new LP. Sets all variables to initial values.
The LP has rows rows and columns columns. The matrix contains no values, but space for one value. All arrays that depend on rows and columns are allocated.

It is advised not to read/write the lprec structure. Instead, use the function interface to communicate with the lp_solve library. This because the structure can change over time. The function interface will be more stable.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /*
  .
  .
  .
  */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also copy_lp, delete_lp, free_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, resize_lp

./MathProg.htm000666 000000 000000 00000021150 10455166056 011627 0ustar00000000 000000 GNU MathProg

GNU MathProg

GNU MathProg is a modeling language intended for describing linear mathematical programming models.
Model descriptions written in the GNU MathProg language consist of a set of statements and data blocks constructed by the user.

See http://gnuwin32.sourceforge.net/downlinks/glpk-doc-zip.php for a complete description of this modeling language.

GNU MathProg is part of the GLPK solver. See http://www.gnu.org/software/glpk/glpk.html and http://gnuwin32.sourceforge.net/packages/glpk.htm for the homepage of it.
Note that MathProg is a subset of the AMPL modeling language. See Using lpsolve from AMPL.
The XLI used by lp_solve to read these models is derived from this code.

lp_solve can read/write and solve these MathProg models directly via the xli_MathProg XLI driver (see External Language Interfaces). It reads such a model in above format and can solve it then.

For example:

lp_solve -rxli xli_MathProg Diet1.mod

This gives as result:

Value of objective function: 88.2

Actual values of the variables:
Buy[BEEF]                       0
Buy[CHK]                        0
Buy[FISH]                       0
Buy[HAM]                        0
Buy[MCH]                  46.6667
Buy[MTL]                        0
Buy[SPG]                        0
Buy[TUR]                        0

MathProg has also the possibility to have the model and data in two separate files. lp_solve can handle this also. For example:

lp_solve -rxli xli_MathProg diet.mod -rxlidata diet.dat

This gives as result:

Value of objective function: 88.2

Actual values of the variables:
Buy[BEEF]                       0
Buy[CHK]                        0
Buy[FISH]                       0
Buy[HAM]                        0
Buy[MCH]                  46.6667
Buy[MTL]                        0
Buy[SPG]                        0
Buy[TUR]                        0

Generating MathProg models

The XLI can also create a MathProg model, however it doesn't use the strength of the language. Constraints are written out line per line. But it can be a starter. For example:

lp_solve model.lp -wxli xli_MathProg model.mod

This gives as model.mod:

/* Variable definitions */
var x >= 0;
var y >= 0;

/* Objective function */
maximize obj: +143*x +60*y;

/* Constraints */
R1: +120*x +210*y <= 15000;
R2: +110*x +30*y <= 4000;
R3: +x +y <= 75;

API

Use the lpsolve API call read_XLI to read a model and write_XLI to write a model. See also External Language Interfaces.

IDE

Also from within the IDE, this XLI can be used. However, some entries must be added in LpSolveIDE.ini (in the folder where the IDE is installed).

In the [XLI] section the following must be added:

lib1=xli_MathProg

And a new section for the MathProg XLI must also be added:

[xli_MathProg]
extension=.mod
language=MATHPROG

Then make sure that the xli_MathProg.dll is available for the IDE. This must be done by placing this dll in the IDE folder or in the Windows system32 folder.

Example models/data

Diet1.mod
set NUTR;
set FOOD;

param cost {FOOD} > 0;
param f_min {FOOD} >= 0;
param f_max {j in FOOD} >= f_min[j];

param n_min {NUTR} >= 0;
param n_max {i in NUTR} >= n_min[i];

param amt {NUTR,FOOD} >= 0;

var Buy {j in FOOD} >= f_min[j], <= f_max[j];

minimize total_cost:  sum {j in FOOD} cost[j] * Buy[j];

subject to diet {i in NUTR}:
   n_min[i] <= sum {j in FOOD} amt[i,j] * Buy[j] <= n_max[i];


data;

set NUTR := A B1 B2 C ;
set FOOD := BEEF CHK FISH HAM MCH MTL SPG TUR ;

param:   cost  f_min  f_max :=
  BEEF   3.19    0     100
  CHK    2.59    0     100
  FISH   2.29    0     100
  HAM    2.89    0     100
  MCH    1.89    0     100
  MTL    1.99    0     100
  SPG    1.99    0     100
  TUR    2.49    0     100 ;

param:   n_min  n_max :=
   A      700   10000
   C      700   10000
   B1     700   10000
   B2     700   10000 ;

param amt (tr):
           A    C   B1   B2 :=
   BEEF   60   20   10   15
   CHK     8    0   20   20
   FISH    8   10   15   10
   HAM    40   40   35   10
   MCH    15   35   15   15
   MTL    70   30   15   15
   SPG    25   50   25   15
   TUR    60   20   15   10 ;
end;
diet.mod
set NUTR;
set FOOD;

param cost {FOOD} > 0;
param f_min {FOOD} >= 0;
param f_max {j in FOOD} >= f_min[j];

param n_min {NUTR} >= 0;
param n_max {i in NUTR} >= n_min[i];

param amt {NUTR,FOOD} >= 0;

var Buy {j in FOOD} >= f_min[j], <= f_max[j];

minimize total_cost:  sum {j in FOOD} cost[j] * Buy[j];

subject to diet {i in NUTR}:
   n_min[i] <= sum {j in FOOD} amt[i,j] * Buy[j] <= n_max[i];
diet.dat
set NUTR := A B1 B2 C ;
set FOOD := BEEF CHK FISH HAM MCH MTL SPG TUR ;

param:   cost  f_min  f_max :=
  BEEF   3.19    0     100
  CHK    2.59    0     100
  FISH   2.29    0     100
  HAM    2.89    0     100
  MCH    1.89    0     100
  MTL    1.99    0     100
  SPG    1.99    0     100
  TUR    2.49    0     100 ;

param:   n_min  n_max :=
   A      700   10000
   C      700   10000
   B1     700   10000
   B2     700   10000 ;

param amt (tr):
           A    C   B1   B2 :=
   BEEF   60   20   10   15
   CHK     8    0   20   20
   FISH    8   10   15   10
   HAM    40   40   35   10
   MCH    15   35   15   15
   MTL    70   30   15   15
   SPG    25   50   25   15
   TUR    60   20   15   10 ;
model.lp
/* model.lp */

max: 143 x + 60 y;

120 x + 210 y <= 15000;
110 x + 30 y <= 4000;
x + y <= 75;
./MATLAB.htm000666 000000 000000 00000351731 13772705351 011063 0ustar00000000 000000 Using lpsolve from MATLAB

Using lpsolve from MATLAB

MATLAB?

MATLAB is a high-performance language for technical computing. It integrates computation, visualization, and programming in an easy-to-use environment where problems and solutions are expressed in familiar mathematical notation. Typical uses include

  • Math and computation
  • Algorithm development
  • Data acquisition
  • Modeling, simulation, and prototyping
  • Data analysis, exploration, and visualization
  • Scientific and engineering graphics
  • Application development, including graphical user interface building

MATLAB is an interactive system whose basic data element is an array that does not require dimensioning. This allows you to solve many technical computing problems, especially those with matrix and vector formulations, in a fraction of the time it would take to write a program in a scalar non-interactive language such as C or Fortran.

The name MATLAB stands for matrix laboratory. MATLAB was originally written to provide easy access to matrix software developed by the LINPACK and EISPACK projects. Today, MATLAB engines incorporate the LAPACK and BLAS libraries, embedding the state of the art in software for matrix computation.

MATLAB has evolved over a period of years with input from many users. In university environments, it is the standard instructional tool for introductory and advanced courses in mathematics, engineering, and science. In industry, MATLAB is the tool of choice for high-productivity research, development, and analysis.

MATLAB features a family of add-on application-specific solutions called toolboxes. Very important to most users of MATLAB, toolboxes allow you to learn and apply specialized technology. Toolboxes are comprehensive collections of MATLAB functions (M-files) that extend the MATLAB environment to solve particular classes of problems. Areas in which toolboxes are available include signal processing, control systems, neural networks, fuzzy logic, wavelets, simulation, and many others.

We will not discuss the specifics of MATLAB here but instead refer the reader to the MATLAB website and documentation.

MATLAB and lpsolve

lpsolve is callable from MATLAB via an external interface or MEX-function. As such, it looks like lpsolve is fully integrated with MATLAB. Matrices can directly be transferred between MATLAB and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for MATLAB (especially for matrix support). So you have full control to the complete lpsolve functionality via the mxlpsolve MATLAB driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level M-files that can make things a lot easier. See further in this article.

MATLAB is ideally suited to handle linear programming problems. These are problems in which you have a quantity, depending linearly on several variables, that you want to maximize or minimize subject to several constraints that are expressed as linear inequalities in the same variables.If the number of variables and the number of constraints are small, then there are numerous mathematical techniques for solving a linear programming problem. Indeed these techniques are often taught in high school or university level courses in finite mathematics.But sometimes these numbers are high, or even if low, the constants in the linear inequalities or the object expression for the quantity to be optimized may be numerically complicated in which case a software package like MATLAB is required to effect a solution.

Installation

To make this possible, a driver program is needed: mxlpsolve (mxlpsolve.dll or mxlpsolve.mexw32 or mxlpsolve.mexw64 under Windows). This driver must be put in a directory known to MATLAB (specified via File, Set Path or via the MATLAB path command) and MATLAB can call the mxlpsolve solver.
Note that under Windows, the original extension was .dll. Newer versions of MATLAB require extension .mexw32. You can just rename the .dll to .mexw32 for that.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux) (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). This has the advantage that the mxlpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the Windows path.

So note the difference between the MATLAB lpsolve driver that is called mxlpsolve and the lpsolve library that implements the API that is called lpsolve55.

There are also some MATLAB script files (.m) as a quick start.

To test if everything is installed correctly, enter mxlpsolve in the MATLAB command window. If it gives the following, then everything is ok:

mxlpsolve MATLAB Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: [ret1, ret2, ...] = mxlpsolve('functionname', arg1, arg2, ...)

However, if you get the following:

mxlpsolve driver not found !!!
Check if mxlpsolve.dll (or mxlpsolve.mexw32 or mxlpsolve.mexw64) is on your system and in a directory known to MATLAB.
Press enter to see the paths where MATLAB looks for the driver.

Then MATLAB can find the mxlpsolve.m file, but not the mxlpsolve.dll, mxlpsolve.mexw32 or mxlpsolve.mexw64 file. This dll should be in the same directory as the .m file.
Note that under Windows, the original extension was .dll. Newer versions of MATLAB require extension .mexw32. You can just rename the .dll to .mexw32 for that.

If you get the following:

??? Undefined function or variable 'mxlpsolve'.

Then MATLAB cannot find the mxlpsolve.* files. Enter path in the command line to see the MATLAB search path for its files. You can modify this path via File, Set Path. Specify the path where the mxlpsolve.* files are located on your system.

If you get the following (Windows):

??? Failed to initialise lpsolve library. Error

in == > ...\mxlpsolve.dll

Or (Unix/Linux):

liblpsolve55.so: cannot open shared object file: No such file or directory.

Then MATLAB can find the mxlpsolve driver program, but the driver program cannot find the lpsolve library that contains the lpsolve implementation. This library is called lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux.
Under Windows, the lpsolve55.dll file must be in a directory that in the PATH environment variable. This path can be shown via the following command in MATLAB: !PATH
It is common to place this in the WINDOWS\system32 folder.

Under Unix/Linux, the liblpsolve55.so shared library must be either in the directories /lib or /usr/lib or in a directory specified by the LD_LIBRARY_PATH environment variable.

Note that it may also be necessary to restart MATLAB after having put the files in the specified directory. It was noted that MATLAB sometimes doesn't see the newly added files in folders until it is restarted.

All this is developed and tested with MATLAB version 6.0.0.88 Release 12.

Solve an lp model from MATLAB via mxlpsolve

In the following text, >> before the MATLAB commands is the MATLAB prompt. Only the text after >> must be entered.

To call an lpsolve function, the following syntax must be used:

>> [ret1, ret2, ...] = mxlpsolve('functionname', arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between single quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra MATLAB specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in MATLAB, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2 on, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the MATLAB functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from MATLAB, nothing must be dimensioned in advance. The mxlpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to mxlpsolve. Never as argument to the routine. This can be a single value as for get_objective (although MATLAB stores this in a 1x1 matrix) or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

Note that you can get an overview of the available functionnames and their arguments by entering the following in MATLAB:

>> help mxlpsolve

An example

(Note that you can execute this example by entering command per command as shown below or by just entering example1. This will execute example1.m. You can see its contents by entering type example1.m)

>> lp=mxlpsolve('make_lp', 0, 4);
>> mxlpsolve('set_verbose', lp, 3);
>> mxlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
>> mxlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
>> mxlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
>> mxlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
>> mxlpsolve('set_lowbo', lp, 1, 28.6);
>> mxlpsolve('set_lowbo', lp, 4, 18);
>> mxlpsolve('set_upbo', lp, 4, 48.98);
>> mxlpsolve('set_col_name', lp, 1, 'COLONE');
>> mxlpsolve('set_col_name', lp, 2, 'COLTWO');
>> mxlpsolve('set_col_name', lp, 3, 'COLTHREE');
>> mxlpsolve('set_col_name', lp, 4, 'COLFOUR');
>> mxlpsolve('set_row_name', lp, 1, 'THISROW');
>> mxlpsolve('set_row_name', lp, 2, 'THATROW');
>> mxlpsolve('set_row_name', lp, 3, 'LASTROW');
>> mxlpsolve('write_lp', lp, 'a.lp');
>> mxlpsolve('get_mat', lp, 1, 2)

ans =

   78.2600

>> mxlpsolve('solve', lp)

ans =

     0

>> mxlpsolve('get_objective', lp)

ans =

   31.7828

>> mxlpsolve('get_variables', lp)

ans =

   28.6000
         0
         0
   31.8276

>> mxlpsolve('get_constraints', lp)

ans =

   92.3000
    6.8640
  391.2928

Note that there are some commands that return an answer. To see the answer, the command was not terminated with a semicolon (;). If the semicolon is put at the end of a command, the answer is not shown. However it is also possible to write the answer in a variable. For example:

>> obj=mxlpsolve('get_objective', lp)

obj =

   31.7828

Or without echoing on screen:

>> obj=mxlpsolve('get_objective', lp);

The last command will only write the result in variable obj without showing anything on screen. get_variables and get_constraints return a vector with the result. This can also be put in a variable:

>> x=mxlpsolve('get_variables', lp);
>> b=mxlpsolve('get_constraints', lp);

It is always possible to show the contents of a variable by just giving it as command:

>> x

x =
  28.6000
        0
        0
  31.8276

Don't forget to free the handle and its associated memory when you are done:

>> mxlpsolve('delete_lp', lp);

Using model name instead of handle

From driver version 5.5.0.2 on, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
>> lp=mxlpsolve('make_lp', 0, 4);
>> mxlpsolve('set_lp_name', lp, 'mymodel');
>> mxlpsolve('set_verbose', 'mymodel', 3);
>> mxlpsolve('set_obj_fn', 'mymodel', [1, 3, 6.24, 0.1]);
>> mxlpsolve('add_constraint', 'mymodel', [0, 78.26, 0, 2.9], 2, 92.3);
>> mxlpsolve('add_constraint', 'mymodel', [0.24, 0, 11.31, 0], 1, 14.8);
>> mxlpsolve('add_constraint', 'mymodel', [12.68, 0, 0.08, 0.9], 2, 4);
>> mxlpsolve('set_lowbo', 'mymodel', 1, 28.6);
>> mxlpsolve('set_lowbo', 'mymodel', 4, 18);
>> mxlpsolve('set_upbo', 'mymodel', 4, 48.98);
>> mxlpsolve('set_col_name', 'mymodel', 1, 'COLONE');
>> mxlpsolve('set_col_name', 'mymodel', 2, 'COLTWO');
>> mxlpsolve('set_col_name', 'mymodel', 3, 'COLTHREE');
>> mxlpsolve('set_col_name', 'mymodel', 4, 'COLFOUR');
>> mxlpsolve('set_row_name', 'mymodel', 1, 'THISROW');
>> mxlpsolve('set_row_name', 'mymodel', 2, 'THATROW');
>> mxlpsolve('set_row_name', 'mymodel', 3, 'LASTROW');
>> mxlpsolve('write_lp', 'mymodel', 'a.lp');
>> mxlpsolve('get_mat', 'mymodel', 1, 2)

ans =

   78.2600

>> mxlpsolve('solve', 'mymodel')

ans =

     0

>> mxlpsolve('get_objective', 'mymodel')

ans =

   31.7828

>> mxlpsolve('get_variables', 'mymodel')

ans =

   28.6000
         0
         0
   31.8276

>> mxlpsolve('get_constraints', 'mymodel')

ans =

   92.3000
    6.8640
  391.2928

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific MATLAB routine to get the handle from the model name: get_handle.
For example:

>> mxlpsolve('get_handle', 'mymodel')
0

Don't forget to free the handle and its associated memory when you are done:

>> mxlpsolve('delete_lp', 'mymodel')

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

In MATLAB, all numerical data is stored in matrices; even a scalar variable. MATLAB also supports complex numbers (a + b * i with i=SQRT(-1)). mxlpsolve can only work with real numbers. MATLAB also supports sparse matrices. Sparse matrices are matrices where only the non-zero elements are provided and stored. This results in both less storage and faster calculation if there are a sufficient number of zero values in the matrix and there usually are. The mxlpsolve driver supports both dense and sparse matrices and their use is totally transparent to the user. Everywhere a matrix can be provided, it can be dense or sparse. In the above example all matrices were dense. For example:
>> mxlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);

In sparse matrix notation, this can be written:

>> mxlpsolve('add_constraint', lp, sparse([0.24, 0, 11.31, 0]), 1, 14.8);

Most of the time, variables are used to provide the data:

>> mxlpsolve('add_constraint', lp, a1, 1, 14.8);

Where a1 is a matrix variable that can be dense or sparse.

The mxlpsolve driver sees all provided matrices as sparse matrices. mxlpsolve also uses sparse matrices internally and data can be provided sparse via the ex routines. For example add_constraintex. The mxlpsolve driver always uses the ex routines to provide the data to lpsolve. Even if you call from MATLAB the routine names that would require a dense matrix (for example add_constraint), the mxlpsolve driver will always call the sparse version of the routine (for example add_constraintex). This results in the most performing behaviour. Note that if a dense matrix is provided, the dimension must exactly match the dimension that is expected by mxlpsolve. Matrices with too few or too much elements gives an 'invalid vector.' error. Sparse matrices can off course provide less elements (the non provided elements are seen as zero). However if too many elements are provided or an element with a too large index, again an 'invalid vector.' error is raised.

Most of the time, mxlpsolve needs vectors (rows or columns). In all situations, it doesn't matter if the vectors are row or column vectors. The driver accepts them both. For example:

>> mxlpsolve('add_constraint', lp, [0.24; 0; 11.31; 0], 1, 14.8);

Which is a column vector, but it is also accepted.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the MATLAB interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the MATLAB matrix.

Sets

All numerical data is stored in matrices. Alphanumerical data, however, is more difficult to store in matrices. Matrices require that each element has the same size (length) and that is difficult and unpractical for alphanumerical data. In a limited number of lpsolve routines, alphanumerical data is required or returned and in some also multiple elements. An example is set_col_name. For this, MATLAB sets are used. To specify a set of alphanumerical elements, the following notation is used: { 'element1', 'element2', ... }. Note the { and } symbols instead of [ and ] that are used with matrices.

Maximum usage of matrices/sets with mxlpsolve

Because MATLAB is all about matrices, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the mxlpsolve MATLAB driver to also work with matrices. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The mxlpsolve MATLAB driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = mxlpsolve('set_int', lp, column, must_be_int). The matrix version of this call is: return = mxlpsolve('set_int', lp, [must_be_int]). The API call to return the integer status of a variable is: return = mxlpsolve('is_int', lp, column). The matrix version of this call is: [is_int] = mxlpsolve('is_int', lp)
Also note the get_mat and set_mat routines. In MATLAB these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by just entering example2. This will execute example2.m. You can see its contents by entering type example2.m)

>> lp=mxlpsolve('make_lp', 0, 4);
>> mxlpsolve('set_verbose', lp, 3);
>> mxlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
>> mxlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
>> mxlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
>> mxlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
>> mxlpsolve('set_lowbo', lp, [28.6, 0, 0, 18]);
>> mxlpsolve('set_upbo', lp, [Inf, Inf, Inf, 48.98]);
>> mxlpsolve('set_col_name', lp, {'COLONE', 'COLTWO', 'COLTHREE', 'COLFOUR'});
>> mxlpsolve('set_row_name', lp, {'THISROW', 'THATROW', 'LASTROW'});
>> mxlpsolve('write_lp', lp, 'a.lp');
>> mxlpsolve('get_mat', lp)

ans =

         0   78.2600         0    2.9000
    0.2400         0   11.3100         0
   12.6800         0    0.0800    0.9000

>> mxlpsolve('solve', lp)

ans =

     0

>> mxlpsolve('get_objective', lp)

ans =

   31.7828

>> mxlpsolve('get_variables', lp)

ans =

   28.6000
         0
         0
   31.8276

>> mxlpsolve('get_constraints', lp)

ans =

   92.3000
    6.8640
  391.2928

Note the usage of Inf in set_upbo. This stands for 'infinity'. Meaning an infinite upper bound. It is also possible to use -Inf to express minus infinity. This can for example be used to create a free variable.

Starting from driver version 5.5.0.3 in, get_mat can also return the matrix in sparse format. By default the function returns it in dense format for backwards compatibility. However if a 3rd argument is provided that is non-zero, the returned matrix is sparse:

>> mxlpsolve('get_mat', lp, 1)

ans =

   (2,1)       0.2400
   (3,1)      12.6800
   (1,2)      78.2600
   (2,3)      11.3100
   (3,3)       0.0800
   (1,4)       2.9000
   (3,4)       0.9000

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example:

>> A=mxlpsolve('get_mat', lp);
>> X=mxlpsolve('get_variables', lp);
>> B = A * X

B =
   92.3000
    6.8640
  391.2928

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

>> mxlpsolve('get_constraints', lp)

ans =

   92.3000
    6.8640
  391.2928

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

>> C=mxlpsolve('get_obj_fn', lp);
>> X=mxlpsolve('get_variables', lp);
>> obj = C * X

obj =

   31.7828

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

>> mxlpsolve('get_objective', lp)

ans =

   31.7828

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
>> lp=mxlpsolve('make_lp', 0, 4);
>> mxlpsolve('set_verbose', lp, 3);
>> mxlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
>> mxlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
>> mxlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One could define all the possible constants in MATLAB and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

>> lp=mxlpsolve('make_lp', 0, 4);
>> mxlpsolve('set_verbose', lp, 'IMPORTANT');
>> mxlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 'GE', 92.3);
>> mxlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 'LE', 14.8);
>> mxlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 'GE', 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

>> mxlpsolve('set_verbose', lp, 'blabla');
??? BLABLA: Unknown.

>> mxlpsolve('set_verbose', lp, 'GE');
??? GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. 'LE', 'GE' and 'EQ' in add_constraint and is_constr_type can also be '<', '<=', '>', '>=', '='. When returned however, 'GE', 'LE', 'EQ' will be used.

Also in the matrix version of calls, string constants are possible. For example:

>> mxlpsolve('set_constr_type', lp, {'LE', 'EQ', 'GE'});

Some constants can be a combination of multiple constants. For example set_scaling:

>> mxlpsolve('set_scaling', lp, 3+128);

With the string version of constants this can be done as following:

>> mxlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_INTEGERS');

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

>> mxlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_RANGE');
??? SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

>> mxlpsolve('get_scaling', lp)

ans =

   131

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

>> mxlpsolve('return_constants', 1);

From now on, all returned constants are returned as string:

>> mxlpsolve('get_scaling', lp)

ans =

SCALE_MEAN|SCALE_INTEGERS

Also when an array of constants is returned, they are returned as string when return_constants is set:

>> mxlpsolve('get_constr_type', lp)

ans =

    'LE'    'EQ'    'GE'

This for all routines until return_constants is again called with 0:

>> mxlpsolve('return_constants', 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

>> mxlpsolve('return_constants', 1)

ans =

     1

To get the value without setting it, don't provide the second argument:

>> mxlpsolve('return_constants')

ans =

     1

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

M-files

MATLAB can execute a sequence of statements stored in diskfiles. Such files are called "M-files" because they must have the file type of ".m" as the last part of their filename (extension). Much of your work with MATLAB will be in creating and refining M-files. M-files are usually created using your local editor.

M-files can be compared with batch files or scripts. You can put MATLAB commands in them and execute them at any time. The M-file is executed like any other command, by entering its name (without the .m extension).

The mxlpsolve MATLAB distribution contains some example M-files to demonstrate this.

To see the contents of such a file, enter the command 'type filename'. You can also edit these files with your favourite text editor (or notepad).

example1.m

Contains the commands as shown in the first example of this article.

example2.m

Contains the commands as shown in the second example of this article.

example3.m

Contains the commands of a practical example. See further in this article.

example4.m

Contains the commands of a practical example. See further in this article.

example5.m

Contains the commands of a practical example. See further in this article.

example6.m

Contains the commands of a practical example. See further in this article.

lp_solve.m

This script uses the API to create a higher-level function called lp_solve. This function accepts as arguments some matrices and options to create and solve an lp model. See the beginning of the file or type help lp_solve or just lp_solve to see its usage:

 >> help lp_solve
 LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

>> [obj, x]=lp_solve([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])

obj =

     3


x =

     1
     2

lp_maker.m

This script is analog to the lp_solve script and also uses the API to create a higher-level function called lp_maker. This function accepts as arguments some matrices and options to create an lp model. Note that this scripts only creates a model and returns a handle. See the beginning of the file or type help lp_maker or just lp_maker to see its usage:

 >> help lp_maker

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

>> lp=lp_maker([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])

lp =

     0

To solve the model and get the solution:

>> mxlpsolve('solve', lp)

ans =

     0

>> mxlpsolve('get_objective', lp)

ans =

     3

>> mxlpsolve('get_variables', lp)

ans =

     1
     2

Don't forget to free the handle and its associated memory when you are done:

>> mxlpsolve('delete_lp', lp);

lpdemo.m

Contains several examples to build and solve lp models.

ex.m

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

>> X = 0:125;
>> Y1 = (15000 - 120.*X)./210;
>> area(X, Y1)

Source

Now let's put in the other two constraint inequalities.

>> Y2 = max((4000 - 110.*X)./30, 0);
>> Y3 = max(75 - X, 0);
>> Ytop = min([Y1; Y2; Y3]);
>> area(X, Ytop)
>> axis([0 40 0 75])

Source

The blue 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.

>> hold on
>> [U V] = meshgrid(0:40, 0:75);
>> contour(U, V, 143.*U + 60.*V);
>> hold off

Source

The lines give a picture of the objective function. All solutions that intersect with the blue 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 blue 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 lp_solve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:

>> x = [1 1; 110 30] \ [75; 4000]

x =

   21.8750
   53.1250

The acreage that results in the maximum profit is 21.875 for wheat and 53.125 for barley. In that case the profit is:

>> format bank
>> P = [143 60] * x

P =
       6315.63

That is, $6315.63.

Note that these command are in script example3.m

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

>> help lp_maker

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

>> f = [143 60];
>> A = [120 210; 110 30; 1 1];
>> b = [15000; 4000; 75];
>> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
>> solvestat = mxlpsolve('solve', lp)

solvestat =

             0

>> format bank
>> obj = mxlpsolve('get_objective', lp)

obj =

       6315.63

>> format short
>> x = mxlpsolve('get_variables', lp)

x =

   21.8750
   53.1250

>> mxlpsolve('delete_lp', lp);

Note that these command are in script example4.m

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimentions, but beyound that it is all very theorethical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

>> f = [143 60 195];
>> A = [120 210 150.75; 110 30 125; 1 1 1];
>> b = [15000; 4000; 75];
>> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
>> solvestat = mxlpsolve('solve', lp)

solvestat =

     0

>> format bank
>> obj = mxlpsolve('get_objective', lp)

obj =

       6986.84

>> format short
>> x = mxlpsolve('get_variables', lp)

x =

         0
   56.5789
   18.4211

>> mxlpsolve('delete_lp', lp);

Note that these command are in script example5.m

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that MATLAB can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like MATLAB is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
>> f = [110*1.3 30*2.0 125*1.56 75*1.8 95*.95 100*2.25 50*1.35];
>> A = [120 210 150.75 115 186 140 85;
        110 30 125 75 95 100 50;
        1 1 1 1 1 1 1;
        1 -1 0 0 0 0 0;
        0 0 1 0 -2 0 0;
        0 0 0 -1 0 -1 1];

>> b = [55000;40000;400;0;0;0];
>> lp = lp_maker(f, A, b, [-1; -1; -1; -1; -1; -1], [10 10 10 10 20 20 20], [100 Inf 50 Inf Inf 250 Inf], [], 1, 0);
>> solvestat = mxlpsolve('solve', lp)

solvestat =

     0

>> format bank
>> obj = mxlpsolve('get_objective', lp)

obj =

      75398.04

>> format short
>> x = mxlpsolve('get_variables', lp)

x =

   10.0000
   10.0000
   40.0000
   45.6522
   20.0000
  250.0000
   20.0000

>> mxlpsolve('delete_lp', lp);

Note that these command are in script example6.m

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that Inf is used for variables that have no upper limit. This stands for Infinity.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using MATLAB:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into MATLAB format we get:

f = [4 2 1]
A = [2 1 0; 1 0 2; 1 1 1]
b = [1; 2; 1]

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0 0 0]
u = [ 1 1 2]

Now lets enter this in MATLAB:

>> f = [4 2 1];
>> A = [2 1 0; 1 0 2; 1 1 1];
>> b = [1; 2; 1];
>> l = [ 0 0 0];
>> u = [ 1 1 2];

Now solve the linear program using MATLAB: Type the commands

>> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
>> solvestat = mxlpsolve('solve', lp)

solvestat =

     0

>> obj = mxlpsolve('get_objective', lp)

obj =

    2.5000

>> x = mxlpsolve('get_variables', lp)

x =

    0.5000
         0
    0.5000

>> mxlpsolve('delete_lp', lp)

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the MATLAB command:

>> l = [];

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -Inf as lower bounds:

>> l = [-Inf -Inf -Inf];

Solve this and you get a different result:

>> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
>> solvestat = mxlpsolve('solve', lp)

solvestat =

     0

>> obj = mxlpsolve('get_objective', lp)

obj =

    2.6667

>> x = mxlpsolve('get_variables', lp)

x =

    0.6667
   -0.3333
    0.6667

>> mxlpsolve('delete_lp', lp)

Overview of API routines

Note again that the MATLAB command 'help mxlpsolve' gives an overview of all functions that can be called via mxlpsolve with their arguments and return values.

Note that everwhere where lp is used as argument that this can be a handle (lp_handle) or the models name.

  • add_column, add_columnex
    • return = mxlpsolve('add_column', lp, [column])
    • return = mxlpsolve('add_columnex', lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = mxlpsolve('add_constraint', lp, [row], constr_type, rh)
    • return = mxlpsolve('add_constraintex', lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = mxlpsolve('add_SOS', lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in MATLAB since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = mxlpsolve('column_in_lp', lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = mxlpsolve('copy_lp', lp)
    • No special considerations.
  • default_basis
    • mxlpsolve('default_basis', lp)
    • No special considerations.
  • del_column
    • return = mxlpsolve('del_column', lp, column)
    • No special considerations.
  • del_constraint
    • return = mxlpsolve('del_constraint', lp, del_row)
    • No special considerations.
  • delete_lp
    • mxlpsolve('delete_lp', lp)
    • No special considerations.
  • free_lp
    • mxlpsolve('free_lp', lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = mxlpsolve('get_anti_degen', lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = mxlpsolve('get_basis', lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in MATLAB. If not provided, then 0 is used.
  • get_basiscrash
    • return = mxlpsolve('get_basiscrash', lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = mxlpsolve('get_bb_depthlimit', lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = mxlpsolve('get_bb_floorfirst', lp)
    • No special considerations.
  • get_bb_rule
    • return = mxlpsolve('get_bb_rule', lp)
    • No special considerations.
  • get_bounds_tighter
    • return = mxlpsolve('get_bounds_tighter', lp)
    • No special considerations.
  • get_break_at_value
    • return = mxlpsolve('get_break_at_value', lp)
    • No special considerations.
  • get_col_name
    • name = mxlpsolve('get_col_name', lp, column)
    • [names] = mxlpsolve('get_col_name', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_column get_columnex
    • [column, return] = mxlpsolve('get_column', lp, col_nr)
    • [column, return] = mxlpsolve('get_columnex', lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = mxlpsolve('get_constr_type', lp, row)
    • [constr_type] = mxlpsolve('get_constr_type', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_constr_value
    • return = mxlpsolve('get_constr_value', lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = mxlpsolve('get_constraints', lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = mxlpsolve('get_dual_solution', lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In MATLAB, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = mxlpsolve('get_epsb', lp)
    • No special considerations.
  • get_epsd
    • return = mxlpsolve('get_epsd', lp)
    • No special considerations.
  • get_epsel
    • return = mxlpsolve('get_epsel', lp)
    • No special considerations.
  • get_epsint
    • return = mxlpsolve('get_epsint', lp)
    • No special considerations.
  • get_epsperturb
    • return = mxlpsolve('get_epsperturb', lp)
    • No special considerations.
  • get_epspivot
    • return = mxlpsolve('get_epspivot', lp)
    • No special considerations.
  • get_improve
    • return = mxlpsolve('get_improve', lp)
    • No special considerations.
  • get_infinite
    • return = mxlpsolve('get_infinite', lp)
    • No special considerations.
  • get_lowbo
    • return = mxlpsolve('get_lowbo', lp, column)
    • [return] = mxlpsolve('get_lowbo', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_lp_index
    • return = mxlpsolve('get_lp_index', lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = mxlpsolve('get_lp_name', lp)
    • No special considerations.
  • get_mat
    • value = mxlpsolve('get_mat', lp, row, col)
    • [matrix, return] = mxlpsolve('get_mat', lp[, sparse])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix in the first return value. If sparse is different from zero then the returned matrix is a sparse matrix. The return code of the call is the second return value.
  • get_max_level
    • return = mxlpsolve('get_max_level', lp)
    • No special considerations.
  • get_maxpivot
    • return = mxlpsolve('get_maxpivot', lp)
    • No special considerations.
  • get_mip_gap
    • return = mxlpsolve('get_mip_gap', lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = mxlpsolve('get_nameindex', lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = mxlpsolve('get_Ncolumns', lp)
    • No special considerations.
  • get_negrange
    • return = mxlpsolve('get_negrange', lp)
    • No special considerations.
  • get_nonzeros
    • return = mxlpsolve('get_nonzeros', lp)
    • No special considerations.
  • get_Norig_columns
    • return = mxlpsolve('get_Norig_columns', lp)
    • No special considerations.
  • get_Norig_rows
    • return = mxlpsolve('get_Norig_rows', lp)
    • No special considerations.
  • get_Nrows
    • return = mxlpsolve('get_Nrows', lp)
    • No special considerations.
  • get_obj_bound
    • return = mxlpsolve('get_obj_bound', lp)
    • No special considerations.
  • get_objective
    • return = mxlpsolve('get_objective', lp)
    • No special considerations.
  • get_orig_index
    • return = mxlpsolve('get_orig_index', lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = mxlpsolve('get_origcol_name', lp, column)
    • [names] = mxlpsolve('get_origcol_name', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_origrow_name
    • name = mxlpsolve('get_origrow_name', lp, row)
    • [names] = mxlpsolve('get_origrow_name', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_pivoting
    • return = mxlpsolve('get_pivoting', lp)
    • No special considerations.
  • get_presolve
    • return = mxlpsolve('get_presolve', lp)
    • No special considerations.
  • get_presolveloops
    • return = mxlpsolve('get_presolveloops', lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = mxlpsolve('get_primal_solution', lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = mxlpsolve('get_print_sol', lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = mxlpsolve('get_rh', lp, row)
    • [rh] = mxlpsolve('get_rh', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_rh_range
    • return = mxlpsolve('get_rh_range', lp, row)
    • [rh_ranges] = mxlpsolve('get_rh_range', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_row get_rowex
    • [row, return] = mxlpsolve('get_row', lp, row_nr)
    • [row, return] = mxlpsolve('get_rowex', lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In MATLAB, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = mxlpsolve('get_row_name', lp, row)
    • [names] = mxlpsolve('get_row_name', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_scalelimit
    • return = mxlpsolve('get_scalelimit', lp)
    • No special considerations.
  • get_scaling
    • return = mxlpsolve('get_scaling', lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = mxlpsolve('get_sensitivity_obj', lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = mxlpsolve('get_sensitivity_objex', lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that MATLAB allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = mxlpsolve('get_sensitivity_obj', lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, MATLAB always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = mxlpsolve('get_sensitivity_rhs', lp)
    • [duals, dualsfrom, dualstill, return] = mxlpsolve('get_sensitivity_rhsex', lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that MATLAB allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = mxlpsolve('get_sensitivity_rhs', lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = mxlpsolve('get_simplextype', lp)
    • No special considerations.
  • get_solutioncount
    • return = mxlpsolve('get_solutioncount', lp)
    • No special considerations.
  • get_solutionlimit
    • return = mxlpsolve('get_solutionlimit', lp)
    • No special considerations.
  • get_status
    • return = mxlpsolve('get_status', lp)
    • No special considerations.
  • get_statustext
    • return = mxlpsolve('get_statustext', lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = mxlpsolve('get_timeout', lp)
    • No special considerations.
  • get_total_iter
    • return = mxlpsolve('get_total_iter', lp)
    • No special considerations.
  • get_total_nodes
    • return = mxlpsolve('get_total_nodes', lp)
    • No special considerations.
  • get_upbo
    • return = mxlpsolve('get_upbo', lp, column)
    • [upbo] = mxlpsolve('get_upbo', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_var_branch
    • return = mxlpsolve('get_var_branch', lp, column)
    • [var_branch] = mxlpsolve('get_var_branch', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_var_dualresult
    • return = mxlpsolve('get_var_dualresult', lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = mxlpsolve('get_var_primalresult', lp, index)
    • No special considerations.
  • get_var_priority
    • return = mxlpsolve('get_var_priority', lp, column)
    • [var_priority] = mxlpsolve('get_var_priority', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • get_variables
    • [var, return] = mxlpsolve('get_variables', lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = mxlpsolve('get_verbose', lp)
    • No special considerations.
  • get_working_objective
    • return = mxlpsolve('get_working_objective', lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = mxlpsolve('guess_basis', lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In Matlab, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In Matlab, there is no unused element in the matrix.
  • has_BFP
    • return = mxlpsolve('has_BFP', lp)
    • No special considerations.
  • has_XLI
    • return = mxlpsolve('has_XLI', lp)
    • No special considerations.
  • is_add_rowmode
    • return = mxlpsolve('is_add_rowmode', lp)
    • No special considerations.
  • is_anti_degen
    • return = mxlpsolve('is_anti_degen', lp, testmask)
    • No special considerations.
  • is_binary
    • return = mxlpsolve('is_binary', lp, column)
    • [binary] = mxlpsolve('is_binary', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • is_break_at_first
    • return = mxlpsolve('is_break_at_first', lp)
    • No special considerations.
  • is_constr_type
    • return = mxlpsolve('is_constr_type', lp, row, mask)
    • No special considerations.
  • is_debug
    • return = mxlpsolve('is_debug', lp)
    • No special considerations.
  • is_feasible
    • return = mxlpsolve('is_feasible', lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = mxlpsolve('is_free', lp, column)
    • return = mxlpsolve('is_unbounded', lp, column)
    • [free] = mxlpsolve('is_free', lp)
    • [free] = mxlpsolve('is_unbounded', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • is_infinite
    • return = mxlpsolve('is_infinite', lp, value)
    • No special considerations.
  • is_int
    • return = mxlpsolve('is_int', lp, column)
    • [int] = mxlpsolve('is_int', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • is_integerscaling
    • return = mxlpsolve('is_integerscaling', lp)
    • No special considerations.
  • is_maxim
    • return = mxlpsolve('is_maxim', lp)
    • No special considerations.
  • is_nativeBFP
    • return = mxlpsolve('is_nativeBFP', lp)
    • No special considerations.
  • is_nativeXLI
    • return = mxlpsolve('is_nativeXLI', lp)
    • No special considerations.
  • is_negative
    • return = mxlpsolve('is_negative', lp, column)
    • [negative] = mxlpsolve('is_negative', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • is_piv_mode
    • return = mxlpsolve('is_piv_mode', lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = mxlpsolve('is_piv_rule', lp, rule)
    • No special considerations.
  • is_presolve
    • return = mxlpsolve('is_presolve', lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = mxlpsolve('is_scalemode', lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = mxlpsolve('is_scaletype', lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = mxlpsolve('is_semicont', lp, column)
    • [semicont] = mxlpsolve('is_semicont', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • is_SOS_var
    • return = mxlpsolve('is_SOS_var', lp, column)
    • [SOS_var] = mxlpsolve('is_SOS_var', lp)
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a MATLAB matrix.
  • is_trace
    • return = mxlpsolve('is_trace', lp)
    • No special considerations.
  • is_use_names
    • return = mxlpsolve('is_use_names', lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = mxlpsolve('lp_solve_version')
    • The mxlpsolve API routine returns the version information in 4 provided argument variables while the MATLAB version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = mxlpsolve('make_lp', rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • mxlpsolve('print_constraints', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
    • The same information can also be obtained via mxlpsolve('get_constraints', lp). This shows the result on screen.
  • print_debugdump
    • return = mxlpsolve('print_debugdump', lp, filename)
    • No special considerations.
  • print_duals
    • mxlpsolve('print_duals', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
    • The same information can be obtained via mxlpsolve('get_dual_solution', lp). This shows the result on screen.
  • print_lp
    • mxlpsolve('print_lp', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
  • print_objective
    • mxlpsolve('print_objective', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
    • The same information can be obtained via mxlpsolve('get_objective', lp). This shows the result on screen.
  • print_scales
    • mxlpsolve('print_scales', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
  • print_solution
    • mxlpsolve('print_solution', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
    • The same information can also be obtained via mxlpsolve('get_variables', lp). This shows the result on screen.
  • print_str
    • mxlpsolve('print_str', lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
  • print_tableau
    • mxlpsolve('print_tableau', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under MATLAB (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the mxlpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows MATLAB) to the command window of MATLAB. As such, all reported output can be seen in MATLAB. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = mxlpsolve('read_basis', lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = mxlpsolve('read_freemps', filename {, options})
    • lp_handle = mxlpsolve('read_freeMPS', filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In MATLAB it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = mxlpsolve('read_lp', filename {, verbose {, lp_name}})
    • lp_handle = mxlpsolve('read_LP', filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In MATLAB it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ('').
  • read_mps, read_MPS
    • lp_handle = mxlpsolve('read_mps', filename {, options})
    • lp_handle = mxlpsolve('read_MPS', filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In MATLAB it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = mxlpsolve('read_params', lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = mxlpsolve('read_XLI', xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, '' (NULL) is taken. '' is taken as NULL.
    • options is optional. When not provided, '' is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • mxlpsolve('set_basisvar', lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = mxlpsolve('set_add_rowmode', lp, turnon)
    • No special considerations.
  • set_anti_degen
    • mxlpsolve('set_anti_degen', lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = mxlpsolve('set_basis', lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In MATLAB, there is no unused element in the matrix.
  • set_basiscrash
    • mxlpsolve('set_basiscrash', lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • mxlpsolve('set_bb_depthlimit', lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • mxlpsolve('set_bb_floorfirst', lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • mxlpsolve('set_bb_rule', lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = mxlpsolve('set_BFP', lp, filename)
    • No special considerations.
  • set_binary
    • return = mxlpsolve('set_binary', lp, column, must_be_bin)
    • return = mxlpsolve('set_binary', lp, [must_be_bin])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = mxlpsolve('set_bounds', lp, column, lower, upper)
    • return = mxlpsolve('set_bounds', lp, [lower], [upper])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • mxlpsolve('set_bounds_tighter', lp, tighten)
    • No special considerations.
  • set_break_at_first
    • mxlpsolve('set_break_at_first', lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • mxlpsolve('set_break_at_value', lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = mxlpsolve('set_col_name', lp, column, name)
    • return = mxlpsolve('set_col_name', lp, [names])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_column, set_columnex
    • return = mxlpsolve('set_column', lp, col_no, [column])
    • return = mxlpsolve('set_columnex', lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = mxlpsolve('set_constr_type', lp, row, con_type)
    • return = mxlpsolve('set_constr_type', lp, [con_type])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • mxlpsolve('set_debug', lp, debug)
    • No special considerations.
  • set_epsb
    • mxlpsolve('set_epsb', lp, epsb)
    • No special considerations.
  • set_epsd
    • mxlpsolve('set_epsd', lp, epsd)
    • No special considerations.
  • set_epsel
    • mxlpsolve('set_epsel', lp, epsel)
    • No special considerations.
  • set_epsint
    • mxlpsolve('set_epsint', lp, epsint)
    • No special considerations.
  • set_epslevel
    • mxlpsolve('set_epslevel', lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • mxlpsolve('set_epsperturb', lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • mxlpsolve('set_epspivot', lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = mxlpsolve('set_free', lp, column)
    • return = mxlpsolve('set_unbounded', lp, column)
    • No special considerations.
  • set_improve
    • mxlpsolve('set_improve', lp, improve)
    • No special considerations.
  • set_infinite
    • mxlpsolve('set_infinite', lp, infinite)
    • No special considerations.
  • set_int
    • return = mxlpsolve('set_int', lp, column, must_be_int)
    • return = mxlpsolve('set_int', lp, [must_be_int])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = mxlpsolve('set_lowbo', lp, column, value)
    • return = mxlpsolve('set_lowbo', lp, [values])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = mxlpsolve('set_lp_name', lp, name)
    • In MATLAB, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = mxlpsolve('set_mat', lp, row, column, value)
    • return = mxlpsolve('set_mat', lp, [matrix])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. Consider using a MATLAB sparse matrix for maximum performance and least memory usage. The matrix must be two-dimentional.
  • set_maxim
    • mxlpsolve('set_maxim', lp)
    • No special considerations.
  • set_maxpivot
    • mxlpsolve('set_maxpivot', max_num_inv)
    • No special considerations.
  • set_minim
    • mxlpsolve('set_minim', lp)
    • No special considerations.
  • set_mip_gap
    • mxlpsolve('set_mip_gap', lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • mxlpsolve('set_negrange', negrange)
    • No special considerations.
  • set_obj
    • return = mxlpsolve('set_obj', lp, column, value)
    • return = mxlpsolve('set_obj', lp, [values])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • mxlpsolve('set_obj_bound', lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = mxlpsolve('set_obj_fn', lp, [row])
    • return = mxlpsolve('set_obj_fnex', lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In MATLAB, there is no unused element in the matrix.
  • set_outputfile
    • return = mxlpsolve('set_outputfile', lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In MATLAB under Windows, output to stdout it not shown. However it results in closing the file. Use '' to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • mxlpsolve('set_pivoting', lp, pivoting)
    • No special considerations.
  • set_preferdual
    • mxlpsolve('set_preferdual', lp, dodual)
    • No special considerations.
  • set_presolve
    • mxlpsolve('set_presolve', lp, do_presolve {, maxloops})
    • The maxloops argument is optional in MATLAB. If not provided, then infinite is used.
  • set_print_sol
    • mxlpsolve('set_print_sol', lp, print_sol)
    • No special considerations.
  • set_rh
    • return = mxlpsolve('set_rh', lp, row, value)
    • return = mxlpsolve('set_rh', lp, [values])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = mxlpsolve('set_rh_range', lp, row, deltavalue)
    • return = mxlpsolve('set_rh_range', lp, [deltavalues])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • mxlpsolve('set_rh_vec', lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In MATLAB, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = mxlpsolve('set_row', lp, row_no, [row])
    • return = mxlpsolve('set_rowex', lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In MATLAB, there is no unused element in the matrix.
  • set_row_name
    • return = mxlpsolve('set_row_name', lp, row, name)
    • return = mxlpsolve('set_row_name', lp, [names])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_scalelimit
    • mxlpsolve('set_scalelimit', lp, scalelimit)
    • No special considerations.
  • set_scaling
    • mxlpsolve('set_scaling', lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = mxlpsolve('set_semicont', lp, column, must_be_sc)
    • return = mxlpsolve('set_semicont', lp, [must_be_sc])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • mxlpsolve('set_sense', lp, maximize)
    • No special considerations.
  • set_simplextype
    • mxlpsolve('set_simplextype', lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • mxlpsolve('set_solutionlimit', lp, simplextype)
    • No special considerations.
  • set_timeout
    • mxlpsolve('set_timeout', lp, sectimeout)
    • No special considerations.
  • set_trace
    • mxlpsolve('set_trace', lp, trace)
    • No special considerations.
  • set_upbo
    • return = mxlpsolve('set_upbo', lp, column, value)
    • return = mxlpsolve('set_upbo', lp, [values])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • mxlpsolve('set_use_names', lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = mxlpsolve('set_var_branch', lp, column, branch_mode)
    • return = mxlpsolve('set_var_branch', lp, [branch_mode])
    • In MATLAB, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = mxlpsolve('set_var_weights', lp, [weights])
    • No special considerations.
  • set_verbose
    • mxlpsolve('set_verbose', lp, verbose)
    • No special considerations.
  • set_XLI
    • return = mxlpsolve('set_XLI', lp, filename)
    • No special considerations.
  • solve
    • result = mxlpsolve('solve', lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = mxlpsolve('time_elapsed', lp)
    • No special considerations.
  • unscale
    • mxlpsolve('unscale', lp)
    • No special considerations.
  • write_basis
    • mxlpsolve('write_basis', lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = mxlpsolve('write_freemps', lp, filename)
    • return = mxlpsolve('write_freeMPS', lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In MATLAB it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = mxlpsolve('write_lp', lp, filename)
    • return = mxlpsolve('write_LP', lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In MATLAB it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = mxlpsolve('write_mps', lp, filename)
    • return = mxlpsolve('write_MPS', lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In MATLAB it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = mxlpsolve('write_XLI', lp, filename {, options {, results}})
    • No special considerations.

Extra MATLAB routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = mxlpsolve('get_col_names', lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = mxlpsolve('get_constr_types', lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = mxlpsolve('get_int', lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = mxlpsolve('get_no_cols', lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = mxlpsolve('get_no_rows', lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = mxlpsolve('get_objective_name', lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = mxlpsolve('get_obj_fn', lp)
    [row_vec, return] = mxlpsolve('get_obj_fun', lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = mxlpsolve('get_problem_name', lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = mxlpsolve('get_reduced_costs', lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = mxlpsolve('get_row_names', lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = mxlpsolve('get_solution', lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = mxlpsolve('mat_elm', lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = mxlpsolve('print_handle')
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = mxlpsolve('read_lp_file', filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = mxlpsolve('get_handle', lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = mxlpsolve('return_constants'[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the mxlpsolve driver

Windows

Under Windows, the mxlpsolve MATLAB driver is a dll: mxlpsolve.dll or mxlpsolve.mexw32 or mxlpsolve.mexw64
This dll is an interface to the lpsolve55.dll lpsolve dll that contains the implementation of lp_solve. lpsolve55.dll is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip). The mxlpsolve MATLAB driver dll is just a wrapper between MATLAB and lp_solve to translate the input/output to/from MATLAB and the lp_solve library.
Note that under Windows, the original extension was .dll. Newer versions of MATLAB require extension .mexw32. You can just rename the .dll to .mexw32 for that.
See also External Interfaces/API, MATLAB

Also the library lp_explicit.lib is needed. The lp_explicit.lib file is a wrapper library between the lp_solve dll and the compiled application. This wrapper is needed because the lp_solve dll uses __stdcall calling convention. There seems to be a problem in MATLAB to call __stdcall functions directly (unexpected crashes). The lp_explicit library uses __cdecl calling convention and this then calls the lp_solve dll which uses __stdcall calling convention. Looks a bit complex, but it works without any problem.

There appears to be another way to compile MATLAB mex files with gcc for Windows. This is not tested. See Compiling Matlab mex files with gcc for Windows.

Unix/Linux

Under Unix/Linux, the mxlpsolve MATLAB driver is a shared library. The resulting file has a platform-dependent extension, as shown in the table below:

    sol2, SunOS 5.x - .mexsol
    hpux            - .mexhpux
    hp700           - .mexhp7
    ibm_rs          - .mexrs6
    sgi             - .mexsg
    alpha           - .mexaxp
    glnx86          - .mexglx
    Mac OS X        - .mexmac

This shared library is an interface to the lpsolve55.so lpsolve shared library that contains the implementation of lp_solve. lpsolve55.so is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.tar.gz). The mxlpsolve MATLAB driver library is just a wrapper between MATLAB and lp_solve to translate the input/output to/from MATLAB and the lp_solve library.

All platforms

The mxlpsolve MATLAB driver is written in C. To compile this code, the MATLAB compiler is needed (mex). This compiler must be called from MATLAB. MATLAB may also need to be configured to find the C compiler. For this, enter the following in the MATLAB command windows and follow the instructions: mex -setup

To make the compilation process easier, a makefile can be used: Makefile.m
Enter 'help Makefile' from the MATLAB command window to see a list of options.
It may be necessary to edit this file first to change the path where lp_solve is installed. Change at the beginning lpsolvepath.
To make for release, just enter Makefile and everything is build.
This compiles three source files: lpsolve.c, matlab.c and hash.c
The optional arguments to Makefile are used for development. The first argument allows specifying a filename so that only this file is build. For example hash.c should only be compiled once while developing. So specifying 'lpsolve.c' as first argument will only compile this file and then link everything. This makes the build process a bit faster. The second argument is by default 0. When set to 1, then extra argument checking is done and while executing, some debug information is printed. Should only be used for debugging purposes. When released, this parameter should be 0. The third argument is by default 1. When set to 0, the makefile will not ask to press enter to start building.

See also Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./MATLAB1.jpg000666 000000 000000 00000073757 10251321656 011134 0ustar00000000 000000 JFIFExifII*1&i.Picasa0220 !|b5720b911cbe459c0000000000000000R980100 (HHJFIFC  !"$"$C" L !1AQ"7SVaru2q#BRTU$346CDcEbts6 !14qr23AQRS"abB ?҈4ø2Jk| w%=֥,rmhԚ5^f&&Z䄦¸7 r=;HLӉEE8HB}X[w)qo:C9̅)Q%+ <](/C{i BcAso]DX}@mj+) pt7:Z+޹5YL !JF|TZTBnlnj0.v`\UPMzRX(-r,"9yfko쪻5FF z SXśYgij-a>qiR F`,$6_;GZX.R\Ȳ=PukmeokՊS~x*۪{½5OxWc&pD v-]q oIZUd:n8$Eխ:E԰.q?h篶g~UT{0jz,*˼D.K L QVu Mu G8O-EbU`c/BF`{:e~ 'V*MAT{1Ʃ b܏?;^ceUTSX{½]r+~ӹw ~7NUWLi3) 31DӺ[KZ@$L0њA4VJJ+ LkYI:xlI,(C$Xo|<2V?lyU|,x* sIKL)2z_6T!jr]Yؕ7abm`yE.&*MKK Btv <mf) }LVgr2Sq4N:,*؞1VE3p-q׍],1PCb?9ʙ2ir9ԔQ 5@Cc3 *uҏIzV:us ()d):{)Cclr]e 4`Sb(h[KN\  iP'g1Dܴ2a8IJqISlrn{sDwbݔcSa:VJRu+rnOMQGB.ܱIxYg8]Hړ3nkm\BU$[b/clM$kƛl6_ZZIJH6%*\m`\̊O]*]Rm0@- JHS2*U*\6\T{ix nU~1cp~(g9Ru%KmLS3V:ʒ{]$_vizE2ms[AQaT!4!(J  mh+;+) ܄9iVe" clJ3/,]Є8RA;l5&2k*|@i8v6&;w1a|g(M%]q!JJ R.6cɉ əyLڹzkVsYN8oaKu6)G\ZYV)3,]Q֦W*Z%*#Rm¼K끚.'Wp 38mť ?w*ީ G$̥,T6떅}WXˎ2eŶؤpA {- Dv'b?|,I!cE9rua\|!zڕ9qaQpjaa:Ӊ BР$\Fu= 9t)ZxY DADADADADA[ 8$$ 7# Rj$a Y )g{ڏǾD[ΣSnв'{700oSn!HZzRE{dqmJH- IA6@$ \ZYV)ꉣSYS"ʚMqJl sn6]>ULbb] IHh ܛ $s&ju#W~ :1.ZLLS29&\oQ=Ϙ{nn1 s6Db? W0N^"mttUN#C`OybΞu2Ǔpx9E+/"D>8 `:cݪ&"2&mĦAj D8Bpw{Cl)g{ڏǾD[ΣSnв'{702 )&t 7c#kK}jJ珙ZV\|#%uA[<@(P'r6zz"r!.vVBpw{Ch,{Qȋtzz~\c.7ߠ¾Rw~o KbniT?$#*QRD6*؁Q.T䳹/tZmBhĀmx?5~(;H#*!xDA" ^A/~ɬy_[t9$ӝ7fa ײhA!*rYx^iaLϡvGM0w"AP?]NfsVOx*!WZa GYxR@vJ~QAcT8)'I؍Te0UR_(؝Tلʂeɨ~hp~c'&H|;eT_hA//rG v0ުa?cf:G\4Fm1%1&astԩzJ%B#ݲ*/|y}>PU۶ 6R=|^_xE-^;\9Oz\0eYZ,QQT7:7>zJp"http://ns.adobe.com/xap/1.0/  $(#"8*!%&,*+.2:'>/(-' *!0'''''((''''''.'''''''''''''''''''''''''''''''''''R !"14RSt23AQ#TqrBa$5CcDUbu%=123QR!A"aq#CSB$4 ?l*]87^n |W/ՉF_U[b`Ջ7e'?5VvSُ,ttEN9]Co7q&Q7yTUIj9Ҭ4WCq΃5M1wF}):s4CAqh;Q> tj9ҚcG8SLt4ѨJi5M44ѨJi5M1wF}):s4CAqh;Q> tj9ҚcG8SLt4ѨJi5M1wF}):s4CAqh;Q> tj9ҚcG8SLt4ѨJi5M1wF}):s4CCms%cLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4Ѩ;SLt4,M=|-1J3H˸Lpy7*|I"m[Y(S6z:ǧgUW;?WcOqzQTZ,B0{f~ָfoDDu?lDžkZ{bISg=#~es4Zaصdzm S*WD׋,w|@/Yc%":jsMN/C/ckŲ5EJևO!"&~"17|3xs22Yy m,Kl6ap`߻߉IiĢ't[wN_#%n){A +s#l.n3Z3_44Uiܥ*|$l)<5\7ՖӉTDt_ rыD1ix}U{c hk[u8aڶ<ވ6#U#tN~tC\.}Ƚm\:5p朕soRhSLb XW2iLsnk~0 nE1o3"?W7z譃hĴDR^#N' {?SgssNS𧥿< ~i=m\8g:D 5 i&_~;SGj,TdXS%Sё#pv8'zm*3赧|~jcej‹.*blՅJ,̨T $Li018߾KXbZޝ :0f쮹qK.)b,\rf,\RqK,\RqK,\RqK,\RqK.)b,\r.\RˊXqK.)bA0xQMbl-0*QՒHwVR]+qgP .5\pFGG 7q;ǀo2Ģg-xM?70ygN՞)8_fM*2[f(kZցpkELɹla`L)ߧ%5U@Kts|{|1W\F,Ļ0j/L6GeQhTfi{\7o=ovpbj^89\Q Qz{9Տ-/FhKjǬXTpbFJ[h(XZo_x"]ux8zZrcEO-{"J YJy&:()!$4qF %  G+mx?j1o]|iÈfHf:ƾ5 xO46JޝTWUU?Vaŭ%5H$Rɧ}DYo1.a/ITWMV[u0vQ3[-$Bǀ׃݈le?g_֌F?]a:· (dˈ4XO<kdӏoiIp=%_n]f 6|G$\ٔ۞q7_dbaU+M$M +[+##kË\KYsn;5DEsyŪnv#+̆yZ .7ZY9׍~+zY0 }j2B$!j2Bɨj2B$!j2B$!j2B$!j2B0gQd5! FHCQd5! FHCQd5,l#fL༲w"H?׉M3kO[`Wl:e+liŇhX(`t-ۜ qVW!Ջx)q&Y'ǽ.>FQ|o@[Šc||O&lCdG%CK} ;&8'bG{HZ&_i]MvW-IN>ď(몞.gZY,D+Gpi+u`l3U>Vi4 yXב4ψ<э #y ,WU}#qu1i0-u4Fz)%:3OYvm CtO!w_<~q30f%3MuSB>'Zmǫr޸p6?Jͨx UscMFb;YTK=鼢zyoOgݏ'ޖc?M===N|?ʟSOg;*x1?fgic)wT{=(ޖoSis)wT{='ޖoSis)wT{=(ޖoSis)wT{='ޒoSyswT{='ޒoSyswT{='ޒoSyswT{='ޒoSys)wT{=z&>vs)wT{=(ޒoSys)wT{=(ޒoSyg)սg+ZXN`$qm_naM0RQ>;4ݳZܪ^i}dm{L-:ˆ|]^[4Mɤ&߆8xdX8j &J6|;?4_յh\ZYCx9|X7)vC{:kS _ԭU,cw5k5{G-ʲ̨ʪyT`lvE3D]{twxu0,ZAZ(-l/`qkenCq Ľ"--.>1Wӗ +c 0渴@'f9 ij35US#皢c<:WT1`7 H* ]igQ⊈f1I[$m_F@/qKOaޕ)j7Ak@&cc%|KN@<#%3`h Sa^ٷuUDN =v9q \\7}5{ȃg0*)iihk 8~-%M]m--U{2%& f\9ċr#M fZ#|tD88=h7BSFbӠv:DH%u[7%y=XpɥwQBYb`Tludq$29߭X[9Gë3lg#C'~e[#kk107]7\<#~%Y} j_5-%s/i " M-M qI#+-*FW4V2"|{ ๷K}"A4!{ a"As{n~ް{B,FBt.M5SiFs&@z`_WU)j7Ak@&cc%|KN@<#%3`h Sa^Ѵ!gJ{:6ϓ ɦd^iV]m3䴩OΚ kvxkQ{qh *ێȎZmZg|,0PYN'jf!gw X}i]Pj|]Jn.IND7TT 7.񰦒eSW[KKU^̺`IY+{0;{nq"\ꊺZVBnkьЁ7HKZӸqxuC5GO P 6^-#wpihQ\ )e24T1\e= ۘIqE´%Ϩ 2Z[xkOQ$$1\I׺ωK "uZT巑҇TK͠:^#"s'F_ͩfUaiTQqֽdSKYUN%s\C.c]%36s69s\#t s[u6OQ%'4-#ٱ[m%Pdo9q8{ѽ{GOFb"(b}DMtC=-+cdF ;"p]ȕ?g$8c9Xܖb`).๬cZ@ *Ni,ZDmbTZl88k<2\Zۮ;f"lML׾% F֗pٰO ]\L̈b78M77yZGTX fmu@!a/sFm?qzυX31φ&:,9.,66kHhD2zz3dE M#>Opsmdtllж;!E,n7\8#wŤ(,IC b&q 'R>禚V:6i/{pRDjeu=L%Je,Nǽzh6Fe$.nٱBӳvMy=A?g2V׶Px&H=%׌NBw/qRsOb#m{ cgGs\ 08q1-<gTUTH_K+DrQcJCUץ0ϖSqE,U9cm=ؚw n+?}&C켘iy!\,޻%/E3b%/E3/%ؗKELKcd&v%6J^/gb^Cd&v%6J^/gb^K?v|Vbdv>dD)ph}ǜQ.^"DŽ}4:zI1 W^/->O;J^GKELXKELKl_Dļ6J^/gb^Cd&v%6J^/gb^Cd&v%6J^/gb^Cd&v%6J^/gb^Cd&v%䱲RQ};>ccu)}l_DļKELKl_DļKELKcd&v%䱲RQ};%/E3/!RQ};%/E3/!RQ};%/E3/!RQ};%/E3/!RQ};%/E3/!RQ};%/E3/!RQ};%/E3/!RQ};%/E3/!RQ};%/E3/!RQ};%/E3/"/IiCZ[@Y"6S巑zQcJCUץ0ϖ9/~M?On*8hx.ZVp(cm: M|TMMFMD9΁.K nb\6jS-+5K2SEM455#eЙ5)όh!,D{*Ldl3acdҰ}1A-tОg2-9#մQK饕Cj۲.53{1k-\uSF'{w5#.\޾D妱k* s#J=sk!-s\8 DZ1iskcwmSZ//`8yhn3U6"ZbKm]"qsf<Zk1=][MEF>I] JD6:ۄ y<.5 xdAiΙiSZQ#@بDCM'_zFVϹݗl˗9VN ͟+; #F*+ic)'Ks_M<3q]׉V`Jʊ*g%H);fEf|,7n⛟`]-38cu}L*is寁mKOS9:<4 # +h+mJzYce-d:ZG<]O'>E&#y/rԴ㡊ͬ]$A[ 9u.'wܽPŖ 2z /j >:H慮<&6IZXxxu}sS>?r%_5c]hJ+YIpGbdn}>Bo&] UwdٱYe vub&cx$NI&3qk~ȶ*'uMK4JJx⩕5 v+tuQ5WD]]TZTUUD] NH=?/ y Zk:ςv2ck49i .+?vTvͭu4U$sE$#M/PA k']H iȂgZg` ) 7H !hs\޾DÊްU` pVqXq7Ƒ6Z7`Uh}m% -mTUDŽ6;˜ֵkpff-*f2Y;tpvY.k\7;uS6a6z:Ш2ϓ]l#xhu_yf2:O^l-.sjk*H@*;s{#9݉uaXb726f\ kui݄p MS{ՆU}3I mMqpIGx.spq]776)-7EieYL7wG1K#\&n%yRY*:t"2bŋ.*u8)6Hspw:Q`p!Q0i׈Ѓ#SE\@@ALJ+TOȫ}vFGf/c^Bm}wCkqE- ߃]w ٳ-Z L!e-jkdmc^넲 A?c[=^z߬k} [o@ay~l/=o5 Ʒ۠u{A =Q`p"5Q0i׈Ѓ#SD\@@@@AfR># @@@Ao:7rC(=Lr/X.|F~]͛hɃfŗx7FJ*ֲ_V AXM>(m&p",f&iWЍ74WP%eͨq<"sq!kWV̡d@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AIf$Yxj3v/ϑaLUwh#GWn[yu(q%CUץϔ9~DjOa-oG:K@c(bp݄6.w߿?8=CMm/ggǗw_ufUG5&[fZu4ZVtx]9x Af2cjU0]qQi b4.lL}c$. yp$̅yyzjjWZb Οrlq _Wչmyԡ9 W^¬v>Q`pB#U*m}2qg1:#aq -vA ss21/^iޒ;c[^D+po{\suS4ͥ2A`VteLuޭo#Υ?1jc?ɇLE:"VBʽ 'seُl2W~-p {6\O^fL80_v+px fUG5&D ҫcDmu3C_0m2hy"AzpwWj~Ѝ74WP%eͨq<"sq!r`զ7Y,+:}G]SAĀ:u}^oV巑RPz5]z_S \EG[~"B Ms !ѯʚԑ|IGtx^()JIXa7݄>l3lf͈gohɿ>}aqoAYחU·x:Nƚ+JΑO G#xx AH7j1PYS@ueiIekW=̎1yt5-X=\psYL}czjj I@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AIm.}>Ƕ~?˜r>Ż@@@Ao:7rC(=Lr/X.|DjOa-oG חU·x TEQie;J)˘U6᤟{ ;SGIi1k㑡{s^ n R%z !vNy[GJ~ Acu}L*is#U*mx}2Q`p"5Q0i׈Ѓ#SD\@@@@Akˎa[j# @@@Ao:7rC(=Lr/X.|DjOa-oGlٶk*hDs1{# @@@Ao:7rC(=Lr/X.|DjOa-oG חU·x,%VɝeK|g:yq> n8\ 8@7I{ Mlok*CIhp7qWVQ`p"5Q0i߈Ѓ#SD\@@@@Akˎa[j"T8z1p0A gid0ٖkY' % %W>!j=+:}G]SAĀ:u}^oV巑RPz5]z_S \EG[~"B Ms ! M-<lQD)*,flnέ1Ҹ.q^c[6e8F~_v|]w_vyqٿ_+}G.sgdp{Z9x(pĦiw3t k@h\=sY͙VS]۪H U(: gx9ٜ|@@@Ao:7rC(=Lr/X.|DjOa-oGƪ ֈp⑲FwyƟރa}2ŋ3fǂ|;ߋǽg.;7o972% bWӵ)]5b@A8Iq;B;&=i-jPpiY6X&n&=DqA Anfv, Οrlq _Wչmyԡ9 W^¬v>Q`p"5Q0i߈Ѓ#SD\@@@@Akˎa[j6x/^[cOI)Ժ6%7a@l~EA ``׃V4LJĢd@@@@@@@@@@@@@@@@@AYB:2$#z-:8!U,Fqw4 xopr+SmX) pp 3>15>QYcit-&k-2DH@]x 0N{< rؘuaզMtȀ܄u/:dH#GWn[yu(q%CUץ0ϔXTxL?e- 0d~*V#s"]Bulv f w 7]x֒ ZٌPX CaG;.K\1JsY,LǧTЀ܄u/:dH#GWn[yu(q%CUץ0ϔXTxL?e- 0d~*V#s"]By-,ĿB] &X6UΑH&7]8IfyLίoO'ԫ^># @@@Ao:7rC(=Lr/X.|DjOa-oG]Ѣԧ{LL& f\d/cg$9-ݍwCdٰő-1߃݋w7^\voW dsQndK@ ,LDu]oɷl]J@ /M0au{e &Gv v#efcG Afv, N[>H6}mg3?šO~/Žy[GJ~ Acu}L*is#U*m}2@3 mnm]{ǹll{Vחs6~f߇uP5fUG5&D &魧"6xndyu )Ǧ/tg Kmm3_i"@dтp8oë5Bx׆D># @@@Ao:7rC(=Lr/X.|DjOa-oG חU·x%sH=ֲ_Vn d$bFizSiꚬ+lٚkͪ;fĒn; M؃\fXyۺ># @@@Ao:7rC(=Lr/X.|DjOa-oG חU·x=!Zg6xH5{ ko ̣§5G16nڨuthΑDTD1u.Xs[Cg~wj+uU)># @@@Ao:7rC(=Lr/X.|DjOa-oGEk$sA{{KyN84س3Cqx\\[e~*V#s"]Bbb5kYqXvtMs[%,Wp7@bs13^KM}_Rۆ;J͑3q1#An QM3iJX># @@@Ao:7rC(=Lr/X.|DjOa-oGmAYu_.É' 6 w6Ņ߅g ߊȗP@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AlНa[z 4/J}r0q1뷷A\3:O?PNQimj684Nbkx 0}9l*k* n(Rtkc$EO_m0<#qo>G[ܶC!/q=>[s6nߊȗP@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A3ZUlhͮ&ssK㼘f M <\8H ZYb=w{]>XCӗ]CK渑};eki55]}ZB Οrlq _Wչmyԡ9 W^¬v>Q`p"5Q0i߈Ѓ#SD\@@@@Akˎa[j# @@@Ao:7rC(=Lr/X.|DjOa-oG8L>vϵ{NvvF ;u ^\voW dsQndK@ N|Rwa$:cupkqrl1cU>=245v4V"X %δiK]q7aW:j7I(G[ܶ|^<3h>/bg4AWGzzϟO3 +=gϋا{wޞS=ƈ;OY)yDtw{|^<3h>/bg4AWGzzϟO3 +=gϋا{wޞS=ƈ;OY)yDtw{|^<3h>/bg4AWGzzϟO3 +=gϋا{wޞS=ƈ;OY)yDtw{|^<3h>/bg4AWGzzϟO3 +=gϋا{wޞS=ƈ;OY)yDtw{|^<3he{ɕ5drV@&㉆-|l&7E1ŮȀ:u}^oV巑RPz5]z_S \EG[~"B Ms !c[6e8F~_v|]w_vJȳRu>פuhKL:z%+*0T[|r.h!Ym%1CdWfC 66&`D7]PXW]I{U=_AV\#&}v ;ͳ{Nݽ/:Wd݇ŹţafkCefO+/yMh͒As/:Bs.w}K=\tu4&emE=A_8].5/@%ESǃUtlFGt̎6 kր7&PG[ܶŢ\'5 ] ӹs}؝uכ]e7幭֘H{Z)pdZMhiA,&-b7戤I`c\qdc EqhHACbY3Úyj֒ L`- zH*]B$f0A~ڰyyfbřc~>oށIu< }-Y"[0=\Z04\Z.h#*t~Ϋbg:M,G9Һblx>1_p7u:7g9"j/kɵg Ac 8Kqa%x%$,m=;pK$9qI$I$A쀀:u}^oV巑RPz5]z_S \EG[~"B Ms !uޭo#Υ?1jcS4o{A㭢.ad _Wչmyԡ9 W^¬v>Q`pBc&L9ņ<''zUg;N$^ůN_mt^>;VFcA;VuߓFcA;S^4f;l~5ߓFcA;S^4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5ߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;ܭl~5lߓFcA;SV4f;l~5lߓFcA;SV4f;ܭl~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5ߓFcA;S^4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5ߓFcA;SV4f;l~5lߓFcA;SV4f;l~5ߓFcA;SV4f;l~5ߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcA;SV4f;l~5lߓFcQEZ>j{#\ A{\."ۊF.΢uSOZj[_`Z?G55T|bzvw35RÚi./MATLAB2.jpg000666 000000 000000 00000070674 10251322120 011113 0ustar00000000 000000 JFIFFExifII*1&i.Picasa0220 !|c3dd58ad53a92e7e0000000000000000R980100 (#HHJFIFC  !"$"$C" M !1"7AQ2RTUaqruBV#6$34C%5Dcd8 !134Qqr2RS"Aa#B ?PʱIUruHZvXT-B[)3K+CUrI Nk ~(xX j/᪍Vrzw-yJPRU%Z!Ƨ|LíW֙RKN\eƒ҂VR NP%7ERj`:;]Ci\X݌@&<8TAզ(N*0&8}֬Z㥾3 h΋5:)=ZӊuPu%i$ fāsFXuB,Mu@".yjlҗz*}U{g7S}?h+̩̇Z QQX_$I:M`IrIzbaiIA<]߿vWUvg5w϶`uN_Lvrm)jZ֕es\H-NpCIMAzpݕ;9OEBﺧ}f T著lƉZ6M:&\()bsv$DŽucXOFX,+岼Dsuj0CvU+xwfw[x9}f T﹏lƦ)ڣӗaL޵,+=ٝ';sك};c1 `>SG.|:vgu9gCk,˶FV66hJ9&e*dJ+CN qe$"گrKoKEm *=Q4IFQikTH{/4c>WX1HԪ%U]B2+Rٙؤ_ҕ&FEeuNe6'X _Ukf%AaiUY*}Co®whz(eaMZo kרǂ\P_ ;n!6T($i1f!;v+"bU-GVQٺc5Kou]*Ukx]Y RX6a{)lpG2ik2jjbH^֚u][1/t|KOHJgɕX<İ%feKϴ+K)$x"A޽%AȫeHׄ8r:Хk,jcﭘᅲزUiCvwl?g}ŗV Hל[NJʫ:sXnjrG'[1/eU[1/u\\EXKIW%}9>Blyrcᅲز*ӭᅲ❕I95Aj]ݘ9PrlЈ<~+eⷃ/-W;99y%B8|dCh-0qyQȋrT=E6틗DXGW'8ou]}ܝ[KKkR@WlckKLeb_4݃z-7z6.yb#SL(Mﶈ6VE:W{ Lj"'p1XJg|aAQ."Y%*ګg(1uQ!2+o^U$dZE=Wՙ15Irlj(KosH_cUhH/I-$ q+_mVPZ<2~z<6rbNmfm-5'V^=]Ħdr2]`)l[ACRI8M $L80+ 8n-w$&?2{ƛqsDܑV1ͪb5^  |q\tTLD"xDĐnqj%R=m/j>{nCJ9ݱr蓋7pТ @\vB8~o ,bYwpA";X7`.g a*NU`f[6WTZDX~a ITJ:׽k   Igߖ}8ͫ2mE*Ik8E4OOxgRSd+w!3hO:]GĻߜmɁ=+Jv%:$'T,r(A<9-!AĎh0SNSԭMXp<;]P1.O) P@5#VA.鏆= 0"LQNH"I/j>{!KL^|>2"܆xsQGͻb'8ojJV%)H$FX'8o@)%$\";X7`JcARi{! )e͒m/Ve5lc(RRzfRQr䀐v [coq+cĈ : " "#]eaմk Bl!\|A B~]"ԤJfe[*(ymjܩQ7[j2Eq75Ay DD>y0MmO:ITjN|q\tT"–8|dCh-0q{QȋrT=E6틗DXGgTRڔ$w,蓋7pZZd]s+-OAMJ`Zq $.qz nI-Ra?E~PxG\DADADADo*aJ٫T-FꘕPl>i1D⡣MkLfIµ86s$x'KZ>!t!>"?V)%ZLfFué7 J9 B>PA_DA5+jK.;ydqt(\܍CiȇuGL|5F"R=m/j>{nCJ9ݱr蓋7pb*r6կ :$ =4֖yľi%LiV/ FjEԔ`f7[6HڦuF9m.8~o I X¾8~o 1Ew2/nSP&):+e,nR[Jl;Hڋs 6TҨv"Ām;v %_ScĈ \wIoۭW OAq'!~iDAtXOB҈ >tXu}b > J"/&i b3K':,lmc7h|?(>eZMҤqNK _݄z5[J@y\y997RJ+yvqT{o >GlA6icZ5x6O)J$w5xS/È(B"(R=m!KL^|>2"Y *棏vˢN,pߣDV9btؚCo6e]% Ԙ쏃|.z#d[$7͆H.w*(aM kTw`>]ǔwl)$)̕\e.l3Oڟ'k-G=7=ELkwd}?]H:O|FG# d|s!znS 3M2% 8%NQ Ƚs!o|FG;# d|!znS td}#<%ё7=A`G`3^ӧw? `%)@b}?]H[쏃|0z#doD{5黁N&N%ёbɦL )t̔ȷ.`M!# d|!MznS CӝLi2a3ô|N%ё7=A`G`3^d!@ 0F%%&]D7kTʭIe"7> }vF= צ;h~a1RDЦˉң3&;m `oD{#L9YtdfqIt*mE)9LCs#G+ 2E"http://ns.adobe.com/xap/1.0/  '(*%$;,#'),,8!=61+A(78*  *%6--**---*-****-*****-******-*****-*********--**-**S !"14Qt23ARUr#Saq$B%TbCe5Ddu;123!QRAa"BSbq$4C ?ˋ:gvf"ѷ*wlQݢ:qO1GQzKYzL sI?/T^rwiwy_pN? NI}8ty_pN?$촞WO;-'bN}8ty_pN?$촞WO;-'bNI}8ty_pN?$켞WO;/'bN}8ty_pN?$켾WO;//bN}8t_pN?$켾WO;//bN}8t_pN?$켾WO;//bN}8t_pN?$켾WO;//bN}8ty_pN?%e:~ ;/'ny<'vN}8tv^O+ çݓy_pN?읗p7d켞WO'e:~ ;/'nk UcC y/\mv˂.myMܦuoMUq[Ou_ģʟcC4msW16 Z c {_f%71ĢioxM8pکmLE{C)qikB^SrN˨%om?z>h* Gq5 \^R۽Lջ]=:ZQQNg=vH/_bqLU~P;_UJ/K\zj& e.]{1֑p ,lvVzgYwtsHNh}s:l\9q7/k?|A~w !tv5Ĺ5cZXD~l;Gs&{\I[߸[.rv 9Nm\:&f]&߹4 n k$ E㹷*_}Dޮ6b3\~kp&vMUROx`dzfj-8QTDcjŊk,xp7EQAO3DIYv~ $E/Sܹ1i̍634Ѻ]O d[u0Hɵ^+8?)[QtMUg݉WU[Yؘ$c\"\oz_bn3b4']کNV2>ScI$8.s]flG:v"&j4g1}{-Z""sIÍcyqĽ\<ޣߧ6wnK/wEO]4ϖC.2j$dXy[R&SOIvb`su,nQ+s9̱t/1'X+ :ݢ}ZFj `aPPE>5K#|x"8\n, knj.ܦ1zmۊP6VhLdY0LdY0LdY0LdY0LdY0LdY0LdY0Ld 0R0:wE4gQw!inqj]KEoQD#1d{ڿ5ы_X-U[0y/]i i V?ey]QU67ɷDՉ{M`*O6ub3UUqh 05&mU0` nU]g?2žgͫNZxQYۛ< sObwE8oʫ n)5W.;.?tډUzQ‹jUE+ǽV) >* ѷ$[6.Wz.LtMT‹R$ޮu&m`Yim+-nkUU"e؃ݭ&$ kcm9֒ ixƿgjE>:6ѷ:^xOh%^"ܮq bl_!]5M5TMQ? eES$ك8W8zFʺU zӟtbMXk {+媻5-k۽4@9| :1iݪ}Ի~5CLh(Lig 樌>YLlubb{~=ٻr-!> 2:LJG\׹BgL8qߍnU"b"j=Tz14{nE07*d4Ե2lVTl+l&f\϶1#3/=F^j;*%{Ac.I1 uh-ju4ƣ" dtl3 K#/ Ei'Җ aƆ).`wf憭Fbzv35[ESn-E+I'ƫSLE4. P;'[?J ?hTq|-k\|ـP|}_)M1TuVSU1}d綾|n؏R}d=u;b'֓%kWQOI֧lʣsZhD 6 ^)v))*\12wm'K/|>WQONku}WQONku}WQONku|}WWONku}WQONku}WQONku}WQONku}WQONku}WQONku}WQONku}WQONku}WQONku}WQONku}WQONku8wm'K'?rx}d?r;?I|Nx}ds_+#Y/wm'K'?r;?I|Nx}ds_+#Y/wm'K'?r;?IO ԉ0Cf^On3Vݧ;S91%=;ӵ SP h)WM{:I9. H6^[L3e%ڣ.bZ6#&flh$DDzڗ6[L1%tDvJQ?ϦU c ͆1yEڸk\]MkjimNiYVqGI$sZܒ5 s&0m~,dɂR`02jfQƒf "kZFP ߐ[ ?{/K6։Z)amfDA{n.cx`lEvY^aW\$j2ZG 1i')t2I.k}SKCrT>Af#ڟ28ZD6 CɐM2O1$ܸ%3#*q!koc,M&N$%Ǐv,28qk9k^Zr9/c]n sA~p G-4؜>-dSAQIQDs+*5solyRhtNhi.qmHP !:2>2;k0l(Li̯vG;X<A 3"Maf;A6 EI$ kddS6gI <^v?bp 2=،ԒG,TȨI'ExyLeŴh# <:(ÁAc2<[!WU 9c F|奱D2mٰ,FL%, C&ei,a`2&eM  #_ #^$V:X$m|OdqclX|>[1"٣UJjX%.6SAQGPL&qe!aX+4FYF9d5kAY+ˮ\Nk7MQEi雕Ē\$I$I$,F7!oG T75=:_W ik6-~G7R/T=T:.Z}aO'dupj?:t]նiYdյԸu=T}-d02=`&f<iijLD,[7ê+pwFydG՗73n2ew &QUaH[OS+!sY<%d29{c14r#pȱQLL(YqYaVP4acdcpc #dbl-KOfv4ݑZ iq~r*A;)*䧂X爢sָ:V:ܞ1ΙV`toiq*)P5Kn8/;llmb:٤Y`3=k $־-!pgq1vH` H21Tb *+i{aD(vI e(㭍_ZA-sb H ARKNoY"0nMa5UthL=m:;$5zNr,U4aZHZM S~b)*1IO5<LjZ6 FXVw;ƫjQi;EIW>i6."9v-U." Kb3U5-gk3J[u2KKN\꣙c^286E1/9mЂW-=Lz;Sɕf0l&jݢoCD~eyeKNoY" =06P5vg [mb~YaoLJ-ڝP#%z=) c㻆VG>gل65{C9ik ^Yw@@@@@@@@@@@@@@@A܆~G-7%Pc}\*hyg*FOEum7=-.ZVp+4, :,k-qmrqpJC#aԵOSyǫ٣x.ݦi1U18/;Hq[N-2Y-rpns|٧S"?BpxeáK(O+C\O8j}ت߅VoL x{s*9AdO*1,)>?6+MF)_Q%&Zi$bI,5ozXr8ЯOVřB}SԯspS2'+[1-i {taS=&<-k&&hp{#eX܁xj3T<,#~W-7% !UJ+ܣM̶Zh_W2G\~jP6KV;C(vB/r72hA}\@@@@Ah4UnEe-zl2J60H3nA7U=o؇vC[!P*iT#A?u]o巣Rd5=:_W iEc{x)B ukVB ;RbQS>9̨F&{X;cɀ;`Xճ}v[Wr ^{eĂv]sqkr5h nεMj V3ٱWI+G2:+%CmfqX[*]]p}e3IM#'=A6q &= u#˜j"ifeisp7[En%vfTӹcDZ{\.5an?OԊ=Q߸_ߔ;k8>ڃty+ޏJݒc}\*hyEQaf[[4}կY<[LHsv20[aODo}f_6_6{|;nw. mh˩,޾LK&~OKFn<ٳezF^^pm?101d#HkclH~1vr(Wt"ty+ޏJݒc}\*hyEQaf[{4}կY5V\xW eyѫP@@@@@^fjL38[4L s["Xs;,25O9Uvma4{wR33I/[%lE+3?0U7U;=Ep?tZG*#كIlܸ dN|`/kUUQ8%W@@@@@@@@@@@@@@@@@@@@@@@@@@@@A]B:nd#GU[z?5(ovJqCSӥp6;!Gчm!Vad [q5_+}G_F]B\26I!$Otr2򠽧z1T=D6nQIh4-ͿYH =~` EUSo$-ɣGEq9-4ˀD9fTQU*Uy>#A?u]o巣Rd5=:_W iEc{x)B ukB UU·^Duj {QC#jhd[|DG#.9^pH* {wLd쵸NJ\yˆFѐ_?k\l9^u+H[Lh4s>*b٣<`v߈KrvBHl+}GMWL~?<ߕoG Cn1jztc<Ҋd"(Sz03-ք>̬D4͉VQEPIZTI(eM<-&GрrKCQ][7e{ :{j׶]H+q5_+}G_F]Bxetl9{ǵůcn5h nW,v1T3 kpw+u ~)lָsQ6WK>i76;] ngL[4g3nnZI?OԊ=Q߸_ߔ;k8>ڃty+ޏJݒc}\*hyEQaf[[4}կY#JzkkhZnsp7o}f_6_6{|;nw.#A?u]o巣Rd5=:_W iEc{x)B ukB UU·^Duj 5tK_Ӻ*Gm-clј*$o KlUNhI#(u\"&P뷈[0m/XK@Ȁ܄t/t1G\~jP6KV;C(vB/r72hA}\@@@@ArjV+ȎXPvW@DZ{Z9s\6Gr7"i4M" ťUR-{OLlkiu$k 6R{Wt"ty+ޏJݒc}\*hyEQaf[[4}կY)l-TatšdtP 0f݂وuޱ;+f춯|Wo}mW˳ww.6?u]o巣Rd5=:_W iEc{x)B ukBi6y{>6[ a)+Yͽͬ_7oǵˏa[":5b9Aww9su78˛/ە#w rp @@@A:7rC{Pیr/X4<ތ?oos !ˏa[":5b9AETbvY!F؀v(oڋM}_F*fQ#v6֊$n[Oo'qWmͺ6"rQ !7 ]2 D#~W-7% !UJ+ܣM̶Zh_W0jܸ#V.`'ěC9 v{sk=ں|#->\awO_b WGmԡ(m9 ON¬vQX^ oFeЃGZg5\ˈwk~o mU·^Duj ݋"ff'73eSqH.Ņ+Y52ى-D>#A?u]o巣Rd5=:_W iEc{x)B ukB NV ':5t|sh$Z%1"-rj,f3nLJW}uth{gs,1TdbC\Jzn%;NR.a8Dz}proSLy> ŷA~?<ߕoG Cn1jztc<Ҋd"(Sz03-ք>,% 5p݋vC{þ>?R_ k8kmܸ#V.} j`&1lncE0?$~M6.OĶ)ewO_b WGmԡ(m9 ON¬vQX^ oFeЃGZUnLJW}uOj1X1gcoyiݲFemfkIUCOƷtN%2{ֽc8]k pwO_b WGmԡ(m9 ON¬vQX^ oFeЃGZUnLJW}uv[p5Ğ, H\CslblW%4b)0j@@@@@@@@@@A]B:nd#GU[z?5(ovJqCSӥpV;!Gчm Vad è)de%MD1&\>f6Y3nnA;)M~||F,vq ۹q5_+}G_F]Bn ˂М#dnlvR kE#ƵV"^K tR ci2B@yňB.Q6j6"r^Wt"ty+ޏJݒc}\*hyEQaf[{4}կY+XW6Zi&DTVP ?Mcw. ŷA~?<ߕoG Cn1jztc<Ҋd"(Sz03-ք>,u]5TIc˒WKS^Eʼn'bbݐԳ_ŗZ>$w.?+L !7 ]2 D#~W-7% !UJ+ܣM̶Zh_W0jܸ#V.1/Ҷc4 *^DXa >JVE hcA\A'͋ئs >#A?u]o巣Rd5=:_W iEc{x)B ukBnǶ ~f+4XMf3WM˫r_7ٯDZˏa[":5b't'Hb,cӻdqۄ6֓īo1KH&eK=;={1p\0Ar- rp @@@A:7rC{Pیr/X4<ތ?oos !kIqILEU<&Hj],`@Ak4x8Nk^;=Gb]ol|YﭪKv LJW}up-)8J>"C}%/$ciecnG_3%=mU^ Uz&z/wQ}lPw@@@A:7rC{Pیr/X4<ތ?oos !ˏa[":5b3plN\NX$l[A-pH$x֮_4S8=CTqqfK^plٰq4L-+}GMWL~?<ߕoG Cn1jztc<Ҋd"(Sz03-ք>,w.Y{k/W2n_7b wU·^Duj ]$Ӣw5ndU%g|";盒ma Zjix?˚L !7 ]2 D#~W-7% !UJ+ܣM̶Zh_W0B14Ua;:3j֓6c΂}GVo^5]_ {[.$ܸ#V./5SF%һicWUQG#K,NW:mquw'e٦:~aЀUD}pޒoSL9FųA~?<ߕoG Cn1jztc<Ҋd"(Sz03-ք>,w.#A?u]o巣Rd5=:_W iEc{x)B ukB7g>Y{k/W2n_7b wU·^Dw:5b9A ǢKc/E6is H M\e;6Z9xGQW_D3*Xױc=k .}+wO_b WGmԡ(m9 ON¬vQX^ oFeЃGZv+Xmf7ίگo :7F[Y[:}EV*11WطǎOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOSOS$܅C{ Q[aOQF ܻWDzI%I$uK^D:C[`nH+KI5FsK(mD|e&( ! /:lَVC3]ͮ5;z7{-#]* ۩Āda 77+I%5|D meT5|NW59ً }m]KI-,=3ƹ`O aUZ Ga캪J`.cLe=. A?3y>WDzI%I$uK^D:C[`nH#GU[z?5(ovJqCSӥpV;!Gчm Vad 3i:~ QϮϛ. kv @@@@@@@@A6h h c|wxg d7y,#XK.;V呆ֶ! i6 x+* |uQ8FֱdL\Źfc@ 3i:~ QϮϛ. kv @@@@@@@A_D꼮hیЖ6\条rX؀M<8t55G7c^jTShkSu jzm߼vٍynSOM1xTBڱfwc^jTSho;lƼ7Pm߼vٍynSOM15M*}fwc^jTShkSu jzmٍmך>?xTBڞG7c^jTShkSu jzmٝmך>?xTBڞGc~f5橺O=6o;lƼ7P߼vٍynSOM15M*}f7c^jTShkSu jzm߼vٍynSX?xTBڳc~f5橺O=6o;lƼ7P߼vٍynSOM15M*}f7c^jTShkSu jzmٝmך>?xTBڞGc~f5橺O=6o;lƼ7Pzm߼vٍynSY?xTBڱfwc^jTV}6o;lƼ7P߼vٍynSOM15M*}c~f5橺O=6o;lƼ7P߼Lf)) a"8m^[*<7jJϹ T3as$xl7B3. O[vfidi./MATLAB3.jpg000666 000000 000000 00000103313 10251321502 011102 0ustar00000000 000000 JFIFExifII*1&i.Picasa0220 !|7506101048b70d7c0000000000000000R980100 (xHHJFIFC  !"$"$C" M !1AQ"6RTUaqt27Vu#BCb3cr$%&5S8 !134QRqr"2ASBa# ?ةjJ6Mrd_uk_q&։FP4qE12Z.f% {_ L ^RzrErZt #V'S{RtV6q)iJ)u\il(&ַ@彤+>4w1A l֎K~ä MMMinE =YM\KOj͗;[1AP-rYNJFfe} &l' ZDpvȼP\N,Sr8Mg`&fNSo.h>ѯRԶ#Y|aBku٩Lu,)ے|׾]U|jg X-.BJhQ3*i'k7 oם8`, m`a>PAל{[sq:Ɋ?S@]uU0uSƦ}?̡ʜ}7Æ*cZTʒ^Mr<_ZQp I@uU=y뺧Lfx϶b{`\ %Eo W\ ;J`?`Qm*yYrWBPn.ԦW-{7^^N#"z٪bFR10 D{"c@}#$dl-jBЧ luy8,z$u6E]'*eJG0TF#"*G1W Oڃ)u{QP#jȎçAٔ1W !#cn~O}Oچf*{cD=1|۵2o qݸlz' 螢D,M, h-LN#z\ w ][Yf]ɇsieR4I:f!;;nѱ*JgI7SreԖ]+̇7.Y\ǞpVm16*R6S鄺/)T:[ML1`K:+M?Gg_`f!;;۾16D*t >4,wy m)$y2D{H?FMV%VR %!E\ e<]f!;;Jҕ@E;&˕RnQ&Y?ٟdx$7VS#?Gg_bK(QrUuʆfǔ#b/%_+)\ogΨRA~\\CrwVS-0jRݔh3s[,S,%\ mbB$(ZJ0u9P $t$ ;~<ė iCvwVGΟ~JuO3hkZU_VZQƤvJME@5 OMN_AI1%1jÕKeyFlm||M.?JjLeY~]ۈ<@G3?Ixtobs#}cy9ͬ*6x!G>”Q uWbzdiX@bIDJ 7̫*xߞk/hLuәR)(;>[=&O[fhZȤh q&X8L~h-v;j䫮Sl52y9b/FxCkϦK V$O /rCvqq<ΨDR?udRM F'yGl5:D;xL4Q>sFm*6mۊQxOQkfV[qRH{nn螢D.'tF3M.PwT-^rz蚕C!P,H([([Q1u)Sԟn?E)IPwuD7PAP#iT,QAJ?k$؀#!ci}V`j"mBkaw0zJ{rLw(pq.7 /QtTv}iTJ;vBdgқ  Šz~6 LG/24(ym]*IЈ ?ZPMμT$ w@+\s O8k >h}ZHqa|Qk"6`.o qnRǢz]42./%ʹm鶐螢D.E'tF3M.PTTj_cV/%sR_2~| .UjU2&2ױ"G{ F1YI,mAU掠P E ʁ1PEI "ղ#2wqѬe&Ǥ@mF i-8\ Pf[eolư3HZ{_-b^SyyŽq6=LTe4%]K<ٲZMҡy w%ӱ |\8#P`jHۘ0Uj0_=.%E }\tkH-KxҕK}(K+?W25Gz1ʧyGl4:D;h}ZH?KTl۷螢D.)!I)PKݑCw.ظ?GGȦwq>/vG|7{b+/ 틃t{M}nQC 6lVn%%$^I@쀔YhX kOd~P퉃t{.5G}h'cOd~QO~p|vV_=Aাr(օN˟i2jlHyO7b^}?^0Wo|vV_Aাr(|yTc"藑`9-K7z/aza&ؘ?ʫG<E=^2䌒yM,DZ~MhW}?^0|vU_Aাr($$@#3JM3-VGˉBŌ'U_AY~ȣ&D\|VF ͳb\lLe6pWgUm>yىIzQcTf cC0B"http://ns.adobe.com/xap/1.0/    $#,.!$%,(,-1,&0.(4& &2)'''&'&'&''&'&&''&'&'&&&&&&&&&&&&&&&&&&&&&&&&&&&&Y  !1"2AQRq45Us#BSatu$3%TbrCDed=1Q!3A24BRa"#qbCSr$ ?u6` 盹 sSsr4CWjwwSh?Q%39cwE.W k2'Xb ڷzob_=ZvTt1'V_Pʎ$j+QĞ[}B;*:ի|GeGCzobOV IվW#=ZvTt1'V_Pʎ$j+QĞ[}B;*:ի|GeGCzob_}[vTt1'v_Pʎ$n+QĞ}B;*:ջ|GeGCzobOV IݾW#=[vTt1'v_Pʎ$n+QĞ}B;*:ջ|GeGCzobOV Kv_PΎ=Zvtt6վW#OV zomի|GgGCl[}B;::dj+'V_PΎ=Zvtt6վW#R ]}TPʶ-۬5V"`5B \m6U1>θuc_FqOy}h.MW 1[QI]Ht$k[j3V۔M9w)u#19l=D2)5̧nlyJg[LQ3sVFwg:O/RcSTOGLڙ!ZQkbt:ry256Jvuc:Zg-s4iN`o%EO'*-31VB<~/L],y-ٝ\#{}2(-evjۻ`7^0zֲͶsKsm}_drU@ mBۡys礪lQEHĶkk")f:#~r9 Id_nBlg]{B;~qM񮇔n{ޗCbnW}H(nx@4k*sxܥ=~VXY/(޹M{Qpu,xVi$#oݝUVbc}aƷgF4tuºuep_F6nRx4]'1Ly1$DMoFԲV]{Pk`zlS4SL.}f+PN(b}dF'35yDinϒq FfE6unA #޺hoTދ UGZRnj||ƿ[:hɧ-p_[ʹ{K]нoî>sSWƊf컩;5kVܶTFkiv-.~_ݩrvhYţ}y}wmMF-\ۢjpˆTCmҝf2c~>Ph .ԍy˚֯OMbyzNf0FHi #`40FHi #`40FHi #M#M#M#M#M#M#M#M#M$UҘF|+=ӟ֯՚<Ε!EuSkV';kj#Vm5ecB5S4Џ/8ػۋSoDә6¶y;ֺ֤C;gVMtk5]:#}a>UvOM%i5zWrhpb]W]c4TO{z馻~\ɉU6VAӎx|vmS;s?c\Loڳ~ {.z<'u\C1G&i֪j5X se|nUڈz bms/"aYB{Pg[f&"%VJE85pf9:鑒 ŃnUU1c{G6}}F*ayVr2;~%bӥ,Xs˙S_⟶beSMʦ4btL GaU.ؙ%MMT4kjwWSLm;gb:lG(lU Ey= tP i̿=i;MUvq/jlі)$F]Yߌ=UUDU|R11qXQeF4'^%v*5aSr"9WFqqqqqqqqqqqqqqs          E\1WzeFƯ& lMC1x|l:iSWToK!ڛ!QE[ 5H)ڎHQoUcsOGz7f:Q&eo1j#jҹ;RYl Z+FZ29U6WF&cgXoMQX[M{ۅbYڵ ^]R۾vSVF'E_y\*c#1h ۔RN%1SXND|ދEUL{際^i滗t*Ϗr]u*|h|^ 4nsQDW)<;RBi|AgY<*{O+w21M]T?|ބtOj{26ayl'&«Jmu^״k&4|640K v0M]Oc \OЏt=WSi.#+]t0KC5u=6q>RB>#M]Oc \OЏt=QaKzj{m?|ބ|EkO)w{.']Gv髩aKzj{m?|ބ|GkO)w{.'IC5u=6q>VBGv髩aKzj{m?|ބ|GkO+w{.'Gv髩aKzj{m?|ބ|GkO+w{.'Gv髩aKzj{m?|ބ|GkO+w{.'Gv髩aKzja?Kzj=6q>RBOv0ڟKC5S)w{j~.#;]t{mO|ބ|Gkc \OЏt=Qa?Kzj=6q>RB>#MG.']Gv0ڟK {u]*͝`Aq[W]wU]I宜'VsL;"Uz#4&W?Ư}_@éN&D$Z+#S鬺ڝ9fg 7kLoݍ]@lǗ.g+3Tqm?1Wj[GcAЁU9[yLyaVX̲[pM-gåݏ%'S4*jͿަ涘Vzw˶~mJ.jU(w u*/t p!Ś1ڿvrgtg(磻{Jχg:KmhmOR.-)PRUt5!]x7Mm@ƿ1:J&U);O2kU]\gP5Km7L (K2k)׆,bڱn$9)Ӝʜ!̫ 6}5r2r+Ȥ^>jk{TgVSFmI{nߛV+omQeLCicZ`XŨh̻G7;Ħ K E:Kr(RD"Na\VG{;Vw:(NE45V~M6SJ*[&6 ~ F>RU]l@ F0&c1!$drV—߬ͩQ+>)cx7GJ݌n2 jm{/Nc~(JpeL멀-cX}ȷqn{2X ߺӸq dnd%&lDjEcvΪxvVwN=;x  z[iv%Zz/6㶧{/n@a`WbZ2:J]j7YePtok(pBwwY cfe[eUv5c]3Kpe*z׫IעxWvo}5d5֭"ڍ\EVUs&llv^kɳ~8<'kSr;!-7IfRY[kygMkՓڇ`K 18B?G ju铐 k˦yxȠWuSv*tL.7)\Z3U]}v VJdgD,5UUMV"E;7wM`8̌)Awk rY.I> QaK]^ƻի!<QUFEcVb6[UJZn{HJoM`a:5,Zw8|=ګɨ*튤T+ ̤]#2]ĥjVЏ}RPMT`fM26mmYUՌvV/ú[v.iùt'^&% z&ΦƿM1q].[o}A\ӈ#A'q7`\cqj^-w[U)6vVCV\ R 2G)U8vn9Y',t%{m;ʿ-93ֽxӓgvpxON֧w93#:BZݱ=Uݏo/U&im,5$g1(kq,Y*l p/g]NչZ1Uu Љ/N#_UġUž]1+BRֻsH`9qsFxG!9n0pϜzQ;>sFxG!9n0pϜzQ;>sFxG!9n0pϜzQ" 0 lds 5ɇJ78Cgr=(`9qכw fVɣ='W=+Pʧ#Sv"IkƏ]Յю\ޢ*3GCv³'hf|  ZUi!Jg}.L!=igmݞ3Ʀa Ղ{krA9VM$Bd<ͣȧiZkVxP.EW]DǘoDrΑP+좗(U@ 22LM8X)Vqk*n6Pp1ўZﲵsatGzlFWG2+DAJY/uOUk&P^V}:u)mf9N͠ S%WMqv8bh|:ӞL`I&)FyȺbV.70x7hu"eLfQ+9&f.]L͟v=2%O}Z6 J) qdݳV֮ͽ^6.U5Se4]4=ala]Vȁ m fΪױ[jYūRe:0Ѓe2sbuOUk&PmcSn]z]+kv+@{Xyyy9=NFNNUm8/uv-kƬ: xk[isO{A2(@¼-CFDnXr֊X\]F𦋷u 77]dҍ`fl6adkёbVPUd*,O;/h&EHWUw p`5è%:fJfDmf5 N:s <Тs1@[.d9+˫R`°: fgu'QxRu<ͫG6}n䔮6_Hokv[^I,R_lR# [Y e܉S6Yy)i,,ƻfW~e{eժ]{&!!r 6[*VYF&^LuKպuV<(5krn[w'=wmLEEʿ#hQg KiӑTb| iS?ĘNǓHEDE X(o;yuIͱVFFxuW)ֶ礲'Oioc{V4j rkK1lf-e|#ZI Qi˹ kۍŢ_lY'kz]TX/gYXѴ Qh?{6vLuBƼ|n  J(k&3)gbuOUkh[6x^)%2,9Wb 5 #:N hy0[; >%G^AV6ؤn(@5U9!=%Ϻi?}ٴrTTWMKT5:gJV/;jP˕iVjE"Q9:D,ul+emfSţx% ;샧VAkSrg11kľl,Y4n}GPn$ NԺڶVY2)bѼUAӫP@ 5L(c&i͘^ߜAHJ'T_feWJvfFn6£Kh̝UZըpVBZ׿5wFd]}6f66%ZedeY}Ufjq*YĆfg\dJRUDE QTh9A1Jҝh,3'hdU`uj -V5ytfP_.Wvƭc[{F54 `wG7PZ*"DE 4UUb.ZՋ*hJ׌È8mfخϓJd3\"^Жv"j/r7w#t0gHI+?o\pOթ>ygR9=ت0?#~Bc^SvƚHn)mנ}=8X'Ra#dć<1!O)~0Hq_#dć<1!O)~0H 'uLbE Vq_$bCRa'F$8/2yKbCRa'F$8/2yKbCRa'F$8/U 4UU'EP$HRa#dć<1&N2yKbCRa'F$O)~0Hq_#dć<1!O)~0Hq_#dć<1!O)~0Hq_#dć<1!O)~0Hq_#dć<1!O)~0Hq_#dĈdkT.@:?=Z ^`n瞲y#7/8sYe069ӿs}N}Z ^sn瞞y7/8sYe069ӿs}N}Z ^sn瞞y7/8sYe069ӿs}N}Z ^sn瞞y㓿7/8sge06_5Yy`iFvV2c1"Ƨ^@<ߦ6`=`oOv7鍧X;?Ǜlci61g~̀yLm?z<ߦ6`k@h`No ?퍡~y,;}_%ֵck!ZʅBUDm g~͒yLm?z<ߦ6`=`oOv7鍧X;?Ǜlci61g~́]phk_ x廽{1g~̀yLm?C孈>|;@n!d^y taJcf͹KFFܶ6U`5Ѓ$JJ$/1%ci61g~́9.^6W{_c@z<ߦ6`=`oOv7鍧X;?Ǜlci61g~̀yLm?aĹZ}6[-z6j_AΨfGķe Uݣ_heٺk{립̖ Νu8?xRu<ͭ~*)bٿo`L [ujUԫeeaVSȍ Bbplކw6{n5zY>2'. ʨ|72X59vV핎v6FHPe'@:#5p'1gfWuu_[oWr-o#e:crXbq+&ٔd(Kk[ɫwUA$L&9! ̰>mrbl*"9 J3Qg`@@@t5_lV—۬秞mh 5NVh~YL' @@@>·=117l_z Fgсlfظu%}J22}nFȹlDsN˙ӵ1)0ܶ[rFL=\WWrf95mu~K1.sh[QSzW8a%<&[Sgh:?s' ZٺgiTO +t]8ħR10yO R ˡV   AHX;'2&CkZl*""4ʨpI`@@@@@@@@@@@@fb/;r[YH՝}׻,oDdK6ϑ*l<s&5Zg恸s/!CL ߹^j'S}]>]g/9YO<Qj9N|fJѭu]Zu'yiPEUN(v5ܒqFFhB{ꮹ H LO4Cws21X-sM`Ӻzu~A  huF_8e'ڧt] m<+M|Gu:Anzйc3h| 7W+#2dԕ?(?"[UTnC98]9FYEp'8ΦV&Jm 7u:G#ϑFUFDs06Q[rj. BZoW]S$eMXgm&n,R[{w{]F[n5Ђ*J&|$ QzltÉe+ e9,սx7` G:w~WIWOWYKm|O6rw+=)/2HYq5Wh̚bǛM 4Wj W[guiͱ^|ǫW{RNDVT>CNmf\VBk8SQc~WzUM'& nwEq.&eK}y;*֏.0'2fijl$ n*^*+)[({]ut1,W~K RڜeV 5Aee%H&Q1\ nիuWGRYO"4$iNkʱlf%Ŭ {%nVkc9ax7` G:w~WIWOWYKΌ9<ͭ~*)'9h_o|pjb%]s110j czjuESTEt gljc_f=˧wSPu:jJ Gj~2{v:۸w~ܣ[Mp;nbfTבQӻbێh2rjiJ@@<;חBm}) ro7sԷ2 w2%3]ȶ Tee:` D3Afw#Ub#i*ARYYt*! LN;၃bX0m7/إ˪KXmV j\2m%%~co,@@@t5_lV—۬秞mh 5NVh~YL' @@@@@=Ч:zvG1;%]5M3T^?_7Sl( el{ǰCf=K$FMkKW~heL:E?&+Tsӎ^@uW*QF=$-]ǣ)CnMy oW`866jQ8U ygP[ە+5lfQP%M^J }TUΤw+S s֋lFWGP"4 % `mmǬ ձ \G-{ uʚ&Ź]TՊg?VUz-ӭ\\k>5EcDި wUאc9-WnqTaNR9ZHl{rf*+Dﺪ*yԎjaNcz:22Fd x7` G:w~WIWOWYKm|6rwx4?, pS_o|?U:IF>/կk\h}>&*l(#NRj0f'2b@@@@@@@@@@@[O9]q\,cVmltbØ`t Qw4\L<6ި52\׿=O6= wPjx=3kcMίA[[7i. |k;ƉQ@6*ﮫ pnZ؜r4Y7 ks0# ̬g}ZG%я6JKsY߹^j'S}]>]g/9YO<Qj9N|;4{Ou}W\z$%twCO_xfY^k5JA}?X=`nҶ{{틧WQ<,ܙsݣs6]n)5ܶPTG"G/1{OEv pbS,Nâ`<~ٹ4/s d@@@@@@@@@@ccR{+w=r2|1Y5PjYOF|*. ΁fs~ydNtug=]g/9YO<Qj9N|nNl_M'kopwupƩW5_eT Bc]]*7hTh 8ft)wުO@1u~DSy/jm(! è{L~۪'j䡗CSTWOrg`cf98jI! yYrFq,ٹ+h0̀c3w 4*! LN;၃bX0m7/إ˪KXmV j\2m%%~co,@@@t5_lV—۬秞mh 5NVh~YL' @@@@@=Ч:zu=t11,bs k/J-4Nʽ%mtqUu{MZ㲫|r3Ff ~ME1d] GF"tAuzoژU4ٻlSI֬ԩewHjt*DS4%HCgVFU@ YY:t$hA3+LN6Vw6hUe[7ATYCW}JCzػͻDq $M@9ӿs}N}Z ^sn瞞y7/8sYe06vhB{ꮹ H#huݷ,^QGFajfipTKԐ1isR#=c?vɰZߏ˫"U :8m8_O>lh)z"qV06nXȫSMwwG^[&]X+,L2w'hВ;kw귷v!JHѴIU8|(M@9ӿs}N}Z ^sn瞞y7/8sYe06fU.ۨ ]=gu< L \}eEy4u{Jk`1L+٣ cS) T.zxe7m[nwO!O:f拔mJe ᗉevUSn_C:>j9Ͽg4͹gc;1잉Ne,ځmjƋƒe.HPO^PCDO)rM kvr&+IݦMKp BĀAuxQ>R6dU]Cأ]V DITbp߿nt+0#;?+W$pի6>yZ9;cj?S:tڹF™ct11,bsKV l+,EW X)*E3ĴDt=/9 h=vupֶgTpTȞ"b(IrdUڍ폑vvifUm9%s~ydNtug=VgF/;?4k:BaK3Lw`@@@t5_lV—۬秞mh 5NVh~YL' @@@@@=Ч:zu=/QjכS9/<֦Nc*&0IAYovm!s֏ii6ģA]z7wG8_fN%Mx*]Imw]mۯBV "WUN;X"]7?NU:j<)yͺϞzy֎NڏsTqfp٥Oo|"1;c5 DKB "c=ɉ| ~3SXħ>nm!ƺbĥNƝ.mBmm ,}s1kY{۬J W]Ofyy6טĺ r[S,5]:A &c A%~co,@@@t5_lV—۬秞mh 5NVh~YL' @@@cڽOlw{c[,z+ɦ˫S]&mUш^`q̭hRQ«_{4LUG8&>nr˧VEP6+ }Nsʚ'0xuQMSn涨 seA{ݳ3)Ψo[).ȷTG*M!stUzsznت[U m.֝kw@ ᾚ)L=gwt4^*،у++ C+Dhuar@@@@@@@@@t߿nt 0#;?+$poի&>y^9;cj?SP#;?+W$poի6>yZ9;cj?SSf'1$GDŽxĪe!N}`n邺1˕/fYM_Sn[MmOm+`ۭ:i(ًe{G~X\Ԟ뫮G)khi&JbzӹucRz FUegod Do 7:Νu87xRu<ͭ~*)#GW;UuΧRHy.5Տ)HϟZQ*ANGQzcuGVsfdRzu^:!F`:ft)wުO@[Nba]\bYT9nGxUjWY]11uZuoWNPF5EQUTLN%dĀLUmfT$cxSw,N@ 5zyriF3tɁwV;~-qN[RR5G:mTՃgm&n,P[{w{]F[n5Ђ*w @[Nhmmv*òS]sZ.苩˪TNU:j<)yͺϞzy֎NڏsTqfp٣ cS) T帪?UWafm2F;㔨 "c)]=S?PBnv6jFȭu;7uPNA:o"9GK[ 6uwNEMU>wC#nr##1"@=TdЮO(l5* *QN7a5yJ r[S,5]:A &0˄"]7?NU:j<)yͺϞzy֎NڏsTqfp٣ cS) V#Q~(jfwS8\3Z;FZTQeMSVQ:8[he^6Z̶i-]圕(k( B[,?YaMvs3òluvӶ1 2B):(10q9K?2m *t*HA,f&' Do 7:Νu8?xRu<ͭ~*)#GW;UuΧR@@@@@@;z&'}?}Dڔ2h+ªg3b@@@@@@@@@@@G101,i·Q 1'e?9,սx7` Gzw~WIWOWYKM|6rwx4?, hhURT-;SP h.eO_G|Nmc[2)~=cK0fGW;UuΧR@@@@@@@DR1ןW]M‰P@@@@@@@@@@@N]`M{am]g/97YQ<Qjx?, pS_o|?U:I&%M3T1#)UIYU1TnDP@@@@@@@@@@@@^~4ֹL;Uʔ)}5EQUU3|1 &5Dĥ.}/CgV,}M(m]GmXM5ch4MKb'YhlB[Yʬed5Б̬ Jbptkoٲq(m M^Tɭ 'X)b)USX#;?+W$poիFϞzy֎NڏsTqfp٣ cS) !*:Nۯl:͕t}Т^w_~3WYČy[19$$/Kyf/:P sf3:U#G^ZZXo1QV%z/K,Ut2:0YXr y%"}6=yBΝu87xRu<ͭ~*)NcZZ3ﮫ!{uU,5oGW;UuΧR@@@@@@@@@@BU#QGw5=㮇<$ڹ;(=e &' sGj'}_kSi@@@@@@@}{'ы[l떚µPa6mޮ Ay%kDwJ*$ Do 7:Νu87xRu<ͭ~*)mSd#Xl̊_XD;hYGM{=ܥi~.coo4O*o9}2=!/G!/G!/G!/G!/G!/G!/G!/G!/G!/G!/G!/G*%sn #ĩ >RY{8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8}^#i Gƾ)]qeLm݃[DZx،IU=OC_ԓ{{8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԏ{;8=OC_ԉ'u]uM^կ&㆙6 )+zMH̹\U98oS_^O+IlU 1'#Ź m.qs4{60#;?+W$pի6>yZ9;cj?Szm{뻤v_͡{뻤v_͡;t=wt{cٴ?t=wt{c?t=w{c?A=Ge1 ] }Ǯ{{>}{{>}{{6}wH==C7zdz8NǮ{{>oy;/fpoy;/fpoy;/fp] m] m{뻤v_͡{뻤v_͡{뿤v_͡;t=w{cٴ?A=Ge1 ] }{뻤v_ϡ{뿤v_͡;A=Ge1 A=Ge1CwH==CCwH==CCwH==CCwH==CCwH==CCwH==Cwzdz87zdzh8F] m] } {뻤v_ϡ{뻤v_ϡt=wt{c?t=wt{c?t=w{c?'}{{6}wH==CCwH==C7zdzh87zdzh87zdzh87zdzh87onf;쌕[7u) 4'_ ~4v.Ek qa= _ͩX[./mps-format.htm000666 000000 000000 00000051460 11243721172 012172 0ustar00000000 000000 MPS file format

MPS file format

Fixed MPS format

The main things to know about fixed MPS format are that it is column oriented
(as opposed to entering the model as equations), and everything
(variables, rows, etc.) gets a name.

MPS is an old format, so it is set up as though you were using punch
cards. Fields start in column 2, 5, 15, 25, 40 and 50.
Sections of an MPS file are marked by so-called header cards,
which are distinguished by their starting in column 1. Although it is
typical to use upper-case throughout the file (like I said, MPS has
long historical roots), many MPS-readers will accept mixed-case for
anything except the header cards, and some allow mixed-case anywhere.
The names that you choose for the individual entities (constraints or
variables) are not important to the solver; you should pick names that
are meaningful to you, or will be easy for a post-processing code to
read.

Here is a little sample model written in MPS format (explained in more
detail below):

NAME          TESTPROB
ROWS
 N  COST
 L  LIM1
 G  LIM2
 E  MYEQN
COLUMNS
    XONE      COST                 1   LIM1                 1
    XONE      LIM2                 1
    YTWO      COST                 4   LIM1                 1
    YTWO      MYEQN               -1
    ZTHREE    COST                 9   LIM2                 1
    ZTHREE    MYEQN                1
RHS
    RHS1      LIM1                 5   LIM2                10
    RHS1      MYEQN                7
BOUNDS
 UP BND1      XONE                 4
 LO BND1      YTWO                -1
 UP BND1      YTWO                 1
ENDATA

For comparison, here is the same model written out in lp-format:

min: +XONE +4 YTWO +9 ZTHREE;
LIM1: +XONE +YTWO <= 5;
LIM2: +XONE +ZTHREE >= 10;
MYEQN: -YTWO +ZTHREE = 7;
XONE <= 4;
YTWO >= -1;
YTWO <= 1;

Strangely, there is nothing in MPS format that specifies the direction
of optimisation.  And there really is no standard "default" direction;
some LP codes will maximize if you don't specify otherwise, others will
minimize, and still others put safety first and have no default and
require you to specify it somewhere in a control program or by a
calling parameter. lp_solve uses minimization as default. This can be
changed do maximization by calling set_maxim or set_sense after reading
the file or by using option -max on the lp_solve command line program.
If you have a model formulated for minimization and the code you are
using insists on maximization (or vice versa), it may be easy to convert:
just multiply all the coefficients in your objective function by (-1).
The optimal value of the objective function will then be the negative of
the true value, but the values of the variables themselves will be correct.

Any line with an asterisk (*) in Column 1 is treated as a comment.

The eight character names used to specify variables, constraints and
other entities are fixed format. Names are not automatically justified,
so blanks are treated just like other characters. For example "ROW1    "
is not the same as " ROW1   ". (Note that some optimisers do not permit
blanks in names.) No case conversion is performed, so "row1    " is
different from "ROW1    ".

Floating point numbers may be specified in free format within the 12
character field (including embedded blanks). The following list describes
the possible ways of writing a number.

Mantissa:

        + or -      optional sign character (no sign indicates a positive number)

        digits      optional integer part of the mantissa

        .           optional decimal point (if not present, a decimal point will
                    be assumed after the mantissa digit)

        digits      optional fraction part of the mantissa -the mantissa must
                    contain at least one digit

Exponent (optional):

        D or E      exponent leader

        + or -      optional exponent sign

        digits      exponent digits

Numbers with an absolute value greater than 1010 or less than 10-10 are rejected.

The NAME card can have anything you want, starting in column 15.  The
ROWS section defines the names of all the constraints; entries in
column 2 or 3 are E for equality rows, L for less-than ( <= ) rows, G
for greater-than ( >= ) rows, and N for non-constraining rows (the
first of which would be interpreted as the objective function).  The
order of the rows named in this section is unimportant.

The largest part of the file is in the COLUMNS section, which is the
place where the entries of the A-matrix are put. All entries for a given
column must be placed consecutively, although within a column the
order of the entries (rows) is irrelevant. Rows not mentioned for a
column are implied to have a coefficient of zero.

The RHS section allows one or more right-hand-side vectors to be
defined; most people don't bother having more than one.  In the above
example, the name of the RHS vector is RHS1, and has non-zero values
in all 3 of the constraint rows of the problem.  Rows not mentioned in
an RHS vector would be assumed to have a right-hand-side of zero.
Note that the objective may also have a constant. This can also be
specified in this section by using the object name as constraint name
and then specifying the constant. Note that there are 2 interpretations
of this constant. Some solvers see this as the constant that would be
really in the RHS and when brought into the objective (LHS), it is negated.
Other solvers, as lp_solve does, use the specified value in the MPS file
as the value for the objective and don't negate it.

The optional BOUNDS section lets you put lower and upper bounds on
individual variables (no * wild cards, unfortunately), instead of
having to define extra rows in the matrix.  All the bounds that have
a given name in column 5 are taken together as a set.  Variables not
mentioned in a given BOUNDS set are taken to be non-negative (lower
bound zero, no upper bound).  A bound of type UP means an upper bound
is applied to the variable.  A bound of type LO means a lower bound is
applied.  A bound type of FX ("fixed") means that the variable has
upper and lower bounds equal to a single value.  A bound type of FR
("free") means the variable has neither lower nor upper bounds.

There is another optional section called RANGES that I won't go into
here. The final card must be ENDATA, and yes, it is spelled funny.

==========================================================================

MPS input format was originally introduced by IBM to express linear
and integer programs in a standard way.  The format is a fixed column
format, so care must be taken that all information is placed in the
correct columns as described below.

The following is not intended as a complete description of MPS format,
but only as a brief introduction.  For more information, the reader is
directed to:

  "Advanced Linear Programming," by Bruce A. Murtagh
  "Computer Solutions of Linear Programs," by J.L. Nazareth


It may be useful to look at an example MPS file while reading this
MPS information.


The following template is a guide for the use of MPS format:

---------------------------------------------------------------------
Field:    1           2          3         4         5         6
Columns:  2-3        5-12      15-22     25-36     40-47     50-61

          NAME   problem name

          ROWS

           type     name

          COLUMNS
                   column       row       value     row      value
                    name        name                name
          RHS
                    rhs         row       value     row      value
                    name        name                name
          RANGES
                    range       row       value     row      value
                    name        name                name
          BOUNDS

           type     bound       column    value
                    name        name

          SOS
           type     CaseName    SOSName   SOSpriority
                    CaseName    VarName1  VarWeight1
                    CaseName    VarName2  VarWeight2

                    CaseName    VarNameN  VarWeightN

          ENDATA
---------------------------------------------------------------------

NOTES:

A. In the ROWS section, each row of the constraint matrix must have a
   row type and a row name specified.  The code for indicating row type
   is as follows:

                     type      meaning
                     ---------------------------
                      E    equality
                      L    less than or equal
                      G    greater than or equal
                      N    objective
                      N    no restriction

B. In the COLUMNS section, the names of the variables are defined along
   with the coefficients of the objective and all the nonzero constraint
   matrix elements.  It is not necessary to specify columns for slack or
   surplus variables as this is taken care of automatically.

C. The RHS section contains information for the right-hand side of the problem.

D. The RANGES section is for constraints of the form:  h <= constraint <= u .
   The range of the constraint is  r = u - h .  The value of r is specified
   in the RANGES section, and the value of u or h is specified in the RHS
   section.  If b is the value entered in the RHS section, and r is the
   value entered in the RANGES section, then u and h are thus defined:

        row type       sign of r       h          u
        ----------------------------------------------
           G            + or -         b        b + |r|
           L            + or -       b - |r|      b
           E              +            b        b + |r|
           E              -          b - |r|      b


E. In the BOUNDS section, bounds on the variables are specified.  When
   bounds are not indicated, the default bounds ( 0 <= x < infinity )
   are assumed.  The code for indicating bound type is as follows:

                    type            meaning
                   ---------------------------------------------------
                     LO    lower bound        b <= x (< +inf)
                     UP    upper bound        (0 <=) x <= b
                     FX    fixed variable     x = b
                     FR    free variable      -inf < x < +inf
                     MI    lower bound -inf   -inf < x (<= 0)
                     PL    upper bound +inf   (0 <=) x < +inf
                     BV    binary variable    x = 0 or 1
                     LI    integer variable   b <= x (< +inf)
                     UI    integer variable   (0 <=) x <= b
                     SC    semi-cont variable x = 0 or l <= x <= b
                           l is the lower bound on the variable
                           If none set then defaults to 1

F. Sections RANGES and BOUNDS are optional as are the fields 5 and 6.
   Everything else is required.  In regards to fields 5 and 6, consider
   the following 2 constraints:

                       const1:  2x + 3y <= 6
                       const2:  5x + 8y <= 20

   Two ways to enter the variable x in the COLUMNS section are:

     (Field:  2    3           4            5         6  )
   1.         x  const1       2.0         const2     5.0

   2.         x  const1       2.0
              x  const2       5.0

G. A mixed integer program requires the specification of which variables
   are required to be integer.  Markers are used to indicate the start
   and end of a group of integer variables.  The start marker has its
   name in field 2, 'MARKER' in field 3, and 'INTORG' in field 5.  The
   end marker has its name in field 2, 'MARKER' in field 3, and 'INTEND'
   in field 5.  These markers are placed in the COLUMNS section.
   When there are BOUNDS on the variables, then these are used as lower
   and upper bound of these integer variables and there is no confusion
   possible. Even a lower bound of 0 is already enough. In that case, if
   there is no upper bound, infinite is used.
   However there is an interpretation problem if there are no bounds at
   all on these variables. Some solvers then use 0 as lower bound and 1
   as upper bound. So the variables are treated as binary variables.
   That is the original IBM interpretation.
   Other solvers, like lp_solve, use the default bounds on variables in
   that case. That is 0 as lower bound and infinite as upper bound.
   When lp_solve writes an MPS file, it will write the default lower
   bound of 0 if there are no lower/upper bounds set on the variable. As
   such, there is no confusion.
   However when lp_solve reads an MPS file and there are no bounds on
   variables between INTORG/INTEND, it interpretes the variables as
   integer and not binary as some other solvers do. That could result
   in another solution than expected.

H. A specially ordered set of degree N is a collection of variables where
   at most N variables may be non-zero.  The non-zero variables must be
   contiguous (neighbours) sorted by the ascending value of their respective
   unique weights.  In lp_solve, specially ordered sets may be of any
   cardinal type 1, 2, and higher, and may be overlapping.  The number of
   variables in the set must be equal to, or exceed the cardinal SOS order.

   Below is a representation of a SOS in an MPS file, where each SOS is
   defined in its own SOS section, which should follow the BOUNDS section.

   0        1         2         3         4
   1234567890123456789012345678901234567890
   SOS
    Sx CaseName  SOSName.  SOSpriority.
       CaseName  VarName1  VarWeight1..
       CaseName  VarName2  VarWeight2..

       CaseName  VarNameN  VarWeightN..

   x at the second line, position 3, defines is the order of the SOS.
   Due to limitations in the MPS format, N is restricted to the 1..9 range.
   Each SOS should be given a unique name, SOSName. lp_solve does not
   currently use case names for SOS'es and the CaseName could be any non-empty
   value.  The SOSpriority value determines the order in which multiple SOS'es
   are analysed in lp_solve.
   See also Interpolation with GAMS.

Example:
NAME SOS2test ROWS N obj L c1 L c2 E c3 COLUMNS x1 obj -1 c1 -1 x1 c2 1 x2 obj -2 c1 1 x2 c2 -3 c3 1 x3 obj -3 c1 1 x3 c2 1 x4 obj -1 c1 10 x4 c3 -3.5 x5 obj 0 RHS rhs c1 30 c2 30 BOUNDS UP BOUND x1 40 LI BOUND x4 2 UI BOUND x4 3 SOS S2 SET SOS2 10 SET x1 10000 SET x2 20000 SET x4 40000 SET x5 50000 ENDATA

Free MPS format

The free format is very similar to the fixed MPS format, but it is less restrictive e.g. it allows longer names. Also some implementations allow more than 12 positions to specify the values. The fields do not have fixed column positions as in the fixed MPS format. They may be written anywhere except column 1, with each field separated from the next by one or more blanks. However, they must appear in the same sequence as in fixed format. In the rows and bounds sections, the codes can be lower and upper case and at any starting position. Repeated column names are sometimes skipped and spaces are put there instead. The Fortran D exponent is allowed in the values.

There is one important limitation compared to the fixed MPS format: names may not contain blanks.

Note that the free MPS parser cannot read all fixed MPS formats correctly. Spaces in the names or names starting with spaces will give problems. It is not sure that an error will be given in that case. If the format complies to the free MPS format then it won't... So if you know that a model is in fixed MPS format, use it and not the free format. It is advised to first try the fixed format and only if it doesn't work, use the free format.

Also note that there is no real standard for the free format. Each implementer has its own implementation and interpretation of the free format ... Some allow one space in the name, some require that names must take at least 8 positions (and thus extended with spaces). Some allow to have more than 6 fields on a line. lp_solve only reads the first 6 fields and ignores the rest.

lp_solve tries to handle all possible free formats. The only real limitation is that there may be no blanks in names (also no leading blanks) and only 6 fields per line may be used. When lp_solve writes an mps file in free format, it will be the same as for fixed format, except if names are longer than 8 characters. In that case all data is shifted to the right.

OBJSENSE

Several solvers have added a 'standard' to the free MPS format to allow to specify the objective direction. This via the new optional section OBJSENSE. Below this section, there may be one line that specifies the objective direction. This in field 1 of this line via the following possible keywords: MAXIMIZE, MAX, MINIMIZE, MIN. If the section is not specified, then lp_solve assumes minimization, just like the fixed MPS format.
For example:

OBJSENSE
 MAX

This section should be before the ROWS section.
For example:

NAME          TESTPROB
OBJSENSE
 MAX
ROWS
 N  COST
 L  LIM1
 G  LIM2
 E  MYEQN
COLUMNS
    XONE      COST                 1   LIM1                 1
    XONE      LIM2                 1
    YTWO      COST                 4   LIM1                 1
    YTWO      MYEQN               -1
    ZTHREE    COST                 9   LIM2                 1
    ZTHREE    MYEQN                1
RHS
    RHS1      LIM1                 5   LIM2                10
    RHS1      MYEQN                7
BOUNDS
 UP BND1      XONE                 4
 LO BND1      YTWO                -1
 UP BND1      YTWO                 1
ENDATA

The lp_solve free MPS reader recognises and interprets all possible OBJSENSE direction values. When a free MPS file is created, the OBJSENSE section will only be written when the direction is maximization. This because minimization is by default assumed and to stay as compatible as possible with other solvers.

OBJNAME

Several solvers have added a 'standard' to the free MPS format to allow to specify the objective row. By default the first "N" row defined in the ROWS section becomes a problem's objective; a different objective may be specified in the optional OBJNAME section, which contains exactly one data line that names the objective in field 1.
For example:

OBJNAME
 obj2

This section should be before the ROWS section.
For example:

NAME          TESTPROB
OBJNAME
 PROFIT
ROWS
 N  COST
 N  PROFIT
 L  LIM1
 G  LIM2
 E  MYEQN
COLUMNS
    XONE      COST                -1   PROFIT               1
    XONE      LIM1                 1   LIM2                 1
    YTWO      COST                -4   PROFIT               4
    YTWO      LIM1                 1   MYEQN               -1
    ZTHREE    COST                -9   PROFIT               9
    ZTHREE    LIM2                 1   MYEQN                1
RHS
    RHS1      LIM1                 5   LIM2                10
    RHS1      MYEQN                7
BOUNDS
 UP BND1      XONE                 4
 LO BND1      YTWO                -1
 UP BND1      YTWO                 1
ENDATA

The lp_solve free MPS reader recognises and interprets this OBJNAME section and uses the objective name specified here. Other "N" cards in the ROWS section are then ignored. Note that if there is no OBJNAME section that, just like in the fixed MPS format, the first "N" card from the rows section is then taken and all other "N" cards are ignored. When a free MPS file is created, the OBJNAME section will never be created since lp_solve always only has one objective function in memory.

./MSF.htm000666 000000 000000 00000162436 13772705351 010552 0ustar00000000 000000 Using lpsolve from Microsoft Solver Foundation

Using lpsolve from Microsoft Solver Foundation

Microsoft Solver Foundation?

Microsoft Solver Foundation is an extensible .NET framework that helps you model and solve complex problems by:

  • Modeling and solving scenarios by using constraints, goals, and data.
  • Programming in the Optimization Modeling Language (OML), in C# imperatively, in F# functionally, or in any .NET Framework language.
  • Integrating third-party solvers, such as Gurobi, Mosek, FICO Xpress, LINDO, CPLEX®, and lp_solve.
  • Using familiar interfaces in Microsoft Office Excel and SharePoint to create and solve models.

Modeling and solving capabilities
Solver Foundation Services (SFS) can automatically analyze models and determine which solver is most appropriate. If you are an advanced modeler, you can choose specific solvers and solver attributes. While solving the models, SFS manages all threading, many-core, synchronization, scheduling, and model execution issues. When finished, SFS produces reports about solver behavior and results, and provides additional information about solutions, including sensitivity. Finally, SFS allows LINQ data binding of model parameters and delivery of results in multiple formats.

Program in OML, F#, C#, VB, C++, IronPython, and more
Solver Foundation supports all the .NET Framework languages and provides samples in many of them. In addition, if you prefer a modeling language, you can use Solver Foundation's type safe optimization modeling language (OML).

Integrated and Third-Party Solvers
Solver Foundation allows new or existing third-party solvers to plug into the SFS directly, avoiding the need to learn a new modeling language or the significant overhead in managing solver specific solutions. These solvers include numerical, symbolic, and search algorithms that you can use in your models. There is a collection of certified partner wrappers for Gurobi, Mosek, FICO Xpress, and LINDO, as well as reference wrapper source code for CPLEX® and lp_solve.

The following system diagram describes the extensible architecture of Microsoft Solver Foundation.

sf-arch.jpg

For more information see Microsoft Solver Foundation blog

Introduction

Solver Foundation can be approached either at the Solver Foundation Services (SFS) level or via the APIs for specific kinds of solver.

The SFS level is recommended for conceptual clarity of modeling, for ease of binding to data from various sources, for educational use, for introducing you to all the capabilities of Solver Foundation, for automatic selection of a solver to suit your model, and for construction of models which may require the use of more than one kind of solver. Solver Foundation will be heavily investing in the SFS.

The Solver-specific APIs are intended for use by experienced programmers who clearly know which kind of solver they need to use, are prepared to write code to translate a model into a sequence of API calls, and where the usage is to be embedded in an application where the application is fully responsible for capturing the model and supplying the instance data.

The advantage of using the SFS level is that code is (almost) solver independent. In the ideal case the system chooses which solver to use dependent of the model and availability of solvers. Solver choice can also be instructed via the configuration file. To have more control of the chosen solver and its parameters also a specific solver directive can be chosen in the code. Only that directive code is then solver specific.

The advantage of using the API of the specific solver is that you have more control over the solvers' specific features. But the disadvantage is that you are targetting specifically that solver and it is thus more difficult to change solver.

The Microsoft solver foundation team recommend use of the Solver Foundation Services unless you are absolutely sure you need to program direct to a specific solver API.

Microsoft Foundation Solver and lpsolve

lpsolve is callable from Microsoft Foundation Solver via a wrapper or plugin. As such, it looks like lpsolve is fully integrated with Microsoft Foundation Solver.

This plugin acts as a bridge between Solver foundation and lpsolve.
Users of the plugin and MSF need to register the new solver in the app.config in order to use it.

To use the lpsolve plugin with MSF:

  • Copy the compiled lpsolve plugin wrapper code i.e LpSolvePlugIn.dll and the lpsolve library i.e lpsolve55.dll to the bin\Debug, bin\Release folder. As an alternative, MSF has created a registry key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Solver Foundation" with a string value PluginDirectory. The lpsolve plugin can also installed in this folder. MSF will search first in the folder of the executable that embeds Solver Foundation, and then in the plug-in directory specified in the registry key. In 64-bit machines, Solver Foundation will also create the same registry key for 32-bit apps. The key will be stored under "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft"
  • Add a new file App.config to the project or edit the existing App.config and paste the solver registration contents as below:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    <configSections>
    <section name="MsfConfig"
    type="Microsoft.SolverFoundation.Services.MsfConfigSection, Microsoft.Solver.Foundation, Version={Version}, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    allowLocation="true"
    allowDefinition="Everywhere"
    allowExeDefinition="MachineToApplication"
    restartOnExternalChanges="true"
    requirePermission="true" />
    </configSections>
    
    <MsfConfig>
    <MsfPluginSolvers>
    <MsfPluginSolver name="LpSolveLP"
    capability="LP"
    assembly="LpSolvePlugIn.dll"
    solverclass="SolverFoundation.Plugin.LpSolve.LpSolveSolver"
    directiveclass="SolverFoundation.Plugin.LpSolve.LpSolveDirective"
    parameterclass="SolverFoundation.Plugin.LpSolve.LpSolveParams" />
    <MsfPluginSolver name="LpSolveMIP"
    capability="MILP"
    assembly="LpSolvePlugIn.dll"
    solverclass="SolverFoundation.Plugin.LpSolve.LpSolveSolver"
    directiveclass="SolverFoundation.Plugin.LpSolve.LpSolveDirective"
    parameterclass="SolverFoundation.Plugin.LpSolve.LpSolveParams" />
    </MsfPluginSolvers>
    </MsfConfig>
    </configuration>
    
    {Version} must be replaced by the version of MSF that is used. For example 2.0.2.8632 or 2.0.3.9657

LpSolveDirective object

Microsoft Foundation Services can instruct the solver via a directive. All properties and methods starting with LpSolve are lp_solve specific and control the solver. All others are inherited from the base Directive object. These are the available properties and methods:

Arithmetic Get or set the arithmetic to use for numeric solving. lp_solve only allows double arithmetic. Setting this property to something different from Double or Default will result in a NotImplementedException exception.
GetSensitivity Whether to generate sensitivity information at report. The default is False.
LpSolveLogFunc A log callback function to allow lp_solve to return information to the application. See put_logfunc
LpSolveMsgFunc A message callback function to allow lp_solve to return information to the application. See put_msgfunc
LpSolveAntiDegen See set_anti_degen
LpSolveBasiscrash See set_basiscrash
LpSolveBbDepthlimit See set_bb_depthlimit
LpSolveBbFloorfirst See set_bb_floorfirst
LpSolveBbRule See set_bb_rule
LpSolveBreakAtFirst See set_break_at_first
LpSolveBreakAtValue See set_break_at_value
LpSolveDebug See set_debug
LpSolveEpsb See set_epsb
LpSolveEpsd See set_epsd
LpSolveEpsel See set_epsel
LpSolveEpsint See set_epsint
LpSolveEpsperturb See set_epsperturb
LpSolveEpspivot See set_epspivot
LpSolveImprove See set_improve
LpSolveInfinite See set_infinite
LpSolveLogFile See set_outputfile
LpSolveMaxpivot See set_maxpivot
LpSolveMipGapAbs See set_mip_gap
LpSolveMipGapRel See set_mip_gap
LpSolveNegrange See set_negrange
LpSolveObjBound See set_obj_bound
LpSolveObjInBasis See set_obj_in_basis
LpSolvePivoting See set_pivoting
LpSolvePresolve See set_presolve
LpSolvePresolveMaxLoops See set_presolve
LpSolveReadParams Read all settings from a file. See read_params
LpSolveScalelimit See set_scalelimit
LpSolveScaling See set_scaling
LpSolveSimplextype See set_simplextype
LpSolveSolutionlimit See set_solutionlimit
LpSolveTimeout See set_timeout
LpSolveTrace See set_trace
LpSolveVerbose See set_verbose
MaximumGoalCount Get and set the maximum number of goals to optimize. lp_solve allows only one goal. If something different from 1 is specified, a NotImplementedException will be thrown.
TimeLimit Get and set the time-limit (in milliseconds) of Solve. No limit if it is set to a negative value. Default value is -1 (no limit).
WaitLimit Get and set the amount of time (in milliseconds) the SFS will wait for a result after requesting a timeout/abort.

LpSolveSolver object (API)

When the solver is called directly via the API, the LpSolveSolver object is used to build and solve the model. All properties and methods starting with LpSolve are lp_solve specific and control the solver. All others are inherited from the base object. These are the available properties and methods:

LpSolveLogFunc A log callback function to allow lp_solve to return information to the application. See put_logfunc
LpSolveMsgFunc A message callback function to allow lp_solve to return information to the application. See put_msgfunc
LpSolvePrintDebugDump See print_debugdump
LpSolveWriteLp See write_lp
LpSolveWriteMPS See write_mps
LpSolveWriteParams See write_params
LpSolveWriteXLI See write_XLI

The LpSolveSolver object can also be subclassed to override the LpSolveLogFunc and LpSolveMsgFunc methods. That is an alternative for providing the these functions via the LpSolveLogFunc and LpSolveMsgFunc properties. That will be shown in the examples below.

SFS examples

Example1

static void Example1()
{
    // Create the model
    SolverContext context = SolverContext.GetContext();
    Model model = context.CreateModel();
    // Add a decision
    Decision x = new Decision(Domain.RealNonnegative, "x");
    model.AddDecisions(x);
    // Add a constraint
    model.AddConstraints("one", x == 1);

    //SimplexDirective simplex = new SimplexDirective();
    LpSolveDirective simplex = new LpSolveDirective();

    // Solve the problem
    Solution sol = context.Solve(simplex);
    // Display the results
    Console.WriteLine("x: {0}", x);

    Report report = sol.GetReport();

    Console.WriteLine(report);

    using (StreamWriter sw = new StreamWriter("Example1.mps"))
    {
        context.SaveModel(FileFormat.FreeMPS, sw);
    }
}

This gives as output:

x: 1
===Solver Foundation Service Report===
Date: 16-May-10 17:20:36
Version: Microsoft Solver Foundation 2.0.3.9657 Express Edition
Model Name: Default
Capabilities Applied: LP
Solve Time (ms): 34
Total Time (ms): 113
Solve Completion Status: Optimal
Solver Selected: SolverFoundation.Plugin.LpSolve.LpSolveSolver
Directives:
LpSolve(SolveAntiDegen:ANTIDEGEN_FIXEDVARS, ANTIDEGEN_STALLING,SolveBasiscrash:C
RASH_NOTHING,SolveBbDepthlimit:-50,SolveBbFloorfirst:BRANCH_AUTOMATIC,SolveBbRul
e:NODE_PSEUDONONINTSELECT, NODE_GREEDYMODE, NODE_DYNAMICMODE, NODE_RCOSTFIXING,S
olveBreakAtFirst:False,SolveBreakAtValue:-1E+30,SolveDebug:False,SolveEpsb:1E-10
,SolveEpsd:1E-09,SolveEpsel:1E-12,SolveEpsint:1E-07,SolveEpsperturb:1E-05,SolveE
pspivot:2E-07,SolveImprove:IMPROVE_DEFAULT,SolveInfinite:1E+30,SolveMaxpivot:250
,SolveMipGapAbs:1E-11,SolveMipGapRel:1E-11,SolveNegrange:-1000000,SolveObjBound:
1E+30,SolveObjInBasis:True,SolvePivoting:PRICER_DEVEX, PRICE_ADAPTIVE,SolvePreso
lve:PRESOLVE_NONE,SolvePresolveMaxLoops:2147483647,SolveScalelimit:5,SolveScalin
g:SCALE_GEOMETRIC, SCALE_EQUILIBRATE, SCALE_INTEGERS,SolveSimplextype:SIMPLEX_DU
AL_PRIMAL,SolveSolutionlimit:1,SolveTimeout(s):4294967296,SolveTrace:False,Solve
Verbose:4,Arithmetic:Double,TimeLimit (ms):-1,GetSensitivity:False,MaximumGoalCo
unt:1)
===SolverDetails====
Iteration Count:1
Presolve loops:2147483647
Pivot count:250
===Model details===
Variables:1
Rows:1
Non-zeros:1
===Solution Details===
Goals:

Decisions:
x: 1

Example2

static void Example2()
{
    // Get the context and create a new model.
    SolverContext context = SolverContext.GetContext();
    Model model = context.CreateModel();
    // Create two decision variables representing the number of barrels to
    // purchase from two countries.
    // AddDecisions tells the model about the two variables.
    Decision vz = new Decision(Domain.RealNonnegative, "barrels_venezuela");
    Decision sa = new Decision(Domain.RealNonnegative, "barrels_saudiarabia");
    model.AddDecisions(vz, sa);
    // Adding five constraints. The first line defines the allowable range // for the two decision variables. The other constraints put
    // minimums on the total yield of three products.
    model.AddConstraints("limits",
    0 <= vz <= 9000,
    0 <= sa <= 6000);
    model.AddConstraints("production",
    0.3 * sa + 0.4 * vz >= 2000,
    0.4 * sa + 0.2 * vz >= 1500,
    0.2 * sa + 0.3 * vz >= 500);
    // AddGoal states that we want to minimize the total cost subject to the
    // above constraints
    model.AddGoal("cost", GoalKind.Minimize,
    20 * sa + 15 * vz);

    // Solve the problem using the simplex solver
    //SimplexDirective simplex = new SimplexDirective();
    LpSolveDirective simplex = new LpSolveDirective();
    Solution solution = context.Solve(simplex);
    // Report the solution values
    Report report = solution.GetReport();
    Console.WriteLine("vz: {0}, sa: {1}", vz, sa);
    Console.Write("{0}", report);

    using (StreamWriter sw = new StreamWriter("Example2.mps"))
    {
        context.SaveModel(FileFormat.FreeMPS, sw);
    }
}

This gives as output:

vz: 3848290697215999/1099511627776, sa: 2199023255552001/1099511627776
===Solver Foundation Service Report===
Date: 16-May-10 17:27:53
Version: Microsoft Solver Foundation 2.0.3.9657 Express Edition
Model Name: Default
Capabilities Applied: LP
Solve Time (ms): 35
Total Time (ms): 119
Solve Completion Status: Optimal
Solver Selected: SolverFoundation.Plugin.LpSolve.LpSolveSolver
Directives:
LpSolve(SolveAntiDegen:ANTIDEGEN_FIXEDVARS, ANTIDEGEN_STALLING,SolveBasiscrash:C
RASH_NOTHING,SolveBbDepthlimit:-50,SolveBbFloorfirst:BRANCH_AUTOMATIC,SolveBbRul
e:NODE_PSEUDONONINTSELECT, NODE_GREEDYMODE, NODE_DYNAMICMODE, NODE_RCOSTFIXING,S
olveBreakAtFirst:False,SolveBreakAtValue:-1E+30,SolveDebug:False,SolveEpsb:1E-10
,SolveEpsd:1E-09,SolveEpsel:1E-12,SolveEpsint:1E-07,SolveEpsperturb:1E-05,SolveE
pspivot:2E-07,SolveImprove:IMPROVE_DEFAULT,SolveInfinite:1E+30,SolveMaxpivot:250
,SolveMipGapAbs:1E-11,SolveMipGapRel:1E-11,SolveNegrange:-1000000,SolveObjBound:
1E+30,SolveObjInBasis:True,SolvePivoting:PRICER_DEVEX, PRICE_ADAPTIVE,SolvePreso
lve:PRESOLVE_NONE,SolvePresolveMaxLoops:2147483647,SolveScalelimit:5,SolveScalin
g:SCALE_GEOMETRIC, SCALE_EQUILIBRATE, SCALE_INTEGERS,SolveSimplextype:SIMPLEX_DU
AL_PRIMAL,SolveSolutionlimit:1,SolveTimeout(s):4294967296,SolveTrace:False,Solve
Verbose:4,Arithmetic:Double,TimeLimit (ms):-1,GetSensitivity:False,MaximumGoalCo
unt:1)
===SolverDetails====
Iteration Count:2
Presolve loops:2147483647
Pivot count:250
===Model details===
Variables:2
Rows:6
Non-zeros:10
===Solution Details===
Goals:
cost: 92500

Decisions:
barrels_venezuela: 3500
barrels_saudiarabia: 2000

Example3

It is also possible to return and access the sensitivity information (from MSF version 2.1). This is demonstrated by this example. This is the same example as in the sensitivity section.

static void Example3()
{
    SolverContext context = SolverContext.GetContext();
    Model model = context.CreateModel();
    Decision COLONE = new Decision(Domain.RealRange(28.6, Rational.PositiveInfinity), "COLONE");
    Decision COLTWO = new Decision(Domain.RealNonnegative, "COLTWO");
    Decision COLTHREE = new Decision(Domain.RealNonnegative, "COLTHREE");
    Decision COLFOUR = new Decision(Domain.RealRange(18.0, 48.98), "COLFOUR");
    model.AddDecisions(COLONE, COLTWO, COLTHREE, COLFOUR);

    model.AddConstraints("THISROW",
    +78.26 * COLTWO + 2.9 * COLFOUR >= 92.3);

    model.AddConstraints("THATROW",
    +0.24 * COLONE + 11.31 * COLTHREE <= 14.8);

    model.AddConstraints("LASTROW",
    +12.68 * COLONE + 0.08 * COLTHREE + 0.9 * COLFOUR >= 4);

    model.AddGoal("cost", GoalKind.Minimize, COLONE + 3 * COLTWO + 6.24 * COLTHREE + 0.1 * COLFOUR);

    //SimplexDirective simplex = new SimplexDirective(); simplex.GetSensitivity = true;
    //LindoSimplexDirective simplex = new LindoSimplexDirective();
    //GurobiDirective simplex = new GurobiDirective(); simplex.GetSensitivity = true;
    LpSolveDirective simplex = new LpSolveDirective(); simplex.GetSensitivity = true;

    Solution solution = context.Solve(simplex);
    Report report = solution.GetReport();
    Console.Write("{0}", report);

    LinearReport lpReport = report as LinearReport;
    object ShadowPrices = lpReport.GetAllShadowPrices();
    object ConstraintBoundsSensitivity = lpReport.GetAllConstraintBoundsSensitivity();

    Console.WriteLine("Decisions");
    foreach (Decision d in solution.Decisions)
        Console.WriteLine("Name: " + d.Name + ", Description: " + d.Description);

    Console.WriteLine("GetAllShadowPrices:");
    foreach (KeyValuePair<string, Rational> o in lpReport.GetAllShadowPrices())
        Console.WriteLine("Key: " + o.Key + ", Value: " + o.Value.ToDouble().ToString());

    Console.WriteLine("GetAllConstraintBoundsSensitivity:");
    foreach (KeyValuePair<string, LinearSolverSensitivityRange> o in lpReport.GetAllConstraintBoundsSensitivity())
        Console.WriteLine("Key: " + o.Key + ", Current: " + o.Value.Current.ToDouble().ToString()  + ", Value.Lower: " + o.Value.Lower.ToDouble().ToString() + ", Value.Upper: " + o.Value.Upper.ToDouble().ToString());

    object[] indexes = new object[0];
    Console.WriteLine("GetGoalCoefficientSensitivity:");
    foreach (Decision d in solution.Decisions)
    {
        LinearSolverSensitivityRange ? o = lpReport.GetGoalCoefficientSensitivity(d, indexes);
        Console.WriteLine("Name: " + d.Name + ", Current: " + o.Value.Current.ToDouble().ToString() + ", Lower: " + o.Value.Lower.ToDouble().ToString() + ", Upper: " + o.Value.Upper.ToDouble().ToString());
    }

    using (StreamWriter sw = new StreamWriter("Example3.mps"))
    {
        context.SaveModel(FileFormat.FreeMPS, sw);
    }
}

Note that GetSensitivity on the directive must be set on true to get sensitivity information. By default this is not set and as in the examples above there is no sensitivity information provided if not set.

This gives as output:

===Solver Foundation Service Report===
Date: 16-May-10 17:32:08
Version: Microsoft Solver Foundation 2.0.3.9657 Express Edition
Model Name: Default
Capabilities Applied: LP
Solve Time (ms): 34
Total Time (ms): 119
Solve Completion Status: Optimal
Solver Selected: SolverFoundation.Plugin.LpSolve.LpSolveSolver
Directives:
LpSolve(SolveAntiDegen:ANTIDEGEN_FIXEDVARS, ANTIDEGEN_STALLING,SolveBasiscrash:C
RASH_NOTHING,SolveBbDepthlimit:-50,SolveBbFloorfirst:BRANCH_AUTOMATIC,SolveBbRul
e:NODE_PSEUDONONINTSELECT, NODE_GREEDYMODE, NODE_DYNAMICMODE, NODE_RCOSTFIXING,S
olveBreakAtFirst:False,SolveBreakAtValue:-1E+30,SolveDebug:False,SolveEpsb:1E-10
,SolveEpsd:1E-09,SolveEpsel:1E-12,SolveEpsint:1E-07,SolveEpsperturb:1E-05,SolveE
pspivot:2E-07,SolveImprove:IMPROVE_DEFAULT,SolveInfinite:1E+30,SolveMaxpivot:250
,SolveMipGapAbs:1E-11,SolveMipGapRel:1E-11,SolveNegrange:-1000000,SolveObjBound:
1E+30,SolveObjInBasis:True,SolvePivoting:PRICER_DEVEX, PRICE_ADAPTIVE,SolvePreso
lve:PRESOLVE_NONE,SolvePresolveMaxLoops:2147483647,SolveScalelimit:5,SolveScalin
g:SCALE_GEOMETRIC, SCALE_EQUILIBRATE, SCALE_INTEGERS,SolveSimplextype:SIMPLEX_DU
AL_PRIMAL,SolveSolutionlimit:1,SolveTimeout(s):4294967296,SolveTrace:False,Solve
Verbose:4,Arithmetic:Double,TimeLimit (ms):-1,GetSensitivity:True,MaximumGoalCou
nt:1)
===SolverDetails====
Iteration Count:1
Presolve loops:2147483647
Pivot count:250
===Model details===
Variables:4
Rows:4
Non-zeros:11
===Solution Details===
Goals:
cost: 31.7827586206897

Decisions:
COLONE: 28.6
COLTWO: 0
COLTHREE: 0
COLFOUR: 31.8275862068966

Shadow Pricing:
THISROW: 0.0344827586206897
THATROW: 0
LASTROW: 0

Goal Coefficients:
COLONE: 1 [0 Infinity]
COLTWO: 3 [2.69862068965517 Infinity]
COLTHREE: 6.24 [0 Infinity]
COLFOUR: 0.1 [-Infinity 0.111167901865576]

Constraint Bounds:
THISROW: 92.3 [52.2 142.042]
THATROW: 14.8 [-Infinity Infinity]
LASTROW: 4 [-Infinity Infinity]

Note that sensitivity information can also be retrieved from the report in variables via the methods GetAllShadowPrices() and GetAllConstraintBoundsSensitivity()

Example4

This example is an extension to Example3. Sensitivity is not asked and thus not reported. COLFOUR is defined as integer and an extra constraint is added. This constraint will be removed afterwards. Also log and message callback functions are set to show the lp_solve optimization process.

private static void LpSolveLogFunc(int lp, int userhandle, string buffer)
{
    Console.Write("{0}", buffer);
}

private static void LpSolveMsgFunc(int lp, int userhandle, LpSolveNativeInterface.lpsolve.lpsolve_msgmask message)
{
    Console.Write("{0}\n", message);
}

static void Example4()
{
    SolverContext context = SolverContext.GetContext();
    Model model = context.CreateModel();
    Decision COLONE = new Decision(Domain.RealRange(28.6, Rational.PositiveInfinity), "COLONE");
    Decision COLTWO = new Decision(Domain.RealNonnegative, "COLTWO");
    Decision COLTHREE = new Decision(Domain.RealNonnegative, "COLTHREE");
    Decision COLFOUR = new Decision(Domain.IntegerRange(18.0, 48.98), "COLFOUR");
    model.AddDecisions(COLONE, COLTWO, COLTHREE, COLFOUR);

    model.AddConstraints("THISROW",
    +78.26 * COLTWO + 2.9 * COLFOUR >= 92.3);

    model.AddConstraints("THATROW",
    +0.24 * COLONE + 11.31 * COLTHREE <= 14.8);

    model.AddConstraints("LASTROW",
    +12.68 * COLONE + 0.08 * COLTHREE + 0.9 * COLFOUR >= 4);

    Constraint extrarow = model.AddConstraints("EXTRAROW", +78.26 * COLTWO + 2.9 * COLFOUR >= 92.4);

    model.AddGoal("cost", GoalKind.Minimize, COLONE + 3 * COLTWO + 6.24 * COLTHREE + 0.1 * COLFOUR);

    //SimplexDirective simplex = new SimplexDirective();
    //LindoSimplexDirective simplex = new LindoSimplexDirective();
    //GurobiDirective simplex = new GurobiDirective();
    LpSolveDirective simplex = new LpSolveDirective(); simplex.LpSolveMsgFunc = LpSolveMsgFunc; simplex.LpSolveVerbose = 4; simplex.LpSolveLogFunc = LpSolveLogFunc;

    Solution solution = context.Solve(simplex);
    Report report = solution.GetReport();
    Console.Write("{0}", report);

    model.RemoveConstraint(extrarow);

    solution = context.Solve(simplex);
    report = solution.GetReport();
    Console.Write("{0}", report);
}

This gives as output:

Model name:  '' - run #1
Objective:   Minimize(R0)

SUBMITTED
Model size:        4 constraints,       4 variables,            9 non-zeros.
Sets:                                   0 GUB,                  0 SOS.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
The primal and dual simplex pricing strategy set to 'Devex'.


Relaxed solution       31.7862068966 after          2 iter is B&B base.

MSG_LPOPTIMAL
Feasible solution               31.8 after          3 iter,         1 nodes (gap
 0.0%)
MSG_MILPFEASIBLE
Improved solution      31.7958343982 after          4 iter,         2 nodes (gap
 0.0%)
MSG_MILPBETTER

Optimal solution       31.7958343982 after          4 iter,         2 nodes (gap
 0.0%).

Excellent numeric accuracy ||*|| = 0

 MEMO: lp_solve version 5.5.2.11 for 32 bit OS, with 64 bit REAL variables.
      In the total iteration count 4, 0 (0.0%) were bound flips.
      There were 1 refactorizations, 0 triggered by time and 0 by density.
       ... on average 4.0 major pivots per refactorization.
      The largest [LUSOL v2.2.1.0] fact(B) had 8 NZ entries, 1.0x largest basis.

      The maximum B&B level was 2, 1.0x MIP order, 2 at the optimal solution.
      The constraint matrix inf-norm is 78.26, with a dynamic range of 978.25.
      Time to load data was 0.011 seconds, presolve used 0.005 seconds,
       ... 0.003 seconds in simplex solver, in total 0.019 seconds.
===Solver Foundation Service Report===
Date: 17-May-10 22:41:11
Version: Microsoft Solver Foundation 2.0.3.9657 Express Edition
Model Name: Default
Capabilities Applied: MILP
Solve Time (ms): 39
Total Time (ms): 133
Solve Completion Status: Optimal
Solver Selected: SolverFoundation.Plugin.LpSolve.LpSolveSolver
Directives:
LpSolve(SolveAntiDegen:ANTIDEGEN_FIXEDVARS, ANTIDEGEN_STALLING,SolveBasiscrash:C
RASH_NOTHING,SolveBbDepthlimit:-50,SolveBbFloorfirst:BRANCH_AUTOMATIC,SolveBbRul
e:NODE_PSEUDONONINTSELECT, NODE_GREEDYMODE, NODE_DYNAMICMODE, NODE_RCOSTFIXING,S
olveBreakAtFirst:False,SolveBreakAtValue:-1E+30,SolveDebug:False,SolveEpsb:1E-10
,SolveEpsd:1E-09,SolveEpsel:1E-12,SolveEpsint:1E-07,SolveEpsperturb:1E-05,SolveE
pspivot:2E-07,SolveImprove:IMPROVE_DEFAULT,SolveInfinite:1E+30,SolveMaxpivot:250
,SolveMipGapAbs:1E-11,SolveMipGapRel:1E-11,SolveNegrange:-1000000,SolveObjBound:
1E+30,SolveObjInBasis:True,SolvePivoting:PRICER_DEVEX, PRICE_ADAPTIVE,SolvePreso
lve:PRESOLVE_NONE,SolvePresolveMaxLoops:2147483647,SolveScalelimit:5,SolveScalin
g:SCALE_GEOMETRIC, SCALE_EQUILIBRATE, SCALE_INTEGERS,SolveSimplextype:SIMPLEX_DU
AL_PRIMAL,SolveSolutionlimit:1,SolveTimeout(s):4294967296,SolveTrace:False,Solve
Verbose:4,Arithmetic:Double,TimeLimit (ms):-1,GetSensitivity:False,MaximumGoalCo
unt:1)
===SolverDetails====
Iteration Count:4
Presolve loops:2147483647
Node Count:2
===Model details===
Variables:4
Rows:5
Non-zeros:13
===Solution Details===
Goals:
cost: 31.79583439816

Decisions:
COLONE: 28.6
COLTWO: 0.03194479938666
COLTHREE: 0
COLFOUR: 31

Model name:  '' - run #1
Objective:   Minimize(R0)

SUBMITTED
Model size:        3 constraints,       4 variables,            7 non-zeros.
Sets:                                   0 GUB,                  0 SOS.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
The primal and dual simplex pricing strategy set to 'Devex'.


Relaxed solution       31.7827586207 after          1 iter is B&B base.

MSG_LPOPTIMAL
Feasible solution               31.8 after          2 iter,         1 nodes (gap
 0.1%)
MSG_MILPFEASIBLE
Improved solution      31.7920010222 after          3 iter,         2 nodes (gap
 0.0%)
MSG_MILPBETTER

Optimal solution       31.7920010222 after          3 iter,         2 nodes (gap
 0.0%).

Excellent numeric accuracy ||*|| = 0

 MEMO: lp_solve version 5.5.2.11 for 32 bit OS, with 64 bit REAL variables.
      In the total iteration count 3, 0 (0.0%) were bound flips.
      There were 1 refactorizations, 0 triggered by time and 0 by density.
       ... on average 3.0 major pivots per refactorization.
      The largest [LUSOL v2.2.1.0] fact(B) had 6 NZ entries, 1.0x largest basis.

      The maximum B&B level was 2, 1.0x MIP order, 2 at the optimal solution.
      The constraint matrix inf-norm is 78.26, with a dynamic range of 978.25.
      Time to load data was 0.000 seconds, presolve used 0.001 seconds,
       ... 0.002 seconds in simplex solver, in total 0.003 seconds.
===Solver Foundation Service Report===
Date: 17-May-10 22:41:12
Version: Microsoft Solver Foundation 2.0.3.9657 Express Edition
Model Name: Default
Capabilities Applied: MILP
Solve Time (ms): 4
Total Time (ms): 5
Solve Completion Status: Optimal
Solver Selected: SolverFoundation.Plugin.LpSolve.LpSolveSolver
Directives:
LpSolve(SolveAntiDegen:ANTIDEGEN_FIXEDVARS, ANTIDEGEN_STALLING,SolveBasiscrash:C
RASH_NOTHING,SolveBbDepthlimit:-50,SolveBbFloorfirst:BRANCH_AUTOMATIC,SolveBbRul
e:NODE_PSEUDONONINTSELECT, NODE_GREEDYMODE, NODE_DYNAMICMODE, NODE_RCOSTFIXING,S
olveBreakAtFirst:False,SolveBreakAtValue:-1E+30,SolveDebug:False,SolveEpsb:1E-10
,SolveEpsd:1E-09,SolveEpsel:1E-12,SolveEpsint:1E-07,SolveEpsperturb:1E-05,SolveE
pspivot:2E-07,SolveImprove:IMPROVE_DEFAULT,SolveInfinite:1E+30,SolveMaxpivot:250
,SolveMipGapAbs:1E-11,SolveMipGapRel:1E-11,SolveNegrange:-1000000,SolveObjBound:
1E+30,SolveObjInBasis:True,SolvePivoting:PRICER_DEVEX, PRICE_ADAPTIVE,SolvePreso
lve:PRESOLVE_NONE,SolvePresolveMaxLoops:2147483647,SolveScalelimit:5,SolveScalin
g:SCALE_GEOMETRIC, SCALE_EQUILIBRATE, SCALE_INTEGERS,SolveSimplextype:SIMPLEX_DU
AL_PRIMAL,SolveSolutionlimit:1,SolveTimeout(s):4294967296,SolveTrace:False,Solve
Verbose:4,Arithmetic:Double,TimeLimit (ms):-1,GetSensitivity:False,MaximumGoalCo
unt:1)
===SolverDetails====
Iteration Count:3
Presolve loops:2147483647
Node Count:2
===Model details===
Variables:4
Rows:4
Non-zeros:11
===Solution Details===
Goals:
cost: 31.7920010222336

Decisions:
COLONE: 28.6
COLTWO: 0.0306670074111935
COLTHREE: 0
COLFOUR: 31

API examples

Example5

private static void LpSolveLogFunc(int lp, int userhandle, string buffer)
{
    Console.Write("{0}", buffer);
}

private static void LpSolveMsgFunc(int lp, int userhandle, LpSolveNativeInterface.lpsolve.lpsolve_msgmask message)
{
    Console.Write("{0}\n", message);
}

static void Example5()
{
    LpSolveSolver solver = new LpSolveSolver();
    //SimplexSolver solver = new SimplexSolver();

    // data about the projects.
    double[] estimatedProfitOfProjectX = new double[] { 1, 1.8, 1.6, 0.8, 1.4 };
    double[] capitalRequiredForProjectX = new double[] { 6, 12, 10, 4, 8 };
    double availableCapital = 20;
    // decision variables.
    int[] chooseProjectX = new int[5];
    int goal;
    solver.AddRow("goal", out goal);
    solver.AddGoal(goal, 0, false);
    int expenditure;
    solver.AddRow("expenditure", out expenditure);
    solver.SetBounds(expenditure, 0, availableCapital);
    for (int i = 0; i < 5; i++)
    {
        solver.AddVariable(string.Format("project{0}", i),
        out chooseProjectX[i]);
        solver.SetBounds(chooseProjectX[i], 0, 1);
        // we either choose or don't choose the project; no half way decisions.
        solver.SetIntegrality(chooseProjectX[i], true);
        solver.SetCoefficient(goal, chooseProjectX[i],
        estimatedProfitOfProjectX[i]);
        solver.SetCoefficient(expenditure, chooseProjectX[i],
        capitalRequiredForProjectX[i]);
    }

    LpSolveDirective simplex = new LpSolveDirective(); simplex.LpSolveReadParams(@"params.par", ""); simplex.GetSensitivity = true; simplex.LpSolveLogFunc = LpSolveLogFunc; simplex.LpSolveMsgFunc = LpSolveMsgFunc; LpSolveParams param = new LpSolveParams(simplex);
    //SimplexSolverParams param = new SimplexSolverParams(); param.MixedIntegerGenerateCuts = true;

    ILinearSolution solution = solver.Solve(param);

    ILinearSolverReport sensitivity = solver.GetReport(LinearSolverReportType.Sensitivity);

    Console.WriteLine(solver.MipResult);
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("Project {0} is {1} selected.", i,
        solver.GetValue(chooseProjectX[i]) == 1 ? "" : "not ");
    }
    Console.WriteLine("The estimated total profit is: ${0}.",
    (double)solver.GetValue(goal).ToDouble());
    Console.WriteLine("The total expenditure is: ${0}.",
    solver.GetValue(expenditure).ToDouble());

    solver.LpSolveWriteParams(@"params.par", "");
    solver.LpSolveWriteLp(@"a.lp");
    solver.LpSolveWriteMPS(@"a.mps", true);
    solver.LpSolvePrintDebugDump(@"a.txt");
}

This gives as output:

Model name:  '' - run #1
Objective:   Maximize(R0)

SUBMITTED
Model size:        1 constraints,       5 variables,            5 non-zeros.
Sets:                                   0 GUB,                  0 SOS.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
The primal and dual simplex pricing strategy set to 'Devex'.


Relaxed solution                3.52 after          2 iter is B&B base.

MSG_LPOPTIMAL
Feasible solution                  3 after          8 iter,         8 nodes (gap
 11.5%)
MSG_MILPFEASIBLE
Improved solution                3.4 after          9 iter,         9 nodes (gap
 2.7%)
MSG_MILPBETTER

Optimal solution                 3.4 after         10 iter,        10 nodes (gap
 2.7%).

Excellent numeric accuracy ||*|| = 0

 MEMO: lp_solve version 5.5.2.11 for 32 bit OS, with 64 bit REAL variables.
      In the total iteration count 10, 2 (20.0%) were bound flips.
      There were 5 refactorizations, 0 triggered by time and 0 by density.
       ... on average 1.6 major pivots per refactorization.
      The largest [LUSOL v2.2.1.0] fact(B) had 3 NZ entries, 1.0x largest basis.

      The maximum B&B level was 6, 0.6x MIP order, 3 at the optimal solution.
      The constraint matrix inf-norm is 12, with a dynamic range of 3.
      Time to load data was 0.013 seconds, presolve used 0.002 seconds,
       ... 0.003 seconds in simplex solver, in total 0.018 seconds.
Optimal
Project 0 is  selected.
Project 1 is not  selected.
Project 2 is  selected.
Project 3 is  selected.
Project 4 is not  selected.
The estimated total profit is: $3.4.
The total expenditure is: $20.

Example6

private class MyLpSolveSolver : LpSolveSolver
{
    public override void LpSolveLogFunc(int lp, int userhandle, string buffer)
    {
        base.LpSolveLogFunc(lp, userhandle, buffer);
        Console.Write("{0}", buffer);
    }

    public override void LpSolveMsgFunc(int lp, int userhandle, LpSolveNativeInterface.lpsolve.lpsolve_msgmask message)
    {
        base.LpSolveMsgFunc(lp, userhandle, message);
        Console.Write("{0}", message);
    }
}

static void Example6()
{
    MyLpSolveSolver solver = new MyLpSolveSolver();
    //SimplexSolver solver = new SimplexSolver();

    // add variables with their lower and upper bounds
    int savid, vzvid;
    solver.AddVariable("Saudi Arabia", out savid);
    solver.SetBounds(savid, 0, 9000);
    solver.AddVariable("Venezuela", out vzvid);
    solver.SetBounds(vzvid, 0, 6000);
    solver.SetIntegrality(vzvid, true);
    // add constraints to model
    int c1rid, c2rid, c3rid, goalrid;
    solver.AddRow("constraint1", out c1rid);
    solver.AddRow("constraint2", out c2rid);
    solver.AddRow("constraint3", out c3rid);
    solver.AddRow("goal", out goalrid);
    // add coefficients to constraint rows
    solver.SetCoefficient(c1rid, savid, 0.3);
    solver.SetCoefficient(c1rid, vzvid, 0.4);
    solver.SetBounds(c1rid, 2000, Rational.PositiveInfinity);
    solver.SetCoefficient(c2rid, savid, 0.4);
    solver.SetCoefficient(c2rid, vzvid, 0.2);
    solver.SetBounds(c2rid, 1500, Rational.PositiveInfinity);
    solver.SetCoefficient(c3rid, savid, 0.2);
    solver.SetCoefficient(c3rid, vzvid, 0.3);
    solver.SetBounds(c3rid, 500, Rational.PositiveInfinity);
    // add objective (goal) to model and specify minimization (==true)
    solver.SetCoefficient(goalrid, savid, 20);
    solver.SetCoefficient(goalrid, vzvid, 15);
    solver.AddGoal(goalrid, 1, true);
    // solve the model

    LpSolveDirective simplex = new LpSolveDirective(); simplex.GetSensitivity = true; ; simplex.LpSolveVerbose = 4; LpSolveParams parameter = new LpSolveParams(simplex);
    //SimplexSolverParams parameter = new SimplexSolverParams(); parameter.GetSensitivityReport = true;
    //SimplexSolverParams parameter = new DemoSimplexSolverParams(); parameter.GetSensitivityReport = true;

    ILinearSolution solution = solver.Solve(parameter);
    Console.WriteLine("SA {0}, VZ {1}, C1 {2}, C2 {3}, C3 {4}, Goal {5}",
    solver.GetValue(savid).ToDouble(), solver.GetValue(vzvid).ToDouble(),
    solver.GetValue(c1rid).ToDouble(), solver.GetValue(c2rid).ToDouble(),
    solver.GetValue(c3rid).ToDouble(), solver.GetValue(goalrid).ToDouble());

    Console.WriteLine("{0}", solver.PivotCount);
    Console.WriteLine("{0}", solver.AlgorithmUsed);

    Console.WriteLine("{0}", solver.GetDualValue(2).ToDouble());
    solver.LpSolveWriteParams(@"d:\brol\params.par", "");

    ILinearSolverReport report = solver.GetReport(LinearSolverReportType.Sensitivity);

    Report Report = report as Report;
    LinearReport lpReport = report as LinearReport;
}

This gives as output:

Model name:  '' - run #1
Objective:   Minimize(R0)

SUBMITTED
Model size:        3 constraints,       2 variables,            6 non-zeros.
Sets:                                   0 GUB,                  0 SOS.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
The primal and dual simplex pricing strategy set to 'Devex'.


Relaxed solution               92500 after          2 iter is B&B base.

MSG_LPOPTIMALFeasible solution              92500 after          2 iter,
 0 nodes (gap 0.0%)
MSG_MILPFEASIBLE
Optimal solution               92500 after          2 iter,         0 nodes (gap
 0.0%).

Excellent numeric accuracy ||*|| = 0

 MEMO: lp_solve version 5.5.2.11 for 32 bit OS, with 64 bit REAL variables.
      In the total iteration count 2, 0 (0.0%) were bound flips.
      There were 0 refactorizations, 0 triggered by time and 0 by density.
       ... on average 2.0 major pivots per refactorization.
      The largest [LUSOL v2.2.1.0] fact(B) had 4 NZ entries, 1.0x largest basis.

      The maximum B&B level was 1, 0.5x MIP order, 1 at the optimal solution.
      The constraint matrix inf-norm is 0.4, with a dynamic range of 2.
      Time to load data was 0.014 seconds, presolve used 0.002 seconds,
       ... 3.674 seconds in simplex solver, in total 3.690 seconds.
SA 2000, VZ 3500, C1 2000, C2 1500, C3 1450, Goal 92500
250
Primal
20

Example7

static void Example7()
{
    LpSolveSolver solver = new LpSolveSolver();
    int COLONE, COLTWO, COLTHREE, COLFOUR;

    solver.AddVariable("COLONE", out COLONE); solver.SetBounds(COLONE, 28.6, Rational.PositiveInfinity);
    solver.AddVariable("COLTWO", out COLTWO); solver.SetBounds(COLTWO, 0.0, Rational.PositiveInfinity);
    solver.AddVariable("COLTHREE", out COLTHREE); solver.SetBounds(COLTHREE, 0.0, Rational.PositiveInfinity);
    solver.AddVariable("COLFOUR", out COLFOUR); solver.SetBounds(COLFOUR, 18.0, 48.98);

    int THISROW, THATROW, LASTROW, goal;
    solver.AddRow("THISROW", out THISROW); solver.SetBounds(THISROW, 92.3, Rational.PositiveInfinity); solver.SetCoefficient(THISROW, COLTWO, 78.26); solver.SetCoefficient(THISROW, COLFOUR, 2.9);
    solver.AddRow("THATROW", out THATROW); solver.SetBounds(THATROW, Rational.NegativeInfinity, 14.8); solver.SetCoefficient(THATROW, COLONE, 0.24); solver.SetCoefficient(THATROW, COLTHREE, 11.31);
    solver.AddRow("LASTROW", out LASTROW); solver.SetBounds(LASTROW, 4.0, Rational.PositiveInfinity); solver.SetCoefficient(LASTROW, COLONE, 12.68); solver.SetCoefficient(LASTROW, COLTHREE, 0.08); solver.SetCoefficient(LASTROW, COLFOUR, 0.9);

    solver.AddRow("goal", out goal); solver.SetCoefficient(goal, COLONE, 1.0); solver.SetCoefficient(goal, COLTWO, 3.0); solver.SetCoefficient(goal, COLTHREE, 6.24); solver.SetCoefficient(goal, COLFOUR, 0.1);
    solver.AddGoal(goal, 1, true);

    LpSolveDirective simplex = new LpSolveDirective(); simplex.GetSensitivity = true; ; simplex.LpSolveVerbose = 4; LpSolveParams parameter = new LpSolveParams(simplex);
    ILinearSolution solution = solver.Solve(parameter);

    solver.LpSolveWriteLp("con");

    double Value;

    Console.WriteLine("GetValue:");
    foreach (int vid in solver.VariableIndices)
    {
        Value = solver.GetValue(vid).ToDouble();
        Console.WriteLine(solver.GetKeyFromIndex(vid) + ": Value: " + Value.ToString());
    }

    Console.WriteLine("GetDualValue:");
    foreach (int rid in solver.RowIndices)
    {
        if (!solver.IsGoal(rid))
        {
            Value = solver.GetDualValue(rid).ToDouble();
            Console.WriteLine(solver.GetKeyFromIndex(rid) + ": Value: " + Value.ToString());
        }
    }
    foreach (int vid in solver.VariableIndices)
    {
        Value = solver.GetDualValue(vid).ToDouble();
        Console.WriteLine(solver.GetKeyFromIndex(vid) + ": Value: " + Value.ToString());
    }

    LinearSolverSensitivityRange x;

    Console.WriteLine("Variable GetVariableRange:");
    foreach (int vid in solver.VariableIndices)
    {
        x = solver.GetVariableRange(vid);
        Console.WriteLine(solver.GetKeyFromIndex(vid) + ": Current: " + x.Current.ToDouble().ToString() + ", Lower: " + x.Lower.ToDouble().ToString() + ", Upper: " + x.Upper.ToDouble().ToString());
    }

    Console.WriteLine("RHS GetVariableRange:");
    foreach (int rid in solver.RowIndices)
    {
        if (!solver.IsGoal(rid))
        {
            x = solver.GetVariableRange(rid);
            Console.WriteLine(solver.GetKeyFromIndex(rid) + ": Current: " + x.Current.ToDouble().ToString() + ", Lower: " + x.Lower.ToDouble().ToString() + ", Upper: " + x.Upper.ToDouble().ToString());
        }
    }

    Console.WriteLine("GetObjectiveCoefficientRange:");
    foreach (int vid in solver.VariableIndices)
    {
        x = solver.GetObjectiveCoefficientRange(vid);
        Console.WriteLine(solver.GetKeyFromIndex(vid) + ": Current: " + x.Current.ToDouble().ToString() + ", Lower: " + x.Lower.ToDouble().ToString() + ", Upper: " + x.Upper.ToDouble().ToString());
    }
}

This gives as output:

/* Objective function */
min: +C1 +3 C2 +6.24 C3 +0.1 C4;

/* Constraints */
+78.26 C2 +2.9 C4 >= 92.3;
+0.24 C1 +11.31 C3 <= 14.8;
+12.68 C1 +0.08 C3 +0.9 C4 >= 4;

/* Variable bounds */
C1 >= 28.6;
18 <= C4 <= 48.98;
GetValue:
COLONE: Value: 28.6
COLTWO: Value: 0
COLTHREE: Value: 0
COLFOUR: Value: 31.8275862068966
GetDualValue:
THISROW: Value: 0.0344827586206897
THATROW: Value: 0
LASTROW: Value: 0
COLONE: Value: 1
COLTWO: Value: 0.301379310344828
COLTHREE: Value: 6.24
COLFOUR: Value: 0
Variable GetVariableRange:
COLONE: Current: 28.6, Lower: -1.94359839007941, Upper: 61.6666666666667
COLTWO: Current: 0, Lower: -0.635599284436494, Upper: 0.512394582162024
COLTHREE: Current: 0, Lower: -4841.16034482759, Upper: 0.701679929266136
COLFOUR: Current: 18, Lower: -Infinity, Upper: Infinity
RHS GetVariableRange:
THISROW: Current: 92.3, Lower: 52.2, Upper: 142.042
THATROW: Current: 14.8, Lower: -Infinity, Upper: Infinity
LASTROW: Current: 4, Lower: -Infinity, Upper: Infinity
GetObjectiveCoefficientRange:
COLONE: Current: 1, Lower: 0, Upper: Infinity
COLTWO: Current: 3, Lower: 2.69862068965517, Upper: Infinity
COLTHREE: Current: 6.24, Lower: 0, Upper: Infinity
COLFOUR: Current: 0.1, Lower: -Infinity, Upper: 0.111167901865576

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from Scilab

./O-Matrix.htm000666 000000 000000 00000343002 13772705352 011554 0ustar00000000 000000 Using lpsolve from O-Matrix

Using lpsolve from O-Matrix

O-Matrix?

O-Matrix is an integrated environment for analysing and visualizing data, and building turnkey scientific and engineering computing solutions. The program includes hundreds of engineering and statistical functions for solving a broad range of technical computing problems. Easy-to-use and flexible plotting commands enable you to rapidly build design prototypes, and implement sophisticated systems.

The foundation of O-Matrix is a high-performance matrix language that is specifically designed for high-performance technical computing. The notation of this language will dramatically reduce your design and implementation efforts, and enable the construction of systems that execute far quicker than other interpreted environments. O-Matrix also provides a compatibility mode that enables you to run MATLAB m-files. This enables you to leverage existing m-files, and simplifies the transition to O-Matrix for users experienced with MATLAB.

The O-Matrix environment is interpreted which means your commands are immediately executed as you enter them. Textual output is displayed in the Command window, and plotting commands are displayed in one or more Graphic windows. The environment provides a debugger for debugging, analysing, and profiling complex algorithms.

We will not discuss the specifics of O-Matrix here but instead refer the reader to the O-Matrix website.

O-Matrix and lpsolve

lpsolve is callable from O-Matrix via a dynamic linked DLL function. As such, it looks like lpsolve is fully integrated with O-Matrix. Matrices can directly be transferred between O-Matrix and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for O-Matrix (especially for matrix support). So you have full control to the complete lpsolve functionality via the omlpsolve O-Matrix driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level script files that can make things a lot easier. See further in this article.

Quickstart

Compile and build omlpsolve:
----------------------------

1. Under Windows, the Microsoft Visual C/C++ compiler must be installed
   and the environment variables must be active do that when a command prompt
   is opened, the cl and nmake commands can be executed.

2. Go to directory lp_solve_5.5\extra\O-Matrix\lpsolve

3. To compile and build omlpsolve, enter the following command:
      cvc

Load the omlpsolve driver in the O-Matrix memory space:
-------------------------------------------------------

1. Under Windows, make sure that the lpsolve55.dll file is somewhere in the path
   (archive lp_solve_5.5.2.11_dev.zip)

2. A precompiled library is provided for Windows (omlpsolve.dll).

3. Start O-Matrix

4. Enter the following command in O-Matrix:
      O> dll <path>\omlpsolve.dll, omlpsolve
   This can also be added in autoexec.oms to automatically load the omlpsolve driver.

Note that O-Matrix version 5.8 or above is strongly recommended. Lower versions (at least 5.7) should work with this driver, but these versions don't have the ability to print information on the command prompt. For example default while a solve is done, information is printed to the command window. This will only be visible from version 5.8 or above.

O-Matrix is ideally suited to handle linear programming problems. These are problems in which you have a quantity, depending linearly on several variables, that you want to maximize or minimize subject to several constraints that are expressed as linear inequalities in the same variables.If the number of variables and the number of constraints are small, then there are numerous mathematical techniques for solving a linear programming problem. Indeed these techniques are often taught in high school or university level courses in finite mathematics.But sometimes these numbers are high, or even if low, the constants in the linear inequalities or the object expression for the quantity to be optimized may be numerically complicated in which case a software package like O-Matrix is required to effect a solution.

Installation

To make this possible, a driver program is needed: omlpsolve (omlpsolve.dll under Windows). This driver must be loaded in O-Matrix and O-Matrix can call the omlpsolve solver.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows). This has the advantage that the omlpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the Windows path.

So note the difference between the O-Matrix lpsolve driver that is called omlpsolve and the lpsolve library that implements the API that is called lpsolve55.

There are also some O-Matrix script files (.oms) as a quick start.

The first thing that must be done, each time O-Matrix is restarted and you want to use lpsolve is load the omlpsolve driver into the O-Matrix workspace. This is done via the dll command. Suppose that omlpsolve.dll is installed in c:\omwin\dll, then the following command must be used to load the driver:

dll c:\omwin\dll\omlpsolve.dll, omlpsolve

That is basically all you need to do. From now on, you can use the library. This until a clear command is given or O-Matrix is restarted. Then this command must be given again to reload the library.

To make things easier, you can edit the file autoexec.oms with your favourite editor (or notepad) in the omwin folder and add above line at the end of this file (before the last end). That will automatically load the lpsolve driver in memory when O-Matrix is started and also when a clear command is executed. So it will appear as if the omlpsolve command is then always available.

To test if everything is installed correctly, enter omlpsolve in the O-Matrix command prompt. If it gives the following, then everything is ok:

omlpsolve O-Matrix Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: [ret1, ret2, ...] = omlpsolve("functionname", arg1, arg2, ...)

Possibly, this is followed with:

No printing capability to command window available.
You need to upgrade to version 5.8 for this feature.

Then you are working with an O-Matrix version lower than 5.8. The driver should work, but nothing is printed on the command window when lpsolve has something to report (for example while solving).

However, if you get a message box with the following:

The identifier omlpsolve is not defined.

Then either the dll command that was previous given was unsuccessful (or not given at all) or something was misspelled after the ,

If you get the following:

This application has failed to start because lpsolve55.dll was not found.
Re-installing the application may fix this problem.

Then O-Matrix can find the omlpsolve driver program, but the driver program cannot find the lpsolve library that contains the lpsolve implementation. This library is called lpsolve55.dll and should be on your system in a directory that in the PATH environment variable. This path can be shown via the command getenv("PATH")

The lpsolve55.dll files must be in one of these specified directories. It is common to place this in the WINDOWS\system32 folder.

All this is developed and tested with O-Matrix version 5.7. This is the minimum supported release. Older releases are unsupported.

Solve an lp model from O-Matrix via omlpsolve

In the following text, O> before the O-Matrix commands is the O-Matrix command line. Only the text after O> must be entered.

To call an lpsolve function, the following syntax must be used:

O> [ret1, ret2, ...] = omlpsolve("functionname", arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between double quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra O-Matrix specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in O-Matrix, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the O-Matrix functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from O-Matrix, nothing must be dimensioned in advance. The omlpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to omlpsolve. Never as argument to the routine. This can be a single value as for get_objective (although O-Matrix stores this in a 1x1 matrix) or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

An example

(Note that you can execute this example by entering command per command as shown below or by just entering example1. This will execute example1.oms.)

O> lp=omlpsolve("make_lp", 0, 4);
O> omlpsolve("set_verbose", lp, 3);
O> omlpsolve("set_obj_fn", lp, [1, 3, 6.24, 0.1]);
O> omlpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], 2, 92.3);
O> omlpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);
O> omlpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], 2, 4);
O> omlpsolve("set_lowbo", lp, 1, 28.6);
O> omlpsolve("set_lowbo", lp, 4, 18);
O> omlpsolve("set_upbo", lp, 4, 48.98);
O> omlpsolve("set_col_name", lp, 1, "COLONE");
O> omlpsolve("set_col_name", lp, 2, "COLTWO");
O> omlpsolve("set_col_name", lp, 3, "COLTHREE");
O> omlpsolve("set_col_name", lp, 4, "COLFOUR");
O> omlpsolve("set_row_name", lp, 1, "THISROW");
O> omlpsolve("set_row_name", lp, 2, "THATROW");
O> omlpsolve("set_row_name", lp, 3, "LASTROW");
O> omlpsolve("write_lp", lp, "a.lp");
O> omlpsolve("get_mat", lp, 1, 2)
   78.2600
O> omlpsolve("solve", lp)
     0
O> omlpsolve("get_objective", lp)
   31.7828
O> omlpsolve("get_variables", lp)
{
28.6
0
0
31.8276
}

O> omlpsolve("get_constraints", lp)
{
92.3
6.8640
391.293
}

Note that there are some commands that return an answer. To see the answer, the command was not terminated with a semicolon (;). If the semicolon is put at the end of a command, the answer is not shown. However it is also possible to write the answer in a variable. In that case the result is never shown. With or without a terminating semicolon. For example:

O> obj=omlpsolve("get_objective", lp)

Or:

O> obj=omlpsolve("get_objective", lp);

Both will only write the result in variable obj without showing anything on screen. get_variables and get_constraints return a vector with the result. This can also be put in a variable:

O> x=omlpsolve("get_variables", lp);
O> b=omlpsolve("get_constraints", lp);

It is always possible to show the contents of a variable by just giving it as command:

O> x
{
28.6
0
0
31.8276
}

Don't forget to free the handle and its associated memory when you are done:

O> omlpsolve("delete_lp", lp);

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
O> lp=omlpsolve("make_lp", 0, 4);
O> omlpsolve("set_lp_name", lp, "mymodel");
O> omlpsolve("set_verbose", "mymodel", 3);
O> omlpsolve("set_obj_fn", "mymodel", [1, 3, 6.24, 0.1]);
O> omlpsolve("add_constraint", "mymodel", [0, 78.26, 0, 2.9], 2, 92.3);
O> omlpsolve("add_constraint", "mymodel", [0.24, 0, 11.31, 0], 1, 14.8);
O> omlpsolve("add_constraint", "mymodel", [12.68, 0, 0.08, 0.9], 2, 4);
O> omlpsolve("set_lowbo", "mymodel", 1, 28.6);
O> omlpsolve("set_lowbo", "mymodel", 4, 18);
O> omlpsolve("set_upbo", "mymodel", 4, 48.98);
O> omlpsolve("set_col_name", "mymodel", 1, "COLONE");
O> omlpsolve("set_col_name", "mymodel", 2, "COLTWO");
O> omlpsolve("set_col_name", "mymodel", 3, "COLTHREE");
O> omlpsolve("set_col_name", "mymodel", 4, "COLFOUR");
O> omlpsolve("set_row_name", "mymodel", 1, "THISROW");
O> omlpsolve("set_row_name", "mymodel", 2, "THATROW");
O> omlpsolve("set_row_name", "mymodel", 3, "LASTROW");
O> omlpsolve("write_lp", "mymodel", "a.lp");
O> omlpsolve("get_mat", "mymodel", 1, 2)
   78.2600
O> omlpsolve("solve", "mymodel")
     0
O> omlpsolve("get_objective", "mymodel")
   31.7828
O> omlpsolve("get_variables", "mymodel")
{
28.6
0
0
31.8276
}

O> omlpsolve("get_constraints", "mymodel")
{
92.3
6.8640
391.293
}

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific O-Matrix routine to get the handle from the model name: get_handle.
For example:

O> omlpsolve("get_handle", "mymodel")
0

Don't forget to free the handle and its associated memory when you are done:

O> omlpsolve("delete_lp", "mymodel")

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

In O-Matrix, all numerical data is stored in matrices; even a scalar variable. O-Matrix also supports complex numbers. omlpsolve can only work with real numbers. For example:
O> omlpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);

Most of the time, variables are used to provide the data:

O> omlpsolve("add_constraint", lp, a1, 1, 14.8);

Where a1 is a matrix variable.

Matrices with too few or too much elements gives an 'invalid vector.' error.

Most of the time, omlpsolve needs vectors (rows or columns). In all situations, it doesn't matter if the vectors are row or column vectors. The driver accepts them both. For example:

O> omlpsolve("add_constraint", lp, {0.24, 0, 11.31, 0}, 1, 14.8);

Which is a column vector, but it is also accepted.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the O-Matrix interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the O-Matrix matrix.

Maximum usage of matrices with omlpsolve

Because O-Matrix is all about matrices, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the omlpsolve O-Matrix driver to also work with matrices. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The omlpsolve O-Matrix driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = omlpsolve("set_int", lp, column, must_be_int). The matrix version of this call is: return = omlpsolve("set_int", lp, [must_be_int]). The API call to return the integer status of a variable is: return = omlpsolve("is_int", lp, column). The matrix version of this call is: [is_int] = omlpsolve("is_int", lp)
Also note the get_mat and set_mat routines. In O-Matrix these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by just entering example2. This will execute example2.oms.)

O> lp=omlpsolve("make_lp", 0, 4);
O> omlpsolve("set_verbose", lp, 3);
O> omlpsolve("set_obj_fn", lp, [1, 3, 6.24, 0.1]);
O> omlpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], 2, 92.3);
O> omlpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);
O> omlpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], 2, 4);
O> omlpsolve("set_lowbo", lp, [28.6, 0, 0, 18]);
O> omlpsolve("set_upbo", lp, [INF, INF, INF, 48.98]);
O> omlpsolve("set_col_name", lp, {"COLONE", "COLTWO", "COLTHREE", "COLFOUR"});
O> omlpsolve("set_row_name", lp, {"THISROW", "THATROW", "LASTROW"});
O> omlpsolve("write_lp", lp, "a.lp");
O> omlpsolve("get_mat", lp)
{
[ 0 , 78.26 , 0 , 2.9 ]
[ 0.24 , 0 , 11.31 , 0 ]
[ 12.68 , 0 , 0.08 , 0.9 ]
}

O> omlpsolve("solve", lp)
0
O> omlpsolve("get_objective", lp)
31.7828
O> omlpsolve("get_variables", lp)
{
28.6
0
0
31.8276
}

O> omlpsolve("get_constraints", lp)
{
92.3
6.8640
391.293
}

Note the usage of INF in set_upbo. This stands for "infinity". Meaning an infinite upper bound. It is also possible to use -INF to express minus infinity. This can for example be used to create a free variable.

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example:

O> A=omlpsolve("get_mat", lp);
O> X=omlpsolve("get_variables", lp);
O> B = A * X
O> B
{
92.3
6.864
391.293
}

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

O> omlpsolve("get_constraints", lp)
{
92.3
6.864
391.293
}

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

O> C=omlpsolve("get_obj_fn", lp);
O> X=omlpsolve("get_variables", lp);
O> obj = C * X
O> obj
31.7828

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

O> omlpsolve("get_objective", lp)
31.7828

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
O> lp=omlpsolve("make_lp", 0, 4);
O> omlpsolve("set_verbose", lp, 3);
O> omlpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], 2, 92.3);
O> omlpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], 1, 14.8);
O> omlpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], 2, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One could define all the possible constants in O-Matrix and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

O> lp=omlpsolve("make_lp", 0, 4);
O> omlpsolve("set_verbose", lp, "IMPORTANT");
O> omlpsolve("add_constraint", lp, [0, 78.26, 0, 2.9], "GE", 92.3);
O> omlpsolve("add_constraint", lp, [0.24, 0, 11.31, 0], "LE", 14.8);
O> omlpsolve("add_constraint", lp, [12.68, 0, 0.08, 0.9], "GE", 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

O> omlpsolve("set_verbose", lp, "blabla");
BLABLA: Unknown.

O> omlpsolve("set_verbose", lp, "GE");
GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. "LE", "GE" and "EQ" in add_constraint and is_constr_type can also be "<", "<=", ">", ">=", "=". When returned however, "GE", "LE", "EQ" will be used.

Also in the matrix version of calls, string constants are possible. For example:

O> omlpsolve("set_constr_type", lp, {"LE", "EQ", "GE"});

Some constants can be a combination of multiple constants. For example set_scaling:

O> omlpsolve("set_scaling", lp, 3+128);

With the string version of constants this can be done as following:

O> omlpsolve("set_scaling", lp, "SCALE_MEAN|SCALE_INTEGERS");

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

O> omlpsolve("set_scaling", lp, "SCALE_MEAN|SCALE_RANGE");
SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

O> omlpsolve("get_scaling", lp)
131

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

O> omlpsolve("return_constants", 1);

From now on, all returned constants are returned as string:

O> omlpsolve("get_scaling", lp)
SCALE_MEAN|SCALE_INTEGERS

Also when an array of constants is returned, they are returned as string when return_constants is set:

O> omlpsolve("get_constr_type", lp)

LE
EQ
GE

This for all routines until return_constants is again called with 0:

O> omlpsolve("return_constants", 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

O> omlpsolve("return_constants", 1)
1

To get the value without setting it, don"t provide the second argument:

O> omlpsolve("return_constants")
1

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don"t let you hold that back to use string constants in your code.

oms scripts

O-Matrix can execute a sequence of statements stored in files. Such files are called oms files because they must have the file type of ".oms" as the last part of their filename (extension).

oms scripts can be compared with batch files or scripts. You can put O-Matrix commands in them and execute them at any time. The oms script is executed like any other command, by entering its name (without the .oms extension).

The omlpsolve O-Matrix distribution contains some example oms scripts to demonstrate this.

You can also edit these files with your favourite text editor (or notepad).

example1.oms

Contains the commands as shown in the first example of this article. To execute and also see which commands are executed in the debug window, use following commands:

O> stop
O> trace on example1.oms
O> quit
O> example1

Note however that execution is much slower when trace is on. It is only used here to see the statements executed.

example2.oms

Contains the commands as shown in the second example of this article. To execute and also see which commands are executed in the debug window, use following commands:

O> stop
O> trace on example2.oms
O> quit
O> example2

Note however that execution is much slower when trace is on. It is only used here to see the statements executed.

example3.oms

Contains the commands of a practical example. See further in this article.

example4.oms

Contains the commands of a practical example. See further in this article.

example5.oms

Contains the commands of a practical example. See further in this article.

example6.oms

Contains the commands of a practical example. See further in this article.

lp_solve.oms

This script uses the API to create a higher-level function called lp_solve. This function accepts as arguments some matrices and options to create and solve an lp model. See the beginning of the file to see its usage:

 LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

O> include lp_solve.oms
O> [obj, x]=lp_solve([-1, 2], {[2, 1], [-4, 4]}, [5, 5], [-1, -1], [], [], [1, 2])
O> obj
3
O> x
{
1
2
}

lp_maker.oms

This script is analog to the lp_solve script and also uses the API to create a higher-level function called lp_maker. This function accepts as arguments some matrices and options to create an lp model. Note that this scripts only creates a model and returns a handle. See the beginning of the file to see its usage:

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

O> include lp_maker.oms
O> lp=lp_maker([-1, 2], {[2, 1], [-4, 4]}, [5, 5], [-1, -1], [], [], [1, 2])
O> lp
0

To solve the model and get the solution:

O> omlpsolve("solve", lp)
0
O> omlpsolve("get_objective", lp)
3
O> omlpsolve("get_variables", lp)
{
1
2
}

Don't forget to free the handle and its associated memory when you are done:

O> omlpsolve("delete_lp", lp);

lpdemo.oms

Contains several examples to build and solve lp models. To execute and also see which commands are executed in the debug window, use following commands:

O> stop
O> trace on lpdemo.oms
O> quit
O> lpdemo

Note however that execution is much slower when trace is on. It is only used here to see the statements executed.

ex.oms

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution. To execute and also see which commands are executed in the debug window, use following commands:

O> stop
O> trace on ex.oms
O> quit
O> ex

Note however that execution is much slower when trace is on. It is only used here to see the statements executed.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

O> clear
O> X = 0.1:0.05:125;
O> Y1 = (15000. - 120*X)/210;
O> bar(X, Y1)

Source

Now let's put in the other two constraint inequalities.

O> clear
O> X = 0.1:0.05:38;
O> mlmode
O> Y1 = (15000. - 120*X)/210;
O> Y2 = max((4000 - 110.*X)./30, 0);
O> Y3 = max(75 - X, 0.);
O> Ytop = min(min(Y1, Y2), Y3);
O> omatrix
O> bar(X, Ytop)
O> gtitle("Solution space")

Source

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.

O> mlmode meshgrid.m
O> [U, V] = meshgrid(0:1:40, 0:1:80);
O> Ur = U.row(1)
O> Vc = V.col(1)
O> Z = 143.*U + 60.*V
O> levels = (0:1:11)*1000.
O> contour(Z', levels, Ur', Vc');
O> gtitle("Solution space and objective")

Source

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 lp_solve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:

O> x = {[1, 1], [110, 30]} \ {75, 4000}
O> print "x =", x
x = {
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:

O> P = [143, 60] * x
O> print "Profit, P =", P
Profit, P = 6315.63

That is, $6315.63.

Note that these command are in script example3.oms

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

O> f = [143, 60];
O> A = {[120, 210], [110, 30], [1, 1]};
O> b = {15000, 4000, 75};
O> lp = lp_maker(f, A, b, [-1, -1, -1], [], [], [], 1, 0);
O> solvestat = omlpsolve("solve", lp)
O> omlpsolve("get_objective", lp)
6315.63
O> omlpsolve("get_variables", lp)
{
21.875
53.125
}
O> omlpsolve("delete_lp", lp);

Note that these command are in script example4.oms

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimentions, but beyound that it is all very theorethical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

O> f = [143, 60, 195];
O> A = {[120, 210, 150.75], [110, 30, 125], [1, 1, 1]};
O> b = {15000, 4000, 75};
O> lp = lp_maker(f, A, b, [-1, -1, -1], [], [], [], 1, 0);
O> solvestat = omlpsolve("solve", lp)
O> omlpsolve("get_objective", lp)
6986.84
O> omlpsolve("get_variables", lp)
{
0
56.5789
18.4211
}
O> omlpsolve("delete_lp", lp);

Note that these command are in script example5.oms

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that O-Matrix can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like O-Matrix is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
O> f = [110*1.3, 30*2.0, 125*1.56, 75*1.8, 95*.95, 100*2.25, 50*1.35];
O> A = {[120,210,150.75,115,186,140,85],[110,30,125,75,95,100,50],[1,1,1,1,1,1,1],
                  [1,-1,0,0,0,0,0],[0,0,1,0,-2,0,0],[0,0,0,-1,0,-1,1]};
O> b = {55000, 40000, 400, 0, 0, 0};
O> lp = lp_maker(f, A, b, [-1,-1,-1,-1,-1,-1],[10,10,10,10,20,20,20],[100,INF,50,INF,INF,250,INF],[],1,0);
O> solvestat = omlpsolve("solve", lp)
O> omlpsolve("get_objective", lp)
75398
O> omlpsolve("get_variables", lp)
{
10
10
40
45.6522
20
250
20
}
O> omlpsolve("delete_lp", lp);

Note that these command are in script example6.oms

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that Inf is used for variables that have no upper limit. This stands for Infinity.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using O-Matrix:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into O-Matrix format we get:

f = [4, 2, 1]
A = {[2, 1, 0], [1, 0, 2], [1, 1, 1]}
b = {1, 2, 1}

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0, 0, 0]
u = [ 1, 1, 2]

Now lets enter this in O-Matrix:

O> f = [4, 2, 1];
O> A = {[2, 1, 0], [1, 0, 2], [1, 1, 1]};
O> b = {1, 2, 1};
O> l = [ 0, 0, 0];
O> u = [ 1, 1, 2];

Now solve the linear program using O-Matrix: Type the commands

O> lp = lp_maker(f, A, b, [-1, -1, -1], l, u, [], 1, 0);
O> solvestat = omlpsolve("solve", lp)
O> omlpsolve("get_objective", lp)
2.5
O> omlpsolve("get_variables", lp)
{
0.5
0
0.5
}
O> omlpsolve("delete_lp", lp)

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the O-Matrix command:

O> l = [];

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -INF as lower bounds:

O> l = [-INF, -INF, -INF];

Solve this and you get a different result:

O> lp = lp_maker(f, A, b, [-1, -1, -1], l, u, [], 1, 0);
O> solvestat = omlpsolve("solve", lp)
O> omlpsolve("get_objective", lp)
2.66667
O> omlpsolve("get_variables", lp)
{
0.666667
-0.333333
0.666667
}
O> omlpsolve("delete_lp", lp)

Overview of API routines

Note that everwhere where lp is used as argument that this can be a handle (lp_handle) or the models name.

  • add_column, add_columnex
    • return = omlpsolve("add_column", lp, [column])
    • return = omlpsolve("add_columnex", lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = omlpsolve("add_constraint", lp, [row], constr_type, rh)
    • return = omlpsolve("add_constraintex", lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = omlpsolve("add_SOS", lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in O-Matrix since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = omlpsolve("column_in_lp", lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = omlpsolve("copy_lp", lp)
    • No special considerations.
  • default_basis
    • omlpsolve("default_basis", lp)
    • No special considerations.
  • del_column
    • return = omlpsolve("del_column", lp, column)
    • No special considerations.
  • del_constraint
    • return = omlpsolve("del_constraint", lp, del_row)
    • No special considerations.
  • delete_lp
    • omlpsolve("delete_lp", lp)
    • No special considerations.
  • free_lp
    • omlpsolve("free_lp", lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = omlpsolve("get_anti_degen", lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = omlpsolve("get_basis", lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in O-Matrix. If not provided, then 0 is used.
  • get_basiscrash
    • return = omlpsolve("get_basiscrash", lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = omlpsolve("get_bb_depthlimit", lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = omlpsolve("get_bb_floorfirst", lp)
    • No special considerations.
  • get_bb_rule
    • return = omlpsolve("get_bb_rule", lp)
    • No special considerations.
  • get_bounds_tighter
    • return = omlpsolve("get_bounds_tighter", lp)
    • No special considerations.
  • get_break_at_value
    • return = omlpsolve("get_break_at_value", lp)
    • No special considerations.
  • get_col_name
    • name = omlpsolve("get_col_name", lp, column)
    • [names] = omlpsolve("get_col_name", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_column get_columnex
    • [column, return] = omlpsolve("get_column", lp, col_nr)
    • [column, return] = omlpsolve("get_columnex", lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = omlpsolve("get_constr_type", lp, row)
    • [constr_type] = omlpsolve("get_constr_type", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_constr_value
    • return = omlpsolve("get_constr_value", lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = omlpsolve("get_constraints", lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = omlpsolve("get_dual_solution", lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = omlpsolve("get_epsb", lp)
    • No special considerations.
  • get_epsd
    • return = omlpsolve("get_epsd", lp)
    • No special considerations.
  • get_epsel
    • return = omlpsolve("get_epsel", lp)
    • No special considerations.
  • get_epsint
    • return = omlpsolve("get_epsint", lp)
    • No special considerations.
  • get_epsperturb
    • return = omlpsolve("get_epsperturb", lp)
    • No special considerations.
  • get_epspivot
    • return = omlpsolve("get_epspivot", lp)
    • No special considerations.
  • get_improve
    • return = omlpsolve("get_improve", lp)
    • No special considerations.
  • get_infinite
    • return = omlpsolve("get_infinite", lp)
    • No special considerations.
  • get_lowbo
    • return = omlpsolve("get_lowbo", lp, column)
    • [return] = omlpsolve("get_lowbo", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_lp_index
    • return = omlpsolve("get_lp_index", lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = omlpsolve("get_lp_name", lp)
    • No special considerations.
  • get_mat
    • value = omlpsolve("get_mat", lp, row, col)
    • [matrix, return] = omlpsolve("get_mat", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix in the first return value. The return code of the call is the second return value.
  • get_max_level
    • return = omlpsolve("get_max_level", lp)
    • No special considerations.
  • get_maxpivot
    • return = omlpsolve("get_maxpivot", lp)
    • No special considerations.
  • get_mip_gap
    • return = omlpsolve("get_mip_gap", lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = omlpsolve("get_nameindex", lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = omlpsolve("get_Ncolumns", lp)
    • No special considerations.
  • get_negrange
    • return = omlpsolve("get_negrange", lp)
    • No special considerations.
  • get_nonzeros
    • return = omlpsolve("get_nonzeros", lp)
    • No special considerations.
  • get_Norig_columns
    • return = omlpsolve("get_Norig_columns", lp)
    • No special considerations.
  • get_Norig_rows
    • return = omlpsolve("get_Norig_rows", lp)
    • No special considerations.
  • get_Nrows
    • return = omlpsolve("get_Nrows", lp)
    • No special considerations.
  • get_obj_bound
    • return = omlpsolve("get_obj_bound", lp)
    • No special considerations.
  • get_objective
    • return = omlpsolve("get_objective", lp)
    • No special considerations.
  • get_orig_index
    • return = omlpsolve("get_orig_index", lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = omlpsolve("get_origcol_name", lp, column)
    • [names] = omlpsolve("get_origcol_name", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_origrow_name
    • name = omlpsolve("get_origrow_name", lp, row)
    • [names] = omlpsolve("get_origrow_name", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_pivoting
    • return = omlpsolve("get_pivoting", lp)
    • No special considerations.
  • get_presolve
    • return = omlpsolve("get_presolve", lp)
    • No special considerations.
  • get_presolveloops
    • return = omlpsolve("get_presolveloops", lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = omlpsolve("get_primal_solution", lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = omlpsolve("get_print_sol", lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = omlpsolve("get_rh", lp, row)
    • [rh] = omlpsolve("get_rh", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_rh_range
    • return = omlpsolve("get_rh_range", lp, row)
    • [rh_ranges] = omlpsolve("get_rh_range", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_row get_rowex
    • [row, return] = omlpsolve("get_row", lp, row_nr)
    • [row, return] = omlpsolve("get_rowex", lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = omlpsolve("get_row_name", lp, row)
    • [names] = omlpsolve("get_row_name", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_scalelimit
    • return = omlpsolve("get_scalelimit", lp)
    • No special considerations.
  • get_scaling
    • return = omlpsolve("get_scaling", lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = omlpsolve("get_sensitivity_obj", lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = omlpsolve("get_sensitivity_objex", lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that O-Matrix allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = omlpsolve("get_sensitivity_obj", lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, O-Matrix always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = omlpsolve("get_sensitivity_rhs", lp)
    • [duals, dualsfrom, dualstill, return] = omlpsolve("get_sensitivity_rhsex", lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that O-Matrix allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = omlpsolve("get_sensitivity_rhs", lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = omlpsolve("get_simplextype", lp)
    • No special considerations.
  • get_solutioncount
    • return = omlpsolve("get_solutioncount", lp)
    • No special considerations.
  • get_solutionlimit
    • return = omlpsolve("get_solutionlimit", lp)
    • No special considerations.
  • get_status
    • return = omlpsolve("get_status", lp)
    • No special considerations.
  • get_statustext
    • return = omlpsolve("get_statustext", lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = omlpsolve("get_timeout", lp)
    • No special considerations.
  • get_total_iter
    • return = omlpsolve("get_total_iter", lp)
    • No special considerations.
  • get_total_nodes
    • return = omlpsolve("get_total_nodes", lp)
    • No special considerations.
  • get_upbo
    • return = omlpsolve("get_upbo", lp, column)
    • [upbo] = omlpsolve("get_upbo", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_var_branch
    • return = omlpsolve("get_var_branch", lp, column)
    • [var_branch] = omlpsolve("get_var_branch", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_var_dualresult
    • return = omlpsolve("get_var_dualresult", lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = omlpsolve("get_var_primalresult", lp, index)
    • No special considerations.
  • get_var_priority
    • return = omlpsolve("get_var_priority", lp, column)
    • [var_priority] = omlpsolve("get_var_priority", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • get_variables
    • [var, return] = omlpsolve("get_variables", lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = omlpsolve("get_verbose", lp)
    • No special considerations.
  • get_working_objective
    • return = omlpsolve("get_working_objective", lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = omlpsolve("guess_basis", lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
  • has_BFP
    • return = omlpsolve("has_BFP", lp)
    • No special considerations.
  • has_XLI
    • return = omlpsolve("has_XLI", lp)
    • No special considerations.
  • is_add_rowmode
    • return = omlpsolve("is_add_rowmode", lp)
    • No special considerations.
  • is_anti_degen
    • return = omlpsolve("is_anti_degen", lp, testmask)
    • No special considerations.
  • is_binary
    • return = omlpsolve("is_binary", lp, column)
    • [binary] = omlpsolve("is_binary", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • is_break_at_first
    • return = omlpsolve("is_break_at_first", lp)
    • No special considerations.
  • is_constr_type
    • return = omlpsolve("is_constr_type", lp, row, mask)
    • No special considerations.
  • is_debug
    • return = omlpsolve("is_debug", lp)
    • No special considerations.
  • is_feasible
    • return = omlpsolve("is_feasible", lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = omlpsolve("is_free", lp, column)
    • return = omlpsolve("is_unbounded", lp, column)
    • [free] = omlpsolve("is_free", lp)
    • [free] = omlpsolve("is_unbounded", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • is_infinite
    • return = omlpsolve("is_infinite", lp, value)
    • No special considerations.
  • is_int
    • return = omlpsolve("is_int", lp, column)
    • [int] = omlpsolve("is_int", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • is_integerscaling
    • return = omlpsolve("is_integerscaling", lp)
    • No special considerations.
  • is_maxim
    • return = omlpsolve("is_maxim", lp)
    • No special considerations.
  • is_nativeBFP
    • return = omlpsolve("is_nativeBFP", lp)
    • No special considerations.
  • is_nativeXLI
    • return = omlpsolve("is_nativeXLI", lp)
    • No special considerations.
  • is_negative
    • return = omlpsolve("is_negative", lp, column)
    • [negative] = omlpsolve("is_negative", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • is_piv_mode
    • return = omlpsolve("is_piv_mode", lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = omlpsolve("is_piv_rule", lp, rule)
    • No special considerations.
  • is_presolve
    • return = omlpsolve("is_presolve", lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = omlpsolve("is_scalemode", lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = omlpsolve("is_scaletype", lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = omlpsolve("is_semicont", lp, column)
    • [semicont] = omlpsolve("is_semicont", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • is_SOS_var
    • return = omlpsolve("is_SOS_var", lp, column)
    • [SOS_var] = omlpsolve("is_SOS_var", lp)
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a O-Matrix matrix.
  • is_trace
    • return = omlpsolve("is_trace", lp)
    • No special considerations.
  • is_use_names
    • return = omlpsolve("is_use_names", lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = omlpsolve("lp_solve_version")
    • The omlpsolve API routine returns the version information in 4 provided argument variables while the O-Matrix version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = omlpsolve("make_lp", rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • omlpsolve("print_constraints", lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
    • The same information can also be obtained via omlpsolve("get_constraints", lp). This shows the result on screen.
  • print_debugdump
    • return = omlpsolve("print_debugdump", lp, filename)
    • No special considerations.
  • print_duals
    • omlpsolve("print_duals", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
    • The same information can be obtained via omlpsolve("get_dual_solution", lp). This shows the result on screen.
  • print_lp
    • omlpsolve("print_lp", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
  • print_objective
    • omlpsolve("print_objective", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
    • The same information can be obtained via omlpsolve("get_objective", lp). This shows the result on screen.
  • print_scales
    • omlpsolve("print_scales", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
  • print_solution
    • omlpsolve("print_solution", lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
    • The same information can also be obtained via omlpsolve("get_variables", lp). This shows the result on screen.
  • print_str
    • omlpsolve("print_str", lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
  • print_tableau
    • omlpsolve("print_tableau", lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under O-Matrix (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the omlpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows O-Matrix) to the command window of O-Matrix. As such, all reported output can be seen in O-Matrix. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines. Note that at least O-Matrix version 5.8 is needed to see this information on the command window. Older versions will not print information on the command window.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = omlpsolve("read_basis", lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = omlpsolve("read_freemps", filename {, options})
    • lp_handle = omlpsolve("read_freeMPS", filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In O-Matrix it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = omlpsolve("read_lp", filename {, verbose {, lp_name}})
    • lp = omlpsolve("read_LP", filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In O-Matrix it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ("").
  • read_mps, read_MPS
    • lp_handle = omlpsolve("read_mps", filename {, options})
    • lp_handle = omlpsolve("read_MPS", filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In O-Matrix it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = omlpsolve("read_params", lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = omlpsolve("read_XLI", xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, "" (NULL) is taken. "" is taken as NULL.
    • options is optional. When not provided, "" is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • omlpsolve("set_basisvar", lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = omlpsolve("set_add_rowmode", lp, turnon)
    • No special considerations.
  • set_anti_degen
    • omlpsolve("set_anti_degen", lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = omlpsolve("set_basis", lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
  • set_basiscrash
    • omlpsolve("set_basiscrash", lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • omlpsolve("set_bb_depthlimit", lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • omlpsolve("set_bb_floorfirst", lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • omlpsolve("set_bb_rule", lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = omlpsolve("set_BFP", lp, filename)
    • No special considerations.
  • set_binary
    • return = omlpsolve("set_binary", lp, column, must_be_bin)
    • return = omlpsolve("set_binary", lp, [must_be_bin])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = omlpsolve("set_bounds", lp, column, lower, upper)
    • return = omlpsolve("set_bounds", lp, [lower], [upper])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • omlpsolve("set_bounds_tighter", lp, tighten)
    • No special considerations.
  • set_break_at_first
    • omlpsolve("set_break_at_first", lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • omlpsolve("set_break_at_value", lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = omlpsolve("set_col_name", lp, column, name)
    • return = omlpsolve("set_col_name", lp, [names])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_column, set_columnex
    • return = omlpsolve("set_column", lp, col_no, [column])
    • return = omlpsolve("set_columnex", lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = omlpsolve("set_constr_type", lp, row, con_type)
    • return = omlpsolve("set_constr_type", lp, [con_type])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • omlpsolve("set_debug", lp, debug)
    • No special considerations.
  • set_epsb
    • omlpsolve("set_epsb", lp, epsb)
    • No special considerations.
  • set_epsd
    • omlpsolve("set_epsd", lp, epsd)
    • No special considerations.
  • set_epsel
    • omlpsolve("set_epsel", lp, epsel)
    • No special considerations.
  • set_epsint
    • omlpsolve("set_epsint", lp, epsint)
    • No special considerations.
  • set_epslevel
    • omlpsolve("set_epslevel", lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • omlpsolve("set_epsperturb", lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • omlpsolve("set_epspivot", lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = omlpsolve("set_free", lp, column)
    • return = omlpsolve("set_unbounded", lp, column)
    • No special considerations.
  • set_improve
    • omlpsolve("set_improve", lp, improve)
    • No special considerations.
  • set_infinite
    • omlpsolve("set_infinite", lp, infinite)
    • No special considerations.
  • set_int
    • return = omlpsolve("set_int", lp, column, must_be_int)
    • return = omlpsolve("set_int", lp, [must_be_int])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = omlpsolve("set_lowbo", lp, column, value)
    • return = omlpsolve("set_lowbo", lp, [values])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = omlpsolve("set_lp_name", lp, name)
    • In O-Matrix, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = omlpsolve("set_mat", lp, row, column, value)
    • return = omlpsolve("set_mat", lp, [matrix])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. The matrix must be two-dimentional.
  • set_maxim
    • omlpsolve("set_maxim", lp)
    • No special considerations.
  • set_maxpivot
    • omlpsolve("set_maxpivot", max_num_inv)
    • No special considerations.
  • set_minim
    • omlpsolve("set_minim", lp)
    • No special considerations.
  • set_mip_gap
    • omlpsolve("set_mip_gap", lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • omlpsolve("set_negrange", negrange)
    • No special considerations.
  • set_obj
    • return = omlpsolve("set_obj", lp, column, value)
    • return = omlpsolve("set_obj", lp, [values])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • omlpsolve("set_obj_bound", lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = omlpsolve("set_obj_fn", lp, [row])
    • return = omlpsolve("set_obj_fnex", lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
  • set_outputfile
    • return = omlpsolve("set_outputfile", lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In O-Matrix under Windows, output to stdout it not shown. However it results in closing the file. Use "" to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • omlpsolve("set_pivoting", lp, pivoting)
    • No special considerations.
  • set_preferdual
    • omlpsolve("set_preferdual", lp, dodual)
    • No special considerations.
  • set_presolve
    • omlpsolve("set_presolve", lp, do_presolve {, maxloops})
    • The maxloops argument is optional in O-Matrix. If not provided, then infinite is used.
  • set_print_sol
    • omlpsolve("set_print_sol", lp, print_sol)
    • No special considerations.
  • set_rh
    • return = omlpsolve("set_rh", lp, row, value)
    • return = omlpsolve("set_rh", lp, [values])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = omlpsolve("set_rh_range", lp, row, deltavalue)
    • return = omlpsolve("set_rh_range", lp, [deltavalues])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • omlpsolve("set_rh_vec", lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = omlpsolve("set_row", lp, row_no, [row])
    • return = omlpsolve("set_rowex", lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In O-Matrix, there is no unused element in the matrix.
  • set_row_name
    • return = omlpsolve("set_row_name", lp, row, name)
    • return = omlpsolve("set_row_name", lp, [names])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_scalelimit
    • omlpsolve("set_scalelimit", lp, scalelimit)
    • No special considerations.
  • set_scaling
    • omlpsolve("set_scaling", lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = omlpsolve("set_semicont", lp, column, must_be_sc)
    • return = omlpsolve("set_semicont", lp, [must_be_sc])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • omlpsolve("set_sense", lp, maximize)
    • No special considerations.
  • set_simplextype
    • omlpsolve("set_simplextype", lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • omlpsolve("set_solutionlimit", lp, simplextype)
    • No special considerations.
  • set_timeout
    • omlpsolve("set_timeout", lp, sectimeout)
    • No special considerations.
  • set_trace
    • omlpsolve("set_trace", lp, trace)
    • No special considerations.
  • set_upbo
    • return = omlpsolve("set_upbo", lp, column, value)
    • return = omlpsolve("set_upbo", lp, [values])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • omlpsolve("set_use_names", lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = omlpsolve("set_var_branch", lp, column, branch_mode)
    • return = omlpsolve("set_var_branch", lp, [branch_mode])
    • In O-Matrix, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = omlpsolve("set_var_weights", lp, [weights])
    • No special considerations.
  • set_verbose
    • omlpsolve("set_verbose", lp, verbose)
    • No special considerations.
  • set_XLI
    • return = omlpsolve("set_XLI", lp, filename)
    • No special considerations.
  • solve
    • result = omlpsolve("solve", lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = omlpsolve("time_elapsed", lp)
    • No special considerations.
  • unscale
    • omlpsolve("unscale", lp)
    • No special considerations.
  • write_basis
    • omlpsolve("write_basis", lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = omlpsolve("write_freemps", lp, filename)
    • return = omlpsolve("write_freeMPS", lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In O-Matrix it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = omlpsolve("write_lp", lp, filename)
    • return = omlpsolve("write_LP", lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In O-Matrix it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = omlpsolve("write_mps", lp, filename)
    • return = omlpsolve("write_MPS", lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In O-Matrix it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = omlpsolve("write_XLI", lp, filename {, options {, results}})
    • No special considerations.

Extra O-Matrix routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = omlpsolve("get_col_names", lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = omlpsolve("get_constr_types", lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = omlpsolve("get_int", lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = omlpsolve("get_no_cols", lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = omlpsolve("get_no_rows", lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = omlpsolve("get_objective_name", lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = omlpsolve("get_obj_fn", lp)
    [row_vec, return] = omlpsolve("get_obj_fun", lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = omlpsolve("get_problem_name", lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = omlpsolve("get_reduced_costs", lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = omlpsolve("get_row_names", lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = omlpsolve("get_solution", lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = omlpsolve("mat_elm", lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = omlpsolve("print_handle")
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = omlpsolve("read_lp_file", filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = omlpsolve("get_handle", lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = omlpsolve("return_constants"[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the omlpsolve driver

Windows

Under Windows, the omlpsolve O-Matrix driver is a dll: omlpsolve.dll
This dll is an interface to the lpsolve55.dll lpsolve dll that contains the implementation of lp_solve. lpsolve55.dll is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip). The omlpsolve O-Matrix driver dll (omlpsolve.dll) is just a wrapper between O-Matrix and lp_solve to translate the input/output to/from O-Matrix and the lp_solve library.

The omlpsolve O-Matrix driver is written in C. To compile this code, Microsoft compiler is needed. Other compilers might also work, but this is untested. To make the compilation process easier, a batch file can be used: cvc.bat
It may be necessary to edit this file first to change the path where lp_solve and the O-Matrix dll sources are installed. Change at the beginning lpsolvepath and dllsrcpath. dllsrcpath must point to the folder where dll.h is located.
To make for release, just enter cvc and everything is build.
This compiles three source files: lpsolve.c, omatrix.c and hash.c
Then these are linked with the library lpsolve55.lib to generate the omlpsolve.dll file.
The optional arguments to cvc are used for development. Source files can be provided and then only these are compiled. For example hash.c should only be compiled once while developing. So specifying lpsolve.c as first argument will only compile this file and then link everything. This makes the build process a bit faster. Also the option -DDEMO can be added to add the demo command to test some functionality of lpsolve. This is also only for debugging. Also the option -DDEBUG can be added. This to print some debug information while executing omlpsolve. Should only be used for debugging purposes.

Note that the omlpsolve.dll file can be locked by O-Matrix. Then the build process will fail because the dll can not be overwritten. This can be solved by giving the clear command in O-Matrix. This will free the dll.

Unix/Linux

At this moment, there is no O-Matrix version for this platform.

See also Using lpsolve from MATLAB, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./O-Matrix1.jpg000666 000000 000000 00000045276 10251314500 011615 0ustar00000000 000000 JFIFExifII*1&i.Picasa0220 !|43576e1548d7f8dc0000000000000000R980100 (HHJFIFC  !"$"$C" B !17AuT"BQVa2RUqѱ$%34dt4 3q4QRSr!1A"Ba ??bQR3/lG1&ZִtqXVQk:!pbA'x;[wW/bjvQRF<,;%s_W ƈq>U?ZCf4'sva.v${ 9Ƕ<ȕsI k#pd#1[B넻]/Sqj;.y=]'c%jU{<ަ+o{R瞝vs_K]ܞLz9U^3y]S;.yj5ns{{5c{m`W{ݪ|Ӱ+>}E>5ns{{5:,atYua) 1燭%&L 9q."1FXZp9fJq6 ª1`H~anX8;yW˛\WY"*nNM(8j#~_y|OÄXdl7/cG9{Œ,+533##csؤ!ZG\q"}†u:-ZJ:fNA{ӑY1#b=2*oʶ[F8nW1wZG7`}!JTV1al/>v՘lROӣ[0L_K?8׾p*bQ/% 4*cMĎc8j)i+tu @""" ""Fl:p UH͇[l]M ƫuef6k=ٮ Ru)׾ ؄Z'(%bhO@0@GdwqQ RCCt }F5K6N{00݈7;8B k=xRVY5%`rCUxVrD@DDD@UH͇X a¢-~ 8nL.?@_D̖,oDuc.n8E ٍ>› 6N-!}oNn' U9;| ۶=H:>^j-ɵӔ!d lfb7<EGkVÎ!*:wns̜nDdnioAY CtOӜL˚ڍ9 ݈3ߡL, ۋ-'i,&&٤ ޳=WG " """ *fí _uQ|?kPjX^cfl)IԢG7`}!JN9ڸVjq=ETvl89Ph.Ӊ"4Ӏ\}v BQ׋6~iKIf9!2܎xPUx =tvʥhsnkj4F]Qߨ嫥6Pmvr}Ƿ"ӽr @gQDDD@UH͇[X a-t~ 1Bqbkٍ~Z"FyЀ0ÃC-!%=?k0~f6oB?x}mI #ϳsQE* [;=T""]KT٩gD=O'ъZl؍G%W"ЭVr z6(qs{\5Zsf.z<_=z/_,bNЦɊ 6!:[ۀ'- o^&jr[lCõagRay{ g*x/p?`~4>i|"@xT[O0cׁٙPk,:@7p">i|EIר3gӐHC9+&ѲWI_ufn 3Yacx8 :+EVBolfEۈAsP4XɪV]&#! ~NZDŕƷiJ#ZrJ4*/Fl:p en(N5[S/t{1|6k딮z^KI2Kgf%˳Q4{\\=/%4Jc2:MsHkTze`Ő aGGسٮ4k\\=/>fY0R+liH^>ӎjANd9|<5-.%# wࣽ]_h'lW NFz^KI2Kgit450J=AvuPy>kg%Ӥ0–eҍT(U*PB̏'nMM$fA8W=AvuPy>kg%䦕+RS53@aL}"A7 wH͇[~g(   "#3+#%0&%,<-$46798*5C>76389.  7 %7.-7.+/7+.---77+/+++/7+--.-+-++/-+--+-.---/-++-+--U !16A"QRTUat27f#BS3r5cqse$4CVd94QR!23S1Aq"Bb#Ca ?C[4\rUU?D֍puk*V|u-Mʿ8§u|qǁN㳏 שg;S< *w^xTO;80zvqaS>8§u|qǁN㳏 ;QO?vpaSgNOx;QO?vqjG?$ǁSgNOx;QO?vqjG?$ǁSgYT)Sz%2k[uTM0[ʘ֌vRpj25jtiSJuY_<_K!M4\jˣw$93+ʶevG:ae\{/lwH0nIUOU n:B,ޗE.&´iJ׾Ve5k\=v ljSRr9ʑf*+UȉƉknEJU2􅶽;x]7r0eH;W͗hX֣UQUުMMƞ۶˜w6m>V=Aq3Xl}6>k@5 cccMccXAl} 6>kH5 ccXAl} 6>kk?6 6 6 6 6 6 6 6 6 6 m0_SUo_7L[?޿nOb*9(eMղ.h$[}kg,(YjU;\b>21\쨼hE,XRTҽM;Z68s]۰GigT2*lMjD%jvmeMZFƸzV[)(e[>W*ϴDDD{?3f֝)LiO?NEqZ]Ԅ0zTFY'kŸsuKV$%~cՕ+GO \b5SmN$W9} Z {|f3^ԭ1x+kFDOۓy+[./ i=>Y?K-#OnO}jerpc~SIgS,#OnO3>Zn=n>R/_\{r|gW\N ti=>Xjeupc~SIgS,#OnO3>Zd{r|%HۓϖY.':G4ܟ,g|2q81?)c?婖KM''-L\N ti=>Xjepc~SIgS,#OnO3>Zex{r|gS+#OnO3>Z\{r|HۓϖW.':G4ܟ,g|2q81?)c?婕ˉM''-L\N ti=>Xjerpc~SIgS+#OnO3>Z\{r|HۓϖW.':G4ܟ,g|2q81?)c?婕ˉM''-L\_{r|I<ۓϖex'Qr|+I<ۓϖY^':IT~ܟ,g|281O*c?婖WyU'-LN tʨ>XjepcUGgS,$?nO3>Zex'Qr|+K)keVʛEEG"eOBoX{8WՓiW?ۢrKY{n>J>'$_f@e_stJ;Fi ¸SGCuW ^'<n/Wd Xf\jNl,k|-T/ӴJ޿mŋt%Ueu&uþ3fw:aXU?}[CEF,E[s>d=ߧѶ͙7HU=ijexױbUn]x&Em)L,%X^1'|8b:74/xGo뛗}S!2~lKS|>dkxˡx;x\ܹv~)dzĞ#;F] TðHuL'R&$:2^p?.'ߺCd:0Xq.OH<+ipWUWImwcdlLWh? 7H0\Vu 髞̭VHm3*5Wu7@+q?G0.~S'Ե7ɇÌ|t/ zGo11jhp)]X{oG5z[r/#HᤋñG6cQ'yv7o)kZҞF3^,%5ɳnW3=nl|X4sY5N#QG#_UeT@TðHuL'R&2=teм)e y)gdfdf;{P &M5%t{$kDZ,hW+z"drD8|`Q#^EDgcZ7+Xjrd Lr,+Dpw9̆ +"^̀IW s~a]:O͓jo:2^?)+;A\sQK梥ȩ; u\Sf];vks~_u!TðHuL'R&$:2^G_ ~\OL; t_yu-Ma#;F] žDu_.b4k Բ5uj19TtP=}Ze2 5lYY-.*nMh'TðHuL'R&2=teм)]v_F4|a6ܨs"sm"P-V:V.K י|-[-neED k}S!2^lKS||8їBvmvV|`UP618 0OnEdz9o,jL4ҶvOmXUnjl{s** H ~\OL; t_u-MbOXq.OH :hƐZ/3&={xNv$T*]2tJ=IaUz/ę#\v~)dZĞ#;F] žAa[uU@s:G[Xܙ\؋d+hw*'lTވэ!tf)Mc*.抗EEPڀp7.gߺCd:1'|8їBv }+'ja]MlJMR6D_ݤseGfjJqN [jZ$7KtW"{쑣eNn`khuUW=d{xˡxS;x6~+z0* [8Gidrmb^-Wz'r%Z Ĩ:aw/6NLI2=teм)]v_Tzl):aX5wܫN5bjY7R ٘棚+\KƊ\v~)dZĞ#;F] žAa[uU@/T͗E'L+{s.u;wƬUޭO&A4U06zy[3s\EktsU8S\5ˉ>aw/6NLI2=teм) [ *2F䍹~TV7k"xT6Y oM5DsZJ}5DhI{5j*eD|n`hbؽ;j E Bߣ%TW;l޶ dY&I)(^YsU["Y70SX]9[}nvU^w_cߍl\X\v~)dZĞ#;F] ž]2ֹyr#\jG""jej/\%a؜5d.r=UֹFo^DTݻ[c]v_TcG; _Ⱦ'w{߰k}S!2^lKS|>d{xˡxS;x6~+z0*SnMjl3G"%~Xp?.'ߺCd:1'|8їBvmvV|`UPv=OkO4{I?cxx` ~\OL; t_yu-MbOXq.OH :۵g1;;沙K;Or7]DE[/ ~\OL; t_yu-MbOXq.OH :j{Z}ɣMQm͆w/_Ľ\v~)dZĞ#;F] žAa[uU@ iK&i5G6ܿ#|l;+q?G0.~S'Ե7ɉ=cGw=#k·,,=grKE K}`W s~a]:O͓jozÌ|t/ zGoo݅oAUzsf&-INd5"u׾ꖵ{K; ~\OL; t_u-MbOXq.OH :M-4힞WB5U"N%E@,V0X]چo{ZMFJTðHuL'R&$:2^xWK<4}%7ҟUUj^ꨊE9ljjjs؈{]${*&f*#=%kkX#JyǤz,l#&͹^ΨS8F5_+ɱvY9br#(|KM;gнG5UG5ȷG5SQy +mfťp&=5r6GoVuѡҀ\v~)dZĞ#;F] žmtlrU3&eE;-%tT)9419&WdTo3fFz֢#Q"ZVidDz"Fȳj\[{92cZaZsa+&ȉ{'2Wiil湪q*/:euMش±ƷrF5{؜HMn4:P\5ˉ>aw/6NLI2=teм)]v_TM-4힞WB5U"N%E@,51ßGYU [QZ3vխEE%\d+q?G0.~S%Ե7ɉ=cGw=#k·^VxPicvfhܨQw**X4Zmdz66+T~6*6y5 ~\OL; t_yu-MbOXq.OH :/ īp|Fd{xˡxS;x6~+z0*bU>#!T:Xݙo/**nT]ʊz a8_ͪ^epM@TðHuL'R&$:2^ ߻ ރ ±**M,n׷7*.ET]Z[i62e6oQXW#UU*Up?.'ߺCd:1'|8їBvmvV|`UP i%1L"m۹QwDjEK*"Z,7M0t]d['2Z[;ʊ0 ~\OL; t_yu-Ma#;F] žAa[uU@mcHq-alʋgljjlvV1\{%yW?}^{SnO`W?}^{SnO`W?}^{SnO`W?é|GkYnɱdnDt(*xhXʎurtd]ހ2M)7lݰv>M)7lݰv>M)7lݰs*h=F59kQ.rۑ@A`lZ٘棚ӢT9oENt=Ga.âx_3$-Y󙷺'|?y< 1-GaT >)б],-*EtȻe^{SnO`W?}^yڥĴ?Iblw*}Bs]*)`I,ctNEi;)/Y+u_޶[ Wh?Kpt4إ8&i&CStNd06W+Xj+V}~z)a,2I#˴ci$W2]˶/J{*L;+eD2wӺ'+U\YQ^4cTlsQsUjTENt V .UVﲦH`\5ˉ>aw?6NLI2=teм)nŻ˴fmO3fgqs?DCi$MMsg׽m@5Z9UԕbFKW&]vqm e,mg6[+}"Mϛ&.[n˖۬TT>MFI#3F=MKT߼ Vr nh9 eoC#jߥ_>]Ӟ\߼[ͷ6Y˶ߡowLcoU?$lmop.6QYļjj%z021jr*'X`d,׎g1Q[+TE[55v+gdbX"THEUDcU.io'in-[p?.'ߺCd:1'|8їBvf] W##cd~e̹u%a )C sّ5eLȎEe]20VXdG"ﲮHf aAAٶQ<ֽeD~<3v# ,QIkwWS0VXdG"ﲮH`DnvOPG5ͧ"FT^t/_/u+_.6I\ȶg~BvelLlmWY2Q7 TðHuL'R&$:2^p?.'ߺCd:1'|8їB'v+s?G0.~S'ɶeSh_B^g|Z["MZkxty0žẛ4ZzT_7Svgܖ>S3{d=ͪ| fݘi{}TN167Svc%mS8n7KOSڧpOo}ٌٵOẟ-=Ooj)u?f2Zzf>S3{d=ͪ| fݘi{}TN167vc%mS8n7KOSڧpOo}ٌٵOẟ-=Ooj)u?f2Zzf>S3{d=ͪ| fݘi{}TN167Svc%mS8n7KOSڧpOo}ٌٵOẟ-=Ooj)u?f2Zzf>S3{d=ͪ| fݘi{}TN167Svc%mS8n7KOSڧpOo}ٌٵOẟ-=Ooj)u?f2Zzf>S3{d=ͪ| fݘi{}TN167Svc%mS8n7KOSڧpOo}ٌٵOẟ-=Ooj)u?f2Zzf>S3{d=ͪ| fݘi{}TN167Svc%mS8n7KOSڧpOo}ٌٵOẟ-=Ooj)u?f2Zzf>S3{d=ͪ| fݘi{}TN16򹞜\up3sfx?2,lceJ,4e*ʴ./O-Matrix2.jpg000666 000000 000000 00000050733 10251317640 011620 0ustar00000000 000000 JFIFRExifII*1&i.Picasa0220 !|693cb2b819b2f5190000000000000000R980100 (0HHJFIFC  !"$"$C" H  !7u"1AaQTVq2U #$B%3CRbdrt4 3q4QRSr!1A"Ba ?<73f^؎cLih7nU#[Ec1ftC {AԶ._-3 BByiss+<-K=E_@"g‹ ~:#W/)U6kJB{70 Y%ιapzzDØNx,K^Hq&m ^6{9ExLt_4G}ߙMb~7^ơrLSU}*g¶LjzbTaR*N Tb WRZFp>cչj*TS=.g+f^\|ꔼ8U}չuplWXehPZ/1< n54i_NV7籭s?NWTlWDOP&ŶNEzOeb G]bY:* $yŻ)_NV7j+z\S=.g+dN]e:^naRmL;+,51-_kMm(["j-%բl냫Rkչ{fꞕ3uOKڌ;s[dәGx 38lGhWn`Ѫ~=_NV7籨9|OÄXdl7^ƏuУ9!K LĈ\Ƕ):'Hj:;$pSϕ5OP\'EʌIV5GL>46y`piVyj~ H؏vLѫn] {1{Era~[ OfԨiу`[fX3nb7L{\O!-EPK24H *8N9LM2 (>\=mSpΐ0iُE21,jt_;|iw 6 |=)0n%U5F;ث" ,3auE,͇c Q\.U.G7`|JORep)=Jsuq9!0߳PR0߳PYʄD@DD+s/?PB-!0҆ZqkuWZV0tKEly Ƅu H @YKQy98 .;{\DD@DDc/dE?neu&(N5[R픛1{%꘦,G@ўt 0zHpy?;-~f8ovB?x}mI7]z)VpmkozB" ""4]NVO|fG·9WXtI*0[@pv_ft*]JkWY3Ѓ8Hn." ,/au, \. ƫu]f8ovB= PzڸVpkozVpmkozB" "" pu)=(ЭhQ{iox\SḬ̺v&K#Yg=ýդ^jTR-RɉI,+9B,3auE,͇c Q\.U.J/ov\F..shq:.۩&YG7`|JOR{\N@mrK8Mo;==E8v7=EVrD@DD?3PO#bdKĄ -'Hv5m uL%S<Z#ƙp-+]4 ] SỽJ#67T_ ~0Q~]LPjX(cl)IQlَݰ>@Ɋ 6!:]'AKDn' U9M;Z{W s,A]wg*Ql{c@Ql{c@Ql{c@Ql{c@Ql{c@Qln1bdC"I9œyAuV=^b:k P"4j]B?- ~ Hv)/:P:Q[UFl?ne#67T_GpVp"CF<9X wsaD" X-g-!=&e Ë 9 Hyʿ_(>(+MH,wCwy(1XH9fI#'3t# .?u5'/D9ʿ_(>('UAA4 SQė&<ۧ$" q,n?Ixv~!>UAA9ʿ_(>(&5u3_jO^W0ēl&K@EҌCs@4Hu~Mϕ~P|PNy Mrr>$p9~P*2 }VsDG+?Ixv~!>UAA9ʿ_(>(&5u3_jO^ְ Q26-_XUAA4 [Qė zx8o !cKktXjpv0Q~>UAAB52곔XKTiٚtHp`Bm`jl5XnO'+L"http://ns.adobe.com/xap/1.0/ ##%.-%(3(!$?/379<<7$-B:C4I*;<.  8'!'6..2.:/:77../8/58../780.6/.5..//.5.///.2../5//....X  !"16AQRTUt27afBS#3q5u4CcesVbdr94QR!23S1A"qb#BCa ?C[4\˽WTugL*cYW|u-Mʿ|Vʿ?jd}%e*G\Z3vq ;Q< *wڣxTG;80j,vqaSX§}<ǁNTyc g;Q< *wޣxTG;80z,vqaSX§}<ǁNyc ;80z,vqaS>X§}|ǁNc g;S< *wާxTO;80z,vqaS>X§}|ǁNc g;S< *wާ=¯~'xTG?!ǁS gN~'x;QvqjG?!ǁS gN~'x;QvqjG?!ǁVf.!T)ޛkSuwQ?3쩍hge) 6+c[;Of&4g_?>g.j?՟]*^lybUrSnLK֪zY97slJUhvXųzfobZүjn5+n+(!?͛0)<21Xcn7"oeR,YاǵpefH[QKvutRՠHʮX#{or/1,-:-e aF~+ceWd[-ʈκJ4g\.$/-V-;5‰"J5GS^Ƹ`iͨcrF,yۿ+z: Gލg*Ru{WUA=#hR퉱"٨su_ UK,)Hw5QaҳXPՕT2bR׽rjx~DWY/t8Vb,k>U ֵs2FJFʬ~:mҽ]t|CGL9:V$+ΗnѭroUgxXWVϩh֑ &iZxhrDΖ79+QQfDTȊD%Hįw82htftc- {fTUuWwni:U,kmNg=Jq 081elnu:eke{\ԵuOM]LekўGc\EaX`aX`=,0 ,0 ,0 ,0 aX`aX`ahs)_o_3N3oFu[JE)FyIyvMJR, %z/a"8+R_T:>gcrUGn4V2[Xjepc~sIgWd[!mF[>i~S/_\{r|?,#OnO3>Z]x{r|Y^':G4ܟ,g|yW''-LN ti=>Xjepc~sIgS,#OnO3>Zex{r|+HۓϖY^':G4ܟ,g|281?9c?ܲN ti=>XW]x{r|ÖW^':G4ܟ,g婕׉''9jeupc~sIZ]x{r|ÖW^':G4ܟ,g婕׉''9jeupc~sIZ]x{r|ÖW^':G4ܟ,g婕׉''9jeupc~sIZ]x{r|ÖW^':G4ܟ,g婕׋#OnO3rI<ۓ{Wy'9jepcuGZex'Qr|ÖY^':IT~ܟ,g婖Wy'9jepcuGZex'Qr|ÖY^':IT~ܟ,g婖Wy'9je֔˵ʛ"򣚱SSckYB]qY?m*56_g??Ut.{hu͚׏=N]+]Df4a\(iJJ?U0m/$_ɳqAmT[ _\EvO+yZbū*UY]Insu؝a:aXU ?=Fd=KfjD{Gq*=ijexڷbUocH(gg*7͉=gsѷxSKt"8![OMXM#*nty-T'eL#]dvcQx̡MVŅQRH35($F5Iej۹±)jgOXY]+n,ltU]544Y}B9Z=ʗHeKK.?QIN֤pA3^W+2ȖsrUE|+tTGi.!hX"ʮlkL1do*5Z[T uLGw,UrZ~eMBpWa{a9#ms_Evhוʩ}/\~IҶ&E\$oUrdF[qQ]Rhf"&ԍ~Hj9IEc[o#thzEbQbCqtq+fJH"$٣[ʼnD.d $;BڍkTfix#*\.T[-]q'}=53mDdն eTrh3Qgusn*5AzAUG+Pƭ̯$YU?2~\@3HY옲R5_QjCk.W9m{nG&[[K^&5,jrkgh^75\ >) 8۲sXtVc̷zȈ\Ѝ;oݍ_r[.lg7 :GGհ.~SԵ7͉=gIw<$@G.1؄pqmkdoj1cdhԻYŏ1Z[ܡYSL{rDtL"֫UFeTTյ@0Pf4ye˴z6[kZKuUsC[KU+uz&=ldNs"S?zYwK^!UrSH67F1\G$#-`n|M \_UIʗ{Uv_{\ԓMJݮ͍j*lEUor*[20jjLE4F#[MsZu^6o[]pİ*if.EEUF=5QUQmtS3^ S3vrM*dYW#V*]Zw%#Q=+pUi1)i"Ek+e׽8~K [Y.tt ˻z=kƽ9Q^ڵW3kU6G2<ȚllM>ʶdKE4b3KGUU9i$t2DDsUkULvʹU@7 U[KOM"R'mrFK,{%F)h𵠎uD'`G+c[u}|sّUp'Y1z˕]UE[68؊dUKnebGc5pȐF66Y[ezeMʈ\eߺCt:'87ѓB𧄖+Ql:t_u-MbOYq&OI-W s⣣uw~)dZĞ%_;FM ž[xWV(lϑu]ʶMR 7H0\Vuz72)Y+W s⣣uw~)dZĞ%_;FM ž[LZZ*z)]3664kUQ.T"4Z^H:$sѱXZs^蓋v|F86RbÅ, Jy[v4$5ɳnYU8bcb'I#%&j:kar#w@GGհ~SԵ7͉=gJw=$^C%.Hg$fdf;|`h0U؅'tSRC6dkƬV4HثLވ7-+E_] GeWDr".UVﲢ`e\]ߺït:'8WѓB𧤖mvVt`UPzA4Ӷx%s#檵r-TT]MpMmi۱ If֓sʷN7p+g.w{FZ*^m"!QW6{W'Yk.UT\ ~|Tt}[!:^lKS|ؓ~dxɡxSKt6~+z0*ki.9Y0ZxQ%I21Hm]QD=5FCXʫtJyldk\ʈ{UywX'fV)ߕUnQlkU7j'.KK)[UES_F:elS\5ϊa:O͓jozÌ|4/ zInoمoAFUec> Ħs5˳rV-۝MQSzz#hQ- r]Qu3%*@61)[4kn3UD\NVKR\]ߺCt:'8WѓB𧤖mvVt`UPKJ.HdKq"rr9j]`M|(6M-:"9ʈǍʉu**'"#Pσcn;B]lsF1oeTEk-/ W ss棣uw~)dZĞ%_;FM ž[h1u3ĮFڑ ]~v5msUv8jA -t k:+\쫛#εqۘ#*UU{w5Ts\՚5G5S7Vzڬ>TU2E#oc{n[9U?0:־MI (OfnkZe`KJ8>#O]U;m򭮉{njk5VëHuN'R6$*:2h^kt\WG*|BuѨZD]P#WSW*1Z9aHYcF= &TՉ\\ȯzŕZŚy;C# Q,or%vhw[g"EVN⤢۫U̒&Uu C[U6Hm7,omg"7*Y}{blH4)?JU\ʬD岢"&^ME435stNL|^TEz&doȪ\5ϊa:K͓jozÌ|4/ zInoمoAFU +5Uknj"n1'%.;vDnPr>Ȋm꫽v<K τ׵˙;37%1yQ虒"\5ϊa:K͓jozÌ|4/ zInoمoAFU/DϤ8 ckcG9Ues{*njMu܋{Um薰vmrJZ)k*J\5ϊa:O͓jozÌ|4/ zInoمoAFUt}6wwEʒ^,Ur}dvX렚olk699gU<"NkVëHuN'R6$*:2h^ ߳ ރ  =%D Yb;,m;sluVّ[&{s\G5T9@ ~|Tt}[!:~lKS|ؓ~dxɡxSKt6~+z0* OeFX$YGL9zYwfj.^N*kVëXuN'R6$*:2h^ ߳ ރ ;Ū,bR)QިnVʋRTUOFx*$2K5"1ʜffNUjݫW s⣣uw~)dZĞ%_;FM ž[Aa[uсU@a9];XܒBTjm5Y|DK]yXW s⣣uw~)dZĞ%_;FM ž[Aa[uсU@iilJ=G5Uk[ȨzovC=EXfFHTTD]N^U \5ϊa:K͓jozÌ|4/ zInoمoAFUCԖEPӵ H*5{n˕w]U{\]ߺït:'8WѓB𧤖¾dI&H<ʗ\'6Y oM4εmjZkF5DUި0,wv)NVC @Kf;6 dLICC#dng*,j O,JtIYr@ί{ڍL=z+וZOW s⣣uw~)dZĞ%_;FM ž[]2eȍr"9|Q.Nt*>6U]k$nq^gn-1߳ ރ }\i<)׶V79ήj6rg[&o '*]-ESgVj9j]NTTW s⣣uw~)dZĞ%_;FM ž[Aa[uсU@?ݣuy)\>Tu\֦EDD⪨uGGհ~SԵ7͉=gJw=$@k· cu9ËjIS2fj**~E±*,c,R73\EO*.EފX+Ql:u_yu-MbOYq&OI- 0:j'2|uKUkv<9UʨK$MTG?eGr@\5ϊa:K͓jozÌ|4/ zInoمoAFU=+'룭,#t[*Yw ZChSF:&ˢG2"g˽, .TU \uw~)dZĞ%_;FM ž[Aa[uсU@;Qzd HS[U+ZW.mkRUF.%UQ,\]ߺCt:'8WѓB𧤖mvVt`UP ]m0vhMW#V'l#n*.rxld5\5ϊa:O͓jozÌ|4/ zInoمoAFUjK()rGPۮUbGe[s%( +^55QsU.j**okVëHuN'R6$*:2h^ ߳ ރ L` ݵ+ZnFޭTʫdܬU@@\]ߺCt:'8WѓB𧤖ºYsi܍ndUmw9y"l["ê䦩{Jv";+I"9ȉvTG#]=%kk X7si6Ikfܲ53=n&pk^,WS05`#7"9W} s:G[Xr#ڋ%'n]ʉ[-7oJã07S QwGGհ~SԵ7͉=gJw=$X8q'ofeʍY+QəQr:{*{].jpJl~fE5 #X\{JUbkw XZZcj+7w_zHhlnFd-ݝʶu" vp?>*:>Ww/6NlI?2Utdм)%]f]Tz id$rF:bʖ]莑iV+DXfۓz*eMʀn@ ~|Tt}[!:^lKS|ؓ~dxɡxSKt6~+z0*:>-l9fr6}\]T "W s⣣uw~)dZĞ%_;FM ž[Aa[uсU@Kj#jGPۦdznGeK#3%\5ϊa:K͓jozÌ|4/ zInoمoAFU  5\Jy[ȮrLիᲮUu\uw~)dZĞ%_;FM ž[Aa[uсU@FF{YUMf1FݗOon\5ω>Ww/6NlI?2Utdм)%]f]TH4Ie=(bX+[~']ߺCt:'8WѓB𧤖mvVt`UP֘:F;E+dor5U.$wnU{kVëHuN'R6$*:2h^MT!%΁zCtgEr+sdb9ֶ;sc\EScN湪kFr*bU>#!:)cvfEMʋQU {T̙\*:>Ww?6NlI?2Utdм)%6ʇxbG*:>Ww?6NlI?2Utdм)%cXT8~9bWԹdVHec̷DK"~M=)7lݰv>M=)7lݰv>MUZ<զQǞV#3F6rr&2>M;`Y7v#U*/_O`G?}{SnO`G?}{Sn JaTu̡Ӹ#rFlXnd 4}-k֫SZ֢]\Y"&M=)7lݰv>M=)7lݰ;~Ή!j9{qSv@:o WeGK bjQW*+ME_ v>M=)7lݰv}ilik6ZMQwwR} {5DWddDDޒw"op 3`DIᛋE".hdlMkD_1<I1*f67D7D\u؈u(rvaʫ3czfb*v.UTUT91<>,Etжg3bW%swS 2p?>*:>Ww?6NlI?2Utdм)%n{gjkeNgUo}0'_Z.m{ MD͞^**^掻v*m6} kr\ 40.o4[]=g5e\cb=[[ȐW&,S,i^_flh;67|TPSa+Vq5,[4DUTTlrse;6_x37uⴔ\6HYIp:(H\z]5k^֣WgvuKm7,mo; 0&_5[+}]Mg-eX 7=}6pMTk.r"EWeK1m'u0p4WN%UEG]WʾG*m_r+Ql:u_yu-MbOYq&OI-1+0>xWѺF5ETڋĞ 2Z?ⳤM;ѹQ\EUʊ]U_ *\>To#cn[5ɽU0<3 X0`b2&6&3*5},}Ѻ<=D9rUnU˸{{=eʛ=%ۭ`4T}+ih6+#jFnj%z`{:RG+g?2s=uK }Xfb40vdllG"*fDr.*X46G\\2~l26G[g]nu0>\E0f7+eV5ekwZ]02p?>*:>Ww?6NlI?2Utdм)% ~|Tt}[!:~lKS|ؓ~dxɡxSKt\]ߺCt6m–:}m|gƛGHפ0on7L6.W ݙKOWڧpOo}ٌٵOᾟ-=_oj)}?f2Zzf>SC{%mS8o7KOWڧpOo}ٞ}ͪ| ݘi}TN 167vc%mS8o7KOWڧpOo}ٌٵOᾟSC{d}ͪ| ݘi}TN 167vc%mS8n7KOWڧpOo}ٌٵOᾟ-=_oj)}?f2Zzf>SC{d}ͪ| ݘi}TN 167vg4}Z~ͦ| ݙOVi)}?f2x}LN 1էgpOo}ٌ>?_f>SC{di67vc'Oٴϔᾟ<}Z~ͦ| ݘm38o7OVi)}?f2x}LN 1էgpOo}ٌ>?_f>SC{di67vc'Oٴϔᾟ<}Z~ͦ| ݘm38o7OVi)}?f2x}LN 1էgpOo}ٌ>?_f>SC{di67vc'Oٴϔᾟ<}Z~ͦ| ݘm3s=9\u!ɟ/6{ej7ܩcF[1bYVA02aSgR^U=./O-Matrix3.jpg000666 000000 000000 00000114407 10251315114 011612 0ustar00000000 000000 JFIF ExifII*1&i.Picasa0220 !|66f80d9bff66f96a0000000000000000R980100 (HHJFIFC  !"$"$C" T !1A"Qau#267SVqBRb3rt$4CUce %&5Ts5 3Rq!12ASQar"Bb ?p܋T_C\%i(E6xx8x$&)J s R$u RI&v&t?q sFs]$OG~QuRQz/$Md:Cnb^;Ș*p*!*A,CVy"Hz>%5'3.(VMad 4ᖕT R}L51<`GX Cs5Os#<_Zc5+lTJ^ vf`M8Z:HHۖvfaMl0ӜA6^K(@}-y|ͯ|X֟}?^F:޹]Sfi7'`25=4$ eYF^6=3FSes*6+$kȣ y|jͯ|a֞}=^F:h$*<-NN+fƮ⫍ GmQٖpa 0Je(ج ;xk&sEի^(=^F3Z{½tގp#rJuPDSӥ:e7`U ]BhARo NjBhꌹs+dnFWk&sCVmxr!T{Mi 1z2/0T z]ID+M- x 6VesYѶK`*E\'Y~kq~p<ς Z⏟c5+hUEw )e[O:sWY;rnwF>lV՘LnYYEiڒ y|jկ|v9^0p>#Z$H(1̥BF[gReJn ԅE:- hݕQ&Fcgۇ4p}jϾ>/?>]:_;=9 8%/?;i|8ئSKJiB7#8cd8ni6[CHVh9e:zŕGŨ>b+:S.hT%isI*UFaA+JIv91󆄪ӊi[>\*p#};wBT5p/q+v<3RdFYFbjպo| {3WltȷEZGb5Օ6N0P I"l6Be*Ir!.jsA9uxjS#Ml],&m1o~~; eF (m)B,` Si.1QR.L~s9/ Rc8QDvR g%_yL~d 9 oTr2pha|ި)qRҲk yG$o=/?\71@[D75SmwT*3ǜk9D^2B$[NPDV6*sTq;c/?\ ֍'hlDjSP6ۖ_tFBvRjZuҤ^FNtYb~f=3=1/1VY0&Ѳ0h\ M eR`ьWlRG#4֊$ZbDNXff//YvoG}`5P-e%@oM\Ly%.1{=jV:8Kkr* *;S[d`:ްBH6 PaGX#uW<5 lDDTčZ^ ,HۣeY8GaٗZ\S%/iczT.3.`\MJ8Fj %jO"n9A!Ysp*I;䎲+3UHRoZؔ AI$En, U6=D`qR7z|USlTޟtTǠcdkZY'q4.IFNh]/Lbbb9Dc%k^evTuwvUdyJH +%3Uxt,~0G I]V,JI^} F RRn >K/!)J;"G'7SBBcF4/TE{a5HN`Ʊk% A_z'5iǚӎ%2mXRMa@o.(q!IP\q#ÕI7T$7O%}S MjYi^[H־ {5 /TKi>P{]U*OEEGL1OELz-*:fQz*c1_5bܲaL M eR`U$Dn`GDF/1m:ԃZ:RA_m\xA{c{-wV_bX} j9JAa#j*STKQʵU71/nZ{_ ut>G3^t=˪W3}- Pkz>҃u>GR$O|V}RiVL)BXk-q=G\xA{c:J#_MO`zCNMbBʬ.qH # L@뗣(>|lg\xA{a+|DGZ~Y7f$}ÔVR` )(:ex߮^t=r}ϑTc HfY0 ,vf7 #L@뗣>|lg\A{a+|A6pb{_RI6Z 5:cMf߼,% ԱCm'\xA{azJ#_MO a*JUb27@]3]1^z?҃cK:@3ĒxM!JZ c]Wp{sՇ"http://ns.adobe.com/xap/1.0/        " "$-$  ( Y !1A"5Q#2RTaqtu4BSU$3rC%VbcDs@ !14q2AQR"Sarс#3BCT$b ?дBfv@K6b;N8aZ1&xL=ؗK~^'<o1_N-ݻmddro1[96Q~O]Ў7?kkBŹ7MhSrg{sF=&zi7?iOaɞMhSrg{sF=&zi7?iOaɞMhSrg{sF=&zi7?iOaɞMhSrg{sF=&zk7?iOaɞhSrg{sF=&zk7?iOaɞhSrg{sF=&zk7?iOaɞhSrg{sF=&zk7?iOaɞhSrg{sFêhS؞L_nߦޚ4鬾ݿL4i93Y}~zhrgv3ѧMegOaɞFÓ=5۷=&zk/o?M{L_nߦޚ4鬾ݿL4i96 6}DMA\ đA!ET.Cree95o5^ѳgյd\sbeiӜ1f ?OV#? hrRi#_}ݳDzYpccY(.-l!"A4$;xS"9`x.uW#LU'Ta.~M%.beR34ʧY'6x"62 Bn$qHpdK+FH1oĢ40)_ЧQV Nq JK*I9՟(«GFo)Mt9=1w> WI8dWbʣs`< ǽY3bUk#5ݥۛ2@)F8dcSo# m ׫vyQ90vJ y wwֶ~NGÙ!Hi:1W )4fLIyۏ.с4442|>Uq3&"ڧfsL cCJ{ZG(of$Y$7 x8{ 2nO:igVԜfR'k'} ؼ.ncdLs r2Eam1ZY;13 WU.-{du/x:l]x"F͔Ǒca>&z4գx|W4UZ&~(7}1;%N5kq74cg1"'jW^[m6d"HE:!";Z,iy)I/EU`#;G|VIif*b#Jb;~vW7MTu"Jek[+K"I6n\Qa0-S\D_":Yu1)n 24rHKrႱ%yXljJh "ţTOSYw,,\,\,\,\,\,\,])s.b%SDh1M)\4Ks.b%SDh1M)b)b)\,\4Kss.b.b.޺mtsPgJ/aGү8tE_V;ֲaE1j21WsɻMmLhjkSzɍqS7dzQ?eUU8}{KР&c1\qvf\Ӎ4]smshh|rLQo9UPIxkKGK_"k}rd]V| /4c]9rMS .&;B+9Zq[/wҽ&UNhөjigsrVm7 /<)<^=1MQ1T;X;hJ*F DeެC1 nOr8QFIw /VKdIUPNߛ\JlٳS6W]cx1]7HApbG(ipb&t rp 98CNN'Pӓ(i4 rp 98CNN'PӐ(iI'''''CHJi0=(i#뉜#S3G]9<n' }IhG\ÞB*?SYf*6)r1ַ3}reaNzT×M@t"q gGqFs=^w/&ǫ 0n8>k+GPrz*}jsF_qQ{ }O;kQGh)K⧼}WsCTQT~}qS>Ry+}#D_y_ʏϢ=OxKm*?>x)<>G=/ӝ⧼}WsCTz1IR:n=;K9sCT~Ry+}9_ʏϡ*{ _?ϧ;kQ=OxKm*?>x)<>G=/ӝ⧼}WsCTGWT~}qS>Ry_ϧ;Q=OxK>G=/sCTGWT~}qS>Ry_ϧ;Q=OxK>G=/sCTGWT~}qS>Ry_ϧ;Q=OxK>G=/sCTGWT~}qS>Ry_ϧ;Q=OxK>G=囮@4B@i^GXPMDzguP;I`3NwW{___ϧ;QOx=>G/ӝ㣼}eUsCtw ʿNwW{=E.WMVh\H[d<:)T~}q]u*?>x=>G/ӝ㣼}eUsCtw,z`ko(Q=2Xqztq0bc>љ≽5Y?s3}Sg}}Q**t XA* gJ2zo_DNnuiI"՘a-aۂVdV?8c4kf͗?37kW?5?F_wYTJK҉扽Im+#*npk&{ª*'&>՛j-5uszDn8ⶫ`J3N>'-8vZA:@/ _7z?&DU&c]njs[x<1oٷr;s>чF,ůk^h'_3ׄ['G6巊JsI5*^ZKՖQEkQO f^duurd Gg%6ZeI4H,䝷q!W) |]383^@j3[G{$ڽm*A=$I.fF[R0Bц?%jZ=ZC-Orѭ4PyˈNaw%Om|M zuTM6{Cu6[ V)۸jOO4PxeG3[AX*ERc*n`q3 )&Y Zn3OэcGVYx&g oRBKFoۻBn,m`$]\$֗j#F.Bc%tU[{ƚch.DŽ[-xjq*3Yn Ωkm`H+2IcqxZ5r,wc.I ڧHCF]>HKn<"6ȍ>ˮ+  蹆`S]6W֌֢ѡF覫-̒C2GsE읙U âڳ_[G;Ic#Dݣ$,pءd. T$ :mő[;%89ݭB!kjE0YwDtRWP{Xีfi.'KG dNc*A}͎ 0oGw}iyad=췫`QV0Ht;r#֬ut9/䳽5-Ů3R/O?96+=9I1Ҩ5h,q_\G{2u om[$’#K#= z؟G ZnM!8m^ᢶ)g}oxnbUky^BiѐPƁt#Rl4+]7OkH'7o 32ޙfnfkpA.oiuwm-ZrmﴉnZim]!kEO nd:yCi..l.1M;HfV(%;ePLjZD BOus3[$tԴtȍ {2ՒF|0d VjsؤPmȑRd n1dHb uڨE6pKu,lidqaL;5X:;vl|"][|x ,:dŕ=t&$D xC[}J;{/#Y^o7X+̱.|XS[XobdY KKaGsIp,AYXw ZJ5 LmGw%Z&{cj-"]vx05>;,.^{4wIăEhu藉Fc!i q@P( @4D*kQ\vcƧWau'_3׎['mo5o _轕-L-M c,.0v\w kXͨZ͖e9AnS&L!w.Xv,IbHE:1ifHTS$%Y6CD,i;[M{tgV^Ԡ&1(#;C!hF./nc HQYeC,f{h[cHeP31VH<@B7&'׀qwq8n'wpgP:I-ImmX5hAN4O‚dC"^~(Kx#'3Mp?]I#L$I0!D*Wjmc$i$Ŗn؆{Nݴ !rafZ[גS3oqc*d- X#RQP+! HK`sf$̒h-j|7pop[Y+ĎU)"ReX: N+ie7̛&XX KTc:Pl0! eԮ/ KItzhR *) sg Pnm KWئ5K#ÈٓX4.XȷrƑ\.u;ݪ3k&z|Pͻ-m@P( @P( @P( @P( @P( @P( @"\o5J&Ea}SҫEyCs6巊~OXpi6Պ7sᕉCA'}u1eXЪH;[c`=Lœ10yc COZ%Bjz(w??dP>,!~_d}XCP־@'}:,F3'EtvXFQIM5DmUyc COZ%BOjz(w??dP>,!~_d}XCP־@'}yc COZ%y`+UEvtRΊYES&7gn{(w??dP>,!~_d}XCP־@'}yc COZ%잵J œg֯*dƯ3ځ)'d()'}yc COZ%잵J5=kjz(w??dP>,!~_dþ2Fd̈]T ] 3_yb"Wyc COZ%J5=kjz(w??dP>,!~_d}XCP־A\=8v !_ $e*|D͵fyZ =eЀU+ELL^ j잵Jw??dP~Ֆ$F`4 JltPXU@"\o5J&Ea}SҫEyCs6巚Ou ,g u(Uf᳢!׏"WFka Bh#V:724\$KfxTd(gu rodhmwf!GqY38_#)/ z'?µz ں .lKԹQxA ʻ#fr ֦zzfbv}k,-6݌VR#T$ P(!IEDEu 0Ȃ0h`kWX Ii1wbAIfoc!>1m k]KBm;z)@P(nLAr$Pbf Uev) e%eGI Vr A BE@P(#!mDFp!g>!&@P(u !Y w[HUe2FHRP E<05EoGD{ȶL%lݝ&_;X7[G\k,YP(* ;x ȐNmNIs %ɭ3L5Pje +aAP( %}oVZ勞d[N5=*?$Z7I~z18ǔ73nKy[y״a0̃u @P( Nj雋XD $W1U 8VPϚu.Q? S%'I!Rб;IYH)blC`2HAF&TM6P(Mu`!Ab&-(-,x۸Gb嘕8 FbI$1'ihMc'6W"Cl(6@4D*kQLvcƧWa'_3׏['mo5o =6w2XڄfXZhj$|*w!8 6 KR7l/F1!P`[Ywگg`v!@$77_\ܳZk&5 *,:h2H29 f,ŗh sUc<ʲC++ 0 "&LU=iTpg6 y2*Y"WT-))Dje( qn"vQz$\mY8E!2s`dWPтe`U#wU@P(pC `9k&z|Pͻ-m@WRҬ洞K;-RM[m! 2(>+џDHvi7?4hy4nAsAz)4;\i37zx<7P}Wbhz Xj3MA ݿ,fG7vsڨ-][ʂXYeGP"!*A Jblh{y^][GMw di_h6pV3E @jVK^m) FXvuGmm]l'\>ƄےT$d>2RAįMW@ZD"&W0Um mND/2 @<;A"cc8h#NG;m6"&6$]P( Ť)#EiwւHtm%UV9p4ʣFUUSyGzypl5J@Ժʉ8HQZTKXwU1UDU13V5LL6ڻ!@P .ʷ}%}"ݰqU}I"L\΀$qZbip٪ Am$CslIƗ1BT2HT2zf'JA$M69e ee e`ARpEDŗ/  WRуVPUAwPc$hdHţ 9$b^Od^&cC>3)>C%@P( 1g̠vg`2v$*r{F9A<{1AU@PZIUDDEu 0A&[N.K7*sx$J}%okK[ٚiH;z?]P(YEDPmT hp[U֣+ǓOJ.O gN1 ۻk( 5tk\vakkڵ4ShSUP( 2[iRX]2'G**AR; T6FnF:6|1uMWR,+,뒸yHM諱bjXH|Z{7ےyM#d58`l97UG3+Rm<2ᒪ}ru%@( .RÏtRM@occΫ,B$A#ňhשޮjr@P(-][RA3̂ 9 0AAh_Ͻıfam 'ƊAE*JP(5^ڨ >GW2- '\]ԟ-~^?=ocw-P(j _^qX8Mn3hY4Q u%@PHckP2;x^E%ø8#jMU:3eRJUy,w [y) 6V`p{  ?E6n=fuT76m )X+(U^d!ӽX麌7VG1,nllq,G& )"HH2ȮՆ< bm{6Xc%[I݋˒(m;1@P(FrDBDXǸ^7`2Y$m۴+I)+*8HXJH ( A/YŸ<&BO$>a ؽ A46׍-`g#|Mw&FvYUe:vj~pg=0x ,#`n) ծ*A$_(tO@P([j?n_ly8>k&z|Pͻ-m]SP&w»rB3!GvUTPYT@z4d#mۍƪR qd'`N({ Mr&j׉tn'w$V|#Ć@Ȏ Li'C_"kk*N*գ78Y1)*Q + J@jUFٰs=n J-VGu*H#g Ŕ.dHdhg7)$N2A=utp׋ 8I'8.(:4}}7i׋$CMm'[O2eE2&1!+#d+8`ԆS&.rG n$d{iBqErʣ *# ՗dpMSS-Ue( r ā%:Od [YEL$gtR*hF7 K!tdxdI 9sP}sOXHT-9h"JNC7vdLt=R!0[GwVe a޶_jS Mۦ~!E&$$ʱVq 0W;Y:B@P(1Pe55*(1 2eY)#P( 2 ox8 32~R|r#$/P(  mgMc!JQNCcvYծTM5megIQ^7DZ6F + 9A"116_|?CjP(DKƵI_Dȷl/ FA,tb$ƒ߁ٴ1*WLjNuj1[Jcxy$Qj4gŌ\p(v@!98A⢨€8j$*@P[=Cp؂~An#d=88> h h0rBL=t$jOI;e7 |VwJOHtǏ:'V® >GW2- '\]ԟ-~^?=ocw-P(j _^qU@[{ՖhRfT( HH ;ELMd.j?;0Og!i/?Z@P(-.W9Ah Dz ɞC+n^hbu-*4aU$E6"A 5]SLK:C6ESn[U.'fI66vD@P(U0[VxŘbܰ $2@C%@P( 71^R 27)>fh#6psCrR=  E:qd Y{迃#vkMNFE* }n*#*r#gbq]P([j?n_ly8>k&z|Pͻ-m@Wȶ(Z A?jjѫB1X-6 A\2  ꘛkM5LMvя0q99^jDNZE @8* l% ݁@3v9bo5 n1u!FFA1:nWPU `Fp"*aDavWT]etF/m6dWܻ[- %] ALѫWP(* Ȃ;1tA2nH0 ,$2T @sq\r3j皞;0|`{G18##(=P( W"Cl(6@4D*kQLvcƧWa'_3׏['mo5o =EB״U@P(=ʶ?捋u@P(/[M 3rʵ5Yzj׷tg;pGqo ҪlUMŊ@Pd>Vó2{ﹲ|v)fSqou#m0j|%+#7.nn[}s"I 4*<2FVVH 9h.(d(ĨlnaFUN #+,bPOFLN r=h _|?U@"\o5J&Ea}SҫEyCs6巊ྌ]?L-sm|88;r3dg"'8բ H'RJL 2ݐF !@P(=13xcVi/Qn$P( 8~q68C?ؚ3mSz*آ5#uDőU6ZP( EG}/{;mbpc&靧woJ5MmYE]N$lʇ!r@}g+nv#|meVnW^mG;s6`g2@P( 8+pa T̃0A*@Pje +aAP( %}oVZ勞d[N5=*?$Z7I~z18ǔ73nKy[xP(>-F{yV@#P `1>(.9Vŵun1GXcAɔ#SP( g{jU:QV A" |Ǽy MJJ(|R;ywTM6ETj@P(+FBIV K0^72Y{坳[͓zk "wncF7 YdpD.)5]B+)e 0A H EB@PE92B¶Cm؀rṲQ$,%XFpA$A  @B#=;,U/HP[ @P .ʷ}%}"ݰqU}I"LGW2- '\]ԟ-~^?=ocw-P(j _^qU6-dnղ ȧh8`ʻ5"4fCW @v"`a|wTWMlJP( h%3 G3UH`| yrLQeX؞P( KaH$^Yy˘ j]76R'I]psIk~u_u:9cg~ krM[MN*A!0jP( l"RYbE%%'%˛/ d Anx^Ă;T wr |Pyqp{h5^ڨ >GW2- '\]ԟ-~^?=ocw-PEԭXc9n\I24ּP^.$`M f֬- TsY!'{.#h>!-FqHC#u )!`;4ns)v01I2@c9_!+CV @[ڲ\tebU6@T%Re=Y=ĜEfE+@P(lveXq!lq8391*M&ɦLdulUc%RU1[rhF!%3x:@ZTRlT"D`'O%@P( W0J63< 凌raݟx095ڨ >GW2- '\]ԟ-~^?=ocw-tioADzuG|I$jN==v/VԮ/Hޏk'Wff;,x- :5O:O3zM>\: Wѫ[_-~{AT [H8iR8<1Q1xzų1䖵c#by@o O"V)#V @<5gbЫD#bd ArJp=*bm7T#C’C/o /JJ7I@P(/6gpoŒ1{F$Tݒw @P(,DI ]sXS9h!({8r|S魆AUC>I]E{{Hd"R\f;T긒N@o9Wȶ(Z Yljr.Q D I#$(cFr.vUѰ"@P(.~\hb:( dAa jbm)m+19||~>-1 UO\#( ~n.MȺ ᐬ\U<: L1x$UxIh2:ʐÑx\JALчR 0`v+FH*}Aln]U^)0P`qh|]T2 @:ā839ME?cYqR8Ry6Pmt hp[U֣+ǓOJ.O gN1 ۻk( z5|kѯh8@P(%Xd7c8e8;]rp=kU7]Za !DRpFYO":}N20LG @Meg捋ub( 1H!}?;GZh١Vr6{A1=MT.UPP( *u&PD ,Q%cpQq`Ziu1O7tUP( 2IFR'BRA#A )ߔ~W 7g;dU޶Iq @z/:'VƒjP(DKƵI_Dȷl/k&z|Pͻ-m@':M=zak*^?s5D7V<(nqiQ*˔ Af#m ȴE J“ K!*QԐR9A  AUi׼vڲbSSP( Plշ}O;Gx7ZY)&4jY" 0$Zm*UL6 =8[oZ%WF1)idWa2lP&&LUJ{#g'U ` :$` tf/iz1@P(B,Ќ̜@@7qo'ܬԞW*[Cw!9AO5`AHAh W"Cl(6@4D*kQLvcƧWa'_3׏['mo5o =EB״eeql3T woq`UjU7v0w1v;dd{JMWԍVXP( ґS2"maBLm* AR?߫^׼vU(QXP( H ^7v6!IjX(:$3{EVbsSP@h֟qՔky H܇ ɔAR`A"ZՎa ոi,nWtbEh扣rRH匍y4aMSej*J^y Žf5|[\) 7 sVGy0jYJ@[lfns y,+`d v 2$HXSr#U/HP[ @P .ʷ}%}"ݰqU}I"Lk&z|Pͻ-m@Wȶ(Z a85P`yqS#F~UvG A"92VT`JLݐF 1q^ +sZnH[k]ClrA1L͵*@P(2k6U(#biKʀP(m(A#A5jfuFnxDzL圏`NyO#݁1 :b@Pws50w+\j I#'ҳlH6bm1}wi$S$ˑ#"1JJ$'#1rkU3^哷$UxIh2:ʐÑUY"nD պJ$< Ú oNZE Q M1mhTҹ ށ@P .ʷ}%}"ݰqU}I"L8ɜnpyucYMj/XeGF)歌2954XR  ]lO"q⍋u@P(/\qXd7gթ\B73=h>55iWMR=QBAuKI4 NK_Ƅqo'2C㌞ѭ'Pn-ߋkW=Mtr<-*Z摩[bմx6a6纛 F訁F%9D|&KAkǿ6e廎+(3!`cw^<?[=EB״UA &h20vA"<##5Dғ<*daF8s#<ݜՉV&bm(Uu@Z\#c=ɂ|*`90DpU1iVq;AH 9Ahj( &boVj**- A*P|IG~>/LK%Vf 1c1e*bm+u(A'a}"um.^x'σpl:R)"HH2ȮՆ< DLD6=,SʭŞ6' yI%>˒( f@z/:'VƒjP(DKƵI_Dȷl/-FD"ˎ\A'6k3b|(f@P(%\ 69 YA ÖsU:Ԫ[O2;DZa=|T7U+  d_UG|T2`nprs)@PWc\*vJ%.?ߪFMP( dT0G|~([,q~:̐I <2F$ԆVVՁ9(?Fz="ӡŸRA"r2%ެsx7Z gO_:4r[I&'C aG\٩%QѵBY83#I{bt8< V]IH^kOd(5^ڨ >GW2- '\]ԟ-~^?=ocw-P(j _^qUqSL]jjf2 y0w|٨&4X1  2;UܞPfN{*yQmp\[I!V`;AzJ7QD d!:QG0AN>54QĠlX$$)VzS6gڸP( jdz5DƍH,1XiJ^UB@Pz(%dm?po<GW2- '\]ԟ-~^?=ocw-P(j _^qUi3Q+SU\_`ǜcǞ=KWM1ֳRP( 6H dzZMZxRC v<{hJA\R! C)>j=1A7RCf8\֬rDlO3IC*֙1`P( ڳaگ%IS%@P( rݎ16H%a1?_Χ{L^҄ZA޾.uW]j8QyƑ]6IDų_P(1SwEl2 `0GV8ܢ5L1WLtDlVR VVRVV T)1e*\/HP[ U@"\o3J&Ea}SҫEyCs6巊_"kk*P(.Dv{GQ0[ndzŷ;;;ԉMth덒RP( LT5r09Ls'ہ1ȁtfHUvG A"u: SN9RAÀTUBfxlх`Tee Xr8 |WCv*)B@P\N|DEq֍ub*@P\M`VqjJiJ 6݌>|dsw0-U=pT\uo}Kt9xQ+$:qM 'iq9wdI!fEGHA D鮝$_4Hϵy1ǞM*m]ʱuSNUe( %}oVZ勞d[N5=*?$Z7I~z18ǔ73nKy[xPi0)hh6xFx+WrEga-F@6u>n oY)&4jY2UŦҥT3it#}V{yI4f,ǺI@Y|(06iNa^ǷodfsF8} gWilb<2H7okwy;ێ_gίxeĐn߷~0w~ vb/:'VƒjP(DKƵI_Dȷl/AT$gU?H&*t{ݚVfIK:j1A w64/{Y- r: ]N!zz1kM=+$\[39bmKI#*(,ʪ PZ= Bڑ %I.-m5tpA+"0`Hd=Jfէ٨N{Pjеe۸xUj-&"f~N{Pj)=Jfէ٨N{PjRG٨~ijS?Z5woBwIMJgIdUM2'RQc@c ɑ Z l赒 ./ D3\9 b6V"7cilBe9c=>&9Dk@2\7 DDFJfէ٪CԩvjZ}T5֭>@*t{ݚVfz:=COP=Jfէ٨=n{P*hb&#Y.jy&/5wI/l8AffcmP$@ 螇ވ^QԝÊ;U2I- ~ uı qƣ#),vq%+&KXII=rb967T5֭>@*t{ݚVfz:=COP=Jfէ٨+г9k@(*ӰS3}fлB$: <2G{lBC++ lsT!Y:pGp Q t9v_孡9##g,dyzA<447O*x^tg[Hڞ8R4S[޵<irtTiRK]:(&åo$, HkAQe-IXϺdF6GWl Mx2 @4D*kQLvcƧWa'_3׏['mo5o uKLtW^n-qW\Mh'qiFR= pZP( @X,ҭﴘm緾#P$G5FI `*{aA}mUHiF7V_ۤ9}$2]EfwukA.[yu9'8"\Ѻn @P(>A;dlގ[íƭk8dgφ1Q4#Eh 1WR-38K{in%$Jj`&wH{xw˧=IcڙSekv:u܎CjP( <+yd!Ab8wlJyMᾳu;IPGW2- '\]ԟ-~^?=ocw-P( @P( @P( @P( @P( @P( @P(DKƵI_Dȷl/T~[_ͬ^T~[_ͬ^T~[_ͬ^T~[_͜^T~[_ͬ^T~[_ͬ^T~[_ͬ^T~[_ͬ^T~[_ͬ^T~[_ͬ^1zor_Nm`׈{&skWC{&skWC{&skWC{&skWC{&skWC{&skWC{&skWGź]5̷.$@ #`$,{uŒ)çe1f<;./octave.htm000666 000000 000000 00000334221 13772705352 011400 0ustar00000000 000000 Using lpsolve from Octave

Using lpsolve from Octave

Octave?

GNU Octave is a high-level language, primarily intended for numerical computations. It provides a convenient command line interface for solving linear and non-linear problems numerically, and for performing other numerical experiments. It may also be used as a batch-oriented language.

GNU Octave is also freely redistributable software.

We will not discuss the specifics of Octave here but instead refer the reader to the Octave website and GNU Octave Repository.

Octave and lpsolve

lpsolve is callable from Octave via a dynamic linked function. As such, it looks like lpsolve is fully integrated with Octave. Matrices can directly be transferred between Octave and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for Octave (especially for matrix support). So you have full control to the complete lpsolve functionality via the octlpsolve Octave driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level script files that can make things a lot easier. See further in this article.

Note that your version of Octave must support dynamic linking. To find out if it does, type the command:

octave_config_info ("ENABLE_DYNAMIC_LINKING")

at the Octave prompt. Support for dynamic linking is included if this expression returns the string "true".

If this is not the case, then Octave is not able to call dynamic linked routines and as such also not lpsolve. In that case you must recompile Octave with dynamic linked routines enabled. Under Linux, the following commands must be executed for this:

configure --enable-shared
make

See Installing Octave for more information.

Under Windows, dynamic linking should already be active. If not, then Octave must be recompiled. The following document can help in this process: README.Windows

The octave dynamic linked routine is in a file with extension .oct. It is impossible to provide a precompiled octlpsolve.oct file with the lpsolve distribution because the structure of the .oct files change often on new releases of Octave and are not compatible with each other. Therefore you must build the driver yourself. Look at the end of this document how to do this.

Installation

A driver program is needed: octlpsolve (octlpsolve.oct). This driver must be put in a directory known to Octave (in one of the directories from the Octave 'path' command) and Octave can call the octlpsolve solver.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux) (in archives lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). This has the advantage that the octlpsolve driver doesn't have to be recompiled when an update of lpsolve is provided.

So note the difference between the Octave lpsolve driver that is called octlpsolve and the lpsolve library that implements the API that is called lpsolve55.

There are also some Octave script files (.m) as a quick start.

To test if everything is installed correctly, enter octlpsolve in the Octave command window. If it gives the following, then everything is ok:

octlpsolve  Octave Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: [ret1, ret2, ...] = octlpsolve('functionname', arg1, arg2, ...)

However, if you get the following:

error: 'octlpsolve' undefined near line 2 column 1

Then Octave cannot find octlpsolve.oct

If you get the following:

error: Failed to initialise lpsolve library.

Then Octave can find the octlpsolve driver program, but the driver program cannot find the lpsolve library that contains the lpsolve implementation. This library is called lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux. Under Windows, the dll should be in a directory specified by the PATH environment variables and under Unix/Linux in directory /lib, /usr/lib or a directory defined by LD_LIBRARY_PATH.

Solve an lp model from Octave via octlpsolve

In the following text, octave:> before the Octave commands is the Octave prompt. Only the text after octave:> must be entered. Note that the default prompt also contains an incrementing number starting from one each time Octave starts. For this documentation, the default Octave was changed with the following command: PS1 = "\\s:> "

To call an lpsolve function, the following syntax must be used:

octave:> [ret1, ret2, ...] = octlpsolve('functionname', arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between single or double quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra Octave specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in Octave, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the Octave functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from Octave, nothing must be dimensioned in advance. The octlpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to octlpsolve. Never as argument to the routine. This can be a single value as for get_objective (although Octave stores this in a 1x1 matrix) or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

Note that you can get an overview of the available functionnames and their arguments by entering the following in Octave:

>> help octlpsolve.m

An example

(Note that you can execute this example by entering command per command as shown below or by just entering example1. This will execute example1.m. You can see its contents by entering type example1.m)

octave:> lp=octlpsolve('make_lp', 0, 4);
octave:> octlpsolve('set_verbose', lp, 3);
octave:> octlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
octave:> octlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
octave:> octlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
octave:> octlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
octave:> octlpsolve('set_lowbo', lp, 1, 28.6);
octave:> octlpsolve('set_lowbo', lp, 4, 18);
octave:> octlpsolve('set_upbo', lp, 4, 48.98);
octave:> octlpsolve('set_col_name', lp, 1, 'COLONE');
octave:> octlpsolve('set_col_name', lp, 2, 'COLTWO');
octave:> octlpsolve('set_col_name', lp, 3, 'COLTHREE');
octave:> octlpsolve('set_col_name', lp, 4, 'COLFOUR');
octave:> octlpsolve('set_row_name', lp, 1, 'THISROW');
octave:> octlpsolve('set_row_name', lp, 2, 'THATROW');
octave:> octlpsolve('set_row_name', lp, 3, 'LASTROW');
octave:> octlpsolve('write_lp', lp, 'a.lp');
octave:> octlpsolve('get_mat', lp, 1, 2)
ans = 78.260
octave:> octlpsolve('solve', lp)
ans = 0
octave:> octlpsolve('get_objective', lp)
ans = 31.783
octave:> octlpsolve('get_variables', lp)
ans =

  28.60000
   0.00000
   0.00000
  31.82759

octave:> octlpsolve('get_constraints', lp)
ans =

   92.3000
    6.8640
  391.2928

Note that there are some commands that return an answer. To see the answer, the command was not terminated with a semicolon (;). If the semicolon is put at the end of a command, the answer is not shown. However it is also possible to write the answer in a variable. For example:

octave:> obj=octlpsolve('get_objective', lp)
obj = 31.783

Or without echoing on screen:

octave:> obj=octlpsolve('get_objective', lp);

The last command will only write the result in variable obj without showing anything on screen. get_variables and get_constraints return a vector with the result. This can also be put in a variable:

octave:> x=octlpsolve('get_variables', lp);
octave:> b=octlpsolve('get_constraints', lp);

It is always possible to show the contents of a variable by just giving it as command:

octave:> x
x =

  28.60000
   0.00000
   0.00000
  31.82759

Don't forget to free the handle and its associated memory when you are done:

octave:> octlpsolve('delete_lp', lp);

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
octave:> lp=octlpsolve('make_lp', 0, 4);
octave:> octlpsolve('set_lp_name', lp, 'mymodel');
octave:> octlpsolve('set_verbose', 'mymodel', 3);
octave:> octlpsolve('set_obj_fn', 'mymodel', [1, 3, 6.24, 0.1]);
octave:> octlpsolve('add_constraint', 'mymodel', [0, 78.26, 0, 2.9], 2, 92.3);
octave:> octlpsolve('add_constraint', 'mymodel', [0.24, 0, 11.31, 0], 1, 14.8);
octave:> octlpsolve('add_constraint', 'mymodel', [12.68, 0, 0.08, 0.9], 2, 4);
octave:> octlpsolve('set_lowbo', 'mymodel', 1, 28.6);
octave:> octlpsolve('set_lowbo', 'mymodel', 4, 18);
octave:> octlpsolve('set_upbo', 'mymodel', 4, 48.98);
octave:> octlpsolve('set_col_name', 'mymodel', 1, 'COLONE');
octave:> octlpsolve('set_col_name', 'mymodel', 2, 'COLTWO');
octave:> octlpsolve('set_col_name', 'mymodel', 3, 'COLTHREE');
octave:> octlpsolve('set_col_name', 'mymodel', 4, 'COLFOUR');
octave:> octlpsolve('set_row_name', 'mymodel', 1, 'THISROW');
octave:> octlpsolve('set_row_name', 'mymodel', 2, 'THATROW');
octave:> octlpsolve('set_row_name', 'mymodel', 3, 'LASTROW');
octave:> octlpsolve('write_lp', 'mymodel', 'a.lp');
octave:> octlpsolve('get_mat', 'mymodel', 1, 2)
ans = 78.260
octave:> octlpsolve('solve', 'mymodel')
ans = 0
octave:> octlpsolve('get_objective', 'mymodel')
ans = 31.783
octave:> octlpsolve('get_variables', 'mymodel')
ans =

  28.60000
   0.00000
   0.00000
  31.82759

octave:> octlpsolve('get_constraints', 'mymodel')
ans =

   92.3000
    6.8640
  391.2928

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific Octave routine to get the handle from the model name: get_handle.
For example:

>> octlpsolve('get_handle', 'mymodel')
0

Don't forget to free the handle and its associated memory when you are done:

octave:> octlpsolve('delete_lp', 'mymodel');

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

In Octave, all numerical data is stored in matrices; even a scalar variable. Octave also supports complex numbers (a + b * i with i=sqrt(-1)). octlpsolve can only work with real numbers. For example:
octave:> octlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);

Most of the time, variables are used to provide the data:

octave:> octlpsolve('add_constraint', lp, a1, 1, 14.8);

Where a1 is a matrix variable.

Most of the time, octlpsolve needs vectors (rows or columns). In all situations, it doesn't matter if the vectors are row or column vectors. The driver accepts them both. For example:

octave:> octlpsolve('add_constraint', lp, [0.24; 0; 11.31; 0], 1, 14.8);

Which is a column vector, but it is also accepted.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the Octave interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the Octave matrix.

Sets

All numerical data is stored in matrices. Alphanumerical data, however, is more difficult to store in matrices. Matrices require that each element has the same size (length) and that is difficult and unpractical for alphanumerical data. In a limited number of lpsolve routines, alphanumerical data is required or returned and in some also multiple elements. An example is set_col_name. For this, Octave sets are used. To specify a set of alphanumerical elements, the following notation is used: { 'element1', 'element2', ... }. Note the { and } symbols instead of [ and ] that are used with matrices.

Maximum usage of matrices/sets with octlpsolve

Because Octave is all about matrices, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the octlpsolve Octave driver to also work with matrices. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The octlpsolve Octave driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = octlpsolve('set_int', lp, column, must_be_int). The matrix version of this call is: return = octlpsolve('set_int', lp, [must_be_int]). The API call to return the integer status of a variable is: return = octlpsolve('is_int', lp, column). The matrix version of this call is: [is_int] = octlpsolve('is_int', lp)
Also note the get_mat and set_mat routines. In Octave these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by just entering example2. This will execute example2.m. You can see its contents by entering type example2.m)

octave:> lp=octlpsolve('make_lp', 0, 4);
octave:> octlpsolve('set_verbose', lp, 3);
octave:> octlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
octave:> octlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
octave:> octlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
octave:> octlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
octave:> octlpsolve('set_lowbo', lp, [28.6, 0, 0, 18]);
octave:> octlpsolve('set_upbo', lp, [Inf, Inf, Inf, 48.98]);
octave:> octlpsolve('set_col_name', lp, {'COLONE', 'COLTWO', 'COLTHREE', 'COLFOUR'});
octave:> octlpsolve('set_row_name', lp, {'THISROW', 'THATROW', 'LASTROW'});
octave:> octlpsolve('write_lp', lp, 'a.lp');
octave:> octlpsolve('get_mat', lp)
ans =

   0.00000  78.26000   0.00000   2.90000
   0.24000   0.00000  11.31000   0.00000
  12.68000   0.00000   0.08000   0.90000

octave:> octlpsolve('solve', lp)
ans = 0
octave:> octlpsolve('get_objective', lp)
ans = 31.783
octave:> octlpsolve('get_variables', lp)
ans =

  28.60000
   0.00000
   0.00000
  31.82759

octave:> octlpsolve('get_constraints', lp)
ans =

   92.3000
    6.8640
  391.2928

Note the usage of Inf in set_upbo. This stands for 'infinity'. Meaning an infinite upper bound. It is also possible to use -Inf to express minus infinity. This can for example be used to create a free variable.

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example:

octave:> A=octlpsolve('get_mat', lp);
octave:> X=octlpsolve('get_variables', lp);
octave:> B = A * X
B =

   92.3000
    6.8640
  391.2928

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

octave:> octlpsolve('get_constraints', lp)
ans =

   92.3000
    6.8640
  391.2928

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

octave:> C=octlpsolve('get_obj_fn', lp);
octave:> X=octlpsolve('get_variables', lp);
octave:> obj = C * X
obj = 31.783

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

octave:> octlpsolve('get_objective', lp)
ans = 31.783

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
octave:> lp=octlpsolve('make_lp', 0, 4);
octave:> octlpsolve('set_verbose', lp, 3);
octave:> octlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
octave:> octlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
octave:> octlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One could define all the possible constants in Octave and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

octave:> lp=octlpsolve('make_lp', 0, 4);
octave:> octlpsolve('set_verbose', lp, 'IMPORTANT');
octave:> octlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 'GE', 92.3);
octave:> octlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 'LE', 14.8);
octave:> octlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 'GE', 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

octave:> octlpsolve('set_verbose', lp, 'blabla');
error: BLABLA: Unknown.

octave:> octlpsolve('set_verbose', lp, 'GE');
error: GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. 'LE', 'GE' and 'EQ' in add_constraint and is_constr_type can also be '<', '<=', '>', '>=', '='. When returned however, 'GE', 'LE', 'EQ' will be used.

Also in the matrix version of calls, string constants are possible. For example:

octave:> octlpsolve('set_constr_type', lp, {'LE', 'EQ', 'GE'});

Some constants can be a combination of multiple constants. For example set_scaling:

octave:> octlpsolve('set_scaling', lp, 3+128);

With the string version of constants this can be done as following:

octave:> octlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_INTEGERS');

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

octave:> octlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_RANGE');
error: SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

octave:> octlpsolve('get_scaling', lp)
ans = 131

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

octave:> octlpsolve('return_constants', 1);

From now on, all returned constants are returned as string:

octave:> octlpsolve('get_scaling', lp)
ans = SCALE_MEAN|SCALE_INTEGERS

Also when an array of constants is returned, they are returned as string when return_constants is set:

octave:> octlpsolve('get_constr_type', lp)
ans =
{
  [1,1] = LE
  [1,2] = EQ
  [1,3] = GE
}

This for all routines until return_constants is again called with 0:

octave:> octlpsolve('return_constants', 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

octave:> octlpsolve('return_constants', 1)
ans = 1

To get the value without setting it, don't provide the second argument:

octave:> octlpsolve('return_constants')
ans = 1

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

Script files

Octave can execute a sequence of statements stored in diskfiles. Script files mostly have the file type of ".m" as the last part of their filename (extension). Much of your work with Octave will be in creating and refining script files. Script files are usually created using your local editor.

Script files can be compared with batch files or scripts. You can put Octave commands in them and execute them at any time. The script file is executed like any other command, by entering its name (without the .m extension).

The octlpsolve Octave distribution contains some example script files to demonstrate this.

To see the contents of such a file, enter the command 'type filename'. You can also edit these files with your favourite text editor (or notepad).

example1.m

Contains the commands as shown in the first example of this article.

example2.m

Contains the commands as shown in the second example of this article.

example3.m

Contains the commands of a practical example. See further in this article.

example4.m

Contains the commands of a practical example. See further in this article.

example5.m

Contains the commands of a practical example. See further in this article.

example6.m

lp_solve.m

This script uses the API to create a higher-level function called lp_solve. This function accepts as arguments some matrices and options to create and solve an lp model. See the beginning of the file or type help lp_solve or just lp_solve to see its usage:

 LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

octave:> [obj, x]=lp_solve([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])
obj = 3
x =

  1
  2

lp_maker.m

This script is analog to the lp_solve script and also uses the API to create a higher-level function called lp_maker. This function accepts as arguments some matrices and options to create an lp model. Note that this scripts only creates a model and returns a handle. See the beginning of the file or type help lp_maker or just lp_maker to see its usage:

octave:> help lp_maker

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            x >= vlb >= 0
            x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

octave:> lp=lp_maker([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])
lp = 0

To solve the model and get the solution:

octave:> octlpsolve('solve', lp)
ans = 0

octave:> octlpsolve('get_objective', lp)
ans = 3

octave:> octlpsolve('get_variables', lp)
ans =

  1
  2

Don't forget to free the handle and its associated memory when you are done:

octave:> octlpsolve('delete_lp', lp);

lpdemo.m

Contains several examples to build and solve lp models.

ex.m

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

octave:> X = 0.1:0.1:125;
octave:> Y1 = (15000 - 120.*X)./210;
octave:> bar(X, Y1);

Source

Now let's put in the other two constraint inequalities.

octave:> X = 0.1:0.05:40;
octave:> Y1 = (15000. - 120*X)/210;
octave:> Y2 = max((4000 - 110.*X)./30, 0);
octave:> Y3 = max(75 - X, 0);
octave:> Ytop = min([Y1; Y2; Y3]);
octave:> bar(X, Ytop);

Source

The red 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 the objective function P.

octave:> hold on
octave:> X=15:25:40;
octave:> title('Solution space and objective')
octave:> plot(X,(6315.63-143.0*X)/60.0);
octave:> hold off

Source

The line gives a picture of the objective function. All solutions that intersect with the red area are valid solutions, meaning that this result also fulfils the set constraints. The more the line goes to the right, the higher the objective value is. The optimal solution or best objective is a line that is still in the red 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 lp_solve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:

octave:> x = [1 1; 110 30] \ [75; 4000]
x =

   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:

octave:> P = [143 60] * x
P = 6315.6

That is, $6315.6.

Note that these command are in script example3.m

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            x >= vlb >= 0
            x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

octave:> f = [143 60];
octave:> A = [120 210; 110 30; 1 1];
octave:> b = [15000; 4000; 75];
octave:> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
octave:> solvestat = octlpsolve('solve', lp)
solvestat = 0
octave:> obj = octlpsolve('get_objective', lp)
obj = 6315.6
octave:> x = octlpsolve('get_variables', lp)
x =

  21.875
  53.125

octave:> octlpsolve('delete_lp', lp);

Note that these command are in script example4.m

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimentions, but beyound that it is all very theorethical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

octave:> f = [143 60 195];
octave:> A = [120 210 150.75; 110 30 125; 1 1 1];
octave:> b = [15000; 4000; 75];
octave:> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
octave:> solvestat = octlpsolve('solve', lp)
solvestat = 0
octave:> obj = octlpsolve('get_objective', lp)
obj = 6986.8
octave:> x = octlpsolve('get_variables', lp)
x =

   0.00000
  56.57895
  18.42105

octave:> octlpsolve('delete_lp', lp);

Note that these command are in script example5.m

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that Octave can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like Octave is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
octave:> f = [110*1.3 30*2.0 125*1.56 75*1.8 95*.95 100*2.25 50*1.35];
octave:> A = [120 210 150.75 115 186 140 85;
        110 30 125 75 95 100 50;
        1 1 1 1 1 1 1;
        1 -1 0 0 0 0 0;
        0 0 1 0 -2 0 0;
        0 0 0 -1 0 -1 1];

octave:> b = [55000;40000;400;0;0;0];
octave:> lp = lp_maker(f, A, b, [-1; -1; -1; -1; -1; -1],
                          [10 10 10 10 20 20 20], [100 Inf 50 Inf Inf 250 Inf], [], 1, 0);
octave:> solvestat = octlpsolve('solve', lp)
solvestat = 0
octave:> obj = octlpsolve('get_objective', lp)
obj =  7.5398e+04
octave:> x = octlpsolve('get_variables', lp)
x =

   10.000
   10.000
   40.000
   45.652
   20.000
  250.000
   20.000

octave:> octlpsolve('delete_lp', lp);

Note that these command are in script example6.m

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that Inf is used for variables that have no upper limit. This stands for Infinity.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using Octave:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into Octave format we get:

f = [4 2 1]
A = [2 1 0; 1 0 2; 1 1 1]
b = [1; 2; 1]

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0 0 0]
u = [ 1 1 2]

Now lets enter this in Octave:

octave:> f = [4 2 1];
octave:> A = [2 1 0; 1 0 2; 1 1 1];
octave:> b = [1; 2; 1];
octave:> l = [ 0 0 0];
octave:> u = [ 1 1 2];

Now solve the linear program using Octave: Type the commands

octave:> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
octave:> solvestat = octlpsolve('solve', lp)
solvestat = 0
octave:> obj = octlpsolve('get_objective', lp)
obj = 2.5000
octave:> x = octlpsolve('get_variables', lp)
x =

  0.50000
  0.00000
  0.50000

octave:> octlpsolve('delete_lp', lp)

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the Octave command:

octave:> l = [];

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -Inf as lower bounds:

octave:> l = [-Inf -Inf -Inf];

Solve this and you get a different result:

octave:> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
octave:> solvestat = octlpsolve('solve', lp)
solvestat = 0
octave:> obj = octlpsolve('get_objective', lp)
obj = 2.6667
octave:> x = octlpsolve('get_variables', lp)
x =

   0.66667
  -0.33333
   0.66667

octave:> octlpsolve('delete_lp', lp)

Overview of API routines

Note again that the Octave command 'help octlpsolve.m' gives an overview of all functions that can be called via octlpsolve with their arguments and return values.

Note that everwhere where lp is used as argument that this can be a handle (lp_handle) or the models name.

  • add_column, add_columnex
    • return = octlpsolve('add_column', lp, [column])
    • return = octlpsolve('add_columnex', lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = octlpsolve('add_constraint', lp, [row], constr_type, rh)
    • return = octlpsolve('add_constraintex', lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = octlpsolve('add_SOS', lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in Octave since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = octlpsolve('column_in_lp', lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = octlpsolve('copy_lp', lp)
    • No special considerations.
  • default_basis
    • octlpsolve('default_basis', lp)
    • No special considerations.
  • del_column
    • return = octlpsolve('del_column', lp, column)
    • No special considerations.
  • del_constraint
    • return = octlpsolve('del_constraint', lp, del_row)
    • No special considerations.
  • delete_lp
    • octlpsolve('delete_lp', lp)
    • No special considerations.
  • free_lp
    • octlpsolve('free_lp', lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = octlpsolve('get_anti_degen', lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = octlpsolve('get_basis', lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in Octave. If not provided, then 0 is used.
  • get_basiscrash
    • return = octlpsolve('get_basiscrash', lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = octlpsolve('get_bb_depthlimit', lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = octlpsolve('get_bb_floorfirst', lp)
    • No special considerations.
  • get_bb_rule
    • return = octlpsolve('get_bb_rule', lp)
    • No special considerations.
  • get_bounds_tighter
    • return = octlpsolve('get_bounds_tighter', lp)
    • No special considerations.
  • get_break_at_value
    • return = octlpsolve('get_break_at_value', lp)
    • No special considerations.
  • get_col_name
    • name = octlpsolve('get_col_name', lp, column)
    • [names] = octlpsolve('get_col_name', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_column get_columnex
    • [column, return] = octlpsolve('get_column', lp, col_nr)
    • [column, return] = octlpsolve('get_columnex', lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = octlpsolve('get_constr_type', lp, row)
    • [constr_type] = octlpsolve('get_constr_type', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_constr_value
    • return = octlpsolve('get_constr_value', lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = octlpsolve('get_constraints', lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = octlpsolve('get_dual_solution', lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Octave, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = octlpsolve('get_epsb', lp)
    • No special considerations.
  • get_epsd
    • return = octlpsolve('get_epsd', lp)
    • No special considerations.
  • get_epsel
    • return = octlpsolve('get_epsel', lp)
    • No special considerations.
  • get_epsint
    • return = octlpsolve('get_epsint', lp)
    • No special considerations.
  • get_epsperturb
    • return = octlpsolve('get_epsperturb', lp)
    • No special considerations.
  • get_epspivot
    • return = octlpsolve('get_epspivot', lp)
    • No special considerations.
  • get_improve
    • return = octlpsolve('get_improve', lp)
    • No special considerations.
  • get_infinite
    • return = octlpsolve('get_infinite', lp)
    • No special considerations.
  • get_lowbo
    • return = octlpsolve('get_lowbo', lp, column)
    • [return] = octlpsolve('get_lowbo', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_lp_index
    • return = octlpsolve('get_lp_index', lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = octlpsolve('get_lp_name', lp)
    • No special considerations.
  • get_mat
    • value = octlpsolve('get_mat', lp, row, col)
    • [matrix, return] = octlpsolve('get_mat', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix in the first return value. The return code of the call is the second return value.
  • get_max_level
    • return = octlpsolve('get_max_level', lp)
    • No special considerations.
  • get_maxpivot
    • return = octlpsolve('get_maxpivot', lp)
    • No special considerations.
  • get_mip_gap
    • return = octlpsolve('get_mip_gap', lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = octlpsolve('get_nameindex', lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = octlpsolve('get_Ncolumns', lp)
    • No special considerations.
  • get_negrange
    • return = octlpsolve('get_negrange', lp)
    • No special considerations.
  • get_nonzeros
    • return = octlpsolve('get_nonzeros', lp)
    • No special considerations.
  • get_Norig_columns
    • return = octlpsolve('get_Norig_columns', lp)
    • No special considerations.
  • get_Norig_rows
    • return = octlpsolve('get_Norig_rows', lp)
    • No special considerations.
  • get_Nrows
    • return = octlpsolve('get_Nrows', lp)
    • No special considerations.
  • get_obj_bound
    • return = octlpsolve('get_obj_bound', lp)
    • No special considerations.
  • get_objective
    • return = octlpsolve('get_objective', lp)
    • No special considerations.
  • get_orig_index
    • return = octlpsolve('get_orig_index', lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = octlpsolve('get_origcol_name', lp, column)
    • [names] = octlpsolve('get_origcol_name', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_origrow_name
    • name = octlpsolve('get_origrow_name', lp, row)
    • [names] = octlpsolve('get_origrow_name', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_pivoting
    • return = octlpsolve('get_pivoting', lp)
    • No special considerations.
  • get_presolve
    • return = octlpsolve('get_presolve', lp)
    • No special considerations.
  • get_presolveloops
    • return = octlpsolve('get_presolveloops', lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = octlpsolve('get_primal_solution', lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = octlpsolve('get_print_sol', lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = octlpsolve('get_rh', lp, row)
    • [rh] = octlpsolve('get_rh', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_rh_range
    • return = octlpsolve('get_rh_range', lp, row)
    • [rh_ranges] = octlpsolve('get_rh_range', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_row get_rowex
    • [row, return] = octlpsolve('get_row', lp, row_nr)
    • [row, return] = octlpsolve('get_rowex', lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Octave, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = octlpsolve('get_row_name', lp, row)
    • [names] = octlpsolve('get_row_name', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_scalelimit
    • return = octlpsolve('get_scalelimit', lp)
    • No special considerations.
  • get_scaling
    • return = octlpsolve('get_scaling', lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = octlpsolve('get_sensitivity_obj', lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = octlpsolve('get_sensitivity_objex', lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that Octave allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = octlpsolve('get_sensitivity_obj', lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, Octave always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = octlpsolve('get_sensitivity_rhs', lp)
    • [duals, dualsfrom, dualstill, return] = octlpsolve('get_sensitivity_rhsex', lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that Octave allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = octlpsolve('get_sensitivity_rhs', lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = octlpsolve('get_simplextype', lp)
    • No special considerations.
  • get_solutioncount
    • return = octlpsolve('get_solutioncount', lp)
    • No special considerations.
  • get_solutionlimit
    • return = octlpsolve('get_solutionlimit', lp)
    • No special considerations.
  • get_status
    • return = octlpsolve('get_status', lp)
    • No special considerations.
  • get_statustext
    • return = octlpsolve('get_statustext', lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = octlpsolve('get_timeout', lp)
    • No special considerations.
  • get_total_iter
    • return = octlpsolve('get_total_iter', lp)
    • No special considerations.
  • get_total_nodes
    • return = octlpsolve('get_total_nodes', lp)
    • No special considerations.
  • get_upbo
    • return = octlpsolve('get_upbo', lp, column)
    • [upbo] = octlpsolve('get_upbo', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_var_branch
    • return = octlpsolve('get_var_branch', lp, column)
    • [var_branch] = octlpsolve('get_var_branch', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_var_dualresult
    • return = octlpsolve('get_var_dualresult', lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = octlpsolve('get_var_primalresult', lp, index)
    • No special considerations.
  • get_var_priority
    • return = octlpsolve('get_var_priority', lp, column)
    • [var_priority] = octlpsolve('get_var_priority', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • get_variables
    • [var, return] = octlpsolve('get_variables', lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = octlpsolve('get_verbose', lp)
    • No special considerations.
  • get_working_objective
    • return = octlpsolve('get_working_objective', lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = octlpsolve('guess_basis', lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In Octave, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In Octave, there is no unused element in the matrix.
  • has_BFP
    • return = octlpsolve('has_BFP', lp)
    • No special considerations.
  • has_XLI
    • return = octlpsolve('has_XLI', lp)
    • No special considerations.
  • is_add_rowmode
    • return = octlpsolve('is_add_rowmode', lp)
    • No special considerations.
  • is_anti_degen
    • return = octlpsolve('is_anti_degen', lp, testmask)
    • No special considerations.
  • is_binary
    • return = octlpsolve('is_binary', lp, column)
    • [binary] = octlpsolve('is_binary', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • is_break_at_first
    • return = octlpsolve('is_break_at_first', lp)
    • No special considerations.
  • is_constr_type
    • return = octlpsolve('is_constr_type', lp, row, mask)
    • No special considerations.
  • is_debug
    • return = octlpsolve('is_debug', lp)
    • No special considerations.
  • is_feasible
    • return = octlpsolve('is_feasible', lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = octlpsolve('is_free', lp, column)
    • return = octlpsolve('is_unbounded', lp, column)
    • [free] = octlpsolve('is_free', lp)
    • [free] = octlpsolve('is_unbounded', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • is_infinite
    • return = octlpsolve('is_infinite', lp, value)
    • No special considerations.
  • is_int
    • return = octlpsolve('is_int', lp, column)
    • [int] = octlpsolve('is_int', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • is_integerscaling
    • return = octlpsolve('is_integerscaling', lp)
    • No special considerations.
  • is_maxim
    • return = octlpsolve('is_maxim', lp)
    • No special considerations.
  • is_nativeBFP
    • return = octlpsolve('is_nativeBFP', lp)
    • No special considerations.
  • is_nativeXLI
    • return = octlpsolve('is_nativeXLI', lp)
    • No special considerations.
  • is_negative
    • return = octlpsolve('is_negative', lp, column)
    • [negative] = octlpsolve('is_negative', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • is_piv_mode
    • return = octlpsolve('is_piv_mode', lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = octlpsolve('is_piv_rule', lp, rule)
    • No special considerations.
  • is_presolve
    • return = octlpsolve('is_presolve', lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = octlpsolve('is_scalemode', lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = octlpsolve('is_scaletype', lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = octlpsolve('is_semicont', lp, column)
    • [semicont] = octlpsolve('is_semicont', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • is_SOS_var
    • return = octlpsolve('is_SOS_var', lp, column)
    • [SOS_var] = octlpsolve('is_SOS_var', lp)
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into an Octave matrix.
  • is_trace
    • return = octlpsolve('is_trace', lp)
    • No special considerations.
  • is_use_names
    • return = octlpsolve('is_use_names', lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = octlpsolve('lp_solve_version')
    • The octlpsolve API routine returns the version information in 4 provided argument variables while the Octave version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = octlpsolve('make_lp', rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • octlpsolve('print_constraints', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
    • The same information can also be obtained via octlpsolve('get_constraints', lp). This shows the result on screen.
  • print_debugdump
    • return = octlpsolve('print_debugdump', lp, filename)
    • No special considerations.
  • print_duals
    • octlpsolve('print_duals', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
    • The same information can be obtained via octlpsolve('get_dual_solution', lp). This shows the result on screen.
  • print_lp
    • octlpsolve('print_lp', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
  • print_objective
    • octlpsolve('print_objective', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
    • The same information can be obtained via octlpsolve('get_objective', lp). This shows the result on screen.
  • print_scales
    • octlpsolve('print_scales', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
  • print_solution
    • octlpsolve('print_solution', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
    • The same information can also be obtained via octlpsolve('get_variables', lp). This shows the result on screen.
  • print_str
    • octlpsolve('print_str', lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
  • print_tableau
    • octlpsolve('print_tableau', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Octave (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the octlpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows Octave) to the command window of Octave. As such, all reported output can be seen in Octave. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = octlpsolve('read_basis', lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = octlpsolve('read_freemps', filename {, options})
    • lp_handle = octlpsolve('read_freeMPS', filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In Octave it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = octlpsolve('read_lp', filename {, verbose {, lp_name}})
    • lp_handle = octlpsolve('read_LP', filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In Octave it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ('').
  • read_mps, read_MPS
    • lp_handle = octlpsolve('read_mps', filename {, options})
    • lp_handle = octlpsolve('read_MPS', filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In Octave it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = octlpsolve('read_params', lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = octlpsolve('read_XLI', xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, '' (NULL) is taken. '' is taken as NULL.
    • options is optional. When not provided, '' is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • octlpsolve('set_basisvar', lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = octlpsolve('set_add_rowmode', lp, turnon)
    • No special considerations.
  • set_anti_degen
    • octlpsolve('set_anti_degen', lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = octlpsolve('set_basis', lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In Octave, there is no unused element in the matrix.
  • set_basiscrash
    • octlpsolve('set_basiscrash', lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • octlpsolve('set_bb_depthlimit', lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • octlpsolve('set_bb_floorfirst', lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • octlpsolve('set_bb_rule', lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = octlpsolve('set_BFP', lp, filename)
    • No special considerations.
  • set_binary
    • return = octlpsolve('set_binary', lp, column, must_be_bin)
    • return = octlpsolve('set_binary', lp, [must_be_bin])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = octlpsolve('set_bounds', lp, column, lower, upper)
    • return = octlpsolve('set_bounds', lp, [lower], [upper])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • octlpsolve('set_bounds_tighter', lp, tighten)
    • No special considerations.
  • set_break_at_first
    • octlpsolve('set_break_at_first', lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • octlpsolve('set_break_at_value', lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = octlpsolve('set_col_name', lp, column, name)
    • return = octlpsolve('set_col_name', lp, [names])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_column, set_columnex
    • return = octlpsolve('set_column', lp, col_no, [column])
    • return = octlpsolve('set_columnex', lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = octlpsolve('set_constr_type', lp, row, con_type)
    • return = octlpsolve('set_constr_type', lp, [con_type])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • octlpsolve('set_debug', lp, debug)
    • No special considerations.
  • set_epsb
    • octlpsolve('set_epsb', lp, epsb)
    • No special considerations.
  • set_epsd
    • octlpsolve('set_epsd', lp, epsd)
    • No special considerations.
  • set_epsel
    • octlpsolve('set_epsel', lp, epsel)
    • No special considerations.
  • set_epsint
    • octlpsolve('set_epsint', lp, epsint)
    • No special considerations.
  • set_epslevel
    • octlpsolve('set_epslevel', lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • octlpsolve('set_epsperturb', lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • octlpsolve('set_epspivot', lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = octlpsolve('set_free', lp, column)
    • return = octlpsolve('set_unbounded', lp, column)
    • No special considerations.
  • set_improve
    • octlpsolve('set_improve', lp, improve)
    • No special considerations.
  • set_infinite
    • octlpsolve('set_infinite', lp, infinite)
    • No special considerations.
  • set_int
    • return = octlpsolve('set_int', lp, column, must_be_int)
    • return = octlpsolve('set_int', lp, [must_be_int])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = octlpsolve('set_lowbo', lp, column, value)
    • return = octlpsolve('set_lowbo', lp, [values])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = octlpsolve('set_lp_name', lp, name)
    • In Octave, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = octlpsolve('set_mat', lp, row, column, value)
    • return = octlpsolve('set_mat', lp, [matrix])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. The matrix must be two-dimentional.
  • set_maxim
    • octlpsolve('set_maxim', lp)
    • No special considerations.
  • set_maxpivot
    • octlpsolve('set_maxpivot', max_num_inv)
    • No special considerations.
  • set_minim
    • octlpsolve('set_minim', lp)
    • No special considerations.
  • set_mip_gap
    • octlpsolve('set_mip_gap', lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • octlpsolve('set_negrange', negrange)
    • No special considerations.
  • set_obj
    • return = octlpsolve('set_obj', lp, column, value)
    • return = octlpsolve('set_obj', lp, [values])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • octlpsolve('set_obj_bound', lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = octlpsolve('set_obj_fn', lp, [row])
    • return = octlpsolve('set_obj_fnex', lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In Octave, there is no unused element in the matrix.
  • set_outputfile
    • return = octlpsolve('set_outputfile', lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In Octave under Windows, output to stdout it not shown. However it results in closing the file. Use '' to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • octlpsolve('set_pivoting', lp, pivoting)
    • No special considerations.
  • set_preferdual
    • octlpsolve('set_preferdual', lp, dodual)
    • No special considerations.
  • set_presolve
    • octlpsolve('set_presolve', lp, do_presolve {, maxloops})
    • The maxloops argument is optional in Octave. If not provided, then infinite is used.
  • set_print_sol
    • octlpsolve('set_print_sol', lp, print_sol)
    • No special considerations.
  • set_rh
    • return = octlpsolve('set_rh', lp, row, value)
    • return = octlpsolve('set_rh', lp, [values])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = octlpsolve('set_rh_range', lp, row, deltavalue)
    • return = octlpsolve('set_rh_range', lp, [deltavalues])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • octlpsolve('set_rh_vec', lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In Octave, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = octlpsolve('set_row', lp, row_no, [row])
    • return = octlpsolve('set_rowex', lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In Octave, there is no unused element in the matrix.
  • set_row_name
    • return = octlpsolve('set_row_name', lp, row, name)
    • return = octlpsolve('set_row_name', lp, [names])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_scalelimit
    • octlpsolve('set_scalelimit', lp, scalelimit)
    • No special considerations.
  • set_scaling
    • octlpsolve('set_scaling', lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = octlpsolve('set_semicont', lp, column, must_be_sc)
    • return = octlpsolve('set_semicont', lp, [must_be_sc])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • octlpsolve('set_sense', lp, maximize)
    • No special considerations.
  • set_simplextype
    • octlpsolve('set_simplextype', lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • octlpsolve('set_solutionlimit', lp, simplextype)
    • No special considerations.
  • set_timeout
    • octlpsolve('set_timeout', lp, sectimeout)
    • No special considerations.
  • set_trace
    • octlpsolve('set_trace', lp, trace)
    • No special considerations.
  • set_upbo
    • return = octlpsolve('set_upbo', lp, column, value)
    • return = octlpsolve('set_upbo', lp, [values])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • octlpsolve('set_use_names', lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = octlpsolve('set_var_branch', lp, column, branch_mode)
    • return = octlpsolve('set_var_branch', lp, [branch_mode])
    • In Octave, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = octlpsolve('set_var_weights', lp, [weights])
    • No special considerations.
  • set_verbose
    • octlpsolve('set_verbose', lp, verbose)
    • No special considerations.
  • set_XLI
    • return = octlpsolve('set_XLI', lp, filename)
    • No special considerations.
  • solve
    • result = octlpsolve('solve', lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = octlpsolve('time_elapsed', lp)
    • No special considerations.
  • unscale
    • octlpsolve('unscale', lp)
    • No special considerations.
  • write_basis
    • octlpsolve('write_basis', lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = octlpsolve('write_freemps', lp, filename)
    • return = octlpsolve('write_freeMPS', lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In Octave it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = octlpsolve('write_lp', lp, filename)
    • return = octlpsolve('write_LP', lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In Octave it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = octlpsolve('write_mps', lp, filename)
    • return = octlpsolve('write_MPS', lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In Octave it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = octlpsolve('write_XLI', lp, filename {, options {, results}})
    • No special considerations.

Extra Octave routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = octlpsolve('get_col_names', lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = octlpsolve('get_constr_types', lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = octlpsolve('get_int', lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = octlpsolve('get_no_cols', lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = octlpsolve('get_no_rows', lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = octlpsolve('get_objective_name', lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = octlpsolve('get_obj_fn', lp)
    [row_vec, return] = octlpsolve('get_obj_fun', lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = octlpsolve('get_problem_name', lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = octlpsolve('get_reduced_costs', lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = octlpsolve('get_row_names', lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = octlpsolve('get_solution', lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = octlpsolve('mat_elm', lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = octlpsolve('print_handle')
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = octlpsolve('read_lp_file', filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = octlpsolve('get_handle', lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = octlpsolve('return_constants'[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the octlpsolve driver

Windows

To compile the Octave driver under Windows, the cygwin environment is needed. The following document describes what is needed for this: README.Windows. It may not be needed to build the Octave sources to compile the binary file, but the proposed cygwin and octave packages are needed to build a .oct file.
The build must be done from the cygwin prompt from the directory where the lpsolve octave files are located.
To make the compilation process easier, a script file can be used: ccc.win32
To make for release, just enter ./ccc.win32 and everything is build.

Unix/Linux

The build must be done from a shell prompt from the directory where the lpsolve octave files are located.
To make the compilation process easier, a script file can be used: ccc
To make for release, just enter sh ccc and everything is build.

All platforms

This compiles three source files: lpsolve.cpp, octave.cpp and hash.cpp
Then these are linked together to generate the octlpsolve.oct file.
The optional arguments to ccc are used for development. Source files can be provided and then only these are compiled. For example hash.cpp should only be compiled once while developing. So specifying lpsolve.cpp as first argument will only compile this file and then link everything. This makes the build process a bit faster. Also the option -DDEMO can be added to add the demo command to test some functionality of lpsolve. This is also only for debugging. Also the option -DDEBUG can be added. This to print some debug information while executing octlpsolve. Should only be used for debugging purposes.

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./Octave1.jpg000666 000000 000000 00000071034 10252612604 011374 0ustar00000000 000000 JFIF4ExifII*1&i.Picasa0220 !|3bdf178b4782e3c40000000000000000R980100 (HHJFIFC  !"$"$C" N !1AQ"27VqsRSTa#6Btu$3Cbr4DF=q!1AQ2345STar"Rc#b ?ŧizzvWgSeS9N7c=&2TVY?7qcm^Џ]=Vi:L2Y*[Q$&7(:~:։JF$)EJR@ FNrc=53d6G06hӐ,e(ֻb܃N>Xg*R!  g*SQ#1ɮ3dެ~G>x][,~J}-rG0mo%oթy7L`OR-V7Ӝ|U>5L\]q%HRjE$+AXiĉO]"l**n'N%f+k\.*tO{zbFZ)z*I%jH4WwvlHb*aԟ"#㰪aU>9L:j=鋟E"OW}5-s oEI-'8"Cx& GaTϦ|sޘtO{?eDܮ:.ׇRAjA?خ䁌aԗ"x*j-S^"'+;G>$I :]1Sza>5L\ִ]uފZJd~G>$I :]1RSDjZA2ğøR !;J(sE2tiR[{;[?خ3F~G11Ս5\YeǾe"]ݓ]'(Ԝ07h(! o&5̥/'=mLurTs9q,ƓȗZlPҞHr`G }#NU-=Obiж]C]'x0r)!Թ:9|S28ӭ)ZO lPm4E$!/B B u&i3#5سd w7!Q*nH6A`F{Nd!@cԘq-@i b֙}5U*`GpTE_FZ[5EA)n]G_|"Z\V{$i4 \Ftk-7gu iS% ^هYtYuG LGfBekH6ʲPFAy##?:T<1J^Utv~MR%ԙۨ;=Dp 7*hZt7XFP# B B G*; Eoς*GDJuB5SRHn䓁_U0Z'!5q\Vk(9g4n$- K$ c"8~ l:Hʵ.% gdIa&OCkTonQ riD,e*˂:F#~M ӥBB3y)'Hl%[*r+1U!6PrՑ2FAFA3ުVxSaSF]tKvhS]w R9+".tmc@fE2AܶW ?>DjֆHw(8L̲U}u'KR+JM0KA,΍Uz;,qB<"Is״9Wa*ߣ?"#"$wjmʶlޔmci*K[Jmjie (Ӆ`dRF$vD&˒OCيe𔳒±PGL/w՞0XT]!HBE"ʵ5uz3; '}C lu^PR/yLԢ՗%z~\5,D{oC慎`#|\EҮػu\zS`ӐhV68s\B!Q5Mh7&wl$Je6#CmsԤiH΁n" Bj:B$!"%zf)&MA1>a)ߣ?"#֢$wjmɧj4G4):%-ɩҕ! 3g`"QdHIp[Ո]m3^-+,QiWZvk @5렐 B [KWeTYKͰw)ZyCO1F\jMDLI9$U4~~#Fc]9YbFrRq8sp q WXqXmm);&1zF~a&OCkTonI!V{IGE5Ie帕5.@Kyg$rMAtKztZ4bzY N5I!뮂B$!"B$!"B,3s2> iղ(p 1o,5ݖֲVVܾe;ͤ @䮴#vqOc,ĜSr+ mR(o)ʾѓ8Xg ˴t ȄxMjӺٮ8eܦp:>#ӑK)Z*jtlp#H5)UD)9wzN Eς*GDJu1T; Eς*GDOժ6زyoV#&4iMVGQNT IpA +k:N_etXq;l9LHϘ2A'1ҾJLc6)on~EPr REkTSQJ2O˴R kvx7]I77.WҥaK7%k=&3 $ 6r_W?}:Zz։!4'Jww|ѻ~?!}qѺ^9*j`-ԩږRV6эss=(]wDչi!L.yE*VJSB IPP3&Dm߭jn\n5 ΰ%켕 +@GL]t?_sنC]JϺ`M)e')SƵ:ښTdQ70V3DI.al=eۉ)ZKn`0G{T[j(V@8y@ 7Gw2L6< ԯ<|{ Cˍ-ie'Q%2fZBҪ gYwnx+n{1̞׶vvQsHoag;$:L9/au+>Kn~CPr݇2eh >'V׍V'n\Τqi%w?46r_W?}jd=M*U\}co]52Pm/([hCvÄL%Fc["aa"http://ns.adobe.com/xap/1.0/ "$4$$&'''-1"&6+6/6"+@8?8G49:.  -% &88-88-5/--./-,8------5--/7.----------/---00--8-78-S!1AV"467QTUrsuaqt2B#b$5CR%E3d7 2Q!4AS1R"aq#B3r ?Ʊ7Բ$lZkƍF5mvuW_٪vXbE__;]Uxڝe Sɟ?Z;Z?eM3ZV?e x~n7cPsq8|^+iXo;NypV?e7Ӈ(9v>/Ax~n7cPsq8|^+iXo;NypV?e7Ӈ(9v>/Ax~n7cPsq8|~+iXo;NypV?e7Ӈ(9v>?A~n7cPsq8|~+iXo;NypV?e7Ӈ(9v>?A~n7cPsq8|~+iXo;N~nӇ(9;NG8|~-~nӇ(9;NG8|~-~nӇ(9;NG8|~-~nV::uUF5>*'4ޮݨֹluW'--/G7gE2JZe^dIiWDI.!2o?΍uAOU_ճ D_ܨ oZ*gcE}+W'--/j7>u>W%;dv[5U_TYt] v#Iţ{i=bb*-KFn=Z6¿z5CKHꜯLja؅-+kR ¨Ǫ}'vEk,.pnEW-pbR؅+}k\i"9r]nn/>HW U❇34RXƩHɿTEEeZƪQq*ȈAMSo }_7gH)4WFiO'HEcZu[7'}"QrlK;±* dj-9~[]:V&%MEbaճBG#W#IVַb_TɚR-U1A]6E#- 1˧Z:۞܂tQ"Sc<+ŇʱWMm{ƬTȚWص\ƺ:nKSK#RuHUnjʪ4F}1v+t-yTxp췊419s^5}''췞!jSVıcr2z X\/#Z[%"kM!(Hu} p dzZom+ZzmO+3kM ±[A*5r=Q[j=f&#{FZN*e]4cmV-V]kMQGuF]f+MlэU"H9/˭uۑMVM?[gył0 `ohohohohohohדf| sYv'JjtջJVCeU!+,**KLW?{s⵿%&=7Է c^.'AᴵӪ-W6{5F9ˢEG/'c{+ƹv.Un5:z>E)]I6!VZVU$VL;DVtᾒ>_ֽ)וj(\1m]2GHrl7EN[EW.]ngMt1Tgk [ê&_LG":XU^DZT_޺SY'ݚ~Z騸-KR>.$XftnK#n*œYxRL3^תEZmQU/"<^?UuHե=4*6_#^ޗFҍUנ֢*v&&SLYcڊZʙǶJT>Ydt9HܭMktG2/<+T4fcN6EpL1\JkoPW.=\2E*[EW.]ngETE5k˸D)kfTZhk7{_֍[^nOM=>4d[zO;to/!ډFG.tzo?aFQCo?`49F QCo?`?7yQ7yQ7yQ7yQ7yQ7yQ7yQ7yQ7yQ7>ҟt9FCoJ49FCoJ49FCoJ49FCoJ49FCoJ49FCoJ49I%t˧[n-_ƥ 5WʏXڮDE-G*6*M=?,=25-Z;U?f%H'}jb)\YTGCgJ%{UKDe7Qs?eES-1>КZDչڴȩ._5vMMvU1c()"(u*mv9^ӦN;&V)3 :*:ʏEmߙRڹ?iؗN㜙jJZHhfWj\eT)~g _;7G:>,GsÑ(qs :Gh#t&6W9< ^m}"P=WjJ}'68\J͞G_̇l-Ic<z^elOKM4i{:V*_ sp.*k&iK,b#"jMEu.i:9;9Sɾcs&Kʒ]?ùO&?IJ/fqUaHn*]"%u Ils3gR\&L#[&F"fZ%S|]m{r<(kR8w<3gRo\Fl?C:]wqČԇlu.i:]um3gR8ۻ$f#;cqwIշwH͞GHv\n8<펹'Vq#6y!sNČԇlu.i:]um3gRXۻ$f#;cwIշwH͞GHv]bn8<펺'Vq#6y!uNFl?C:[wqČԇlu.i:]um3gRXۻ$f#;cwIշwH͞GHv]bn8<펺'Vq#6y!uNFl?C:[wqČԇlu.i:]um3gRXۻ$f#;cwIշwH;GXv]bn8|펺'Vq#6auNFm?ö:[wqČՇlu.i:]um3oVXۻ$f#;cwIշwH;GXv]bn8|펺'Vq#6auNFm?ö:[ws)v:' {m&>X쪗ݲ#R9WG,[LU117ZûoL>O7MOw1s|O0#a-Vg:*6Uzf?>tk[s{ͭ"JijVJתOySOcF5Ư*fC$5^t3>2fD)Ǧ&W+Wˆmәm,OewfcvF:g7ENO}9ZۭY3u^e*۔Ur^Zy4}[  gY缥9{si2Q+W6[K*&D]S]SgqEq3>ӓG"ynIjZhRt[+f.nNᛴܷET%X]QC5nVX[U5CX dwY+;U: Z2)tzک5~j(⌮IVi$hQVRK74wG%ҍ\vhZֻqi's jhoq,#m+bx~OWE (^5UQVȮTKWwIh;@8zKG!9^vq*CyW}bsʽ%U-XhIh;@8zKG!9^vq*CyW}bsʽ%U-XhIh;@8zKG!9^vq*CyW}bsʽ%U-XhIh;@8zKG!9^vq*CyW}bsʽ%U-XhIh;@8zKG!9^vq*CyW}bsʽ%U-XhIh;@8zKG!9^vq*CyW}bsʽ%U-XhIh;@8zKG!9^vq*CyW}b;g F[Ԍ~km2'}ESL.;Vvuړ9M?G -,*.ɒ؆$GTGS>7G5ʑ׳wYu'b+AJ뢑HHtMDѹzR\+`?|;O '9#[E dwY+;U: J2zS6aST9yoz!TzV|j'YD]~igv N{Ṙޔ =XamTy`a޲U:ޫմ_ A;z*auݭ|BSpԨ!7nV[U5CXEPlJZ rI}G4nrVȎWc8V/N' 6ޤctm-[^klAME_VY㽾r*܊#YIĹTn;~GQ MsQQQnȨQ:UL:Kt}zV82'}ESL.;Vvuڕd>0m js 6f޳Bچ~w9ct\D@A;z*auݭ|BSpԨ!7nV[U5CXy P3BY{]\ꪪΪr6i}C-KE's~- <݇EŮʗ.Y :ILUWS~Wg5f6O#s7z/ih!Iz9j**-QyUL:Kv^ՀN ~T k{d>ڣՆMPP7dz/ŷἇ踵R@ BΒ`%{_cUooMwE5} $dD޳`:RhktT^EE-bupUS4Β>ޫմ_ A;z*auݭ|BSpԨ!7nV[U5CX@ݓ߆nâ{cKmyާ.'5[ˮg=|?G9NO[}~[tGQ M sQQQnS4Β>AoU/XK ȝO0־x!Yک׸OjTyқG -,n_oy7aqk1XflU&RN>D۝'~.U=%ؕjG1tTZ-*aWmWjadAoU/XK ȝO0x!Yک׸OjTyқG -,n_oy7aqk1S9 M;/2|:OEFe{+Ksë*6Jc}[TUίYsEqäɬAoU/XK ȝO0־x!Yک׸OjOCJo=XamTy`_5Ӿ 鷇Jڇ5kM-=5mo2-?ZWO"籲+9j+4Uk%eUwdz/ŷἇ踵R@S9 M;/2|:OEFe{+Ksë*6Jc}[TUήڮsEqäɬ mƬp%dNފ]fwk_<T'*<}M`ۣՆMPTxN ec~ ʓ% #WSxj>.ȊE{.4I樫i)H⡩c,3CK-:1r][{Y/kvN[~y]я/D<*rg;rq>ET6I(_(̣OeqIn^'ERNP׷ԋeNT]iuF+W"i.&V$;ooJɦ,ՖctXsi]P,,"w߮U?43Zgj^]QCJo0j<'s~- <݇EŮʗS3嚧IHƹcѫ̼ݯZkS}nT+4fL} Rc4 tUj"˩Rt.h*aخh4w4GݽWh5`,"w߮U?43Zgj^]QCJo0j<'s~- <݇EŮʗ.b*nղ=ܩ̼uwY6Vp[ͷUIn3G躕'2j.h+aX1MDv^ՀN ~T k{vG)tzک E7vߣ*^/3 f\8U"ݫd{u=?Syzm> oI>,f[A%u*/+WNeO\\Wrnc\w#I8v^ՀN ~T k{d>ۣՆMPP7dz/ŷἇ踵R@c0eCR-ڶGWS9.7Jyʣ-h=]RyTmEq<+5ɷr4H mƬp%dNފ]fwk_<T''!70j<'s~- <݇EŮʗ+!5]Zʟ޷fVY<k2*Ktه5-K9{*n-\[Mq/7»W&h6"t}zV82'}ESL.;Vvuڕd>0m js 4N:|y8dCӵ^ǢoEVz5óxtZI伭ņHlK*H_[kk@n_oy7aqk1 a":[*9.b9,Wj:̣rT̔yK#U^eqj\a0r+j5޳Ա4A6j˵]NMWEրYYD]~igv N»Ṙޔ =XamTy`Xrn51d|-l-e 71WBG豉eDDM /U/]dGEj$ҕlm^KgvN[~y]я/DqIg'99EmfWfY6vʙ2a"l>5]l_Eesj\a0r+jAoU/XK ȝO0־x!Yک׸OjOCJo=XamTy`vN[~y]я/D6-Y Ors΋͖͹mۚ+3%deuy\ڻ#Xy~;'zlڂ:>[E dwY+;U: I}M?G -,n_oy7aqk1v V`kh$rsenu,yvLEi7kkw-[]ObnFnUkN^v^ՀN ~T k{vG)tzک E7vߣ*^ڔs[_Z-šRS:.UDXh܍[Lԙ{љM6*Zfošʗ~y pe:JoUޫմ_ A;z*auݭ|BSpԨ!7nV[U5CX@ݓ߆nâ{cK=*(*WG*u\輦TW4No"۹ķ %&lN͞3\̫sb\)w0o~@t}zV82'}ESL.;Vvuڕd>0m js5&ΐ:TVۦUʉʨy9pg F[Ԍ~kmNݓ߆nâ{cK{VTPUUkyLha'Er5n'7JM ,ڝ0m js 0WK5$[NQ֖M%fF*p+;moƣ's~- <݇EŮʗEYQAVں9Uk'7E2u|ky%dO)4$'jvlYg^e[o6N sO3ު+xKꝝ8d,miW7~v7EˮM$O d dwY+;U: J2zS6aST9Ii\uIʊEDUknOf a_Dåm-63KFD@n_oy7aqk1dg1檢ڕ5ST:M^h5ݒs>co5dIeVj_=\Xȋ߅x"Zi8ޫմ_ A;z*auݭ|BSpԨ!7nV[U5CX@ݓ߆nâ{cK)$OTr***-9MS5ܵMfX͐31ĜPyTNt99S".Fy p=Xr}rR mƬp%dNފ]fwk_<T+*<}M`ۣՆMPP7dz/ŷἇ踵R@D'9ʊ}[3MQKf٘iNDDԼ*':x)Ήo#I8Jtv>˹)B:>[E dwY+;U: J2zS6aST9 ;mo!:.-wF>TG"IeENEE>S5ܷMfX͐31ĜPyTNt99S".Fy p=Xr}rR:>[E dwY+;U: J2zS6aST9 ;mo!:.-wF>TD'9ʊ}[3MQKc;7j&m׽ED^DDMVT"tcU1Ti-csn9kc,Uߙm{\|p\3uczm>?4rkޫմ_ A;z*auݭ|BSpԨ!7nV[U5CXgL*APY;glLҡ$HEbn+uErUʡ?KTjd*=4=ӫ#G%շ\!7dz/ŷἇ踵R@b&4z:8F5/g#/1y_Ư7=I9+xLA7ڷɥCHHAj1,N9 @A;z*aum|BSpԨ!7nV[U5CX@ݓ߆nâ{cK5DUKV=p#ԑȿkV[E dwY+;U: J2zS6aST9 ;mo!:.-wF>Tb&4z:8F5/g#/1y_Ư7=I9:>[E dwY+;U: J2zS6aST9 ;mo!:.-wF>TV31̋ F"2Uҽg'":{XZO p#["аr/zV|j'YD]~igu N»Ṙޔ =XamTy`vN[~y]я/D1C< e9]_6?sBſ@v^ՀN ~T k{vG)tzک E7vߣ*^ƭs '.H_w| wcdS[#?**] ':>[E dwY+;U: J2zS6aST9+2bZ/tO$,鱬jHIvo}DEUr+FvcvKI<SC{eI}+mmw ;mo!:.-wF>T=3+pf_#U/߳aN;8]o؎kht,[&;p:?B79Yv˩ɪ K ȝO0־x!Yک׸WjTyқG -,*8Dub22)#̧{%{ֶ7CֳItSESVs%AJ뢑HHtMDѹzR\+`_oy7aqk11@90 Uʪ~kV<aps7?A4s“Bs\EETR'WU3L/zV|j'YD]~igv N»Ṙޔ =XamTy`vN[~y]я/DIϕ8D$Wk-z9>vK[7*i5} p 7bn؍*olMD)4G5EEE*/":JgIzXt}zV82'}ESL.;Vvuڕd>0m js(w=Ct\Z~|z .Y :ILUWS~Wg5f6O#s7z/ih!Iz9j**-QyUL:KAoU/XK ȝO0־x!Yک׸WjTyқG -,n_oy7aqk1rYLdr5^vtYTd6]Ы|X+Quxn{]x3DWӕO.DWmuu6%Fں)r]?֯y jjXyUڮh4tZޫմ_ A;z*aum|BSpԨ!7nV[U5CXg OET6I(_(̣OeqInxuu6%Fں)Qr]?֯y zjXyUڮh4t5AoU/XK ȝO0־x!Yک׸OjTyқG -,n_oy7aqk1,y36TwB||̩'"mΓQpQG*lJtS#*_rF󫶫\\i0> mƬp%dNފ]fw[_<T'*<}M`ۣՆMPP7dz/ŷἇ踵R@,y36TwB||̩'"mΓQљO*knqZlg e}Uʖ[**}t-*a8ܛul;:>[E dwY+;U: J2zS6aST9 ;mo!:.-wF>Tc0eCR-ڶGWS9.7Jyʼ%X;KT^V;\ʟ5bƹ6F 4pGݽWh5`,"w߮U?43Zgj^]QCJo0j<'s~- <݇EŮʗX5sTvUNe?ү2m'KwnFJZkbo#-m+WYݓ߆nâ{cKX5sTvUNe?ү2m'Kw2W%shW_ɫ펋kq׹g~̯vE3?GWjdcuw+52]mn:;y.趷{{GM_̗lt[[=}^e&K:-^y>2W%shW_ɫ펋kq׹g~̯vE3?GWjdcuw+52]mn:;y.趷{{GM_̗lt[[=}^e&K:-^y>2W%shW_ɫ펋kq׹g~̯vE3?GWjdcuw+52]mn:;y.趷{{GM_̗lt[[=}^e&K:-^y>2W%shW_ɫ펋kq׹g~̯vE3?GWjdcuw+52]mn:;y.趷{{GM_̗lt[[=}^e&K:-^y>2W%shW_ɫ펋kq׹g~̯vE3?GWjdcuw+52]mn:;y.趷{{GM_̗lt[[=}^e&K:-^y>2W%shW_ɫ펋kq׹g~̯vE3?GWjdcuw6H/;U5QܗЕ/m|efoeLM=xg^<؈qSν]x*a3Y׫L;k:w8xg^<+§|FtM3V,r"ܠI ~T k{vG)tzکK ȝO0־x!Yک׸WjTyқG -,T~3fvGҺ6,#ըTEr5Tm49:zUvN9ʪ*UU]jLpWҭ-\zLuuDr"]m^Ejr]P | }E\lHQHgX+dt&4^,-r](X1RUVRDѭr MbM;+ gt{E#ZV=UkETarɚE9]YSf1Nf֢&DD@' nչpJSRs$Dk9j[ڑ\8S:8)"k!fBTM55V6Yرf#P,y.ijru>sUUUy3K>7ȶѢOTٹڇ+  h[KG{-{h< nJ؎*ƺ.KIr^T[*pJĹ}or5&6vEDrTa+QIP4p5ͅlI!kQMmNDK%-NNUs݇ӹrʱ5UUWZ8 -7 ިхrʨUEAjg eCU[Lb]jv=ne[UĪ12jJdc*rF谺wE#M+ފ]'*򪁧M|ˇU,{1/CT'+KDmwi+0"L^$JlAo[Q]$si̾j1u*=ҵSZi0lNCDm<:iIOFtnE@4K ȝO0־x!Yک׸WjTyқG - \$f\)к%{]4IkU{Er-CX9s^|َJujj[$AejxꚮxfqQT{]wNȨrk~p;na,.|z詣jAR^Tj".G/&t %q*$ ITб#csDW*i1UDD|*l[ZH["-Qˤh/}Vifsw FۥՎEV*kTjP#dʺJRYc4ߤ㍲+v5]Η[cY, k%Wb즍WV3EI.NߗEUQu2˨n$4jȱ4{76fDP,K0g>{ ij;MQ*]XUjF.u *|M G=Whދ4$ǣ\庲7Dթ,4pPR5,vj_UUUUU\sUU\UUUUUP=O 4V9%莵N75+fUj*rI0drE:QOQ+s$GHJ]ܼ[M`ƵֵD""jDD@=컆WU-EDO3#ȉ,mz2K#WMDE" .;Ohoo:ZZZ[Ξ_F]kT&]Cb{ IKF1jٷEUEV925VhGJ)"s%wdI^\{pl#X֣Z֢#ZDDMH摩=({nvE]u8^J,#bV5TEfȪFFyR`,aSJX^ŭswtZ挪DkDrDd𨣂h;RطTru.zY| *(ਗ਼9-4\;]}_49w JxvAgS(dvEV%dU@%A,"w߮U?43Zgj^]QCJo=XaT]ЛƞoKu9冪=q,ũY>)jeM9M%E͍k#4uU*T2E6NS-cfcXYUXQ-K8Qc lnq7w-Qw?cẒǁF")]*>4tp#ѳޚjv}@݆p*X + N牮{t^is()|. #[M"5^u<.D1\]z*@jf)I0HS;jaQU{\{VrhCqC/V8K".]{*#ٴ9Gk5y *i|R#t,ȍӒ 9U嵚UVíV(E, jfK"}2L,#v^Ds]uU쁪ǖ m. H%[r]=uUU-j5 @jP5 @jP5 @jP5 @jP5 @jP5 @jW|d9wY;;U9pЖ{G_6;7Z>F4v%Tzf7}jM[cy_8?IY*3_qJαU:f79㉛b`to+s5}7G+:VWj&nVu1L[cy_8?IY*L3V󉛣b`to+s5o8?IY*L3V󉛣b`to+s5}7G+:VWj&nVu1ռf%gX3_qJαU:f79㉛b`1L[ޙ~bf%gX3_qJαU:f79㉛b`to+s5}7G+:VWjq3t~Ul~ff%gX3_qJαU:f/9㉛b`to+s5}7G+:V阾Wj&nVu1L[cy_yJαU:f/9㉛b`to+s5}7G+:VWj&nVu1ռf%gX3_qJαU:f79㉛b`to+s5}7G+:VWj&nVu1L[cy_8?IY*L1Wq3t~Ul~ff%gX3_qJαU:f79㉛b`t_+s5}7G+:VWj&nVu1L[cy_8?IY*L3Wq3t~Ul~ff%gX3_qJαU:f79㉛b`1L[ޙ~ff%gX3[&nVu1L[cy_8?IY*L3Wq3t~Ul~ff%gX3_qJαU:f79㉛b`to+s5}7G+:VW*d|sb\/Ӧ{XscLO빣324ƚ6Z./Octave2.jpg000666 000000 000000 00000072262 10252613224 011400 0ustar00000000 000000 JFIFExifII*1&i.Picasa0220 !|5164728f80c3d8a60000000000000000R980100 (HHJFIFC  !"$"$C" O !1"7AQ#TVaqs26CRrt$BSu%45> !14q3AQSr"Tabc2R#B ?rVc*jS݉(%])0rzzoP ٕ~2"hیom-ʌ!zLwQƊJ1ψ]$mu*{`L0Z =kI-$oKO: $wA /:lQ3Z뛐t7sXS%b>.3TJT?+v{Y\{^˝v -=+v&kA7/ KJ5>Jk}֕=^#Ɋa %և77E0:iFqiMuOҷg:KoŘw.^>H8v&`wBa7PuɃuRsqiMuKz·h᜼:Ko˘`OckSuXܘ17X5-'Ի7)woXVvI{ ùsLD\Ex6?')n_pb^jZLcT[d P,d` y1tvrto:Ko X,{0H 6 ES#kA(m%zӯ.7D]Ҽ*NRNrQ4ذiB.a}o;)P`>,l'$Lis,K6{ά)aZÔi0qaJa3h l+-j,{:1} SI|Mqpn#ӈɒ/XS5Z7 ~ҀWy7":m\7C+ɌĄ$'D:dļh",& h6Rr;iWh|8/s{N p_a\@[vwlTߣHO4( FDv#B^zWAUD%Deڹ"TDDDDDDDDDDDDEKL@2ZY ؃l""2{Śop, Ohkn7LĴH|*`[W}Z1 UDyL)İ6CЫ3bba{ 8'Bg$u0εqG1W~Hr . [g‡(7&kZ  ٛԦLƇ-Zb3aâ{mC[Ϻ>uw\-ߵPTv)>x^6jgbI":9l(0[O(b5ao5NSܝɪqebj4iCi辂A/״V}^U#C˙c7`XV\MB(59ysw;Z|DHa_YQfd&DGA#nbٖ/F_H}W7P_-'_CP2+u!M*y {^0p_W qDD_UGo?EUs*gZi 7S$=VϞHak<=#jnM 6;ph]Kd}2~z\.'y*ǒ/p*Z>!9d3Pa?HAQ[]\i{lB/^DDDDDDDDE;TLF T)7sfu- ^cMEҩtefvÉ[U#q*6e_OQlK""""""(Pֻ T'U[>y"uVNmw8p|G_ TsrnWnJd\49K *})tLAʉhD@ {@@u$]66I87'@.I'ws tԴK׌(j.a:׌nQ[]\i;lB/^DDDDDDDDDY2?0BRĬpXet2(Tm*I)e=_GA_psgf*t%fNw7+l/ҲZ!= uC-TIA"""-kQhsL[.|G_ 8O~Ul䊿ֱY#6ݠnN6܋7s x~FxQ}cpO@[2@H݇†%\Q5p;ⰏAQ[]\i;lB/^DDDDDDDDDDDE?c>sZ$m]2iY˝^~rݦEķC3/ARVfksyZ-+c#q*6KN! K'""ؗDDDQ~12qn?|E_ XXO~U\䊿ֱY#6ݠaxQQ *4(4L-LME`h&åwX [C %"[ '#uQ[]\i;lB/^DDDDDDDDDDDDY i+b.6zҳ;+>M%I +F+BJYAߤe MXf38/E/Ҵef ;^;-򴬠elч!^Nh%ꤥ0UIF᪣ny8Zl~U|䊿ֱZ7ʟ"ª3bGGmQɻA]${ 4yq*zPFɌD30V1nvemH0n(W?1Elrwp{=hZRQseЈ ݂x%8y&~ppABķ3^3f)St%7Z-i[Ui+yQ2ӈ{RH5Tn)n7Iͼ]6#U_>y#uVMrHp|G_ XTsrnW~Hr?uasxZViSqaAi,X挥#aY v,-MÚ77 iarC@#f~IX]QXhea Z}益dO1_)*DMc.#B:WL|GCtg8.Z^WZc,+٘mdϻjbq xhmmUӧѥ" _UƆ BճHpt[bw- -\w̥=}?kyr,%2 JX1764zv/%8^7ػçBZ-ktx4};v\*Y 8 ڛ ݢ'>w&ZArV~? EL4Ww1"H.= qt-esL&RLOÞpib7ߺ7ؾ}ra/ugc |3uO[mݭ6;4oB~9FݚgcEK-h-$tN _(o{_|^IlH ĆƗ4^#Gg]KYe?d3)Qj,k2H.H <>ӹ0|>WG!ydN;'Zm7]mep!IGL[5\y߼ciܘake xƗ:%`4 f۳-mJbk-s#~Ȭ sKmqa U.iit\[eF?蹃yXy;RtkI>^2s{%CQ‹F3.sNP]x*Zb 'ō[\@hI'G`^j|RRxjf{YGIUrSRHNc9^bEgd&b. f>TR/)痝*nl7OVEa<*tGHGd~iφs47U횗ɺĬfƂ- {MVoH\kjtj|8Ñe 6 f:˨YXnf; žc6kGRQ6vÔsFE"http://ns.adobe.com/xap/1.0/ 3+$0&,=-$57/:7!572.C3.9+  1%!77+---27+-0+-77--+-+-72.+/++-+-+++0++77-+--/--+---S!1A"467QSUrst#2TBRaq35bCe$%:Q2R!4A"13aq#BCb$S ?ı1YU֍26M~պʋk7kZ٢GwylSzlֹ=4RQka\/&#b\ZNIɆ}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}äM$y;0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# 7N<:r0}ç# Aӑy?{'xtdjɾ~OpՓ}ӑ&=ç#VM{NF'dY7O9o<:r5dy?{'xtjɾ~OpՓ}ӑ&=ç#VM{NFpvbr@浱;||ֵUUl9x>VVv+ΪSa}3۱j鮻'mי3:Del͛*8}UnusD";5U]/PeNv~Låo-U?ܩ/3?='R|TԍfWĉ}Qxλ9c7lyaXUHcdΪETUDc詷{җ{Z)W]oxjY]N!ǯSptƫ5s$DŽؤZEKoh׮<E$X%/5I׵܎֢f"b_[S1WGʓ2s&JZ.M1]}vZE|yΖ#n[}nr,MUyR˜s{1- !s˲u]οԸ6uSy%LSa04zkHƮ\QEXյEr':MaeT\Kgv1Ed <3\z#FgΑ]w5n5yRWZ]&1)p )Vg~U'*2aF3Æ=~)NGMtӱڄ{MlI$ٜeC ފ8ge[YpmK&GS@s꣨lc"c)ks+dkl!xi?,aW.UUO^+-SeCjتkZ܋EV9)eФk"fuULL,bi8}t=SSKD jȒY+5q+9R˱!aEsES%7kJֈnF6 GY"ZƲF]K Kg9rrߓE#M负(,eSs.c,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 Q3j0ޞUq?'g jlVԹVΈ}* [2 N"b)|be־}D*9CuZ'#L3]%SV7+rUEl>T_m){|M% cBUWfJ1Un$kZSk8O4Mq4 FJKUͽWQtV?աIꟾM\Fknw-ٚl':tG19z&}U5NFs9fM3S7u~Fω8Oq$?|䥤}z';iq*%r5s.UcV m)e6jso ƫ?Uӵ]$c\tʹ=n|L6r0<sa )kHގʪW9˱UUіiyp67l+xTU2"1ȨٖɕkEC!y8y}1 јF=SFY%TrIGEX*.o*9,JkoMuXa7ib uls̱67ݪܪ~D[jՌu;嗼t0 'lĎ#2{Xs*]ڈ}6ƮikmkeLe"-Κ|n9>ŅU2[ύS"#ݨ2*-%/.ګI? +S\}ȎV'zZ1g]v˟/~a.S[p,fgDGыC s^msϕ̪*s\v/~V|||.UNj>mRpԒjrT@ƻW7Jȫs+Vdba6Dy氵'Z~twIbG6JhњdL4뛶Gr&&4mu4DN8aEhppYh1`N_-<5,FessTj#l1?:ki8xcĚ9]TbYw%6ĻmmWaarvEv6+*uhUMs0˩>H5IjAjAjAjAjAjAjAjAjAjAjAjAjAjAjAjAauHyjAjAjAjAjAjAjAjAjAjAjA_$_*6 ZZM61WO3F"Hr]d̩Q]^uk;,5|3Q_jyʮ1tO3y*9MpyiS7#[I[Y%Nt=϶lUDz(ՉZ5yelsiFUj"TrD=)g?51s 6|k#Օ?Oy_gx?5|ӒvH֥3:Z/]18DydGETWϛhrD*ֹnNb_miՏ,M'Njyr餶ov>Jq+Q\5зTWkّ-1F8SvjgḺR}~[,Y΍7x1le6)w-WQ-.7cWևҍiG s VGd؉[3=gQLT3/x<%'ߗg/7eYxϟ=k_VylRY'83g,7dqcxJO/ϖMVos %%bym,tM24mQ8ľcܲ/D峤O3tݍ?J%w JŎ!)> '7磽|^78K=^c~_{e3CR}~|nʳ8<%'ߗg/wdqcxJO/ϖ^nʳ8<%'ߗg&3CR}~|nʳ8<%'ߗg&3CR}~|nʳ8<%'ߗg&3CR}~uՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]YXuՙŎ!)> o>Y7]Y~_7,s8<%ߗg/wdqcxJ?/ϖM9XvNg81dݓŎ!( o>Y7dqcxJ?/ϖM9XvNg81dݓŎ!( o>Y7dqcxJ?/ϖM9XvNg81dݓŎ!( o>Y7dI'HEg%瑎K߮cT_LXZ?_K;v|26'9*gM\-Q͂6=Qͧ/Cؿ]#Js٭b Rker=s9"we%LWo)җkL5,,(^bOhφt)M7V58e*E3H]iu'3) S \[DUV![_g!sN̾wά8r.Qx-nzYڨ^U6r{a^ľvM:Ռ#w)uS+ᥖ7+nUmL-UKl&i{h|.j_pŨb1n\U-CZY T {u2"l@⩷Wby1{S> 㣫 KP֖@TENjӺKI,}}K EtDvk޶-*aU $u#fjFƭYmy>t l[Y>MTm)j$s>K#"jՍ 帇º_n!p[|+u 帇cK3֢Ev^#۬j"stC]?8WO->:qtCm1mkQ\"jf{mUW59Qº_n!p[|+u 帇º_n!>@ZF{>kQ.9DEڠd]?8WO->:qtC]?8WO->Z=;k\cۇ׹j ڊP +u 帇º_n!p[|+u pi-L dG5Rs\mEEMN:qtC]?8WO->:q8tƖvgDs>əV=H9QZTTT' 帇º_n!p[|+u 帇zcK+țZHתZk ض{V̨d]?8WO->:qtC]?cLie{kUcvI0V+^r$jy +u 帇º_n!p[|+u +Rk{&#fcn?jw A7Q#/o˿d *{v%G9tucrjnBvU8{rڽ[""/{mڈ]:MzvT88zcUX/d[]jƻ9¸ѓJ7Ry#tYcuMrYP%Ph'uCt祲NJ=QNIn\U-CZX^n7'E#^ԮQNr,R$*EE**sESpXDTDĺ;t*5ҶVQUsl]Τ/P>ZpF,;uh&qdUֻU%b7g\{(?_&xbGۘ~4TWdYl]*s*Jkow-iJ^ w N84!:dewc-{ɋڜR5흯SzrtZ5J@D{0ƪ) ӊ1dUVMK}eɱ/v?ʜ'8UōC,J۫*ƻQmWf۲e'ʨk(Ƭ`ᘤ82Ta5^vE2MMQTc Vƭ[H[O:>bN yy|] KopĨb$AGV.*,@7lzӓԑ_jWzШ'VjRG1M[].eNt؛aQ8([ZqX/}ܔDnb/2%Ɖʶ],>U!TDvIWl =#;r9eS)aPΪ'VYX w N84!:dewcSopĨb$|AGV7.*,@7lzӓԑ_jWzШ'VKǧjV|5sYLr"ESnղϵVs䭿h 8ZG6 ܰc l^9y[Wb"mqge{)hm16$#G5TV*]98g d=b w N84!:dewcSopĨb$i::qT ibygkޜzR>FQ:N`YW.Z)//t^R$Y^kRߴ-SU-mlm̫d.Fz"M9[+􆅼]&g ib- *Gn~I1'Uw_/.tg:>bN yy|] KopĨb$AGV.*,@+:W1t$+*h&F${tZlDFݍVui6#q3MNziT9t=ĆGDu[6`7lzӓԑ_jWzШ'VN j*&ΎnQeM|idfDSr;b/.U1[R5giwyr-\ơᲵYcjfjO-tիkN3EFind]e%,$Ψ7;+vlklD T u22l@⩷WbTy1{S~ 㣫KP֖ WvMjHׯ+TeOPYjWo#keS*kg|-vF1+FwN[O=Yڙ^Ժs,K-~7jm?H|3Mwo18qZdkڼ[leNeڛieMQTc .ƭ[H[OG۽_Rt@ A7Q#//˿d )mؕL^䟈8R5흯SzrtZ5J@D±9äV=[tb!ƙC\oTjZӊԣկmT}LW {XTq=c#[-?bcjDK1ޯ):F JN鑗Ke߲M»ɋڜXܸZݳoNNRF}]_B(XI`XFR˚fcr/ڛv.}%mFX^]O[c\xn~I1'Uw_FQ: H#n9ە.vm[[vԯW1G?A".K w N84!:dewc-{ɋڜR5흯SzrtZ5J@D+raq-Ji3Ү3+,Q6%v[MzYVHSt}'H T u22l@⩷WbTy1{S~ 㣫KP֖ WvMjHׯ+Te=!8Ϊʙ&D9Zlm%]m*JNXcD|?t[/@ w N84!:dewcSopĨb$AGV7.*,@4jqzZ墩6V־W#[w&յr-CNAkѹѓJ5cfcs"+um홷n7'E#^ԮQNy1ܳ<_kc_ג܈νmהч9~י#?hKkz@*A;nF^_=-~bN yy|] XT+*j|_(Kn^ޯ):F JN鑗Ke߲M»ɋڜXܸZݳoNNRF}]_B(X<0^clμE-['XNuTq}wףff">YVHSz@*A;nF^_=-~p ` w N84!:dewcSopĨb$AGV7.*,@9GIbrSQc[$jƱ%<ֽɛ*".d R}n o;X2Dz&e[{׵7'E#^ԮQNw?wH]h)nj]z׭b"+wK]J🤵?q.O+rހn~I1'Uw_ 㣫KP֖ ?ͤPXf΃W3_E5;"|Mc4UDr5NQ؎LjM5;)馁Rw@KLo_mݳoNNRF}]_B(Xcznqo֏:S[lcꫵ9וQ^˔iygY!LiIuFQ:K;z@JE?KuRֽny\KZW%iw֦>j|_(Kn^t}'H T u22lA]QNH.\U-CZX^n7'E#^ԮQN&1 %JR'.lr#S,Eu^ݭur5qo'?ZIRAW#p%Ph'uCt祲NJ[{v%G9#::qT ibygkޜzR>FQ:swx􁮕֊f׭zQ6/:"tԯ K^L|Qn.ܽt}'H T u22lA]QNH.\U-CZX^n7'E#^ԮQN!1߭kfu)nr:ǭWjs*뽮(71Ϝ:BG۽_Rt@ A7Q#/o˿d)mؕL^䏈8R5흯SzrtZ5J@DtǤ tS[5.kꉱyבĻxOZ}jc?tv@AW#p%Ph'uCt祲NJ[{v%G9#::qT ib[d)QTT*ij,Nĉ(9VY mȍL@L#JuydluHի;ܭO'յgkޜzR>FQ:cznqo֏:S[lcꫵ9וQ^˔iygY!LsxM[j޷T&'gHW[v9j* yy|] KopĨb$AGV.*,@9mH ʹuL2*$+Hk"%FdD@7ikz$ ǹD[QkTGvש9:-Iw}} u`tǤ tS[5.kꉱyבĻxOZ}jc?tv@ w N84!:dewc-»ɋڜXܸZݳoNNRF}]_B(X&1h[35?Ku=nSyU_]uF췙|Ւz@*A;nF^_=-~bN yy|] XT+*j|_(Kn^ޯ):F JN鑗Ke߲M»ɋڜXܸZߊtfEe15drMvIJK<7`\ףs'j*#DW63okÎݳoNNRF}]_B(X<1c R*je\U2 Mz"\J&yo>AW#p%Ph'uCt祲NJ]QNHn\U-CZXpEEy1ZpVe6ΒG[5s{6'30OM 솊 3'X1VK"u=;^$kڕށ*2Հswx􁮕֊f׭zQ6/:"uԯ K] 5S5>q[˷0z9%MzHX+]w3mܖE T u22l@]QNIn\U-CZX^n7'E#^ԮQNɌc=Z>ORnu[^UG{]z?.Qn;-b#8ud0t}'H T u22lA=QNI.\U-CZX^n7'E#^ԮQNw?wH]h)nj]z׭b"+wK]J🤵?q.O+rހn~I1'Uw_ 㣫 KP֖ WvMjHׯ+TeLc/M1g^jw-zUv:8r3ro3,ë$)AW#p%Ph'uCt祲NJ[{%G9#::qT ibygkޜzR>FQ:_9:Bү'b_U9nv$-?Z? 6G۽_Rt@ A7Q#//˿d *{v%G9'::qT ibygkޜzR>FQ:DƪbWDA#UxW$܉~T^EOd/%4dM4Ϝ:Bz@*A;nF^_=-~UTTx,8,no?h.Koa56ziYll˛"%y{JN鑗Ke߲  J&/jrOtuarj O2D/]+!͖ٲT''}51,N *XdG#bbQUr5v% lX*UPId͒5Vjv8Ƴ5ssZj9tE{.'| Z\f4u>h+[Qo rL؞J쑢"=Z^UNdUFm ꩛:H4m3푺[s6tHhx6} Y|Yl͗:9;e eD [j|dkrVuED8GiQ:Jsel/l@1ZAGNbTнΌhzUQr˵vHjbXT >)40ȏFr5Mj  9jeCs&E9z䳛;][JUGli$sc.ԻM@ԓH(ÛULHγFɚlU;n,B*$X|FUg5lQShc44U[QqI$dzƫ9mEN^{6N湒5ǵQsU.5ʊP R '2#&{kVUURFl_o}a >431ȯFr"*\]rl(%Ph'uCt祲NJ]QNIn\U-CZXG۽_Rt@vNH(=Cf4n,pFFl5U]d7Uʭ v%M5;շF9TI֪V׵Plt*oMASzU6j]v5.ʛ.筮*V j@74l.ZVʪfW9Qd役r;pgKjIђ28߭ZPċ>*:6HUĪC:-4m}UCrFijƪK.XXdG9kލư=4l͖k8ĪC:-4m}UCrFijƪK.XXdG9k<> Ii"Ѭ/Y d9'9L^5U\j4qFTRc*G-ukDE[@9Mtv85UMk[tU\ˣU.}YE#fiu͒m9al浱T9G%{uHîbXndS[tcD9j*Um{]mu BL;seW6 U>5Vuuш}bF@9(ipHȠ6HcTbbTE[5E"EDC$*'G 宊)&tQ m{ƪ[%]Wz=FOa5߈g}e-DSlV.g[K5/pjQK^J9I]oO r:6ٗe* T u22l@⩷WbTy1{S~ 㣫ICI ; H>/%[R;$dQvUȮNSZXx{S}WS~l~v|tќ:X5-Zبi海fWtDcfo-hFZWSCR&e4i5rHI<̈"}*mv äv cndsuR:LK?*_5cՔ>5O/HɡD|15}"+Q4u5^WG)qj>)ލ1$M{.H ㇵ<'ooPW>?Wl.ԻtWdp6ZǾY]$MW*ۥEځMciZiiZF8$7KeU3*"9,[B 7m%<4͖)h#(|]Uf,UW4!:dewc-»ɋڜ`=mTNձԺVO 95tPKmr939z[\֖8+u;S6o3ROo6~My%ticuCJYԌj䧉zzeT{jKm a Z A4 j䑪oTzR2sF#YNV8)ڮm+Zfʌ"5FrmnOOX_WP9dc5W"Y9WfͣoR[`f &twвFʬ#֪r a¹NjMԿS2[l͟n^`cxygQeuUl701槬 w [+keUE>\5A97=k)Jce;UͥkQ[LQDFu]mzs*(Ŭd^g5"Ȭ4jƙZG1Ufͣ0m0U3I;jEc&e{E˙sQv"Yv a3-S]_5sZhDWYr-1Gpc0\pc0\pc0\pc0\pc0\pc0\pc0\pc0\pc0\pc0\pc0\pc0t!:dewc/7#Xn#9SΚ|{7JqrOz<5rG}lq7'}W調#Ngrx~hUrG} q5'}WW$w)jOHSԞ1_7\Cd3F;lq5'}WW$w)jOHSԞ1_7\Cd3F;lF;lq5'}WW$w)jOHSԞ1_7\Cd3F;lq5'}WW$w)jOHS&Ѿ%9jOHSԞ1_7\Cd3F;lq5'}WW$w)jOHSԞ1_7\Cd3F;lq5'}WW$w)Rx~hUrG} &Ѿ%9MIU}U6Js8>F;lq5'}WW$w)jOHS&Ѿ%9s\iZ| ]N{r U"&0>./Octave3.jpg000666 000000 000000 00000102467 10252613474 011411 0ustar00000000 000000 JFIFXExifII*1&i.Picasa0220 !|40c95d7a5d00cc880000000000000000R980100 (5HHJFIFC  !"$"$C" U !1"AQa7Vqu#4RTs23BUr$56Sb%Ccd=  q!13AQ2Sr4Tac"R# ?2UO>JYqī- In~{4eZccp5gr CRJ!JZ$jb2ah`s #{8L%#`/#톙rZFk]FwkZmPKJy}q*U7Ik}|Pk !$ܓcsvu#py%CMGFnno+&:Z-_ҭ\ZKZir0)'AKP*N¹F|`p?7 70GTNd{aa05МNڏ0f#VqTS[JcdI݁9+1^7h7- L8jSNԛ쇀8:Ro-bnnZ+TҘp?77p?T>d1[;$xݠܴPS[JaT޿0?T>d<IP}\|1b7h7-j_ { 8ZCJԛ쇀#*Ro-㒮,E|-Ko}!’ay S* mTT ]}#m<IP}X( )EI4DS0v$:ܵSRT|(ֶީ[[VlȒ~meHF,E$*܁˦{xo(nGdW37`\s2bS&(6H B `#jfdG5^Q)>e) ( ."lW#O/DK}+ds%l+ ,c&)hķ?Xs! v7Uc ?Q;NJ@6Ј#U#TGUnt|yZ5_':FBuQ<USO1[KJMu JwWꨎYhl[QވQazTqEOMӒ^ZbbyfVZܾ{wWꨎY/ضE"^Hu aA,o{ N>j$-F F{kv=U25mVS羰E'iMj+Nl!*!;)_Q:/YqRlTIe`6LT% @vAix⬋7.2]ɜ* m4`fWL@{Ԅ0ԐA}"_TiI%+& G"Od Lich4r;IL[li#]3Zda B/1-w NNbIjaqI_(EqiM <S8i?"[!sc0LbMA@W举ǤFd.V \Zd!П`9l#74BRti1Ysq 9B0xX! BjFMiB Bi*QI&qLT%$@v|D[*?S߸̼qVE(7Qʉ:W;1! @w dKm$k5bْ'%~vɜ@YeEkۑƒ=Y ^8f0j B B=X°T q[.t))V,W,7{[:)c 7sX~񕷎y<IvID,}&PRd봇R3,ֈӄA<76CͅnXLnuWnkNJ!A=QA4ٕ(VI☩KVH7E Wb|K}Df^8" ˌVNaEi\b*9[d#[&P,M !c+IG^"LWeDRG+!޻+gW!A!Alor6:H`ZbUFü0e%I?@j-JrWӞ,:YXP7q14/R"&[rӃEU5Iۚ9?~ȹ{[Z\BV%BQ_+Yd/6xsk!EUvi*6ef\)87jɱwD[j>}F*xĽgO-e㊲'PܺRrk ) (.69"3UjK6K>-λ!)JoK`D_tf+߲"-4w`-'0sUHBD!HBD!H,c-QZb}K:[C}F*xĽg̼qV9! z_2GS AOv\P!{i\hߒ~Xfe3+̅CP%l6.!+ma eeMI5BUũ AI@(2A'Qڬǵps\՞? |f{YM%emN G[.] o1*\c8Ly*-7r3П<Ŏ*u}Yc4Bejfv@JWGRq&RUSS@SП<-kT'/g&X2ggji}%)lΧh WO4]=v7\nqu8flRl$un䫎*C\' gbiFhΤ(}αvOb1W+(+A6Nn}aOJk[}=l~c!5;T\*i3 \yly]}v7؍bPcV SlMwÐn6>y&8Zc_{[1%2+[7]nhLII/'qcyclEӱQHO<<3STARAU y:Iz~'co=ιẕxzS *bmOZe.'e_[EYbGs䨷ԌJ\Į;ْRl_Sc`{E m)fY98.*d$&@mTJT(B Ж\kDidԫ8ABE<0ytVĆ9mDh`Ma1ݸ)ì}j2%/AR`ڒJ4 n#Lff2ZUE'^]ыQ쪨I='5y H!7DV1;l464oSf!JRE)JE幹f H"http://ns.adobe.com/xap/1.0/   %'(# # 8) 1&555.29'=#()' 133(*'''*''('(33'('''''('''*'''/'''''''/''(''''''''T !1AQt"235TVar4RSU#Bq㑵$CDFbs= 1Q!2Rq"345ASa#BCbr$ ?Wi VT;Ѵڶ_U f%ҽqMpZ1g8<75g1:Hmu+Fy6nDg/U)|WarTl2U_?NJRtjIQNU|9*6IѪ'%F):5U$e'F䜕 WNU|9*6IѪ'%F):5U$e'F䜕 WarTl2U_?NJRtjIQNU|9*6KF꾓NJRtn?$e'F꾓NJRtn?$e'F꾓NJRtn?$e'F꾓NJRtn?$e'F꾓NJRtn?$e'F꾓NJRtn?$e'F꾓NJRtn?$e'F꾓NJRtn?$e'F꾓NJRtn?$e/O9*62tj?NNOa'FhѪ9:62tj?NNOa'FhѪ9:62tj?NNOa'FhѪ9:62tj?NNX;qLhA3Ze#KYNWlEˉnGVs:Պ6.«?ثsF*gn<_IR͇- ΈIe6/o9ʟ>]3b=Ѽ45q$\_fˎPNZ?эZvZnUĵ*>qO.pbI!#hk~kL\/Qˮs8%vTax+m\qF2 xZ#c\snVo ahU.'SK&6vĸzIѬTG Ġlj1c\GIp 爮'a܋tKN#1(Ӯ:3FroCfT!;KmOpu~Ֆ&&玶Bhl9Na.9N&3_~"|ezV7-PUUNTLۥ:?kr챹uo {uS%ˍ)+j ű@RS댭>Hb|!w#xmyسT\ƾ--Θyh+\OMM5:`,&uA<EpUU_~c rc8]ūu1^1v;xU4}[u< ro3VE]=;\ΧDoB]lv4갯U4U=q'YFy3eїKGU@:Jj36Ct`g.q0|qsY#`@hʻb٢+9C5WV1[Ͻ ߗS˗aGKKjmydG|Ѻ,A2͚Ke=<*KLD0'OSe#ο%W=5LIG dFյ3|iU3GVm'Et'Ob9~5(gSMx*e179ck[qrX% ڛZ3qZ#KG Xb&sOPum|8q/\'zʚSbuM$ԭĢ>A#!9a$˲CS5SqVX)d}=p3GS`eTtN1G,Z;1m ubngr՞[N f=}mVt4taXţHuoc3Fa֓spZ몬ܮ^m|s׮j,%si/[\̰QRfB}: ,O_B3vLmug:5ES,A0"1I絇Y35`7hkN͛y]~c^s'D_Mkk \̣h^onZ[Ā=͹k |=UٮSkm:2$YelFבَ:Hv^.~{/hi}/?[#Vמ0gc{U19 ]`\1qlxW S<Z:4`+Vzإ\Vj8[TO=,lv=lN4f/q7u[eѢ:bfsԐvsN< tU-ή3L#U=Y v*˕MYLۗ Th184jħY&`E b<9kg8j.n6׆v4ƽc/ۦ5u%N& {-Ew mo]\-cF]zD)5CZXӣDD\Ķ5iFĆ!j%uŋ5}se5۫ߦ="PlmQ{_SՍ֐K9)"hc]udݖw719DulHQU35z)sM>&Xא\Ѽ&H.ru3Lug TtΥ[5ߍO8Ct;Ҧ8BPZ^ 1FySN_dKtnF~s3 kԟJ{$qreU.G7m໦6V/*5k6Q(7#vl>kqQϭ'e&w'ۛN[ϭ=V_>k_<׷%/:Ak<%+G>&w'ۛ^v}oa욶I4>tv}o=VùeuMaX0ڞYGKGjEӪe_\/NQtnoe+}5m~z5<ֵ{r_"BY2s~iG}}HgɫiԓJ;'Hg5m:iG}}5m:iG}}5m:iG}}{&RM(O7"ݟ[dմIIVy욶I4>tv}o=Vө&w'ۛN[ϭjԓJ;/zEo>ɫiԓJ;'Hg5m:iG}R}{&RM(O?"ݟ[dմIIVy욶I4>tv}o=Vө&w'۟N[ϭju$Ҏs +}M[NQTn:Eo>ɫiԓJ;'Hg5m:iG}R}{&RM(O?"ݟ[dմIIVy욶I4>tv}o=Vө&w'۟N[ϭju$Ҏs +}M[NQTn:Eo>ɫiԓJ;'Hg5m:iO}}{&RM)??"ݟ[&vI4tv}o=;NStn:Eo>ɝRM)??"ݟ[dө&۟N[ϭgiԓJ{'Hg3I=GVyu$Ҟs +}L:iO}{&vI4tv}o=;NStn:Eo>ɝRM)??"ݟ[dө&۟N[ϭgk"s0$YEg =$n] Eތ|rfYOtǗ h?\ܫim tɧ;$ᵮd1n&en i^m K7MwƼY+@l-|^^SWiѮL%$uC' nZ\e%uYf^Fp7 uM':nkyVB-?W9Wl/EjV]ɤQcѽZU OUjs qڕWji=)wtogVm" 1(p\shcb%Fr.tm@ \W6§,M;[ncd-tHS4][`(pDqke9*#܍Ҵxf âġęU\*!0Y`-qK@@@@@@@@AEC]$5Գ6 3ZpYce`m51:8:i٠(fٜ#5sC_%$ȪQ9̎ skp.\l^b-;Ujs x"\»UGINۣ{<jiHZRI@f6VLb,/#ruıuDN :ESk$~rK&Rc10y 3d-q]eLi%lC՜)Zl 嘮5=H}<Ϥ41NauAn®17~R.ðHatF4Gxo|u@^{W^p$mAQAX$G(*0/cDfg(K4bSLʶo8\ ҹچ !3 4ة<={tIM45Q#dÌuq\BDH R n :֗A=DzJˌ,ֺ.5{LH8fsPDirXֹknֆAh n*VG[62fCKIQ$#d9(mK'p Tv%˴j`hé(O,X=cXeXO>,Nm>G<pbxUmHkv#SUMF&,ϧMë/ &L GC!k3 6siA@@@@@@@@@@@@@@@@@@B\u*Wz~^\kWji=)togVi" Ǡ!<`@@@@@@@@@@@@@@@@@@@@@@@B\u*Wz~^\kOji=)togVi" !.B\=]p/G.5'Ty4?}7[광Uo^1 SAQN>jPԶ6o$6˚2uk 3ausUGQMY95 k}_~i'u/)[ =*qWs'G,oc ؙqY&~|E rԪ5^z<qV=ɤQcѽZU??*9U$1堣Yi#s3֗LHOG8rHh(ٗ-$c$KђY3瑼v[uJ:<' %E RN61>ynoyPdI3XFˀ%,s Oq@@@@@A_0=A @B\u*Wz~^\kOji=)wtogVm" ʰ/Ur ^1š'0:9dExׇB]g0uZo$A0^g30L Õ38.9S38}^GW0iPH!nJsU랮_onڪ{UZH#E W p 9YTY RÍ/5TuՓPf7Lƈ Y©ضpn#ᣥ'i!p 8\3 MuW6X@f&L׿e'dm~^ 86(1)98-`4I~03 7|9 S͜ygU 1\QO]ImQ\َ.}R]Tb-תPXwu9ܥz@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Ak뱊WL.)unkr.n%[wRz+Eƹ[ۄ&ҝGFxk}V" Ѩej\<T1q87>%[b23 >C |Ekۮkݳ4R S|].VN~M!,@8?+mg< mT1uܢ%/wZeK.IR[-k,,vi[>u\SftzޚỮVmlrr#Ͳie;H\ mԯb8؍/_c^2f]fhpt]5uġ/oX67 #a #/&3L:JGR뽻X`dfκe66 -tU1:2nѩ#}ثG($K\=]p/G.5'Ty4;}7[궑V|3*W6/JoP&aV\$ni6fŊ[5֗:ۀk.1)q]Wԙac0Z!wXr꣄#@bx\DfDK4kؒg`n ?۪MJ?jluA Dd}3+]lo,}b+J:QZJ}㑙de ccx (>[>Y#}ثG($K@W9W\/r UM':n=$D!J͋R-u&"uz7QU^/ vtWoc*\ZW/$dvM ]J.T~+ TO0)^ژ086fk/mޏU35֖BA{&\VTդʊ&bv*8 -;Ujs x"\»UGINۣ{<jIigi=sb j]A> #Ɍ L(w\OZEmbc*\ZW/$dvM ]J.J+ Tƕ;c:Pk}!5$۬p|^[ѝ(hL:tإdFA6+lNqu5Dp^#}ثG($K@W9W\/r UM':n=$D!J͋R-u&3H0 3o_C%pq=i鵊W TUm۩ี;^I1`;,Mԕ]OT!V94pw]hx ps;K(ɹ9<<[sl>sY7@?G݊a{N"@ tUs\u+pQzS13[ʴUZgPhǏ,{MLцF-S΍ Y#c8fi{YFq .<.|^j)'&|oS;mݳ4R S|].Vm֏V+/PO֜٢~gB@,m[Xg]Daє텽ื쫎B G;&Ǝ.au)kEzEwi:voTMpkAkEps@L9Kz@" CMϙ+7ߨ[R aLfzOe~{aoީE ~o`{x /K)-u$-(---կDqobfh:vYPOKDH湤\G+'4T3zQuL0J۵h"hXLUK芣)cS$n7I ' š'F+gBӵ#}ثG($K@W9W\/r UM':n=D!J͋R-uo>/χUtgErqcn0WoTǿO^ֵsu:->1gz˒N݀ RVUWRYXΫ^?aAU #q%[wRz+Eƹ[v&ҝGFZUݳ4R S|].Vm='u?hxP.,mXV;ظֶnW# ]Z8xYrI۰J6RxC8kߧu'22Afhemx&Ћ骘kf'd҆}3d,}XCuG^JͰ@@@@@@@@@@@@@@@@@@@@@@@@@@A_0=A @B\u*Wr~^\kWji=)to{UZH+M>CMϙ+7ߨ[R a|_G]-m]݇aoީEc ~e`PW{ 5;lR\3l f%vSC>+0YxkyV"#5w9ZvU5,ԅL^8䩔f@d!-S!H<`d䐸ޚ+Xu\e!J͋R-uW:F0*InHpmMyXaغtjѝR#ӈzi]J3im. #)*ZgFw>WLhU[>U #q%[wRz+Eƹ[v&ҝGFxkyV" vϐs{%J)MwԺ}X@@@@@@@@@@@@@@@@@@@@@@@@@@G1αi5$,սבmb<7a7S.=ں,NGe$hٝ㈞B ESZuL{kg-v*8 -;Ujs x"\»UGINۣ{<jIigi=sb j]A> hVɣU2eKv,;3ml۰2p: wcާ=WCS #~W :m`3]]qkծi*Fe_ :w4\2Vmv*8 -;Ujs x"\»UGINۣ{<jIigi=sb j]A> w&=Lpz/-7k \;6, gwJ>in11})U+im_NJw OPWG^:޴,`M<8qn^Vfq\fYGW0iPH!nJsU뜮_oڪ{UZH+M>CMϙ+7ߨ[R aƪ~+Fva$wamvm՜#OF2۫tMQU_*ߙ1ak pLLg\U7Ln[`۝`4rpmmWLR宙t إdFA6+lNpMQ1?kעv*8 -;Ujs x"\»UGINۣ{<jI/ӉʺHh[$Xu}\.-{꩛O.l@'YZ8QVqj&SCMϙ+7ߨ[R a/*dἴ?xs<+hJƾѪ14F=x-"7}"}G#/EF'?sug}ntf baӈ !.B\9]p/G.5+Ty4?}7[ʴW;UHC% \W8Kplq2ͬyc K 1WX[D0F&Y$sɗzX_9rݳ4R S|].VeaF3+]i"s^ Cmh#抢rclUj0Nu+C#p|` EQ>?Unp"M@NjW71<|muNgSd:|&tŭVֳY+q ?/darvA(@B\u*Wr~^\kWji=)togVi" 7l 7>gTl_”~mK'ՄNM3jCcBMlio ^ RX{qfMկ( )[pm#h 6TQ25%DT:hc59Ff֝Š'FZ1:3~|E rԪ5^z<qV]ɤQcѽZUݳ4R S|].V~H\%ikHs\ prnQ4UĺWD:Fr2nVp͇ʬnEtEOp."S-U+*E!ݎ]?A$,j6ѥ* 3%aW/8AX۫>yUch?G݊a{N"@ tUs\u+pQzS1ڭo*D@@AZnn|d\ؿ).BڗPO&{i+4~UU(e=@ ΰkۖ8xx_spW*ѝRgc3w@}eAu3h݇3Ip< -w)Ϯ5]>u֖BlɮpcA5fʊf baӈ !.BUs\u+pQzS1ڭo*D@@AZnn|d\ؿ).BڗPO LjJ&MQG D`23 ;+fٳq?(IV4eΩoE0j f ?hI'ηUS1:TL:tdGR,N7lAgMQTg WFpY2GW0iPH!nJsU랮_r UM':n=$DgTl_”~mK'Մa5iE<%@ _. ^(0pl:EЧ-ɩ8kx\vAw iNzSb 9~|E rԪ5^{~+pQzS1ڭo*DA 4wҸhccjj |WCQF {Z"t>noҊf-SA #dIS@9|q˽Z,9znn|d\ؿ).BڗPOc5nDR+٥479N|ˌ|oj](5' x2>6"mL{9:OlV@/QΒ8\k%}N!Gl.N݈%K@W9W\/Eƹ[v&ҝGFxkyV" vϐs{%J)MwԺ}X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AьrMa9Zm+Ep߇|c0Q.&Uӿ4r5ak p蘘%nuMk,L9 A!y1*rKry 뭪jit*- baӈ !.B\9]p/ooڪ{UZH+M>CMϙ+7ߨ[R aŹ~;,8lNu%/:|XNb)V!]3*by#kH#99ڱ(Ʌ4'-Sェ@qnQq~;q~|E rԪ5^{~+pQzS1ڭo*D@@AZnn|d\ؿ).BڗPO6&-6S'pu ;ېmp\/uɷ\T8=Vl#i)]vJHk}*~"Xɷ^fDtI pº3mw(pQUo׷+8. w$҇C'K&;.%`-9Qxto%q)5 @@A[O#V`4mcO! ꮙzm7)ɧ:bu 6A"X*ᲊ&Bv*8 -;Ujs x"\»UGINۣ{<jI/,{E#()- E`pZVBJ*bN-Q*gC%6{5I6i-CfB)gi=sb j]A> F{ ALJh **g8iX\g-٤tqׂ3fucl8؎U?fS\# x7k@@AoZKHZi@Zjҍ4եNlr2f#p- FAmẚc8~ׯD>U #q%[wRz+Eƹ[v&ҝGFxkyV"<cMaTEQ4ΤXֲ gBvx."*bCT7Đ=sy2V=^"|3*W6/JoP I&V055FsC% 9KAwlmO[c߁ZTr9]??KKv }5p]qsxs<$'c? ont"M1[#[I.fW~^؂P tUs\u+pQzS1ڭo*D@@AZnn|d\ؿ).BڗPO?Q$.45$98^T wmSr%Ѻ =1вG^f~@\ ]`n%?Q/ `g-H3Lr4Ah QK E pvg O os'Ftee[>U #q%[wRz+Eƹ[v&ҝGFxkyV" vϐs{%J)MwԺ}X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A-Iݣ z]!H˔obЯ)*618~RSO :mDn#p25FRƤ4u.۵6Fl6\coŠ'FZ1:53~|E rԪ5^z<qV]ɤQcѽZUݳ4R S|].VLe+s&4rOLC^\:&;3%Rpo8;bs2SԁcWRoekm%?°(kFuk)*Fe_ Yn[%f baӈ !.B\=]p/G.5+Ty4?}7[ʴV|3*W6/JoP ch\x iZ/(ˆ%w%᪣<]1Ա sZEp=S4ĽDuymL ~u5ܗ6Xp]t:QQQL 5܎"&TWu1~|E rԪ5^z<qV]ɤQcѽZU'Yu{aQ@^8p2]bKU%c0Z TJm^9k>mp[lքSvϐs{%J)MwԺ}X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AvM{^Z~s:vlX 347Vj>U7]LM,cn9xnFthtYHɚ$AA'8ͺ3z@@@A_0=A @B\u*Wz~^\kWji=)togVi" 56,溡񽦳36-Vmgpl$=(bص4 6A4:$sLբ:c!J͋R-uab`u1bp '[`ӱ͹W[lܛuNӋj~&Uӿ3$c^b.AV nuM5kƒlec@&fnO$FO""5?KעAGCV:Har˫kY8iq;v !.B\=]p/G.5'Ty4?}7[광V|3*W6/JoP [r #_Tyi~8>y*S{8Е \Tbhz^ uI)bv*8 -;Ujs qV=ɤQcѽZUݳ4R S|].VzTKG#j`~W潆 côM34blS~V]16S2îHnc Ȯ +ުflr#}ثG($K@W9W\/Eƹ[ۄ&ҝGFxk}V" vϐs{%J)MwԺ}X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AcnKPڌ3M]; Gv"fkU]4(ο_]UAGW0iPH!nJsU뜮_oڪ{UZH+M>CMϙ+7ߨ[R a9$XZ湤5G jnQ4UĺKC-'mcvH2vش6P\{v} f\8|5/ͺx7k@@@@@@@@A_0=A @B\u*Wr~^\kWji=)togVi" 㸟A(1mN}D/>7?.k_-b_E[R3 j`_Ldy cI3M7{,hE7l 7>gTl_”.OiSL*vN24&F;DҧhT#JdiSL*vN24&F;DҧhT#JdiSL*vN24&F;DҧhT#JdiSL*vN24&F;DҧhT#JdiSL*vN24&F;DҧhT#JdiSL*vTL6VhfPz+`9,q6vUgsb.QU?m_S/&aʆFaʆFaʆLJ,J'f!6sX`mx@@@@A_0=A @B\u*Wz~^\kWji=)togVi" gF0vMD&736[5p_CEU3iQL o {>8eޭ{pmQ8k]5- ^LDK:.UEZTRQ}^%FG>wNtw:oܜ}Ϝ(ts9*6ߟ9:Qߨ/rrTl9#>rtQ}^sG~|GG~Q؎ҎGM1{aϱb'%Fßb;'J:;7NJ>wNtw:oܜ}Ϝ(ts9*6ߟ9:Qߨ/rrTl9#>rtQ}^sG~|GG~Q؎ҎGM1{aϱb'%Fßb;'J:;7NJ>wNtw:oܜ}Ϝ(ts9*6ߟ9:Qߨ/rrTl9#>rtQ}^sG~|GG~Q؎ҎGM1{aϱb'%Fßb;'J:;7NJ>wNtw:oܜ}Ϝ(ts9*6ߟ9:Qߨ/rrTl9#>rtQ}^sG~|GG~Q؎ҎGM1{aϱb'%Fßb;'J:;7NJ>wNtw:oܜ}Ϝ(ts9*6ߟ9:Qߨ/rrTl9#>rtQ}^sG~|GG~Q؎ҎGM1{aϱb'%Fßb;'J:;7NJ>wNtw:oܜ}Ϝ(ts9*6ߟ9:Qߨ/raϱb/t)Ý]IҎGM1{B9(ts4)s:Qߨ/rhSW{BtVcmyq-^Djkߞ4?J5W4?J5P:D(<֛@CZoMRi 3L  ej"o6@/l(6K@W9W\/r UM':n=$DOL`fm.r/l60,[ *1LBx˃dL/ \m(=(k8e\sD'6HbZr fxZNZ$s^ahsxHFx7 åpz韇QKQ}l1#]6Āol`IᄵֺGF@/xcZxNV=M'm%i\3*K&vf[m*  ~'&^bS3j|͗9fr wuf+UC$i3#qAb65;z-Oͫ96\^ٛyZK7MO!h{Y$͒7Xm"!n+QIcdz5q`cx#w!A1|oacv pN-2JBdF1=٤c6?= Űe !8ςFJ-.a 901 rԪ5^z<qV]ɤQcѽZU?G݊a{N"1oH(1*CTY87K8[$q1ډIqZ۴h%6+OkDBˆ=2Si$8]lֻrDyi ?AIsdxcA=Er COG_*C 1],Aē>W84nb{[6F^`ӿL Jjq0Yrkm[5:̡аB4F6rd!8@@@Aī! 5#ehdLcdD-dQ.7s<3.5h{eϪ&fsk彮PZ5xd8{l |ye,31%Y{XaƅSROII 0j@5N:Y.4ᕭ !fsnM8E]h8gs7!{!tDcupq %Š\f! Nƒ٘@#KlNj52mc.i>.P@0bbԍmd29O>(姤lsȪ_HL# SbHɫ),cMS%;֒KC%I6k!@@AN s裘#'O960X6 ~(H=,&Hsc)`8ٮh7sNָhodR  ~9?IntpD$ZcC3mrNPVz=C%X ñST]KUaԹ̦yk5kkq ʳQI^ct$MtQ˚8¤6ٝ|P%[wRz+Eƹ[v&ҝGFxkyV" ~'`^aPTjjG6L͗86Vrx, DadV@pkA +OOYF1kZѰ=y!sCi{vH@f~#GADGlLvy.  9 b\_pas 9^q84}ET{fz 65x`8F)STH R0CC o@~`2>*Jvgb/؝k4  ^%X2Q`5 mw8PX %12dF'Z ;@măhpeᨌ8=6J x 92FArSHb{!e\,f4X[61(8}$sDgVHb31 94krΦb015Ȉ={Ǖ!cik#cZ1kZ6 }f:* b>QF.slO\R2!cik#cZ1kZ6 :' dx|2G;$l{%{C]#HF.~cyJ <21GAI12#6ܗm$2! rԪ5^z<qVGUM':n,խUZH*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*qʆp\rg*0=;Ujs x##\FT#nzU\;\sDyNyQ%[hG;ѯԍx|~%!ϧsߓl"[*oEڻs3i*Gqu _'kG3i*ȞݯΝ sqʬ|S| ɽFͬ6[^=_r=n{*fr[o:2\qrOLD7W~^t[:/ټzt[Y7W~:IsǭCIΫ$$~U߿N\qq?|fI.~8u>_ywS?zt:/ټ~K=n:gOu]:IsǭCIΫI.~8u>_yw%'oJޝ$$~U߿N\qq?|fI.~8u>_ywS?zt:/ٽ*zt[Y7W~N\qq?|fI.~8u>_zUw%'oJޝ$$~U߿N\qq?|fI.~8u>_ywS?zt:/ټ~K=n:gOu]?T%'o:t[Y7W~:IsǭCIΫ$$~U߿N\qq?|fI.~8u>_ywS?zt:/ټ~K=n:gOu]?T%'o:t[Y7W~:IsǭCIΫ$$~U߿N\qq?|fI.~8u>_;Ui$xLnG3/߃tSg+ zQ9u _/}_r=nrs:vB-qu _'kG3i*ȞݯΝP ?"{vzs:v+w=5f: 8õ؏[\SE9Ux[ݯ3;N5^kD}t:x[۵#ӴUoOn܏[gNӨUW=_r=n9;NU^kD}t:Ux[۵#ӴUoOn܏[gNֿrZjnoe5wge~+ckG3ka*ȼ}txK9[y5pSgN)/./open.gif000666 000000 000000 00000001072 11034075772 011023 0ustar00000000 000000 GIF89a   0 00 @80`H PH@^YY`X@vgIp`Ph p x pPx``kp̙А 000ШPаp@@PPPf`ppúƷȀЀ؀؀Р!, DD.4:BBA?-5-@??'*++>?9%*>00,,+(+ Using lpsolve from PHP

Using lpsolve from PHP

PHP?

PHP is a general-purpose scripting language that is especially suited for web development. PHP generally runs on a web server, taking PHP code as its input and creating web pages as output. It can also be used for command-line scripting and client-side GUI applications. PHP can be deployed on most web servers, many operating systems and platforms, and can be used with many relational database management systems. It is available free of charge, and the PHP Group provides the complete source code for users to build, customize and extend for their own use. PHP primarily acts as a filter, taking input from a file or stream containing text and/or PHP instructions and outputs another stream of data; most commonly the output will be HTML. It can automatically detect the language of the user. From PHP 4, the PHP parser compiles input to produce bytecode for processing by the Zend Engine, giving improved performance over its interpreter predecessor. Originally designed to create dynamic web pages, PHP's principal focus is server-side scripting, and it is similar to other server-side scripting languages that provide dynamic content from a web server to a client, such as Microsoft's ASP.NET system, Sun Microsystems' JavaServer Pages, and mod_perl. PHP has also attracted the development of many frameworks that provide building blocks and a design structure to promote rapid application development (RAD). Some of these include CakePHP, PRADO, Symfony and Zend Framework, offering features similar to other web application frameworks.

We will not discuss the specifics of PHP here but instead refer the reader to the PHP website.
An introduction to PHP can be found at w3schools

PHP and lpsolve

lpsolve is callable from PHP via an extension or module. As such, it looks like lpsolve is fully integrated with PHP. Matrices can directly be transferred between PHP and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for PHP (especially for matrix support). So you have full control to the complete lpsolve functionality via the lpsolve PHP driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level script files that can make things a lot easier. See further in this article.

Installation

To make this possible, a driver program is needed: php_phplpsolve55.dll (windows) or phplpsolve55.so (Unix/Linux).
Secondly in the file php.ini, which is a PHP configuration file, the location of the driver must be specified. The location of this ini file depends on the environment.
Under windows it is commonly \Program Files\php\php.ini
Under Unix/Linux it was found under /etc/php5/cli and /etc/php5/apache2
In that file there is an item extension_dir=. The driver program must be put in the directory specified by that item.
Then an extra entry 'extension' must be added.
Under windows it must be: extension=php_phplpsolve55.dll
Under Unix/Linux it must be: extension=phplpsolve55.so

Note that there is an alternative way but it is not always working, especially as webservice. In the php.ini file, specify enable_dl=on
Then in the PHP code, use the following command to load the lpsolve driver: dl('lpsolve.so');
However, this was not tested so use it at own risk.

To take these changes in effect, the webservice has to be restarted.
Under windows, this is done by restarting the service.
Under Unix/Linux it depends on the system. For example in Ubuntu the command is: sudo /etc/init.d/apache2 restart
This must be done with root privileges: sudo su -

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux) (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). This has the advantage that the lpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the Windows path.

So note the difference between the PHP lpsolve driver that is called (php_)phplpsolve55 and the lpsolve library that implements the API that is called lpsolve55.

Testing the installation

Note. In the following text PHP commands are given. They are just provided as is. However in a real PHP application, all PHP commands must be between <?php and ?>

Note. Some of these commands return new lines to continue on the next line. This is fine under CLI (php executed in a command line), but when PHP is used in a web environment and shown in html, then these newlines are by default just ignored by html. This gives an output that is not always that readable. Therefore you can put everything between <pre> </pre>
This combined with the note from above, put the commands in following block:

<?php
echo "<pre>";
// your php commands
echo "</pre>";
?>

To test if everything is installed correctly, execute the following statement in PHP.

lpsolve();

Note. As stated above, these commands must be between <?php and ?> and when used in html between a pre block as shown below:

<?php
echo "<pre>";
lpsolve();
echo "</pre>";
?>

Keep this in mind. This will not be repeated in the following text.

If it gives the following, then everything is ok:

lpsolve PHP Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: ret = lpsolve("functionname", arg1, arg2, ...)

If you get the following:

Windows:
PHP Warning:  PHP Startup: Unable to load dynamic library 'F:\php-5.2.6\Release_TS\php_phplpsolve55.dll' - The specified module could not be found. in Unknown on line 0
PHP Fatal error:  Call to undefined function lpsolve() in Command line code on line 1
Possible also with a messagebox saying:
---------------------------
php.exe - Unable To Locate Component
---------------------------
This application has failed to start because lpsolve55.dll was not found. Re-installing the application may fix this problem.
or Unix/Linux:
PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib/php5/20060613+lfs/phplpsolve55.so' - liblpsolve55.so: cannot open shared object file: No such file or directory in Unknown on line 0

Fatal error: Call to undefined function lpsolve() in Command line code on line 1

Note that the PHP Warning is not always shown. The Fatal error is. This was specifically noted in the web environment.

Then PHP can find the lpsolve driver program, but the driver program cannot find the lpsolve library that contains the lpsolve implementation. This library is called lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux.
Under Windows, the lpsolve55.dll file must be in a directory that in the PATH environment variable. This path can be shown via the following command in a command prompt: PATH
It is common to place this in the WINDOWS\system32 folder.

Under Unix/Linux, the liblpsolve55.so shared library must be either in the directories /lib or /usr/lib or in a directory specified by the LD_LIBRARY_PATH environment variable.

Note that in a web environment the webserver may need to be restarted after making changes in the configuration. For example on Ubuntu this is done by the following command:

sudo /etc/init.d/apache2 restart

Another way to check if the lpsolve extension is available in PHP is by entering the following command:

print_r(get_extension_funcs("lpsolve"));

This must return:

Array
(
    [0] => lpsolve
)

To return the version of lpsolve, the following PHP command can be executed:

echo phpversion("lpsolve");

This must return:

5.5.0.6

Note that this is the version of the PHP driver, not the version of lpsolve itself.

Solve an lp model from PHP via lpsolve

To call an lpsolve function, the following syntax must be used:

ret = lpsolve('functionname', arg1, arg2, ...);

The return value is optional and depend on the function called. Sometimes it is a single value, sometimes a vector and sometimes a vector of vector. functionname must always be enclosed between single or double quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra PHP specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in PHP, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the PHP functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from PHP, nothing must be dimensioned in advance. The lpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to lpsolve. Never as argument to the routine. This can be a single value as for get_objective or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

Note that you can get a usage of lpsolve, its arguments and the constants that it defines by entering the following in PHP:

lpsolve();
$a=get_defined_constants(true); print_r($a[lpsolve]);

This will give:

lpsolve  PHP Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: ret = lpsolve("functionname", arg1, arg2, ...)
Array
(
    [LE] => 1
    [EQ] => 3
    [GE] => 2
    [FR] => 0
    [SCALE_NONE] => 0
    [SCALE_EXTREME] => 1
    [SCALE_RANGE] => 2
    [SCALE_MEAN] => 3
    [SCALE_GEOMETRIC] => 4
    [SCALE_CURTISREID] => 7
    [SCALE_QUADRATIC] => 8
    [SCALE_LOGARITHMIC] => 16
    [SCALE_USERWEIGHT] => 31
    [SCALE_POWER2] => 32
    [SCALE_EQUILIBRATE] => 64
    [SCALE_INTEGERS] => 128
    [SCALE_DYNUPDATE] => 256
    [SCALE_ROWSONLY] => 512
    [SCALE_COLSONLY] => 1024
    [IMPROVE_NONE] => 0
    [IMPROVE_SOLUTION] => 1
    [IMPROVE_DUALFEAS] => 2
    [IMPROVE_THETAGAP] => 4
    [IMPROVE_BBSIMPLEX] => 8
    [PRICER_FIRSTINDEX] => 0
    [PRICER_DANTZIG] => 1
    [PRICER_DEVEX] => 2
    [PRICER_STEEPESTEDGE] => 3
    [PRICE_PRIMALFALLBACK] => 4
    [PRICE_MULTIPLE] => 8
    [PRICE_PARTIAL] => 16
    [PRICE_ADAPTIVE] => 32
    [PRICE_RANDOMIZE] => 128
    [PRICE_AUTOPARTIAL] => 256
    [PRICE_LOOPLEFT] => 1024
    [PRICE_LOOPALTERNATE] => 2048
    [PRICE_HARRISTWOPASS] => 4096
    [PRICE_TRUENORMINIT] => 16384
    [PRESOLVE_NONE] => 0
    [PRESOLVE_ROWS] => 1
    [PRESOLVE_COLS] => 2
    [PRESOLVE_LINDEP] => 4
    [PRESOLVE_SOS] => 32
    [PRESOLVE_REDUCEMIP] => 64
    [PRESOLVE_KNAPSACK] => 128
    [PRESOLVE_ELIMEQ2] => 256
    [PRESOLVE_IMPLIEDFREE] => 512
    [PRESOLVE_REDUCEGCD] => 1024
    [PRESOLVE_PROBEFIX] => 2048
    [PRESOLVE_PROBEREDUCE] => 4096
    [PRESOLVE_ROWDOMINATE] => 8192
    [PRESOLVE_COLDOMINATE] => 16384
    [PRESOLVE_MERGEROWS] => 32768
    [PRESOLVE_IMPLIEDSLK] => 65536
    [PRESOLVE_COLFIXDUAL] => 131072
    [PRESOLVE_BOUNDS] => 262144
    [PRESOLVE_DUALS] => 524288
    [PRESOLVE_SENSDUALS] => 1048576
    [ANTIDEGEN_NONE] => 0
    [ANTIDEGEN_FIXEDVARS] => 1
    [ANTIDEGEN_COLUMNCHECK] => 2
    [ANTIDEGEN_STALLING] => 4
    [ANTIDEGEN_NUMFAILURE] => 8
    [ANTIDEGEN_LOSTFEAS] => 16
    [ANTIDEGEN_INFEASIBLE] => 32
    [ANTIDEGEN_DYNAMIC] => 64
    [ANTIDEGEN_DURINGBB] => 128
    [ANTIDEGEN_RHSPERTURB] => 256
    [ANTIDEGEN_BOUNDFLIP] => 512
    [CRASH_NONE] => 0
    [CRASH_MOSTFEASIBLE] => 2
    [CRASH_LEASTDEGENERATE] => 3
    [SIMPLEX_PRIMAL_PRIMAL] => 5
    [SIMPLEX_DUAL_PRIMAL] => 6
    [SIMPLEX_PRIMAL_DUAL] => 9
    [SIMPLEX_DUAL_DUAL] => 10
    [NODE_FIRSTSELECT] => 0
    [NODE_GAPSELECT] => 1
    [NODE_RANGESELECT] => 2
    [NODE_FRACTIONSELECT] => 3
    [NODE_PSEUDOCOSTSELECT] => 4
    [NODE_PSEUDONONINTSELECT] => 5
    [NODE_PSEUDORATIOSELECT] => 6
    [NODE_USERSELECT] => 7
    [NODE_WEIGHTREVERSEMODE] => 8
    [NODE_BRANCHREVERSEMODE] => 16
    [NODE_GREEDYMODE] => 32
    [NODE_PSEUDOCOSTMODE] => 64
    [NODE_DEPTHFIRSTMODE] => 128
    [NODE_RANDOMIZEMODE] => 256
    [NODE_GUBMODE] => 512
    [NODE_DYNAMICMODE] => 1024
    [NODE_RESTARTMODE] => 2048
    [NODE_BREADTHFIRSTMODE] => 4096
    [NODE_AUTOORDER] => 8192
    [NODE_RCOSTFIXING] => 16384
    [NODE_STRONGINIT] => 32768
    [NOMEMORY] => -2
    [OPTIMAL] => 0
    [SUBOPTIMAL] => 1
    [INFEASIBLE] => 2
    [UNBOUNDED] => 3
    [DEGENERATE] => 4
    [NUMFAILURE] => 5
    [USERABORT] => 6
    [TIMEOUT] => 7
    [PRESOLVED] => 9
    [PROCFAIL] => 10
    [PROCBREAK] => 11
    [FEASFOUND] => 12
    [NOFEASFOUND] => 13
    [BRANCH_CEILING] => 0
    [BRANCH_FLOOR] => 1
    [BRANCH_AUTOMATIC] => 2
    [BRANCH_DEFAULT] => 3
    [MSG_PRESOLVE] => 1
    [MSG_LPFEASIBLE] => 8
    [MSG_LPOPTIMAL] => 16
    [MSG_MILPEQUAL] => 256
    [MSG_MILPFEASIBLE] => 128
    [MSG_MILPBETTER] => 512
    [NEUTRAL] => 0
    [CRITICAL] => 1
    [SEVERE] => 2
    [IMPORTANT] => 3
    [NORMAL] => 4
    [DETAILED] => 5
    [FULL] => 6
    [Infinite] => 1.0E+30
)

The array shows all constants defined by the lpsolve driver and are all the constants of the lpsolve API. That way one can enter these symbols instead of their numerical values.

Also see Using string constants for an alternative.

An example

(Note that you can execute this example by entering command per command as shown below or by executing script example1.php)

$lp = lpsolve('make_lp', 0, 4);
lpsolve('set_verbose', $lp, IMPORTANT);
$ret = lpsolve('set_obj_fn', $lp, Array(1, 3, 6.24, 0.1));
$ret = lpsolve('add_constraint', $lp, Array(0, 78.26, 0, 2.9), GE, 92.3);
$ret = lpsolve('add_constraint', $lp, Array(0.24, 0, 11.31, 0), LE, 14.8);
$ret = lpsolve('add_constraint', $lp, Array(12.68, 0, 0.08, 0.9), GE, 4);
$ret = lpsolve('set_lowbo', $lp, 1, 28.6);
$ret = lpsolve('set_lowbo', $lp, 4, 18);
$ret = lpsolve('set_upbo', $lp, 4, 48.98);
$ret = lpsolve('set_col_name', $lp, 1, 'COLONE');
$ret = lpsolve('set_col_name', $lp, 2, 'COLTWO');
$ret = lpsolve('set_col_name', $lp, 3, 'COLTHREE');
$ret = lpsolve('set_col_name', $lp, 4, 'COLFOUR');
$ret = lpsolve('set_row_name', $lp, 1, 'THISROW');
$ret = lpsolve('set_row_name', $lp, 2, 'THATROW');
$ret = lpsolve('set_row_name', $lp, 3, 'LASTROW');
$ret = lpsolve('write_lp', $lp, 'a.lp');
print lpsolve('get_mat', $lp, 1, 2) . "\n";
print lpsolve('solve', $lp) . "\n";
print lpsolve('get_objective', $lp) . "\n";
print_r(lpsolve('get_variables', $lp));
print_r(lpsolve('get_constraints', $lp));
lpsolve('delete_lp', $lp);

This gives as output:

78.26
0
31.7827586207
Array
(
    [0] => Array
        (
            [0] => 28.6
            [1] => 0
            [2] => 0
            [3] => 31.8275862069
        )

    [1] => 1
)
Array
(
    [0] => Array
        (
            [0] => 92.3
            [1] => 6.864
            [2] => 391.292827586
        )

    [1] => 1
)

Note that get_variables and get_constraints return two results: The result vector and a status. If only the vector is needed, then variable indexing must be used. For example:

$ret = lpsolve('get_variables', $lp);
$x = $ret[0];
$ret = $ret[1];
print_r($x);
print $ret . "\n";

Variable x will contain the result vector and ret the return status of the call:

Array
(
    [0] => 28.6
    [1] => 0
    [2] => 0
    [3] => 31.8275862069
)
1

Don't forget to free the handle and its associated memory when you are done:

lpsolve('delete_lp', $lp);

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
$lp = lpsolve('make_lp', 0, 4);
$ret = lpsolve('set_lp_name', $lp, 'mymodel');
lpsolve('set_verbose', 'mymodel', IMPORTANT);
$ret = lpsolve('set_obj_fn', 'mymodel', Array(1, 3, 6.24, 0.1));
$ret = lpsolve('add_constraint', 'mymodel', Array(0, 78.26, 0, 2.9), GE, 92.3);
$ret = lpsolve('add_constraint', 'mymodel', Array(0.24, 0, 11.31, 0), LE, 14.8);
$ret = lpsolve('add_constraint', 'mymodel', Array(12.68, 0, 0.08, 0.9), GE, 4);
$ret = lpsolve('set_lowbo', 'mymodel', 1, 28.6);
$ret = lpsolve('set_lowbo', 'mymodel', 4, 18);
$ret = lpsolve('set_upbo', 'mymodel', 4, 48.98);
$ret = lpsolve('set_col_name', 'mymodel', 1, 'COLONE');
$ret = lpsolve('set_col_name', 'mymodel', 2, 'COLTWO');
$ret = lpsolve('set_col_name', 'mymodel', 3, 'COLTHREE');
$ret = lpsolve('set_col_name', 'mymodel', 4, 'COLFOUR');
$ret = lpsolve('set_row_name', 'mymodel', 1, 'THISROW');
$ret = lpsolve('set_row_name', 'mymodel', 2, 'THATROW');
$ret = lpsolve('set_row_name', 'mymodel', 3, 'LASTROW');
$ret = lpsolve('write_lp', 'mymodel', 'a.lp');
print lpsolve('get_mat', 'mymodel', 1, 2) . "\n";
print lpsolve('solve', 'mymodel') . "\n";
print lpsolve('get_objective', 'mymodel') . "\n";
print_r(lpsolve('get_variables', 'mymodel'));
print_r(lpsolve('get_constraints', 'mymodel'));
lpsolve('delete_lp', 'mymodel');

This gives:

78.26
0
31.7827586207
Array
(
    [0] => Array
        (
            [0] => 28.6
            [1] => 0
            [2] => 0
            [3] => 31.8275862069
        )

    [1] => 1
)
Array
(
    [0] => Array
        (
            [0] => 92.3
            [1] => 6.864
            [2] => 391.292827586
        )

    [1] => 1
)

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific PHP routine to get the handle from the model name: get_handle.
For example:

$lp = lpsolve('get_handle', 'mymodel');
print $lp;

This gives:

0

Don't forget to free the handle and its associated memory when you are done:

lpsolve('delete_lp', 'mymodel');

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

lpsolve uses PHP arrays to represent matrices (and vectors).
For example:
lpsolve('add_constraint', $lp, Array(0.24, 0, 11.31, 0), 1, 14.8);

Most of the time, variables are used to provide the data:

lpsolve('add_constraint', $lp, $a1, 1, 14.8);

Where $a1 is a variable of type array. Sometimes a two-dimensional matrix is used. In PHP, that is an array of arrays:

lpsolve('set_mat', $lp, Array(Array(1, 2, 3), Array(4, 5, 6)));

Array(1, 2, 3) is the first row and Array(4, 5, 6) is the second row.

PHP also supports sparse matrices because of the way arrays are internally supported.
For example:

$a[2] = 3;
$a[5] = 5;

print_r($a);

This gives:

Array
(
    [2] => 3
    [5] => 5
)

The lpsolve driver accepts these as is. No conversion or so is needed. The non-provided elements are seen as zero-values.

In fact, the lpsolve driver sees all provided matrices as sparse matrices. lpsolve uses sparse matrices internally and data can be provided sparse via the ex routines. For example add_constraintex. The lpsolve driver always uses the ex routines to provide the data to lpsolve. Even if you call from PHP the routine names that would require a dense matrix (for example add_constraint), the lpsolve driver will always call the sparse version of the routine (for example add_constraintex). This results in the most performing behaviour.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the PHP interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the PHP matrix.

Maximum usage of matrices with lpsolve

Because PHP has the array possibility to represent vectors, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the lpsolve PHP driver to also work with vectors. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The lpsolve PHP driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: $return = lpsolve('set_int', $lp, $column, $must_be_int);. The matrix version of this call is: $return = lpsolve('set_int', $lp, $must_be_int);. Here $must_be_int must be an array variable. The API call to return the integer status of a variable is: $return = lpsolve('is_int', $lp, $column);. The matrix version of this call is: $is_int = lpsolve('is_int', $lp);
$is_int is again an array variable in this case. Also note the get_mat and set_mat routines. In PHP these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by executing script example2.php)

$lp = lpsolve('make_lp', 0, 4);
lpsolve('set_verbose', $lp, IMPORTANT);
$ret = lpsolve('set_obj_fn', $lp, Array(1, 3, 6.24, 0.1));
$ret = lpsolve('add_constraint', $lp, Array(0, 78.26, 0, 2.9), GE, 92.3);
$ret = lpsolve('add_constraint', $lp, Array(0.24, 0, 11.31, 0), LE, 14.8);
$ret = lpsolve('add_constraint', $lp, Array(12.68, 0, 0.08, 0.9), GE, 4);
$ret = lpsolve('set_lowbo', $lp, Array(28.6, 0, 0, 18));
$ret = lpsolve('set_upbo', $lp, Array(Infinite, Infinite, Infinite, 48.98));
$ret = lpsolve('set_col_name', $lp, Array('COLONE', 'COLTWO', 'COLTHREE', 'COLFOUR'));
$ret = lpsolve('set_row_name', $lp, Array('THISROW', 'THATROW', 'LASTROW'));
$ret = lpsolve('write_lp', $lp, 'a.lp');
print_r(lpsolve('get_mat', $lp));
print lpsolve('solve', $lp) . "\n";
print lpsolve('get_objective', $lp) . "\n";
print_r(lpsolve('get_variables', $lp));
print_r(lpsolve('get_constraints', $lp));
lpsolve('delete_lp', $lp);

This gives:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => 0
                    [1] => 78.26
                    [2] => 0
                    [3] => 2.9
                )

            [1] => Array
                (
                    [0] => 0.24
                    [1] => 0
                    [2] => 11.31
                    [3] => 0
                )

            [2] => Array
                (
                    [0] => 12.68
                    [1] => 0
                    [2] => 0.08
                    [3] => 0.9
                )

        )

    [1] => 1
)
0
31.7827586207
Array
(
    [0] => Array
        (
            [0] => 28.6
            [1] => 0
            [2] => 0
            [3] => 31.8275862069
        )

    [1] => 1
)
Array
(
    [0] => Array
        (
            [0] => 92.3
            [1] => 6.864
            [2] => 391.292827586
        )

    [1] => 1
)

Note the usage of Infinite in set_upbo. This stands for 'infinity'. Meaning an infinite upper bound. It is also possible to use -Infinite to express minus infinity. This can for example be used to create a free variable. Infinite is a constant defined by the lpsolve library.

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example. Note that PHP doesn't support much matrix calculations on arrays. We only need a matrix multiplication routine to demonstrate the following. For this the following routine can be used. Include it in the next code to perform the matrixmultiply:

function matrixmultiply($Array1, $Array2) {
        $rows2 = count($Array2);
        if (is_array($Array2[0])) {
            $dim2 = 2;
            $columns2 = count($Array2[0]);
        }
        else {
            $dim2 = 1;
            $columns2 = 1;
        }

        $rows1 = count($Array1);
        if (is_array($Array1[0])) {
            $dim1 = 2;
            $columns1 = count($Array1[0]);
        }
        else {
            $dim1 = 1;
            if ($rows2 == 1)
                $columns1 = 1;
            else {
                $columns1 = $rows1;
                $rows1 = 1;
            }
        }

        for($i=0; $i<$rows1; $i++){
                for($j=0; $j<$columns2; $j++){
                        $a = 0;
                        for($M=0;$M<$columns1;$M++){
                                if ($dim1 == 2)
                                    $b = $Array1[$i][$M];
                                else if ($rows2 == 1)
                                    $b = $Array1[$i];
                                else
                                    $b = $Array1[$M];
                                $c = $Array2[$M];
                                if ($dim2 == 2)
                                    $c = $c[$j];
                                $a = $a + $b * $c;
                        }
                        if ($dim2 == 2)
                            $ArrayMultipli[$i][$j] = $a;
                        else
                            $ArrayMultipli[$i] = $a;
                }
        }
        return $ArrayMultipli;
}

Now do the following calculations:

$lp = lpsolve('make_lp', 0, 4);
lpsolve('set_verbose', $lp, IMPORTANT);
$ret = lpsolve('set_obj_fn', $lp, Array(1, 3, 6.24, 0.1));
$ret = lpsolve('add_constraint', $lp, Array(0, 78.26, 0, 2.9), GE, 92.3);
$ret = lpsolve('add_constraint', $lp, Array(0.24, 0, 11.31, 0), LE, 14.8);
$ret = lpsolve('add_constraint', $lp, Array(12.68, 0, 0.08, 0.9), GE, 4);
$ret = lpsolve('set_lowbo', $lp, Array(28.6, 0, 0, 18));
$ret = lpsolve('set_upbo', $lp, Array(Infinite, Infinite, Infinite, 48.98));
$ret = lpsolve('set_col_name', $lp, Array('COLONE', 'COLTWO', 'COLTHREE', 'COLFOUR'));
$ret = lpsolve('set_row_name', $lp, Array('THISROW', 'THATROW', 'LASTROW'));
$ret = lpsolve('write_lp', $lp, 'a.lp');
lpsolve('solve', $lp);

$A = lpsolve('get_mat', $lp);
$A = $A[0];
print_r($A);
$X = lpsolve('get_variables', $lp);
$X = $X[0];
print_r($X);
$B = matrixmultiply($A, $X);
print_r($B);

$C = lpsolve('get_obj_fn', $lp);
$C = $C[0];
print_r($C);
$X = lpsolve('get_variables', $lp);
$X = $X[0];
$obj = matrixmultiply($C, $X);
print_r($obj);

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector.
This gives:

Array
(
    [0] => Array
        (
            [0] => 0
            [1] => 78.26
            [2] => 0
            [3] => 2.9
        )

    [1] => Array
        (
            [0] => 0.24
            [1] => 0
            [2] => 11.31
            [3] => 0
        )

    [2] => Array
        (
            [0] => 12.68
            [1] => 0
            [2] => 0.08
            [3] => 0.9
        )

)
Array
(
    [0] => 28.6
    [1] => 0
    [2] => 0
    [3] => 31.8275862069
)
Array
(
    [0] => 92.3
    [1] => 6.864
    [2] => 391.292827586
)
Array
(
    [0] => 1
    [1] => 3
    [2] => 6.24
    [3] => 0.0:
)
Array
(
    [0] => 31.7827586207
)

Now take a look at the values of the constraints that lpsolve has found:

print_r(lpsolve('get_constraints', $lp));

That gives:

Array
(
    [0] => Array
        (
            [0] => 92.3
            [1] => 6.864
            [2] => 391.292827586
        )

    [1] => 1
)

Exactly the same as the calculated B vector, as expected.

Also the value of the objective is calculated in $obj. What we have done is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

print lpsolve('get_objective', $lp);

That gives:

31.7827586207

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
$lp=lpsolve('make_lp', 0, 4);
lpsolve('set_verbose', $lp, IMPORTANT);
lpsolve('add_constraint', $lp, Array(0, 78.26, 0, 2.9), GE, 92.3);
lpsolve('add_constraint', $lp, Array(0.24, 0, 11.31, 0), LE, 14.8);
lpsolve('add_constraint', $lp, Array(12.68, 0, 0.08, 0.9), GE, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One can define all the possible constants in PHP as is done in the lpsolve driver and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

$lp=lpsolve('make_lp', 0, 4);
lpsolve('set_verbose', $lp, 'IMPORTANT');
lpsolve('add_constraint', $lp, Array(0, 78.26, 0, 2.9), 'GE', 92.3);
lpsolve('add_constraint', $lp, Array(0.24, 0, 11.31, 0), 'LE', 14.8);
lpsolve('add_constraint', $lp, Array(12.68, 0, 0.08, 0.9), 'GE', 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

lpsolve('set_verbose', $lp, 'blabla');
PHP Fatal error:  lpsolve() [<a href='function.lpsolve'>function.lpsolve</a>]:
BLABLA: Unknown.

lpsolve('set_verbose', $lp, 'GE');
PHP Fatal error:  lpsolve() [<a href='function.lpsolve'>function.lpsolve</a>]:
GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. 'LE', 'GE' and 'EQ' in add_constraint and is_constr_type can also be '<', '<=', '>', '>=', '='. When returned however, 'GE', 'LE', 'EQ' will be used.

Also in the matrix version of calls, string constants are possible. For example:

lpsolve('set_constr_type', $lp, Array('LE', 'EQ', 'GE'));

Some constants can be a combination of multiple constants. For example set_scaling:

lpsolve('set_scaling', $lp, 3+128);

With the string version of constants this can be done as following:

lpsolve('set_scaling', $lp, 'SCALE_MEAN|SCALE_INTEGERS');

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

lpsolve('set_scaling', $lp, 'SCALE_MEAN|SCALE_RANGE');
PHP Fatal error:  lpsolve() [<a href='function.lpsolve'>function.lpsolve</a>]:
SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

echo lpsolve('get_scaling', $lp);
131

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

lpsolve('return_constants', 1);

From now on, all returned constants are returned as string:

echo lpsolve('get_scaling', $lp);
SCALE_MEAN|SCALE_INTEGERS

Also when an array of constants is returned, they are returned as string when return_constants is set:

print_r(lpsolve('get_constr_type', $lp));
Array
(
    [0] => LE
    [1] => EQ
    [2] => GE
)

This for all routines until return_constants is again called with 0:

lpsolve('return_constants', 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

echo lpsolve('return_constants', 1);
1

To get the value without setting it, don't provide the second argument:

echo lpsolve('return_constants');
1

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

php-files

PHP can execute a sequence of statements stored in diskfiles. Such files are called PHP scripts and should have the file type of ".php" as the last part of their filename (extension).

You can put PHP commands in them and execute them at any time. The PHP script can be executed in the command line via the command php -f script.php. The script files contain plain ascii data. a PHP file can also be included by other PHP code. This via the include command. This way it is possible to define routine in one script and execute it in another. All this can be done via command line or via a webserver.

Note that when used under a webserver like apache that these php files must be in a specific location. For example /var/www

The lpsolve PHP distribution contains some example script to demonstrate this.

example1.php

Contains the commands as shown in the first example of this article.

example2.php

Contains the commands as shown in the second example of this article.

example3.php

Contains the commands of a practical example. See further in this article.

example4.php

Contains the commands of a practical example. See further in this article.

example5.php

Contains the commands of a practical example. See further in this article.

example6.php

Contains the commands of a practical example. See further in this article.

lp_solve.php

This script uses the API to create a higher-level function called lp_solve. This function accepts as arguments some matrices and options to create and solve an lp model. The script must first be inserted in the current code via an include command:

include "lp_solve.php";

Use lp_solve(); to see its usage:

LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

include "lp_solve.php";
$ret = lp_solve(Array(-1, 2), Array(Array(2, 1), Array(-4, 4)), Array(5, 5), Array(-1, -1), null, null, Array(1, 2));
print_r($ret);
This gives:
Array
(
    [0] => 3
    [1] => Array
        (
            [0] => 1
            [1] => 2
        )

    [2] => Array
        (
            [0] => 0
            [1] => 0
        )

)

lp_maker.php

This script is analog to the lp_solve script and also uses the API to create a higher-level function called lp_maker. This function accepts as arguments some matrices and options to create an lp model. Note that this scripts only creates a model and returns a handle. The script must first be inserted in the current code via an include command:

include "lp_maker.php";

Use lp_maker(); to see its usage:

LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

include "lp_maker.php";
$lp = lp_maker(Array(-1, 2), Array(Array(2, 1), Array(-4, 4)), Array(5, 5), Array(-1, -1), null, null, Array(1, 2));
print $lp . "\n";
This gives 0.

To solve the model and get the solution:

lpsolve('solve', $lp);
print lpsolve('get_objective', $lp) . "\n";
$ret = lpsolve('get_variables', $lp);
print_r($ret);
This gives:
3
Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 2
        )

    [1] => 1
)

Don't forget to free the handle and its associated memory when you are done:

lpsolve('delete_lp', $lp);

lpdemo.php

Contains several examples to build and solve lp models.

ex.php

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

Source

Now let's put in the other two constraint inequalities.

Source

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.

Source

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. This is done here with an undefined function matrixinverse which is not available in PHP:

$x = matrixmultiply(inverse(Array(Array(1, 1), Array(110, 30))), array(75, 4000));
print_r($x);
With inverse(Array(Array(1, 1), Array(110, 30))) = Array(Array(-0.375, 0.0125), Array(1.375, -0.0125)) that is:
$x = matrixmultiply(Array(Array(-0.375, 0.0125), Array(1.375, -0.0125)), array(75, 4000));
print_r($x);
That gives:
Array
(
    [0] => 21.875
    [1] => 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 = matrixmultiply(Array(143, 60), $x);
print_r($P);

That gives:

Array
(
    [0] => 6315.625
)

That is, $6315.625.

Note that these command are in script example3.php

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

include "lp_maker.php";
$f = Array(143, 60);
$A = Array(Array(120, 210), Array(110, 30), Array(1, 1));
$b = Array(15000, 4000, 75);
$lp = lp_maker($f, $A, $b, Array(-1, -1, -1), null, null, null, 1, 0);
$solvestat = lpsolve('solve', $lp);
$obj = lpsolve('get_objective', $lp);
print $obj . "\n";
$x = lpsolve('get_variables', $lp);
print_r($x);
lpsolve('delete_lp', $lp);
That gives:
6315.625
Array
(
    [0] => Array
        (
            [0] => 21.875
            [1] => 53.125
        )

    [1] => 1
)

Note that these command are in script example4.php

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimensions, but beyond that it is all very theoretical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

include("lp_maker.php");

$f = Array(143, 60, 195);
$A = Array(Array(120, 210, 150.75), Array(110, 30, 125), Array(1, 1, 1));
$b = Array(15000, 4000, 75);
$lp = lp_maker($f, $A, $b, Array(-1, -1, -1), null, null, null, 1, 0);
$solvestat = lpsolve('solve', $lp);
$obj = lpsolve('get_objective', $lp);
print $obj . "\n";
$x = lpsolve('get_variables', $lp);
print_r($x);
lpsolve('delete_lp', $lp);
That gives:
6986.84210526
Array
(
    [0] => Array
        (
            [0] => 0
            [1] => 56.5789473684
            [2] => 18.4210526316
        )

    [1] => 1
)

Note that these command are in script example5.php

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that PHP can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like PHP is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
include("lp_maker.php");

$f = Array(110*1.3, 30*2.0, 125*1.56, 75*1.8, 95*.95, 100*2.25, 50*1.35);
$A = Array(Array(120, 210, 150.75, 115, 186, 140, 85), Array(110, 30, 125, 75, 95, 100, 50), Array(1, 1, 1, 1, 1, 1, 1), Array(1, -1, 0, 0, 0, 0, 0), Array(0, 0, 1, 0, -2, 0, 0), Array(0, 0, 0, -1, 0, -1, 1));
$b = Array(55000, 40000, 400, 0, 0, 0);
$lp = lp_maker($f, $A, $b, Array(-1, -1, -1, -1, -1, -1), Array(10, 10, 10, 10, 20, 20, 20), Array(100, Infinite, 50, Infinite, Infinite, 250, Infinite), null, 1, 0);
$solvestat = lpsolve('solve', $lp);
$obj = lpsolve('get_objective', $lp);
print $obj . "\n";
$x = lpsolve('get_variables', $lp);
print_r($x);
lpsolve('delete_lp', $lp);
That gives:
75398.0434783
Array
(
    [0] => Array
        (
            [0] => 10
            [1] => 10
            [2] => 40
            [3] => 45.652173913
            [4] => 20
            [5] => 250
            [6] => 20
        )

    [1] => 1
)

Note that these command are in script example6.php

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that Infinity is used for variables that have no upper limit.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using PHP:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into PHP format we get:

$f = Array(4, 2, 1);
$A = Array(Array(2, 1, 0), Array(1, 0, 2), Array(1, 1, 1));
$b = Array(1, 2, 1);

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

$l = Array( 0, 0, 0);
$u = Array( 1, 1, 2);

Now lets enter this in PHP:

$f = Array(4, 2, 1);
$A = Array(Array(2, 1, 0), Array(1, 0, 2), Array(1, 1, 1));
$b = Array(1, 2, 1);
$l = Array( 0, 0, 0);
$u = Array( 1, 1, 2);

Now solve the linear program using PHP: Use the commands

include "lp_maker.php";
$lp = lp_maker($f, $A, $b, Array(-1, -1, -1), $l, $u, null, 1, 0);
$solvestat = lpsolve('solve', $lp);
$obj = lpsolve('get_objective', $lp);
print $obj . "\n";
$x = lpsolve('get_variables', $lp);
print_r($x);
lpsolve('delete_lp', $lp);
This gives:
2.5
Array
(
    [0] => Array
        (
            [0] => 0.5
            [1] => 0
            [2] => 0.5
        )

    [1] => 1
)

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the PHP command:

l = null

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -Infinite as lower bounds:

$l = Array(-Infinite, -Infinite, -Infinite);

Solve this and you get a different result:

include "lp_maker.php";
$lp = lp_maker($f, $A, $b, Array(-1, -1, -1), $l, $u, null, 1, 0);
$solvestat = lpsolve('solve', $lp);
$obj = lpsolve('get_objective', $lp);
print $obj . "\n";
$x = lpsolve('get_variables', $lp);
print_r($x);
lpsolve('delete_lp', $lp);
This gives:
2.66666666667
Array
(
    [0] => Array
        (
            [0] => 0.666666666667
            [1] => -0.333333333333
            [2] => 0.666666666667
        )

    [1] => 1
)

Overview of API routines

Note that everwhere where lp is used as argument that this can be a handle (lp) or the models name.

  • add_column, add_columnex
    • return = lpsolve('add_column', lp, [column])
    • return = lpsolve('add_columnex', lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = lpsolve('add_constraint', lp, [row], constr_type, rh)
    • return = lpsolve('add_constraintex', lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = lpsolve('add_SOS', lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in PHP since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = lpsolve('column_in_lp', lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = lpsolve('copy_lp', lp)
    • No special considerations.
  • default_basis
    • lpsolve('default_basis', lp)
    • No special considerations.
  • del_column
    • return = lpsolve('del_column', lp, column)
    • No special considerations.
  • del_constraint
    • return = lpsolve('del_constraint', lp, del_row)
    • No special considerations.
  • delete_lp
    • lpsolve('delete_lp', lp)
    • No special considerations.
  • free_lp
    • lpsolve('free_lp', lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = lpsolve('get_anti_degen', lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = lpsolve('get_basis', lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in PHP. If not provided, then 0 is used.
  • get_basiscrash
    • return = lpsolve('get_basiscrash', lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = lpsolve('get_bb_depthlimit', lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = lpsolve('get_bb_floorfirst', lp)
    • No special considerations.
  • get_bb_rule
    • return = lpsolve('get_bb_rule', lp)
    • No special considerations.
  • get_bounds_tighter
    • return = lpsolve('get_bounds_tighter', lp)
    • No special considerations.
  • get_break_at_value
    • return = lpsolve('get_break_at_value', lp)
    • No special considerations.
  • get_col_name
    • name = lpsolve('get_col_name', lp, column)
    • [names] = lpsolve('get_col_name', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_column get_columnex
    • [column, return] = lpsolve('get_column', lp, col_nr)
    • [column, return] = lpsolve('get_columnex', lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = lpsolve('get_constr_type', lp, row)
    • [constr_type] = lpsolve('get_constr_type', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_constr_value
    • return = lpsolve('get_constr_value', lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = lpsolve('get_constraints', lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = lpsolve('get_dual_solution', lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In PHP, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = lpsolve('get_epsb', lp)
    • No special considerations.
  • get_epsd
    • return = lpsolve('get_epsd', lp)
    • No special considerations.
  • get_epsel
    • return = lpsolve('get_epsel', lp)
    • No special considerations.
  • get_epsint
    • return = lpsolve('get_epsint', lp)
    • No special considerations.
  • get_epsperturb
    • return = lpsolve('get_epsperturb', lp)
    • No special considerations.
  • get_epspivot
    • return = lpsolve('get_epspivot', lp)
    • No special considerations.
  • get_improve
    • return = lpsolve('get_improve', lp)
    • No special considerations.
  • get_infinite
    • return = lpsolve('get_infinite', lp)
    • No special considerations.
  • get_lowbo
    • return = lpsolve('get_lowbo', lp, column)
    • [return] = lpsolve('get_lowbo', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_lp_index
    • return = lpsolve('get_lp_index', lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = lpsolve('get_lp_name', lp)
    • No special considerations.
  • get_mat
    • value = lpsolve('get_mat', lp, row, col)
    • [matrix, return] = lpsolve('get_mat', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix in the first return value. The return code of the call is the second return value.
  • get_max_level
    • return = lpsolve('get_max_level', lp)
    • No special considerations.
  • get_maxpivot
    • return = lpsolve('get_maxpivot', lp)
    • No special considerations.
  • get_mip_gap
    • return = lpsolve('get_mip_gap', lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = lpsolve('get_nameindex', lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = lpsolve('get_Ncolumns', lp)
    • No special considerations.
  • get_negrange
    • return = lpsolve('get_negrange', lp)
    • No special considerations.
  • get_nonzeros
    • return = lpsolve('get_nonzeros', lp)
    • No special considerations.
  • get_Norig_columns
    • return = lpsolve('get_Norig_columns', lp)
    • No special considerations.
  • get_Norig_rows
    • return = lpsolve('get_Norig_rows', lp)
    • No special considerations.
  • get_Nrows
    • return = lpsolve('get_Nrows', lp)
    • No special considerations.
  • get_obj_bound
    • return = lpsolve('get_obj_bound', lp)
    • No special considerations.
  • get_objective
    • return = lpsolve('get_objective', lp)
    • No special considerations.
  • get_orig_index
    • return = lpsolve('get_orig_index', lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = lpsolve('get_origcol_name', lp, column)
    • [names] = lpsolve('get_origcol_name', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_origrow_name
    • name = lpsolve('get_origrow_name', lp, row)
    • [names] = lpsolve('get_origrow_name', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_pivoting
    • return = lpsolve('get_pivoting', lp)
    • No special considerations.
  • get_presolve
    • return = lpsolve('get_presolve', lp)
    • No special considerations.
  • get_presolveloops
    • return = lpsolve('get_presolveloops', lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = lpsolve('get_primal_solution', lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = lpsolve('get_print_sol', lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = lpsolve('get_rh', lp, row)
    • [rh] = lpsolve('get_rh', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_rh_range
    • return = lpsolve('get_rh_range', lp, row)
    • [rh_ranges] = lpsolve('get_rh_range', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_row get_rowex
    • [row, return] = lpsolve('get_row', lp, row_nr)
    • [row, return] = lpsolve('get_rowex', lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In PHP, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = lpsolve('get_row_name', lp, row)
    • [names] = lpsolve('get_row_name', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_scalelimit
    • return = lpsolve('get_scalelimit', lp)
    • No special considerations.
  • get_scaling
    • return = lpsolve('get_scaling', lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = lpsolve('get_sensitivity_obj', lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = lpsolve('get_sensitivity_objex', lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that PHP allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = lpsolve('get_sensitivity_obj', lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, PHP always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = lpsolve('get_sensitivity_rhs', lp)
    • [duals, dualsfrom, dualstill, return] = lpsolve('get_sensitivity_rhsex', lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that PHP allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = lpsolve('get_sensitivity_rhs', lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = lpsolve('get_simplextype', lp)
    • No special considerations.
  • get_solutioncount
    • return = lpsolve('get_solutioncount', lp)
    • No special considerations.
  • get_solutionlimit
    • return = lpsolve('get_solutionlimit', lp)
    • No special considerations.
  • get_status
    • return = lpsolve('get_status', lp)
    • No special considerations.
  • get_statustext
    • return = lpsolve('get_statustext', lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = lpsolve('get_timeout', lp)
    • No special considerations.
  • get_total_iter
    • return = lpsolve('get_total_iter', lp)
    • No special considerations.
  • get_total_nodes
    • return = lpsolve('get_total_nodes', lp)
    • No special considerations.
  • get_upbo
    • return = lpsolve('get_upbo', lp, column)
    • [upbo] = lpsolve('get_upbo', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_var_branch
    • return = lpsolve('get_var_branch', lp, column)
    • [var_branch] = lpsolve('get_var_branch', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_var_dualresult
    • return = lpsolve('get_var_dualresult', lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = lpsolve('get_var_primalresult', lp, index)
    • No special considerations.
  • get_var_priority
    • return = lpsolve('get_var_priority', lp, column)
    • [var_priority] = lpsolve('get_var_priority', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • get_variables
    • [var, return] = lpsolve('get_variables', lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = lpsolve('get_verbose', lp)
    • No special considerations.
  • get_working_objective
    • return = lpsolve('get_working_objective', lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = lpsolve('guess_basis', lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In PHP, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In PHP, there is no unused element in the matrix.
  • has_BFP
    • return = lpsolve('has_BFP', lp)
    • No special considerations.
  • has_XLI
    • return = lpsolve('has_XLI', lp)
    • No special considerations.
  • is_add_rowmode
    • return = lpsolve('is_add_rowmode', lp)
    • No special considerations.
  • is_anti_degen
    • return = lpsolve('is_anti_degen', lp, testmask)
    • No special considerations.
  • is_binary
    • return = lpsolve('is_binary', lp, column)
    • [binary] = lpsolve('is_binary', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • is_break_at_first
    • return = lpsolve('is_break_at_first', lp)
    • No special considerations.
  • is_constr_type
    • return = lpsolve('is_constr_type', lp, row, mask)
    • No special considerations.
  • is_debug
    • return = lpsolve('is_debug', lp)
    • No special considerations.
  • is_feasible
    • return = lpsolve('is_feasible', lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = lpsolve('is_free', lp, column)
    • return = lpsolve('is_unbounded', lp, column)
    • [free] = lpsolve('is_free', lp)
    • [free] = lpsolve('is_unbounded', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • is_infinite
    • return = lpsolve('is_infinite', lp, value)
    • No special considerations.
  • is_int
    • return = lpsolve('is_int', lp, column)
    • [int] = lpsolve('is_int', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • is_integerscaling
    • return = lpsolve('is_integerscaling', lp)
    • No special considerations.
  • is_maxim
    • return = lpsolve('is_maxim', lp)
    • No special considerations.
  • is_nativeBFP
    • return = lpsolve('is_nativeBFP', lp)
    • No special considerations.
  • is_nativeXLI
    • return = lpsolve('is_nativeXLI', lp)
    • No special considerations.
  • is_negative
    • return = lpsolve('is_negative', lp, column)
    • [negative] = lpsolve('is_negative', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • is_piv_mode
    • return = lpsolve('is_piv_mode', lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = lpsolve('is_piv_rule', lp, rule)
    • No special considerations.
  • is_presolve
    • return = lpsolve('is_presolve', lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = lpsolve('is_scalemode', lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = lpsolve('is_scaletype', lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = lpsolve('is_semicont', lp, column)
    • [semicont] = lpsolve('is_semicont', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • is_SOS_var
    • return = lpsolve('is_SOS_var', lp, column)
    • [SOS_var] = lpsolve('is_SOS_var', lp)
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a PHP matrix.
  • is_trace
    • return = lpsolve('is_trace', lp)
    • No special considerations.
  • is_use_names
    • return = lpsolve('is_use_names', lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = lpsolve('lp_solve_version')
    • The lpsolve API routine returns the version information in 4 provided argument variables while the PHP version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = lpsolve('make_lp', rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • lpsolve('print_constraints', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
    • The same information can also be obtained via lpsolve('get_constraints', lp). This shows the result on screen.
  • print_debugdump
    • return = lpsolve('print_debugdump', lp, filename)
    • No special considerations.
  • print_duals
    • lpsolve('print_duals', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
    • The same information can be obtained via lpsolve('get_dual_solution', lp). This shows the result on screen.
  • print_lp
    • lpsolve('print_lp', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
  • print_objective
    • lpsolve('print_objective', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
    • The same information can be obtained via lpsolve('get_objective', lp). This shows the result on screen.
  • print_scales
    • lpsolve('print_scales', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
  • print_solution
    • lpsolve('print_solution', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
    • The same information can also be obtained via lpsolve('get_variables', lp). This shows the result on screen.
  • print_str
    • lpsolve('print_str', lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
  • print_tableau
    • lpsolve('print_tableau', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under PHP (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the lpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows PHP) to the command window of PHP. As such, all reported output can be seen in PHP. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = lpsolve('read_basis', lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = lpsolve('read_freemps', filename {, options})
    • lp_handle = lpsolve('read_freeMPS', filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In PHP it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = lpsolve('read_lp', filename {, verbose {, lp_name}})
    • lp_handle = lpsolve('read_LP', filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In PHP it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ('').
  • read_mps, read_MPS
    • lp_handle = lpsolve('read_mps', filename {, options})
    • lp_handle = lpsolve('read_MPS', filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In PHP it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = lpsolve('read_params', lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = lpsolve('read_XLI', xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, '' (NULL) is taken. '' is taken as NULL.
    • options is optional. When not provided, '' is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • lpsolve('set_basisvar', lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = lpsolve('set_add_rowmode', lp, turnon)
    • No special considerations.
  • set_anti_degen
    • lpsolve('set_anti_degen', lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = lpsolve('set_basis', lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In PHP, there is no unused element in the matrix.
  • set_basiscrash
    • lpsolve('set_basiscrash', lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • lpsolve('set_bb_depthlimit', lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • lpsolve('set_bb_floorfirst', lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • lpsolve('set_bb_rule', lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = lpsolve('set_BFP', lp, filename)
    • No special considerations.
  • set_binary
    • return = lpsolve('set_binary', lp, column, must_be_bin)
    • return = lpsolve('set_binary', lp, [must_be_bin])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = lpsolve('set_bounds', lp, column, lower, upper)
    • return = lpsolve('set_bounds', lp, [lower], [upper])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • lpsolve('set_bounds_tighter', lp, tighten)
    • No special considerations.
  • set_break_at_first
    • lpsolve('set_break_at_first', lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • lpsolve('set_break_at_value', lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = lpsolve('set_col_name', lp, column, name)
    • return = lpsolve('set_col_name', lp, [names])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_column, set_columnex
    • return = lpsolve('set_column', lp, col_no, [column])
    • return = lpsolve('set_columnex', lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = lpsolve('set_constr_type', lp, row, con_type)
    • return = lpsolve('set_constr_type', lp, [con_type])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • lpsolve('set_debug', lp, debug)
    • No special considerations.
  • set_epsb
    • lpsolve('set_epsb', lp, epsb)
    • No special considerations.
  • set_epsd
    • lpsolve('set_epsd', lp, epsd)
    • No special considerations.
  • set_epsel
    • lpsolve('set_epsel', lp, epsel)
    • No special considerations.
  • set_epsint
    • lpsolve('set_epsint', lp, epsint)
    • No special considerations.
  • set_epslevel
    • lpsolve('set_epslevel', lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • lpsolve('set_epsperturb', lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • lpsolve('set_epspivot', lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = lpsolve('set_free', lp, column)
    • return = lpsolve('set_unbounded', lp, column)
    • No special considerations.
  • set_improve
    • lpsolve('set_improve', lp, improve)
    • No special considerations.
  • set_infinite
    • lpsolve('set_infinite', lp, infinite)
    • No special considerations.
  • set_int
    • return = lpsolve('set_int', lp, column, must_be_int)
    • return = lpsolve('set_int', lp, [must_be_int])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = lpsolve('set_lowbo', lp, column, value)
    • return = lpsolve('set_lowbo', lp, [values])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = lpsolve('set_lp_name', lp, name)
    • In PHP, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = lpsolve('set_mat', lp, row, column, value)
    • return = lpsolve('set_mat', lp, [matrix])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. Consider using a PHP sparse matrix for maximum performance and least memory usage. The matrix must be two-dimensional.
  • set_maxim
    • lpsolve('set_maxim', lp)
    • No special considerations.
  • set_maxpivot
    • lpsolve('set_maxpivot', max_num_inv)
    • No special considerations.
  • set_minim
    • lpsolve('set_minim', lp)
    • No special considerations.
  • set_mip_gap
    • lpsolve('set_mip_gap', lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • lpsolve('set_negrange', negrange)
    • No special considerations.
  • set_obj
    • return = lpsolve('set_obj', lp, column, value)
    • return = lpsolve('set_obj', lp, [values])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • lpsolve('set_obj_bound', lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = lpsolve('set_obj_fn', lp, [row])
    • return = lpsolve('set_obj_fnex', lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In PHP, there is no unused element in the matrix.
  • set_outputfile
    • return = lpsolve('set_outputfile', lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In PHP under Windows, output to stdout it not shown. However it results in closing the file. Use '' to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • lpsolve('set_pivoting', lp, pivoting)
    • No special considerations.
  • set_preferdual
    • lpsolve('set_preferdual', lp, dodual)
    • No special considerations.
  • set_presolve
    • lpsolve('set_presolve', lp, do_presolve {, maxloops})
    • The maxloops argument is optional in PHP. If not provided, then infinite is used.
  • set_print_sol
    • lpsolve('set_print_sol', lp, print_sol)
    • No special considerations.
  • set_rh
    • return = lpsolve('set_rh', lp, row, value)
    • return = lpsolve('set_rh', lp, [values])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = lpsolve('set_rh_range', lp, row, deltavalue)
    • return = lpsolve('set_rh_range', lp, [deltavalues])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • lpsolve('set_rh_vec', lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In PHP, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = lpsolve('set_row', lp, row_no, [row])
    • return = lpsolve('set_rowex', lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In PHP, there is no unused element in the matrix.
  • set_row_name
    • return = lpsolve('set_row_name', lp, row, name)
    • return = lpsolve('set_row_name', lp, [names])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_scalelimit
    • lpsolve('set_scalelimit', lp, scalelimit)
    • No special considerations.
  • set_scaling
    • lpsolve('set_scaling', lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = lpsolve('set_semicont', lp, column, must_be_sc)
    • return = lpsolve('set_semicont', lp, [must_be_sc])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • lpsolve('set_sense', lp, maximize)
    • No special considerations.
  • set_simplextype
    • lpsolve('set_simplextype', lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • lpsolve('set_solutionlimit', lp, simplextype)
    • No special considerations.
  • set_timeout
    • lpsolve('set_timeout', lp, sectimeout)
    • No special considerations.
  • set_trace
    • lpsolve('set_trace', lp, trace)
    • No special considerations.
  • set_upbo
    • return = lpsolve('set_upbo', lp, column, value)
    • return = lpsolve('set_upbo', lp, [values])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • lpsolve('set_use_names', lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = lpsolve('set_var_branch', lp, column, branch_mode)
    • return = lpsolve('set_var_branch', lp, [branch_mode])
    • In PHP, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = lpsolve('set_var_weights', lp, [weights])
    • No special considerations.
  • set_verbose
    • lpsolve('set_verbose', lp, verbose)
    • No special considerations.
  • set_XLI
    • return = lpsolve('set_XLI', lp, filename)
    • No special considerations.
  • solve
    • result = lpsolve('solve', lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = lpsolve('time_elapsed', lp)
    • No special considerations.
  • unscale
    • lpsolve('unscale', lp)
    • No special considerations.
  • write_basis
    • lpsolve('write_basis', lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = lpsolve('write_freemps', lp, filename)
    • return = lpsolve('write_freeMPS', lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In PHP it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = lpsolve('write_lp', lp, filename)
    • return = lpsolve('write_LP', lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In PHP it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = lpsolve('write_mps', lp, filename)
    • return = lpsolve('write_MPS', lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In PHP it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = lpsolve('write_XLI', lp, filename {, options {, results}})
    • No special considerations.

Extra PHP routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = lpsolve('get_col_names', lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = lpsolve('get_constr_types', lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = lpsolve('get_int', lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = lpsolve('get_no_cols', lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = lpsolve('get_no_rows', lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = lpsolve('get_objective_name', lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = lpsolve('get_obj_fn', lp)
    [row_vec, return] = lpsolve('get_obj_fun', lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = lpsolve('get_problem_name', lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = lpsolve('get_reduced_costs', lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = lpsolve('get_row_names', lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = lpsolve('get_solution', lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = lpsolve('mat_elm', lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = lpsolve('print_handle')
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = lpsolve('read_lp_file', filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = lpsolve('get_handle', lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = lpsolve('return_constants'[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the lpsolve driver

The lpsolve PHP driver is called php_phplpsolve55.dll (windows) and phplpsolve55.so (Unix/Linux).
This driver is an interface to the lpsolve55.dll (windows) and liblpsolve55.so (Unix/Linux) lpsolve shared library that contains the implementation of lp_solve. lpsolve55.dll/liblpsolve55.so is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). The lpsolve PHP driver is just a wrapper between PHP and lp_solve to translate the input/output to/from PHP and the lp_solve library.

The lpsolve PHP driver is written in C. To compile this code a C compiler is needed. Under Unix, this is the standard C compiler (c/gcc) and under windows it is the Microsoft compiler from Visual Studio .NET.

Windows:

First of all, the PHP sources are needed. These must be obtained from http://www.php.net
Extract the sources to a folder. In this example this is f:\php-5.2.6
Secondly, win32build.zip is needed. Note that is looks like this is only the case if method 1) is used. Method 2) works without this folder. This archive should be on that site also, but apparently it is deleted from there. It was however found on following location: http://viewcvs.php.net/viewvc.cgi/phpweb/extra/?hideattic=0
Extract the sources to \win32build. In this example this is f:\win32build

Then there are two ways to compile php_phplpsolve.dll:

1) This is somewhat the standard way, but not the easiest.
First of all, lpsolve must be under the php\ext folder. For example \php-5.2.6\ext\lpsolve
Secondly, a file config.w32 is needed. It is provided with the lpsolve PHP distribution.
To build, execute the following commands in a DOS prompt where the vcvars32.bat file of the Microsoft Visual C compiler:

F:\php-5.2.6>buildconf.bat
F:\php-5.2.6>cscript /nologo configure.js --without-xml --without-wddx --without-simplexml --without-dom --without-libxml --disable-zlib --without-sqlite --disable-odbc --disable-cgi --enable-cli --without-iconv --enable-phplpsolve55=shared --with-phplpsolve55path="z:\lp_solve_5.5"
F:\php-5.2.6>nmake php_phplpsolve55.dll

Each of these commands give some messages. Also note that in the cscript command, the path to lp_solve_5.5 must be provided. In this example this is z:\lp_solve_5.5

If all is successful, php_phplpsolve.dll is made in \php-5.2.6\Release_TS

2) An easier way is using the batch files cvc6.bat or cvc8NOmsvcrt80.bat
cvc6.bat can be used for Microsoft Visual compiler version 6 and cvc8NOmsvcrt80.bat for Microsoft Visual compilers from .NET.
In this case, the lpsolve PHP files do not have to be located under \php-5.2.6\ext. Instead they can be under \lp_solve_5.5\extra\PHP\lpsolve as in the distribution.
First edit cvc6.bat or cvc8NOmsvcrt80.bat
Two commands here must be revised:

set lp_solve=..\..
set php=F:\php-5.2.6

Normally the first one will be ok. The second one must be changed to the path where the PHP sources are located. Here F:\php-5.2.6

To build, execute the following commands in a DOS prompt where the vcvars32.bat file of the Microsoft Visual C compiler:

Z:\lp_solve_5.5\extra\PHP>cvc6.bat
or
Z:\lp_solve_5.5\extra\PHP>cvc8NOmsvcrt80.bat

Unix/Linux:

Go to the lpsolve PHP directory and enter the following commands:

$ phpize
$ ./configure --enable-maintainer-zts --with-phplpsolve55=../..
$ make

Note the ../.. path in the second command. That is the location to lp_solve_5.5 and that is normally 2 directories down.

After this is done, phplpsolve55.so is build in directory modules.

For both windows and unix/linux, don't forget to adapt php.ini as described above and possibly restart the webserver.

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python Using lpsolve from Sage, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./Presolve.htm000666 000000 000000 00000030573 13772705352 011721 0ustar00000000 000000 Presolve

Presolve

Presolve is a preprocess of the lp-model. It looks for ways to simplify it. For example it can delete unused variables and restrictions. Substitute fixed variable values by a constant and so on. The result is a new model that is less complex than the original model and likely solves faster.
The result of presolve can be that there are less variables and/or constraints in the presolved model.

Presolve is not active by default. It must specifically being enabled via the API call set_presolve.

Different presolve options are possible.
The more are chosen, the more presolve can be done and the model could me made simpler thus solved faster, but also presolve takes more time. Presolve will most of the time result in a netto time that is faster than without, but can also result in a slower time. So it is up to the user to decide when and which presolve to use on specific models. There is no general presolve option applicable for all models.

A simple example:

max: x1 + x2 + x3;

r1: x2 = 2;
r2: x1 + x2 <= 6;
r3: x1 - 2 x3 >= 2;
r4: x2 + 3 x3 <= 5;

Row r1 is a constraint on one variable. Presolve can detect this and convert it to a bound on that variable. For this, presolve of rows must be activated:

lp_solve model.lp -wlp con -S1 -wafter -presolverow
/* Objective function */
max: +x1 +x2 +x3;

/* Constraints */
r2: +x1 +x2 <= 6;
r3: +x1 -2 x3 >= 2;
r4: +x2 +3 x3 <= 5;

/* Variable bounds */
x2 = 2;

And even this model can be presolved further.
When presolve of columns is active, variables can be eliminated from the model.

lp_solve model.lp -wlp con -S1 -wafter -presolverow -presolvecol
/* Objective function */
max: +x1 +x3 +2;

/* Constraints */
r3: +x1 -2 x3 >= 2;

/* Variable bounds */
x1 <= 4;
x3 <= 1;

Note the -wafter option. If this option is not specified, the original model is printed. The reason for this is the moment that write_lp is called. The effect of presolve happens when a solve is done. If write_lp is called before solve then the original model is given. If called after solve then the presolved model is.

As previously stated, presolve can result in removal of variables and/or constraints. For some models, presolve can even find the solution of the model.

For constraints that are removed, all information of them are lost. Presolve has removed them from the matrix and cannot retrieve any information of them anymore. The number of rows is decreased by the number of constraints deleted. get_Nrows does not return the original number of rows, but the number of rows in the new model.

Variables that are removed from the matrix result in less columns in the model. get_Ncolumns does not return the original number of columns, but the number of columns in the new model.

However the information of the removed variables is not lost. Only variables that result in a fixed value are removed by presolve and their value is remembered at that time.

Example in C:

#include <stdio.h>

#include "lp_lib.h"

int main(void)
{
# if defined ERROR
#  undef ERROR
# endif
# define ERROR() { fprintf(stderr, "Error\n"); exit(1); }
  lprec *lp;

  if ((lp=make_lp(0, 3)) == NULL)
    ERROR();
  set_col_name(lp, 1, "x1");
  set_col_name(lp, 2, "x2");
  set_col_name(lp, 3, "x3");
  set_maxim(lp);
  if (!str_add_constraint(lp, "0 1 0", EQ, 2))
    ERROR();
  set_row_name(lp, 1, "R1");
  if (!str_add_constraint(lp, "1 1 0", LE, 6))
    ERROR();
  set_row_name(lp, 2, "R2");
  if (!str_add_constraint(lp, "1 0 -2", GE, 2))
    ERROR();
  set_row_name(lp, 3, "R3");
  if (!str_add_constraint(lp, "0 1 3", LE, 5))
    ERROR();
  set_row_name(lp, 4, "R4");
  if (!str_set_obj_fn(lp, "1 1 1"))
    ERROR();

  write_LP(lp, stdout);
  set_presolve(lp, PRESOLVE_ROWS + PRESOLVE_COLS, 0);
  solve(lp);
  print_objective(lp);
  print_solution(lp, 1);
  print_constraints(lp, 1);

  print_duals(lp);

  write_LP(lp, stdout);

  delete_lp(lp);

}

This gives:

/* Objective function */
max: +x1 +x2 +x3;

/* Constraints */
R1: +x2 = 2;
R2: +x1 +x2 <= 6;
R3: +x1 -2 x3 >= 2;
R4: +x2 +3 x3 <= 5;

Model name:  '' - run #1
Objective:   Maximize(R0)

SUBMITTED
Model size:        4 constraints,       3 variables,            7 non-zeros.
Sets:                                   0 GUB,                  0 SOS.

Presolve O:1 -> Reduced rows:    3, cols:    1 --- changed bnds:    4, Ab:    0.

PRESOLVE             Elimination loops performed.......... O3:M3:I5
                   1 empty or fixed variables............. REMOVED.
                   3 empty or redundant constraints....... REMOVED.
                   4 bounds............................... TIGHTENED.
                     [           +2 < Z < +7           ]

REDUCED
Model size:        1 constraints,       2 variables,            2 non-zeros.
Sets:                                   0 GUB,                  0 SOS.
Row-types:         0 LE,                1 GE,                   0 EQ.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
The primal and dual simplex pricing strategy set to 'Devex'.


Optimal solution                   7 after          0 iter.

Excellent numeric accuracy ||*|| = 0

 MEMO: lp_solve version 5.5.2.11 for 32 bit OS, with 64 bit REAL variables.
      In the total iteration count 0, 0 (100.0%) were bound flips.
      There were 0 refactorizations, 0 triggered by time and 0 by density.
       ... on average 0.0 major pivots per refactorization.
      The largest [etaPFI v1.4] fact(B) had 0 NZ entries, 0.0x largest basis.
      The constraint matrix inf-norm is 2, with a dynamic range of 2.
      Time to load data was 0.235 seconds, presolve used 0.140 seconds,
       ... 0.047 seconds in simplex solver, in total 0.422 seconds.

Value of objective function: 7

Actual values of the variables:
x1                              4
x2                              2
x3                              1

Actual values of the constraints:
R3                              2

Objective function limits:
                                 From            Till       FromValue
x1                                  0          1e+030         -1e+030
x3                                  0          1e+030         -1e+030

Dual values with from - till limits:
                           Dual value            From            Till
R3                                  0         -1e+030          1e+030
x1                                  1               4          1e+030
x3                                  1         -1e+030               1
/* Objective function */
max: +x1 +x3 +2;

/* Constraints */
R3: +x1 -2 x3 >= 2;

/* Variable bounds */
x1 <= 4;
x3 <= 1;

The result only shows values of contraint R3, the one that is kept. The information of the removed constraints is no longer there.
The variable result however is not lost. x2 is removed by presolve, but its value is still known. On the other hand, note also that the variable does not appear in the sensitivity result.

Almost all API calls return information of the presolved model. get_Nrows and get_Ncolumns return the number of rows and columns of the presolved model. To know the original values, get_Norig_rows and get_Norig_columns must be used:

printf("get_Nrows: %d\n", get_Nrows(lp));
printf("get_Norig_rows: %d\n", get_Norig_rows(lp));
printf("get_Ncolumns: %d\n", get_Ncolumns(lp));
printf("get_Norig_columns: %d\n", get_Norig_columns(lp));

get_Nrows: 1
get_Norig_rows: 4
get_Ncolumns: 2
get_Norig_columns: 3

To retrieve the variable data of all variables, including the presolved variables, API call get_var_primalresult must be used. This is the only call available to get all information.
The following code prints the values of all variables:

int column, Nrows, Ncolumns;

Ncolumns = get_Norig_columns(lp);
Nrows = get_Norig_rows(lp);
for (column = 1; column <= Ncolumns; column++) {
  printf("x%d: %f\n", column, get_var_primalresult(lp, Nrows + column));
}

With result:

x1: 4.000000
x2: 2.000000
x3: 1.000000

get_var_primalresult also returns information about rows.
The following code prints the results of all rows:

int row, Nrows;

Nrows = get_Norig_rows(lp);

for (row = 1; row <= Nrows; row++) {
  printf("R%d: %f\n", row, get_var_primalresult(lp, row));
}

With result:

R1: 0.000000
R2: 0.000000
R3: 2.000000
R4: 0.000000

You could think here that a result for all original rows are returned, but this is not the case. Only the result of constraints that were kept in the model are given. The other rows will return 0!

There is also a possibility to know which rows and columns are removed from the model. get_orig_index can be used for that.
The following code demonstrates it:

int row, Nrows;
int column, Ncolumns;

Ncolumns = get_Ncolumns(lp);
Nrows = get_Nrows(lp);

for (row = 1; row <= Nrows; row++)
  printf("row %d was row R%d\n", row, get_orig_index(lp, row));

for (column = 1; column <= Ncolumns; column++)
  printf("column %d was column x%d\n", column, get_orig_index(lp, Nrows + column));

With result:

row 1 was row R3
column 1 was column x1
column 2 was column x3

So from this it can be determined that only row R3 and columns x1 and x3 are kept in the model. The others are removed by presolve.

Again note that all other API calls return information about the presolved model. So for example get_ptr_primal_solution must be used like this:

int row, Nrows;
int column, Ncolumns;
double *pv;

get_ptr_primal_solution(lp, &pv);

Ncolumns = get_Ncolumns(lp);
Nrows = get_Nrows(lp);

for (row = 1; row <= Nrows; row++)
  printf("row %d: %f\n", row, pv[row]);

for (column = 1; column <= Ncolumns; column++)
  printf("column %d: %f\n", column, pv[Nrows + column]);

With result:

row 1: 2.000000
column 1: 4.000000
column 2: 1.000000

Row and column names of the original model can be obtained via get_origrow_name and get_origcol_name:

int row, Nrows;
int column, Ncolumns;

Ncolumns = get_Norig_columns(lp);
Nrows = get_Norig_rows(lp);

for (row = 1; row <= Nrows; row++)
 printf("row %d: %s\n", row, get_origrow_name(lp, row));

for (column = 1; column <= Ncolumns; column++)
 printf("column %d: %s\n", column, get_origcol_name(lp, column));

With result:

row 1: R1
row 2: R2
row 3: R3
row 4: R4
column 1: x1
column 2: x2
column 3: x3

Row and column names of the presolved model can be obtained via get_row_name and get_col_name:

int row, Nrows;
int column, Ncolumns;

Ncolumns = get_Ncolumns(lp);
Nrows = get_Nrows(lp);

for (row = 1; row <= Nrows; row++)
 printf("row %d: %s\n", row, get_row_name(lp, row));

for (column = 1; column <= Ncolumns; column++)
 printf("column %d: %s\n", column, get_col_name(lp, column));

With result:

row 1: R3
column 1: x1
column 2: x3
./print_constraints.htm000666 000000 000000 00000006014 10237125126 013662 0ustar00000000 000000 print_constraints

print_constraints

Prints the values of the constraints of the lp.

void print_constraints(lprec *lp, int columns);

Return Value

print_constraints has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

columns

Number of columns to print solution.

Remarks

The print_constraints function prints the values of the constraints of the lp. This can only be done after a successful solve.
This function is meant for debugging purposes. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  print_constraints(lp, 1);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_constraints, get_constr_value, print_lp, print_objective, print_solution, print_duals, print_scales, print_tableau, print_str, set_outputstream, set_outputfile, print_debugdump

./print_debugdump.htm000666 000000 000000 00000005464 10237106220 013271 0ustar00000000 000000 print_debugdump

print_debugdump

Do a generic readable data dump of key lp_solve model variables; principally for run difference and debugging purposes.

unsigned char print_debugdump(lprec *lp, char *filename);

Return Value

print_debugdump returns TRUE if data could be written, else FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The print_debugdump function creates a generic readable data dump of key lp_solve model variables; principally for run difference and debugging purposes
This function is meant for debugging purposes.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  print_debugdump(lp, "debug.txt"); /* dump to file debug.txt in current directory */

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, print_lp, print_objective, print_constraints, print_duals, print_scales, print_tableau, print_str

./print_duals.htm000666 000000 000000 00000006150 10237106220 012416 0ustar00000000 000000 print_duals

print_duals

Prints the values of the duals of the lp.

void print_duals(lprec *lp);

Return Value

print_duals has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The print_duals function prints the values of the duals of the lp. This can only be done after a successful solve.
This function is meant for debugging purposes. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  print_duals(lp, 1);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex, print_lp, print_objective, print_solution, print_constraints, print_scales, print_tableau, print_str, set_outputstream, set_outputfile, print_debugdump

./print_lp.htm000666 000000 000000 00000005372 10237106220 011726 0ustar00000000 000000 print_lp

print_lp

Prints the lp model.

void print_lp(lprec *lp);

Return Value

print_lp has no return value. Note that row entry mode must be off, else this function fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The print_lp function prints the lp model.
This function is meant for debugging purposes. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  print_lp(lp);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, print_objective, print_solution, print_constraints, print_duals, print_scales, print_tableau, print_str, set_outputstream, set_outputfile, print_debugdump

./print_objective.htm000666 000000 000000 00000005452 10237106220 013264 0ustar00000000 000000 print_objective

print_objective

Prints the objective value of the lp.

void print_objective(lprec *lp);

Return Value

print_objective has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The print_objective function prints the objective value of the lp. This can only be done after a successful solve.
This function is meant for debugging purposes. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  print_objective(lp);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_objective, print_lp, print_solution, print_constraints, print_duals, print_scales, print_tableau, print_str, set_outputstream, set_outputfile, print_debugdump

./print_scales.htm000666 000000 000000 00000005565 10237106220 012571 0ustar00000000 000000 print_scales

print_scales

Prints the scales of the lp.

void print_scales(lprec *lp);

Return Value

print_scales has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The print_scales function prints the scales of the lp. This can only be done after a successful solve. It will only output something when the model is scaled.
This function is meant for debugging purposes. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_scaling(lp, CURTISREIDSCALE);

  solve(lp);

  print_scales(lp);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, print_lp, print_objective, print_solution, print_constraints, print_duals, print_tableau, print_str, set_outputstream, set_outputfile, set_scaling, print_debugdump

./print_solution.htm000666 000000 000000 00000005725 10237106220 013171 0ustar00000000 000000 print_solution

print_solution

Prints the solution (variables) of the lp.

void print_solution(lprec *lp, int columns);

Return Value

print_solution has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

columns

Number of columns to print solution.

Remarks

The print_solution function prints the solution (variables) of the lp. This can only be done after a successful solve.
This function is meant for debugging purposes. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  print_solution(lp, 1);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_variables, get_ptr_variables, print_lp, print_objective, print_constraints, print_duals, print_scales, print_tableau, print_str, set_outputstream, set_outputfile, print_debugdump

./print_str.htm000666 000000 000000 00000005344 10255022632 012126 0ustar00000000 000000 print_str

print_str

Prints a string.

void print_str(lprec *lp, char *str);

Return Value

print_str has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

str

The string to print

Remarks

The print_str function prints a string. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.
This function can be useful for debugging/demo purposes.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  print_str(lp, "We are here\n");

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, print_objective, print_solution, print_constraints, print_duals, print_scales, print_tableau, set_outputstream, set_outputfile, print_debugdump

./print_tableau.htm000666 000000 000000 00000005304 10461421734 012734 0ustar00000000 000000 print_tableau

print_tableau

Prints the tableau.

void print_tableau(lprec *lp);

Return Value

print_tableau has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The print_tableau function prints the tableau. This function only works after a successful solve
This function is meant for debugging purposes. By default, the output is stdout. However this can be changed via a call to set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  print_tableau(lp);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, print_objective, print_solution, print_constraints, print_duals, print_scales, print_str, set_outputstream, set_outputfile, print_debugdump

./put_abortfunc.htm000666 000000 000000 00000006132 10310771020 012743 0ustar00000000 000000 put_abortfunc

put_abortfunc

Sets an abort routine.

void put_abortfunc(lprec *lp, lphandle_intfunc newctrlc, void *ctrlchandle);

Return Value

put_abortfunc has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

newctrlc

The abort routine.

typedef int (__WINAPI lphandle_intfunc)(lprec *lp, void *userhandle);

Note the __WINAPI attribute. This is important under Windows. It ensures __stdcall calling convention which is required.

ctrlchandle

A parameter that will be provided to the abort routine.

Remarks

The put_abortfunc function sets an abort routine.
When set, the abort routine is called regularly. The user can do whatever he wants in this routine. For example check if the user pressed abort. The return value of this routine must be FALSE (0) or TRUE (1). If TRUE (1), then lp_solve aborts the solver and returns with an appropriate code. The abort routine can be cleared by specifying NULL as abort routine.
The default is no abort routine (NULL).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int __WINAPI abortfunction(lprec *lp, void *userhandle)
{
 int doabort = FALSE;

 /* do something */

 return(doabort);
}

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  put_abortfunc(lp, abortfunction, NULL);

  solve(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, put_logfunc

./put_bb_branchfunc.htm000666 000000 000000 00000007037 10311020222 013531 0ustar00000000 000000 put_bb_branchfunc

put_bb_branchfunc

Specifies a user function to select a B&B branching, given the column to branch on.

void put_bb_branchfunc(lprec *lp, lphandleint_intfunc newbranch, void *bb_branchhandle);

Return Value

put_bb_branchfunc has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

newbranch

The branch routine.

typedef int (__WINAPI lphandleint_intfunc)(lprec *lp, void *bb_branchhandle, int column);

The routine must return TRUE if first the floor branch must be taken and FALSE if first the ceiling branch must be taken for the specified column.
Note the __WINAPI attribute. This is important under Windows. It ensures __stdcall calling convention which is required.

bb_branchhandle

A parameter that will be provided to the branch routine.

Remarks

Specifies a user function to select a B&B branching, given the column to branch on. With this function you can specify which branch must be taken first in the B&B algorithm. The floor or the ceiling. This overrules the setting of set_bb_floorfirst.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int __WINAPI branchfunction(lprec *lp, void *bb_branchhandle, int column)
{
 int branch;

 /* set branch to TRUE or FALSE to specify to branch first on the floor or ceiling branch */

 return(branch);
}

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  put_bb_branchfunc(lp, branchfunction, NULL);

  solve(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_bb_floorfirst, get_bb_floorfirst, set_var_branch, get_var_branch, set_var_weights, get_var_priority

./put_bb_nodefunc.htm000666 000000 000000 00000006704 10311023150 013224 0ustar00000000 000000 put_bb_nodefunc

put_bb_nodefunc

Allows to set a user function that specifies which non-integer variable to select next to make integer in the B&B solve.

void put_bb_nodefunc(lprec *lp, lphandleint_intfunc newnode, void *bbnodehandle);

Return Value

put_bb_nodefunc has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

newnode

The node selection routine.

typedef int (__WINAPI lphandleint_intfunc)(lprec *lp, void *bb_nodehandle, int vartype);

The routine must return the node (column number) to make integer. vartype is at this moment always equal to BB_INT (1).
When 0 is returned then it indicates that all variables are integer.
When a negative value is returned, lp_solve will determine the next variable to make integer as if the routine is not set.
Note the __WINAPI attribute. This is important under Windows. It ensures __stdcall calling convention which is required.

bb_nodehandle

A parameter that will be provided to the node selection routine.

Remarks

Allows to set a user function that specifies which non-integer variable to select next to make integer in the B&B solve. Via this routine the user can implement his own rule to select the next non-integer variable to make integer. This overrules the setting of set_bb_rule.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int __WINAPI nodefunction(lprec *lp, void *bb_nodehandle, int vartype)
{
 int node = -1;

 /* determine node to make integer */

 return(node);
}

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  put_bb_nodefunc(lp, nodefunction, NULL);

  solve(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_bb_rule

./put_logfunc.htm000666 000000 000000 00000006243 10255022756 012435 0ustar00000000 000000 put_logfunc

put_logfunc

Sets a log routine.

void put_logfunc(lprec *lp, lphandlestr_func newlog, void *loghandle);

Return Value

put_logfunc has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

newlog

The log routine.

typedef void (__WINAPI lphandlestr_func)(lprec *lp, void *userhandle, char *buf);
Note the __WINAPI attribute. This is important under Windows. It ensures __stdcall calling convention which is required.

loghandle

A parameter that will be provided to the log routine.

Remarks

The put_logfunc function sets a log routine.
When set, the log routine is called when lp_solve has someting to report. The return value of this routine should be 0. The log routine can be cleared by specifying NULL as log routine.
This function is called at the same time as something is written to file set via set_outputstream, set_outputfile.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

void __WINAPI logfunction(lprec *lp, void *userhandle, char *buf)
{

 /* do something with buf (the message) */

}

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  put_logfunc(lp, logfunction, NULL);
  set_verbose(lp, FULL);

  del_column(lp, 1); /* Will generate an error because column 1 does not exist */
                     /* Note that del_column returns FALSE (0) to indicate an error */
  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, put_abortfunc

./put_msgfunc.htm000666 000000 000000 00000011641 13555462674 012455 0ustar00000000 000000 put_msgfunc

put_msgfunc

Sets a message routine.

void put_msgfunc(lprec *lp, lphandleint_func newmsg, void *msghandle, int mask);

Return Value

put_msgfunc has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

newmsg

The message routine.

typedef void (__WINAPI lphandleint_func)(lprec *lp, void *userhandle, int message);

Note the __WINAPI attribute. This is important under Windows. It ensures __stdcall calling convention which is required.

msghandle

A parameter that will be provided to the message routine.

mask

Any combination of the following values:

MSG_PRESOLVE (1) Presolve done.
MSG_ITERATION (2)
MSG_INVERT (4)
MSG_LPFEASIBLE (8) Feasible solution found.
MSG_LPOPTIMAL (16) Real optimal solution found. Only fired when there are integer variables at the start of B&B
MSG_LPEQUAL (32)
MSG_LPBETTER (64)
MSG_MILPFEASIBLE (128) First MILPsolution found. Only fired when there are integer variables during B&B
MSG_MILPEQUAL (256) Equal MILP solution found. Only fired when there are integer variables during B&B
MSG_MILPBETTER (512) Better MILPsolution found. Only fired when there are integer variables during B&B
MSG_MILPSTRATEGY (1024)
MSG_MILPOPTIMAL (2048)
MSG_PERFORMANCE (4096)
MSG_INITPSEUDOCOST (8192)

Remarks

The put_msgfunc function sets a message routine. This routine is called when a situation specified in mask occurs. Note that this routine is called while solving the model. This can be useful to follow the solving progress.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

void __WINAPI msgfunction(lprec *lp, void *userhandle, int msg)
{
 switch(msg) {
 case MSG_LPFEASIBLE:
  printf("Feasible solution found\n");
  break;
 case MSG_MILPFEASIBLE:
  printf("Integer feasible solution found\n");
  break;
 case MSG_MILPBETTER:
  printf("Better integer feasible solution found\n");
  break;
 }
}

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  put_msgfunc(lp, msgfunction, NULL, MSG_LPFEASIBLE | MSG_MILPFEASIBLE | MSG_MILPBETTER);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, put_abortfunc

./Python.htm000666 000000 000000 00000372376 13772705352 011415 0ustar00000000 000000 Using lpsolve from Python

Using lpsolve from Python

Python?

Python is an interpreted, interactive, object-oriented programming language. It is often compared to Tcl, Perl, Scheme or Java.

Python combines remarkable power with very clear syntax. It has modules, classes, exceptions, very high level dynamic data types, and dynamic typing. There are interfaces to many system calls and libraries, as well as to various windowing systems (X11, Motif, Tk, Mac, MFC, wxWidgets). New built-in modules are easily written in C or C++. Python is also usable as an extension language for applications that need a programmable interface.

The Python implementation is portable: it runs on many brands of UNIX, on Windows, OS/2, Mac, Amiga, and many other platforms.

Some of Python's notable features:

  • Python uses an elegant syntax for readable programs.
  • Python is an agile language that makes it easy to get your program working. This makes Python an ideal language for prototype development and other ad-hoc programming tasks, without compromising maintainability.
  • A variety of basic data types are available: numbers (floating point, complex, and unlimited-length long integers), strings (both ASCII and Unicode), lists, dictionaries.
  • Python supports object-oriented programming with classes and multiple inheritance.
  • Code can be grouped into modules and packages.
  • The language supports raising and catching exceptions, resulting in cleaner error handling.
  • Data types are strongly and dynamically typed. Mixing incompatible types (e.g. attempting to add a string and a number) causes an exception to be raised.
  • Python contains advanced programming features such as generators and list comprehensions.
  • Automatic garbage collection frees you from the hassles of memory management.
  • The large standard library supports many common programming tasks such as connecting to web servers, regular expressions, and file handling.
  • Python's interactive mode makes it easy to test short snippets of code. There's also a bundled development environment called IDLE.
  • The Python interpreter is easily extended by adding new modules implemented in a compiled language such as C or C++.
  • The interpreter can also be embedded into an application to provide a programmable interface.
  • Python runs on many different computers and operating systems: Windows, MacOS, many brands of Unix, OS/2, ...

We will not discuss the specifics of Python here but instead refer the reader to the Python website. Also see Dive Into Python - Python from novice to pro

Python and lpsolve

lpsolve is callable from Python via an extension or module. As such, it looks like lpsolve is fully integrated with Python. Matrices can directly be transferred between Python and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for Python (especially for matrix support). So you have full control to the complete lpsolve functionality via the lpsolve Python driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level script files that can make things a lot easier. See further in this article.

Python is ideally suited to handle linear programming problems. These are problems in which you have a quantity, depending linearly on several variables, that you want to maximize or minimize subject to several constraints that are expressed as linear inequalities in the same variables.If the number of variables and the number of constraints are small, then there are numerous mathematical techniques for solving a linear programming problem. Indeed these techniques are often taught in high school or university level courses in finite mathematics.But sometimes these numbers are high, or even if low, the constants in the linear inequalities or the object expression for the quantity to be optimised may be numerically complicated in which case a software package like Python is required to effect a solution.

Installation

To make this possible, a driver program is needed: lpsolve55.pyd/lpsolve55.so. This driver must be put in a directory known to Python and Python can call the lpsolve solver.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux) (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). This has the advantage that the lpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the Windows path.

So note the difference between the Python lpsolve driver that is called lpsolve and the lpsolve library that implements the API that is called lpsolve55.

There are also some Python script files (.py) as a quick start.

See Install the lpsolve driver for the installation of these files.

To test if everything is installed correctly, enter the following in the Python command window.

>>> from lpsolve55 import *
>>> lpsolve()

If it gives the following, then everything is ok:

lpsolve Python Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: [ret1, ret2, ...] = lpsolve('functionname', arg1, arg2, ...)

If you get the following:

This application has failed to start because lpsolve55.dll was not found.
Re-installing the application may fix this problem.

Or (Unix/Linux):

liblpsolve55.so: cannot open shared object file: No such file or directory.

Then Python can find the lpsolve driver program, but the driver program cannot find the lpsolve library that contains the lpsolve implementation. This library is called lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux.
Under Windows, the lpsolve55.dll file must be in a directory that in the PATH environment variable. This path can be shown via the following command in Python: !PATH
It is common to place this in the WINDOWS\system32 folder.

Under Unix/Linux, the liblpsolve55.so shared library must be either in the directories /lib or /usr/lib or in a directory specified by the LD_LIBRARY_PATH environment variable.

Solve an lp model from Python via lpsolve

In the following text, >>> before the Python commands is the Python prompt. Only the text after >>> must be entered.

To call an lpsolve function, the following syntax must be used:

>>> [ret1, ret2, ...] = lpsolve('functionname', arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between single quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra Python specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in Python, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the Python functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from Python, nothing must be dimensioned in advance. The lpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to lpsolve. Never as argument to the routine. This can be a single value as for get_objective or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

Note that you can get a usage of lpsolve, its arguments and the constants that it defines by entering the following in Python:

>>> import lpsolve55
>>> help(lpsolve55)
Help on module lpsolve55:

NAME
    lpsolve55

FILE
    c:\python24\lib\site-packages\lpsolve55.pyd

CLASSES
    exceptions.Exception
        lpsolve.error

    class error(exceptions.Exception)
     |  Methods inherited from exceptions.Exception:
     |
     |  __getitem__(...)
     |
     |  __init__(...)
     |
     |  __str__(...)

FUNCTIONS
    lpsolve(...)
        lpsolve('functionname', arg1, arg2, ...) ->  execute lpsolve functionname with args

DATA
    ANTIDEGEN_BOUNDFLIP = 512
    ANTIDEGEN_COLUMNCHECK = 2
    ANTIDEGEN_DURINGBB = 128
    ANTIDEGEN_DYNAMIC = 64
    ANTIDEGEN_FIXEDVARS = 1
    ANTIDEGEN_INFEASIBLE = 32
    ANTIDEGEN_LOSTFEAS = 16
    ANTIDEGEN_NONE = 0
    ANTIDEGEN_NUMFAILURE = 8
    ANTIDEGEN_RHSPERTURB = 256
    ANTIDEGEN_STALLING = 4
    BRANCH_AUTOMATIC = 2
    BRANCH_DEFAULT = 3
    BRANCH_CEILING = 0
    BRANCH_FLOOR = 1
    CRASH_LEASTDEGENERATE = 3
    CRASH_MOSTFEASIBLE = 2
    CRASH_NONE = 0
    CRITICAL = 1
    DEGENERATE = 4
    DETAILED = 5
    EQ = 3
    FEASFOUND = 12
    FR = 0
    FULL = 6
    GE = 2
    IMPORTANT = 3
    IMPROVE_BBSIMPLEX = 8
    IMPROVE_DUALFEAS = 2
    IMPROVE_NONE = 0
    IMPROVE_SOLUTION = 1
    IMPROVE_THETAGAP = 4
    INFEASIBLE = 2
    Infinite = 1e+030
    LE = 1
    MSG_LPFEASIBLE = 8
    MSG_LPOPTIMAL = 16
    MSG_MILPBETTER = 512
    MSG_MILPEQUAL = 256
    MSG_MILPFEASIBLE = 128
    MSG_PRESOLVE = 1
    NEUTRAL = 0
    NODE_AUTOORDER = 8192
    NODE_BRANCHREVERSEMODE = 16
    NODE_BREADTHFIRSTMODE = 4096
    NODE_DEPTHFIRSTMODE = 128
    NODE_DYNAMICMODE = 1024
    NODE_FIRSTSELECT = 0
    NODE_FRACTIONSELECT = 3
    NODE_GAPSELECT = 1
    NODE_GREEDYMODE = 32
    NODE_GUBMODE = 512
    NODE_PSEUDOCOSTMODE = 64
    NODE_PSEUDOCOSTSELECT = 4
    NODE_PSEUDONONINTSELECT = 5
    NODE_PSEUDORATIOSELECT = 6
    NODE_RANDOMIZEMODE = 256
    NODE_RANGESELECT = 2
    NODE_RCOSTFIXING = 16384
    NODE_RESTARTMODE = 2048
    NODE_STRONGINIT = 32768
    NODE_USERSELECT = 7
    NODE_WEIGHTREVERSEMODE = 8
    NOFEASFOUND = 13
    NOMEMORY = -2
    NORMAL = 4
    NUMFAILURE = 5
    OPTIMAL = 0
    PRESOLVED = 9
    PRESOLVE_BOUNDS = 262144
    PRESOLVE_COLDOMINATE = 16384
    PRESOLVE_COLFIXDUAL = 131072
    PRESOLVE_COLS = 2
    PRESOLVE_DUALS = 524288
    PRESOLVE_ELIMEQ2 = 256
    PRESOLVE_IMPLIEDFREE = 512
    PRESOLVE_IMPLIEDSLK = 65536
    PRESOLVE_KNAPSACK = 128
    PRESOLVE_LINDEP = 4
    PRESOLVE_MERGEROWS = 32768
    PRESOLVE_NONE = 0
    PRESOLVE_PROBEFIX = 2048
    PRESOLVE_PROBEREDUCE = 4096
    PRESOLVE_REDUCEGCD = 1024
    PRESOLVE_REDUCEMIP = 64
    PRESOLVE_ROWDOMINATE = 8192
    PRESOLVE_ROWS = 1
    PRESOLVE_SENSDUALS = 1048576
    PRESOLVE_SOS = 32
    PRICER_DANTZIG = 1
    PRICER_DEVEX = 2
    PRICER_FIRSTINDEX = 0
    PRICER_STEEPESTEDGE = 3
    PRICE_ADAPTIVE = 32
    PRICE_AUTOPARTIAL = 256
    PRICE_HARRISTWOPASS = 4096
    PRICE_LOOPALTERNATE = 2048
    PRICE_LOOPLEFT = 1024
    PRICE_MULTIPLE = 8
    PRICE_PARTIAL = 16
    PRICE_PRIMALFALLBACK = 4
    PRICE_RANDOMIZE = 128
    PRICE_TRUENORMINIT = 16384
    PROCBREAK = 11
    PROCFAIL = 10
    SCALE_COLSONLY = 1024
    SCALE_CURTISREID = 7
    SCALE_DYNUPDATE = 256
    SCALE_EQUILIBRATE = 64
    SCALE_EXTREME = 1
    SCALE_GEOMETRIC = 4
    SCALE_INTEGERS = 128
    SCALE_LOGARITHMIC = 16
    SCALE_MEAN = 3
    SCALE_NONE = 0
    SCALE_POWER2 = 32
    SCALE_QUADRATIC = 8
    SCALE_RANGE = 2
    SCALE_ROWSONLY = 512
    SCALE_USERWEIGHT = 31
    SEVERE = 2
    SIMPLEX_DUAL_DUAL = 10
    SIMPLEX_DUAL_PRIMAL = 6
    SIMPLEX_PRIMAL_DUAL = 9
    SIMPLEX_PRIMAL_PRIMAL = 5
    SUBOPTIMAL = 1
    TIMEOUT = 7
    UNBOUNDED = 3
    USERABORT = 6
Also see Using string constants for an alternative.

An example

(Note that you can execute this example by entering command per command as shown below or by executing script example1. This will execute example1.py.)

>>> from lpsolve55 import *
>>> lp = lpsolve('make_lp', 0, 4)
>>> lpsolve('set_verbose', lp, IMPORTANT)
>>> ret = lpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1])
>>> ret = lpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], GE, 92.3)
>>> ret = lpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], LE, 14.8)
>>> ret = lpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], GE, 4)
>>> ret = lpsolve('set_lowbo', lp, 1, 28.6)
>>> ret = lpsolve('set_lowbo', lp, 4, 18)
>>> ret = lpsolve('set_upbo', lp, 4, 48.98)
>>> ret = lpsolve('set_col_name', lp, 1, 'COLONE')
>>> ret = lpsolve('set_col_name', lp, 2, 'COLTWO')
>>> ret = lpsolve('set_col_name', lp, 3, 'COLTHREE')
>>> ret = lpsolve('set_col_name', lp, 4, 'COLFOUR')
>>> ret = lpsolve('set_row_name', lp, 1, 'THISROW')
>>> ret = lpsolve('set_row_name', lp, 2, 'THATROW')
>>> ret = lpsolve('set_row_name', lp, 3, 'LASTROW')
>>> ret = lpsolve('write_lp', lp, 'a.lp')
>>> print lpsolve('get_mat', lp, 1, 2)
78.26
>>> lpsolve('solve', lp)
0L
>>> print lpsolve('get_objective', lp)
31.7827586207
>>> print lpsolve('get_variables', lp)[0]
[28.600000000000001, 0.0, 0.0, 31.827586206896552]
>>> print lpsolve('get_constraints', lp)[0]
[92.299999999999997, 6.863999999999999, 391.2928275862069]

Note that there are commands that return an answer. If they do and their result is not stored in a variable, then it is echoed on screen. If assigned to a variable then the value is not echoed. For example:

>>> obj = lpsolve('get_objective', lp)

The result in then not shown on screen. But the contents of the variable can be printed:

>>> print obj
31.7827586207

Or even:

>>> obj
31.782758620689656

Note that get_variables and get_constraints return two results: The result vector and a status. If only the vector is needed, then [0] can be used as in the example. Or the result can be stored in an extra variables:

>>> [x, ret] = lpsolve('get_variables', lp)

Variable x will contain the result vector and ret the return status of the call.

Note that if this is stored only in one variable that you get the following:

>>> x = lpsolve('get_variables', lp)
>>> print x
[[28.600000000000001, 0.0, 0.0, 31.827586206896552], 1L]

Don't forget to free the handle and its associated memory when you are done:

>>> lpsolve('delete_lp', lp)

Note that there is another way to access the lpsolve library. It is more object oriented, but requires more typing:

>>> import lpsolve55
>>> lp = lpsolve55.lpsolve('make_lp', 0, 4)
>>> lpsolve55.lpsolve('set_verbose', lp, lpsolve55.IMPORTANT)
.
.
.
>>> lpsolve55.lpsolve('delete_lp', lp)

This technique will not be used in this description because the lpsolve library is not really object oriented structured. But if you prefer it, there is nothing that should stop you. The only difference is that you have to put lpsolve55. before every lpsolve function and constant.

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
>>> from lpsolve55 import *
>>> lp = lpsolve('make_lp', 0, 4)
>>> ret = lpsolve('set_lp_name', lp, 'mymodel')
>>> lpsolve('set_verbose', 'mymodel', IMPORTANT)
>>> ret = lpsolve('set_obj_fn', 'mymodel', [1, 3, 6.24, 0.1])
>>> ret = lpsolve('add_constraint', 'mymodel', [0, 78.26, 0, 2.9], GE, 92.3)
>>> ret = lpsolve('add_constraint', 'mymodel', [0.24, 0, 11.31, 0], LE, 14.8)
>>> ret = lpsolve('add_constraint', 'mymodel', [12.68, 0, 0.08, 0.9], GE, 4)
>>> ret = lpsolve('set_lowbo', 'mymodel', 1, 28.6)
>>> ret = lpsolve('set_lowbo', 'mymodel', 4, 18)
>>> ret = lpsolve('set_upbo', 'mymodel', 4, 48.98)
>>> ret = lpsolve('set_col_name', 'mymodel', 1, 'COLONE')
>>> ret = lpsolve('set_col_name', 'mymodel', 2, 'COLTWO')
>>> ret = lpsolve('set_col_name', 'mymodel', 3, 'COLTHREE')
>>> ret = lpsolve('set_col_name', 'mymodel', 4, 'COLFOUR')
>>> ret = lpsolve('set_row_name', 'mymodel', 1, 'THISROW')
>>> ret = lpsolve('set_row_name', 'mymodel', 2, 'THATROW')
>>> ret = lpsolve('set_row_name', 'mymodel', 3, 'LASTROW')
>>> ret = lpsolve('write_lp', 'mymodel', 'a.lp')
>>> print lpsolve('get_mat', 'mymodel', 1, 2)
78.26
>>> lpsolve('solve', 'mymodel')
0L
>>> print lpsolve('get_objective', 'mymodel')
31.7827586207
>>> print lpsolve('get_variables', 'mymodel')[0]
[28.600000000000001, 0.0, 0.0, 31.827586206896552]
>>> print lpsolve('get_constraints', 'mymodel')[0]
[92.299999999999997, 6.863999999999999, 391.2928275862069]

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific Python routine to get the handle from the model name: get_handle.
For example:

>>> lp = lpsolve('get_handle', 'mymodel')
>>> print lp
0

Don't forget to free the handle and its associated memory when you are done:

>>> lpsolve('delete_lp', 'mymodel')

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

lpsolve uses Python lists to represent matrices (and vectors). Note that lpsolve can only work with real numbers, not complex numbers. For example:
>>> lpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8)

[0.24, 0, 11.31, 0] is a list type variable.

Most of the time, variables are used to provide the data:

>>> lpsolve('add_constraint', lp, a1, 1, 14.8)

Where a1 is a variable of type list. Sometimes a two-dimensional matrix is used:

>>> lpsolve('set_mat', lp, [[1, 2, 3], [4, 5, 6]])

[1, 2, 3] is the first row and [4, 5, 6] is the second row.

The lpsolve driver sees all provided matrices as sparse matrices. lpsolve uses sparse matrices internally and data can be provided sparse via the ex routines. For example add_constraintex. The lpsolve driver always uses the ex routines to provide the data to lpsolve. Even if you call from Python the routine names that would require a dense matrix (for example add_constraint), the lpsolve driver will always call the sparse version of the routine (for example add_constraintex). This results in the most performing behaviour. Matrices with too few or too much elements gives an 'invalid vector.' error.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the Python interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the Python matrix.

Maximum usage of matrices with lpsolve

Because Python has the list possibility to represent vectors, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the lpsolve Python driver to also work with vectors. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The lpsolve Python driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = lpsolve('set_int', lp, column, must_be_int). The matrix version of this call is: return = lpsolve('set_int', lp, [must_be_int]). The API call to return the integer status of a variable is: return = lpsolve('is_int', lp, column). The matrix version of this call is: [is_int] = lpsolve('is_int', lp)
Also note the get_mat and set_mat routines. In Python these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by executing script example2. This will execute example2.py.)

>>> lp = lpsolve('make_lp', 0, 4)
>>> lpsolve('set_verbose', lp, IMPORTANT)
>>> ret = lpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1])
>>> ret = lpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], GE, 92.3)
>>> ret = lpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], LE, 14.8)
>>> ret = lpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], GE, 4)
>>> ret = lpsolve('set_lowbo', lp, [28.6, 0, 0, 18])
>>> ret = lpsolve('set_upbo', lp, [Infinite, Infinite, Infinite, 48.98])
>>> ret = lpsolve('set_col_name', lp, ['COLONE', 'COLTWO', 'COLTHREE', 'COLFOUR'])
>>> ret = lpsolve('set_row_name', lp, ['THISROW', 'THATROW', 'LASTROW'])
>>> ret = lpsolve('write_lp', lp, 'a.lp')
>>> print lpsolve('get_mat', lp)[0]
[[0.0, 78.26, 0.0, 2.9], [0.24, 0.0, 11.31, 0.0], [12.68, 0.0, 0.08, 0.9]]
>>> lpsolve('solve', lp)
0L
>>> print lpsolve('get_objective', lp)
31.7827586207
>>> print lpsolve('get_variables', lp)[0]
[28.600000000000001, 0.0, 0.0, 31.827586206896552]
>>> print lpsolve('get_constraints', lp)[0]
[92.299999999999997, 6.8639999999999999, 391.29282758620695]

Note the usage of Infinite in set_upbo. This stands for 'infinity'. Meaning an infinite upper bound. It is also possible to use -Infinite to express minus infinity. This can for example be used to create a free variable. Infinite is a constant defined by the lpsolve library.

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example. Note that Python doesn't support matrix calculations on lists. However, there are several numerical packages that can do this. The list type variables must be converted to the matrix types of these packages. Two common known packages for this are Numeric and numpy. These are not installed by default but can be easily installed. See http://sourceforge.net/project/showfiles.php?group_id=1369&package_id=1351 and http://sourceforge.net/projects/numpy/files/. See http://numpy.scipy.org/ for a brief overview.

>>> from numpy import *
or
>>> from Numeric import *

This documentation works with numpy, but Numeric can be used also.

>>> from numpy import *
>>> A = array(lpsolve('get_mat', lp)[0])
>>> A
array([[  0.  ,  78.26,   0.  ,   2.9 ],
       [  0.24,   0.  ,  11.31,   0.  ],
       [ 12.68,   0.  ,   0.08,   0.9 ]])
>>> X = array(lpsolve('get_variables', lp)[0])
>>> X
array([ 28.6       ,   0.        ,   0.        ,  31.82758621])
>>> B = dot(A, X)
>>> B
array([  92.3       ,    6.864     ,  391.29282759])

We even don't have to explicitly convert the lists to matrices:

>>> from numpy import *
>>> a = lpsolve('get_mat', lp)[0]
>>> a
[[0.0, 78.26, 0.0, 2.9], [0.24, 0.0, 11.31, 0.0], [12.681, 0.0, 0.018, 0.9]]
>>> x = lpsolve('get_variables', lp)[0]
>>> x
[28.600000000000001, 0.0, 0.0, 31.827586206896552]
>>> B = dot(a, x)
>>> B
array([  92.3       ,    6.864     ,  391.29282759])

dot returns not a list, but an array object. If the result is needed again in a list, then this can be easily done:

>>> b = list(B)
>>> b
[92.299999999999997, 6.8639999999999999, 391.29282758620695]

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

>>> lpsolve('get_constraints', lp)[0]
[92.299999999999997, 6.8639999999999999, 391.29282758620695]

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

>>> c = lpsolve('get_obj_fn', lp)[0]
>>> x = lpsolve('get_variables', lp)[0]
>>> obj = dot(c, x)
>>> obj
31.782758620689656

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

>>> lpsolve('get_objective', lp)
31.782758620689656

Again exactly the same as the calculated obj value, as expected.

numpy package

In the above section Maximum usage of matrices with lpsolve the package numpy was already mentioned. See http://numpy.scipy.org/ for a brief overview. This package is the successor of the older and obsolete package Numeric. Since lp_solve is all about arrays and matrices, it is logical that the lpsolve Python driver accepts numpy arrays. This is possible from driver version 5.5.0.9. Before it was needed that numpy arrays were converted to lists.
For example:
>>> from numpy import *
>>> from lpsolve55 import *
>>> lp=lpsolve('make_lp', 0, 4);
>>> c = array([1, 3, 6.24, 0.1])
>>> ret = lpsolve('set_obj_fn', lp, c)
Note that the numpy array variable c is passed directly to lpsolve. Before driver version 5.5.0.9 this gave an error since lpsolve did not know numpy arrays. They had to be converted to lists:
>>> ret = lpsolve('set_obj_fn', lp, list(c))

That is ok for small models, but for larger arrays this gives an extra memory overhead since c is now two times in memory. Once as the numpy array and once as list.

Note that all returned arrays from lpsolve are always lists.

Also note that the older package Numeric is not supported by lpsolve. So it is not possible to provide a Numeric array to lpsolve. That will give an error.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
>>> lp=lpsolve('make_lp', 0, 4);
>>> lpsolve('set_verbose', lp, IMPORTANT);
>>> ret = lpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], GE, 92.3);
>>> ret = lpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], LE, 14.8);
>>> lpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], GE, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One can define all the possible constants in Python as is done in the Python driver and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

>>> lp=lpsolve('make_lp', 0, 4);
>>> lpsolve('set_verbose', lp, 'IMPORTANT');
>>> ret = lpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 'GE', 92.3);
>>> ret = lpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 'LE', 14.8);
>>> ret = lpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 'GE', 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

>>> lpsolve('set_verbose', lp, 'blabla');

Traceback (most recent call last):
  File "", line 1, in 
    lpsolve('set_verbose', lp, 'blabla');
error: BLABLA: Unknown.

>>> lpsolve('set_verbose', lp, 'GE');

Traceback (most recent call last):
  File "", line 1, in 
    lpsolve('set_verbose', lp, 'GE');
error: GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. 'LE', 'GE' and 'EQ' in add_constraint and is_constr_type can also be '<', '<=', '>', '>=', '='. When returned however, 'GE', 'LE', 'EQ' will be used.

Also in the matrix version of calls, string constants are possible. For example:

>>> ret = lpsolve('set_constr_type', lp, ['LE', 'EQ', 'GE']);

Some constants can be a combination of multiple constants. For example set_scaling:

>>> lpsolve('set_scaling', lp, 3+128);

With the string version of constants this can be done as following:

>>> lpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_INTEGERS');

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

>>> lpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_RANGE');

Traceback (most recent call last):
  File "", line 1, in 
    lpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_RANGE');
error: SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

>>> lpsolve('get_scaling', lp)
131L

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

>>> ret = lpsolve('return_constants', 1);

From now on, all returned constants are returned as string:

>>> lpsolve('get_scaling', lp)
'SCALE_MEAN|SCALE_INTEGERS'

Also when an array of constants is returned, they are returned as string when return_constants is set:

>>> lpsolve('get_constr_type', lp)
['LE', 'EQ', 'GE']

This for all routines until return_constants is again called with 0:

>>> ret = lpsolve('return_constants', 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

>>> lpsolve('return_constants', 1)
1L

To get the value without setting it, don't provide the second argument:

>>> lpsolve('return_constants')
1L

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

Callbacks

lp_solve has a callback mechanisms to Python while it is in the solve process. To enable this, a python routine must be registered to lp_solve and it will then be called when needed. Following callbacks are possible:

Callback functionality Python example See
Sets an abort routine. lpsolve('put_abortfunc', lp, abortfunc, "extra") put_abortfunc
Sets a log routine. lpsolve('put_logfunc', lp, logfunc, "extra") put_logfunc
Sets a message routine. lpsolve('put_msgfunc', lp, msgfunc, "extra", 1023) put_msgfunc
Specifies a user function to select a B&B branching, given the column to branch on. lpsolve('put_bb_branchfunc', lp, branchfunc, "extra") put_bb_branchfunc
Allows to set a user function that specifies which non-integer variable to select next to make integer in the B&B solve. lpsolve('put_bb_nodefunc', lp, nodefunc, "extra") put_bb_nodefunc

Note that the callback routine *must* have the same parameter list as required by the callback routine for the put_* routine. If that is not the case it is likely that the program will crash. There is no check done by lp_solve that this is the case.

Example:

>>> from lpsolve55 import *

>>> lp = lpsolve('make_lp', 0, 4)
>>> lpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1])
>>> lpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], GE, 92.3)
>>> lpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], LE, 14.8)
>>> lpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], GE, 4)
>>> lpsolve('set_lowbo', lp, 1, 28.6)
>>> lpsolve('set_lowbo', lp, 4, 18)
>>> lpsolve('set_upbo', lp, 4, 48.98)
>>> lpsolve('set_int', lp, [1, 1, 1, 1])

>>> def abortfunc(lp, userhandle): print "abortfunc(%d, %s)" % (lp, userhandle); return 0
>>> lpsolve('put_abortfunc', lp, abortfunc, "abortfunc")

>>> def logfunc(lp, userhandle, buf): print "logfunc(%d, %s, %s)" % (lp, userhandle, buf); return 0
>>> lpsolve('put_logfunc', lp, logfunc, "logfunc")

>>> def msgfunc(lp, userhandle, message): print "msgfunc(%d, %s %d)" % (lp, userhandle, message); return 0
>>> lpsolve('put_msgfunc', lp, msgfunc, "msgfunc", 1023)

>>> def branchfunc(lp, branchhandle, column): print "branchfunc(%d, %s, %d)" % (lp, branchhandle, column); return 0
>>> lpsolve('put_bb_branchfunc', lp, branchfunc, "branchfunc")

>>> def nodefunc(lp, nodehandle, vartype): print "nodefunc(%d, %s, %d)" % (lp, nodehandle, vartype); return -1
>>> lpsolve('put_bb_nodefunc', lp, nodefunc, "nodefunc")

>>> lpsolve('solve', lp)
>>> lpsolve('delete_lp', lp)

py-files

Python can execute a sequence of statements stored in diskfiles. Such files are called Python scripts and should have the file type of ".py" as the last part of their filename (extension).

You can put Python commands in them and execute them at any time. The Python script is executed either via the command python script.py. The script files contain plain ascii data.

The lpsolve Python distribution contains some example script to demonstrate this.

example1.py

Contains the commands as shown in the first example of this article.

example2.py

Contains the commands as shown in the second example of this article.

example3.py

Contains the commands of a practical example. See further in this article.

example4.py

Contains the commands of a practical example. See further in this article.

example5.py

Contains the commands of a practical example. See further in this article.

example6.py

Contains the commands of a practical example. See further in this article.

lp_solve.py

This script uses the API to create a higher-level function called lp_solve. This function accepts as arguments some matrices and options to create and solve an lp model. Type help(lp_solve) or just lp_solve() to see its usage:

 LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

>>> from lp_solve import *
>>> [obj, x, duals] = lp_solve([-1, 2], [[2, 1], [-4, 4]], [5, 5], [-1, -1], None, None, [1, 2])
>>> print obj
3.0
>>> print x
[1.0, 2.0]

lp_maker.py

This script is analog to the lp_solve script and also uses the API to create a higher-level function called lp_maker. This function accepts as arguments some matrices and options to create an lp model. Note that this scripts only creates a model and returns a handle. Type help(lp_maker) or just lp_maker() to see its usage:

   LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

>>> from lp_maker import *
>>> lp = lp_maker([-1, 2], [[2, 1], [-4, 4]], [5, 5], [-1, -1], None, None, [1, 2])
>>> lp
0L

To solve the model and get the solution:

>>> lpsolve('solve', lp)
0L
>>> lpsolve('get_objective', lp)
3.0
>>> lpsolve('get_variables', lp)[0]
[1.0, 2.0]

Don't forget to free the handle and its associated memory when you are done:

>>> lpsolve('delete_lp', lp)

lpdemo.py

Contains several examples to build and solve lp models.

ex.py

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

Source

Now let's put in the other two constraint inequalities.

Source

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.

Source

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:

>>> from numpy import *
>>> from numpy.linalg import inv
>>> x = dot(inv(array([[1, 1], [110, 30]])), array([75, 4000]))
>>> print x
[ 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 = dot(array([143, 60]), x)
>>> print P
6315.625

That is, $6315.625.

Note that these command are in script example3.py

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

>>> from lp_maker import *
>>> f = [143, 60]
>>> A = [[120, 210], [110, 30], [1, 1]]
>>> b = [15000, 4000, 75]
>>> lp = lp_maker(f, A, b, [-1, -1, -1], None, None, None, 1, 0)
>>> solvestat = lpsolve('solve', lp)
>>> obj = lpsolve('get_objective', lp)
>>> print obj
6315.625
>>> x = lpsolve('get_variables', lp)[0]
>>> print x
[21.874999999999993, 53.125000000000007]
>>> lpsolve('delete_lp', lp)

Note that these command are in script example4.py

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimensions, but beyond that it is all very theoretical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

>>> from lp_maker import *
>>> f = [143, 60, 195]
>>> A = [[120, 210, 150.75], [110, 30, 125], [1, 1, 1]]
>>> b = [15000, 4000, 75]
>>> lp = lp_maker(f, A, b, [-1, -1, -1], None, None, None, 1, 0)
>>> solvestat = lpsolve('solve', lp)
>>> obj = lpsolve('get_objective', lp)
>>> print obj
6986.84210526
>>> x = lpsolve('get_variables', lp)[0]
>>> print x
[0.0, 56.578947368421055, 18.421052631578945]
>>> lpsolve('delete_lp', lp)

Note that these command are in script example5.py

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that Python can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like Python is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
>>> from lpsolve55 import *
>>> from lp_maker import *
>>> f = [110*1.3, 30*2.0, 125*1.56, 75*1.8, 95*.95, 100*2.25, 50*1.35]
>>> A = [[120, 210, 150.75, 115, 186, 140, 85], [110, 30, 125, 75, 95, 100, 50], [1, 1, 1, 1, 1, 1, 1],
         [1, -1, 0, 0, 0, 0, 0], [0, 0, 1, 0, -2, 0, 0], [0, 0, 0, -1, 0, -1, 1]]
>>> b = [55000, 40000, 400, 0, 0, 0]
>>> lp = lp_maker(f, A, b, [-1, -1, -1, -1, -1, -1], [10, 10, 10, 10, 20, 20, 20],
                           [100, Infinite, 50, Infinite, Infinite, 250, Infinite], None, 1, 0)
>>> solvestat = lpsolve('solve', lp)
>>> obj = lpsolve('get_objective', lp)
>>> print obj
75398.0434783
>>> x = lpsolve('get_variables', lp)[0]
>>> print x
[10.0, 10.0, 40.0, 45.652173913043455, 20.0, 250.0, 20.0]
>>> lpsolve('delete_lp', lp)

Note that these command are in script example6.py

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that Infinity is used for variables that have no upper limit.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using Python:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into Python format we get:

f = [4, 2, 1]
A = [[2, 1, 0], [1, 0, 2], [1, 1, 1]]
b = [1, 2, 1]

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0, 0, 0]
u = [ 1, 1, 2]

Now lets enter this in Python:

>>> f = [4, 2, 1]
>>> A = [[2, 1, 0], [1, 0, 2], [1, 1, 1]]
>>> b = [1, 2, 1]
>>> l = [ 0, 0, 0]
>>> u = [ 1, 1, 2]

Now solve the linear program using Python: Type the commands

>>> from lpsolve55 import *
>>> from lp_maker import *
>>> lp = lp_maker(f, A, b, [-1, -1, -1], l, u, None, 1, 0)
>>> solvestat = lpsolve('solve', lp)
>>> obj = lpsolve('get_objective', lp)
>>> print obj
2.5
>>> x = lpsolve('get_variables', lp)[0]
>>> print x
[0.5, 0.0, 0.5]
>>> lpsolve('delete_lp', lp)

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the Python command:

>>> l = None

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -Infinite as lower bounds:

>>> l = [-Infinite, -Infinite, -Infinite]

Solve this and you get a different result:

>>> lp = lp_maker(f, A, b, [-1, -1, -1], l, u, None, 1, 0)
>>> solvestat = lpsolve('solve', lp)
>>> obj = lpsolve('get_objective', lp)
>>> print obj
2.66666666667
>>> x = lpsolve('get_variables', lp)[0]
>>> print x
[0.66666666666666674, -0.33333333333333348, 0.66666666666666674]
>>> lpsolve('delete_lp', lp)

Overview of API routines

Note that everwhere where lp is used as argument that this can be a handle (lp) or the models name.

  • add_column, add_columnex
    • return = lpsolve('add_column', lp, [column])
    • return = lpsolve('add_columnex', lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = lpsolve('add_constraint', lp, [row], constr_type, rh)
    • return = lpsolve('add_constraintex', lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = lpsolve('add_SOS', lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in Python since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = lpsolve('column_in_lp', lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = lpsolve('copy_lp', lp)
    • No special considerations.
  • default_basis
    • lpsolve('default_basis', lp)
    • No special considerations.
  • del_column
    • return = lpsolve('del_column', lp, column)
    • No special considerations.
  • del_constraint
    • return = lpsolve('del_constraint', lp, del_row)
    • No special considerations.
  • delete_lp
    • lpsolve('delete_lp', lp)
    • No special considerations.
  • free_lp
    • lpsolve('free_lp', lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = lpsolve('get_anti_degen', lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = lpsolve('get_basis', lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in Python. If not provided, then 0 is used.
  • get_basiscrash
    • return = lpsolve('get_basiscrash', lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = lpsolve('get_bb_depthlimit', lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = lpsolve('get_bb_floorfirst', lp)
    • No special considerations.
  • get_bb_rule
    • return = lpsolve('get_bb_rule', lp)
    • No special considerations.
  • get_bounds_tighter
    • return = lpsolve('get_bounds_tighter', lp)
    • No special considerations.
  • get_break_at_value
    • return = lpsolve('get_break_at_value', lp)
    • No special considerations.
  • get_col_name
    • name = lpsolve('get_col_name', lp, column)
    • [names] = lpsolve('get_col_name', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_column get_columnex
    • [column, return] = lpsolve('get_column', lp, col_nr)
    • [column, return] = lpsolve('get_columnex', lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = lpsolve('get_constr_type', lp, row)
    • [constr_type] = lpsolve('get_constr_type', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_constr_value
    • return = lpsolve('get_constr_value', lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = lpsolve('get_constraints', lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = lpsolve('get_dual_solution', lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Python, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = lpsolve('get_epsb', lp)
    • No special considerations.
  • get_epsd
    • return = lpsolve('get_epsd', lp)
    • No special considerations.
  • get_epsel
    • return = lpsolve('get_epsel', lp)
    • No special considerations.
  • get_epsint
    • return = lpsolve('get_epsint', lp)
    • No special considerations.
  • get_epsperturb
    • return = lpsolve('get_epsperturb', lp)
    • No special considerations.
  • get_epspivot
    • return = lpsolve('get_epspivot', lp)
    • No special considerations.
  • get_improve
    • return = lpsolve('get_improve', lp)
    • No special considerations.
  • get_infinite
    • return = lpsolve('get_infinite', lp)
    • No special considerations.
  • get_lowbo
    • return = lpsolve('get_lowbo', lp, column)
    • [return] = lpsolve('get_lowbo', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_lp_index
    • return = lpsolve('get_lp_index', lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = lpsolve('get_lp_name', lp)
    • No special considerations.
  • get_mat
    • value = lpsolve('get_mat', lp, row, col)
    • [matrix, return] = lpsolve('get_mat', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix in the first return value. The return code of the call is the second return value.
  • get_max_level
    • return = lpsolve('get_max_level', lp)
    • No special considerations.
  • get_maxpivot
    • return = lpsolve('get_maxpivot', lp)
    • No special considerations.
  • get_mip_gap
    • return = lpsolve('get_mip_gap', lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = lpsolve('get_nameindex', lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = lpsolve('get_Ncolumns', lp)
    • No special considerations.
  • get_negrange
    • return = lpsolve('get_negrange', lp)
    • No special considerations.
  • get_nonzeros
    • return = lpsolve('get_nonzeros', lp)
    • No special considerations.
  • get_Norig_columns
    • return = lpsolve('get_Norig_columns', lp)
    • No special considerations.
  • get_Norig_rows
    • return = lpsolve('get_Norig_rows', lp)
    • No special considerations.
  • get_Nrows
    • return = lpsolve('get_Nrows', lp)
    • No special considerations.
  • get_obj_bound
    • return = lpsolve('get_obj_bound', lp)
    • No special considerations.
  • get_objective
    • return = lpsolve('get_objective', lp)
    • No special considerations.
  • get_orig_index
    • return = lpsolve('get_orig_index', lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = lpsolve('get_origcol_name', lp, column)
    • [names] = lpsolve('get_origcol_name', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_origrow_name
    • name = lpsolve('get_origrow_name', lp, row)
    • [names] = lpsolve('get_origrow_name', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_pivoting
    • return = lpsolve('get_pivoting', lp)
    • No special considerations.
  • get_presolve
    • return = lpsolve('get_presolve', lp)
    • No special considerations.
  • get_presolveloops
    • return = lpsolve('get_presolveloops', lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = lpsolve('get_primal_solution', lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = lpsolve('get_print_sol', lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = lpsolve('get_rh', lp, row)
    • [rh] = lpsolve('get_rh', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_rh_range
    • return = lpsolve('get_rh_range', lp, row)
    • [rh_ranges] = lpsolve('get_rh_range', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_row get_rowex
    • [row, return] = lpsolve('get_row', lp, row_nr)
    • [row, return] = lpsolve('get_rowex', lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Python, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = lpsolve('get_row_name', lp, row)
    • [names] = lpsolve('get_row_name', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_scalelimit
    • return = lpsolve('get_scalelimit', lp)
    • No special considerations.
  • get_scaling
    • return = lpsolve('get_scaling', lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = lpsolve('get_sensitivity_obj', lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = lpsolve('get_sensitivity_objex', lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that Python allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = lpsolve('get_sensitivity_obj', lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, Python always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = lpsolve('get_sensitivity_rhs', lp)
    • [duals, dualsfrom, dualstill, return] = lpsolve('get_sensitivity_rhsex', lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that Python allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = lpsolve('get_sensitivity_rhs', lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = lpsolve('get_simplextype', lp)
    • No special considerations.
  • get_solutioncount
    • return = lpsolve('get_solutioncount', lp)
    • No special considerations.
  • get_solutionlimit
    • return = lpsolve('get_solutionlimit', lp)
    • No special considerations.
  • get_status
    • return = lpsolve('get_status', lp)
    • No special considerations.
  • get_statustext
    • return = lpsolve('get_statustext', lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = lpsolve('get_timeout', lp)
    • No special considerations.
  • get_total_iter
    • return = lpsolve('get_total_iter', lp)
    • No special considerations.
  • get_total_nodes
    • return = lpsolve('get_total_nodes', lp)
    • No special considerations.
  • get_upbo
    • return = lpsolve('get_upbo', lp, column)
    • [upbo] = lpsolve('get_upbo', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_var_branch
    • return = lpsolve('get_var_branch', lp, column)
    • [var_branch] = lpsolve('get_var_branch', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_var_dualresult
    • return = lpsolve('get_var_dualresult', lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = lpsolve('get_var_primalresult', lp, index)
    • No special considerations.
  • get_var_priority
    • return = lpsolve('get_var_priority', lp, column)
    • [var_priority] = lpsolve('get_var_priority', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • get_variables
    • [var, return] = lpsolve('get_variables', lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = lpsolve('get_verbose', lp)
    • No special considerations.
  • get_working_objective
    • return = lpsolve('get_working_objective', lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = lpsolve('guess_basis', lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In Python, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In Python, there is no unused element in the matrix.
  • has_BFP
    • return = lpsolve('has_BFP', lp)
    • No special considerations.
  • has_XLI
    • return = lpsolve('has_XLI', lp)
    • No special considerations.
  • is_add_rowmode
    • return = lpsolve('is_add_rowmode', lp)
    • No special considerations.
  • is_anti_degen
    • return = lpsolve('is_anti_degen', lp, testmask)
    • No special considerations.
  • is_binary
    • return = lpsolve('is_binary', lp, column)
    • [binary] = lpsolve('is_binary', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • is_break_at_first
    • return = lpsolve('is_break_at_first', lp)
    • No special considerations.
  • is_constr_type
    • return = lpsolve('is_constr_type', lp, row, mask)
    • No special considerations.
  • is_debug
    • return = lpsolve('is_debug', lp)
    • No special considerations.
  • is_feasible
    • return = lpsolve('is_feasible', lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = lpsolve('is_free', lp, column)
    • return = lpsolve('is_unbounded', lp, column)
    • [free] = lpsolve('is_free', lp)
    • [free] = lpsolve('is_unbounded', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • is_infinite
    • return = lpsolve('is_infinite', lp, value)
    • No special considerations.
  • is_int
    • return = lpsolve('is_int', lp, column)
    • [int] = lpsolve('is_int', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • is_integerscaling
    • return = lpsolve('is_integerscaling', lp)
    • No special considerations.
  • is_maxim
    • return = lpsolve('is_maxim', lp)
    • No special considerations.
  • is_nativeBFP
    • return = lpsolve('is_nativeBFP', lp)
    • No special considerations.
  • is_nativeXLI
    • return = lpsolve('is_nativeXLI', lp)
    • No special considerations.
  • is_negative
    • return = lpsolve('is_negative', lp, column)
    • [negative] = lpsolve('is_negative', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • is_piv_mode
    • return = lpsolve('is_piv_mode', lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = lpsolve('is_piv_rule', lp, rule)
    • No special considerations.
  • is_presolve
    • return = lpsolve('is_presolve', lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = lpsolve('is_scalemode', lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = lpsolve('is_scaletype', lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = lpsolve('is_semicont', lp, column)
    • [semicont] = lpsolve('is_semicont', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • is_SOS_var
    • return = lpsolve('is_SOS_var', lp, column)
    • [SOS_var] = lpsolve('is_SOS_var', lp)
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Python matrix.
  • is_trace
    • return = lpsolve('is_trace', lp)
    • No special considerations.
  • is_use_names
    • return = lpsolve('is_use_names', lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = lpsolve('lp_solve_version')
    • The lpsolve API routine returns the version information in 4 provided argument variables while the Python version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = lpsolve('make_lp', rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • lpsolve('print_constraints', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
    • The same information can also be obtained via lpsolve('get_constraints', lp). This shows the result on screen.
  • print_debugdump
    • return = lpsolve('print_debugdump', lp, filename)
    • No special considerations.
  • print_duals
    • lpsolve('print_duals', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
    • The same information can be obtained via lpsolve('get_dual_solution', lp). This shows the result on screen.
  • print_lp
    • lpsolve('print_lp', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
  • print_objective
    • lpsolve('print_objective', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
    • The same information can be obtained via lpsolve('get_objective', lp). This shows the result on screen.
  • print_scales
    • lpsolve('print_scales', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
  • print_solution
    • lpsolve('print_solution', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
    • The same information can also be obtained via lpsolve('get_variables', lp). This shows the result on screen.
  • print_str
    • lpsolve('print_str', lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
  • print_tableau
    • lpsolve('print_tableau', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Python (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the lpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows Python) to the command window of Python. As such, all reported output can be seen in Python. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = lpsolve('read_basis', lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = lpsolve('read_freemps', filename {, options})
    • lp_handle = lpsolve('read_freeMPS', filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In Python it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = lpsolve('read_lp', filename {, verbose {, lp_name}})
    • lp_handle = lpsolve('read_LP', filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In Python it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ('').
  • read_mps, read_MPS
    • lp_handle = lpsolve('read_mps', filename {, options})
    • lp_handle = lpsolve('read_MPS', filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In Python it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = lpsolve('read_params', lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = lpsolve('read_XLI', xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, '' (NULL) is taken. '' is taken as NULL.
    • options is optional. When not provided, '' is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • lpsolve('set_basisvar', lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = lpsolve('set_add_rowmode', lp, turnon)
    • No special considerations.
  • set_anti_degen
    • lpsolve('set_anti_degen', lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = lpsolve('set_basis', lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In Python, there is no unused element in the matrix.
  • set_basiscrash
    • lpsolve('set_basiscrash', lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • lpsolve('set_bb_depthlimit', lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • lpsolve('set_bb_floorfirst', lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • lpsolve('set_bb_rule', lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = lpsolve('set_BFP', lp, filename)
    • No special considerations.
  • set_binary
    • return = lpsolve('set_binary', lp, column, must_be_bin)
    • return = lpsolve('set_binary', lp, [must_be_bin])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = lpsolve('set_bounds', lp, column, lower, upper)
    • return = lpsolve('set_bounds', lp, [lower], [upper])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • lpsolve('set_bounds_tighter', lp, tighten)
    • No special considerations.
  • set_break_at_first
    • lpsolve('set_break_at_first', lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • lpsolve('set_break_at_value', lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = lpsolve('set_col_name', lp, column, name)
    • return = lpsolve('set_col_name', lp, [names])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_column, set_columnex
    • return = lpsolve('set_column', lp, col_no, [column])
    • return = lpsolve('set_columnex', lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = lpsolve('set_constr_type', lp, row, con_type)
    • return = lpsolve('set_constr_type', lp, [con_type])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • lpsolve('set_debug', lp, debug)
    • No special considerations.
  • set_epsb
    • lpsolve('set_epsb', lp, epsb)
    • No special considerations.
  • set_epsd
    • lpsolve('set_epsd', lp, epsd)
    • No special considerations.
  • set_epsel
    • lpsolve('set_epsel', lp, epsel)
    • No special considerations.
  • set_epsint
    • lpsolve('set_epsint', lp, epsint)
    • No special considerations.
  • set_epslevel
    • lpsolve('set_epslevel', lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • lpsolve('set_epsperturb', lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • lpsolve('set_epspivot', lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = lpsolve('set_free', lp, column)
    • return = lpsolve('set_unbounded', lp, column)
    • No special considerations.
  • set_improve
    • lpsolve('set_improve', lp, improve)
    • No special considerations.
  • set_infinite
    • lpsolve('set_infinite', lp, infinite)
    • No special considerations.
  • set_int
    • return = lpsolve('set_int', lp, column, must_be_int)
    • return = lpsolve('set_int', lp, [must_be_int])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = lpsolve('set_lowbo', lp, column, value)
    • return = lpsolve('set_lowbo', lp, [values])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = lpsolve('set_lp_name', lp, name)
    • In Python, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = lpsolve('set_mat', lp, row, column, value)
    • return = lpsolve('set_mat', lp, [matrix])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. Consider using a Python sparse matrix for maximum performance and least memory usage. The matrix must be two-dimensional.
  • set_maxim
    • lpsolve('set_maxim', lp)
    • No special considerations.
  • set_maxpivot
    • lpsolve('set_maxpivot', max_num_inv)
    • No special considerations.
  • set_minim
    • lpsolve('set_minim', lp)
    • No special considerations.
  • set_mip_gap
    • lpsolve('set_mip_gap', lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • lpsolve('set_negrange', negrange)
    • No special considerations.
  • set_obj
    • return = lpsolve('set_obj', lp, column, value)
    • return = lpsolve('set_obj', lp, [values])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • lpsolve('set_obj_bound', lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = lpsolve('set_obj_fn', lp, [row])
    • return = lpsolve('set_obj_fnex', lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In Python, there is no unused element in the matrix.
  • set_outputfile
    • return = lpsolve('set_outputfile', lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In Python under Windows, output to stdout it not shown. However it results in closing the file. Use '' to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • lpsolve('set_pivoting', lp, pivoting)
    • No special considerations.
  • set_preferdual
    • lpsolve('set_preferdual', lp, dodual)
    • No special considerations.
  • set_presolve
    • lpsolve('set_presolve', lp, do_presolve {, maxloops})
    • The maxloops argument is optional in Python. If not provided, then infinite is used.
  • set_print_sol
    • lpsolve('set_print_sol', lp, print_sol)
    • No special considerations.
  • set_rh
    • return = lpsolve('set_rh', lp, row, value)
    • return = lpsolve('set_rh', lp, [values])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = lpsolve('set_rh_range', lp, row, deltavalue)
    • return = lpsolve('set_rh_range', lp, [deltavalues])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • lpsolve('set_rh_vec', lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In Python, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = lpsolve('set_row', lp, row_no, [row])
    • return = lpsolve('set_rowex', lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In Python, there is no unused element in the matrix.
  • set_row_name
    • return = lpsolve('set_row_name', lp, row, name)
    • return = lpsolve('set_row_name', lp, [names])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_scalelimit
    • lpsolve('set_scalelimit', lp, scalelimit)
    • No special considerations.
  • set_scaling
    • lpsolve('set_scaling', lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = lpsolve('set_semicont', lp, column, must_be_sc)
    • return = lpsolve('set_semicont', lp, [must_be_sc])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • lpsolve('set_sense', lp, maximize)
    • No special considerations.
  • set_simplextype
    • lpsolve('set_simplextype', lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • lpsolve('set_solutionlimit', lp, simplextype)
    • No special considerations.
  • set_timeout
    • lpsolve('set_timeout', lp, sectimeout)
    • No special considerations.
  • set_trace
    • lpsolve('set_trace', lp, trace)
    • No special considerations.
  • set_upbo
    • return = lpsolve('set_upbo', lp, column, value)
    • return = lpsolve('set_upbo', lp, [values])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • lpsolve('set_use_names', lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = lpsolve('set_var_branch', lp, column, branch_mode)
    • return = lpsolve('set_var_branch', lp, [branch_mode])
    • In Python, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = lpsolve('set_var_weights', lp, [weights])
    • No special considerations.
  • set_verbose
    • lpsolve('set_verbose', lp, verbose)
    • No special considerations.
  • set_XLI
    • return = lpsolve('set_XLI', lp, filename)
    • No special considerations.
  • solve
    • result = lpsolve('solve', lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = lpsolve('time_elapsed', lp)
    • No special considerations.
  • unscale
    • lpsolve('unscale', lp)
    • No special considerations.
  • write_basis
    • lpsolve('write_basis', lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = lpsolve('write_freemps', lp, filename)
    • return = lpsolve('write_freeMPS', lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In Python it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = lpsolve('write_lp', lp, filename)
    • return = lpsolve('write_LP', lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In Python it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = lpsolve('write_mps', lp, filename)
    • return = lpsolve('write_MPS', lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In Python it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = lpsolve('write_XLI', lp, filename {, options {, results}})
    • No special considerations.

Extra Python routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = lpsolve('get_col_names', lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = lpsolve('get_constr_types', lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = lpsolve('get_int', lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = lpsolve('get_no_cols', lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = lpsolve('get_no_rows', lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = lpsolve('get_objective_name', lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = lpsolve('get_obj_fn', lp)
    [row_vec, return] = lpsolve('get_obj_fun', lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = lpsolve('get_problem_name', lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = lpsolve('get_reduced_costs', lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = lpsolve('get_row_names', lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = lpsolve('get_solution', lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = lpsolve('mat_elm', lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = lpsolve('print_handle')
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = lpsolve('read_lp_file', filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = lpsolve('get_handle', lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = lpsolve('return_constants'[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the lpsolve driver

The lpsolve Python driver is called lpsolve55.pyd (windows) and lpsolve55.so (Unix).
This driver is an interface to the lpsolve55.dll (windows) and liblpsolve55.so (Unix) lpsolve shared library that contains the implementation of lp_solve. lpsolve55.dll/liblpsolve55.so is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). The lpsolve Python driver is just a wrapper between Python and lp_solve to translate the input/output to/from Python and the lp_solve library.

The lpsolve Python driver is written in C. To compile this code a C compiler is needed. Under Unix, this is the standard C compiler (cc/gcc) and under windows it is the Microsoft compiler from Visual Studio .NET. or the mingw gcc compiler This compiler must be called from Python. To make the compilation process easier, a Python script can be used: setup.py (setup64.py for 64 bit OS)

To be able to compile this driver, Python must be installed on the system and callable from a shell or command prompt by just entering the command Python. If this is not the case, set the PATH environment variable to the location where Python is installed. For example C:\Python25

The lpsolve Python driver can use the Python numpy package. To be able to compile the lpsolve driver, this numpy package should also be installed on the system. If the numpy package cannot be found at compilation time, the lpsolve Python driver will not be able to work with numpy. The compilation script setup.py/setup64.py automatically detects if numpy is installed and uses it if found. This is done by searching the numpy directory. This is done by the following python commands:

import sys
import os
p = sys.prefix
NUMPYPATH = ''
if os.path.isdir(p + '/include/numpy'):
  NUMPY = 'NUMPY'
elif os.path.isdir(p + '/Lib/site-packages/numpy/core/include/numpy'):
  NUMPY = 'NUMPY'
  NUMPYPATH = p + '/Lib/site-packages/numpy/core/include'
else:
  NUMPY = 'NONUMPY'

Under Unix, make sure you have enough rights. Possibly you must be logged in as a root user.

Under Windows, the Microsoft visual C compiler is needed by default.
Unfortunately apparently there is a test that the version must be exactly the same as the one where Python itself is build with.
However it is also possible to compile with the mingw gcc compiler. For this, create (or edit) the file C:\Python25\Lib\distutils\distutils.cfg:

[build]
compiler=mingw32

The python folder can of course be different.

Note that liblpsolve55.a may not exist in directory ../../lpsolve55/bin/win32. Delete it or temporary rename it such that lpsolve55.dll is used.

Now to compile and install the package, just enter the following in a command prompt/shell:

python setup.py install
or
python setup64.py install

and everything is done.

To create a distribution package, enter:

python setup.py bdist

Under Windows, use:

python setup.py bdist_wininst

Install the lpsolve driver

Under Linux, the distributable packages is called lpsolve55-5.5.0.6.linux-i686.tar.gz
The contents must be expanded to the appropriate directory.

Under Windows, there is an installer that installs the Python lpsolve driver and the supporting scripts lp_maker.py and lp_solve.py. Just run lpsolve55-5.5.0.6.win32-py2.4.exe (this installer is in archive lp_solve_5.5_Python_exe.zip).

On other platforms, the lpsolve driver must be compiled as described in the previous section: Compile the lpsolve driver

Don't forget that lpsolve55.dll (Windows) or liblpsolve55.so (Unix/Linux) is also needed for this (In archive lp_solve_5.5.2.11_dev.zip).

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from PHP, Using lpsolve from Sage, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./quickstart.htm000666 000000 000000 00000023313 13772705352 012306 0ustar00000000 000000 Quick Start

Quick Start

lp_solve (or lpsolve) has allot of features in-house. For a beginner, it can be difficult to determine where to start. The distribution contains many files and to start with, you need only a couple of them. As you learn the package you may need extras. This text explains how to start with lp_solve.

Skip the blabla, just give me a very quick start.

How to call lp_solve

Basically, lp_solve is a library, a set of routines, called the API that can be called from almost any programming language to solve MILP problems. There are several ways to pass the data to the library:

  • Via the API
  • Via input files
  • Via an IDE

Via the API

The API is a set of routines that can be called from a programming language to build the model in memory, solve it and return the results. There are many API routines to perform many possible tasks and set several options. See lp_solve API reference for an overview.

Via input files

Standard, lp_solve supports several input files types. The common known MPS format (see mps-format) is supported by most solvers, but it is not very readable for humans. Another format is the lp format (see lp-format) that is more readable. lp_solve has the unique ability to use user-written routines to input the model (see External Language Interface). See read_mps, read_freemps, read_MPS, read_freeMPS and read_lp, read_LP for the API calls to read the model from file.

There is also a driver program called lp_solve that uses the API to provide a command line application to solve models. See lp_solve for its usage. With this program you don't have to know anything of API or computer programming languages. You can just provide your model via file to the program and it will solve the model and give you the result.

Via an IDE

Thanks to Henri Gourvest, there is now also an IDE program called LPSolve IDE that uses the API to provide a Windows application to solve models. See LPSolve IDE for its usage. With this program you don't have to know anything of API or computer programming languages. You can just provide your model to the program and it will solve the model and give you the result.

As already stated, lp_solve can be called from many programming language. Among them are C, C++, Pascal, Delphi, Java, VB, C#, VB.NET, Excel. But let this list not be a limitation. Any programming language capable of calling external libraries (DLLs under Windows, Shared libraries (.so) under Unix/Linux) can call lp_solve.

Some key features of lp_solve

  • Mixed Integer Linear Programming (MILP) solver
  • Basically no limit on model size
  • It is free and with sources
  • Supports Integer variables, Semi-continuous variables and Special Ordered Sets
  • Can read model from MPS, LP or user written format
  • Models can be build in-memory without the use of files
  • Has a powerful API interface
  • Easy callable from other programming languages
  • Advanced pricing using Devex and Steepest Edge for both primal and dual simplexes
  • Provides different scaling methods to make the model more numerical stable
  • Has presolve capabilities to tighten constraints/make the model smaller and faster to solve
  • Has a base crashing routine to determine a starting point
  • Allows restart after making changes to the model. Solve continues from the last found solution
  • Possible to select desired combinations of primal and dual phases 1 and 2
  • Possible to set several solver parameters like tolerances
  • Alternative (and faster) inverse/re-factorisation libraries are provided for. See Basis Factorization Packages
  • Alternative model readers and writers possible via the XLI implementation. See External Language Interfaces
  • Has the possibility to convert one model format to another format
  • Provides post-optimal sensitivity analysis. See Sensitivity
  • ...

Quick quick start

Formulating a problem

If you don't know much about linear programming, first take a look at Formulation of an lp problem in lpsolve. Start with reading the first part where a practical example is presented until the point where the formulation is given in mathematical format, then return to here. This practical example is used in the next presentations.

Another very usefull and free paper about linear programming fundamentals and advanced features plus several problems being discussed and modeled is Applications of optimization with Xpress-MP. It describes linear programming and modeling with the commercial solver Xpress-MP, but is as usefull for other solvers like lp_solve. In case that this link would not work anymore, try this via google search.

Solve a problem via the IDE

The easiest way to start with lp_solve is via the IDE. This only works under Windows. See LPSolve IDE.

Solve a problem via the lp_solve command line program

Another way to solve a model is via the lp_solve command line program. This works on any platform, but is completely command-line driven. Well known by Unix/Linux shell programmers and DOS box users. See lp_solve command.

solve a problem via the API

Programmers want to call lp_solve in a totally different way. They want to call lp_solve as a library directly from their programming language. This is what is called the API (Application Programming Interface). See Calling the lpsolve API from your application and Construct the model from a Programming Language. An overview of the complete API can be found on: lp_solve API reference.

Compile the source code yourself

The distribution contains precompiled libraries/binaries for Windows and Linux. However lp_solve can be compiled on other platforms also. You may also to make modifications to it and then you have to recompile also, even on the precompiled platforms. See Calling the lpsolve API from your application. In this article it is both explained how to link your code to the library and how to compile the lp_solve code.

Basis Factorization Packages

Alternative inverse/re-factorization libraries can be used by lp_solve. This is a feature for the more experienced users of lp_solve. See Basis Factorization Packages for more information. The sources of these packages are in the lp_solve_5.5.2.11_bfp_*_source.tar.gz archives. The binaries are in the lp_solve_5.5.2.11_exe* archive.

External Language Interfaces

Alternative model readers and writers possible via the XLI implementation. Models expressed in format files other than lp or MPS format can also be read or written by lp_solve via this unique feature. See External Language Interfaces for more information. The sources of these packages are in the lp_solve_5.5.2.11_xli_*_source.tar.gz archives. The binaries are in the lp_solve_5.5.2.11_exe* archive.

Calling lp_solve from higher level Mathematical languages.

lp_solve can be called from AMPL, MATLAB, O-Matrix, Sysquake, Scilab, Octave, FreeMat, Euler, Python, Sage, PHP, R, Microsoft Solver Foundation.

You now have a pretty good idea what lp_solve is about.

./R.htm000666 000000 000000 00000031072 11361044040 010274 0ustar00000000 000000 Using lpsolve from R

Using lpsolve from R

R?

R is a language and environment for statistical computing and graphics. It is a GNU project which is similar to the S language and environment which was developed at Bell Laboratories (formerly AT&T, now Lucent Technologies) by John Chambers and colleagues. R can be considered as a different implementation of S. There are some important differences, but much code written for S runs unaltered under R.

R provides a wide variety of statistical (linear and nonlinear modelling, classical statistical tests, time-series analysis, classification, clustering, ...) and graphical techniques, and is highly extensible. The S language is often the vehicle of choice for research in statistical methodology, and R provides an Open Source route to participation in that activity.

One of R's strengths is the ease with which well-designed publication-quality plots can be produced, including mathematical symbols and formulae where needed. Great care has been taken over the defaults for the minor design choices in graphics, but the user retains full control.

R is available as Free Software under the terms of the Free Software Foundation's GNU General Public License in source code form. It compiles and runs on a wide variety of UNIX platforms and similar systems (including FreeBSD and Linux), Windows and MacOS.

The R environment

R is an integrated suite of software facilities for data manipulation, calculation and graphical display. It includes

  • an effective data handling and storage facility,
  • a suite of operators for calculations on arrays, in particular matrices,
  • a large, coherent, integrated collection of intermediate tools for data analysis,
  • graphical facilities for data analysis and display either on-screen or on hardcopy, and
  • a well-developed, simple and effective programming language which includes conditionals, loops, user-defined recursive functions and input and output facilities.

The term "environment" is intended to characterize it as a fully planned and coherent system, rather than an incremental accretion of very specific and inflexible tools, as is frequently the case with other data analysis software.

R, like S, is designed around a true computer language, and it allows users to add additional functionality by defining new functions. Much of the system is itself written in the R dialect of S, which makes it easy for users to follow the algorithmic choices made. For computationally-intensive tasks, C, C++ and Fortran code can be linked and called at run time. Advanced users can write C code to manipulate R objects directly.

Many users think of R as a statistics system. We prefer to think of it of an environment within which statistical techniques are implemented. R can be extended (easily) via packages. There are about eight packages supplied with the R distribution and many more are available through the CRAN family of Internet sites covering a very wide range of modern statistics.

We will not discuss the specifics of R here but instead refer the reader to the R website. Also see An Introduction to R

R and lpsolve

lpsolve is callable from R via an extension or module. As such, it looks like lpsolve is fully integrated with R. Matrices can directly be transferred between R and lpsolve in both directions. The complete interface is written in C so it has maximum performance.

There are currently two R packages based on lp_solve. Both packages are available from CRAN.

The lpSolve R package is the first implementation of an interface of lpsolve to R. It provides high-level functions for solving general linear/integer problems, assignment problems and transportation problems. The following link contains the version of the driver: lpSolve: Interface to Lp_solve v. 5.5 to solve linear/integer programs. It does not contain the lpsolve API. Only the higher level calls. Documentation for this interface can be found on: Interface to Lp_solve v. 5.5 to solve linear/integer programs
This driver is written and maintained by Sam Buttrey.

The lpSolveAPI R package is a second implementation of an interface of lpsolve to R. It provides an R API mirroring the lp_solve C API and hence provides a great deal more functionality but has a steeper learning curve. The R interface to lpsolve contains its own documentation. See An R interface to the lp_solve library for the driver.
This driver is written and maintained by Kjell Konis.

Installing the lpsolve driver in R

How to install the driver depends on the environment.

Windows

In the RGui menu, there is a menu item 'Packages'. From there a package can be installed from a CRAN mirror or from a local zip file.

R command line

Packages can also be installed from the R command line. This is a more general approach that will work under all environments.
Installing the package takes a single command:

The lpSolve R package:

  > install.packages("lpSolve")
and to install the lpSolveAPI package use the command:
  > install.packages("lpSolveAPI")
Note

The > shown before each R command is the R prompt. Only the text after > must be entered.

Loading the lpsolve driver in R

Installing the package is not enough. It must also loaded in the R memory space before it can be used. This can be done with the following command:
  > library(lpSolveAPI)
Or
  > library("lpSolveAPI", character.only=TRUE)

Getting Help

Documentation is provided for each function in the lpSolve package using R's built-in help system. For example, the command

  > ?add.constraint
will display the documentation for the add.constraint function.

Building and Solving Linear Programs Using the lpSolve R Package

This implementation provides the functions lp, lp.assign, lp.object, lp.transport and print.lp. These functions allow a linear program (and transport and assignment problems) to be defined and solved using a single command.

For more information enter:

  > ?lp
  > ?lp.assign
  > ?lp.object
  > ?lp.transport
  > ?print.lp

See also Interface to Lp_solve v. 5.5 to solve linear/integer programs

Building and Solving Linear Programs Using the lpSolveAPI R Package

This implementation provides an API for building and solving linear programs that mimics the lp_solve C API. This approach allows much greater flexibility but also has a few caveats. The most important is that the lpSolve linear program model objects created by make.lp and read.lp are not actually R objects but external pointers to lp_solve 'lprec' structures. R does not know how to deal with these structures. In particular, R cannot duplicate them. Thus one must never assign an existing lpSolve linear program model object in R code.

To load the library, enter:

  > library(lpSolveAPI)

Consider the following example. First we create an empty model x.

  > x <- make.lp(2, 2)
Then we assign x to y.
  > y <- x
Next we set some columns in x.
  > set.column(x, 1, c(1, 2))
  > set.column(x, 2, c(3, 4))

And finally, take a look at y.

  > y
  Model name:
              C1    C2
  Minimize     0     0
  R1           1     3  free  0
  R2           2     4  free  0
  Type      Real  Real
  upbo       Inf   Inf
  lowbo        0     0
The changes we made in x appear in y as well. Although x and y are two distinct objects in R, they both refer to the same lp_solve 'lprec' structure.

The safest way to use the lpSolve API is inside an R function - do not return the lpSolve linear program model object.

Learning by Example
  > lprec <- make.lp(0, 4)
  > set.objfn(lprec, c(1, 3, 6.24, 0.1))
  > add.constraint(lprec, c(0, 78.26, 0, 2.9), ">=", 92.3)
  > add.constraint(lprec, c(0.24, 0, 11.31, 0), "<=", 14.8)
  > add.constraint(lprec, c(12.68, 0, 0.08, 0.9), ">=", 4)
  > set.bounds(lprec, lower = c(28.6, 18), columns = c(1, 4))
  > set.bounds(lprec, upper = 48.98, columns = 4)
  > RowNames <- c("THISROW", "THATROW", "LASTROW")
  > ColNames <- c("COLONE", "COLTWO", "COLTHREE", "COLFOUR")
  > dimnames(lprec) <- list(RowNames, ColNames)
Lets take a look at what we have done so far.
  > lprec  # or equivalently print(lprec)
  Model name:
              COLONE    COLTWO  COLTHREE   COLFOUR
  Minimize         1         3      6.24       0.1
  THISROW          0     78.26         0       2.9  >=  92.3
  THATROW       0.24         0     11.31         0  <=  14.8
  LASTROW      12.68         0      0.08       0.9  >=     4
  Type          Real      Real      Real      Real
  upbo           Inf       Inf       Inf     48.98
  lowbo         28.6         0         0        18
Now lets solve the model.
  > solve(lprec)
  [1] 0

  > get.objective(lprec)
  [1] 31.78276

  > get.variables(lprec)
  [1] 28.60000  0.00000  0.00000 31.82759

  > get.constraints(lprec)
  [1]  92.3000   6.8640 391.2928

Note that there are some commands that return an answer. For the accessor functions (generally named get.*) the output should be clear. For other functions (e.g., solve), the interpretation of the returned value is described in the documentation. Since solve is generic in R, use the command

  > ?solve.lpExtPtr
to view the appropriate documentation. The assignment functions (generally named set.*) also have a return value - often a logical value indicating whether the command was successful - that is returned invisibly. Invisible values can be assigned but are not echoed to the console. For example,
  > status <- add.constraint(lprec, c(12.68, 0, 0.08, 0.9), ">=", 4)
  > status
  [1] TRUE
indicates that the operation was successful. Invisible values can also be used in flow control.
Cleaning up

To free up resources and memory, the R command rm() must be used.
For example:

  > rm(lprec)

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from Scilab Using lpsolve from Microsoft Solver Foundation

./ratio.htm000666 000000 000000 00000036423 10505250166 011225 0ustar00000000 000000 Ratio's

Ratios

Constraints

Linear constraints are of the form:

a1 x1 + a2 x2 + a3 x3 + ... >= minimum

a1 x1 + a2 x2 + a3 x3 + ... <= maximum

Where minimum and maximum are constants.

lp_solve can only handle these kind of Linear equations. However sometimes there are tricks to convert an equation that seems non-Linear at first sight to a Linear equation. One of these is ratio's:

a11 x1 + a12 x2 + a13 x3 + ... <= minimum
a21 x1 + a22 x2 + a23 x3 + ...

On condition that a21 x1 + a22 x2 + a23 x3 + ... is positive, this is equal to:

a11 x1 + a12 x2 + a13 x3 + ... <= minimum * (a21 x1 + a22 x2 + a23 x3 + ...)

If the denominator is always negative, then it can be converted to:

a11 x1 + a12 x2 + a13 x3 + ... >= minimum * (a21 x1 + a22 x2 + a23 x3 + ...)

Let's continue with the case that the denominator is positive, then the equation is also equal to:

a11 x1 + a12 x2 + a13 x3 + ... - minimum * (a21 x1 + a22 x2 + a23 x3 + ...) <= 0

Or

(a11 - minimum * a21) x1 + (a12 - minimum * a22) x2 + (a13 - minimum * a23) x3 + ... <= 0

And there we have again a Linear equation. The same can be done for a maximum or equality of course. Don't forget that there is one assumption: the denominator is positive or negative. If it can be both, then this trick cannot be used.

One example of this is for example that it is required that two variables must have a ration of 1/2. For example:

x1 = 1/2
x2

With the formula above, this gives:

x1 - 0.5 x2 = 0

Adding this equation will result in the fact that x2 will be two times larger than x1. Again in the assumption that x2 stays positive.

Oh, and what if the denominator is zero? Division by zero is undefined and cannot give a real value. In the above example with two variables, if x2 is zero, then x1 is also forced to be zero. That is the side effect by converting the non-Linear equation to a Linear equation.

Objective function

max   c0 + c1 x1 + c2 x2 + c3 x3 + ...
      d0 + d1 x1 + d2 x2 + d3 x3 + ...

s.t.  ai1 x1 + ai2 x2 + ai3 x3 + ... <= bi
      xj >= 0

Note that c0 and d0 are constants. They are optional and not required for this solution.
Also note that the explanation uses <= constraints, but they can as well be >= constraints without any modification.
And as a last note, this text uses maximization of the objective function, but minimization works as good without any modification.

Linear programming only accepts models with equations in the first degree. The objective function however has a numerator and denominator so this seems not possible to solve with pure linear programming. However there is a trick to overcome to this problem. This model can be transformed to another model that is pure linear. When the solution is found to this transformed model, the results can be recalculated back to the original model.

There is only one condition to make this possible: the denominator must be strictly positive (or negative, but in that case you can multiply numerator and denominator by -1 such that the denominator becomes positive).

      d0 + d1 x1 + d2 x2 + d3 x3 + ... > 0

Again note the > sign. The denominator may also not become zero. If the transformed model returns a solution saying that it is zero, then the solution is invalid.

Now with this assumption in mind, we can introduce a new variable y0:

      y0 =                   1               
            d0 + d1 x1 + d2 x2 + d3 x3 + ...

Then the model can also be written as:

max   c0 y0 + c1 x1 y0 + c2 x2 y0 + c3 x3 y0 + ...

s.t.  ai1 x1 + ai2 x2 + ai3 x3 + ... <= bi
      y0 =                   1               
            d0 + d1 x1 + d2 x2 + d3 x3 + ...
      y0, xj >= 0

The constraints can also be multiplied by y0 and the y0 constraint can be written differently:

max   c0 y0 + c1 x1 y0 + c2 x2 y0 + c3 x3 y0 + ...

s.t.  ai1 x1 y0 + ai2 x2 y0 + ai3 x3 y0 + ... <= bi y0
      d0 y0 + d1 x1 y0 + d2 x2 y0 + d3 x3 y0 + ... = 1
      y0, xj y0 >= 0

Note again that this can only be done if y0 > 0

Now also make following substitution:

      yj = xj y0

Also put the bi y0 term to the left:

max   c0 y0 + c1 y1 + c2 y2 + c3 y3 + ...

s.t.  -bi y0 + ai1 y1 + ai2 y1 + ai3 y3 + ... <= 0
      d0 y0 + d1 y1 + d2 y2 + d3 y3 + ... = 1
      yj >= 0

All yj are variables (j starting from 0)

This new transformed model is an exact transformation of the original model, but with the advantage that it is a pure linear model. Also note that this model has one extra variable (y0) with coefficients in the matrix which are the negative of the right hand side (-bi y0). A constraint is also added requiring the constant term in the denominator times the new variable (d0 y0) plus the denominator terms involving the transformed variables to equal 1. The transformed model uses the same aij's as the original. Its right hand sides are all 0's except the one in the new constraint. The objective function does not have a denominator term and the objective function altered to include the numerator constant times the new variable y0.
This model can now be solved with lp_solve. Then to get the solution of the original model we must do a reverse transformation of this solution. This can be easily done:

      yj = xj y0
      
So:

      xj = yj / y0
Example

Suppose that it is desirable to solve the following problem.

max         1.8 x1 + 1.7 x2  
       10 + 4.0 x1 + 4.1 x2

s.t.  1.5 x1 +   x2 <= 6
      3.0 x1 + 4 x2 <= 20
      x1, x2 >= 0

Then the transformed problem is:

max            1.8 y1 + 1.7 y2

s.t.   -6 y0 + 1.5 y1 +     y2 <= 0
      -20 y0 + 3.0 y1 +   4 y2 <= 0
       10 y0 + 4.0 y1 + 4.1 y2 = 1
          y0, y1, y2 >= 0

The solution of this transformed model is:

Value of objective function: 0.289916

Actual values of the variables:
y1                      0.0420168
y2                        0.12605
y0                      0.0315126

Dual values with from - till limits:
                           Dual value            From            Till
R1                           0.342437     -0.03278689       0.1090909
R2                         0.04222689      -0.3076923       0.1156069
R3                           0.289916               0          1e+030
y1                                  0         -1e+030          1e+030
y2                                  0         -1e+030          1e+030
y0                                  0         -1e+030          1e+030

The value of the objective function of this transformed model is also the value of the objective function of the original model. The values of the original xi variables are calculated by dividing the yi values by y0:

x1 = y1 / y0 = 0.0420168 / 0.0315126 = 1.33333333
x2 = y2 / y0 = 0.12605 / 0.0315126 = 4

Plugging back into the original problem, the numerator equals 9.2; the denominator, 31.73, and their fraction 0.289916 (the objective function value reported). One may also recover the dual values or reduced costs. In this case since the rows are multiplied by one over the denominator, the original values may be recovered by dividing through by the denominator (1 / y0 or multiplying them by y0). Thus the effective dual value for constraint 1 is 0.01079, and constraint 2 is 0.0013307. Constraint 3 has no analogue in the original problem, and thus, is not transformed. The From - Till limits can also be recalculated back by dividing them by y0 and correcting these values with the bi y0 term.

Comments

This is an exact transformation as long as the denominator remains strictly positive. The formulation fails if y0 equals zero in the optimal solution. Much research has been done on fractional programming. The original development appears in Charnes and Cooper (1962). A historical perspective and literature review can be found in Schaible and Ibaraki.

Integer variables
Extra complexity arises if there are integer variables in the original model. Ie, one or more of the xi variables must be integer. Remember that:
yj = xj y0
and
y0 = 1 / denominator
Because of the latter, y0 is a real number. So yj is real, even if xj is integer. None of the xj variables are in the transformed model and from above you can see that you can't make the yj variables integer to have xj integer. So is it then not possible to define something that xj become integer?
Remember that
xj = yj / y0
Suppose that xj must take an integer value i:
yj / y0 = i
or
yj = i * y0
Unfortunately, this constraint can't be handled by lpsolve since it is quadratic.
However a special case of integer variables can be solved:
Binary variables
Binary variables are a special kind of integer variables. They can only take 0 or 1 values. From the previous section we know that
yj = i * y0
In this case is i either zero or one. If zero, then yj must be zero. If one, then yj = y0. If we can put this into the formulation, then the xj variables will be binary.

To make this possible, you must introduce extra binary variables: zj

When zj = 0, then it must make yj = 0 and when zj = 1, then it must make yj = y0

One way to make this possible is by doing the following.
First you must determine a constant value f1 for which you know that f1 > yj in all cases and f2 for which you know that f2 > y0 in all cases.

Then you can write:
yj <= f1 zj
yj - y0 - f2 zj >= -f2
yj - y0 + f2 zj <= f2
Two cases have to be considered:

1) zj = 0
yj <= 0
yj - y0 >= -f2
yj - y0 <= f2
or
yj = 0
-y0 >= -f2
-y0 <= f2
or
yj = 0
y0 <= f2
y0 >= -f2
since you have chosen the constant f2 such that it is always larger than y0, equations 2 and 3 are redundant in this case and yj is indeed 0. And from above, this means that xj will be 0.

2) zj = 1
yj <= f1
yj - y0 - f2 >= -f2
yj - y0 + f2 <= f2
or
yj <= f1
yj - y0 >= 0
yj - y0 <= 0
since you have chosen the constant f1 such that it is always larger than yj, equation 1 is redundant. Equations 2 and 3 together make that yj equals y0. And from above, this means that xj will be 1.

Of course your model becomes alot more complex. Per xj integer variable, you must introduce an extra binary variable zj and add 3 constraints for each. And you must have a guess for f1 and f2. Don't take a very very large number like 1e10 or something like this because that would make the model very unstable because of scaling/rouding errors. You must deduce from your model what these two factors can be. Maybe by first solving the model without integer constraints and determine f1 and f2 from this real result.

Using the example from above, now requiring that both x1 and x2 are integer. The result of the real model is:
Value of objective function: 0.289916

Actual values of the variables:
y1                      0.0420168
y2                        0.12605
y0                      0.0315126
From this, choose f1 and f2 being 10.

Now add the following constraints to this model:
y1 <= 10 z1
y1 - y0 - 10 z1 >= -10
y1 - y0 + 10 z1 <= 10

y2 <= 10 z2
y2 - y0 - 10 z2 >= -10
y2 - y0 + 10 z2 <= 10

int z1, z2
The solution of this model is:
Value of objective function: 0.19337

Actual values of the variables:
y1                      0.0552486
y2                      0.0552486
y0                      0.0552486
z1                              1
z2                              1

x1 = y1 / y0 = 1
x2 = y2 / y0 = 1
Indeed binary values.
./read_basis.htm000666 000000 000000 00000007504 10472053014 012175 0ustar00000000 000000 read_basis

read_basis

Read basis from a file and set as default basis.

unsigned char read_basis(lprec *lp, char *filename, char *info);

Return Value

Returns TRUE if basis could be read from filename and FALSE if not.
A FALSE return value indicates an error. Specifically file could not be opened or file has wrong structure or wrong number/names rows/variables or invalid basis.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

Filename to read the basis from.

info

When not NULL, returns the information of the INFO card in filename. When NULL, the information is ignored. Note that when not NULL, that you must make sure that this variable is long enough, else a memory overrun could occur.

Remarks

The read_basis function reads a basis from filename and sets it as initial basis of the lp.
Setting an initial basis can speed up the solver considerably. It is the starting point from where the algorithm continues to find an optimal solution.
When a restart is done, lp_solve continues at the last basis, except if set_basis, default_basis, guess_basis or read_basis is called.

The basis in the file must be in MPS bas file format.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;

  /* Read LP model */
  lp = read_LP("model.lp", NORMAL, "test model");
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  ret = read_basis(lp, "model.bas", NULL);

  ret = solve(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_basis, set_basis, default_basis, write_basis, guess_basis, get_basiscrash, set_basiscrash

./read_lp.htm000666 000000 000000 00000007267 10661574756 011542 0ustar00000000 000000 read_lp, read_LP

read_lp, read_LP

Create an lprec structure and read an lp model from file.

lprec *read_lp(FILE *stream, int verbose, char *lp_name);

lprec *read_LP(char *filename, int verbose, char *lp_name);

Return Value

Returns a pointer to a new lprec structure. This must be provided to almost all lp_solve functions.
A NULL return value indicates an error. Specifically file could not be opened or file has wrong structure or not enough memory available to setup an lprec structure.

Parameters

stream

Pointer to FILE structure.

filename

Filename to read the lp model from.

verbose

The verbose level. Can be one of the following values:
CRITICAL (1), SEVERE (2), IMPORTANT (3), NORMAL (4), DETAILED (5), FULL (6)

See also set_verbose and get_verbose.

lp_name

Initial name of the model. See also set_lp_name and get_lp_name. May be NULL if the model has no name.

Remarks

The read_lp and read_LP functions construct a new lprec structure and read the model from filename. read_lp needs a file pointer to an already opened file. read_LP accepts the name of the file. The latter function will generally be more convenient.

The model in the file must be in lp-format.

It is advised not to read/write the lprec structure. Instead, use the function interface to communicate with the lp_solve library. This because the structure can change over time. The function interface will be more stable.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"
int main(void)
{
  lprec *lp;

  /* Read LP model */
  lp = read_LP("model.lp", NORMAL, "test model");
  if(lp == NULL) {
    fprintf(stderr, "Unable to read model\n");
    return(1);
  }

  /* Model read */

  /*
  .
  .
  .
  */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp, write_lp, write_LP, write_lpex, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex

./read_mps.htm000666 000000 000000 00000012774 11247734012 011705 0ustar00000000 000000 read_mps, read_freemps, read_MPS, read_freeMPS

read_mps, read_freemps, read_MPS, read_freeMPS

Create an lprec structure and read an mps model from file.

lprec *read_mps(FILE *stream, int options);

lprec *read_freemps(FILE *stream, int options);

lprec *read_MPS(char *filename, int options);

lprec *read_freeMPS(char *filename, int options);

Return Value

Returns a pointer to a new lprec structure. This must be provided to almost all lp_solve functions.
A NULL return value indicates an error. Specifically file could not be opened or file has wrong structure or not enough memory available to setup an lprec structure.

Parameters

stream

Pointer to FILE structure.

filename

Filename to read the mps model from.

options

Specifies the verbose level and how to interprete the MPS layout.

The verbose level can be one of the following values:
CRITICAL (1), SEVERE (2), IMPORTANT (3), NORMAL (4), DETAILED (5), FULL (6)

See also set_verbose and get_verbose.

This can be ORed by any one of the following combinations:

MPS_FREE (8) The MPS format is free MPS format. If not specified, read_MPS and read_mps use by default the fixed MPS format. The option is not needed for read_freemps and read_freeMPS as these routine already interprete the file in free MPS format, but it is allowed to specify the option anyway. See also MPS file format
MPS_IBM (16) Interprete integer variables without bounds as binary variables. That is the original IBM standard. By default lp_solve interpretes variables without bounds as having no upperbound as for real variables. See also MPS file format (section G.)
MPS_NEGOBJCONST (32) Interprete the objective constant with an oposite sign. Some solvers interprete the objective constant as a value in the RHS and negate it when brought at the LHS. This option allows to let lp_solve do this also. See also MPS file format

Remarks

The read_mps, read_freemps, read_MPS, read_freeMPS functions construct a new lprec structure and read the model from filename. read_mps, read_freemps need a file pointer to an already opened file. read_MPS, read_freeMPS accepts the name of the file. The latter functions will generally be more convenient.

The model in the file must be in mps-format. The read_free* routines accept files only in free MPS format. The other routines by default accept files in fixed MPS format. However via the options parameter this can be set to free format also. That makes the read_free* routines obsolete, but they are kept for backward compatibility. The second argument of the routines was originally called verbose. This is extended from version 5.5.15 on to verbose with the possibility to add extra options.

It is advised not to read/write the lprec structure. Instead, use the function interface to communicate with the lp_solve library. This because the structure can change over time. The function interface will be more stable.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"
int main(void)
{
  lprec *lp;

  /* Read MPS model */
  lp = read_MPS("model.mps", NORMAL);
  if(lp == NULL) {
    fprintf(stderr, "Unable to read model\n");
    return(1);
  }

  /* Model read */

  /*
  .
  .
  .
  */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex, read_lp, read_LP, write_lp, write_LP, write_lpex

./read_params.htm000666 000000 000000 00000010657 10252334136 012365 0ustar00000000 000000 read_params

read_params

Read settings from a parameter file.

unsigned char read_params(lprec *lp, char *filename, char *options);

Return Value

Returns TRUE (1) if parameters could be read, else FALSE (0).

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

Filename to read the parameters from.

options

Optional options. Can be:
-h header: Read parameters at specified header. By default this is Default

Remarks

lp_solve parameters (options) are read from a parameter file. This file has an ini-format as used by Windows applications. All parameters are read from a header. This is by default [Default]. The header can be specified in the options parameter. Other headers are ignored.

Example parameter file:

[Default]
; lp_solve version 5.5 settings

anti_degen=ANTIDEGEN_FIXEDVARS + ANTIDEGEN_STALLING + ANTIDEGEN_INFEASIBLE
basiscrash=CRASH_NONE
improve=IMPROVE_DUALFEAS + IMPROVE_THETAGAP
maxpivot=250
negrange=-1e+006
pivoting=PRICER_DEVEX + PRICE_ADAPTIVE
presolve=PRESOLVE_NONE
presolveloops=2147483647
scalelimit=5
scaling=SCALE_GEOMETRIC + SCALE_EQUILIBRATE + SCALE_INTEGERS
simplextype=SIMPLEX_DUAL_PRIMAL
bb_depthlimit=-50
bb_floorfirst=BRANCH_AUTOMATIC
bb_rule=NODE_PSEUDONONINTSELECT + NODE_GREEDYMODE + NODE_DYNAMICMODE + NODE_RCOSTFIXING
;break_at_first=0
;break_at_value=-1e+030
mip_gap_abs=1e-011
mip_gap_rel=1e-011
epsint=1e-007
epsb=1e-010
epsd=1e-009
epsel=1e-012
epsperturb=1e-005
epspivot=2e-007
infinite=1e+030
;debug=0
;obj_bound=1e+030
;print_sol=0
;timeout=0
;trace=0
;verbose=NORMAL

Note that there are some options commented out (;). This is done because these options can not be used in general for all models or because they are debug/trace/print options. These options can be made active and will be read by read_params but note again that they are possible dangerous to be used in general (except for the debug/trace/print options). Note that there are two kind of entries:

  • Numerical values
  • Options

Numercial values can be integer values like maxpivot or floating point values like epsel

Options are a combination of constants as defined in the manual. Multiple options are added with +. For example option anti_degen.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  read_params(lp, "a.ini", "-h MyParams"); /* Will read parameters from file a.ini under section MyParams */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, write_params, reset_params

./read_XLI.htm000666 000000 000000 00000006271 10661575022 011540 0ustar00000000 000000 read_XLI

read_XLI

Create an lprec structure and read a model via the External Language Interface.

lprec *read_XLI(char *xliname, char *modelname, char *dataname, char *options, int verbose);

Return Value

Returns a pointer to a new lprec structure. This must be provided to almost all lp_solve functions.
A NULL return value indicates an error.

Parameters

xliname

Filename of the XLI package.

modelname

Filename to read the model from.

dataname

Filename to read the data from. This may be optional. In that case, set the parameter to NULL.

options

Extra options that can be used by the reader.

verbose

The verbose level. Can be one of the following values:
CRITICAL (1), SEVERE (2), IMPORTANT (3), NORMAL (4), DETAILED (5), FULL (6)

See also set_verbose and get_verbose.

Remarks

The read_XLI function constructs a new lprec structure and reads the model from filename via the specified XLI. See External Language Interfaces for a complete description on XLIs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"
int main(void)
{
  lprec *lp;

  /* Read LP model */
  lp = read_XLI("xli_MathProg", "model.mat", NULL, "", NORMAL);
  if(lp == NULL) {
    fprintf(stderr, "Unable to read model\n");
    return(1);
  }

  /* Model read */

  /*
  .
  .
  .
  */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp, write_lp, write_LP, write_lpex, read_mps, read_freemps, read_MPS, read_freeMPS, write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex, write_XLI, has_XLI, is_nativeXLI, set_XLI

./reset_basis.htm000666 000000 000000 00000004341 10237107364 012407 0ustar00000000 000000 reset_basis

reset_basis

Causes reinversion at next opportunity

void reset_basis(lprec *lp);

Return Value

reset_basis has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

This routine is ment for internal use and development. It causes a reinversion of the matrix at a next opportunity. The routine should only be used by people deeply understanding the code.
In the past, this routine was documented as the routine to set an initial base. This is incorrect. default_basis must be used for this purpose. It is very unlikely that you must call this routine.

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_basis, set_basis, default_basis, get_basiscrash set_basiscrash

./reset_params.htm000666 000000 000000 00000004042 10252334364 012566 0ustar00000000 000000 reset_params

reset_params

Resets parameters back to their default values.

void reset_params(lprec *lp);

Return Value

No return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

This routine resets parameters back to their default values.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  reset_params(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, read_params, write_params

./resize_lp.htm000666 000000 000000 00000007067 10564037636 012117 0ustar00000000 000000 resize_lp

resize_lp

Allocate memory for the specified size.

unsigned char resize_lp(lprec *lp, int rows, int columns);

Return Value

Returns TRUE if succeeded, FALSE if not.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

rows

Allocate memory for this amount of rows.

columns

Allocate memory for this amount of columns.

Remarks

The resize_lp function deletes the last rows/columns of the model if the new number of rows/columns is less than the number of rows/columns before the call.

However, the function does not add rows/columns to the model if the new number of rows/columns is larger. It does however changes internal memory allocations to the new specified sizes. This to make the add_constraint, add_constraintex, str_add_constraint and add_column, add_columnex, str_add_column routines faster. Without resize_lp, these functions have to reallocated memory at each call for the new dimensions. However if resize_lp is used, then memory reallocation must be done only once resulting in better performance. So if the number of rows/columns that will be added is known in advance, then performance can be improved by using this function.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 3);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  /* 1000 constraints will be added, so allocate memory for it in advance to make things faster */
  resize_lp(lp, 1000, get_Ncolumns(lp));

  /* Now add the 1000 constraints */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also copy_lp, delete_lp, free_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_column, add_columnex, str_add_column, add_constraint, add_constraintex, str_add_constraint

./Sage.htm000666 000000 000000 00000014006 11361044152 010754 0ustar00000000 000000 Using lpsolve from Sage

Using lpsolve from Sage

Sage?

Sage is free, open-source math software that supports research and teaching in algebra, geometry, number theory, cryptography, numerical computation, and related areas. Both the Sage development model and the technology in Sage itself are distinguished by an extremely strong emphasis on openness, community, cooperation, and collaboration: we are building the car, not reinventing the wheel. The overall goal of Sage is to create a viable, free, open-source alternative to Maple, Mathematica, Magma, and MATLAB.

We will not discuss the specifics of Sage here but instead refer the reader to the Sage website. Also see Sage Tutorial, Sage Tutorial (pdf), Sage Feature Tour and Sage For Newbies.

Sage and lpsolve

The primary implementation language of Sage is Python. Sage is build on top of Python. See Sage afterword.
Because there is already a link from lpsolve to Python (see Using lpsolve from Python), the link from Sage to lpsolve is in fact quite easy and ready available. Nothing special must be done except for installing the lpsolve Python driver.
lpsolve is callable from Sage via this Python extension or module. As such, it looks like lpsolve is fully integrated with Sage. Matrices can directly be transferred between Sage and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for Sage (especially for matrix support). So you have full control to the complete lpsolve functionality via the lpsolve Sage driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level script files that can make things a lot easier. See further in this article.

Sage is ideally suited to handle linear programming problems. These are problems in which you have a quantity, depending linearly on several variables, that you want to maximize or minimize subject to several constraints that are expressed as linear inequalities in the same variables.If the number of variables and the number of constraints are small, then there are numerous mathematical techniques for solving a linear programming problem. Indeed these techniques are often taught in high school or university level courses in finite mathematics.But sometimes these numbers are high, or even if low, the constants in the linear inequalities or the object expression for the quantity to be optimised may be numerically complicated in which case a software package like Sage is required to effect a solution.

Installation

To make this possible, the Python driver program is needed. This driver must be put in a directory known to Sage and Sage can call the lpsolve solver.
How this can be done can be read in the Python documentation: Using lpsolve from Python.

There is only one thing that must be considered: Sage comes with its own version of Python. So not the Python version that is already installed on the system (/usr/bin/python and /usr/lib/pythonx.y/*) is used, but a Python version in a subdirectory of the sage installation. For example /sage-3.4-linux-Ubuntu_8.10-i686-Linux/local/bin and /sage-3.4-linux-Ubuntu_8.10-i686-Linux/local/lib/pythonx.y/*

The consequence is that the lpsolve Python driver must also be installed on that place. The same installation files as for Python can be used, but they must be installed on the sage directory.
For example /sage-3.4-linux-Ubuntu_8.10-i686-Linux/local/lib/python2.5/site-packages. There lpsolve55.so, lp_solve.py, lp_solve.pyc, lp_maker.py, lp_maker.pyc and lpsolve55-5.5.0.6-py2.5.egg-info must reside after the installation.
See also Install the lpsolve driver for the installation of these files.

Solve an lp model from Sage via lpsolve

See Using lpsolve from Python. Everything that is written there also applies to sage.
Note however that the prompt is different.

Under Python the prompt is >>>
Under Sage the prompt is sage:

That is the only difference.

Sage also has a web interface called Sage Notebook. Also in this application lpsolve can be called in the same way.

Also note that you can enter the command load "filename" with filename a .py Python file with commands. The lpsolve examples (example1.py, ...) can be loaded and executed from the sage prompt as such.

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./scaling.htm000666 000000 000000 00000012534 10205775120 011523 0ustar00000000 000000 Scaling

Scaling

Scaling is a very important issue to consider in mathematical computations on a computer. A computer stores floating-point numbers with a limited precision because it uses a fixed number of bytes to store them. Consider for example the result of the following calculation: 1/3 In our metric system, the result of this computation cannot be represented with a finite number of digits. The value is 0.3333333333333... with an infinite number of digits. Because a computer only has a certain precision, the result is stored with a finite number of digits. For regular floating-point numbers this is about 15 digits, independent of its size. So this result would for example be stored as 0.333333333333333 on a computer. The computation of 100000000000000000/3 would be stored as 33333333333333300. In several cases, this is no problem. The stored value is close enough to the value that is needed. However, when doing calculations, problems can arise because of this. Especially if small and large values are added or subtracted from each other. In that case, the precision of the small number is lost. This can result in the effect that calculated values aren't correct anymore.

The more floating-point calculations are done, the more chance there is that numerical instability occurs and doing calculations with big and small numbers results in faster occurrence of this effect. Then there is also the effect of accumulating rounding errors which can result in a totally screwed up data matrix after having done several calculations.

The simplex algorithm is a typical iterating process where factors of thousands of floating calculations are done to find the optimal solution. The chance of numerical instability is then also quite big. But scaling not only improves numerical stability and minimizes rounding errors, it also improves performance. This may seem strange, but it is true. When a model is not scaled, the algorithm could reject certain pivot elements because they are too small and because of this, the solver doesn't choose the shortest route to the solution. If a model is proper scaled, this effect will not occur.

There are several ways to cope with this and it starts with the input data. The chance for numerical instability and rounding errors is considerably larger when the input data contains both large and small numbers. So to improve stability, one must try to work with numbers that are somewhat in the same range. Ideally in the neighbourhood of 1.

You should realize, that you the user are probably in a better position to scale the problem than any computer algorithm. The way to do this is: first choose appropriately scaled units for the extensive variables of the problem, e.g., kilo-tons instead of pounds, tankcar loads instead of gallons, millions of dollars instead of pennies, or nanometers instead of feet, so that the numerical spread of the coefficients in each single constraint, and in the objective function, will be at most one or two orders of magnitude; and then second scale the constraints themselves, by multiplying each entire constraint relation by an appropriate positive constant, so that the numerical spread of the coefficients in the different constraints is at most another one or two orders of magnitude. For example saying:

10000 x1 + 20000 x2 <= 30000

Can also be expressed as:

1 x1 + 2 x2 <= 3

lp_solve also has some build-in scaling routines which can take over this scaling job from the modeller or maybe better, to do additional scaling. This is implemented in such a way that it is transparent to the user. When scaling is done, lp_solve scales rows and/or columns, but the user doesn't see anything of this process. The returned values are still as if no scaling was done. See set_scaling for the possible scaling types. Note that lp_solve, by default doesn't do scaling. It must be invoked explicitly. Also note that even when scaling is enabled that integer variables are then again by default not scaled. To scale also integer variables, SCALE_INTEGERS must be added to the scale mode. This is done because of the nature of integer variables. If you want them integer, but you also scale them, then they aren't integer anymore. It is possible to scale those variables with the SCALE_INTEGERS flag, but some accuracy on being integer can be lost.

Conslusion. You should always do some sort of scaling. It starts when you design the model. Extra scaling can be accomplished by one of the scaling options of lp_solve.

./Scilab.htm000666 000000 000000 00000360432 13772705352 011317 0ustar00000000 000000 Using lpsolve from Scilab

Using lpsolve from Scilab

Scilab?

Developed at INRIA, Scilab has been developed for system control and signal processing applications. It is freely distributed in source code format.

Scilab is made of three distinct parts: an interpreter, libraries of functions (Scilab procedures) and libraries of Fortran and C routines. These routines (which, strictly speaking, do not belong to Scilab but are interactively called by the interpreter) are of independent interest and most of them are available through Netlib. A few of them have been slightly modified for better compatibility with Scilab's interpreter. A key feature of the Scilab syntax is its ability to handle matrices: basic matrix manipulations such as concatenation, extraction or transpose are immediately performed as well as basic operations such as addition or multiplication. Scilab also aims at handling more complex objects than numerical matrices. For instance, control people may want to manipulate rational or polynomial transfer matrices. This is done in Scilab by manipulating lists and typed lists which allows a natural symbolic representation of complicated mathematical objects such as transfer functions, linear systems or graphs.

Polynomials, polynomials matrices and transfer matrices are also defined and the syntax used for manipulating these matrices is identical to that used for manipulating constant vectors and matrices.

Scilab provides a variety of powerful primitives for the analysis of non-linear systems. Integration of explicit and implicit dynamic systems can be accomplished numerically. The scicos toolbox allows the graphic definition and simulation of complex interconnected hybrid systems.

Scilab has an open programming environment where the creation of functions and libraries of functions is completely in the hands of the user. Functions are recognized as data objects in Scilab and, thus, can be manipulated or created as other data objects. For example, functions can be defined inside Scilab and passed as input or output arguments of other functions.

In addition Scilab supports a character string data type which, in particular, allows the on-line creation of functions. Matrices of character strings are also manipulated with the same syntax as ordinary matrices.

Finally, Scilab is easily interfaced with Fortran or C subprograms. This allows use of standardized packages and libraries in the interpreted environment of Scilab.

The general philosophy of Scilab is to provide the following sort of computing environment:

  • To have data types which are varied and flexible with a syntax which is natural and easy to use.
  • To provide a reasonable set of primitives which serve as a basis for a wide variety of calculations.
  • To have an open programming environment where new primitives are easily added. A useful tool distributed with Scilab is intersci which is a tool for building interface programs to add new primitives i.e. to add new modules of Fortran or C code into Scilab.
  • To support library development through ``toolboxes'' of functions devoted to specific applications (linear control, signal processing, network analysis, non-linear control, etc.)

We will not discuss the specifics of Scilab here but instead refer the reader to the Scilab website and documentation.

Scilab and lpsolve

lpsolve is callable from Scilab via an external interface. As such, it looks like lpsolve is fully integrated with Scilab. Matrices can directly be transferred between Scilab and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for Scilab (especially for matrix support). So you have full control to the complete lpsolve functionality via the sclpsolve Scilab driver. If you find that this involves too much work to solve an lp model then you can also work via higher-level scripts that can make things a lot easier. See further in this article.

Quickstart

Compile and build sclpsolve:
----------------------------
  1. Get the needed sources and libraries: Archive lp_solve_5.5.2.11_scilab_source.tar.gz contains the sources to build sclpsolve. Uncompress it to a directory, for example d:\lp_solve. Make sure that the folder structure is kept. It will create a directory structure lp_solve_5.5\extra\scilab\lpsolve in that folder. Archive lp_solve_5.5.2.11_dev.zip (Windows) or lp_solve_5.5.2.11_dev.tar.gz (Unix) contains needed libraries and include files to link the sources with. Uncompress it to the same folder as for the sources, appended with lp_solve_5.5. In this example that would be d:\lp_solve\lp_solve_5.5 You have now all needed files in place. In your chosen directory (in this example d:\lp_solve) there will only be a directory lp_solve_5.5 In this directory, you have a directory extra and some files ending with .h and .lib The extra directory contains a scilab directory which contains a directory lpsolve with some files and directories. Under Windows, the lpsolve library lpsolve55.lib must be available in the lpsolve55 directory. However older version of scilab (<=3.0) require that this file is called lpsolve55.ilib In that case copy lpsolve55.lib to lpsolve55.ilib
  2. Under Windows, the Microsoft Visual C/C++ compiler must be installed and the environment variables must be active so that when a command prompt is opened, the cl and nmake commands can be executed. This can be done also by opening a command prompt and execute the batch file VCVARS32.BAT (somewhere on your system) and then starting scilab from that same command prompt. Under Unix/Linux, the standard c compiler is used so no special things must be done.
  3. Start Scilab
  4. Check under Scilab that the current directory is the lpsolve directory. Use the Scilab pwd command to show the current directory. With the chdir command, you can change the current directory. This current directory must be lp_solve_5.5/extra/scilab/lpsolve example: chdir('d:/lp_solve/lp_solve_5.5/extra/scilab/lpsolve')
  5. To compile and build sclpsolve, enter the following command in Scilab: -->exec builder.sce This should be done once to build the sclpsolve driver and to produce the file loader.sce.
Load the sclpsolve driver in the Scilab memory space: -----------------------------------------------------
  1. Under Windows, make sure that the lpsolve55.dll file is somewhere in the path Under Unix/Linux, make sure that the liblpsolve55.so shared library is in /usr/lib or /lib so that Unix can find it. They are in archives lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz and were installed in the lp_solve_5.5 directory of step 1 of the previous procedure.
  2. It is required that the sclpsolve driver is first build. That must be done only once. So if you haven't taken the steps yet to build the sclpsolve driver, then do this first as described previously in 'Compile and build sclpsolve'
  3. Start Scilab
  4. Check under Scilab that the current directory is the lpsolve directory. Use the Scilab pwd command to show the current directory. With the chdir command, you can change the current directory. This current directory must be lp_solve_5.5/extra/scilab/lpsolve example: chdir('/lp_solve/lp_solve_5.5/extra/scilab/lpsolve')
  5. Enter the following command in Scilab: -->exec loader.sce

Installation

To make this possible, a driver program is needed: sclpsolve (sclpsolve.dll under Windows, sclpsolve.a under Unix/Linux). This driver must be put in a directory known to Scilab and Scilab can call the sclpsolve solver.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux) (in archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). This has the advantage that the sclpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. For Windows, the lpsolve55.dll file must be somewhere in the path. For Unix, the lpsolve shared library (liblpsolve55.so) must be in the /usr/lib or /lib directory.

So note the difference between the Scilab lpsolve driver that is called sclpsolve and the lpsolve library that implements the API that is called lpsolve55.

There are also some Scilab script files (*.sce, *.sci) as a quick start.

The first thing that must be done, each time Scilab is restarted and you want to use lpsolve is load the sclpsolve driver into the Scilab workspace. This can be done via the script loader.sce. The following command must be used to load the driver:

exec loader.sce

It is assumed here that the current directory is the Scilab lpsolve directory (lp_solve_5.5/extra/scilab/lpsolve), but this is not a requirement. You can also provide the full path to the script files. The current directory can be shown via the pwd command in Scilab:

pwd

That is basically all you need to do. From now on, you can use the library. This until Scilab is restarted. Then this command must be given again to reload the library.

To make things easier, you can edit the file scilab.star with your favourite editor (or notepad/vi) in the Scilab directory and add above line at the end of this file. That will automatically load the lpsolve driver in memory when Scilab is started. So it will appear as if the sclpsolve command is then always available.

If you get an error similar to below, then probably the lpsolve library can not be found:

link failed for dll c:\lp_solve\lp_solve_5.5\extra\scilab\lpsolve\libs\sclpsolve.dll
addinter(liblpmex,'lpmex_gateway','sclpsolve')
                                               !--error   236
link: the shared archive was not loaded

Under Windows, the lpsolve55.dll file must be in one of the directories specified by the PATH environment variable. This path can be seen in Scilab via the command getenv("PATH"). It is common to place dlls in the WINDOWS\system32 folder.

Under Unix/Linux, the liblpsolve55.so file must be in the directory /usr/lib or /lib.

To test if everything is installed correctly, enter sclpsolve() in the Scilab command window. If it gives the following, then everything is ok:

sclpsolve  scilab Interface version 5.5.0.6
using lpsolve version 5.5.2.11

Usage: [ret1, ret2, ...] = sclpsolve('functionname', arg1, arg2, ...)

All this is developed and tested with Scilab versions 2.7 and 3.0 both under Windows and Linux (RedHat).

Solve an lp model from Scilab via sclpsolve

In the following text, --> before the Scilab commands is the Scilab prompt. Only the text after --> must be entered.

To call an lpsolve function, the following syntax must be used:

-->[ret1, ret2, ...] = sclpsolve('functionname', arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between (single or double) quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra Scilab specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in Scilab, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the Scilab functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from Scilab, nothing must be dimensioned in advance. The sclpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to sclpsolve. Never as argument to the routine. This can be a single value as for get_objective (although Scilab stores this in a 1x1 matrix) or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

Note that you can get an overview of the available functionnames and their arguments by entering the following in Scilab:

-->help sclpsolve

An example

(Note that you can execute this example by entering command per command as shown below or by just entering exec example1.sce. This will execute example1.sce.)

-->lp=sclpsolve('make_lp', 0, 4);
-->sclpsolve('set_verbose', lp, 3);
-->sclpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
-->sclpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
-->sclpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
-->sclpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
-->sclpsolve('set_lowbo', lp, 1, 28.6);
-->sclpsolve('set_lowbo', lp, 4, 18);
-->sclpsolve('set_upbo', lp, 4, 48.98);
-->sclpsolve('set_col_name', lp, 1, 'COLONE');
-->sclpsolve('set_col_name', lp, 2, 'COLTWO');
-->sclpsolve('set_col_name', lp, 3, 'COLTHREE');
-->sclpsolve('set_col_name', lp, 4, 'COLFOUR');
-->sclpsolve('set_row_name', lp, 1, 'THISROW');
-->sclpsolve('set_row_name', lp, 2, 'THATROW');
-->sclpsolve('set_row_name', lp, 3, 'LASTROW');
-->sclpsolve('write_lp', lp, 'a.lp');
-->sclpsolve('get_mat', lp, 1, 2)
 ans  =

    78.26

-->sclpsolve('solve', lp)
 ans  =

     0.

-->sclpsolve('get_objective', lp)
 ans  =

   31.782759

-->sclpsolve('get_variables', lp)
 ans  =

!   28.6      !
!   0.        !
!   0.        !
!   31.827586 !

-->sclpsolve('get_constraints', lp)
 ans  =

!   92.3      !
!   6.864     !
!   391.29283 !

Note that there are some commands that return an answer. To see the answer, the command was not terminated with a semicolon (;). If the semicolon is put at the end of a command, the answer is not shown. However it is also possible to write the answer in a variable. For example:

-->obj=sclpsolve('get_objective', lp)
 obj  =

    31.782759

Or without echoing on screen:

-->obj=sclpsolve('get_objective', lp);

The last command will only write the result in variable obj without showing anything on screen. get_variables and get_constraints return a vector with the result. This can also be put in a variable:

-->x=sclpsolve('get_variables', lp);

-->b=sclpsolve('get_constraints', lp);

It is always possible to show the contents of a variable by just giving it as command:

-->x

 x  =
!   28.6      !
!   0.        !
!   0.        !
!   31.827586 !

Don't forget to free the handle and its associated memory when you are done:

-->sclpsolve('delete_lp', lp);

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
-->lp=sclpsolve('make_lp', 0, 4);
-->sclpsolve('set_lp_name', lp, 'mymodel');
-->sclpsolve('set_verbose', 'mymodel', 3);
-->sclpsolve('set_obj_fn', 'mymodel', [1, 3, 6.24, 0.1]);
-->sclpsolve('add_constraint', 'mymodel', [0, 78.26, 0, 2.9], 2, 92.3);
-->sclpsolve('add_constraint', 'mymodel', [0.24, 0, 11.31, 0], 1, 14.8);
-->sclpsolve('add_constraint', 'mymodel', [12.68, 0, 0.08, 0.9], 2, 4);
-->sclpsolve('set_lowbo', 'mymodel', 1, 28.6);
-->sclpsolve('set_lowbo', 'mymodel', 4, 18);
-->sclpsolve('set_upbo', 'mymodel', 4, 48.98);
-->sclpsolve('set_col_name', 'mymodel', 1, 'COLONE');
-->sclpsolve('set_col_name', 'mymodel', 2, 'COLTWO');
-->sclpsolve('set_col_name', 'mymodel', 3, 'COLTHREE');
-->sclpsolve('set_col_name', 'mymodel', 4, 'COLFOUR');
-->sclpsolve('set_row_name', 'mymodel', 1, 'THISROW');
-->sclpsolve('set_row_name', 'mymodel', 2, 'THATROW');
-->sclpsolve('set_row_name', 'mymodel', 3, 'LASTROW');
-->sclpsolve('write_lp', 'mymodel', 'a.lp');
-->sclpsolve('get_mat', 'mymodel', 1, 2)
 ans  =

    78.26

-->sclpsolve('solve', 'mymodel')
 ans  =

     0.

-->sclpsolve('get_objective', 'mymodel')
 ans  =

   31.782759

-->sclpsolve('get_variables', 'mymodel')
 ans  =

!   28.6      !
!   0.        !
!   0.        !
!   31.827586 !

-->sclpsolve('get_constraints', 'mymodel')
 ans  =

!   92.3      !
!   6.864     !
!   391.29283 !

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific Scilab routine to get the handle from the model name: get_handle.
For example:

-->sclpsolve('get_handle', 'mymodel')
0

Don't forget to free the handle and its associated memory when you are done:

-->sclpsolve('delete_lp', 'mymodel');

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

In Scilab, all numerical data is stored in matrices; even a scalar variable. Scilab also supports complex numbers (a + b * %i with %i=SQRT(-1)). sclpsolve can only work with real numbers. Scilab also supports sparse matrices. Sparse matrices are matrices where only the non-zero elements are provided and stored. This results in both less storage and faster calculation if there are a sufficient number of zero values in the matrix and there usually are. The sclpsolve driver supports both dense and sparse matrices and their use is totally transparent to the user. Everywhere a matrix can be provided, it can be dense or sparse. However, Scilab requires for interface programs that sparse matrixes are converted to MATLAB sparse matrices via the function mtlb_sparse(mat). In the above example all matrices were dense. For example:
-->sclpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);

In sparse matrix notation, this can be written:

-->sclpsolve('add_constraint', lp, mtlb_sparse(sparse([0.24, 0, 11.31, 0])), 1, 14.8);

Most of the time, variables are used to provide the data:

-->sclpsolve('add_constraint', lp, a1, 1, 14.8);

Where a1 is a dense matrix variable. A sparse matrix is then provided as follows:

-->sclpsolve('add_constraint', lp, mtlb_sparse(a1), 1, 14.8);

The sclpsolve driver sees all provided matrices as sparse matrices. sclpsolve also uses sparse matrices internally and data can be provided sparse via the ex routines. For example add_constraintex. The sclpsolve driver always uses the ex routines to provide the data to lpsolve. Even if you call from Scilab the routine names that would require a dense matrix (for example add_constraint), the sclpsolve driver will always call the sparse version of the routine (for example add_constraintex). This results in the most performing behaviour. Note that if a dense matrix is provided, the dimension must exactly match the dimension that is expected by sclpsolve. Matrices with too few or too much elements gives an 'invalid vector.' error. Sparse matrices can off course provide less elements (the non provided elements are seen as zero). However if too many elements are provided or an element with a too large index, again an 'invalid vector.' error is raised.

Most of the time, sclpsolve needs vectors (rows or columns). In all situations, it doesn't matter if the vectors are row or column vectors. The driver accepts them both. For example:

-->sclpsolve('add_constraint', lp, [0.24; 0; 11.31; 0], 1, 14.8);

Which is a column vector, but it is also accepted.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the Scilab interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the Scilab matrix.

Sets

All numerical data is stored in matrices. Alphanumerical data, however, is more difficult to store in matrices. Matrices require that each element has the same size (length) and that is difficult and unpractical for alphanumerical data. In a limited number of lpsolve routines, alphanumerical data is required or returned and in some also multiple elements. An example is set_col_name. For this, Scilab sets are used.
To specify a set of alphanumerical elements, the following notation is used: cellstr([element1; element1; ...]).
Note the cellstr() function and the ; between each element.
An alternative is the Scilab makecell() function. For example makecell([1,3], element1, element2, element3).
Another alternative is the Scilab cell() function. For example x=cell(1,3); x(1).entries=element1; x(2).entries=element2; x(3).entries=element3

Don't forget that a set of strings must be provided. Don't make the mistake of using the syntax {element1, element2, ...} because then the following error occurs:

                                                                           !--error  9999
Invalid string matrix (at most one column!)
                                                                           !--error   999
SIGSTP: aborting current computation

And also not {element1; element2; ...} because then the following error is given:

                                                                           !--error  9999
invalid vector
                                                                           !--error   999
SIGSTP: aborting current computation

This is not an error generated by the sclpsolve driver, but from the Scilab parser because both are not sets.

Maximum usage of matrices/sets with sclpsolve

Because Scilab is all about matrices, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the sclpsolve Scilab driver to also work with matrices. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The sclpsolve Scilab driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = sclpsolve('set_int', lp, column, must_be_int). The matrix version of this call is: return = sclpsolve('set_int', lp, [must_be_int]). The API call to return the integer status of a variable is: return = sclpsolve('is_int', lp, column). The matrix version of this call is: [is_int] = sclpsolve('is_int', lp)
Also note the get_mat and set_mat routines. In Scilab these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by just entering exec example2.sce. This will execute example2.sce.)

-->lp=sclpsolve('make_lp', 0, 4);
-->sclpsolve('set_verbose', lp, 3);
-->sclpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
-->sclpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
-->sclpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
-->sclpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);
-->sclpsolve('set_lowbo', lp, [28.6, 0, 0, 18]);
-->sclpsolve('set_upbo', lp, [%inf, %inf, %inf, 48.98]);
-->sclpsolve('set_col_name', lp, cellstr(['COLONE';'COLTWO';'COLTHREE';'COLFOUR']));
-->sclpsolve('set_row_name', lp, cellstr(['THISROW';'THATROW';'LASTROW']));
-->sclpsolve('write_lp', lp, 'a.lp');
-->sclpsolve('get_mat', lp)
 ans  =

!   0.       78.26    0.       2.9 !
!    .24     0.       11.31    0.  !
!   12.68    0.        .08      .9 !

-->sclpsolve('solve', lp)
 ans  =

    0.

-->sclpsolve('get_objective', lp)
 ans  =

    31.782759

-->sclpsolve('get_variables', lp)
 ans  =

!   28.6      !
!   0.        !
!   0.        !
!   31.827586 !

-->sclpsolve('get_constraints', lp)
 ans  =

!   92.3      !
!   6.864     !
!   391.29283 !

Note the usage of %inf in set_upbo. This stands for 'infinity'. Meaning an infinite upper bound. It is also possible to use -%inf to express minus infinity. This can for example be used to create a free variable.

Starting from driver version 5.5.0.3, get_mat can also return the matrix in sparse format. By default the function returns it in dense format for backwards compatibility. However if a 3rd argument is provided that is non-zero, the returned matrix is sparse:

-->sclpsolve('get_mat', lp, 1)
 ans  =

(3,    4) m sparse matrix

(2,    1)         .24
(3,    1)        12.68
(1,    2)        78.26
(2,    3)        11.31
(3,    3)         .08
(1,    4)        2.9
(3,    4)         .9

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example:

-->A=sclpsolve('get_mat', lp);

-->X=sclpsolve('get_variables', lp);

-->B = A * X
 B  =

!   92.3      !
!   6.864     !
!   391.29283 !

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

-->sclpsolve('get_constraints', lp)
 ans  =

!   92.3      !
!   6.864     !
!   391.29283 !

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

-->C=sclpsolve('get_obj_fn', lp);

-->X=sclpsolve('get_variables', lp);

 obj  =

    31.782759

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

-->sclpsolve('get_objective', lp)
 ans  =

   31.7828

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
-->lp=sclpsolve('make_lp', 0, 4);
-->sclpsolve('set_verbose', lp, 3);
-->sclpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 2, 92.3);
-->sclpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 1, 14.8);
-->sclpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 2, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One could define all the possible constants in Scilab and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

-->lp=sclpsolve('make_lp', 0, 4);
-->sclpsolve('set_verbose', lp, 'IMPORTANT');
-->sclpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 'GE', 92.3);
-->sclpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 'LE', 14.8);
-->sclpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 'GE', 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

-->sclpsolve('set_verbose', lp, 'blabla');

BLABLA: Unknown.

-->sclpsolve('set_verbose', lp, 'GE');

GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. 'LE', 'GE' and 'EQ' in add_constraint and is_constr_type can also be '<', '<=', '>', '>=', '='. When returned however, 'GE', 'LE', 'EQ' will be used.

Also in the matrix version of calls, string constants are possible (hm). For example:

-->sclpsolve('set_constr_type', lp, cellstr(['LE'; 'EQ'; 'GE']));

Some constants can be a combination of multiple constants. For example set_scaling:

-->sclpsolve('set_scaling', lp, 3+128);

With the string version of constants this can be done as following:

-->sclpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_INTEGERS');

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

-->sclpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_RANGE');

SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

-->sclpsolve('get_scaling', lp)
 ans  =

    131.

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

-->sclpsolve('return_constants', 1);

From now on, all returned constants are returned as string:

-->sclpsolve('get_scaling', lp)
 ans  =

 SCALE_MEAN|SCALE_INTEGERS

Also when an array of constants is returned, they are returned as string when return_constants is set:

-->sclpsolve('get_constr_type', lp)
 ans  =


!"LE"  "EQ"  "GE"  !

This for all routines until return_constants is again called with 0:

-->sclpsolve('return_constants', 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

-->sclpsolve('return_constants', 1)
 ans  =

    1.

To get the value without setting it, don't provide the second argument:

-->sclpsolve('return_constants')
 ans  =

    1.

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

Script files

Scilab can execute a sequence of statements stored in diskfiles. Scilab has two kinds of these. The first kinds are ASCII files where Scilab commands are written in the same way as in the command window. These files normally have the extension .sce. These script files must be executed via the exec command. For example:

exec example1.sce

The second kinds are binary files. However the user enters the commands first in an ASCII file (normally with extension .sci) and then these are translated to binary files via the Scilab genlib command. The .sci files also may only contain Scilab commands. There are two advantages of using these. The first is that you don't have to use the exec command or provide the extension to execute them. So it is as if you execute a regular Scilab command. The second advantage is that they are somewhat faster.

The lpsolve distribution contains some sample .sce files that must be executed via exec and also some .sci high-level routines that can be executed without exec. They are already precompiled.

example1.sce

Contains the commands as shown in the first example of this article. Execute via exec example1.sce

example2.sce

Contains the commands as shown in the second example of this article. Execute via exec example2.sce

example3.sce

Contains the commands of a practical example. See further in this article.

example4.sce

Contains the commands of a practical example. See further in this article.

example5.sce

Contains the commands of a practical example. See further in this article.

example6.sce

Contains the commands of a practical example. See further in this article.

lp_solve.sci

This script uses the API to create a higher-level function called lp_solve. This function accepts as arguments some matrices and options to create and solve an lp model. See the beginning of the file or type help lp_solve to see its usage:

 LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

-->[obj, x]=lp_solve([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])
 x  =

!   1. !
!   2. !
 obj  =

    3.

Note that you can also provide sparse matrices to this function without having to use mtlb_sparse. The script is taking care of this.

lp_maker.sci

This script is analog to the lp_solve script and also uses the API to create a higher-level function called lp_maker. This function accepts as arguments some matrices and options to create an lp model. Note that this scripts only creates a model and returns a handle. See the beginning of the file or type help lp_maker or just lp_maker to see its usage:

-->help lp_maker

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            x >= vlb >= 0
            x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

-->lp=lp_maker([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])
 lp  =

    0.

To solve the model and get the solution:

-->sclpsolve('solve', lp)
 ans  =

    0.

-->sclpsolve('get_objective', lp)
 ans  =

    3.

-->sclpsolve('get_variables', lp)
 ans  =

!   1. !
!   2. !

Don't forget to free the handle and its associated memory when you are done:

-->sclpsolve('delete_lp', lp);

Note that you can also provide sparse matrices to this function without having to use mtlb_sparse. The script is taking care of this.

lpdemo.sce

Contains several examples to build and solve lp models. Execute via exec lpdemo.sce

ex.sce

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution. Execute via exec ex.sce

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

-->clear
-->X = 0.1:0.1:125;
-->Y1 = (15000. - 120*X)/210;
-->plot2d3(X, Y1)

Source

Now let's put in the other two constraint inequalities.

-->clear
-->X = 0.1:0.05:38;
-->Y1 = (15000. - 120*X)/210;
-->Y2 = max((4000 - 110.*X)./30, 0);
-->Y3 = max(75 - X, 0.);
-->Ytop = min(min(Y1, Y2), Y3);
-->plot2d3(X, Ytop)
-->xtitle("Solution space")

Source

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 the objective function P.

-->X = 15:20:35;
-->plot2d(X, (6315.63 - 143.0 * X) / 60.0)
-->xtitle("Solution space and objective")

Source

The line gives 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 line goes 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 (as shown here).

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 lp_solve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:

-->x = [1, 1; 110, 30] \ [75; 4000]
 x  =

!   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, 60] * x
 P  =

    6315.625

That is, $6315.625.

Note that these command are in script example3.sce

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            x >= vlb >= 0
            x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

-->f = [143, 60];
-->A = [120, 210; 110, 30; 1, 1];
-->b = [15000, 4000, 75];
-->lp = lp_maker(f, A, b, [-1, -1, -1], [], [], [], 1, 0);
-->solvestat = sclpsolve("solve", lp)
 solvestat  =

    0.

-->sclpsolve("get_objective", lp)
 ans  =

    6315.625

-->sclpsolve("get_variables", lp)
 ans  =

!   21.875 !
!   53.125 !

-->sclpsolve("delete_lp", lp);

Note that these command are in script example4.oms

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimentions, but beyound that it is all very theorethical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

-->f = [143, 60, 195];
-->A = [120, 210, 150.75; 110, 30, 125; 1, 1, 1];
-->b = [15000, 4000, 75];
-->lp = lp_maker(f, A, b, [-1, -1, -1], [], [], [], 1, 0);
-->solvestat = sclpsolve("solve", lp)
 solvestat  =

    0.

-->sclpsolve("get_objective", lp)
 ans  =

    6986.8421

-->sclpsolve("get_variables", lp)
 ans  =

!  0.        !
!  56.578947 !
!  18.421053 !

-->sclpsolve("delete_lp", lp);

Note that these command are in script example5.oms

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that Scilab can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like Scilab is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
-->f = [110*1.3, 30*2.0, 125*1.56, 75*1.8, 95*.95, 100*2.25, 50*1.35];
-->A = [120,210,150.75,115,186,140,85;110,30,125,75,95,100,50;1,1,1,1,1,1,1;
           1,-1,0,0,0,0,0;0,0,1,0,-2,0,0;0,0,0,-1,0,-1,1];
-->b = [55000, 40000, 400, 0, 0, 0];
-->lp = lp_maker(f, A, b, [-1,-1,-1,-1,-1,-1],[10,10,10,10,20,20,20],[100,%inf,50,%inf,%inf,250,%inf],[],1,0);
-->solvestat = sclpsolve("solve", lp)
 solvestat  =

    0.

-->sclpsolve("get_objective", lp)
 ans  =

    75398.043

-->sclpsolve("get_variables", lp)
 ans  =

!   10.       !
!   10.       !
!   40.       !
!   45.652174 !
!   20.       !
!   250.      !
!   20.       !

-->sclpsolve("delete_lp", lp);

Note that these command are in script example6.oms

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that %inf is used for variables that have no upper limit. This stands for Infinity.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using Scilab:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into Scilab format we get:

f = [4, 2, 1]
A = [2, 1, 0; 1, 0, 2; 1, 1, 1]
b = [1, 2, 1]

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0, 0, 0]
u = [ 1, 1, 2]

Now lets enter this in Scilab:

-->f = [4, 2, 1];
-->A = [2, 1, 0; 1, 0, 2; 1, 1, 1];
-->b = [1, 2, 1];
-->l = [ 0, 0, 0];
-->u = [ 1, 1, 2];

Now solve the linear program using Scilab: Type the commands

-->lp = lp_maker(f, A, b, [-1, -1, -1], l, u, [], 1, 0);
-->solvestat = sclpsolve("solve", lp)
 solvestat  =

    0.

-->sclpsolve("get_objective", lp)
 ans  =

    2.5

-->sclpsolve("get_variables", lp)
 ans  =

!   0.5 !
!   0.  !
!   0.5 !

-->sclpsolve("delete_lp", lp)

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the Scilab command:

-->l = [];

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -%inf as lower bounds:

-->l = [-%inf, -%inf, -%inf];

Solve this and you get a different result:

-->lp = lp_maker(f, A, b, [-1, -1, -1], l, u, [], 1, 0);
-->solvestat = sclpsolve("solve", lp)
 solvestat  =

    0.

-->sclpsolve("get_objective", lp)
 ans  =

    2.6666667

-->sclpsolve("get_variables", lp)
 ans  =

!   0.6666667 !
! - 0.3333333 !
!   0.6666667 !

-->sclpsolve("delete_lp", lp)

Overview of API routines

Note that everwhere where lp is used as argument that this can be a handle (lp_handle) or the models name.

  • add_column, add_columnex
    • return = sclpsolve('add_column', lp, [column])
    • return = sclpsolve('add_columnex', lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = sclpsolve('add_constraint', lp, [row], constr_type, rh)
    • return = sclpsolve('add_constraintex', lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = sclpsolve('add_SOS', lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in Scilab since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = sclpsolve('column_in_lp', lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = sclpsolve('copy_lp', lp)
    • No special considerations.
  • default_basis
    • sclpsolve('default_basis', lp)
    • No special considerations.
  • del_column
    • return = sclpsolve('del_column', lp, column)
    • No special considerations.
  • del_constraint
    • return = sclpsolve('del_constraint', lp, del_row)
    • No special considerations.
  • delete_lp
    • sclpsolve('delete_lp', lp)
    • No special considerations.
  • free_lp
    • sclpsolve('free_lp', lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = sclpsolve('get_anti_degen', lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = sclpsolve('get_basis', lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in Scilab. If not provided, then 0 is used.
  • get_basiscrash
    • return = sclpsolve('get_basiscrash', lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = sclpsolve('get_bb_depthlimit', lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = sclpsolve('get_bb_floorfirst', lp)
    • No special considerations.
  • get_bb_rule
    • return = sclpsolve('get_bb_rule', lp)
    • No special considerations.
  • get_bounds_tighter
    • return = sclpsolve('get_bounds_tighter', lp)
    • No special considerations.
  • get_break_at_value
    • return = sclpsolve('get_break_at_value', lp)
    • No special considerations.
  • get_col_name
    • name = sclpsolve('get_col_name', lp, column)
    • [names] = sclpsolve('get_col_name', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_column get_columnex
    • [column, return] = sclpsolve('get_column', lp, col_nr)
    • [column, return] = sclpsolve('get_columnex', lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = sclpsolve('get_constr_type', lp, row)
    • [constr_type] = sclpsolve('get_constr_type', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_constr_value
    • return = sclpsolve('get_constr_value', lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = sclpsolve('get_constraints', lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = sclpsolve('get_dual_solution', lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = sclpsolve('get_epsb', lp)
    • No special considerations.
  • get_epsd
    • return = sclpsolve('get_epsd', lp)
    • No special considerations.
  • get_epsel
    • return = sclpsolve('get_epsel', lp)
    • No special considerations.
  • get_epsint
    • return = sclpsolve('get_epsint', lp)
    • No special considerations.
  • get_epsperturb
    • return = sclpsolve('get_epsperturb', lp)
    • No special considerations.
  • get_epspivot
    • return = sclpsolve('get_epspivot', lp)
    • No special considerations.
  • get_improve
    • return = sclpsolve('get_improve', lp)
    • No special considerations.
  • get_infinite
    • return = sclpsolve('get_infinite', lp)
    • No special considerations.
  • get_lowbo
    • return = sclpsolve('get_lowbo', lp, column)
    • [return] = sclpsolve('get_lowbo', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_lp_index
    • return = sclpsolve('get_lp_index', lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = sclpsolve('get_lp_name', lp)
    • No special considerations.
  • get_mat
    • value = sclpsolve('get_mat', lp, row, col)
    • [matrix, return] = sclpsolve('get_mat', lp[, sparse])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix in the first return value. If sparse is different from zero then the returned matrix is a sparse matrix. The return code of the call is the second return value.
  • get_max_level
    • return = sclpsolve('get_max_level', lp)
    • No special considerations.
  • get_maxpivot
    • return = sclpsolve('get_maxpivot', lp)
    • No special considerations.
  • get_mip_gap
    • return = sclpsolve('get_mip_gap', lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = sclpsolve('get_nameindex', lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = sclpsolve('get_Ncolumns', lp)
    • No special considerations.
  • get_negrange
    • return = sclpsolve('get_negrange', lp)
    • No special considerations.
  • get_nonzeros
    • return = sclpsolve('get_nonzeros', lp)
    • No special considerations.
  • get_Norig_columns
    • return = sclpsolve('get_Norig_columns', lp)
    • No special considerations.
  • get_Norig_rows
    • return = sclpsolve('get_Norig_rows', lp)
    • No special considerations.
  • get_Nrows
    • return = sclpsolve('get_Nrows', lp)
    • No special considerations.
  • get_obj_bound
    • return = sclpsolve('get_obj_bound', lp)
    • No special considerations.
  • get_objective
    • return = sclpsolve('get_objective', lp)
    • No special considerations.
  • get_orig_index
    • return = sclpsolve('get_orig_index', lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = sclpsolve('get_origcol_name', lp, column)
    • [names] = sclpsolve('get_origcol_name', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_origrow_name
    • name = sclpsolve('get_origrow_name', lp, row)
    • [names] = sclpsolve('get_origrow_name', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_pivoting
    • return = sclpsolve('get_pivoting', lp)
    • No special considerations.
  • get_presolve
    • return = sclpsolve('get_presolve', lp)
    • No special considerations.
  • get_presolveloops
    • return = sclpsolve('get_presolveloops', lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = sclpsolve('get_primal_solution', lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = sclpsolve('get_print_sol', lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = sclpsolve('get_rh', lp, row)
    • [rh] = sclpsolve('get_rh', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_rh_range
    • return = sclpsolve('get_rh_range', lp, row)
    • [rh_ranges] = sclpsolve('get_rh_range', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_row get_rowex
    • [row, return] = sclpsolve('get_row', lp, row_nr)
    • [row, return] = sclpsolve('get_rowex', lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = sclpsolve('get_row_name', lp, row)
    • [names] = sclpsolve('get_row_name', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_scalelimit
    • return = sclpsolve('get_scalelimit', lp)
    • No special considerations.
  • get_scaling
    • return = sclpsolve('get_scaling', lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = sclpsolve('get_sensitivity_obj', lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = sclpsolve('get_sensitivity_objex', lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that Scilab allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = sclpsolve('get_sensitivity_obj', lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, Scilab always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = sclpsolve('get_sensitivity_rhs', lp)
    • [duals, dualsfrom, dualstill, return] = sclpsolve('get_sensitivity_rhsex', lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that Scilab allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = sclpsolve('get_sensitivity_rhs', lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = sclpsolve('get_simplextype', lp)
    • No special considerations.
  • get_solutioncount
    • return = sclpsolve('get_solutioncount', lp)
    • No special considerations.
  • get_solutionlimit
    • return = sclpsolve('get_solutionlimit', lp)
    • No special considerations.
  • get_status
    • return = sclpsolve('get_status', lp)
    • No special considerations.
  • get_statustext
    • return = sclpsolve('get_statustext', lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = sclpsolve('get_timeout', lp)
    • No special considerations.
  • get_total_iter
    • return = sclpsolve('get_total_iter', lp)
    • No special considerations.
  • get_total_nodes
    • return = sclpsolve('get_total_nodes', lp)
    • No special considerations.
  • get_upbo
    • return = sclpsolve('get_upbo', lp, column)
    • [upbo] = sclpsolve('get_upbo', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_var_branch
    • return = sclpsolve('get_var_branch', lp, column)
    • [var_branch] = sclpsolve('get_var_branch', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_var_dualresult
    • return = sclpsolve('get_var_dualresult', lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = sclpsolve('get_var_primalresult', lp, index)
    • No special considerations.
  • get_var_priority
    • return = sclpsolve('get_var_priority', lp, column)
    • [var_priority] = sclpsolve('get_var_priority', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • get_variables
    • [var, return] = sclpsolve('get_variables', lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = sclpsolve('get_verbose', lp)
    • No special considerations.
  • get_working_objective
    • return = sclpsolve('get_working_objective', lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = sclpsolve('guess_basis', lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
  • has_BFP
    • return = sclpsolve('has_BFP', lp)
    • No special considerations.
  • has_XLI
    • return = sclpsolve('has_XLI', lp)
    • No special considerations.
  • is_add_rowmode
    • return = sclpsolve('is_add_rowmode', lp)
    • No special considerations.
  • is_anti_degen
    • return = sclpsolve('is_anti_degen', lp, testmask)
    • No special considerations.
  • is_binary
    • return = sclpsolve('is_binary', lp, column)
    • [binary] = sclpsolve('is_binary', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • is_break_at_first
    • return = sclpsolve('is_break_at_first', lp)
    • No special considerations.
  • is_constr_type
    • return = sclpsolve('is_constr_type', lp, row, mask)
    • No special considerations.
  • is_debug
    • return = sclpsolve('is_debug', lp)
    • No special considerations.
  • is_feasible
    • return = sclpsolve('is_feasible', lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = sclpsolve('is_free', lp, column)
    • return = sclpsolve('is_unbounded', lp, column)
    • [free] = sclpsolve('is_free', lp)
    • [free] = sclpsolve('is_unbounded', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • is_infinite
    • return = sclpsolve('is_infinite', lp, value)
    • No special considerations.
  • is_int
    • return = sclpsolve('is_int', lp, column)
    • [int] = sclpsolve('is_int', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • is_integerscaling
    • return = sclpsolve('is_integerscaling', lp)
    • No special considerations.
  • is_maxim
    • return = sclpsolve('is_maxim', lp)
    • No special considerations.
  • is_nativeBFP
    • return = sclpsolve('is_nativeBFP', lp)
    • No special considerations.
  • is_nativeXLI
    • return = sclpsolve('is_nativeXLI', lp)
    • No special considerations.
  • is_negative
    • return = sclpsolve('is_negative', lp, column)
    • [negative] = sclpsolve('is_negative', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • is_piv_mode
    • return = sclpsolve('is_piv_mode', lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = sclpsolve('is_piv_rule', lp, rule)
    • No special considerations.
  • is_presolve
    • return = sclpsolve('is_presolve', lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = sclpsolve('is_scalemode', lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = sclpsolve('is_scaletype', lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = sclpsolve('is_semicont', lp, column)
    • [semicont] = sclpsolve('is_semicont', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • is_SOS_var
    • return = sclpsolve('is_SOS_var', lp, column)
    • [SOS_var] = sclpsolve('is_SOS_var', lp)
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Scilab matrix.
  • is_trace
    • return = sclpsolve('is_trace', lp)
    • No special considerations.
  • is_use_names
    • return = sclpsolve('is_use_names', lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = sclpsolve('lp_solve_version')
    • The sclpsolve API routine returns the version information in 4 provided argument variables while the Scilab version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = sclpsolve('make_lp', rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • sclpsolve('print_constraints', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
    • The same information can also be obtained via sclpsolve('get_constraints', lp). This shows the result on screen.
  • print_debugdump
    • return = sclpsolve('print_debugdump', lp, filename)
    • No special considerations.
  • print_duals
    • sclpsolve('print_duals', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
    • The same information can be obtained via sclpsolve('get_dual_solution', lp). This shows the result on screen.
  • print_lp
    • sclpsolve('print_lp', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
  • print_objective
    • sclpsolve('print_objective', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
    • The same information can be obtained via sclpsolve('get_objective', lp). This shows the result on screen.
  • print_scales
    • sclpsolve('print_scales', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
  • print_solution
    • sclpsolve('print_solution', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
    • The same information can also be obtained via sclpsolve('get_variables', lp). This shows the result on screen.
  • print_str
    • sclpsolve('print_str', lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
  • print_tableau
    • sclpsolve('print_tableau', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Scilab (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the sclpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows Scilab) to the command window of Scilab. As such, all reported output can be seen in Scilab. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = sclpsolve('read_basis', lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = sclpsolve('read_freemps', filename {, options})
    • lp_handle = sclpsolve('read_freeMPS', filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In Scilab it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = sclpsolve('read_lp', filename {, verbose {, lp_name}})
    • lp_handle = sclpsolve('read_LP', filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In Scilab it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ('').
  • read_mps, read_MPS
    • lp_handle = sclpsolve('read_mps', filename {, options})
    • lp_handle = sclpsolve('read_MPS', filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In Scilab it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = sclpsolve('read_params', lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = sclpsolve('read_XLI', xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, '' (NULL) is taken. '' is taken as NULL.
    • options is optional. When not provided, '' is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • sclpsolve('set_basisvar', lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = sclpsolve('set_add_rowmode', lp, turnon)
    • No special considerations.
  • set_anti_degen
    • sclpsolve('set_anti_degen', lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = sclpsolve('set_basis', lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
  • set_basiscrash
    • sclpsolve('set_basiscrash', lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • sclpsolve('set_bb_depthlimit', lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • sclpsolve('set_bb_floorfirst', lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • sclpsolve('set_bb_rule', lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = sclpsolve('set_BFP', lp, filename)
    • No special considerations.
  • set_binary
    • return = sclpsolve('set_binary', lp, column, must_be_bin)
    • return = sclpsolve('set_binary', lp, [must_be_bin])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = sclpsolve('set_bounds', lp, column, lower, upper)
    • return = sclpsolve('set_bounds', lp, [lower], [upper])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • sclpsolve('set_bounds_tighter', lp, tighten)
    • No special considerations.
  • set_break_at_first
    • sclpsolve('set_break_at_first', lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • sclpsolve('set_break_at_value', lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = sclpsolve('set_col_name', lp, column, name)
    • return = sclpsolve('set_col_name', lp, [names])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_column, set_columnex
    • return = sclpsolve('set_column', lp, col_no, [column])
    • return = sclpsolve('set_columnex', lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = sclpsolve('set_constr_type', lp, row, con_type)
    • return = sclpsolve('set_constr_type', lp, [con_type])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • sclpsolve('set_debug', lp, debug)
    • No special considerations.
  • set_epsb
    • sclpsolve('set_epsb', lp, epsb)
    • No special considerations.
  • set_epsd
    • sclpsolve('set_epsd', lp, epsd)
    • No special considerations.
  • set_epsel
    • sclpsolve('set_epsel', lp, epsel)
    • No special considerations.
  • set_epsint
    • sclpsolve('set_epsint', lp, epsint)
    • No special considerations.
  • set_epslevel
    • sclpsolve('set_epslevel', lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • sclpsolve('set_epsperturb', lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • sclpsolve('set_epspivot', lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = sclpsolve('set_free', lp, column)
    • return = sclpsolve('set_unbounded', lp, column)
    • No special considerations.
  • set_improve
    • sclpsolve('set_improve', lp, improve)
    • No special considerations.
  • set_infinite
    • sclpsolve('set_infinite', lp, infinite)
    • No special considerations.
  • set_int
    • return = sclpsolve('set_int', lp, column, must_be_int)
    • return = sclpsolve('set_int', lp, [must_be_int])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = sclpsolve('set_lowbo', lp, column, value)
    • return = sclpsolve('set_lowbo', lp, [values])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = sclpsolve('set_lp_name', lp, name)
    • In Scilab, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = sclpsolve('set_mat', lp, row, column, value)
    • return = sclpsolve('set_mat', lp, [matrix])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. Consider using a Scilab sparse matrix for maximum performance and least memory usage. The matrix must be two-dimentional.
  • set_maxim
    • sclpsolve('set_maxim', lp)
    • No special considerations.
  • set_maxpivot
    • sclpsolve('set_maxpivot', max_num_inv)
    • No special considerations.
  • set_minim
    • sclpsolve('set_minim', lp)
    • No special considerations.
  • set_mip_gap
    • sclpsolve('set_mip_gap', lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • sclpsolve('set_negrange', negrange)
    • No special considerations.
  • set_obj
    • return = sclpsolve('set_obj', lp, column, value)
    • return = sclpsolve('set_obj', lp, [values])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • sclpsolve('set_obj_bound', lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = sclpsolve('set_obj_fn', lp, [row])
    • return = sclpsolve('set_obj_fnex', lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
  • set_outputfile
    • return = sclpsolve('set_outputfile', lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In Scilab under Windows, output to stdout it not shown. However it results in closing the file. Use '' to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • sclpsolve('set_pivoting', lp, pivoting)
    • No special considerations.
  • set_preferdual
    • sclpsolve('set_preferdual', lp, dodual)
    • No special considerations.
  • set_presolve
    • sclpsolve('set_presolve', lp, do_presolve {, maxloops})
    • The maxloops argument is optional in Scilab. If not provided, then infinite is used.
  • set_print_sol
    • sclpsolve('set_print_sol', lp, print_sol)
    • No special considerations.
  • set_rh
    • return = sclpsolve('set_rh', lp, row, value)
    • return = sclpsolve('set_rh', lp, [values])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = sclpsolve('set_rh_range', lp, row, deltavalue)
    • return = sclpsolve('set_rh_range', lp, [deltavalues])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • sclpsolve('set_rh_vec', lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = sclpsolve('set_row', lp, row_no, [row])
    • return = sclpsolve('set_rowex', lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In Scilab, there is no unused element in the matrix.
  • set_row_name
    • return = sclpsolve('set_row_name', lp, row, name)
    • return = sclpsolve('set_row_name', lp, [names])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_scalelimit
    • sclpsolve('set_scalelimit', lp, scalelimit)
    • No special considerations.
  • set_scaling
    • sclpsolve('set_scaling', lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = sclpsolve('set_semicont', lp, column, must_be_sc)
    • return = sclpsolve('set_semicont', lp, [must_be_sc])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • sclpsolve('set_sense', lp, maximize)
    • No special considerations.
  • set_simplextype
    • sclpsolve('set_simplextype', lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • sclpsolve('set_solutionlimit', lp, simplextype)
    • No special considerations.
  • set_timeout
    • sclpsolve('set_timeout', lp, sectimeout)
    • No special considerations.
  • set_trace
    • sclpsolve('set_trace', lp, trace)
    • No special considerations.
  • set_upbo
    • return = sclpsolve('set_upbo', lp, column, value)
    • return = sclpsolve('set_upbo', lp, [values])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • sclpsolve('set_use_names', lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = sclpsolve('set_var_branch', lp, column, branch_mode)
    • return = sclpsolve('set_var_branch', lp, [branch_mode])
    • In Scilab, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = sclpsolve('set_var_weights', lp, [weights])
    • No special considerations.
  • set_verbose
    • sclpsolve('set_verbose', lp, verbose)
    • No special considerations.
  • set_XLI
    • return = sclpsolve('set_XLI', lp, filename)
    • No special considerations.
  • solve
    • result = sclpsolve('solve', lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = sclpsolve('time_elapsed', lp)
    • No special considerations.
  • unscale
    • sclpsolve('unscale', lp)
    • No special considerations.
  • write_basis
    • sclpsolve('write_basis', lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = sclpsolve('write_freemps', lp, filename)
    • return = sclpsolve('write_freeMPS', lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In Scilab it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = sclpsolve('write_lp', lp, filename)
    • return = sclpsolve('write_LP', lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In Scilab it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = sclpsolve('write_mps', lp, filename)
    • return = sclpsolve('write_MPS', lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In Scilab it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = sclpsolve('write_XLI', lp, filename {, options {, results}})
    • No special considerations.

Extra Scilab routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = sclpsolve('get_col_names', lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = sclpsolve('get_constr_types', lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = sclpsolve('get_int', lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = sclpsolve('get_no_cols', lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = sclpsolve('get_no_rows', lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = sclpsolve('get_objective_name', lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = sclpsolve('get_obj_fn', lp)
    [row_vec, return] = sclpsolve('get_obj_fun', lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = sclpsolve('get_problem_name', lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = sclpsolve('get_reduced_costs', lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = sclpsolve('get_row_names', lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = sclpsolve('get_solution', lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = sclpsolve('mat_elm', lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = sclpsolve('print_handle')
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = sclpsolve('read_lp_file', filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = sclpsolve('get_handle', lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = sclpsolve('return_constants'[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the sclpsolve driver

Windows, Unix/Linux

Under Windows, the sclpsolve Scilab driver is a dll: sclpsolve.dll
Under Unix/Linux, the sclpsolve Scilab driver is a static library sclpsolve.a
The library is an interface to the lpsolve55 library that contains the implementation of lp_solve. Under windows this is a dll lpsolve55.dll and under Unix/Linux it is a shared library liblpsolve55.so
They are distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). See at the beginning of this article where these files must be installed. The sclpsolve Scilab driver is just a wrapper between Scilab and lp_solve to translate the input/output to/from Scilab and the lp_solve library.

The sclpsolve Scilab driver is written in C. To compile this code, under Windows the Microsoft C compiler is needed and under Unix the standard compiler is used.
This compiler must be called from Scilab. To make the compilation process easier, a script can be used: builder.sce
To make everything, just enter exec builder.sce and everything is build.
This compiles the source files to the needed libraries, compiles the sci scripts and makes the manuals. It also generates a new loader.sce file to load the driver into the Scilab workspace.

This build process is the same under Windows and Unix/Linux. Note that builder.sce generates Makefiles that are then used to build the code. Don't edit the Makefiles since your changes will be lost when build.sce is executed again.

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Sysquake, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./Scilab1.jpg000666 000000 000000 00000065165 10252536726 011372 0ustar00000000 000000 JFIFExifII*1&i.Picasa0220 !|8b9ea5b65c4aebcc0000000000000000R980100 (HHJFIFC  !"$"$C" H !17AQS"2TUau6Vqt $BR%&3#43 !q34QRr1AS#B"ab ?&+iJO)ZVZo^cvR6+JCs(Iu+X iF7"(n-iXQ@MQSқ|ϩ$RX\ xNh"t+ z~P I}.$fg2QQ**Jg+a7խk_KV–yl YJ\iZ7X k4IO>w5Wn&VQ*tZHNsG)MJ5^m0ۨm2lSp-H牧%*ξFhW2+$ c˵0 l“rNGXkz9Q%{2ls[a:VhrEAǸm0 _ꒂ&%)uiJHP (J4Gr1m}VE'hq`^Ե%TեKm ŌFG3Y[l뭦I#4$ X) bF]<Ϋeebo.}+%7 1V36*X%@ +P)@ʶb`pE8b&\ue֠ V\t&.ة|&ܘ *eBRo!k$H*&0Íԧ^~U) 55AR5̋Xad bw7,"=jCtq3S {P(,#1ij9n0yR^%7C应rJax!!rJ`9n0M±#Su)JnyR<[L/2SpC应rJax!bG-Ԧ#S +9n1,z CiIsbt_!Ow ҡY&(U#KmwD¯*2bV^iRJHA<#KmwDva̸P 31:GkT&amjd,~iiuK@0OkX"Xy(vʧ)ǂ"8Hx2mHʽUTAF8| $^a()*:cpOS}T7CGU>Mv<peSgc@ T7AOS};4peSgcU>Mv<OS}T7CGU>Mv<peSgc@ T7GSV'df8e)m!h`jUQzuCž?CžCj̘\m[#KmwD!) HRT,pGDA[]."}tRm %*v;#/mɁ?hM1zBJ#mũ JAW$Ssj꘩}`]xEӴG;8J=-^l^D(] M%jyy ÌL08=-zu&yc}*Í:ڊTpF` An{eSimjMIՖB[Kb+nxPNa !;9CɩZ2\[cj} frJegiE’FD AACTҪ%3 RJ?t@~0S'v0S5mPڷ\+F0soJ}*G/@a/J&iO8jRP63?`;\^gbeM02&$= EQ gREģnfѻާ?RU!D=yx{n.Ӝax\AA@u΢RߪQ.WIRvvmF{t;3r YSvohh3˂   "x[a䧘66 N$mqNv'q=b swE\HY)N>q SuEaƶӝk`Om9؟CEFz SuA”]cXq=bNv'g>'tQą”]cp;XVk`Om9؟Aƶӝ4Yωgq!g;X)N>qNv'q=b swE\HY)N>q SuEaƶӝk`Om9؟CEFz SuDt, 4iN)P'`5'O"#a֎q >tm z,NQFZi&a&R{.+ȎOC"http://ns.adobe.com/xap/1.0/  .'"!#(7)#%(4(4-38(="')' & )2'&('2&('&&&'2&'&&&'2(&&&&&&&'&'&&&&'&&&&&&&&'&&'S !15U"ASTq23QVru#aB$4CRbDc%Fst: 2QR!4aq13A"SBC#r$ ?_%S^m_}~QwCYͥx~٬{MoFjV23(YټT쯗{Z=WKZc#QO]ڙcڙc8}8ڙc8}8ڙid8FjeCjϚ{%j"bퟴdI>78glcZ&V')[z0cJ9tz,"JJl90>9u; CEse׼-Mז'w0?fXY͖l1KQuN66<Ή-ikrlHn|+Vt\3ُ )LF-~#^h-f:'2I^$_,kKooeUUׇ>?~,K>WJgqh".H7?|!7ZiJ+~/96crOiL$3cr:FٜOstU4[} ]"j m55ԭ7w훃l34 ߉}/WZ1ag9{1BʈJF!-Kx/VaZ+W --lִ9/сǿm߈ *i:+p/oxvwE| Dm+.aOol˗[[KLNX4futCFI{-o*fZE=Y[.4V3M?yf\QoT4h)Y\famXxyo T3Wd7XV҆A[_`~Ϳbsdlѐ8ooF]]jj?k|Š*d58+]&DsF.F'{ o$]u>#آMuE= $;HnYK/&)6kq%q hҍ+ ڶg.C1f6! !؄3cblBC1f6! !؄3cb؄w1f6! !؄3cblBC1f6!rvS4utX6KS#bA=ml⬳*}4LplZ&AKM 8"e/Fr5V/6iNN 't3{~+3pmRoOȮ[6Xx*DeV-^9McDE,g)LǵŦ&U;cg4Մ if8,H*㣔{A%8_}kZS4Ma>|fҚgixj$vXxk!p96Ks&ai*svL%tWl%n t-0'MvuUvVwh_g8ik 5Tv|h;~Sq7ii45S2StJm,pq.unoie3C/ImTfM3x,y U|U*XC6?J3l6mLٳŭz)4\qe]"UX^5K0U,>Ӣ)O?Ty~x%*ǧo?4"'YpOlx f?ʟSO!)x%*}M<ȧo?4"'YpOlx f?ʟSO!)x%*Գٲ#K7Uߩ<>CdSK7Ty O,8'Si6Ds f?ʟSO!#K7Ty O,8'Si6E}j]لzūK,y/ܲB5}` vMd@nkZm{ JUcMªcH}ۨmK0_;V8 Z,W`_y̬Yi, ,F]S) QwR`xq|*ҷz.ErI>U{ۨ;kt@+0zjHU+.w]fe46Qg%VtiUXHo'u]%ޫ]BCR?YI+\7o)1*CJX SH涎6{Fb~iG:mF`ݭc9g{sᡸ!Z1AR@:5ng2[@[gx3nCA Qn'Le p[<8F>ohiƛK1NX H1Fl>;Y0 ֖us؇%&!3+嬫lkb\YS;2C!,ր[7(]J#OT]c*_l#Qʻ~BGRsre_ u:;Y$4U0dQe. lyL8ٍ 77m*#s`p>99`[k44 q'hlgعeMS 5!`aslADswx0} Nmɲr2 samhIQ4Xlncrc21kp??*v./5TxDQTvD;#CZf P>@?e'>$MQ$H؃)f {;Ic;\*GwMV,O$1e'm/ӱ.:\+6/ĘHgعO6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}O6}Mdx, Z/'k/ҭKFu|G%5(q2ci=Un .m,QMSZ[C :GDWYyxŦa@+Yb4(7Jf\e'M+d$@?l=1!ͥ)kKsbHȁ$b~ :X .02-.%1s;)6IҺ&BH CS^K]y^X+i,638d}~ڶYmnX_&XxޓGYy6 jJM~'5;V)bꇑ]G_*5%e =K|N'iY֟IUoҭ1آk# 4gpd|0G[wVmĩZ_P0@i(etD%5;o85)IW?BZYq ҘqO+* orp )xPCbLè+t'KQ3ce9#e,HB ?aEc_Bs?l3 y7a,\J%gfː91 uE#XȻ ,Hin0. yQntaEY,v]W%8{.=xae% D6Xے㕭$Q - c~! 7Vݻ>P`csq'k0Emq9H̯n&۹ٍlE7 K 1YO]UK0|F:kJM~'5;V)bj]G_*5%c D^))YHUV4DWz֖z%Z.Fu|G&xЧfZ#ߣV[4GKq_cZZ#Qk&ui_V;OBkt~_[nD@@A _l[+$v.e|YQ.A;$qFUq~pS:Qjњh@;Ui(Ol.1EP -Cevgvi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfsevi1P}_ wfse .lv{zHe|6˚k ֗$cƴG|*,]P6P=?!5>?2}yGtXP NJѯ: @@@@A.I~ǭihGUXlQʡ{~ YnBkQ?} e==~n;պMTKW.5UBڎ 7})9-wSANM&3c{H&bV/sэ'_=;w>'fVppA!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A?_URuLA@?Z\[_^uC?CH܄ޢ/[{z*wu" 1PeKT5;e;6@s1,ֱ7aSJ g,286ZevQ6 x v;ދv52tg;K1lg9\AރO#há#cL#0 'k+mrV}UI1irN+=lkKDw={R#`U #kJrSS-nqޭחh!KK<#)!VΙ񰴃M-mnnCCʚ߯f9]$n1ւ&iAj[ ]RC3Y:wAql v`>pxeKfnAlA1rV}UI1irN+=lkKDw=|R#`U #kJrzSS-^qޭכh&Ь6TIʉIw :B  +k*毚FFK.;$e0ccl nH <] *4NM=;'2v!ζ0\9t`~Y"x #.vEq" b Wz֖z%Z.Fu|G'5xЧfZ#ߣV[/4y]"Al0lsY_WOT-00;+K[vmζp7e=CO e; C NJѯ: @@@@A.I~ǭihGUXlQʡ{~ XBoQ?} e==~n;պM5AGcX$pRa8#coN9XarI2 |U9=p7k@z?Vz' :G.VrMbn,ri ؀A9+Fꘂ~'5;V~)bj]G_*5%c D^))YHUVʹD~np9lS5=66 eqMpn`[!n0hbOjZ291H-!ywOD ]fk7l. Ǎ;ְk8㬠zW_,HXiAA9+Fꘂ~'5;V~)bj]G_*5%c E|^))YHUV4Dx;V OdqekcK,xb? 9 ^ lV7Q T dF(Q\ֺML%#(.*k~ Ʊ: Hn,qFre: ]72K)=#}Gn9ihzF4 hq|"|A-9[pErV}UI1irN+=lkKDw=|R#`U #kJrSS-nqޭחh<] 7/ևќ/8 ,qrAzY.0-bfbTҙ*s=𹏊7U *2ŌBL£ +1lRjYTFa|tN{hceڛlc[0ys[cXVQ ^Yx"#0nsGPC 隳vW@}9.\rlAmݘ=Ob84R٨ff=DqAA @@@@@@@@@@@@@@@@@@@@@@A?_URuLA@?Z\[__?5E?CH܄梾/[{z*wu" kqDH9 5G= 92ҹG(6 q1kl.,HzC4Ө_]d6H p'kN(GKq_cZZ#k&ui_V;WBkt~_[nD@@@@AoIc0M[%Dayd u65mCyAacJ"Jzoـ!^8Z۵m> gsc+3s|׹ŧx0k NJѯ: @@@@A.I~ǭihGUXlQʡ{~ XBsQ_} e==~n;պM5˸~$ |U9=p7k@z/Uf)*S{&!8 O'%hTSP ֗$cƴG{*,MQr6P=?w!9>?2 yySS=y2hcOZ(J ݊œD\|vN6G)"\bM,1Ԕ텮},b47;}5-44;9Cedx2㖫 ,?Њct#uobw^!v X뮳F[KL HkXCpO S"@1!{H\ F耀A9+Fꘂ~y'5;V~)bꇑ]G_*5%e E|^))YHUV4D@o.sn)%Gd2S{YFsc~i>Dݸ<[4r+Ǯ  b Wz֖z%ZFu|G&xЧfZ#ߣV[/4x[쬏[_)50D*4r3MY0]?d2Ӽ.>`x D Z5U'T#8-(JKT\:T4y+Nj+OO̵GG­z^^i ywOD ±Zj|O t530xA pPz_VVSaC;aNjl$iyM$eYZqrV}UI1irN+=lkKDw={R#`U #kJrSS-nqޭחh91CƢ"si3FgiD2:JL:oٸA_9ho4r'ˌGۆ6й/ԓP&8E0y[ﬓ]_qUC3#y[,EF\: y͞EXnsnq6 }ֵ{@A<5LVǴ5"s\7A b Wz֖z%Z.Fu|G'5xЧfZ#ߣV[/4y]"At[{mRtg!3arCNAR9V*[5Ƿ#pw b ؄'kN(GKq_cZZ#Qk.yui_V[WBkt~_[nD@@@@AoKWc3E%PƮjIDQF%̔vAl#wX4=_Ou48>zwn |Oq"CpA9+Fꘂ~y'5;V~)bj]G_*5%c E|^))YHUV4D@o.skCe~Zvrc s Y.FчCFƙiF`|N װ!KK<#)!VΙ񰴃M-mnnCCʚ߯f9]$n1ւ&iA" : momiGվj(4:\].ӊNr] #/κw:>އ^z1{ Z5U'T#8-(JKT<:T4y+-Mj'OO̵GG­z_^i ǯ⩠=,>9rx-x7xV 0U_5Ud]vHad7sܐ}03$Ūvٻha{o%lc:h#$҉%7'36'wq_Pd ǣicY>;p.'{zIl6,͖{\ ǯ⩠=,>9rx-x71(iF%@.G4FOd 8g 6&ZYolMF[\|-61(iI4L叄ŕ}2cPպi$2"7#+ 6+d ͆mjmTd>}kZy-61CO$׺;2)#cw2C1wqB vP,O8ůac4C~mB_ŶSŒbߛ5ߺmkn ǧu\GIJnNg2lN& ⿔AOCOH깠,J$ܜ d ؝,L)A_al꥽o4msv{ ǣicY>vsP=7-}8/ge!+C0ډi0TUX nNw9ˑy;80qZݭ#WrեfhQZ0n9C zg\ᖻ+K4u1񺖮8CXiї;hs#ipnf)KIF)6:u=0d{дNjg寧l\ b7hu$LcijeӜ[iȽ쨥}Lm, ;r,b%n(ihO5$F7SGL2sbܒ!HGMSGU19_v s7̡٢n[1bPCapDi0GMB)L"G6c$8FGN]W @Ѩk1B6\f}c7A@@A7M[tdu`&Z^֎796&ۃrv`a&d종_TQ>hKGwU,fx߶qn(ihO5$F7SGL2sbܒ!H,>J+qJ0'5[5YhcZif斺_;o $Y} |]i]O(duـ_$2AyPSQabm G$0;nh &<Ɍ1I<}DFJjYHܷchk6e, :lqzjك(m-A~xd4Q, sY2#8-(JKT\:T4y+Nj+OO̵GG­z^^i ֗$cƴG|*׿,MQr6P=?w!9>?2 yy?Z\[__?uC?CH܄ޢ/[{z*wu"irN+=lkKDw=|R#`U #kJrژu++%tp n҃0Z%*|nպ hv h~3+S.g08V];D`pOvZAw9µ>&sj}߃L h~3+S.g08V];D`pOvZAw9µ>&sj}߃L h~3+S.g08V];D`pOvZAw9µ>&sj}߃L h~3+S.g08V];D`pOvZAw9µ>&sj}߃L h~3+S.g08V];D`pOvZAw9µ>&sj}߃L h~3+S.g08V];D`pOvZAw9µ>&sj}߃L h~3+S.g08V];D`5l8^,7,F/pʵ45X(*#_MQr6M#kvr:Sz1w4«ab1 cy@򟔋}m e|R#`U#kvr:++"d{cf"Ż["Ҫ2F*w:^kSihuq;򗦏MJۖ}wŁs/M,I^?y5+nYϔ4~jVܳ'_G, )zhԭgN'|X>Rɩ[rϴ}N.|Ri:8`\KG&m>uq;򗦏MJۖ}wŁs/M,I^?y5+nYϔ4~jVܳ'_G, )zhԭgN'|X>Rɩ[rϴ}N.|Ri:8`\KG&m>uq;򗦏MJۖ}wŁs/M,I^?y5+nYϔ4~jVܳ'_G, )zhԭgN'|X>Rɩ[rϴ}N.|Ri:8`\KG&m>uq;򗦏MJۖ}wŁs/M,I^?y5+nYϔ4~jVܳ'_G, )zhԭgN'|X>Rɩ[rϴ}N.|Ri:8`\KG&m>uq;򗦏MJۖ}wŁs/M,I^?y5+nYϔ4~jVܳ'_G, )zhԭgN'|X>Rɩ[rϴ}N.|Ri:8`\KG&m>uq;򗦏MJۖ}wŁs/M,I^?y5+nYϔ4~jVܳ'_G, )zhԭgN'|X>Rɩ[rϴ}N.|Ri:8`\KG&m>uq;򗦏MJۖ}wŁs/M,I^?y5+nYI0ys^bZx-7>SQr_Gƚd8Qb4c 1R18#k@7w.MMUS8^kMVs*MP6_ #k}l!F+_oibNOW_Gخmkǁxu"Wv<h:tv)A;GyֻMx5z;ε$]mkǁxu"Sk^< ^nwIbZjtwkHͭx5z;ε$}ּxZ.6<h:tv)A7GyֻMx5z;ε$]mkǁx u"W6<:tv)A;Gyֻ]׏W]EئּxZ.6<:t)A;GyֻMx5z;ε$]mkǁxu"Sk^< ^vwIbZjtwkH׏W]GئּxZ.6<h:tv)A7GyֻMx5z;ε$}mkǁxu"Sk^< ^vwIbZjwkH׏W]EئּxZ.sk^< ^vwIbA;GyֻMx5z;ε$]mkǁxu"Sk^< ^vwIbZjwkH׏W]EئּxZ.6<h:tv)A;GyֻMx5z;ε$]ּxZ.wk^< ^nwIbZjwkH׏W]EئּxZ.6<h:tv)A;GyֻMx5z;ε$]mkǁq+H׏W}X.RR=^AqHs7"ͶֹSLD`./Scilab2.jpg000666 000000 000000 00000062060 10252537332 011354 0ustar00000000 000000 JFIFbExifII*1&i.Picasa0220 !|b659ae42ce8449a10000000000000000R980100 (?HHJFIFC  !"$"$C" I  !17AQVau"Sq25Rs #3Bb$C5 q!134AQRSr"a# ?LדPfYs&UP\q2I42("kdڬnn Z]@x3ΰ/jQy2׳wseO~0nHD]8 Bne J˦X3YB8}ORf3}3xPR%;4bX'tgS[tD>)[-!$$ίn4Ўpc1Ʌ%t 9SIVhѰr8"Iڬ&g@QPq/}um`V*=&S\SBFn)TO Ͷ"]ɷ-쐢|,@܁Z7!E\YviMPE ^O`{Ž=#*Kd)t]K%$tSvGYשd%)]mIU]E*_*r3_*sn5ɉ;>3vsXd)*->IV(?ZZZY%22A?25M%!BvjY˸iuI*J H抄KhRԐ: )$m~+=bU!ʄS BT$=Up–4RV_j#` 9(2e9x5OƼZqǣn!%Dj@UjtY^V#"ҴX"XBR枚ؗygrl{.L%BB P7Er;tW!úrT. jQF0u*SOަSKʬ1׎)c w[>sxI0S԰갽N:96*NiR0ZDR:P$!zZf?S[i"ă7/q1--'V%0oH M5=\!@B=e&&%&[}iAmT"O0!1S8qR3MK ؐ@6 @%jb]qBдI"5ѯa6q\QSjo^2:IFڸB?ϕkSG}` x?wS~Cu=6]y\m[=v|"4_ΙdRh / R|"jq%H%JQs#us/mIq]nlXY^#ҡljmdht syRO!mK{#us/mIq;z6dڐKuJAZrt{cB|vg*[aS4)kЍ@:4hlc. !BB}[[=W6!6]'b^[vʮG:"۲,wV>bA*rYy_`ɘeZ-v hpX ӱ%cK/9 G}b^"(>V~L/\{/@~0#\ /+uGy]τ^bF0uYw-)̃e&/sS}SjKq!N_-1nZϘM g|Ng8=wӤF2BB !B;\}[5e+-w;ѵJFqk}ie[/4BTpADo:ܳVvIy٧[;,YyV3eY־1/+?ZܦCu=?wSCjܗպ`y;\^^2ԗ׻bKS窕6+Gn8ۙ Itƒm88g '܁m{crSf&1.-s-@I{^n8F޿lc.9 vud\Oy% N-G?F6\- )CvduyJ.x.D˥巰 Y}E \9 jZQqBʰ)/`l|4 xFvJ0&(PڐcGV)25yz4< %t$NdBӅ HJ|skg[Au%M\NRJi/lGH 06'-[6qI-o:M>HO;J ǚ:^2e2KC'Qsb:_B59=wysgK{6wdl My#f'%3?2&&3Hq .h<^vQ '$* USo5HP:ۏ.N|^v!+*p@4Q6fuUY>PmM܅nf(>Yfқ s A)$y[N8jВX%K6H4M dsLVةtJ[,TJr;th-LB9ONUҚjn(ZI* |o`o`Rʺ$e3zӲRhRM(ֈ:>+XVyEL4`loZjPwEr;EtW!úrT.伮6)0uäFl,=#TŴi$zhW:bVzEB^ifa9S\yHa#p޺{/eu~#K7u-2a!tĜ%loބ8Ko]߽d}X22ZeäC08Jo]p߽p޺zf.| d>dyHa#p޺z+eu~!]b|i äF$+eu~!^zC%1-"HI^zC ؆K7uc!%[:D3 ؇ [- oCKLtf"1' [-[\7b,E/̖o0AGú.[\7b)e&٦$q=jfbm-FJG9rI5 V=ɹx,Hx}ɣ"http://ns.adobe.com/xap/1.0/  !2+#%%& 1,04*8.8762+B(-/+  - 6+******---**66**--*-**----5***-**.*.-**-**6*-****R!"1QS35ATrt#26URa$q4BCbdsԳDe; 2!5RSq134A"QaBC#$ ?"sw+"+Q?>Z+Nj+8ĵ_ |G_Z>U~Һ$#FʷOo<e֯;+i|6(k{kyC_'8C_'8P.bNqsbNqsbNqsbNqsbNqsbNqsbNqw5sء\ء5sbNplP 9C_'86(k |ء5sbNplP 9C_'86(k |أw56(k.lP׼\ءxC^sb {͊56(k.lQ+)Nk"fv9ɬk6ݻ{<o1\Rտ:r| l[3\.b_}UӞ .-ms5ۧ} 5K cF2GD+,wUEDZػ|fosU2ڭ+g [+*?Ps ccy{rl:S]̩D'cdԥhmW݅p0ma:1?LS9#wln`?O:C!V[UdC?z1O曏,.w6|I{dl[73v08ɋ,JFtc<<:2;WŌSBYxMD4L]I%گGfVÛf/?[/'$9G3E랔EN#KZꨗS甕eU 1i_Sm+zT͑ZEUj3۰N5? 2Z:& jSO>J߱%&D+VlY3|IVZWeizе5.{[<ձ6G2-c\̨_dvN,eX9[6kZ1+Zڵ'߇SµFG]SNDvܓ=3qv-b|oZ~os~Ǜ쇬чM\R]=LEeoT%pV÷5ojxS,i$l^䍴/ljMIj7T9nTU[jn N}ڷl[?d].7R5{Z-O?QQZژ}Z;Ttt0i#{[V+UF5RŲE11iIJLYee(aך×ZB1"SM"jeձ#9;[9p+'Q4Ls`WGM+'|jֶȊ/MpaiO鶹ݺ~hެkפNnmƭvG":Gj?'/Sgb~ ʈgm:-bҭ\cY]O#˕M98|HJ5{S!ZҴ?]ȐD@6>ɪȈZTmU2aN2ھy5ůIKMձMG96$]kt[-μN$k*}VeKҿfY1BEXQg j1ڸimlE}vn;c sמ4y#÷m;GϙrƓ[XFH[QyvX1qƕeI[jc-Z_ff=6 –5FȞֽUTU]eMZl1).h6u 9ڸv;[*ae6vs,}dTr^k [r?*[RcU@C5U2wRע˕Rܦ3NUo 2ʔUS>ֲ8j[*UW*ܐeҲ1ZV4^|mQԕ9H7De|rUG$ʛ6ƫag Ӛ+:뚮eF ,O=U=n&YANc5rG1.*d2W{R N45(Ij$I,ݍkzj*W*r!%(q1?F-Ⱨd`/S#z ^F20Ld`/S#z ^F20LLdh/S#Az ^F24L%LqlLO67Znvmb7;e_k[V̵ox ='e|fev+ 1rؕq>=hbbB6ũqP*t{h$F[]?+aaÙ<IOj͹,YfhuNl{+1_)b偍s܊Lfz5UTD6QiӁYVUsU5D>fvOj\ؚ~]^L˫vTᜦ4c[}pk ?IVmXs#jFM j#vr'Hcյy5aҴڥo`\Z)䅰N|N"z9=ʖDND3وe66W+8BWs&3Cnzd_ RKw(JZH#35M.KW"_O_=v>^8ҕ74z- 1Zvx$GSR$UʎF5{j{';; |1vGOWwӰ 0g9aa=_φ5sN~ kg{Q{dsU.5T[wӰ߾ 0g9aa=_φ5sN~$Z*jZ;,hFeW+Zf9ɪvlc]{aa=_φ5wvlc]43L#ƻigGOWwӰ 0g9aa=_φ5sN84:z- k杆pit~[>q; |1vlc]43L#ƻigGOWwӰ 0g9aa=_φ5sN84:z- k杆pit~[>q; |1vlc]43L#ƻigGOWwӰ 0g9aa=_φ5sN84:z- k杆pgt~[>q; |1Ӱ g9a=_φ5sN83:z- k杆pgt~[>q; |1vlc]43<#ƻigxGOWwӰ g9a=_φ5z~lg7GxGOWo9 g1=_φy~9 ~g=A_~[> WgŸ png1qJy=tEܿ^Y|3p-> Zl:s#Yr6-?I⑺Hr%ZC>1s,r[w3 cQ3ε*ʈY-8F'a?WR|M/76j]H""nDUTETg+J6j] Z:lZ$/v;n{ϖj-k.G[k"ڥiV4dDUm芪wO6j]zPlԹ٩te~#%|1l5S@rrUSn[_as7| l,G*1W9^DK&gUUO6j]{AR҃f/7K^oJ 7ޔ5.oyy(6j\zPlԹ٩s{AR҃f/7K^oJ 7ޔ5.oyy(6j\zPlԹ٩s{AR҃f/7K^oJ 7ޔ5.oyy(6j\zPlԹ٩s{AR҃f/7K^oJ 7ޔ5.oyy(6j\zPlԹ٩s{AR҃f/7K^oJ 7ޔ5.oyy(6j\zPlԹ٩s{AR҃f/7K^oJ UU[ ]K42?6FiLŽ-W}#MII$q$ӾY jxU]ITUD]L'**)Wf>̦#Hh=5D($3""&+k/TV&{?xC%Z 6|HH`sK+کQ2Yʊ|ACX4j=dw[.fk@>G 6 Z^{i˛b#9sZ+s>ʩG)JDX妕֫ەQQ{UXL̾G;.vcʌeoqI6ASoQO/,#n-jʛ֔ˌ[cޛO0HgFEJʇQ-6Fb3,.ŽfI$4/ lL:':z9eIm%,GG2jU-aU<8Bp1 VzGC2wRMSXMmTF-$4~MWU]4UE{͕Uj"[>nG;%[r*lf"fUfE;kStm[y gGկ++3uw`핽'<*6<E??K#ϓWr5T22wYW{Kʊ]t^nMz,r[u9tp:ͮUƕ-ĈDDJiZ?NlԻN $SIOYvӵeGZze&vOmQG nnGXٵʰ=_#8ҽxȈ+Q'_Ki+_5/*S#Q&n"?57g.Q[EZJ#G +Xgk%mjT֯a-Q5s㣫j*S=ʍG9mlƧ5-RY&tR׶cUVdrTigt&o16L=U,j#ʫޱ*>K5R˱TpEQ]tuf6:zwj*_fLW+QT |{L5-ҎXWlg*IW-H餃 ^9W9tTD[qV9s&DxIO| S#6JXk&G"6 ~J3^z8˪ݹꁽAEW>9}+ژԒhޑ$ܰʬDjr!4kuKO>HYiXԹNVfDs;/%JH(Z嚭tnkYzdZ;[uDFN0ZvU 蒑dʦH>9cIElou92+Q\ptbE[FO%Tڎkt*rQO/,#'w4޴0oŎOzkP$@Sé6$5h5:7)c}32XճTT9ȻQCVmf:i""ϕ33%r:6EDsrHwh Yl|r>9RdG1r1U.__VȐImIdȑR̒"=X*v**I4s |k"U,S;퍹xɗ29TEi0fb9Vcǹřjݫ&%ke.!2YaŎ([,nW:+D%j6~dTV3|&Y굻Qf/h:sQ\5̖FKTTc HcD興"66+ֵ9TD+UUʪ2*)إ]W~|;:֔ xoMjTS/K2=6w u]7)cޚ+I!4 JL44Եl\~uWkֹKYA>*GSFµrHUNYF=U-w&͎L_b td{\l껚oZSgŎKzkP@4[|֦+>)3:,ձj>ž?fe\0 | <:*gRPom;;ޯ\4[ZLKz6JaKh5OF(#rUF1{9SP~/t{>7E,4^+e@}M_(?MnYAhStWEP~/t{>7E,4^+e@}M_(?MnYAhStWEP~/t{>7E,4^+e@}M_(?MnYAhStWEP~/t{>7E,4^+e@}M_(?MnYAhStWEP~/t{>7E,4^+e@}M_(?MnYAhStWEa~V w5`N*)إ]W~|;:֔ xoMjsxK*zūbǒ-UݙɶLʀt YgՁ8_b td{\6w u]7)cޚ+IgxaV:>w5`N*)إ]W~|;:֔cޚ+i9A zzż#`X#cr6< $T:԰j)ԾJɝ*bxtcYM#VHV5''^Fq`7ukUg*HV4Q[S#+]DɵP! 4TT9ΎʬeW:"Ytpp ߥEFiUμjV'[Λf0Mִ7ճ}oy$uMXeߗlitmӍDeC[KFڪ c'$9$[-ղQS(]k; 'lR.?>MzWsMJm65U#r[/8|Gu֟"@= mV#j%Y|DF,{VtUOvX&Zejپq:_˲E"rl7~QtnEFѪ9V*Y,W:NM7Tm-Si::ϰV?-E\tTDr-hX#ZG1r]kdGZ= E??K#ϓgpUzқx9-B5}!+ik1X˪dR܏ڙsD.%RV xn'aOY槑V==XW5SeڋoYZf3+uvL|5Ʋ]\/3*p֮)W+k\n[**NgxaV|^X%ёpGɳWSiiM`߇֡ZH~uP*X/h*QͺU]#3\ֻͲY,q:- D͢y"rF͈׊仕˕W* gxaV|^X%ёpG$+w4޴0oŎKzkP$@ԓ♘tڙ=3ؗ8oW'>X(Y)ݖ|/YջVrYy;T:}&dl8UK sW{ʉ,6G}rʭU-MܰJjHƺjyQjʊʠZT5m9}IHe[-?:>w5`N*)إ]W~MzWsMJlxoMjUfZOS9j+hY> p[,r:K,rF+T{U`gl/}u$0(#2G,rO^:1xJI5%uTD$^$LԶ^K] +IԋSIѪ슉'"]׺ph-+lhqj)"Q3*8UEU؈^P. qؒ9uѭYͻVʗڀoAֳ0ipQO/,#+w4޴0oŎKzkP$@?H^(P 5X|HeeI9t[U?lإ6 $i%HfF+^FʈU.=<KHĨcsfyQndo@:>w5`N*)إ]W~|;u:֔ xoMjybFR1"սd+v7+mڙ?@@ {gs$nk{Z=vNEED[azG Iw ~,TyxUr_2?cQ(VnH'݂5R*25:ֹUoɱlAֳ0ipQO/,#'w4޴߇֡[H~uP*эӴFє#T4M^F"%6V%EC!H`]QQQlt}u 3jTS/K2=D;:֔cޚ+i9+:5c쨪f&M.C^w1_#;T K>m3\GV&Gڦ-Y&`|W|.xj#mMs{eb=*$Ujl[T\{3hfkd7gLMe_=]k; 'lR.?Q&]N6~,r[Zi"UfRyUWRjr:).Wn5s?0cv {$YH!Zz8VdUj1Wn\(w]i/i  {gs$nk{Z=vNEED[4-.kkcb*gISbJFDntY.E\\{MX x)`FGgpUzқx9-B8#O{LU@v].P91r,K%VV:Y.Ve֠ YgՁ8_b td{\6w u]7)cޚ+IW:\V=RȺFHduLFrn͍K"v@z+p-0n)KrZ&Ъ=&dDLꫵfh-:>w5`N*)إ]W~MºWsMJmZTeDK%cQWMt9c|NrVbq~2A䘄 E Ro( ];K9^虶nm۰+@-]tMk* j-ʦr"gKb*R$:>w5`N*)إ]W~MºWsMJmw5`N*)إ]W~MºWsMJmfbPA w5`N*)إ]W~MºWsMJm65U#r[/8|Gu֟"@,=Ĵ-Z|A펒zY+v]g*"ks*@:>w5`N*)إ]W~|;u:֔ xoMjyZ~e ƴSH5nkY"+'DmRUUԺ: ]k; 'lR.?Q&]N6~,r[Zi"jBQR8[Heյ2M[%v@t|3,mvZ6iN7.dq֪+!$lLENEK.TTTT]TlGZ= E??K#IWSiiM`߇֡ZHIX\֬VƎTE{ъkQyVs^(<>E<2N {}2֭ڷk>uP*.֘65~WבΗ".EtTsY˭BAֳ0ipQO/,#l껚oZSo7%5V A8Fñ8cy߭z@SrWfg;*]eL^#L!tIaQ>G9eLX%\tbBjPO Dm|lGDW5WmoV'O³9,qSyig&w^3ʯKE3L^z+b}s_?S%[><5 k+QTsUvȶN_b td{\l껚oZSo7%5V v {$YH!Zz8VdUj1Wn\6USby%~|}k[fN+"7+n7ZtU84fPy"~|mk[n~Ŷ0PQrl&W,lj5ȉp4q?~IQ.ZzYa{h}vݛo-Xi[iU.ʲH]#_e3ek5L%^m`7 gM, $If["lh*oT hzZ36Mlՙ/l׵ `}oFs#m{mXcvra)iÞsFguP7QGKv,2ȱ:5uvezmphO>i潲_TZɭ~ͯ 0VQ\Ԇ"i$n/aѵ8v͛}٭kd,PϽn7_G!U)[uLѽ6K }t+Z2vo7lR.?>MzWsMJmą=n:]ºWsMJe xMjPy!cGGۂ>I=dz&VTK܉G0cޚIIgUNO=:i|re8ցTJN׎%VU$rCv^?镞* -nLq%j$߳bGSɧ:iGI絭?VDr[7'f;K+ cK4`x2m{Q|"Xvt_8d5(DkO/sOpGkP!S2Q4Hv9T } %iCDkO/sOpGkP!S2Q4Hv9T } %iCDirN(M|$;Zy{}SJ>_?֞^*PᒏCʧ8d5(hir(M|$;Zy{}CJ>_?֞^*PᒏCʧ8d5(hirN(M|$;Zy{}SJ>_?֞^*PᒏCʧ8d5(hir(M|$;Zy{}SJ>_?֞^*PᒏCʧ8d5(hir(M|$;Zy{}CJ>_?֞^*TᒏCʧ8d5(hir(M|$;Zy{}SJ>_?֞^*TᒏCʧ8d5(hir(M|$;Zy{}CJ>_?֞^*TᒏCʧ8d5(h}%iCDkO/sOpGkP!S2Q4Hv9T } %iCDkO/sOpGkP!S2Q4Hv9T } %iCDkO/sOpGkP!S2Q4Hv9T } %iCDkO/sOpGkP!S2LYJ̓S0Zy{}V MtܭY/s>˕{+E}G165;G[5mrY>Tm6DY/='^>p2¤fW%eZZv'./Scilab3.jpg000666 000000 000000 00000071613 10252540354 011357 0ustar00000000 000000 JFIFLExifII*1&i.Picasa0220 !|c05e10598a33875b0000000000000000R980100 ()HHJFIFC  !"$"$C" Q !1AQT"7Uaq 25SVtu#$B4CRs%3br6 3q!RS14AQraBb ?®N֚5%.([nI(q_2 S'{fZsJ׳Rvamk2@/{>^K)IQY5@̃u J;RiEh8yJ@WuWthiS)"jߡ-wq.y&kı?:+l9!)'08֗YHUU[P;2P!e:K% Y 6Hht 139)UkEU+j5Ȫ$r }](CsǓc7}ndAFNGZ=WF#RUG5T]Kl>ط\h^h^woGZT]Kl>ط\h^h^>vZTBKl)n'ֽ;9'};}9Ȩ)lWŻG'YvG'Yvo>o"ǎ[m8 t!D=99I>ܙh]65$(dr;3Z,M+] [UtL Gaў $HUݏeE;Z"*'?ϻ7A3EV]Cr.A 10o U])m.l&Y^%q6oy&T$knU-h<``xWcM.`<+KSjۚq4M:S@7M}%,N͚J?;tS)XZ)b&jhП%N݆e^N9VBd%RbVҔY$Xenbr˯:uIojP.ehOGy19+VeĂu01$Fͩ_32SHTúSn4Tn.[pR˺m *v #% gV2 īi*Xe o&lk_.+{I38ӡהf\Z,@+̼>Ix ]֧,{솲l-ѻ(Xz[m-H)H͋_"8 f5\=RktknWA?T! mbţ6-|Z>w" 6-|Z>bţq bţpeHkCf̸6Q U&s8Mv$ccy\J[βF[J)Pz$ccU&ČeNm/.@戫~+AvJ!SQƖ˪hRS@EsI>hsRrݨ[6xM,4 vR\m_QVd$1{dcфGw)2]I KG)^UEE+*ڏe:!RL:v^qwR#<"_^ARrݨkzWPq\"j4n]܋ep"_^ARrݨkzWPq\"j*)^UEE+*چ@ WU{0VWo0l$7yN) ڈ6'km;PXpEZCq?_U<7hL~U5۰h1"Smx1F1}kJ# T_k_;oچkm;PXpEZCq?_U<7hL~U5۰h1"AT{Vܐo-6?O8o? 36jqե$\D>W~W!Ox~/+EPde;v'!gY[oh  o;-brЂ   "A[Wʛho$^ n[jJH>xmbn,’8 )OӪ-_+B,Xnq$32ϵ2aĸҡ.?КM YJuv>]Sa)*ATebGOH߿x :%֖cY*I"9*+Z~5T_k_;oڀ/*מ_@8B"yEc'݀D pь~A*3OI i,t<ΰU^3.Ÿu]-$W~W!R}К=*-+Oa-6tj<$}C. =QѦr~dU.o{4m (@AAAԒ$-H    $.'",#7),01444-3,2<.'(&  +&*'&&'&1'&&&'2-&'&&'&*&'(&'&&'&'&''&&'&&&&&&'&'''&[   !"5Qt1RSU#2Aae$3qs6BEdv%4br&DFTuC913Qq!24R"Aa#BC$ ?Rs7aZf g|a_{ TF5q-̾m8mZ_ל!ƭiF2z:UU?8ĝ*q2A$LSt(12A$Q8ĝ*qFH8ĝ)1'JbdIҘ t&H8ĝ)1'Jbq:SdIҘ t&H8ĝ)1'JbdIҘ t&H8ĝ)1'JbdIҘ t&H8ĝ)1'JbdIҘ t&H8ĝ)1'JbdIҘ t&H~q䃌H &&H8ĉ1"bdH &&H8ĉ1"bdH (XBb'e\:9i&p2 1rikV-DDc=Νcnܮj?#Х z02z6Qfbb#Wkto߹jnU1anm|rZsgkzvOojޯҜ~ذx>.?],ԼZ>fN?ƇiNH)FCI33Ěۛ}TUͿ)pV6|1nj2 ؚ_|ͯ{~WSk6wTrU?oJRٚpҁHޖhkc(H-vٽ mo|?wW|]S5uQjd+3j#"{6_#VE-˲qJw<[ mMxRcb-UeΞPByF>Q6];/YSRcad}#SQF.4D.rY:.쾗B92h#cHbhqNz&ɟifmjsLL6gƴET$cŧp Z>% N%ޜعZX3s !ViN>8Kk!pfs 'YxS)6 8A݊gزYmMc嫽paA)X )③rcgcq&Ibgbvv\w6֧ng bb~øsŃ:j~?fgxA10138%;XwU&18s]6}MtzJ4Z(gǗܦmIתjZcdF?/T͊1j#klx^6ACŤijɄ]iN︞͹#HM+QS6>3>ڛ_-&T:I**픣jB-#ɽ [VwSLŊݞ\c1n63b(Cd9=Pᭊ,4Oڱn'{6js6<1?N1><_ R-D8,U҃@-S)X9_7+~m%nQo&8vtne3`,8|r| q (y,Fw"ކ?zi+vm͈ڵ>;9xlKV"qN hdiJ@C&gowRպYY̷b,')O)")بuvy},-g/y^lDژ3?"?aNOǵ> VnP8xTL#Q9}KKSKSK&L&L M.LM.]2]014e14`bitbit遉J`biS014&ҘSJ`biL M)ygSq*D託n.vb)Y׷>(SjS3R~]}GOĨ>dH_mgz5XE-UU+!cgv;t2|j,OeUrYz>zűf58 1ra2k;,ŽbEH>=mYk.o.1/8i? UYwz|/M/)l Yb|Mf<e|DU8L 33`pÄхaZf~0oHryK1?Rj۟?3j K&u1_)|/\O ĭQٱjd} 'oMپC}ƐM{8C֊Ve.+7s,IkFtaW ) OC@C-=pB3 U7Ō3QսѺō fڙ֒++1A1ӽDmVq)Lsrwh7z8Fν6bⲄA(C<NP#:{D@bŹݯk=upSk,?~4YlīHd-&(g0n=bIc󋽭!3׬FY>SHwlm[Mow\[ͫ6qM-#6lZYxb L+fX\45srmmry-krKn"16,Y1e{l^[r ^=ۛcHڌ<6=$̕ JT\h̄ص\,55ũi#8Eݪ䚢mh8۷wuBeKTo4F 'zt5Kl6  \Lȡ''golOKZv5us*cH?gqxi飍q'}6.(438-ՋV"6CA GYf;9,3jne~lI0C6`2l dقɳ1fc&M!0C6`2l dقɳ1fc&_1C6b2l dيɳ1f(c&PM1C6b2lES\Kk,O xf9#$"S wog_'R tlҫk,߱jZgL͘5A8iLke7[LqqEJxlk0`(@u$2Aڞf;s,ڏʟ1ݑ7Aa 7f&>>ZKQj*e1bͨ&1$4OzZAxwJׅ18x~<-X,\$$jZUVG' njSg!vnEsӛK&,+FO?Rf*Zy#PMdͻFz?/uٛ1RRTkcisSI:rc*Yv7&ߥ+ɗKUk @M.ꈩeV}&/o}_MPJ9 _ +ث}V'_3rR|}rgd*0JurN2 1a;gM)VW-۵XRoD}~jOx0*"q7f wzYvvSQz?~Ax5e#> H Ք4'#'VR|Ov_ '!r3)cftjO4/#'VR<ޯ^ YHO{z?~Ax5e']i\6!f2aѽYt~Ax5e'ߚ| ue3> H }~jG| )iOoWGO/y=_i? }~jg| )i_oWGO/y}_i? }~jG| )i_oWGO/y}_i? }~jG| )i_oWGO/y}_i? }~jG| )i_oWGO/y}_i? }~jG| )iOoWGO/ Ք4'#'VS<`ޯ^ YLM{z?~Ax5e36 H Ք4'#'VS<`ޯ^ YLM{z?~Ax5e36 H Ք4'#'VS<`ޯ^ YLM{z?}[]`M{z?}[t5u6 H utjgl_ViOoWGM}[t5u\U_5u7L U^u^y_i5^6x| d\3+u+F)H -ѺVصz[4[3rR|mrgd"<s|j߸h#L)Sl@%aun%@67bo';$/SWTS϶Ѵv cZHd`9݅{^Ni3 JהxG1y10ƪjȶ1B^EŠؽ?pJiTQ`AaUqRD:cޗmww}AZ$eX¾+`hj*yFFH.k_s۷% 2 ;! $f]e,՟ ',@䧫'(Rvfw߻8I+"+WѨšP2hɝIR*vpAȉh͙ޗwrw],ˣ@6@ 'kv˥)ocSt*Ifa}*/Lnn]f &?YɁ|rC4 jچi:'nډӻ~H;X&)g"\@OŦ()ml.Ih%6Y a<|`(04}?:"a!1bMKC.C0lE9;|V8k.sª1zjC~+E5KEo+p4'NK4R*sQ5LR񖥣;GXmPF5NʪMUgWv:+;왚B|SבFE͵tQ$[2ٌk/@ȗ5UC uUq*@'ffIٝdC4yS5ׅY4%\~EDI!< Qic3V`yԕtYRR84e$O$#Ʉ ɛLZ` q:r-m R{ NL朿ԩTko-sk;}kCM{b,u=} >' M`꥚2QLu6ېd ǥ۽8ؤ܈̽$Ds0@Y!gÏ5AGkhm;Jrg4O [ykY؏p7͵cZo+|c+>y=܋[Co甩BS9/*~U\{me~^Xx@@AWf{EK#q 9#g"SF#PPq{J%V%@8<5lu#zZNj|qݞRmy ޗAG)p򍤒'}tMˀFQ~J (qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?@MiC(qOt?A_jk02RDB6r2}gÏ5AGkhm;Jrg4O [ykY؏p7͵cZo+|c5X<<{eM0qWշ^t4xdQE4} c>mͽ{O_?fA @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A|˙zOtH$+>y=܋[Co甪^BS9/*~U\{me~^Xx@@@A<҄! d"""}?Jrk3bĄs e̽B$<YET{!)ɜӗ?t*mrgb=6uhiSq,E O_?fA @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A|˙zOtH$+>y=܋_Co甩BS9/*~U \{me~^Xx@@Al1WMYEWG G-U3b܈Zq`FdO 6D'ggf !qɕ:X226ehżY~?dj9tN-wlmk_}y\2)'aADr ;3lh?2 HV|8Td{)T섧&sN_TЪ5˭|Q>5O½ȱ:?.YA_ K2jhݴ@N+ѻ݈zQ^,Fi:z(Ȁ#6 rs0"3iqlON"m@F, 2fmA@A(F8h6#5C&Yۛs}(, 1TnT򑵾P˔;ݘ[{5Oo'bi$ٱI-{FȽ/gqmnd+9eq+iQC8mvxovݷ SWP5 5J )ٚ{owfgSh6O PEQNBp`L@bMq!&=G2^S  χjw"*iJF9uoj:F4ߩW"^q{{A@@@@@A 3i˛«gl9:9\{=/N DxPU:Kǖ<7AqNm6 [ G%DvdNVamx&Z#̜\UJ q` xj*rŎ3bk 6gmA耀?2 HV|8Td{)S섧&sN_TЪ5˵|Q>5O½ȱ:xF%ܘ \I 8ggoK: ΐ6-` N[P"df23.4h&GӒņͮi~ N\kB *~P" dHSSϥܟK0t }'u5)_DIi}/sgo2hl审<<ήuTG| P'"!8 X0& 1&nvvt#s/PgÏ5AGkhm;Jrg4O [ykY؏p7͵cZo+|c8=e= `ˇf7!"h$x6kgm{2QMvu4# ޝ$NMwv!nVg -猵G4}Q򣕘ms؛1i j  M"G9=Ϊ{oqU'f$m=.e= q:r-m R{ NL朿ԩTko-sk;}kCM{b,u7eH:'x`|wkKs8 :0V]lf/v'v81i) "&!l nMܜ -Fjچ\jZAZE/A@@@@@@@@@@@@ARUA8f`Bm=f ,UƾLf`fqw6'}>wwAuVc En5 [2jp}kjwhl审<<ήuTG| P'"!8 X0& 1&nvvt#s/PgÏ5AGkhm;Jrg4O [ykY؏p7͵cZo+|c8=e= e~s^P` .&f19]齝N\0r/-6Ά7,nWfb݂࡯⎲X+#i#-/n}G&**4MTde>bpY@?2 HV|8Td{)S섧&sN_TЪ5˵|Q>5O½ȱ:wBR)]'"$HٝůAbų T[P mKP3__4h6&dƲjH3q 74 ︙{. F@h`aaR"3I>C7*Z=`uQ́Gʎ\9= jw?2 HV|8Td{)S섧&sN_TЪ5˵|Q>5O½ȱ:3=f^Sޒ 0e^6I? NoKGgq}6 i$.?2 HV|8Td{)S섧&sN_TЪ5˵|Q>5O½ȱ:=0.)=6gDKOQ<p@N&ЍJDk3 ı`KB C;MO$9:HSbنSʶ3qsyI ݮލs g=sֽ訴C1\j -$ϽN[&h@@@@@@@@@@@@@@@A|˙zOtH$+>y=܋[Co甩BS9/*~U\{me~^Xx@@A*h_ij?Kȡ"( hOnmgz̽~$Lɘ2- 7HOt3;PYWSWі4c,Egn"3YU(@@@@@@@@@@@@@@A|˙zOtH$+>y=܋[Co甩BS9/*~U\{me~^Xx@@@A<҄! d"""}3bن:ڃĥ'mF> ʘ֤A.HLʀ7n}Lڂ.W# e̽B$<YET{!)ɜӗ?t*mrgb=6uhiSq,E Y> 8)Ȃp&8 $$eoU׌q V; 3>fޟu;=.e= q:r-m R{ NL朿ԩTko-sk;}kCM{b,un:s}%1YBXJ#rkhCi'$5ɲtm"=#( Oٞa2GK8>l,ښX6gwY^LO PEQNBp`L@bMq!&4?/Gu @@@@@@@@@@@A|˙zOtH$+>y=܋[Co甩BS9/*~U\{me~^Xx@@A aajhΦ!8z{r[f/ 3[S;80o(/#4՝\=P @99٘brv`4a#ID[s36 Ѡ A*|DbC!YE{&u6^#?/Gu @@@@@@@@@@A|˙zOtH$+>y=܋[Co甩BS9/*~U\{me~^Xx@@@@A/_I}EuF55}iA">؀vCp<2 -9|Qwqk更҂H?Jw_P̹TD@ǚ#ȵ6yJd%93rRQ]GڎQ 7~>Eׄs5!,bN@lw[;;zYqtiljp ځ3#7a'w'nwA@@@@@@@@@@@@@@@@@@@@@@@@@A`pIVlY-m'"u̴̳Bކ8 ;hF7$#s/PgÏ5AGkhm;Jrg4O [ykY؏p7͵cZo+|c8=e= o(]؟]5مGw$Z-3ج"9%8 \$ 1& vvdx'8k2`2r0"{-Qw{H;pS=.e= q:r-m R{ NL朿ԩTko-sk;}kCM{b,uWQ9TX]$鋏$Yj :L:F5%0oG2^S  χjw"*iJF9uoj:F4ߩW"^q{{A@@@@@@@@@@@@@@@@@@@@@@@@@@@Alp.׆Tkgw7gܷoɘl<D1p XĚ$/uil⡮"<<ɂF!#OIL̹TD@ǚ#ȵ6yJd%93rRP]lGڎQ 7~>Eׄs8N8"F-n -JDgzڇ@KjZMٜM A@@@@@@@@@@@@@@@@@@@@@@@@@@@@A #Uz8LMOSi-/~V ACT.X;;n <́T5G0RT9={$ )x?2 HV|8Td{)T섧&sN_TЪ˭|Q>5O½ȱ:3=f^Sޒ Q>"4щiiwg{;Yٺbm;_ hqz|O euG ޖv{gggk s PKOP"pH,@bMb5t[I%0nG2^S  χjw"*iJB9uoj:F4ߩW"^@r=YONSAI< @TTLc 9oybD0aX!ղԌhBa8aw=vyIiz_y gI l[0`QVn.`);8ѹݷnwA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Avp a 3'/NF,K6a4̹TD@ǚ#ȵ6yJd%93rRP]lGڎQ 7~>Eׄz\vN-e :hi]s† ::o8u> tQ2Gv?3DlN 0 \P661k黄=.e= q:r-m R{ NL朿ԩTko-s[;}kCM{b,uJT.r\33o ΓUfrj3bHI;;o  Gƣ#4ش[KL3X16-}gϠ᦯-TF2Vv3۝z ̹TD@ǚ#ȵ6yJd%93rRQ]lGڎQ 7~>EׄA2G_ؼ@c]-DFmͮ޻jG2^S  χjw"*wiJF9voj:F4ߩW"^G8XISǴJ]-TM17{= ŃNHj!e<2DzFQ "$=8=e= yN*r 3q0!{ 6v}A1Xe>,B!VPFg}.C6k e̽B$<YET{!)ɜӗ?t*mrgb=6uhiSq,E gՍ.$m90䫈{k#qm/a{;Cҏ.Bb0M Y @NDQS(y)nf8ΐCKfzq+j0aDE33n  \ M+MIuLvٝ:׻;: )N8 I$$۝{\*{A @@@@@AYPuZ!0[`py4SY2?F_ڟ53<~h:ZOOq]תM҃?ePZV zz1Ӷä)T3{]ww{<9C (0)m@ɥ0;dq<PɿG)sP9*y0@vEDޥ^MA<@@@@@AYPuZ7 !S Afbf%3p&wbd7^BM37g9$Y+339YY>PY*a26D8# <]F ' (gI&MKi)@DZowwp Eׄ<YET{!)ɜӗ?t*mrgb=6uhiSq,E q:r-m R{ NL朿ԩTko-s[;}kCM{b,ugÏ5AGkhm;Jrg4O [ykY؄S5W.r[vWl\.TV!G/W5b{22j=x X̼iCڏf^4CV!G/c!ٗ1Ո{QƘj=eLd5b{22j=x X̼iCڏf^4CV!G/c!ٗ1Ո{QƘj=eLd5b{22j=x X̼iCڏf^4CV!G/c!ٗ1Ո{QƘj=eLd5b{22j=x X̼iCڏf^4CV!G/c!ٗ1Ո{QƘj=eLd5b{22j=x X̼iCڏf^4CV!G/c!ٗ1Ո{QƘj=eLd5b{22j=x X̼iCڏf^4CV!G/c!ٗ1Ո{QƘj=eLd5b{22j=x X̼iCV!G/c"|(sb[$<)_6Bo9/*~U:\'_gp+|pX GN/$7r'@}.bm̲KmP ?}m J7rg4O [ykب6|<<)l Xwoݽ4}L&0vF O,S,I[uZ+=xQ~#+=xwyOg&:'GWj{85n1ǕZ?MG[uG| Search

Freefind search

Search this site powered by FreeFind

Google search

Enter keyword(s) or phrase for which to search http://lpsolve.sourceforge.net/5.5/:
Google
./semi-cont.htm000666 000000 000000 00000017664 10503525632 012014 0ustar00000000 000000 semi-continuous variables

semi-continuous variables

Semi-continuous variables are variables that must take a value between their minimum and maximum or zero. So these variables are treated the same as regular variables, except that a value of zero is also accepted, even if there is a minimum bigger than zero is set on the variable.

image\img00340.gif

The practical usage of such variables is the following. If the variable is taken then take at least the minimum or else don't take it at all. For example in a blending problem this could mean if an amount of a raw material is taken then it must be at least the minimum or else take none at all. This because less than the minimum cannot be weighted for example. If a fixed minimum would be set then it would not be allowed to not to use the raw material at all. However via semi-continuous variables it is possible to state this kind of restrictions.

Since release 4, lp_solve has supported semi-continuous variables via the API call set_semicont or in the mps format in the bounds section via the SC bound type. See mps-format. If there is no minimum set on a semi-continuous variable then the default minimum is 1. The SC bound type normally needs the maximum in field 4. However this value may be omitted. In that case an upper bound of infinity is taken.

Example:

NAME
ROWS
 N  r_0
 L  r_1
 G  r_2
 G  r_3
 G  r_4
COLUMNS
    x1        r_0                 -1   r_1                  1
    x1        r_2                  2   r_3                 -1
    x2        r_0                 -2   r_1                  1
    x2        r_2                 -1   r_3                  3
    x3        r_0                  4   r_4                  1
    x4        r_0                  3   r_4                  1
RHS
    RHS       r_1                  5   r_4                0.5
BOUNDS
 SC BND       x3                  10
 LO BND       x3                 1.1
ENDATA

The red lines are two lines that specify that variable x3 is a semi-continuous variable with a maximum of 10 and a minimum of 1.1. If the LO entry would not be there then the minimum would be 1, the default. If the 10 is omitted in the SC entry then there is no maximum.

Since lp_solve version 4.0.1.10, lp_solve also supports semi-continuous variables in the lp-format See lp-format. The above mps example would be in lp-format:

max: x1 + 2x2 - 4x3 -3x4;
x1 + x2 <= 5;
2x1 - x2 >= 0;
-x1 + 3x2 >= 0;
x3 + x4 >= .5;
x3 >= 1.1;
x3 <= 10;

sec x3;

If the line x3 >= 1.1; is omitted then there is an implicit minimum of 1. If the line x3 <= 10; is omitted then there is no maximum on the variable. The new section sec is analogue as the int section and specifies all the variables that are semi-continuous. Multiple variables can be specified separated by a comma (,) or space.

The solution for this model is:

Value of objective function: 6.83333

Actual values of the variables:
x1                   1.66667
x2                   3.33333
x3                   0
x4                   0.5

Why does it take 0 and not 1.1? Because the objective value is better if 0 is taken than 1.1. If the variable would not be semi-continuous (delete sec x3;) then the solution would be:

Value of objective function: 3.93333

Actual values of the variables:
x1                   1.66667
x2                   3.33333
x3                   1.1
x4                   0

6.83333 is a better solution than 3.93333

If the model is changed to:

max: x1 + 2x2 - 0.1x3 -3x4;
x1 + x2 <= 5;
2x1 - x2 >= 0;
-x1 + 3x2 >= 0;
x3 + x4 >= .5;
x3 >= 1.1;
x3 <= 10;

sec x3;

Only the cost of x3 is changed here from -4 to -0.1. The solution of this model is:

Value of objective function: 8.22333

Actual values of the variables:
x1                   1.66667
x2                   3.33333
x3                   1.1
x4                   0

Now the solver takes the 1.1 as value because this solution is better than if 0 would be taken. This can be proven with the following model:

max: x1 + 2x2 - 1x3 -3x4;
x1 + x2 <= 5;
2x1 - x2 >= 0;
-x1 + 3x2 >= 0;
x3 + x4 >= .5;
x3 <= 0;

sec x3;

This gives as solution:

Value of objective function: 6.83333

Actual values of the variables:
x1                   1.66667
x2                   3.33333
x3                   0
x4                   0.5

6.83333 is worse than 8.22333, thus the solver takes the 1.1 solution.

Note that semi-continuous variables may be combined with integer variables. The same rules then apply, but the variable must also be integer then.

For example:

max: x1 + 2x2 - .1x3 -3x4;
x1 + x2 <= 5;
2x1 - x2 >= 0;
-x1 + 3x2 >= 0;
x3 + x4 >= .5;
x3 >= 1.1;
x3 <= 10;

sec x3;

int x3;

The solution of this model is:

Value of objective function: 8.13333

Actual values of the variables:
x1                   1.66667
x2                   3.33333
x3                   2
x4                   0

Because x3 must now be integer, it takes the value 2 instead of 1.1. The objective value 8.13333 is still better than he objective value if x3 would be 0 (6.83333).

In the mps format this can be either specified via the SI attribute or via SC attribute with the MARKER INTORG, MARKER INTEND in the COLUMNS section:

ROWS
 N  r_0
 L  r_1
 G  r_2
 G  r_3
 G  r_4
COLUMNS
    x1        r_0                 -1   r_1                  1
    x1        r_2                  2   r_3                 -1
    x2        r_0                 -2   r_1                  1
    x2        r_2                 -1   r_3                  3
    x3        r_0                0.1   r_4                  1
    x4        r_0                  3   r_4                  1
RHS
    RHS       r_1                  5   r_4                0.5
BOUNDS
 SI BND       x3                  10
 LO BND       x3                 1.1
ENDATA

Or

ROWS
 N  r_0
 L  r_1
 G  r_2
 G  r_3
 G  r_4
COLUMNS
    x1        r_0                 -1   r_1                  1
    x1        r_2                  2   r_3                 -1
    x2        r_0                 -2   r_1                  1
    x2        r_2                 -1   r_3                  3
    MARK0000  'MARKER'                 'INTORG'
    x3        r_0                0.1   r_4                  1
    MARK0001  'MARKER'                 'INTEND'
    x4        r_0                  3   r_4                  1
RHS
    RHS       r_1                  5   r_4                0.5
BOUNDS
 SC BND       x3                  10
 LO BND       x3                 1.1
ENDATA
./Semi-ContinuousVariables_files/000777 000000 000000 00000000000 13751300712 015440 5ustar00000000 000000 ./sensitivity.htm000666 000000 000000 00000017017 10205361500 012467 0ustar00000000 000000 Sensitivity

Sensitivity

Sensitivity or post-optimal analysis is extra information that is provided about the current optimal solution. lp_solve provides a substantial amount of sensitivity information. Several API calls are available to retrieve the sensitivity: get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult. The lp_solve program doesn't show the sensitivity by default. So to see the sensitivity information, use the -S4 option. The best way to explain this is via an example.

min: +COLONE +3 COLTWO +6.24 COLTHREE +0.1 COLFOUR;
THISROW: +78.26 COLTWO +2.9 COLFOUR >= 92.3;
THATROW: +0.24 COLONE +11.31 COLTHREE <= 14.8;
LASTROW: +12.68 COLONE +0.08 COLTHREE +0.9 COLFOUR >= 4;
COLONE >= 28.6;
COLFOUR >= 18.00;
COLFOUR <= 48.98;

The solution of this model is (with the -S4 option):

Value of objective function: 31.7828

Actual values of the variables:
COLONE               28.6
COLTWO               0
COLTHREE             0
COLFOUR              31.8276

Actual values of the constraints:
THISROW              92.3
THATROW              6.864
LASTROW              391.293

Objective function limits:
                              From            Till          FromValue
COLONE                              0          1e+030         -1e+030
COLTWO                       2.698621          1e+030       0.5123946
COLTHREE                            0          1e+030       0.7016799
COLFOUR                             0       0.1111679         -1e+030

Dual values with from - till limits:
                          Dual value          From            Till
THISROW                   0.03448276             52.2         142.042
THATROW                            0          -1e+030          1e+030
LASTROW                            0          -1e+030          1e+030
COLONE                             1        -1.943598        61.66667
COLTWO                     0.3013793       -0.6355993       0.5123946
COLTHREE                        6.24         -4841.16       0.7016799
COLFOUR                            0          -1e+030          1e+030

First look at 'Objective function limits' (via API obtained by get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex). There is a list of all variables with for each variable 3 values. From, Till and FromValue. From - Till gives the limits where between the objective value may vary so that the solution stays the same. For example, variable COLFOUR has a From value of 0 and a Till value of 0.1111679. The coefficient in the objective function of this variable is 0.1. This means that as this coefficient varies between 0 and 0.1111679, the solution doesn't change. The values for the variables and the constraints will remain unchanged as long as the objective coefficient stays in this range. The objective function value will vary of course and also the sensitivity information of the other variables, but the solution will stay the same if only the objective coefficient value for this variable is changed. When the objective coefficient of variable COLFOUR is above 0.1111679 then the solution will change. The FromValue is only meaningful if the variable has a value of 0 (rejected). This is the value that this variable becomes when the From (minimization) or Till (maximization) value is reached. For example, the variable COLTWO that has an amount of 0 will become 0.5123946 if the coefficient in the objective function of COLTWO reaches 2.698621. Note that you only get information about this variable. There is no information what the values will be of the other variables. In a blending example where the coefficients of the objective function are generally the prices of ingredients this information tells you at what point a price may change to have the same composition and the FromValue says at what value a relected ingredient will be taken when the price lowers till the lower range value.

Another piece of information are the Dual values with the from - till limits. This is provided for both the constraints and the variables. The information is the same for both. For example, constraint THISROW has a dual value of 0.03448276 with a From value of 52.2 and a Till value of 142.042. This means that the Dual value specifies how much the objective function will vary if the constraint value is incremented by one unit. This implies that there is only a non-zero dual value if the constraint is active. Constraint THATROW for example is not active because the constraint is <= 14.8, but its value is only 6.864. However constraint THISROW is >= 92.3 and its value is also 92.3, thus active. If the constraint is changed to 93.3 (+1), then the objective value will be the current value + change * dual value = 31.7828 + 1 * 0.03448276 = 31.81728. However this is only true for the range From - Till, which means that the dual value stays only the same as long as the constraint lies between the From - Till limits. The moment that you are outside of these limits, the dual value will change. The dual value gives a very good indication how much this restriction costs. If the dual value is very high then this constraint is very influential on the objective function and if you are able to change it a bit then the solution will be much better. Also the sign of the dual value has a meaning. A positive value means that as the restriction becomes larger, the objective value will be larger, and as it becomes more negative, the objective value will be smaller. Also note that changes in the restrictions, even between the limits, can cause the solution to change. The from - till limits only say that the cost will remain the same, nothing less, nothing more.

Inaccurate sensitivity analysis in a model with integer variables

The sensitivity analysis doesn't take the integer restrictions in account. This is almost impossible since it would ask too much calculation time. In particular the from - till limits on both the objective function and the dual values are trustworthy. They only apply for the current solution without the integer restrictions. Keep this in mind. The dual values are correct.
./set_add_rowmode.htm000666 000000 000000 00000010646 10237106460 013244 0ustar00000000 000000 set_add_rowmode

set_add_rowmode

Specifies which add routine performs best. add_column, add_columnex, str_add_column or add_constraint, add_constraintex, str_add_constraint

unsigned char set_add_rowmode(lprec *lp, unsigned char turnon);

Return Value

set_add_rowmode return TRUE if changed from mode and FALSE if this mode was already set.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

turnon

TRUE or FALSE. If FALSE, then add_column, add_columnex, str_add_column performs best. If TRUE, then add_constraint, add_constraintex, str_add_constraint performs best.

Remarks

Default, this is FALSE, meaning that add_column, add_columnex, str_add_column performs best. If the model is build via add_constraint, add_constraintex, str_add_constraint calls, then these routines will be much faster if this routine is called with turnon set on TRUE. This is also called row entry mode. The speed improvement is spectacular, especially for bigger models, so it is advisable to call this routine to set the mode. Normally a model is build either column by column or row by row.
Note that there are several restrictions with this mode:
Only use this function after a make_lp call. Not when the model is read from file. Also, if this function is used, first add the objective function via set_obj_fn, set_obj_fnex, str_set_obj_fn and after that add the constraints via add_constraint, add_constraintex, str_add_constraint. Don't call other API functions while in row entry mode. No other data matrix access is allowed while in row entry mode. After adding the contraints, turn row entry mode back off. Once turned of, you cannot switch back to row entry mode. So in short:
- turn row entry mode on
- set the objective function
- create the constraints
- turn row entry mode off

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 10);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_add_rowmode(lp, TRUE);
  /* first! set the objective function */

  /* now add the constraints */
  set_add_rowmode(lp, FALSE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_add_rowmode, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, add_column, add_columnex, str_add_column, set_column, set_columnex, add_constraint, add_constraintex, str_add_constraint

./set_anti_degen.htm000666 000000 000000 00000011070 10244101716 013042 0ustar00000000 000000 set_anti_degen

set_anti_degen

Specifies if special handling must be done to reduce degeneracy/cycling while solving.

void set_anti_degen(lprec *lp, int anti_degen);

Return Value

set_anti_degen has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

anti_degen

Can be any combination (OR) of following values:

ANTIDEGEN_NONE (0) No anti-degeneracy handling
ANTIDEGEN_FIXEDVARS (1) Check if there are equality slacks in the basis and try to drive them out in order to reduce chance of degeneracy in Phase 1
ANTIDEGEN_COLUMNCHECK (2)  
ANTIDEGEN_STALLING (4)  
ANTIDEGEN_NUMFAILURE (8)  
ANTIDEGEN_LOSTFEAS (16)  
ANTIDEGEN_INFEASIBLE (32)  
ANTIDEGEN_DYNAMIC (64)  
ANTIDEGEN_DURINGBB (128)  
ANTIDEGEN_RHSPERTURB (256) Perturbation of the working RHS at refactorization
ANTIDEGEN_BOUNDFLIP (512) Limit bound flips that can sometimes contribute to degeneracy in some models

Remarks

The set_anti_degen function specifies if special handling must be done to reduce degeneracy/cycling while solving. Setting this flag can avoid cycling, but can also increase numerical instability. The default is ANTIDEGEN_INFEASIBLE + ANTIDEGEN_STALLING + ANTIDEGEN_FIXEDVARS (37).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_anti_degen(lp, ANTIDEGEN_FIXEDVARS | ANTIDEGEN_PERTURB);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_anti_degen, is_anti_degen

./set_basis.htm000666 000000 000000 00000010654 10472052322 012056 0ustar00000000 000000 set_basis

set_basis

Sets an initial basis of the lp.

unsigned char set_basis(lprec *lp, int *bascolumn, unsigned char nonbasic);

Return Value

set_basis returns TRUE if provided basis was set. FALSE if not. If FALSE then provided data was invalid.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

bascolumn

An array with 1+get_Nrows or 1+get_Nrows+get_Ncolumns elements that specifies the basis.

nonbasic

If FALSE, then bascolumn must have 1+get_Nrows elements and only contains the basic variables. If TRUE, then bascolumn must have 1+get_Nrows+get_Ncolumns elements and will also contain the non-basic variables.

Remarks

The set_basis function sets an initial basis of the lp.
The array receives the basic variables and if nonbasic is TRUE, then also the non-basic variables. If an element is less then zero then it means on lower bound, else on upper bound.
Element 0 of the array is unused.
The default initial basis is bascolumn[x] = -x.
Each element represents a basis variable. If the absolute value is between 1 and get_Nrows, it represents a slack variable and if it is between get_Nrows+1 and get_Nrows+get_Ncolumns then it represents a regular variable. If the value is negative, then the variable is on its lower bound. If positive it is on its upper bound.
Setting an initial basis can speed up the solver considerably. It is the starting point from where the algorithm continues to find an optimal solution.
When a restart is done, lp_solve continues at the last basis, except if set_basis, default_basis or read_basis is called.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int bascolumn[1+2]; /* must be 1 more then number of rows ! */

  /* Create a new LP model */
  lp = make_lp(2, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  bascolumn[0] = 0;
  bascolumn[1] = -1;
  bascolumn[2] = -2;
  set_basis(lp, bascolumn, FALSE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_basis, default_basis, read_basis, write_basis, guess_basis, get_basiscrash, set_basiscrash

./set_basiscrash.htm000666 000000 000000 00000007346 10472052712 013106 0ustar00000000 000000 set_basiscrash

set_basiscrash

Determines a starting base.

void set_basiscrash(lprec *lp, int mode);

Return Value

None

Parameters

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

mode

Specifies which basis crash mode is used. Can by any of the following values:

CRASH_NONE (0) No basis crash
CRASH_MOSTFEASIBLE (2) Most feasible basis
CRASH_LEASTDEGENERATE (3) Construct a basis that is in some measure the "least degenerate"

Remarks

The set_basiscrash function specifies which basis crash mode must be used. Default is CRASH_NONE.

When no base crash is done (the default), the initial basis from which lp_solve starts to solve the model is the basis containing all slack or artificial variables that is automatically associates with each constraint.

When base crash is enabled, a heuristic ``crash procedure'' is executed before the first simplex iteration to quickly choose a basis matrix that has fewer artificial variables. This procedure tends to reduce the number of iterations to optimality since a number of iterations are skipped. lp_solve starts iterating from this basis until optimality.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  /* Model created */

  set_basiscrash(lp, CRASH_MOSTFEASIBLE);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_basiscrash, default_basis, read_basis, write_basis, guess_basis, get_basis, set_basis

./set_basisvar.htm000666 000000 000000 00000003573 10311026176 012571 0ustar00000000 000000 set_basisvar

set_basisvar

This is an internal function that has been published for special purposes. It should generally not be used.

int set_basisvar(lprec *lp, int basisPos, int enteringCol);

Return Value

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

basisPos

enteringCol

Remarks

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

./set_bb_depthlimit.htm000666 000000 000000 00000006070 10255022626 013563 0ustar00000000 000000 set_bb_depthlimit

set_bb_depthlimit

Sets the maximum branch-and-bound depth.

void set_bb_depthlimit(lprec *lp, int bb_maxlevel);

Return Value

set_bb_depthlimit has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

bb_maxlevel

Specifies the maximum branch-and-bound depth. A positive value means that the depth is absoluut. A negative value means a relative B&B depth limit. The "order" of a MIP problem is defined to be 2x the number of binary variables plus the number of SC and SOS variables.A relative value of -x results in a maximum depth of x times the order of the MIP problem.

Remarks

The set_bb_depthlimit function sets the maximum branch-and-bound depth.
This is only useful if there are integer, semi-continious or SOS variables in the model so that the branch-and-bound algorithm must be used to solve them. The branch-and-bound algorithm will not go deeper than this level. When 0 then there is no limit to the depth. Limiting the depth will speed up solving time, but there is a chance that the found solution is not the most optimal one. Be aware of this. It can also result in not finding a solution at all.
The default is -50.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_bb_depthlimit(lp, 10);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_bb_depthlimit

./set_bb_floorfirst.htm000666 000000 000000 00000006541 10310773314 013613 0ustar00000000 000000 set_bb_floorfirst

set_bb_floorfirst

Specifies which branch to take first in branch-and-bound algorithm.

void set_bb_floorfirst(lprec *lp, int bb_floorfirst);

Return Value

set_bb_floorfirst has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

bb_floorfirst

Specifies which branch to take first in branch-and-bound algorithm. Can by any of the following values:

BRANCH_CEILING (0) Take ceiling branch first
BRANCH_FLOOR (1) Take floor branch first
BRANCH_AUTOMATIC (2) Algorithm decides which branch being taken first

Remarks

The set_bb_floorfirst function specifies which branch to take first in branch-and-bound algorithm. This can influence solving times considerably. Depending on the model one rule can be best and for another model another rule.
The default is BRANCH_AUTOMATIC (2).
Note that this setting can be overruled by a user routine to choose the branch. See put_bb_branchfunc.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_bb_floorfirst(lp, BRANCH_AUTOMATIC);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_bb_floorfirst, set_var_branch, get_var_branch, set_var_weights, get_var_priority, put_bb_branchfunc

./set_bb_rule.htm000666 000000 000000 00000014634 10534546660 012405 0ustar00000000 000000 set_bb_rule

set_bb_rule

Specifies the branch-and-bound rule.

void set_bb_rule(lprec *lp, int bb_rule);

Return Value

set_bb_rule has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

bb_rule

The branch-and-bound rule. Can by any of the following values:

NODE_FIRSTSELECT (0) Select lowest indexed non-integer column
NODE_GAPSELECT (1) Selection based on distance from the current bounds
NODE_RANGESELECT (2) Selection based on the largest current bound
NODE_FRACTIONSELECT (3) Selection based on largest fractional value
NODE_PSEUDOCOSTSELECT (4) Simple, unweighted pseudo-cost of a variable
NODE_PSEUDONONINTSELECT (5) This is an extended pseudo-costing strategy based on minimizing the number of integer infeasibilities
NODE_PSEUDORATIOSELECT (6) This is an extended pseudo-costing strategy based on maximizing the normal pseudo-cost divided by the number of infeasibilities. Effectively, it is similar to (the reciprocal of) a cost/benefit ratio
NODE_USERSELECT (7)  

One of these values may be or-ed with one or more of the following values:

NODE_WEIGHTREVERSEMODE (8) Select by criterion minimum (worst), rather than criterion maximum (best)
NODE_BRANCHREVERSEMODE (16) In case when get_bb_floorfirst is BRANCH_AUTOMATIC, select the oposite direction (lower/upper branch) that BRANCH_AUTOMATIC had chosen.
NODE_GREEDYMODE (32)  
NODE_PSEUDOCOSTMODE (64) Toggles between weighting based on pseudocost or objective function value
NODE_DEPTHFIRSTMODE (128) Select the node that has already been selected before the most number of times
NODE_RANDOMIZEMODE (256) Adds a randomization factor to the score for any node candicate
NODE_GUBMODE (512) Enables GUB mode. Still in development and should not be used at this time.
NODE_DYNAMICMODE (1024) When NODE_DEPTHFIRSTMODE is selected, switch off this mode when a first solution is found.
NODE_RESTARTMODE (2048) Enables regular restarts of pseudocost value calculations
NODE_BREADTHFIRSTMODE (4096) Select the node that has been selected before the fewest number of times or not at all
NODE_AUTOORDER (8192) Create an "optimal" B&B variable ordering. Can speed up B&B algorithm.
NODE_RCOSTFIXING (16384) Do bound tightening during B&B based of reduced cost information
NODE_STRONGINIT (32768) Initialize pseudo-costs by strong branching

Remarks

The set_bb_rule function specifies the branch-and-bound rule for choosing which non-integer variable is to be selected. This rule can influence solving times considerably. Depending on the model one rule can be best and for another model another rule.
The default is NODE_PSEUDONONINTSELECT + NODE_GREEDYMODE + NODE_DYNAMICMODE + NODE_RCOSTFIXING (17445).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_bb_rule(lp, NODE_FIRSTSELECT);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_bb_rule, put_bb_nodefunc

./set_BFP.htm000666 000000 000000 00000005607 10237106462 011372 0ustar00000000 000000 set_BFP

set_BFP

Set basis factorization package.

unsigned char set_BFP(lprec *lp, char *filename);

Return Value

set_BFP returns TRUE if the call has succeeded, else FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

The name of the BFP package. Currently following BFPs are implemented:

"bfp_etaPFI" original lp_solve product form of the inverse.
"bfp_LUSOL" LU decomposition.
"bfp_GLPK" GLPK LU decomposition.
NULL The default BFP package.
However the user can also build his own BFP packages ...

Remarks

The set_BFP function sets the basis factorization package (BFP). See Basis Factorization Packages for a complete description on BFPs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_BFP(lp, "bfp_LUSOL");

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, has_BFP, is_nativeBFP

./set_binary.htm000666 000000 000000 00000006253 10237106462 012245 0ustar00000000 000000 set_binary

set_binary

Set the type of the variable. Binary or floating point.

unsigned char set_binary(lprec *lp, int column, unsigned char must_be_bin);

Return Value

set_binary returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be set. It must be between 1 and the number of columns in the lp.

must_be_bin

TRUE (1) if the variable must be binary, FALSE (0) if not.

Remarks

The set_binary function defines if a variable must be binary or not. Default a variable is not binary. A binary variable is an integer variable with a lower bound of 0 and an upper bound of 1. This function also sets these bounds. The argument must_be_bin defines what the status of the variable becomes. From the moment there is at least one integer variable in the model, the Branch and Bound algorithm is used to make these variables integer. Note that solving times can be considerably larger when there are integer variables. See integer variables for a description about integer variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_binary(lp, 1, TRUE); /* sets variable 1 to binary */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_binary, is_int, set_int

./set_bounds.htm000666 000000 000000 00000006771 11127334350 012256 0ustar00000000 000000 set_bounds

set_bounds

Set the lower and upper bound of a variable.

unsigned char set_bounds(lprec *lp, int column, REAL lower, REAL upper);

Return Value

set_bounds returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable on which the bounds must be set. It must be between 1 and the number of columns in the lp.

lower

The lower bound on the variable identified by column.

upper

The upper bound on the variable identified by column.

Remarks

The set_bounds function sets a lower and upper bound on the variable identified by column.
Setting a bound on a variable is the way to go instead of adding an extra constraint (row) to the model. Setting a bound doesn't increase the model size that means that the model stays smaller and will be solved faster.
Note that the default lower bound of each variable is 0. So variables will never take negative values if no negative lower bound is set. The default upper bound of a variable is infinity (well not quite. It is a very big number, the value of get_infinite).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_bounds(lp, 1, 1.0, 2.0);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_lowbo, get_lowbo, set_upbo, get_upbo, set_unbounded, is_unbounded, is_negative

./set_bounds_tighter.htm000666 000000 000000 00000006345 10237121204 013772 0ustar00000000 000000 set_bounds_tighter

set_bounds_tighter

Specifies if set bounds may only be tighter or also less restrictive.

void set_bounds_tighter(lprec *lp, unsigned char tighten);

Return Value

set_bounds_tighter has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

tighten

Specifies if set bounds may only be tighter (TRUE) or also less restrictive (FALSE).

Remarks

The set_bounds_tighter function sets if bounds may only be tighter or also less restrictive. If set to TRUE then bounds may only be tighter. This means that when set_lowbo or set_lowbo is used to set a bound and the bound is less restrictive than an already set bound, then this new bound will be ignored. If tighten is set to FALSE, the new bound is accepted. This functionality is useful when several bounds are set on a variable and at the end you want the most restrictive ones. By default, this setting is FALSE. Note that this setting does not affect set_bounds.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_bounds_tighter(lp, TRUE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_bounds_tighter, set_upbo, get_upbo, set_lowbo, get_lowbo, set_bounds, set_unbounded, is_unbounded, is_negative

./set_break_at_first.htm000666 000000 000000 00000005576 10237106462 013747 0ustar00000000 000000 set_break_at_first

set_break_at_first

Specifies if the branch-and-bound algorithm stops at first found solution.

void set_break_at_first(lprec *lp, unsigned char break_at_first);

Return Value

set_break_at_first has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

break_at_first

TRUE or FALSE. Stop branch-and-bound algorithm at first found solution or not.

Remarks

The set_break_at_first function specifies if the branch-and-bound algorithm stops at the first found solution or not. Stopping at the first found solution can be useful if you are only interested for a solution, but not necessarily (and most probably) the most optimal solution.
The default is not (FALSE) stop at first found solution.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_break_at_first(lp, TRUE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_break_at_first, set_break_at_value, get_break_at_value, set_obj_bound, get_obj_bound, set_mip_gap, get_mip_gap

./set_break_at_value.htm000666 000000 000000 00000005672 10237106462 013731 0ustar00000000 000000 set_break_at_value

set_break_at_value

Specifies if the branch-and-bound algorithm stops when the object value is better than a given value.

void set_break_at_value(lprec *lp, REAL break_at_value);

Return Value

set_break_at_value has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

break_at_value

The value to break on.

Remarks

The set_break_at_value function allows the branch-and-bound algorithm to stops when the object value is better than a given value. Stopping at a given object value can be useful if you are only interested for a solution that has an object value which is at least a given value, but not necessarily (and most probably) the most optimal solution.
The default value is (-) infinity.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_break_at_value(lp, 1000); /* Will stop if object value is better than 1000 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_break_at_value, set_break_at_first, is_break_at_first, set_obj_bound, get_obj_bound, set_mip_gap, get_mip_gap

./set_break_numeric_accuracy.htm000666 000000 000000 00000004416 12673675350 015455 0ustar00000000 000000 set_break_numeric_accuracy

set_break_numeric_accuracy

Sets the accuracy values when solve should fail.

void set_break_numeric_accuracy(lprec *lp, REAL accuracy);

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

accuracy

From which minimal accuracy should solve fail.

Remarks

When accuracy from get_accuracy is larger than this values, optimization will fail with ACCURACYERROR.
By default, accuracy is 5e-7.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_break_numeric_accuracy(lp, 1e-5);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_accuracy, get_break_numeric_accuracy

./set_column.htm000666 000000 000000 00000013372 10351213400 012242 0ustar00000000 000000 set_column, set_columnex

set_column, set_columnex

set a column in the lp.

unsigned char set_column(lprec *lp, int col_no, REAL *column);

unsigned char set_columnex(lprec *lp, int col_no, int count, REAL *column, int *rowno);

Return Value

set_column, set_columnex return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

col_no

The column number that must be changed.

count

Number of elements in column and rowno.

column

An array with 1+get_Nrows (count for set_columnex, if rowno is different from NULL) elements that contains the values of the column.

rowno

A zero-based array with count elements that contains the row numbers of the column. However this variable can also be NULL. In that case element i in the variable column is row i.

Remarks

The set_column, set_columnex functions change the values of an existing column in the model at once.

Note that add_column, add_columnex, str_add_column add a column to the model, making the number of columns one larger. These functions change an existing column.

Note that for set_column (and set_columnex when rowno is NULL) element 0 of the array is row 0 (the objective function), element 1 is row 1, ...

set_columnex has the possibility to specify only the non-zero elements. In that case rowno specifies the row numbers of the non-zero elements. And in contrary to set_column, set_columnex reads the arrays starting from element 0. This will speed up building the model considerably if there are a lot of zero values. In most cases the matrix is sparse and has many zero value.

Thus it is almost always better to use set_columnex instead of set_column. set_columnex is always at least as performant as set_column.

It is more performant to call these functions than multiple times set_mat.

Note that unspecified values by set_columnex are set to zero.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL column[1+3];     /* must be 1 more than number of rows ! */
  REAL sparsecolumn[2]; /* must be the number of non-zero values */
  int rowno[2];

  /* Create a new LP model */
  lp = make_lp(3, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  column[0] = 1.0; /* the objective value */
  column[1] = 2.0;
  column[2] = 0.0;
  column[3] = 3.0;
  set_column(lp, 1, column); /* changes the values of existing column 1 */
  
  rowno[0] = 0; sparsecolumn[0] = 1.0; /* the objective value */
  rowno[1] = 1; sparsecolumn[1] = 2.0;
  rowno[2] = 3; sparsecolumn[2] = 3.0;
  set_columnex(lp, 2, 3, sparsecolumn, rowno); /* changes the values of existing column 2 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_column, get_columnex, add_column, add_columnex, str_add_column, add_constraint, add_constraintex, str_add_constraint, set_row, set_rowex, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, set_add_rowmode, is_add_rowmode, get_constr_type, is_constr_type, del_constraint, add_column, add_columnex, str_add_column, get_column, get_columnex, get_row, get_rowex, get_mat

./set_col_name.htm000666 000000 000000 00000005167 10237106462 012541 0ustar00000000 000000 set_col_name

set_col_name

Set the name of a column in the lp.

unsigned char set_col_name(lprec *lp, int column, char *new_name);

Return Value

set_col_name returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column for which the name must be set. Must be between 1 and the number of columns in the lp.

new_name

The name for the column.

Remarks

The set_col_name sets the name of the column.
The column must already exist. Column names are optional.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_col_name(lp, 1, "col1");

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_col_name, get_origcol_name, set_row_name, get_row_name, get_origrow_name, get_nameindex

./set_constr_type.htm000666 000000 000000 00000007050 10237106462 013326 0ustar00000000 000000 set_constr_type

set_constr_type

Set the type of a constraint.

unsigned char set_constr_type(lprec *lp, int row, int con_type);

Return Value

set_constr_type returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the constraint type must be set. Must be between 1 and number of rows in the lp.

con_type

The type of the constraint. Can by any of the following values:

LE (1) Less than or equal (<=)
EQ (3) Equal (=)
GE (2) Greater than or equal (>=)
FR (0) Free

Remarks

The set_constr_type function sets the constraint type for the specified row.
The default constraint type is LE.
Note the free (FR) constraint type. This is new from version 5.1.0.1
A free constraint will act as if the constraint is not there. The lower bound is -Infinity and the upper bound is +Infinity.
This can be used to temporary disable a constraint without having to delete it from the model. Note that the already set RHS and range on this constraint is overruled with Infinity by this.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_constr_type(lp, 1, GE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_constr_type, is_constr_type, add_constraint, add_constraintex, str_add_constraint, del_constraint

./set_debug.htm000666 000000 000000 00000004527 10237106462 012051 0ustar00000000 000000 set_debug

set_debug

Sets a flag if all intermediate results and the branch-and-bound decisions must be printed while solving.

void set_debug(lprec *lp, unsigned char debug);

Return Value

set_debug has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

debug

TRUE or FALSE. Debug or do not debug.

Remarks

The set_debug function sets a flag if all intermediate results and the branch-and-bound decisions must be printed while solving. This function is mend for debugging purposes. The default is not to debug (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_debug(lp, TRUE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_debug

./set_epsb.htm000666 000000 000000 00000007031 10237106462 011705 0ustar00000000 000000 set_epsb

set_epsb

Specifies the value that is used as a tolerance for the Right Hand Side (RHS) to determine whether a value should be considered as 0.

void set_epsb(lprec *lp, REAL epsb);

Return Value

set_epsb has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

epsb

The value that is used as a tolerance for the Right Hand Side (RHS) to determine whether a value should be considered as 0.

Remarks

The set_epsb function specifies the value that is used as a tolerance for the Right Hand Side (RHS) to determine whether a value should be considered as 0.
Floating-point calculations always result in loss of precision and rounding errors. Therefore a very small value (example 1e-99) could be the result of such errors and should be considered as 0 for the algorithm. epsb specifies the tolerance to determine if a RHS value should be considered as 0. If abs(value) is less than this epsb value in the RHS, it is considered as 0.
The default epsb value is 1.0e-10

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_epsb(lp, 1.0e-9); /* sets epsb to 1e-9 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_epsb, set_infinite, get_infinite, is_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./set_epsd.htm000666 000000 000000 00000006750 10237106462 011716 0ustar00000000 000000 set_epsd

set_epsd

Specifies the value that is used as a tolerance for reduced costs to determine whether a value should be considered as 0.

void set_epsd(lprec *lp, REAL epsd);

Return Value

set_epsd has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

epsd

The value that is used as a tolerance for reduced costs to determine whether a value should be considered as 0.

Remarks

The set_epsd function specifies the value that is used as a tolerance for reduced costs to determine whether a value should be considered as 0.
Floating-point calculations always result in loss of precision and rounding errors. Therefore a very small value (example 1e-99) could be the result of such errors and should be considered as 0 for the algorithm. epsd specifies the tolerance to determine if a reducedcost value should be considered as 0. If abs(value) is less than this epsd value, it is considered as 0.
The default epsd value is 1e-9

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_epsd(lp, 1.0e-8); /* sets epsd to 1e-8 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_epsd, set_infinite, is_infinite, get_infinite, set_epsint, get_epsint, set_epsb, get_epsb, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./set_epsel.htm000666 000000 000000 00000006727 10237106462 012077 0ustar00000000 000000 set_epsel

set_epsel

Specifies the value that is used as a tolerance for rounding values to zero.

void set_epsel(lprec *lp, REAL epsel);

Return Value

set_epsel has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

epsel

The value that is used as a tolerance for rounding values to zero.

Remarks

The set_epsel function specifies the value that is used as a tolerance for rounding values to zero.
Floating-point calculations always result in loss of precision and rounding errors. Therefore a very small value (example 1e-99) could be the result of such errors and should be considered as 0 for the algorithm. epsel specifies the tolerance to determine if a value should be considered as 0. If abs(value) is less than this epsel value, it is considered as 0.
epsel is used on all other places where epsint, epsb, epsd, epspivot, epsperturb are not used. The default epsel value is 1e-12

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_epsel(lp, 1.0e-11); /* sets epsel to 1e-11 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_epsel, set_infinite, get_infinite, is_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsb, get_epsb, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./set_epsint.htm000666 000000 000000 00000007755 10237106462 012273 0ustar00000000 000000 set_epsint

set_epsint

Specifies the tolerance that is used to determine whether a floating-point number is in fact an integer.

void set_epsint(lprec *lp, REAL epsint);

Return Value

set_epsint has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

epsint

The tolerance that is used to determine whether a floating-point number is in fact an integer.

Remarks

The set_epsint function specifies the tolerance that is used to determine whether a floating-point number is in fact an integer. This is only used when there is at least one integer variable and the branch and bound algorithm is used to make variables integer.
Integer variables are internally in the algorithm also stored as floating point. Therefore a tolerance is needed to determine if a value is to be considered as integer or not. If the absolute value of the variable minus the closed integer value is less than epsint, it is considered as integer. For example if a variable has the value 0.9999999 and epsint is 0.000001 then it is considered integer because abs(0.9999999 - 1) = 0.0000001 and this is less than 0.000001
The default value for epsint is 1e-7
So by changing epsint you determine how close a value must approximate the nearest integer. Changing this tolerance value to for example 0.001 will generally result in faster solving times, but your solution is less integer.
So it is a compromise.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_epsint(lp, 1.0e-3); /* sets epsint to 0.001 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_epsint, set_infinite, is_infinite, get_infinite, set_epsb, get_epsb, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./set_epslevel.htm000666 000000 000000 00000006427 10337555000 012600 0ustar00000000 000000 set_epslevel

set_epslevel

This is a simplified way of specifying multiple eps thresholds that are "logically" consistent.

unsigned char set_epslevel(lprec *lp, int epslevel);

Return Value

Returns TRUE if level accepted and FALSE if an incalid epsilon level was provided.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

epslevel

Can by any of the following values:

EPS_TIGHT (0) Very tight epsilon values (default)
EPS_MEDIUM (1) Medium epsilon values
EPS_LOOSE (2) Loose epsilon values
EPS_BAGGY (3) Very loose epsilon values

Remarks

This is a simplified way of specifying multiple eps thresholds that are "logically" consistent.
It sets the following values: set_epsel, set_epsb, set_epsd, set_epspivot, set_epsint, set_mip_gap
The default is EPS_TIGHT.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_epslevel(lp, EPS_MEDIUM);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_epsel, set_epsb, set_epsd, set_epspivot, set_epsint, set_mip_gap

./set_epsperturb.htm000666 000000 000000 00000005347 10237106462 013157 0ustar00000000 000000 set_epsperturb

set_epsperturb

Specifies the value that is used as perturbation scalar for degenerative problems.

void set_epsperturb(lprec *lp, REAL epsperturb);

Return Value

set_epsperturb has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

epsperturb

perturbation scalar.

Remarks

The default epsperturb value is 1e-5

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_epsperturb(lp, 1.0e-6); /* sets epsperturb to 1e-6 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_epsperturb, set_infinite, get_infinite, is_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_mip_gap, get_mip_gap

./set_epspivot.htm000666 000000 000000 00000007204 10237106462 012627 0ustar00000000 000000 set_epspivot

set_epspivot

Specifies the value that is used as a tolerance pivot element to determine whether a value should be considered as 0.

void set_epspivot(lprec *lp, REAL epspivot);

Return Value

set_epspivot has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

epspivot

The value that is used as a tolerance for the pivot element to determine whether a value should be considered as 0.

Remarks

The set_epspivot function specifies the value that is used as a tolerance for the pivot element to determine whether a value should be considered as 0.
Floating-point calculations always result in loss of precision and rounding errors. Therefore a very small value (example 1e-99) could be the result of such errors and should be considered as 0 for the algorithm. epspivot specifies the tolerance to determine if a pivot element should be considered as 0. If abs(value) is less than this epspivot value it is considered as 0 and at first instance rejected as pivot element. Only when no larger other pivot element can be found and the value is different from 0 it will be used as pivot element.
The default epspivot value is 2e-7

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_epspivot(lp, 1.0e-5); /* sets epspivot to 1e-5 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_epspivot, set_infinite, get_infinite, is_infinite, set_epsint, get_epsint, set_epsd, get_epsd, set_epsel, get_epsel, get_epsperturb, set_epsperturb, set_mip_gap, get_mip_gap

./set_improve.htm000666 000000 000000 00000006120 10244104174 012427 0ustar00000000 000000 set_improve

set_improve

Specifies the iterative improvement level.

void set_improve(lprec *lp, int improve);

Return Value

set_improve has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

improve

Specifies the iterative improvement level. Can by any of the following values:

IMPROVE_NONE (0) improve none
IMPROVE_SOLUTION (1) Running accuracy measurement of solved equations based on Bx=r (primal simplex), remedy is refactorization.
IMPROVE_DUALFEAS (2) Improve initial dual feasibility by bound flips (highly recommended, and default)
IMPROVE_THETAGAP (4) Low-cost accuracy monitoring in the dual, remedy is refactorization
IMPROVE_BBSIMPLEX (8) By default there is a check for primal/dual feasibility at optimum only for the relaxed problem, this also activates the test at the node level

Remarks

The default is IMPROVE_DUALFEAS + IMPROVE_THETAGAP (6).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_improve(lp, IMPROVE_DUALFEAS | IMPROVE_BBSIMPLEX);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_improve

./set_infinite.htm000666 000000 000000 00000005715 10237106462 012570 0ustar00000000 000000 set_infinite

set_infinite

Specifies the practical value for "infinite".

void set_infinite(lprec *lp, REAL infinite);

Return Value

set_infinite has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

infinite

The value that must be used for "infinite".

Remarks

The set_infinite function specifies the practical value for "infinite". This value is used for very big numbers. For example the upper bound of a variable without an upper bound.
The default is 1e30

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_infinite(lp, 1.0e100); /* sets infinite to 1e100 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_infinite, is_infinite, set_epsint, get_epsint, set_epsb, get_epsb, set_epsd, get_epsd, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb, set_mip_gap, get_mip_gap

./set_int.htm000666 000000 000000 00000006005 10237106462 011546 0ustar00000000 000000 set_int

set_int

Set the type of the variable. Integer or floating point.

unsigned char set_int(lprec *lp, int column, unsigned char must_be_int);

Return Value

set_int returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be set. It must be between 1 and the number of columns in the lp.

must_be_int

TRUE (1) if the variable must be integer, FALSE (0) if not.

Remarks

The set_int function defines if a variable must be integer or not. Default a variable is not integer. The argument must_be_int defines what the status of the variable becomes. From the moment there is at least one integer variable in the model, the Branch and Bound algorithm is used to make these variables integer. Note that solving times can be considerably larger when there are integer variables. See integer variables for a description about integer variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_int(lp, 1, TRUE); /* sets variable 1 to integer */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_int, is_binary, set_binary

./set_lag_trace.htm000666 000000 000000 00000004451 10553430472 012702 0ustar00000000 000000 set_lag_trace

set_lag_trace

Sets a flag if Lagrangian progression must be printed while solving.

void set_lag_trace(lprec *lp, unsigned char lag_trace);

Return Value

set_lag_trace has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

lag_trace

TRUE or FALSE. Print or do not print.

Remarks

The set_lag_trace function sets a flag if Lagrangian progression must be printed while solving. This function is mend for debugging purposes. The default is not to print (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_lag_trace(lp, TRUE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_lag_trace

./set_lowbo.htm000666 000000 000000 00000005732 11127334362 012105 0ustar00000000 000000 set_lowbo

set_lowbo

Set the lower bound of a variable.

unsigned char set_lowbo(lprec *lp, int column, REAL value);

Return Value

set_lowbo returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable on which the bound must be set. It must be between 1 and the number of columns in the lp.

Remarks

The set_lowbo function sets a lower bound on the variable identified by column.
Setting a bound on a variable is the way to go instead of adding an extra constraint (row) to the model. Setting a bound doesn't increase the model size that means that the model stays smaller and will be solved faster.
Note that the default lower bound of each variable is 0. So variables will never take negative values if no negative lower bound is set.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_lowbo(lp, 1, 1.0);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_lowbo, set_upbo, get_upbo, set_bounds, set_unbounded, is_unbounded, is_negative

./set_lp_name.htm000666 000000 000000 00000004344 10237106464 012375 0ustar00000000 000000 set_lp_name

set_lp_name

Set the name of the lp.

unsigned char set_lp_name(lprec *lp, char *lpname);

Return Value

set_lp_name returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

lpname

The name for the lp.

Remarks

The set_lp_name sets the name of the lp.
Giving the lp a name is optional. The default name is "Unnamed".

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_lp_name(lp, "test");

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_lp_name

./set_mat.htm000666 000000 000000 00000007444 10242041540 011534 0ustar00000000 000000 set_mat

set_mat

Set a single element in the matrix.

unsigned char set_mat(lprec *lp, int row, int column, REAL value);

Return Value

set_mat returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
Note that row entry mode must be off, else this function also fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

Row number of the matrix. Must be between 0 and number of rows in the lp. Row 0 is objective function.

column

Column number of the matrix. Must be between 1 and number of columns in the lp.

value

Value to be set for row row, column column.

Remarks

The set_mat function sets a value in the matrix. If there was already a value for this element, it is replaced and if there was no value, it is added.
This function is not efficient if many values are to be set. Consider to use add_constraint, add_constraintex, str_add_constraint, set_row, set_rowex, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, add_column, add_columnex, str_add_column, set_column, set_columnex.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(2, 3);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_mat(lp, 1, 2, 3.1415927);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_constraint, add_constraintex, str_add_constraint, set_row, set_rowex, set_obj_fn, set_obj_fnex, str_set_obj_fn, add_column, add_columnex, str_add_column, set_column, set_columnex, get_column, get_columnex, get_row, get_rowex, get_mat

./set_maxim.htm000666 000000 000000 00000004252 10237106464 012073 0ustar00000000 000000 set_maxim

set_maxim

Set objective function to maximize.

void set_maxim(lprec *lp);

Return Value

set_maxim has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The set_maxim function sets the objective direction to maximize. The default of lp_solve is to minimize, except for read_lp, read_LP where the default is to maximize.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_maxim(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_maxim, set_minim, set_sense

./set_maxpivot.htm000666 000000 000000 00000005075 10247335336 012636 0ustar00000000 000000 set_maxpivot

set_maxpivot

Sets the maximum number of pivots between a re-inversion of the matrix.

void set_maxpivot(lprec *lp, int max_num_inv);

Return Value

set_maxpivot has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

max_num_inv

The maximum number of pivots between a re-inversion of the matrix.

Remarks

The set_maxpivot function sets the maximum number of pivots between a re-inversion of the matrix.
For stability reasons, lp_solve re-inverts the matrix on regular times. max_num_inv determines how frequently this inversion is done. This can influence numerical stability. However, the more often this is done, the slower the solver becomes.
The default is 250 for the LUSOL bfp and 42 for the other BFPs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_maxpivot(lp, 10);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_maxpivot

./set_minim.htm000666 000000 000000 00000004253 10237106464 012072 0ustar00000000 000000 set_minim

set_minim

Set objective function to minimize.

void set_minim(lprec *lp);

Return Value

set_minim has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The set_minim function sets the objective direction to minimize. The default of lp_solve is to minimize, except for read_lp, read_LP where the default is to maximize.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_minim(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_maxim, is_maxim, set_sense

./set_mip_gap.htm000666 000000 000000 00000006632 10237106464 012400 0ustar00000000 000000 set_mip_gap

set_mip_gap

Specifies the MIP gap value.

void set_mip_gap(lprec *lp, unsigned char absolute, REAL mip_gap);

Return Value

set_mip_gap has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

absolute

If TRUE then the absolute MIP gap is set, else the relative MIP gap

mip_gap

The MIP gap.

Remarks

The set_mip_gap function sets the MIP gap that specifies a tolerance for the branch and bound algorithm. This tolerance is the difference between the best-found solution yet and the current solution. If the difference is smaller than this tolerance then the solution (and all the sub-solutions) is rejected. This can result in faster solving times, but results in a solution which is not the perfect solution. So be careful with this tolerance.
The default mip_gap value is 1e-11

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_mip_gap(lp, TRUE, 1.0e-8); /* sets absolute mip_gap to 1e-8 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_mip_gap, get_epsd, set_epsd, set_infinite, get_infinite, is_infinite, set_epsint, get_epsint, set_epsb, get_epsb, set_epsel, get_epsel, get_epspivot, set_epspivot, set_epsperturb, get_epsperturb

./set_negrange.htm000666 000000 000000 00000005265 10237106464 012553 0ustar00000000 000000 set_negrange

set_negrange

Set negative value below which variables are split into a negative and a positive part.

void set_negrange(lprec *lp, REAL negrange);

Return Value

set_negrange has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

negrange

The negative value below which variables are split into a negative and a positive part.

Remarks

The set_negrange function specifies the negative value below which variables are split into a negative and a positive part. This value must always be zero or negative. If a positive value is specified, then 0 is taken.
In some cases, negative variables must be split in a positive part and a negative part. This is when a negative lower or upper bound is set on a variable. If a bound is less than this value, it is possibly split. The default is -1e6.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_negrange(lp, -1000);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_negrange

./set_obj_bound.htm000666 000000 000000 00000005542 10237106464 012724 0ustar00000000 000000 set_obj_bound

set_obj_bound

Set initial "at least better than" guess for objective function.

void set_obj_bound(lprec *lp, REAL obj_bound);

Return Value

set_obj_bound has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

obj_bound

The initial "at least better than" guess for objective function.

Remarks

The set_obj_bound function specifies the initial "at least better than" guess for objective function. This is only used in the branch-and-bound algorithm when integer variables exist in the model. All solutions with a worse objective value than this value are immediately rejected. This can result in faster solving times, but it can be difficult to predict what value to take for this bound. Also there is the chance that the found solution is not the most optimal one.
The default is infinite.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_obj_bound(lp, 1000);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_obj_bound, , set_break_at_value, get_break_at_value set_mip_gap, get_mip_gap

./set_obj_fn.htm000666 000000 000000 00000013127 10351213172 012206 0ustar00000000 000000 set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj

set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj

Set the objective function (row 0) of the matrix.

unsigned char set_obj_fn(lprec *lp, REAL *row);

unsigned char set_obj_fnex(lprec *lp, int count, REAL *row, int *colno);

unsigned char str_set_obj_fn(lprec *lp, char *row_string);

unsigned char set_obj(lprec *lp, int column, REAL value);

Return Value

set_obj_fn, set_obj_fnex, str_set_obj_fn and set_obj return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

count

Number of elements in row and colno.

row

An array with 1+get_Ncolumns (count for set_obj_fnex) elements that contains the values of the objective function.

colno

An array with count elements that contains the column numbers of the row. However this variable can also be NULL. In that case element i in the variable row is column i.

row_string

A string with column elements that contains the values of the objective function. Each element must be separated by space(s).

column

The column number for which the value must be set.

value

The value that must be set.

Remarks

The set_obj_fn, set_obj_fnex, str_set_obj_fn functions set all values of the objective function at once.
Note that for set_obj_fn (and set_obj_fnex when colno is NULL) element 0 of the array is not considered (i.e. ignored). Column 1 is element 1, column 2 is element 2, ...
set_obj_fnex has the possibility to specify only the non-zero elements. In that case colno specifies the column numbers of the non-zero elements. This will speed up building the model considerably if there are a lot of zero values. In most cases the matrix is sparse and has many zero value. Thus it is almost always better to use set_obj_fnex instead of set_obj_fn. set_obj_fnex is always at least as performant as set_obj_fn. Note that unspecified values by set_obj_fnex are set to zero.
The set_obj function sets the objective value for the specified column. If multiple objective values must be set, it is more performant to use set_obj_fnex.
Note that it is advised to set the objective function before adding rows via add_constraint, add_constraintex, str_add_constraint. This especially for larger models. This will be much more performant than adding the objective function afterwards.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL row[1+2]; /* must be 1 more then number of columns ! */

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  row[1] = 1.0;
  row[2] = 2.0;
  set_obj_fn(lp, row);  /* constructs the obj: +v_1 +2 v_2 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, add_constraint, add_constraintex, str_add_constraint, set_row, set_rowex, add_column, add_columnex, str_add_column, set_column, set_columnex, get_column, get_columnex, get_row, get_rowex, get_mat

./set_obj_in_basis.htm000666 000000 000000 00000005640 10621546234 013403 0ustar00000000 000000 set_obj_in_basis

set_obj_in_basis

Specifies if the objective is in the matrix or not.

void set_obj_in_basis(lprec *lp, unsigned char obj_in_basis);

Return Value

set_obj_in_basis has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

obj_in_basis

TRUE or FALSE. Objective is in matrix or not.

Remarks

The set_obj_in_basis function specifies if the objective is in the matrix or not.
The default is that the objective is in the matrix.

By default, the objective function is stored as the top row in the constraint matrix When this function is called with obj_in_basis = FALSE then it is moved out into separate storage. When out of the basis, the computation of reduced costs is somewhat slower. In the late versions of v5.5, there is now the option to calculate reduced cost in the textbook way, i.e. completely independently of the basis.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_obj_in_basis(lp, FALSE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_obj_in_basis

./set_output.htm000666 000000 000000 00000012000 10617307544 012312 0ustar00000000 000000 set_outputstream, set_outputfile

set_outputstream, set_outputfile

Defines the output when lp_solve has something to report.

void set_outputstream(lprec *lp, FILE *stream);

unsigned char set_outputfile(lprec *lp, char *filename);

Return Value

set_outputstream has no return value.

set_outputfile returns TRUE (1) if the file could be opened, else FALSE (0).

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

stream

The stream to print the results to. If NULL, then output is stdout again.

filename

The file to print the results to. If NULL, then output is stdout again. If "", then output is ignored. It doesn't go to the console or to a file then. This is usefull in combination with put_logfunc to redirect output to somewhere completely different.

Remarks

The set_outputstream, set_outputfile functions define the output when lp_solve has something to report.
This is done at the same time as something is reported via put_logfunc. The default reporting output is screen (stdout). If set_outputstream is called to change output to another stream, then be aware that the stream is not closed automatically when delete_lp is called. Output must be set again to stdout (or NULL) to close this handle or the handle must be closed by the application via a call to fclose afterwards. This allows the application to still print to the stream even after the lp structure is cleaned up. If set_outputfile is called to change output to the specified file, then the file is automatically closed when delete_lp is called. Note that this was not the case in previous versions of lp_solve. If filename is "", then output is ignored. It doesn't go to the console or to a file then. This is usefull in combination with put_logfunc to redirect output to somewhere completely different.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_outputfile(lp, "log.txt");

  /*
  .
  .
  .
  */

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, put_logfunc, print_lp, print_objective, print_solution, print_constraints, print_duals, print_scales, print_tableau, print_str, print_debugdump, write_lp, write_LP, write_mps, write_freemps, write_MPS, write_freeMPS, write_basis

./set_pivoting.htm000666 000000 000000 00000012504 13555461552 012626 0ustar00000000 000000 set_pivoting

set_pivoting

Sets the pivot rule and mode.

void set_pivoting(lprec *lp, int pivoting);

Return Value

set_pivoting has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

pivoting

The pivot rule and mode. Can be one of the following rules:

PRICER_FIRSTINDEX (0) Select first
PRICER_DANTZIG (1) Select according to Dantzig
PRICER_DEVEX (2) Devex pricing from Paula Harris
PRICER_STEEPESTEDGE (3) Steepest Edge

Some of these values can be combined with any (ORed) of the following modes:

PRICE_PRIMALFALLBACK (4) In case of Steepest Edge, fall back to DEVEX in primal
PRICE_MULTIPLE (8) Preliminary implementation of the multiple pricing scheme.This means that attractive candidate entering columnsfrom one iteration may be used in the subsequent iteration, avoiding full updating of reduced costs. In the current implementation, lp_solve only reuses the 2nd best entering column alternative
PRICE_PARTIAL (16) Enable partial pricing
PRICE_ADAPTIVE (32) Temporarily use alternative strategy if cycling is detected
PRICE_RANDOMIZE (128) Adds a small randomization effect to the selected pricer
PRICE_AUTOPARTIAL (256) Indicates automatic detection of segmented/staged/blocked models.It refers to partial pricing rather than full pricing. With full pricing, all non-basic columns are scanned, but with partial pricing only a subset is scanned for every iteration. This can speed up several models
PRICE_AUTOMULTIPLE (512) Automatically select multiple pricing (primal simplex)
PRICE_LOOPLEFT (1024) Scan entering/leaving columns left rather than right
PRICE_LOOPALTERNATE (2048) Scan entering/leaving columns alternatingly left/right
PRICE_HARRISTWOPASS (4096) Use Harris' primal pivot logic rather than the default
PRICE_TRUENORMINIT (16384) Use true norms for Devex and Steepest Edge initializations

Remarks

The set_pivoting function specifies the pivot rule (rule for selecting row and column entering/leaving) and mode. The rule is an exclusive option and the mode is a modifier to the rule. This rule/mode can influence solving times considerably. Depending on the model one rule/mode can be best and for another model another rule/mode.
The default is PRICER_DEVEX | PRICE_ADAPTIVE (34).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_pivoting(lp, PRICER_FIRSTINDEX);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_pivoting, is_piv_rule, is_piv_mode

./set_preferdual.htm000666 000000 000000 00000005305 10237106464 013111 0ustar00000000 000000 set_preferdual

set_preferdual

Sets the desired combination of primal and dual simplex algorithms.

void set_preferdual(lprec *lp, unsigned char dodual);

Return Value

set_preferdual has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

dodual

When TRUE, the simplex strategy is set to SIMPLEX_DUAL_DUAL.
When FALSE, the simplex strategy is set to SIMPLEX_PRIMAL_PRIMAL.
See also get_simplextype

Remarks

The set_preferdual function sets the desired combination of primal and dual simplex algorithms.
set_preferdual with dodual = TRUE is a shortcut for set_simplextype(SIMPLEX_DUAL_DUAL)
set_preferdual with dodual = FALSE is a shortcut for set_simplextype(SIMPLEX_PRIMAL_PRIMAL)
The default is SIMPLEX_DUAL_PRIMAL (6).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_preferdual(lp, TRUE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_simplextype

./set_presolve.htm000666 000000 000000 00000023721 11301707642 012617 0ustar00000000 000000 set_presolve

set_presolve

Specifies if a presolve must be done before solving.

void set_presolve(lprec *lp, int do_presolve, int maxloops);

Return Value

set_presolve has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

do_presolve

Specifies presolve level. Can be the (OR) combination of any of the following values:

PRESOLVE_NONE (0) No presolve at all
PRESOLVE_ROWS (1) Presolve rows
PRESOLVE_COLS (2) Presolve columns
PRESOLVE_LINDEP (4) Eliminate linearly dependent rows
PRESOLVE_SOS (32) Convert constraints to SOSes (only SOS1 handled)
PRESOLVE_REDUCEMIP (64) If the phase 1 solution process finds that a constraint is redundant then this constraint is deleted. This is no longer active since it is very rare that this is effective, and also that it adds code complications and delayed presolve effects that are not captured properly.
PRESOLVE_KNAPSACK (128) Simplification of knapsack-type constraints through addition of an extra variable, which also helps bound the OF
PRESOLVE_ELIMEQ2 (256) Direct substitution of one variable in 2-element equality constraints; this requires changes to the constraint matrix. Elimeq2 simply eliminates a variable by substitution when you have 2-element equality constraints. This can sometimes cause fill-in of the constraint matrix, and also be a source of rounding errors which can lead to problems in the simplex.
PRESOLVE_IMPLIEDFREE (512) Identify implied free variables (releasing their explicit bounds)
PRESOLVE_REDUCEGCD (1024) Reduce (tighten) coefficients in integer models based on GCD argument. Reduce GCD is for mixed integer programs where it is possible to adjust the constraint coefficies due to integrality. This can cause the dual objective ("lower bound") to increase and may make it easier to prove optimality.
PRESOLVE_PROBEFIX (2048) Attempt to fix binary variables at one of their bounds
PRESOLVE_PROBEREDUCE (4096) Attempt to reduce coefficients in binary models
PRESOLVE_ROWDOMINATE (8192) Idenfify and delete qualifying constraints that are dominated by others, also fixes variables at a bound
PRESOLVE_COLDOMINATE (16384) Deletes variables (mainly binary), that are dominated by others (only one can be non-zero)
PRESOLVE_MERGEROWS (32768) Merges neighboring >= or <= constraints when the vectors are otherwise relatively identical into a single ranged constraint
Converts qualifying equalities to inequalities by converting a column singleton variable to slack. The routine also detects implicit duplicate slacks from inequality constraints, fixes and removes the redundant variable.This latter removal also tends to reduce the risk of degeneracy.The combined function of this option can have a dramatic simplifying effect on some models. Implied slacks is when, for example, there is a column singleton (with zero OF) in an equality constraint. In this case, the column can be deleted and the constraint converted to a LE constraint.
PRESOLVE_COLFIXDUAL (131072) Variable fixing and removal based on considering signs of the associated dual constraint. Dual fixing is when the (primal) variable can be fixed due to the implied value of the dual being infinite.
PRESOLVE_BOUNDS (262144) Does bound tightening based on full-row constraint information. This can assist in tightening the OF bound, eliminate variables and constraints. At the end of presolve, it is checked if any variables can be deemed free, thereby reducing any chance that degeneracy is introduced via this presolve option.
PRESOLVE_DUALS (524288) Calculate duals
PRESOLVE_SENSDUALS (1048576) Calculate sensitivity if there are integer variables

maxloops

The maximum number of times presolve may be done. Use get_presolveloops if you don't want to change this value.


Remarks

The set_presolve function specifies if a presolve must be done before solving. Presolve looks at the model and tries to simplify it so that solving times are shorter. For example a constraint on only one variable is converted to a bound on this variable (and the constraint is deleted). Note that the model dimensions can change because of this, so be careful with this. Both rows and columns can be deleted by the presolve.
The maxloops variable specifies the maximum number of times presolve is done. After a presolve is done, another presolve can again result in elimination of extra rows and/or columns. This number specifies the maximum number of times this process is repeated. By default this is until presolve has nothing to do anymore. Use get_presolveloops if you don't want to change this value.
Note that PRESOLVE_LINDEP can result in deletion of rows (the linear dependent ones). get_constraints, get_ptr_constraints will then return only the values of the rows that are kept and the values of the deleted rows are not known anymore. The default is not (PRESOLVE_NONE) doing a presolve. The following code can be used to retrieve the values of all the variables, even if variables are deleted by presolve:

int Norig_columns, Norig_rows, i;
REAL value;

Norig_columns = get_Norig_columns(lp);
Norig_rows = get_Norig_rows(lp);
for(i = 1; i <= Norig_columns; i++) {
  value = get_var_primalresult(lp, Norig_rows + i);
  printf("%f\n", value);
}

Note that there is no possibility to get the values of deleted rows.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_presolve(lp, PRESOLVE_ROWS | PRESOLVE_COLS | PRESOLVE_LINDEP, get_presolveloops(lp));

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_presolve, get_presolveloops, is_presolve

./set_print_sol.htm000666 000000 000000 00000005272 10246267510 012774 0ustar00000000 000000 set_print_sol

set_print_sol

Sets a flag if all intermediate valid solutions must be printed while solving.

void set_print_sol(lprec *lp, int print_sol);

Return Value

set_print_sol has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

print_sol

FALSE (0) No printing
TRUE (1) Print all values
AUTOMATIC (2) Print only non-zero values

Remarks

The set_print_sol function sets a flag if all intermediate valid solutions must be printed while solving. Can give you useful solutions even if the total run time is too long. This function is mend for debugging purposes. The default is not to print (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_print_sol(lp, TRUE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_print_sol

./set_rh.htm000666 000000 000000 00000006257 10242041552 011370 0ustar00000000 000000 set_rh

set_rh

Set the value of the right hand side (RHS) vector (column 0) for one row.

unsigned char set_rh(lprec *lp, int row, REAL value);

Return Value

set_rh returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the RHS value must be set. Must be between 0 and number of rows in the lp.

value

The value of the RHS.

Remarks

The set_rh function sets the value of the RHS vector (column 0) for the specified row.
Note that row can also be 0 with this function. In that case an initial value for the objective value is set. Functions set_rh_vec, str_set_rh_vec ignore row 0 (for historical reasons) in the specified RHS vector, but it is possible to first call one of these functions and then set the value of the objective with set_rh.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(2, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_rh(lp, 1, 1.0); /* sets the value 1.0 for RHS row 1 */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_rh_vec, str_set_rh_vec, get_rh, add_constraint, add_constraintex, str_add_constraint, get_row, get_rowex, get_mat

./set_rh_range.htm000666 000000 000000 00000006112 10237106464 012542 0ustar00000000 000000 set_rh_range

set_rh_range

Set the range on a constraint.

unsigned char set_rh_range(lprec *lp, int row, REAL deltavalue);

Return Value

set_rh_range returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row number of the constraint on which the range must be set. It must be between 1 and the number of rows in the lp.

deltavalue

The range on the constraint.

Remarks

The set_rh_range function sets a range on the constraint (row) identified by row.
Setting a range on a row is the way to go instead of adding an extra constraint (row) to the model. Setting a range doesn't increase the model size that means that the model stays smaller and will be solved faster.
If the row has a less than constraint then the range means setting a minimum on the constraint that is equal to the RHS value minus the range. If the row has a greater than constraint then the range means setting a maximum on the constraint that is equal to the RHS value plus the range.
Note that the range value is the difference value and not the absolute value.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_rh_range(lp, 1, 1.0);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_rh_range

./set_rh_vec.htm000666 000000 000000 00000006775 10242041466 012236 0ustar00000000 000000 set_rh_vec, str_set_rh_vec

set_rh_vec, str_set_rh_vec

Set the right hand side (RHS) vector (column 0).

void set_rh_vec(lprec *lp, REAL *rh);

unsigned char str_set_rh_vec(lprec *lp, char *rh_string);

Return Value

set_rh_vec has no return value. str_set_rh_vec returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

rh

An array with row elements that contains the values of the RHS.

rh_string

A string with row elements that contains the values of the RHS. Each element must be separated by space(s).

Remarks

The set_rh_vec, str_set_rh_vec functions set all values of the RHS vector (column 0) at once.
Note that element 0 of the array is not considered (i.e. ignored). Row 1 is element 1, row 2 is element 2, ...
If the initial value of the objective function must also be set, use set_rh.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL rhs[1+2]; /* must be 1 more then number of rows ! */

  /* Create a new LP model */
  lp = make_lp(2, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  rhs[1] = 1.0;
  rhs[2] = 2.0;
  set_rh_vec(lp, rhs);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_rh, get_rh, add_constraint, add_constraintex, str_add_constraint, add_column, add_columnex, str_add_column, get_mat, get_column, get_columnex, set_column, set_columnex, get_row, get_rowex, set_row, set_rowex

./set_row.htm000666 000000 000000 00000013431 10351213412 011553 0ustar00000000 000000 set_row, set_rowex

set_row, set_rowex

set a constraint in the lp.

unsigned char set_row(lprec *lp, int row_no, REAL *row);

unsigned char set_rowex(lprec *lp, int row_no, int count, REAL *row, int *colno);

Return Value

set_row, set_rowex return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row_no

The row number that must be changed.

count

Number of elements in row and colno.

row

An array with 1+get_Ncolumns (count for set_rowex, if colno is different from NULL) elements that contains the values of the row.

colno

A zero-based array with count elements that contains the column numbers of the row. However this variable can also be NULL. In that case element i in the variable row is column i and values start at element 1.

Remarks

The set_row, set_rowex functions change the values of an existing row in the model at once.

Note that add_constraint, add_constraintex, str_add_constraint add a row to the model, making the number of rows one larger. These functions change an existing row.

Note that for set_row (and set_rowex when colno is NULL) element 1 of the array is column 1, element 2 is column 2, ... element 0 is not used.

set_rowex has the possibility to specify only the non-zero elements. And in contrary to set_row, set_rowex reads the arrays starting from element 0. However when colno is NULL then set_rowex acts as set_row and then values start at element 1. When colno is provided, then it specifies the column numbers of the non-zero elements. This will speed up building the model considerably if there are a lot of zero values.

In most cases the matrix is sparse and has many zero value. Thus it is almost always better to use set_rowex instead of set_row. set_rowex is always at least as performant as set_row.

It is more performant to call these functions than multiple times set_mat.

Note that unspecified values by set_rowex are set to zero.

Note that these routines will perform much better when set_add_rowmode is called before adding constraints.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL row[1+3];     /* must be 1 more than number of columns ! */
  REAL sparserow[2]; /* must be the number of non-zero values */
  int colno[2];

  /* Create a new LP model */
  lp = make_lp(2, 3);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  row[1] = 1.0;
  row[2] = 0.0; /* also zero elements must be provided */
  row[3] = 2.0;
  set_row(lp, 1, row); /* changes the values of existing row 1 */
  
  colno[0] = 1; sparserow[0] = 1.0; /* column 1 */
  colno[1] = 3; sparserow[1] = 2.0; /* column 3 */
  set_rowex(lp, 2, 2, sparserow, colno);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_row, get_rowex, add_constraint, add_constraintex, str_add_constraint, set_obj_fn, set_obj_fnex, str_set_obj_fn, set_obj, set_add_rowmode, is_add_rowmode, get_constr_type, is_constr_type, del_constraint, add_column, add_columnex, str_add_column, set_column, set_columnex, get_column, get_columnex, get_mat

./set_row_name.htm000666 000000 000000 00000005225 10237106464 012570 0ustar00000000 000000 set_row_name

set_row_name

Set the name of a constraint (row) in the lp.

unsigned char set_row_name(lprec *lp, int row, char *new_name);

Return Value

set_row_name returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

row

The row for which the name must be set. Must be between 0 and the number of rows in the lp.

new_name

The name for the row.

Remarks

The set_row_name sets the name of the row.
The row must already exist. row 0 is the objective function. Row names are optional.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(1, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_row_name(lp, 1, "row1");

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_row_name, get_origrow_name, set_col_name, get_col_name, get_origcol_name, get_nameindex

./set_scalelimit.htm000666 000000 000000 00000005321 10237106464 013104 0ustar00000000 000000 set_scalelimit

set_scalelimit

Sets the relative scaling convergence criterion for the active scaling mode; the integer part specifies the maximum number of iterations.

void set_scalelimit(lprec *lp, REAL scalelimit);

Return Value

set_scalelimit has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

scalelimit

The relative scaling convergence criterion for the active scaling mode; the integer part specifies the maximum number of iterations

Remarks

The set_scalelimit function sets the relative scaling convergence criterion for the active scaling mode; the integer part specifies the maximum number of iterations (default is 5).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_scalelimit(lp, 3.1);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_scalelimit, set_scaling, get_scaling, is_integerscaling, is_scalemode, is_scaletype

./set_scaling.htm000666 000000 000000 00000015155 10246631576 012413 0ustar00000000 000000 set_scaling

set_scaling

Specifies which scaling algorithm must be used.

void set_scaling(lprec *lp, int scalemode);

Return Value

set_scaling has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

scalemode

Specifies which scaling algorithm must be used. Can by any of the following values:

SCALE_NONE (0) No scaling
SCALE_EXTREME (1) Scale to convergence using largest absolute value
SCALE_RANGE (2) Scale based on the simple numerical range
SCALE_MEAN (3) Numerical range-based scaling
SCALE_GEOMETRIC (4) Geometric scaling
SCALE_CURTISREID (7) Curtis-reid scaling

Additionally, the value can be OR-ed with any combination of one of the following values:

SCALE_QUADRATIC (8)  
SCALE_LOGARITHMIC (16) Scale to convergence using logarithmic mean of all values
SCALE_USERWEIGHT (31) User can specify scalars
SCALE_POWER2 (32) also do Power scaling
SCALE_EQUILIBRATE (64) Make sure that no scaled number is above 1
SCALE_INTEGERS (128) also scaling integer variables
SCALE_DYNUPDATE (256) dynamic update
SCALE_ROWSONLY (512) scale only rows
SCALE_COLSONLY (1024) scale only columns

Remarks

The set_scaling function specifies which scaling algorithm must be used. This can influence numerical stability considerably. It is advisable to always use some sort of scaling.
set_scaling must be called before solve is called.
SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC, SCALE_CURTISREID are the possible scaling algorithms. SCALE_QUADRATIC, SCALE_LOGARITHMIC, SCALE_USERWEIGHT, SCALE_POWER2, SCALE_EQUILIBRATE, SCALE_INTEGERS are possible additional scaling parameters.
SCALE_POWER2 results in creating a scalar of power 2. May improve stability.
SCALE_INTEGERS results also in scaling Integer columns. Default they are not scaled.
SCALE_DYNUPDATE is new from version 5.1.1.0
It has always been so that scaling is done only once on the original model. If a solve is done again (most probably after changing some data in the model), the scaling factors aren't computed again. The scalars of the original model are used. This is not always good, especially if the data has changed considerably. One way to solve this was/is call unscale before a next solve. In that case, scale factors are recomputed.
From version 5.1.1.0 on, there is another way to make sure that scaling factors are recomputed and this is by settings SCALE_DYNUPDATE. In that case, the scaling factors are recomputed also when a restart is done. Note that they are then always recalculated with each solve, even when no change was made to the model, or a change that doesn't influence the scaling factors like changing the RHS (Right Hand Side) values or the bounds/ranges. This can influence performance. It is up to you to decide if scaling factors must be recomputed or not for a new solve, but by default it still isn't so. It is possible to set/unset this flag at each next solve and it is even allowed to choose a new scaling algorithm between each solve. Note that the scaling done by the SCALE_DYNUPDATE is incremental and the resulting scalarsare typically different from scalars recomputed from scratch.
The default is SCALE_GEOMETRIC + SCALE_EQUILIBRATE + SCALE_INTEGERS (196).

Also see scaling for a description about scaling.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_scaling(lp, CURTISREIDSCALE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_scaling, is_integerscaling, is_scalemode, is_scaletype

./set_semicont.htm000666 000000 000000 00000006327 10237106464 012606 0ustar00000000 000000 set_semicont

set_semicont

Set the type of the variable. semi-continuous or not.

unsigned char set_semicont(lprec *lp, int column, unsigned char must_be_sc);

Return Value

set_semicont returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be set. It must be between 1 and the number of columns in the lp.

must_be_sc

TRUE (1) if the variable must be semi-continuous, FALSE (0) if not.

Remarks

The set_semicont function defines if a variable is semi-continuous or not. By default, a variable is not semi-continuous. The argument must_be_sc defines what the status of the variable becomes.
Note that a semi-continuous variable must also have a lower bound to have effect. This because the default lower bound on variables is zero, also when defined as semi-continuous, and without a lower bound it has no point to define a variable as such. The lower bound may be set before or after setting the semi-continuous status. See semi-continuous variables for a description about semi-continuous variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_lowbo(lp, 1, 2.0);
  set_semicont(lp, 1, TRUE); /* sets variable 1 to semi-continuous */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_semicont, set_lowbo

./set_sense.htm000666 000000 000000 00000004531 10237106464 012075 0ustar00000000 000000 set_sense

set_sense

Set objective function sense.

void set_sense(lprec *lp, unsigned char maximize);

Return Value

set_sense has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

maximize

Set sense to minimize (FALSE) or maximize (TRUE).

Remarks

The set_sense function sets the objective sense. The default of lp_solve is to minimize, except for read_lp, read_LP where the default is to maximize.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_sense(lp, TRUE); /* set object sense to maximize */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_minim, set_maxim, is_maxim

./set_simplextype.htm000666 000000 000000 00000005703 10246270314 013341 0ustar00000000 000000 set_simplextype

set_simplextype

Sets the desired combination of primal and dual simplex algorithms.

void set_simplextype(lprec *lp, int simplextype);

Return Value

set_simplextype has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

simplextype

The desired combination of primal and dual simplex algorithms. Can by any of the following values:

SIMPLEX_PRIMAL_PRIMAL (5) Phase1 Primal, Phase2 Primal
SIMPLEX_DUAL_PRIMAL (6) Phase1 Dual, Phase2 Primal
SIMPLEX_PRIMAL_DUAL (9) Phase1 Primal, Phase2 Dual
SIMPLEX_DUAL_DUAL (10) Phase1 Dual, Phase2 Dual

Remarks

The set_simplextype function sets the desired combination of primal and dual simplex algorithms. The default is SIMPLEX_DUAL_PRIMAL (6).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_simplextype(lp, SIMPLEX_PRIMAL_DUAL);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_simplextype, set_preferdual

./set_solutionlimit.htm000666 000000 000000 00000005274 10237106464 013700 0ustar00000000 000000 set_solutionlimit

set_solutionlimit

Sets the solution number that must be returned.

void set_solutionlimit(lprec *lp, int limit);

Return Value

set_solutionlimit has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

limit

The solution number that must be returned. This value gives the number of the solution that must be returned.

Remarks

This function is only valid if there are integer, semi-continious or SOS variables in the model so that the branch-and-bound algoritm is used. If there are more solutions with the same objective value, then this number specifies which solution must be returned. This can be used to retrieve all possible solutions. Start with 1 till get_solutioncount

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_solutionlimit(lp, 3); /* return the 3rd solution */

  solve(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_solutionlimit, get_solutioncount

./set_timeout.htm000666 000000 000000 00000005654 10237106464 012455 0ustar00000000 000000 set_timeout

set_timeout

Set a timeout.

void set_timeout(lprec *lp, long sectimeout);

Return Value

set_timeout has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

sectimeout

The number of seconds after which a timeout occurs. If zero, then no timeout will occur.

Remarks

The set_timeout function sets a timeout in seconds. The solve and lag_solve functions may not last longer than this time or the routines return with a timeout. The default timeout is 0, resulting in no timeout.
If a timout occurs, but there was already an integer solution found (that is possibly not the best), then solve will return SUBOPTIMAL. If there was no integer solution found yet or there are no integers or the solvers is still in the first phase where a REAL optimal solution is searched for, then solve will return TIMEOUT.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_timeout(lp, 600); /* sets a timeout of 600 seconds (10 minutes) */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_timeout, time_elapsed, solve, lag_solve

./set_trace.htm000666 000000 000000 00000004367 10237106464 012065 0ustar00000000 000000 set_trace

set_trace

Sets a flag if pivot selection must be printed while solving.

void set_trace(lprec *lp, unsigned char trace);

Return Value

set_trace has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

trace

TRUE or FALSE. Print or do not print.

Remarks

The set_trace function sets a flag if pivot selection must be printed while solving. This function is mend for debugging purposes. The default is not to print (FALSE).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_trace(lp, TRUE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_trace

./set_unbounded.htm000666 000000 000000 00000005612 11127334376 012750 0ustar00000000 000000 set_unbounded

set_unbounded

Sets if the variable is free.

unsigned char set_unbounded(lprec *lp, int column);

Return Value

set_unbounded returns TRUE (1) if the variable could be set as free, FALSE (0) otherwise.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable that must be set. It must be between 1 and the number of columns in the lp.

Remarks

The set_unbounded function sets if a variable is free or not. Free means a lower bound of -infinity and an upper bound of +infinity. Default a variable is not free because default it has a lower bound of 0 (and an upper bound of +infinity). See free variables for a description about free variables.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_unbounded(lp, 1); /* will return 0 since the variable is not set as free at this point */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_upbo, set_upbo, set_lowbo, get_lowbo, set_bounds, is_unbounded, is_negative

./set_upbo.htm000666 000000 000000 00000005736 11127334406 011733 0ustar00000000 000000 set_upbo

set_upbo

Set the upper bound of a variable.

unsigned char set_upbo(lprec *lp, int column, REAL value);

Return Value

set_upbo returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable on which the bound must be set. It must be between 1 and the number of columns in the lp.

Remarks

The set_upbo function sets an upper bound on the variable identified by column.
Setting a bound on a variable is the way to go instead of adding an extra constraint (row) to the model. Setting a bound doesn't increase the model size that means that the model stays smaller and will be solved faster.
The default upper bound of a variable is infinity (well not quite. It is a very big number, the value of get_infinite).

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_upbo(lp, 1, 1.0);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_upbo, set_lowbo, get_lowbo, set_bounds, set_unbounded, is_unbounded, is_negative

./set_use_names.htm000666 000000 000000 00000005746 10242072416 012743 0ustar00000000 000000 set_use_names

set_use_names

Sets if variable or constraint names are used.

void set_use_names(lprec *lp, unsigned char isrow, unsigned char use_names);

Return Value

set_use_names has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

isrow

Set to FALSE (0) if column information is needed and TRUE (1) if row information is needed.

use_names

If FALSE (0), then names are not used, else they are.

Remarks

When a model is read from file or created via the API, variables and constraints can be named. These names are used to report information or to save the model in a given format. However, sometimes it is required to ignore these names and to use the internal names of lp_solve. This is for example the case when the names do not comply to the syntax rules of the format that will be used to write the model to.
Names are used by default.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_use_names(lp, FALSE, FALSE); /* specify that variable names are ignored */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, is_use_names, set_col_name, get_col_name, set_row_name, get_row_name

./set_var_branch.htm000666 000000 000000 00000007504 10237106464 013070 0ustar00000000 000000 set_var_branch

set_var_branch

Specifies, for the specified variable, which branch to take first in branch-and-bound algorithm.

unsigned char set_var_branch(lprec *lp, int column, int branch_mode);

Return Value

set_var_branch returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

column

The column number of the variable on which the mode must be set. It must be between 1 and the number of columns in the lp.

branch_mode

Specifies, for the specified variable, which branch to take first in branch-and-bound algorithm.
Can by any of the following values:

BRANCH_CEILING (0) Take ceiling branch first
BRANCH_FLOOR (1) Take floor branch first
BRANCH_AUTOMATIC (2) Algorithm decides which branch being taken first
BRANCH_DEFAULT (3) Use the branch mode specified with set_bb_floorfirst

Remarks

The set_var_branch function specifies which branch to take first in branch-and-bound algorithm. This can influence solving times considerably. Depending on the model one rule can be best and for another model another rule.
The default is BRANCH_DEFAULT (3). BRANCH_DEFAULT (3) means that the branch mode specified with set_bb_floorfirst function must be used.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 1);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_var_branch(lp, 1, BRANCH_AUTOMATIC);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_var_branch, set_bb_floorfirst, get_bb_floorfirst, set_var_weights, get_var_priority

./set_var_weights.htm000666 000000 000000 00000006025 10237106466 013304 0ustar00000000 000000 set_var_weights

set_var_weights

Set the weights on variables.

unsigned char set_var_weights(lprec *lp, REAL *weights);

Return Value

set_var_weights returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

weights

The weights array.

Remarks

The set_var_weights sets a weight factor on each variable. This is only used for the integer variables in the branch-and-bound algorithm. Array members are unique, real-valued numbers indicating the "weight" of the variable at the given index. The array is 0-based. So variable 1 is at index 0, variable 2 at index 1. The array must contain get_Ncolumns elements.
The weights define which variable the branch-and-bound algorithm must select first. The lower the weight, the sooner the variable is chosen to make it integer.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  REAL weights[2];

  /* Create a new LP model */
  lp = make_lp(0, 2);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  weights[0] = 2;
  weights[1] = 1;

  set_var_weights(lp, weights);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_var_priority, set_var_branch, get_var_branch, set_bb_floorfirst, get_bb_floorfirst

./set_verbose.htm000666 000000 000000 00000007523 10255022600 012416 0ustar00000000 000000 set_verbose

set_verbose

Set the verbose level.

void set_verbose(lprec *lp, int verbose);

Return Value

set_verbose has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

verbose

The verbose level. Can be one of the following values:

NEUTRAL (0) Only some specific debug messages in de debug print routines are reported.
CRITICAL (1) Only critical messages are reported. Hard errors like instability, out of memory, ...
SEVERE (2) Only severe messages are reported. Errors.
IMPORTANT (3) Only important messages are reported. Warnings and Errors.
NORMAL (4) Normal messages are reported. This is the default.
DETAILED (5) Detailed messages are reported. Like model size, continuing B&B improvements, ...
FULL (6) All messages are reported. Useful for debugging purposes and small models.

Remarks

The set_verbose function sets the verbose level.
lp_solve reports information back to the user. How much information is reported depends on the verbose level. The default verbose level is NORMAL (4). lp_solve determines how verbose a given message is. For example specifying a wrong row/column index values is considered as a SEVERE error. verbose determines how much of the lp_solve message are reported. All messages equal to and below the set level are reported.
The default reporting device is the console screen. It is possible to set a used defined reporting routine via put_logfunc.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_verbose(lp, NORMAL);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_verbose, put_logfunc

./set_XLI.htm000666 000000 000000 00000005021 10461420102 011372 0ustar00000000 000000 set_XLI

set_XLI

Set External Language Interfaces package.

unsigned char set_XLI(lprec *lp, char *filename);

Return Value

set_XLI returns TRUE if the call has succeeded, else FALSE.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

The name of the XLI package.

Remarks

The set_XLI function sets the External Language Interface (XLI). This call is normally only needed when write_XLI will be called. read_XLI automatically calls this routine. See External Language Interfaces for a complete description on XLIs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_XLI(lp, "xli_MathProg");

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, write_XLI, has_XLI, is_nativeXLI

./simpletree.css000666 000000 000000 00000001357 11034146200 012245 0ustar00000000 000000 .treeview ul{ /*CSS for Simple Tree Menu*/ margin: 0; padding: 0; } .treeview li{ /*Style for LI elements in general (excludes an LI that contains sub lists)*/ margin-left: -2em; background: white url(list.gif) no-repeat left center; list-style-type: none; padding-left: 22px; margin-bottom: 3px; } .treeview li.submenu{ /* Style for LI that contains sub lists (other ULs). */ background: white url(closed.gif) no-repeat left 1px; cursor: hand !important; cursor: pointer !important; } .treeview li.submenu ul{ /*Style for ULs that are children of LIs (submenu) */ margin-left: 2em; display: none; /*Hide them by default. Don't delete. */ } .treeview .submenu ul li{ /*Style for LIs of ULs that are children of LIs (submenu) */ cursor: default; }./simpletreemenu.js000666 000000 000000 00000013346 11034122434 012762 0ustar00000000 000000 var persisteduls=new Object() var ddtreemenu=new Object() ddtreemenu.closefolder="closed.gif" //set image path to "closed" folder image ddtreemenu.openfolder="open.gif" //set image path to "open" folder image //////////No need to edit beyond here/////////////////////////// ddtreemenu.createTree=function(treeid, enablepersist, persistdays){ var ultags=document.getElementById(treeid).getElementsByTagName("ul") if (typeof persisteduls[treeid]=="undefined") persisteduls[treeid]=(enablepersist==true && ddtreemenu.getCookie(treeid)!="")? ddtreemenu.getCookie(treeid).split(",") : "" for (var i=0; i solve

solve

solve the model.

int solve(lprec *lp);

Return Value

NOMEMORY (-2) Out of memory
OPTIMAL (0) An optimal solution was obtained
SUBOPTIMAL (1) The model is sub-optimal. Only happens if there are integer variables and there is already an integer solution found. The solution is not guaranteed the most optimal one.
  • A timeout occured (set via set_timeout or with the -timeout option in lp_solve)
  • set_break_at_first was called so that the first found integer solution is found (-f option in lp_solve)
  • set_break_at_value was called so that when integer solution is found that is better than the specified value that it stops (-o option in lp_solve)
  • set_mip_gap was called (-g/-ga/-gr options in lp_solve) to specify a MIP gap
  • An abort function is installed (put_abortfunc) and this function returned TRUE
  • At some point not enough memory could not be allocated
INFEASIBLE (2) The model is infeasible
UNBOUNDED (3) The model is unbounded
DEGENERATE (4) The model is degenerative
NUMFAILURE (5) Numerical failure encountered
USERABORT (6) The abort routine returned TRUE. See put_abortfunc
TIMEOUT (7) A timeout occurred. A timeout was set via set_timeout
PRESOLVED (9) The model could be solved by presolve. This can only happen if presolve is active via set_presolve
ACCURACYERROR (25) Accuracy error encountered

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The solve function solves the model. solve can be called more than once. Between calls, the model may be modified in every way. Restrictions may be changed, matrix values may be changed and even rows and/or columns may be added or deleted.
If set_timeout was called before solve with a non-zero timeout and a timout occurs, and there was already an integer solution found (that is possibly not the best), then solve will return SUBOPTIMAL. If there was no integer solution found yet or there are no integers or the solvers is still in the first phase where a REAL optimal solution is searched for, then solve will return TIMEOUT.
If set_presolve was called before solve, then it can happen that presolve eliminates all rows and columns such that the solution is known by presolve. In that case, no solve is done. This also means that values of constraints and sensitivity are unknown. solve will return PRESOLVED in this case.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  ret = solve(lp);

  delete_lp(lp);

  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, lag_solve, statustext, is_feasible, get_objective, get_working_objective, get_variables, get_ptr_variables, get_constraints, get_ptr_constraints, get_constr_value, get_primal_solution, get_ptr_primal_solution, get_var_primalresult, get_sensitivity_rhs, get_ptr_sensitivity_rhs, get_dual_solution, get_ptr_dual_solution, get_var_dualresult, get_sensitivity_obj, get_ptr_sensitivity_obj, get_sensitivity_objex, get_ptr_sensitivity_objex

./SOS.htm000666 000000 000000 00000067545 10512203612 010554 0ustar00000000 000000 Special Ordered Sets

Special Ordered Sets (SOS)

Special Ordered Sets of Type One

A Special Ordered Set of type One (SOS1) is defined to be a set of variables for which not more than one member from the set may be non-zero in a feasible solution. All such sets are mutually exclusive of each other, the members are not subject to any other discrete conditions and are grouped together consecutively in the data.

The normal use of an SOS1 is to represent a set of mutually exclusive alternatives ordered in increasing values of size, cost or some other suitable units appropriate to the context of the model. This representation is a discrete programming extension of the separable programming model. There is a strong implied assumption that a non-linear function represented in this way is single valued over the range of its argument.

Consider a function g(y) represented by the points P1,...,PK as shown in figure 2.

image\img00341.gif

Figure 2

 

Given the tabulated coordinates image\img00342.gif k=1,...,K, the function g(y) may be represented as

  image\img00343.gif     (1)

where

  image\img00344.gif     (2)

  image\img00345.gif     (3)

The discrete function can take only one of the image\img00346.gif possible values weighted by the variables image\img00347.gif, of which only one can be non-zero, and that must have the value one.

This requirement could be expressed by restricting each xk to be a binary variable but the alternative of defining them collectively as a special ordered set of type one, which is a direct statement of their nature, leads to a more efficient solution process.

The weighting variables xk are called special ordered set type one variables and the rows (1), (2), and (3) are called function rows, reference rows and convexity rows respectively. Should the SOS1's not represent a modelling of discrete, separable variables then none of these rows need actually exist, but there is an advantage to the system if it is aware of the reference rows at least.


Special Ordered Sets of Type Two

A Special Ordered Set of type Two (SOS2) is a set of consecutive variables in which not more than two adjacent members may be non-zero in a feasible solution. All such sets are mutually exclusive of each other, the members are not subject to any other discrete conditions and each set is grouped together consecutively in the data.

SOS2s were introduced to make it easier to find global optimum solutions to problems containing piecewise linear approximations to a non-linear function of a single argument (as in classical Separable Programming). The overall problem has an otherwise LP or an IP structure except for such non-linear functions.

Consider the function image\img00348.gif illustrated in Figure 3 as a piecewise linear function in one variable defined over the closed intervals image\img00349.gif, where the coordinates image\img00350.gif, represent points P1,...,PK.

 

image\img00351.gif

Figure 3

 

Any point image\img00352.gif in the closed interval image\img00353.gif may be written as

image\img00354.gif

where

image\img00355.gif.

Similarly, as image\img00356.gif is linear in the interval, it can be written as

image\img00357.gif.

This leads to the representation of image\img00358.gif using a set of weighting variables, image\img00359.gif, by the equality

  image\img00360.gif     (4)

where

  image\img00361.gif     (5)

  image\img00362.gif.    (6)

Plus the added condition that not more than two adjacent variables can be non-zero at any one time.

The weighting variables xk are called the special ordered set type two variables and the rows (4), (5), and (6) are called function rows, reference rows and the convexity rows respectively, as in equations (1), (2) and (3) of Topic "Special Ordered Sets of Type One". Should the SOS2's not represent separable functions then none of these rows need actually exist, but there is an advantage to the system if it is aware of the reference rows at least.

 

The lp_solve implementation of SOS is the following:

A specially ordered set of degree N is a collection of variables where at most N variables may be non-zero. The non-zero variables must be contiguous (neighbours) sorted by the ascending value of their respective unique weights. In lp_solve, specially ordered sets may be of any cardinal type 1, 2, and higher, and may be overlapping. The number of variables in the set must be equal to, or exceed the cardinal SOS order.

lp_solve supports Special Ordered Sets via the API interface, in the MPS format and in the lp format (from release 4.0.1.11).

Below is a representation of a SOS in an MPS file, where each SOS is defined in its own SOS section, which should follow the BOUNDS section.

0        1         2         3         4
1234567890123456789012345678901234567890
SOS
 Sx CaseName  SOSName.  SOSpriority.
    CaseName  VarName1  VarWeight1..
    CaseName  VarName2  VarWeight2..

    CaseName  VarNameN  VarWeightN..

x at the second line, position 3, defines is the order of the SOS. Due to limitations in the MPS format, N is restricted to the 1..9 range. Each SOS should be given a unique name, SOSName. lp_solve does not currently use case names for SOS'es and the CaseName could be any non-empty value.

Below is a representation of a SOS in an lp file.

sos
SOS: VarName1: VarWeight1, VarName2: VarWeight2, ..., VarNameN: VarWeightN <= 1: SOSpriority;

In the lp format, the VarWeights are optional:

sos
SOS: VarName1, VarName2, ..., VarNameN <= 1: SOSpriority;

In that case, the order of the variables define the VarWeights. So above is equal to:

sos
SOS: VarName1: 1, VarName2: 2, ..., VarNameN: N <= 1: SOSpriority;

Also the SOSpriority is optional. In that case the order in which the SOS constraints are specified give them a priority.

The SOSpriority value determines the order in which multiple SOS'es are analysed in lp_solve.

VarWeight determines the adjacency of the variables. This is an importand piece of information. Remember that the SOS definition defines that the non-zero variables must be adjacent. The VarWeight values define this adjencency.

SOS1 Example:

ROWS
 L  c1
 L  c2
 N  COST
COLUMNS
    x1        c1                 -1.   c2                  1.
    x1        COST               -1.
    x2        c1                 -1.   COST               -1.
    x3        c1                  1.   c2                  1.
    x3        COST               -3.
    x4        c1                  1.   c2                 -3.
    x4        COST               -2.
    x5        COST               -2.
RHS
    RHS       c1                 30.   c2                 30.
BOUNDS
 UP COLBND    x1                 40.
 UP COLBND    x2                  1.
 UP COLBND    x5                  1.
SOS
 S1 SOS       SOS                 1.
    SOS       x1                  1.
    SOS       x2                  2.
    SOS       x3                  3.
    SOS       x4                  4.
    SOS       x5                  5.
ENDATA


In lp format:

min: -x1 -x2 -3 x3 -2 x4 -2 x5;
c1: -x1 -x2 +x3 +x4 <= 30;
c2: +x1 +x3 -3 x4 <= 30;
x1 <= 40;
x2 <= 1;
x5 <= 1;

sos
SOS: x1,x2,x3,x4,x5 <= 1;

The SOS definition says that either x1 or x2 or x3 or x4 or x5 may be taken. It also says that x1 is adjacent to x2 which is adjacent to x3 which is adjacent to x4 which is adjacent to x5.

The solution is:
Value of objective function: -90

Actual values of the variables:
x1                   0
x2                   0
x3                   30
x4                   0
x5                   0

SOS2 Example:

ROWS
 L  c1
 L  c2
 N  COST
COLUMNS
    x1        c1                 -1.   c2                  1.
    x1        COST               -1.
    x2        c1                 -1.   COST               -1.
    x3        c1                  1.   c2                  1.
    x3        COST               -3.
    x4        c1                  1.   c2                 -3.
    x4        COST               -2.
    x5        COST               -2.
RHS
    RHS       c1                 30.   c2                 30.
BOUNDS
 UP COLBND    x1                 40.
 UP COLBND    x2                  1.
 UP COLBND    x5                  1.
SOS
 S2 SOS       SOS                 1.
    SOS       x1                  1.
    SOS       x2                  2.
    SOS       x3                  3.
    SOS       x4                  4.
    SOS       x5                  5.
ENDATA


In lp format:

min: -x1 -x2 -3 x3 -2 x4 -2 x5;
c1: -x1 -x2 +x3 +x4 <= 30;
c2: +x1 +x3 -3 x4 <= 30;
x1 <= 40;
x2 <= 1;
x5 <= 1;

sos
SOS: x1,x2,x3,x4,x5 <= 2;

The SOS definition says that two consecutive variables from x1, x2, x3, x4, x5 may be taken. It also says that x1 is adjacent to x2 which is adjacent to x3 which is adjacent to x4 which is adjacent to x5.

The solution is:
Value of objective function: -91

Actual values of the variables:
x1                   0
x2                   1
x3                   30
x4                   0
x5                   0

SOS3 Example:

ROWS
 L  c1
 L  c2
 N  COST
COLUMNS
    x1        c1                 -1.   c2                  1.
    x1        COST               -1.
    x2        c1                 -1.   COST               -1.
    x3        c1                  1.   c2                  1.
    x3        COST               -3.
    x4        c1                  1.   c2                 -3.
    x4        COST               -2.
    x5        COST               -2.
RHS
    RHS       c1                 30.   c2                 30.
BOUNDS
 UP COLBND    x1                 40.
 UP COLBND    x2                  1.
 UP COLBND    x5                  1.
SOS
 S3 SOS       SOS                 1.
    SOS       x1                  1.
    SOS       x2                  2.
    SOS       x3                  3.
    SOS       x4                  4.
    SOS       x5                  5.
ENDATA


In lp format:

min: -x1 -x2 -3 x3 -2 x4 -2 x5;
c1: -x1 -x2 +x3 +x4 <= 30;
c2: +x1 +x3 -3 x4 <= 30;
x1 <= 40;
x2 <= 1;
x5 <= 1;

sos
SOS: x1,x2,x3,x4,x5 <= 3;

The SOS definition says that three consecutive variables from x1, x2, x3, x4, x5 may be taken. It also says that x1 is adjacent to x2 which is adjacent to x3 which is adjacent to x4 which is adjacent to x5.

The solution is:
Value of objective function: -93.75

Actual values of the variables:
x1                   0
x2                   1
x3                   30.75
x4                   0.25
x5                   0

SOS4 Example:

ROWS
 L  c1
 L  c2
 N  COST
COLUMNS
    x1        c1                 -1.   c2                  1.
    x1        COST               -1.
    x2        c1                 -1.   COST               -1.
    x3        c1                  1.   c2                  1.
    x3        COST               -3.
    x4        c1                  1.   c2                 -3.
    x4        COST               -2.
    x5        COST               -2.
RHS
    RHS       c1                 30.   c2                 30.
BOUNDS
 UP COLBND    x1                 40.
 UP COLBND    x2                  1.
 UP COLBND    x5                  1.
SOS
 S4 SOS       SOS                 1.
    SOS       x1                  1.
    SOS       x2                  2.
    SOS       x3                  3.
    SOS       x4                  4.
    SOS       x5                  5.
ENDATA


In lp format:

min: -x1 -x2 -3 x3 -2 x4 -2 x5;
c1: -x1 -x2 +x3 +x4 <= 30;
c2: +x1 +x3 -3 x4 <= 30;
x1 <= 40;
x2 <= 1;
x5 <= 1;

sos
SOS: x1,x2,x3,x4,x5 <= 4;

The SOS definition says that four consecutive variables from x1, x2, x3, x4, x5 may be taken. It also says that x1 is adjacent to x2 which is adjacent to x3 which is adjacent to x4 which is adjacent to x5.

The solution is:
Value of objective function: -233.75

Actual values of the variables:
x1                   40
x2                   1
x3                   50.75
x4                   20.25
x5                   0

SOS5 Example:

ROWS
 L  c1
 L  c2
 N  COST
COLUMNS
    x1        c1                 -1.   c2                  1.
    x1        COST               -1.
    x2        c1                 -1.   COST               -1.
    x3        c1                  1.   c2                  1.
    x3        COST               -3.
    x4        c1                  1.   c2                 -3.
    x4        COST               -2.
    x5        COST               -2.
RHS
    RHS       c1                 30.   c2                 30.
BOUNDS
 UP COLBND    x1                 40.
 UP COLBND    x2                  1.
 UP COLBND    x5                  1.
SOS
 S5 SOS       SOS                 1.
    SOS       x1                  1.
    SOS       x2                  2.
    SOS       x3                  3.
    SOS       x4                  4.
    SOS       x5                  5.
ENDATA


In lp format:

min: -x1 -x2 -3 x3 -2 x4 -2 x5;
c1: -x1 -x2 +x3 +x4 <= 30;
c2: +x1 +x3 -3 x4 <= 30;
x1 <= 40;
x2 <= 1;
x5 <= 1;

sos
SOS: x1,x2,x3,x4,x5 <= 5;

The SOS definition says that five consecutive variables from x1, x2, x3, x4, x5 may be taken. It also says that x1 is adjacent to x2 which is adjacent to x3 which is adjacent to x4 which is adjacent to x5.

The solution is:
Value of objective function: -235.75

Actual values of the variables:
x1                   40
x2                   1
x3                   50.75
x4                   20.25
x5                   1
./SpecialOrderedSetsOfTypeOne_files/000777 000000 000000 00000000000 13751300671 016067 5ustar00000000 000000 ./SpecialOrderedSetsOfTypeTwo_files/000777 000000 000000 00000000000 13751300672 016120 5ustar00000000 000000 ./Sysquake.htm000666 000000 000000 00000354257 13772705352 011737 0ustar00000000 000000 Using lpsolve from Sysquake

Using lpsolve from Sysquake

Sysquake?

Sysquake is an interactive design CAD tool for getting insight into complicated scientific problems and designing advanced technical devices.

To design technical devices, or to understand the physical and mathematical laws which describe their behavior, engineers and scientists frequently use computers to calculate and represent graphically different quantities, such as the sample sequence and the frequency response of a digital audio filter, or the trajectory and the mass of a rocket flying to Mars. Usually, these quantities are related to each other; they are different views of the same reality. Understanding these relationships is the key to a good design. In some cases, especially for simple systems, an intuitive understanding can be acquired. For more complicated systems, it is often difficult or impossible to "guess", for instance, whether increasing the thickness of a robot arm will increase or decrease the frequency of the oscillations.

Traditionally, the design of a complicated system is performed in several iterations. Specifications can seldom be used directly to calculate the value of the parameters of the system, because there is no explicit formula to link them. Hence each iteration is made of two phases. The first one, often called synthesis, consists in calculating the unknown parameters of the system based on a set of design variables. The design variables are more or less loosely related to the specifications. During the second phase, called analysis, the performance of the system is evaluated and compared to the specifications. If it does not match them, the design variables are modified and a new iteration is carried out.

When the relationship between the criteria used for evaluating the performance and the design parameters is not very well known, modifications of the design parameters might lead as well to poorer performance as to better one. Manual trial and error may work but is cumbersome. This is where interactive design may help. Instead of splitting each iteration between synthesis and analysis, both phases are merged into a single one where the effect of modifying a parameter results immediately in the update of graphics. The whole design procedure becomes really dynamic; the engineer perceives the gradient of the change of performance criteria with respect to what he manipulates, and the compromises which can be obtained are easily identified.

Sysquake's purpose is to support this kind of design in fields such as automatic control and signal processing. Several graphics are displayed simultaneously, and some of them contain elements which can be manipulated with the mouse. During the manipulation, all the graphics are updated to reflect the change. What the graphics show and how their update is performed are not fixed, but depend on programs written in an easy-to-learn language specialized for numerical computation. Several programs are included with Sysquake for common tasks, such as the design of PID controllers; but you are free to modify them to better suit your needs and to write new ones for other design methods or new applications.

Another area where Sysquake shines is teaching. Replacing the static figures you find in books or the animations you see on the Web with interactive graphics, where the student can manipulate himself the curves to acquire an intuitive understanding of the theory they represent, accelerates and improves the learning process tremendously.

We will not discuss the specifics of Sysquake here but instead refer the reader to the Sysquake website and documentation.

Sysquake and lpsolve

lpsolve is callable from Sysquake via an external interface or external code. As such, it looks like lpsolve is fully integrated with Sysquake. Matrices can directly be transferred between Sysquake and lpsolve in both directions. The complete interface is written in C so it has maximum performance. The whole lpsolve API is implemented with some extra's specific for Sysquake (especially for matrix support). So you have full control to the complete lpsolve functionality via the sqlpsolve Sysquake driver. If you find that this involves too much work to solve an lp model then you can also work via a higher-level library that can make things a lot easier. See further in this article.

Sysquake is ideally suited to handle linear programming problems. These are problems in which you have a quantity, depending linearly on several variables, that you want to maximize or minimize subject to several constraints that are expressed as linear inequalities in the same variables.If the number of variables and the number of constraints are small, then there are numerous mathematical techniques for solving a linear programming problem. Indeed these techniques are often taught in high school or university level courses in finite mathematics.But sometimes these numbers are high, or even if low, the constants in the linear inequalities or the object expression for the quantity to be optimized may be numerically complicated in which case a software package like Sysquake is required to effect a solution.

Although there is a free version of Sysquake (Sysquake LE), it does not support to call external library code as needed by lpsolve. As such, the lpsolve link to Sysquake only works with the commercial version.

Installation

To make this possible, a driver program is needed: sqlpsolve (sqlpsolvext.dll under Windows, sqlpsolvext.so under Unix/Linux). This driver must be put in a directory known to Sysquake (LMEExt under Windows, sys under Unix/Linux) and Sysquake can call the sqlpsolve solver.

This driver calls lpsolve via the lpsolve shared library (lpsolve55.dll under Windows and liblpsolve55.so under Unix/Linux) (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). This has the advantage that the sqlpsolve driver doesn't have to be recompiled when an update of lpsolve is provided. The shared library must be somewhere in the Windows path.

So note the difference between the Sysquake lpsolve driver that is called sqlpsolve, its physical name on disk (sqlpsolvext.*) and the lpsolve library that implements the API that is named lpsolve55.* on disk.

There is also the sqlpsolve.lml higher level library file and some example library files (.lml) as a quick start.

To test if everything is installed correctly, enter sqlpsolve(); in the Sysquake command window. If it gives the following, then everything is ok:

sqlpsolve Sysquake Interface version 5.5.0.7
using lpsolve version 5.5.2.11

Usage: ret = sqlpsolve('functionname', arg1, arg2, ...)

However, if you get the following:

Undefined function 'sqlpsolve'

Then Sysquake cannot find either sqlpsolve.dll/sqlpsolve.so or lpsolve55.dll/liblpsolve55.so.
On Unix/Linux, if liblpsolve55.so cannot be found, then an error message is also displayed when Sysquake is started when all external libraries are loaded:

liblpsolve55.so: cannot open shared object file: No such file or directory

Unfortunately, under Windows no message at all is shown and you can't know if the problem is that sqlpsolveext.dll cannot be found or lpsolve55.dll.

Note that it is necessary to restart Sysquake after having put the files in the specified directory. Sysquake loads the libraries only at startup. When started, a list of loaded extensions is given. Make sure that between the list, there is also:

lpsolve extension: sqlpsolve

You can also use the following Sysquake command:

info b

A list of loaded extension functions is given. LME/sqlpsolve must be in the list to be ok.

All this is developed and tested with Sysquake version 4.1 Pro.

Solve an lp model from Sysquake via sqlpsolve

In the following text, > before the Sysquake commands is the Sysquake prompt. Only the text after > must be entered.

To call an lpsolve function, the following syntax must be used:

> [ret1, ret2, ...] = sqlpsolve('functionname', arg1, arg2, ...)

The return values are optional and depend on the function called. functionname must always be enclosed between single quotes to make it alphanumerical and it is case sensitive. The number and type of arguments depend on the function called. Some functions even have a variable number of arguments and a different behaviour occurs depending on the type of the argument. functionname can be (almost) any of the lpsolve API routines (see lp_solve API reference) plus some extra Sysquake specific functions. Most of the lpsolve API routines use or return an lprec structure. To make things more robust in Sysquake, this structure is replaced by a handle or the model name. The lprec structures are maintained internally by the lpsolve driver. The handle is an incrementing number starting from 0. Starting from driver version 5.5.0.2, it is also possible to use the model name instead of the handle. This can of course only be done if a name is given to the model. This is done via lpsolve routine set_lp_name or by specifying the model name in routine read_lp. See Using model name instead of handle.

Almost all callable functions can be found in the lp_solve API reference. Some are exactly as described in the reference guide, others have a slightly different syntax to make maximum use of the Sysquake functionality. For example make_lp is used identical as described. But get_variables is slightly different. In the API reference, this function has two arguments. The first the lp handle and the second the resulting variables and this array must already be dimensioned. When lpsolve is used from Sysquake, nothing must be dimensioned in advance. The sqlpsolve driver takes care of dimensioning all return variables and they are always returned as return value of the call to sqlpsolve. Never as argument to the routine. This can be a single value as for get_objective (although Sysquake stores this in a 1x1 matrix) or a matrix or vector as in get_variables. In this case, get_variables returns a 4x1 matrix (vector) with the result of the 4 variables of the lp model.

Constants

Some API calls needs constant arguments. For example add_constraint has the constants LE, GE, EQ to define if the added constraint is a less than, greater than, equal to the RHS. Although it is legal and possible to use the constant numbers itself, it is easier, clearer and much readable to use labels. In this documentation these are used everywere. They are not defined in the external library sqlpsolveext.dll/so. They are however defined in the library sqlpsolve.lml. To use these, the library must first be loaded in Sysquaqe via a use statement:

use sqlpsolve

See also libraries

Here is a list of all constants defined in sqlpsolve.lml (end of file):

public

define LPSOLVE_ANTIDEGEN_BOUNDFLIP = 512;
define LPSOLVE_ANTIDEGEN_COLUMNCHECK = 2;
define LPSOLVE_ANTIDEGEN_DURINGBB = 128;
define LPSOLVE_ANTIDEGEN_DYNAMIC = 64;
define LPSOLVE_ANTIDEGEN_FIXEDVARS = 1;
define LPSOLVE_ANTIDEGEN_INFEASIBLE = 32;
define LPSOLVE_ANTIDEGEN_LOSTFEAS = 16;
define LPSOLVE_ANTIDEGEN_NONE = 0;
define LPSOLVE_ANTIDEGEN_NUMFAILURE = 8;
define LPSOLVE_ANTIDEGEN_RHSPERTURB = 256;
define LPSOLVE_ANTIDEGEN_STALLING = 4;
define LPSOLVE_BRANCH_AUTOMATIC = 2;
define LPSOLVE_BRANCH_DEFAULT = 3;
define LPSOLVE_BRANCH_CEILING = 0;
define LPSOLVE_BRANCH_FLOOR = 1;
define LPSOLVE_CRASH_LEASTDEGENERATE = 3;
define LPSOLVE_CRASH_MOSTFEASIBLE = 2;
define LPSOLVE_CRASH_NONE = 0;
define LPSOLVE_CRITICAL = 1;
define LPSOLVE_DEGENERATE = 4;
define LPSOLVE_DETAILED = 5;
define LPSOLVE_EQ = 3;
define LPSOLVE_FEASFOUND = 12;
define LPSOLVE_FR = 0;
define LPSOLVE_FULL = 6;
define LPSOLVE_GE = 2;
define LPSOLVE_IMPORTANT = 3;
define LPSOLVE_IMPROVE_BBSIMPLEX = 8;
define LPSOLVE_IMPROVE_DUALFEAS = 2;
define LPSOLVE_IMPROVE_NONE = 0;
define LPSOLVE_IMPROVE_SOLUTION = 1;
define LPSOLVE_IMPROVE_THETAGAP = 4;
define LPSOLVE_INFEASIBLE = 2;
define LPSOLVE_Infinite = 1e+030;
define LPSOLVE_LE = 1;
define LPSOLVE_MSG_LPFEASIBLE = 8;
define LPSOLVE_MSG_LPOPTIMAL = 16;
define LPSOLVE_MSG_MILPBETTER = 512;
define LPSOLVE_MSG_MILPEQUAL = 256;
define LPSOLVE_MSG_MILPFEASIBLE = 128;
define LPSOLVE_MSG_PRESOLVE = 1;
define LPSOLVE_NEUTRAL = 0;
define LPSOLVE_NODE_AUTOORDER = 8192;
define LPSOLVE_NODE_BRANCHREVERSEMODE = 16;
define LPSOLVE_NODE_BREADTHFIRSTMODE = 4096;
define LPSOLVE_NODE_DEPTHFIRSTMODE = 128;
define LPSOLVE_NODE_DYNAMICMODE = 1024;
define LPSOLVE_NODE_FIRSTSELECT = 0;
define LPSOLVE_NODE_FRACTIONSELECT = 3;
define LPSOLVE_NODE_GAPSELECT = 1;
define LPSOLVE_NODE_GREEDYMODE = 32;
define LPSOLVE_NODE_GUBMODE = 512;
define LPSOLVE_NODE_PSEUDOCOSTMODE = 64;
define LPSOLVE_NODE_PSEUDOCOSTSELECT = 4;
define LPSOLVE_NODE_PSEUDONONINTSELECT = 5;
define LPSOLVE_NODE_PSEUDORATIOSELECT = 6;
define LPSOLVE_NODE_RANDOMIZEMODE = 256;
define LPSOLVE_NODE_RANGESELECT = 2;
define LPSOLVE_NODE_RCOSTFIXING = 16384;
define LPSOLVE_NODE_RESTARTMODE = 2048;
define LPSOLVE_NODE_STRONGINIT = 32768;
define LPSOLVE_NODE_USERSELECT = 7;
define LPSOLVE_NODE_WEIGHTREVERSEMODE = 8;
define LPSOLVE_NOFEASFOUND = 13;
define LPSOLVE_NOMEMORY = -2;
define LPSOLVE_NORMAL = 4;
define LPSOLVE_NUMFAILURE = 5;
define LPSOLVE_OPTIMAL = 0;
define LPSOLVE_PRESOLVED = 9;
define LPSOLVE_PRESOLVE_BOUNDS = 262144;
define LPSOLVE_PRESOLVE_COLDOMINATE = 16384;
define LPSOLVE_PRESOLVE_COLFIXDUAL = 131072;
define LPSOLVE_PRESOLVE_COLS = 2;
define LPSOLVE_PRESOLVE_DUALS = 524288;
define LPSOLVE_PRESOLVE_ELIMEQ2 = 256;
define LPSOLVE_PRESOLVE_IMPLIEDFREE = 512;
define LPSOLVE_PRESOLVE_IMPLIEDSLK = 65536;
define LPSOLVE_PRESOLVE_KNAPSACK = 128;
define LPSOLVE_PRESOLVE_LINDEP = 4;
define LPSOLVE_PRESOLVE_MERGEROWS = 32768;
define LPSOLVE_PRESOLVE_NONE = 0;
define LPSOLVE_PRESOLVE_PROBEFIX = 2048;
define LPSOLVE_PRESOLVE_PROBEREDUCE = 4096;
define LPSOLVE_PRESOLVE_REDUCEGCD = 1024;
define LPSOLVE_PRESOLVE_REDUCEMIP = 64;
define LPSOLVE_PRESOLVE_ROWDOMINATE = 8192;
define LPSOLVE_PRESOLVE_ROWS = 1;
define LPSOLVE_PRESOLVE_SENSDUALS = 1048576;
define LPSOLVE_PRESOLVE_SOS = 32;
define LPSOLVE_PRICER_DANTZIG = 1;
define LPSOLVE_PRICER_DEVEX = 2;
define LPSOLVE_PRICER_FIRSTINDEX = 0;
define LPSOLVE_PRICER_STEEPESTEDGE = 3;
define LPSOLVE_PRICE_ADAPTIVE = 32;
define LPSOLVE_PRICE_AUTOPARTIAL = 256;
define LPSOLVE_PRICE_HARRISTWOPASS = 4096;
define LPSOLVE_PRICE_LOOPALTERNATE = 2048;
define LPSOLVE_PRICE_LOOPLEFT = 1024;
define LPSOLVE_PRICE_MULTIPLE = 8;
define LPSOLVE_PRICE_PARTIAL = 16;
define LPSOLVE_PRICE_PRIMALFALLBACK = 4;
define LPSOLVE_PRICE_RANDOMIZE = 128;
define LPSOLVE_PRICE_TRUENORMINIT = 16384;
define LPSOLVE_PROCBREAK = 11;
define LPSOLVE_PROCFAIL = 10;
define LPSOLVE_SCALE_COLSONLY = 1024;
define LPSOLVE_SCALE_CURTISREID = 7;
define LPSOLVE_SCALE_DYNUPDATE = 256;
define LPSOLVE_SCALE_EQUILIBRATE = 64;
define LPSOLVE_SCALE_EXTREME = 1;
define LPSOLVE_SCALE_GEOMETRIC = 4;
define LPSOLVE_SCALE_INTEGERS = 128;
define LPSOLVE_SCALE_LOGARITHMIC = 16;
define LPSOLVE_SCALE_MEAN = 3;
define LPSOLVE_SCALE_NONE = 0;
define LPSOLVE_SCALE_POWER2 = 32;
define LPSOLVE_SCALE_QUADRATIC = 8;
define LPSOLVE_SCALE_RANGE = 2;
define LPSOLVE_SCALE_ROWSONLY = 512;
define LPSOLVE_SCALE_USERWEIGHT = 31;
define LPSOLVE_SEVERE = 2;
define LPSOLVE_SIMPLEX_DUAL_DUAL = 10;
define LPSOLVE_SIMPLEX_DUAL_PRIMAL = 6;
define LPSOLVE_SIMPLEX_PRIMAL_DUAL = 9;
define LPSOLVE_SIMPLEX_PRIMAL_PRIMAL = 5;
define LPSOLVE_SUBOPTIMAL = 1;
define LPSOLVE_TIMEOUT = 7;
define LPSOLVE_UNBOUNDED = 3;
define LPSOLVE_USERABORT = 6;
Also see Using string constants for an alternative.

An example

(Note that you can execute this example by entering command per command as shown below or by just executing the command from example1.lml as follows:

use example1; example1;

This will execute example1.lml. It will also echo the executes commands. See also libraries)

> use sqlpsolve
> lp=sqlpsolve('make_lp', 0, 4);
> sqlpsolve('set_verbose', lp, 3);
> sqlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
> sqlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], LPSOLVE_GE, 92.3);
> sqlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], LPSOLVE_LE, 14.8);
> sqlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], LPSOLVE_GE, 4);
> sqlpsolve('set_lowbo', lp, 1, 28.6);
> sqlpsolve('set_lowbo', lp, 4, 18);
> sqlpsolve('set_upbo', lp, 4, 48.98);
> sqlpsolve('set_col_name', lp, 1, 'COLONE');
> sqlpsolve('set_col_name', lp, 2, 'COLTWO');
> sqlpsolve('set_col_name', lp, 3, 'COLTHREE');
> sqlpsolve('set_col_name', lp, 4, 'COLFOUR');
> sqlpsolve('set_row_name', lp, 1, 'THISROW');
> sqlpsolve('set_row_name', lp, 2, 'THATROW');
> sqlpsolve('set_row_name', lp, 3, 'LASTROW');
> sqlpsolve('write_lp', lp, 'a.lp');
> sqlpsolve('get_mat', lp, 1, 2)
ans =
   78.2600
> sqlpsolve('solve', lp)
ans =
     0
> sqlpsolve('get_objective', lp)
ans =
   31.7828
> sqlpsolve('get_variables', lp)
ans =
   28.6000
    0.0000
    0.0000
   31.8276
> sqlpsolve('get_constraints', lp)
ans =
   92.3000
    6.8640
  391.2928

Note that there are some commands that return an answer. To see the answer, the command was not terminated with a semicolon (;). If the semicolon is put at the end of a command, the answer is not shown. However it is also possible to write the answer in a variable. For example:

> obj=sqlpsolve('get_objective', lp)
obj =
   31.7828

Or without echoing on screen:

> obj=sqlpsolve('get_objective', lp);

The last command will only write the result in variable obj without showing anything on screen. get_variables and get_constraints return a vector with the result. This can also be put in a variable:

> x=sqlpsolve('get_variables', lp);
> b=sqlpsolve('get_constraints', lp);

It is always possible to show the contents of a variable by just giving it as command:

> x
x =
   28.6000
    0.0000
    0.0000
   31.8276

Don't forget to free the handle and its associated memory when you are done:

> sqlpsolve('delete_lp', lp);

Using model name instead of handle

From driver version 5.5.0.2, it is possible to use the model name instead of the handle. From the moment the model has a name, you can use this name instead of the handle. This is best shown by an example. Above example would look like this:
> use sqlpsolve
> lp=sqlpsolve('make_lp', 0, 4);
> sqlpsolve('set_lp_name', lp, 'mymodel');
> sqlpsolve('set_verbose', 'mymodel', 3);
> sqlpsolve('set_obj_fn', 'mymodel', [1, 3, 6.24, 0.1]);
> sqlpsolve('add_constraint', 'mymodel', [0, 78.26, 0, 2.9], LPSOLVE_GE, 92.3);
> sqlpsolve('add_constraint', 'mymodel', [0.24, 0, 11.31, 0], LPSOLVE_LE, 14.8);
> sqlpsolve('add_constraint', 'mymodel', [12.68, 0, 0.08, 0.9], LPSOLVE_GE, 4);
> sqlpsolve('set_lowbo', 'mymodel', 1, 28.6);
> sqlpsolve('set_lowbo', 'mymodel', 4, 18);
> sqlpsolve('set_upbo', 'mymodel', 4, 48.98);
> sqlpsolve('set_col_name', 'mymodel', 1, 'COLONE');
> sqlpsolve('set_col_name', 'mymodel', 2, 'COLTWO');
> sqlpsolve('set_col_name', 'mymodel', 3, 'COLTHREE');
> sqlpsolve('set_col_name', 'mymodel', 4, 'COLFOUR');
> sqlpsolve('set_row_name', 'mymodel', 1, 'THISROW');
> sqlpsolve('set_row_name', 'mymodel', 2, 'THATROW');
> sqlpsolve('set_row_name', 'mymodel', 3, 'LASTROW');
> sqlpsolve('write_lp', 'mymodel', 'a.lp');
> sqlpsolve('get_mat', 'mymodel', 1, 2)
ans =
   78.2600
> sqlpsolve('solve', 'mymodel')
ans =
     0
> sqlpsolve('get_objective', 'mymodel')
ans =
   31.7828
> sqlpsolve('get_variables', 'mymodel')
ans =
   28.6000
    0.0000
    0.0000
   31.8276
> sqlpsolve('get_constraints', 'mymodel')
ans =
   92.3000
    6.8640
  391.2928

So everywhere a handle is needed, you can also use the model name. You can even mix the two methods. There is also a specific Sysquake routine to get the handle from the model name: get_handle.
For example:

> sqlpsolve('get_handle', 'mymodel')
ans =
     0

Don't forget to free the handle and its associated memory when you are done:

> sqlpsolve('delete_lp', 'mymodel');

In the next part of this documentation, the handle is used. But if you name the model, the name could thus also be used.

Matrices

In Sysquake, all numerical data is stored in matrices; even a scalar variable. Sysquake also supports complex numbers (a + b * i with i=SQRT(-1)). sqlpsolve can only work with real numbers.

Most of the time, variables are used to provide the data:

> sqlpsolve('add_constraint', lp, a1, LPSOLVE_LE, 14.8);

Where a1 is a matrix variable.

Note that if a matrix is provided, the dimension must exactly match the dimension that is expected by sqlpsolve. Matrices with too few or too much elements gives an 'invalid vector.' error.

Most of the time, sqlpsolve needs vectors (rows or columns). In all situations, it doesn't matter if the vectors are row or column vectors. The driver accepts them both. For example:

> sqlpsolve('add_constraint', lp, [0.24; 0; 11.31; 0], LPSOLVE_LE, 14.8);

Which is a column vector, but it is also accepted.

An important final note. Several lp_solve API routines accept a vector where the first element (element 0) is not used. Other lp_solve API calls do use the first element. In the Sysquake interface, there is never an unused element in the matrices. So if the lp_solve API specifies that the first element is not used, then this element is not in the Sysquake matrix.

Sets

All numerical data is stored in matrices. Alphanumerical data, however, is more difficult to store in matrices. Matrices require that each element has the same size (length) and that is difficult and unpractical for alphanumerical data. In a limited number of lpsolve routines, alphanumerical data is required or returned and in some also multiple elements. An example is set_col_name. For this, Sysquake sets are used. To specify a set of alphanumerical elements, the following notation is used: { 'element1', 'element2', ... }. Note the { and } symbols instead of [ and ] that are used with matrices.

Maximum usage of matrices/sets with sqlpsolve

Because Sysquake is all about matrices, all lpsolve API routines that need a column or row number to get/set information for that column/row are extended in the sqlpsolve Sysquake driver to also work with matrices. For example set_int in the API can only set the integer status for one column. If the status for several integer variables must be set, then set_int must be called multiple times. The sqlpsolve Sysquake driver however also allows specifying a vector to set the integer status of all variables at once. The API call is: return = sqlpsolve('set_int', lp, column, must_be_int). The matrix version of this call is: return = sqlpsolve('set_int', lp, [must_be_int]). The API call to return the integer status of a variable is: return = sqlpsolve('is_int', lp, column). The matrix version of this call is: [is_int] = sqlpsolve('is_int', lp)
Also note the get_mat and set_mat routines. In Sysquake these are extended to return/set the complete constraint matrix. See following example.

Above example can thus also be done as follows:
(Note that you can execute this example by entering command per command as shown below or by just executing the command from example2.lml as follows:

use example2; example2;

This will execute example2.lml. It will also echo the executes commands. See also libraries)

> use sqlpsolve
> lp=sqlpsolve('make_lp', 0, 4);
> sqlpsolve('set_verbose', lp, 3);
> sqlpsolve('set_obj_fn', lp, [1, 3, 6.24, 0.1]);
> sqlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], LPSOLVE_GE, 92.3);
> sqlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], LPSOLVE_LE, 14.8);
> sqlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], LPSOLVE_GE, 4);
> sqlpsolve('set_lowbo', lp, [28.6, 0, 0, 18]);
> sqlpsolve('set_upbo', lp, [Inf, Inf, Inf, 48.98]);
> sqlpsolve('set_col_name', lp, {'COLONE', 'COLTWO', 'COLTHREE', 'COLFOUR'});
> sqlpsolve('set_row_name', lp, {'THISROW', 'THATROW', 'LASTROW'});
> sqlpsolve('write_lp', lp, 'a.lp');
> sqlpsolve('get_mat', lp)
ans =
    0.0000   78.2600    0.0000    2.9000
    0.2400    0.0000   11.3100    0.0000
   12.6800    0.0000    0.0800    0.9000
> sqlpsolve('solve', lp)
ans =
     0
> sqlpsolve('get_objective', lp)
ans =
   31.7828
> sqlpsolve('get_variables', lp)
ans =
   28.6000
    0.0000
    0.0000
   31.8276
> sqlpsolve('get_constraints', lp)
ans =
   92.3000
    6.8640
  391.2928

Note the usage of Inf in set_upbo. This stands for 'infinity'. Meaning an infinite upper bound. It is also possible to use -Inf to express minus infinity. This can for example be used to create a free variable.

To show the full power of the matrices, let's now do some matrix calculations to check the solution. It works further on above example:

> A=sqlpsolve('get_mat', lp);
> X=sqlpsolve('get_variables', lp);
> B = A * X
B =
   92.3000
    6.8640
  391.2928

So what we have done here is calculate the values of the constraints (RHS) by multiplying the constraint matrix with the solution vector. Now take a look at the values of the constraints that lpsolve has found:

> sqlpsolve('get_constraints', lp)
ans =
   92.3000
    6.8640
  391.2928

Exactly the same as the calculated B vector, as expected.

Also the value of the objective can be calculated in a same way:

> C=sqlpsolve('get_obj_fn', lp);
> X=sqlpsolve('get_variables', lp);
> obj = C * X
obj =
   31.7828

So what we have done here is calculate the value of the objective by multiplying the objective vector with the solution vector. Now take a look at the value of the objective that lpsolve has found:

> sqlpsolve('get_objective', lp)
ans =
   31.7828

Again exactly the same as the calculated obj value, as expected.

Using string constants

From driver version 5.5.2.11 on, it is possible to use string constants everywhere an lp_solve constant is needed or returned. This is best shown by an example. In the above code we had:
> use sqlpsolve
> lp=sqlpsolve('make_lp', 0, 4);
> sqlpsolve('set_verbose', lp, 3);
> sqlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], LPSOLVE_GE, 92.3);
> sqlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], LPSOLVE_LE, 14.8);
> sqlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], LPSOLVE_GE, 4);

Note the 3rd parameter on set_verbose and the 4th on add_constraint. These are lp_solve constants. One can define all the possible constants in Sysquake as is done in the sqlpsolve library and then use them in the calls, but that has several disadvantages. First there stays the possibility to provide a constant that is not intended for that particular call. Another issue is that calls that return a constant are still returning it numerical.

Both issues can now be handled by string constants. The above code can be done as following with string constants:

> lp=sqlpsolve('make_lp', 0, 4);
> sqlpsolve('set_verbose', lp, 'IMPORTANT');
> sqlpsolve('add_constraint', lp, [0, 78.26, 0, 2.9], 'GE', 92.3);
> sqlpsolve('add_constraint', lp, [0.24, 0, 11.31, 0], 'LE', 14.8);
> sqlpsolve('add_constraint', lp, [12.68, 0, 0.08, 0.9], 'GE', 4);

This is not only more readable, there is much lesser chance that mistakes are being made. The calling routine knows which constants are possible and only allows these. So unknown constants or constants that are intended for other calls are not accepted. For example:

> sqlpsolve('set_verbose', lp, 'blabla');

BLABLA: Unknown.

> sqlpsolve('set_verbose', lp, 'GE');

GE: Not allowed here.

Note the difference between the two error messages. The first says that the constant is not known, the second that the constant cannot be used at that place.

Constants are case insensitive. Internally they are always translated to upper case. Also when returned they will always be in upper case.

The constant names are the ones as specified in the documentation of each API routine. There are only 3 exceptions, extensions actually. 'LE', 'GE' and 'EQ' in add_constraint and is_constr_type can also be '<', '<=', '>', '>=', '='. When returned however, 'GE', 'LE', 'EQ' will be used.

Also in the matrix version of calls, string constants are possible. For example:

> sqlpsolve('set_constr_type', lp, {'LE', 'EQ', 'GE'});

Some constants can be a combination of multiple constants. For example set_scaling:

> sqlpsolve('set_scaling', lp, 3+128);

With the string version of constants this can be done as following:

> sqlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_INTEGERS');

| is the OR operator used to combine multiple constants. There may optinally be spaces before and after the |.

Not all OR combinations are legal. For example in set_scaling, a choice must be made between SCALE_EXTREME, SCALE_RANGE, SCALE_MEAN, SCALE_GEOMETRIC or SCALE_CURTISREID. They may not be combined with each other. This is also tested:

> sqlpsolve('set_scaling', lp, 'SCALE_MEAN|SCALE_RANGE');

SCALE_RANGE cannot be combined with SCALE_MEAN

Everywhere constants must be provided, numeric or string values may be provided. The routine automatically interpretes them.

Returning constants is a different story. The user must let lp_solve know how to return it. Numerical or as string. The default is numerical:

> sqlpsolve('get_scaling', lp)

ans =

  131

To let lp_solve return a constant as string, a call to a new function must be made: return_constants

> sqlpsolve('return_constants', 1);

From now on, all returned constants are returned as string:

> sqlpsolve('get_scaling', lp)

ans =

SCALE_MEAN|SCALE_INTEGERS

Also when an array of constants is returned, they are returned as string when return_constants is set:

> sqlpsolve('get_constr_type', lp)

ans =

 {'LE','EQ','GE'}

This for all routines until return_constants is again called with 0:

> sqlpsolve('return_constants', 0);

The (new) current setting of return_constants is always returned by the call. Even when set:

> sqlpsolve('return_constants', 1)

ans =

    1

To get the value without setting it, don't provide the second argument:

> sqlpsolve('return_constants')

ans =

    1

In the next part of this documentation, return_constants is the default, 0, so all constants are returned numerical and provided constants are also numerical. This to keep the documentation as compatible as possible with older versions. But don't let you hold that back to use string constants in your code.

libraries

Sysquake can execute a sequence of statements stored in diskfiles. Such files are called "libraries". They must have the file type of ".lml" as the last part of their filename (extension). These files are usually created using your local editor.
Note that for Sysquake to be able to find these libraries that they must be put in a special directory named Lib under the Sysquake directory or the file path where the libraries are put must be identified to Sysquake. If you are working with the GUI version of Sysquake, this can be done via the menu option Edit, Preferences and then 'Set SQ File Path' or 'Path'. In that input multiple directories can be specified, line per line. This path can also be seen and changed via the Sysquake path command.

To use a library, it must first be loaded via the following command in Sysquake:

use libraryname

With libraryname the name of the library, without its extension. From that moment on, functions defined in it can be called directly from Sysquake.
All lpsolve examples use as functionname the same name as the libraryname.

The sqlpsolve Sysquake distribution contains some example library files to demonstrate this.

To see the contents of such a file also edit these files with your favourite text editor (or notepad).

example1.lml

Contains the commands as shown in the first example of this article.

example2.lml

Contains the commands as shown in the second example of this article.

example3.lml

Contains the commands of a practical example. See further in this article.

example4.lml

Contains the commands of a practical example. See further in this article.

example5.lml

Contains the commands of a practical example. See further in this article.

example6.lml

Contains the commands of a practical example. See further in this article.

sqlpsolve.lml

This library contains some higher-level functions to simplify things. To use it, first give following Sysquake command:

use sqlpsolve;

lp_solve

The first function herein is called lp_solve.
It accepts as arguments some matrices and options to create and solve an lp model.
type help lp_solve or just lp_solve to see its usage:

> use sqlpsolve
> help lp_solve
 LP_SOLVE  Solves mixed integer linear programming problems.

   SYNOPSIS: [obj,x,duals] = lp_solve(f,a,b,e,vlb,vub,xint,scalemode,keep)

      solves the MILP problem

              max v = f'*x
                a*x <> b
                  vlb <= x <= vub
                  x(int) are integer

   ARGUMENTS: The first four arguments are required:

            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) = -1  ==> Less Than
                      e(i) =  0  ==> Equals
                      e(i) =  1  ==> Greater Than
          vlb: n vector of lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: scale flag. Off when 0 or omitted.
         keep: Flag for keeping the lp problem after it's been solved.
               If omitted, the lp will be deleted when solved.

   OUTPUT: A nonempty output is returned if a solution is found:

          obj: Optimal value of the objective function.
            x: Optimal value of the decision variables.
        duals: solution of the dual problem.

Example of usage. To create and solve following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

> use sqlpsolve
> [obj, x]=lp_solve([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])
obj =
     3
x =
     1
     2

lp_maker

A second function in sqlpsolve.lml is lp_maker. It is analog to lp_solve and also uses the API to create the higher-level function. This function accepts as arguments some matrices and options to create an lp model. Note that this function only creates a model and returns a handle.
type help lp_maker or just lp_maker to see its usage:

> use sqlpsolve
> help lp_maker
 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Example of usage. To create following lp-model:

max: -x1 + 2 x2;
C1: 2x1 + x2 < 5;
-4 x1 + 4 x2 <5;

int x2,x1;

The following command can be used:

> use sqlpsolve
> lp=lp_maker([-1, 2], [2, 1; -4, 4], [5, 5], [-1, -1], [], [], [1, 2])
lp =
     0

To solve the model and get the solution:

> sqlpsolve('solve', lp)
ans =
     0
> sqlpsolve('get_objective', lp)
ans =
     3
> sqlpsolve('get_variables', lp)
ans =
     1
     2

Don't forget to free the handle and its associated memory when you are done:

> sqlpsolve('delete_lp', lp);

lpdemo.lml

Contains several examples to build and solve lp models.

ex.lml

Contains several examples to build and solve lp models. Also solves the lp_examples from the lp_solve distribution.

A practical example

We shall illustrate the method of linear programming by means of a simple example, giving a combination graphical/numerical solution, and then solve both a slightly as well as a substantially more complicated problem.

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.

Source

Now let's put in the other two constraint inequalities.

Source

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.

Source

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 lp_solve, starts from a theorem that the optimal solution is such a corner point.
In fact we can compute the result:

> x = [1 1; 110 30] \ [75; 4000]
x =
   21.8750
   53.1250

The acreage that results in the maximum profit is 21.875 for wheat and 53.125 for barley. In that case the profit is:

> format bank
> P = [143 60] * x
P =
 6315.63

That is, $6315.63.

Note that these command are in example3.lml

Now, lp_solve comes into the picture to solve this linear programming problem more generally. After that we will use it to solve two more complicated problems involving more variables and constraints.

For this example, we use the higher-level script lp_maker to build the model and then some lp_solve API calls to retrieve the solution. Here is again the usage of lp_maker:

> use sqlpsolve
> help lp_maker

 LP_MAKER  Makes mixed integer linear programming problems.

   SYNOPSIS: lp_handle = lp_maker(f,a,b,e,vlb,vub,xint,scalemode,setminim)
      make the MILP problem
        max v = f'*x
          a*x <> b
            vlb <= x <= vub
            x(int) are integer

   ARGUMENTS: The first four arguments are required:
            f: n vector of coefficients for a linear objective function.
            a: m by n matrix representing linear constraints.
            b: m vector of right sides for the inequality constraints.
            e: m vector that determines the sense of the inequalities:
                      e(i) < 0  ==> Less Than
                      e(i) = 0  ==> Equals
                      e(i) > 0  ==> Greater Than
          vlb: n vector of non-negative lower bounds. If empty or omitted,
               then the lower bounds are set to zero.
          vub: n vector of upper bounds. May be omitted or empty.
         xint: vector of integer variables. May be omitted or empty.
    scalemode: Autoscale flag. Off when 0 or omitted.
     setminim: Set maximum lp when this flag equals 0 or omitted.

   OUTPUT: lp_handle is an integer handle to the lp created.

Now let's formulate this model with lp_solve:

> use sqlpsolve
> f = [143 60];
> A = [120 210; 110 30; 1 1];
> b = [15000; 4000; 75];
> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
> solvestat = sqlpsolve('solve', lp)
solvestat =
    0.00
> format bank
> obj = sqlpsolve('get_objective', lp)
obj =
 6315.63
> format short
> x = sqlpsolve('get_variables', lp)
x =
   21.8750
   53.1250
> sqlpsolve('delete_lp', lp);

Note that these command are in example4.lml

With the higher-level script lp_maker, we provide all data to lp_solve. lp_solve returns a handle (lp) to the created model. Then the API call 'solve' is used to calculate the optimal solution of the model. The value of the objective function is retrieved via the API call 'get_objective' and the values of the variables are retrieved via the API call 'get_variables'. At last, the model is removed from memory via a call to 'delete_lp'. Don't forget this to free all memory allocated by lp_solve.

The solution is the same answer we obtained before. Note that the non-negativity constraints are accounted implicitly because variables are by default non-negative in lp_solve.

Well, we could have done this problem by hand (as shown in the introduction) because it is very small and it can be graphically presented.
Now suppose that the farmer is dealing with a third crop, say corn, and that the corresponding data is:

cost per acre$150.75
yield per acre125 bushels
profit per bushel$1.56

With three variables it is already a lot more difficult to show this model graphically. Adding more variables makes it even impossible because we can't imagine anymore how to represent this. We only have a practical understanding of 3 dimentions, but beyound that it is all very theorethical.

If we denote the number of acres allotted to corn by z, then the objective function becomes:

P = (110)(1.30)x + (30)(2.00)y+ (125)(1.56) = 143x + 60y + 195z

And the constraint inequalities are:

120x + 210y + 150.75z <= 15000
110x + 30y + 125z <= 4000
x + y + z <= 75
x >= 0,y >= 0, z >= 0

The problem is solved with lp_solve as follows:

> use sqlpsolve
> f = [143 60 195];
> A = [120 210 150.75; 110 30 125; 1 1 1];
> b = [15000; 4000; 75];
> lp = lp_maker(f, A, b, [-1; -1; -1], [], [], [], 1, 0);
> solvestat = sqlpsolve('solve', lp)
solvestat =
     0
> format bank
> obj = sqlpsolve('get_objective', lp)
obj =
 6986.84
> format short
> x = sqlpsolve('get_variables', lp)
x =
    0.0000
   56.5789
   18.4211
> sqlpsolve('delete_lp', lp);

Note that these command are in example5.lml

So the farmer should ditch the wheat and plant 56.5789 acres of barley and 18.4211 acres of corn.

There is no practical limit on the number of variables and constraints that Sysquake can handle. Certainly none that the relatively unsophisticated user will encounter.Indeed, in many true applications of the technique of linear programming, one needs to deal with many variables and constraints.The solution of such a problem by hand is not feasible, and software like Sysquake is crucial to success.For example, in the farming problem with which we have been working, one could have more crops than two or three. Think agribusiness instead of family farmer.And one could have constraints that arise from other things beside expenses, storage and acreage limitations. For example:

  • Availability of seed.This might lead to constraint inequalities like xj < k.
  • Personal preferences. Thus the farmer's spouse might have a preference for one variety over another and insist on a corresponding planting, or something similar with a collection of crops; thus constraint inequalities like xi < xj or x1 + x2 > x3.
  • Government subsidies. It may take a moment's reflection on the reader's part, but this could lead to inequalities like xj > k.

Below is a sequence of commands that solves exactly such a problem. You should be able to recognize the objective expression and the constraints from the data that is entered. But as an aid, you might answer the following questions:

  • How many crops are under consideration?
  • What are the corresponding expenses? How much is available for expenses?
  • What are the yields in each case? What is the storage capacity?
  • How many acres are available?
  • What crops are constrained by seed limitations? To what extent?
  • What about preferences?
  • What are the minimum acreages for each crop?
> use sqlpsolve
> f = [110*1.3 30*2.0 125*1.56 75*1.8 95*.95 100*2.25 50*1.35];
> A = [120 210 150.75 115 186 140 85;
        110 30 125 75 95 100 50;
        1 1 1 1 1 1 1;
        1 -1 0 0 0 0 0;
        0 0 1 0 -2 0 0;
        0 0 0 -1 0 -1 1];

> b = [55000;40000;400;0;0;0];
> lp = lp_maker(f, A, b, [-1; -1; -1; -1; -1; -1], [10 10 10 10 20 20 20], [100 Inf 50 Inf Inf 250 Inf], [], 1, 0);
> solvestat = sqlpsolve('solve', lp)
solvestat =
     0
> format bank
> obj = sqlpsolve('get_objective', lp)
obj =
 75398.04
> format short
> x = sqlpsolve('get_variables', lp)
x =
   10.0000
   10.0000
   40.0000
   45.6522
   20.0000
  250.0000
   20.0000
> sqlpsolve('delete_lp', lp);

Note that these command are in example6.lml

Note that we have used in this formulation the vlb and vub arguments of lp_maker. This to set lower and upper bounds on variables. This could have been done via extra constraints, but it is more performant to set bounds on variables. Also note that Inf is used for variables that have no upper limit. This stands for Infinity.

Note that despite the complexity of the problem, lp_solve solves it almost instantaneously. It seems the farmer should bet the farm on crop number 6.We strongly suggest you alter the expense and/or the storage limit in the problem and see what effect that has on the answer.

Another, more theoretical, example

Suppose we want to solve the following linear program using Sysquake:

max 4x1 + 2x2 + x3
s. t. 2x1 + x2 <= 1
x1 + 2x3 <= 2
x1 + x2 + x3 = 1
x1 >= 0
x1 <= 1
x2 >= 0
x2 <= 1
x3 >= 0
x3 <= 2

Convert the LP into Sysquake format we get:

f = [4 2 1]
A = [2 1 0; 1 0 2; 1 1 1]
b = [1; 2; 1]

Note that constraints on single variables are not put in the constraint matrix. lp_solve can set bounds on individual variables and this is more performant than creating additional constraints. These bounds are:

l = [ 0 0 0]
u = [ 1 1 2]

Now lets enter this in Sysquake:

> use sqlpsolve
> f = [4 2 1];
> A = [2 1 0; 1 0 2; 1 1 1];
> b = [1; 2; 1];
> l = [ 0 0 0];
> u = [ 1 1 2];

Now solve the linear program using Sysquake: Type the commands

> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
> solvestat = sqlpsolve('solve', lp)
solvestat =
     0
> obj = sqlpsolve('get_objective', lp)
obj =
    2.5000
> x = sqlpsolve('get_variables', lp)
x =
    0.5000
    0.0000
    0.5000
> sqlpsolve('delete_lp', lp);

What to do when some of the variables are missing ?
For example, suppose there are no lower bounds on the variables. In this case define l to be the empty set using the Sysquake command:

> l = [];

This has the same effect as before, because lp_solve has as default lower bound for variables 0.

But what if you want that variables may also become negative?
Then you can use -Inf as lower bounds:

> l = [-Inf -Inf -Inf];

Solve this and you get a different result:

> use sqlpsolve
> lp = lp_maker(f, A, b, [-1; -1; -1], l, u, [], 1, 0);
> solvestat = sqlpsolve('solve', lp)
solvestat =
     0
> obj = sqlpsolve('get_objective', lp)
obj =
    2.6667
> x = sqlpsolve('get_variables', lp)
x =
    0.6667
   -0.3333
    0.6667
> sqlpsolve('delete_lp', lp);

Overview of API routines

Note that everwhere where lp is used as argument that this can be a handle (lp_handle) or the models name.

  • add_column, add_columnex
    • return = sqlpsolve('add_column', lp, [column])
    • return = sqlpsolve('add_columnex', lp, [column])
    • Both have the same interface from add_column but act as add_columnex
  • add_constraint, add_constraintex
    • return = sqlpsolve('add_constraint', lp, [row], constr_type, rh)
    • return = sqlpsolve('add_constraintex', lp, [row], constr_type, rh)
    • Both have the same interface from add_constraint but act as add_constraintex
  • add_SOS
    • return = sqlpsolve('add_SOS', lp, name, sostype, priority, [sosvars], [weights])
    • The count argument in the API documentation is not needed in Sysquake since the number of elements is derived from the size of the sosvars and weights matrices. These must have the same size.
  • column_in_lp
    • return = sqlpsolve('column_in_lp', lp, [column])
    • No special considerations.
  • copy_lp
    • lp_handle = sqlpsolve('copy_lp', lp)
    • No special considerations.
  • default_basis
    • sqlpsolve('default_basis', lp)
    • No special considerations.
  • del_column
    • return = sqlpsolve('del_column', lp, column)
    • No special considerations.
  • del_constraint
    • return = sqlpsolve('del_constraint', lp, del_row)
    • No special considerations.
  • delete_lp
    • sqlpsolve('delete_lp', lp)
    • No special considerations.
  • free_lp
    • sqlpsolve('free_lp', lp)
    • lp is not changed as in the lpsolve API since it is a read_only input parameter. So it acts the same as delete_lp.
  • get_anti_degen
    • return = sqlpsolve('get_anti_degen', lp)
    • No special considerations.
  • get_basis
    • [bascolumn] = sqlpsolve('get_basis', lp {, nonbasic})
    • The bascolumn argument in the API documentation is here the return value. The nonbasic argument is optional in Sysquake. If not provided, then 0 is used.
  • get_basiscrash
    • return = sqlpsolve('get_basiscrash', lp)
    • No special considerations.
  • get_bb_depthlimit
    • return = sqlpsolve('get_bb_depthlimit', lp)
    • No special considerations.
  • get_bb_floorfirst
    • return = sqlpsolve('get_bb_floorfirst', lp)
    • No special considerations.
  • get_bb_rule
    • return = sqlpsolve('get_bb_rule', lp)
    • No special considerations.
  • get_bounds_tighter
    • return = sqlpsolve('get_bounds_tighter', lp)
    • No special considerations.
  • get_break_at_value
    • return = sqlpsolve('get_break_at_value', lp)
    • No special considerations.
  • get_col_name
    • name = sqlpsolve('get_col_name', lp, column)
    • [names] = sqlpsolve('get_col_name', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_column get_columnex
    • [column, return] = sqlpsolve('get_column', lp, col_nr)
    • [column, return] = sqlpsolve('get_columnex', lp, col_nr)
    • The column argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_constr_type
    • return = sqlpsolve('get_constr_type', lp, row)
    • [constr_type] = sqlpsolve('get_constr_type', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_constr_value
    • return = sqlpsolve('get_constr_value', lp, row {, primsolution})
    • The primsolution argument is optional. If not provided, then the solution of last solve is used.
  • get_constraints
    • [constr, return] = sqlpsolve('get_constraints', lp)
    • The constr argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_dual_solution
    • [duals, return] = sqlpsolve('get_dual_solution', lp)
    • The duals argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_epsb
    • return = sqlpsolve('get_epsb', lp)
    • No special considerations.
  • get_epsd
    • return = sqlpsolve('get_epsd', lp)
    • No special considerations.
  • get_epsel
    • return = sqlpsolve('get_epsel', lp)
    • No special considerations.
  • get_epsint
    • return = sqlpsolve('get_epsint', lp)
    • No special considerations.
  • get_epsperturb
    • return = sqlpsolve('get_epsperturb', lp)
    • No special considerations.
  • get_epspivot
    • return = sqlpsolve('get_epspivot', lp)
    • No special considerations.
  • get_improve
    • return = sqlpsolve('get_improve', lp)
    • No special considerations.
  • get_infinite
    • return = sqlpsolve('get_infinite', lp)
    • No special considerations.
  • get_lowbo
    • return = sqlpsolve('get_lowbo', lp, column)
    • [return] = sqlpsolve('get_lowbo', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_lp_index
    • return = sqlpsolve('get_lp_index', lp, orig_index)
    • No special considerations.
  • get_lp_name
    • name = sqlpsolve('get_lp_name', lp)
    • No special considerations.
  • get_mat
    • value = sqlpsolve('get_mat', lp, row, col)
    • [matrix, return] = sqlpsolve('get_mat', lp[, sparse])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix in the first return value. sparse is ignored in Sysquake.
  • get_max_level
    • return = sqlpsolve('get_max_level', lp)
    • No special considerations.
  • get_maxpivot
    • return = sqlpsolve('get_maxpivot', lp)
    • No special considerations.
  • get_mip_gap
    • return = sqlpsolve('get_mip_gap', lp, absolute)
    • No special considerations.
  • get_nameindex
    • return = sqlpsolve('get_nameindex', lp, name, isrow)
    • No special considerations.
  • get_Ncolumns
    • return = sqlpsolve('get_Ncolumns', lp)
    • No special considerations.
  • get_negrange
    • return = sqlpsolve('get_negrange', lp)
    • No special considerations.
  • get_nonzeros
    • return = sqlpsolve('get_nonzeros', lp)
    • No special considerations.
  • get_Norig_columns
    • return = sqlpsolve('get_Norig_columns', lp)
    • No special considerations.
  • get_Norig_rows
    • return = sqlpsolve('get_Norig_rows', lp)
    • No special considerations.
  • get_Nrows
    • return = sqlpsolve('get_Nrows', lp)
    • No special considerations.
  • get_obj_bound
    • return = sqlpsolve('get_obj_bound', lp)
    • No special considerations.
  • get_objective
    • return = sqlpsolve('get_objective', lp)
    • No special considerations.
  • get_orig_index
    • return = sqlpsolve('get_orig_index', lp, lp_index)
    • No special considerations.
  • get_origcol_name
    • name = sqlpsolve('get_origcol_name', lp, column)
    • [names] = sqlpsolve('get_origcol_name', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_origrow_name
    • name = sqlpsolve('get_origrow_name', lp, row)
    • [names] = sqlpsolve('get_origrow_name', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_pivoting
    • return = sqlpsolve('get_pivoting', lp)
    • No special considerations.
  • get_presolve
    • return = sqlpsolve('get_presolve', lp)
    • No special considerations.
  • get_presolveloops
    • return = sqlpsolve('get_presolveloops', lp)
    • No special considerations.
  • get_primal_solution
    • [pv, return] = sqlpsolve('get_primal_solution', lp)
    • The pv argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_print_sol
    • return = sqlpsolve('get_print_sol', lp)
    • No special considerations.
  • get_ptr_constraints
    • Not implemented.
  • get_ptr_dualsolution
    • Not implemented.
  • get_ptr_primal_solution
    • Not implemented.
  • get_ptr_sensitivity_obj, get_ptr_sensitivity_objex
    • Not implemented.
  • get_ptr_sensitivity_rhs
    • Not implemented.
  • get_ptr_variables
    • Not implemented.
  • get_rh
    • return = sqlpsolve('get_rh', lp, row)
    • [rh] = sqlpsolve('get_rh', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_rh_range
    • return = sqlpsolve('get_rh_range', lp, row)
    • [rh_ranges] = sqlpsolve('get_rh_range', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_row get_rowex
    • [row, return] = sqlpsolve('get_row', lp, row_nr)
    • [row, return] = sqlpsolve('get_rowex', lp, row_nr)
    • The row argument in the API documentation is here the first return value.
    • In the API, element 0 is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
    • The return code of the call is the second return value.
  • get_row_name
    • name = sqlpsolve('get_row_name', lp, row)
    • [names] = sqlpsolve('get_row_name', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_scalelimit
    • return = sqlpsolve('get_scalelimit', lp)
    • No special considerations.
  • get_scaling
    • return = sqlpsolve('get_scaling', lp)
    • No special considerations.
  • get_sensitivity_obj, get_sensitivity_objex
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = sqlpsolve('get_sensitivity_obj', lp)
    • [objfrom, objtill, objfromvalue, objtillvalue, return] = sqlpsolve('get_sensitivity_objex', lp)
    • The objfrom, objtill, objfromvalue, objtillvalue arguments in the API documentation are here the return values. Note that Sysquake allows the return of fewer variables. For example if only objfrom and objtill are needed then the call can be [objfrom, objtill] = sqlpsolve('get_sensitivity_obj', lp). The unrequested values are even not calculated.
    • Since the API routine doesn't calculate the objtillvalue value at this time, Sysquake always returns a zero vector for this.
    • The return code of the call is the last value.
    • get_sensitivity_obj and get_sensitivity_objex are both implemented, but have the same functionality.
  • get_sensitivity_rhs, get_sensitivity_rhsex
    • [duals, dualsfrom, dualstill, return] = sqlpsolve('get_sensitivity_rhs', lp)
    • [duals, dualsfrom, dualstill, return] = sqlpsolve('get_sensitivity_rhsex', lp)
    • The duals, dualsfrom, dualstill arguments in the API documentation are here the return values. Note that Sysquake allows the return of fewer variables. For example if only duals is needed then the call can be [duals] = sqlpsolve('get_sensitivity_rhs', lp). The unrequested values are even not calculated.
    • The return code of the call is the last value.
    • get_sensitivity_rhs and get_sensitivity_rhsex are both implemented, but have the same functionality.
  • get_simplextype
    • return = sqlpsolve('get_simplextype', lp)
    • No special considerations.
  • get_solutioncount
    • return = sqlpsolve('get_solutioncount', lp)
    • No special considerations.
  • get_solutionlimit
    • return = sqlpsolve('get_solutionlimit', lp)
    • No special considerations.
  • get_status
    • return = sqlpsolve('get_status', lp)
    • No special considerations.
  • get_statustext
    • return = sqlpsolve('get_statustext', lp, statuscode)
    • No special considerations.
  • get_timeout
    • return = sqlpsolve('get_timeout', lp)
    • No special considerations.
  • get_total_iter
    • return = sqlpsolve('get_total_iter', lp)
    • No special considerations.
  • get_total_nodes
    • return = sqlpsolve('get_total_nodes', lp)
    • No special considerations.
  • get_upbo
    • return = sqlpsolve('get_upbo', lp, column)
    • [upbo] = sqlpsolve('get_upbo', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_var_branch
    • return = sqlpsolve('get_var_branch', lp, column)
    • [var_branch] = sqlpsolve('get_var_branch', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_var_dualresult
    • return = sqlpsolve('get_var_dualresult', lp, index)
    • No special considerations.
  • get_var_primalresult
    • return = sqlpsolve('get_var_primalresult', lp, index)
    • No special considerations.
  • get_var_priority
    • return = sqlpsolve('get_var_priority', lp, column)
    • [var_priority] = sqlpsolve('get_var_priority', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • get_variables
    • [var, return] = sqlpsolve('get_variables', lp)
    • The var argument in the API documentation is here the first return value.
    • The return code of the call is the second return value.
  • get_verbose
    • return = sqlpsolve('get_verbose', lp)
    • No special considerations.
  • get_working_objective
    • return = sqlpsolve('get_working_objective', lp)
    • No special considerations.
  • guess_basis
    • [basisvector, return] = sqlpsolve('guess_basis', lp, [guessvector])
    • In the API, element 0 of guessvector is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
    • In the API, element 0 of basisvector is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
  • has_BFP
    • return = sqlpsolve('has_BFP', lp)
    • No special considerations.
  • has_XLI
    • return = sqlpsolve('has_XLI', lp)
    • No special considerations.
  • is_add_rowmode
    • return = sqlpsolve('is_add_rowmode', lp)
    • No special considerations.
  • is_anti_degen
    • return = sqlpsolve('is_anti_degen', lp, testmask)
    • No special considerations.
  • is_binary
    • return = sqlpsolve('is_binary', lp, column)
    • [binary] = sqlpsolve('is_binary', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • is_break_at_first
    • return = sqlpsolve('is_break_at_first', lp)
    • No special considerations.
  • is_constr_type
    • return = sqlpsolve('is_constr_type', lp, row, mask)
    • No special considerations.
  • is_debug
    • return = sqlpsolve('is_debug', lp)
    • No special considerations.
  • is_feasible
    • return = sqlpsolve('is_feasible', lp, [values] {, threshold})
    • The threshold argument is optional. When not provided, the value of get_epsint will be taken.
  • is_free is_unbounded
    • return = sqlpsolve('is_free', lp, column)
    • return = sqlpsolve('is_unbounded', lp, column)
    • [free] = sqlpsolve('is_free', lp)
    • [free] = sqlpsolve('is_unbounded', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • is_infinite
    • return = sqlpsolve('is_infinite', lp, value)
    • No special considerations.
  • is_int
    • return = sqlpsolve('is_int', lp, column)
    • [int] = sqlpsolve('is_int', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • is_integerscaling
    • return = sqlpsolve('is_integerscaling', lp)
    • No special considerations.
  • is_maxim
    • return = sqlpsolve('is_maxim', lp)
    • No special considerations.
  • is_nativeBFP
    • return = sqlpsolve('is_nativeBFP', lp)
    • No special considerations.
  • is_nativeXLI
    • return = sqlpsolve('is_nativeXLI', lp)
    • No special considerations.
  • is_negative
    • return = sqlpsolve('is_negative', lp, column)
    • [negative] = sqlpsolve('is_negative', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • is_piv_mode
    • return = sqlpsolve('is_piv_mode', lp, testmask)
    • No special considerations.
  • is_piv_rule
    • return = sqlpsolve('is_piv_rule', lp, rule)
    • No special considerations.
  • is_presolve
    • return = sqlpsolve('is_presolve', lp, testmask)
    • No special considerations.
  • is_scalemode
    • return = sqlpsolve('is_scalemode', lp, testmask)
    • No special considerations.
  • is_scaletype
    • return = sqlpsolve('is_scaletype', lp, scaletype)
    • No special considerations.
  • is_semicont
    • return = sqlpsolve('is_semicont', lp, column)
    • [semicont] = sqlpsolve('is_semicont', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • is_SOS_var
    • return = sqlpsolve('is_SOS_var', lp, column)
    • [SOS_var] = sqlpsolve('is_SOS_var', lp)
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows retrieving the values into a Sysquake matrix.
  • is_trace
    • return = sqlpsolve('is_trace', lp)
    • No special considerations.
  • is_use_names
    • return = sqlpsolve('is_use_names', lp, isrow)
    • No special considerations.
  • lp_solve_version
    • versionstring = sqlpsolve('lp_solve_version')
    • The sqlpsolve API routine returns the version information in 4 provided argument variables while the Sysquake version returns the information as a string in the format major.minor.release.build
  • make_lp
    • lp_handle = sqlpsolve('make_lp', rows, columns)
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
  • print_constraints
    • sqlpsolve('print_constraints', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
    • The same information can also be obtained via sqlpsolve('get_constraints', lp). This shows the result on screen.
  • print_debugdump
    • return = sqlpsolve('print_debugdump', lp, filename)
    • No special considerations.
  • print_duals
    • sqlpsolve('print_duals', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
    • The same information can be obtained via sqlpsolve('get_dual_solution', lp). This shows the result on screen.
  • print_lp
    • sqlpsolve('print_lp', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
  • print_objective
    • sqlpsolve('print_objective', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
    • The same information can be obtained via sqlpsolve('get_objective', lp). This shows the result on screen.
  • print_scales
    • sqlpsolve('print_scales', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
  • print_solution
    • sqlpsolve('print_solution', lp {, columns})
    • columns is optional. If not specified, then 1 is used.
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
    • The same information can also be obtained via sqlpsolve('get_variables', lp). This shows the result on screen.
  • print_str
    • sqlpsolve('print_str', lp, str)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
  • print_tableau
    • sqlpsolve('print_tableau', lp)
    • First call set_outputfile to specify where the information is written to. In the API documentation it is written that by default, the output goes to stdout, but under Sysquake (Windows) this means that the output is not shown.
  • put_abortfunc
    • Not implemented.
  • put_logfunc
    • Not implemented.
    • However, the sqlpsolve driver sets a log function to redirect the output of lpsolve from stdout (which is not visible in Windows Sysquake) to the command window of Sysquake. As such, all reported output can be seen in Sysquake. How much output is seen is controlled by the verbose level that can be defined by set_verbose or can be specified in the read_ routines.
  • put_msgfunc
    • Not implemented.
  • read_basis
    • [ret, info] = sqlpsolve('read_basis', lp, filename)
    • No special considerations.
  • read_freemps, read_freeMPS
    • lp_handle = sqlpsolve('read_freemps', filename {, options})
    • lp_handle = sqlpsolve('read_freeMPS', filename {, options})
    • In the lpsolve API, read_freemps needs a FILE handle. In Sysquake it needs the filename and thus acts the same as read_freeMPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_lp, read_LP
    • lp_handle = sqlpsolve('read_lp', filename {, verbose {, lp_name}})
    • lp_handle = sqlpsolve('read_LP', filename {, verbose {, lp_name}})
    • In the lpsolve API, read_lp needs a FILE handle. In Sysquake it needs the filename and thus acts the same as read_LP.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • verbose is optional. If not provided then NORMAL is used.
    • lp_name is optional. If not provided then no name is given to the model ('').
  • read_mps, read_MPS
    • lp_handle = sqlpsolve('read_mps', filename {, options})
    • lp_handle = sqlpsolve('read_MPS', filename {, options})
    • In the lpsolve API, read_mps needs a FILE handle. In Sysquake it needs the filename and thus acts the same as read_MPS.
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • options is optional. If not specified, then NORMAL is used.
  • read_params
    • return = sqlpsolve('read_params', lp, filename {, options })
    • options is optional.
  • read_XLI
    • lp_handle = sqlpsolve('read_XLI', xliname, modelname {, dataname {, options {, verbose}}}
    • lp_handle is not a pointer to an lprec structure as in the API, but an incrementing handle number starting from 0.
    • dataname is optional. When not provided, '' (NULL) is taken. '' is taken as NULL.
    • options is optional. When not provided, '' is taken.
    • verbose is optional. If not specified, then NORMAL is used.
  • reset_basis
  • set_basisvar
    • sqlpsolve('set_basisvar', lp, basisPos, enteringCol)
    • No special considerations.
  • set_add_rowmode
    • return = sqlpsolve('set_add_rowmode', lp, turnon)
    • No special considerations.
  • set_anti_degen
    • sqlpsolve('set_anti_degen', lp, anti_degen)
    • No special considerations.
  • set_basis
    • return = sqlpsolve('set_basis', lp, [bascolumn], nonbasic)
    • In the API, element 0 of bascolumn is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
  • set_basiscrash
    • sqlpsolve('set_basiscrash', lp, mode)
    • No special considerations.
  • set_bb_depthlimit
    • sqlpsolve('set_bb_depthlimit', lp, bb_maxlevel)
    • No special considerations.
  • set_bb_floorfirst
    • sqlpsolve('set_bb_floorfirst', lp, bb_floorfirst)
    • No special considerations.
  • set_bb_rule
    • sqlpsolve('set_bb_rule', lp, bb_rule)
    • No special considerations.
  • set_BFP
    • return = sqlpsolve('set_BFP', lp, filename)
    • No special considerations.
  • set_binary
    • return = sqlpsolve('set_binary', lp, column, must_be_bin)
    • return = sqlpsolve('set_binary', lp, [must_be_bin])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds
    • return = sqlpsolve('set_bounds', lp, column, lower, upper)
    • return = sqlpsolve('set_bounds', lp, [lower], [upper])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_bounds_tighter
    • sqlpsolve('set_bounds_tighter', lp, tighten)
    • No special considerations.
  • set_break_at_first
    • sqlpsolve('set_break_at_first', lp, break_at_first)
    • No special considerations.
  • set_break_at_value
    • sqlpsolve('set_break_at_value', lp, break_at_value)
    • No special considerations.
  • set_col_name
    • return = sqlpsolve('set_col_name', lp, column, name)
    • return = sqlpsolve('set_col_name', lp, [names])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_column, set_columnex
    • return = sqlpsolve('set_column', lp, col_no, [column])
    • return = sqlpsolve('set_columnex', lp, col_no, [column])
    • Both have the same interface from set_column but act as set_columnex
  • set_constr_type
    • return = sqlpsolve('set_constr_type', lp, row, con_type)
    • return = sqlpsolve('set_constr_type', lp, [con_type])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_debug
    • sqlpsolve('set_debug', lp, debug)
    • No special considerations.
  • set_epsb
    • sqlpsolve('set_epsb', lp, epsb)
    • No special considerations.
  • set_epsd
    • sqlpsolve('set_epsd', lp, epsd)
    • No special considerations.
  • set_epsel
    • sqlpsolve('set_epsel', lp, epsel)
    • No special considerations.
  • set_epsint
    • sqlpsolve('set_epsint', lp, epsint)
    • No special considerations.
  • set_epslevel
    • sqlpsolve('set_epslevel', lp, epslevel)
    • No special considerations.
  • set_epsperturb
    • sqlpsolve('set_epsperturb', lp, epsperturb)
    • No special considerations.
  • set_epspivot
    • sqlpsolve('set_epspivot', lp, epspivot)
    • No special considerations.
  • set_free set_unbounded
    • return = sqlpsolve('set_free', lp, column)
    • return = sqlpsolve('set_unbounded', lp, column)
    • No special considerations.
  • set_improve
    • sqlpsolve('set_improve', lp, improve)
    • No special considerations.
  • set_infinite
    • sqlpsolve('set_infinite', lp, infinite)
    • No special considerations.
  • set_int
    • return = sqlpsolve('set_int', lp, column, must_be_int)
    • return = sqlpsolve('set_int', lp, [must_be_int])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lowbo
    • return = sqlpsolve('set_lowbo', lp, column, value)
    • return = sqlpsolve('set_lowbo', lp, [values])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_lp_name
    • return = sqlpsolve('set_lp_name', lp, name)
    • In Sysquake, when you name a model, this name can be used everywhere where lp is specified. This to access the model via the name instead of via a handle.
  • set_mat
    • return = sqlpsolve('set_mat', lp, row, column, value)
    • return = sqlpsolve('set_mat', lp, [matrix])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows to set the whole matrix (all rows/columns) at once. This is the most performant way to provide the constraint matrix. The matrix must be two-dimentional.
  • set_maxim
    • sqlpsolve('set_maxim', lp)
    • No special considerations.
  • set_maxpivot
    • sqlpsolve('set_maxpivot', max_num_inv)
    • No special considerations.
  • set_minim
    • sqlpsolve('set_minim', lp)
    • No special considerations.
  • set_mip_gap
    • sqlpsolve('set_mip_gap', lp, absolute, mip_gap)
    • No special considerations.
  • set_negrange
    • sqlpsolve('set_negrange', negrange)
    • No special considerations.
  • set_obj
    • return = sqlpsolve('set_obj', lp, column, value)
    • return = sqlpsolve('set_obj', lp, [values])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables. It is then the same as set_obj_fn
  • set_obj_bound
    • sqlpsolve('set_obj_bound', lp, obj_bound)
    • No special considerations.
  • set_obj_fn, set_obj_fnex
    • return = sqlpsolve('set_obj_fn', lp, [row])
    • return = sqlpsolve('set_obj_fnex', lp, [row])
    • Both have the same interface from set_obj_fn but act as set_obj_fnex
    • In the API, element 0 is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
  • set_outputfile
    • return = sqlpsolve('set_outputfile', lp, filename)
    • In the API description it says that setting filename to NULL results in writing output back to stdout. In Sysquake under Windows, output to stdout it not shown. However it results in closing the file. Use '' to have the effect of NULL.
  • set_outputstream
    • Not implemented.
  • set_pivoting
    • sqlpsolve('set_pivoting', lp, pivoting)
    • No special considerations.
  • set_preferdual
    • sqlpsolve('set_preferdual', lp, dodual)
    • No special considerations.
  • set_presolve
    • sqlpsolve('set_presolve', lp, do_presolve {, maxloops})
    • The maxloops argument is optional in Sysquake. If not provided, then infinite is used.
  • set_print_sol
    • sqlpsolve('set_print_sol', lp, print_sol)
    • No special considerations.
  • set_rh
    • return = sqlpsolve('set_rh', lp, row, value)
    • return = sqlpsolve('set_rh', lp, [values])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows. Note that in this case, the value of row 0 is not specified in the matrix.
  • set_rh_range
    • return = sqlpsolve('set_rh_range', lp, row, deltavalue)
    • return = sqlpsolve('set_rh_range', lp, [deltavalues])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_rh_vec
    • sqlpsolve('set_rh_vec', lp, [rh])
    • In the API, element 0 is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
  • set_row, set_rowex
    • return = sqlpsolve('set_row', lp, row_no, [row])
    • return = sqlpsolve('set_rowex', lp, row_no, [row])
    • Both have the same interface from set_row but act as set_rowex
    • In the API, element 0 is not used and values start from element 1. In Sysquake, there is no unused element in the matrix.
  • set_row_name
    • return = sqlpsolve('set_row_name', lp, row, name)
    • return = sqlpsolve('set_row_name', lp, [names])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all rows.
  • set_scalelimit
    • sqlpsolve('set_scalelimit', lp, scalelimit)
    • No special considerations.
  • set_scaling
    • sqlpsolve('set_scaling', lp, scalemode)
    • No special considerations.
  • set_semicont
    • return = sqlpsolve('set_semicont', lp, column, must_be_sc)
    • return = sqlpsolve('set_semicont', lp, [must_be_sc])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_sense
    • sqlpsolve('set_sense', lp, maximize)
    • No special considerations.
  • set_simplextype
    • sqlpsolve('set_simplextype', lp, simplextype)
    • No special considerations.
  • set_solutionlimit
    • sqlpsolve('set_solutionlimit', lp, simplextype)
    • No special considerations.
  • set_timeout
    • sqlpsolve('set_timeout', lp, sectimeout)
    • No special considerations.
  • set_trace
    • sqlpsolve('set_trace', lp, trace)
    • No special considerations.
  • set_upbo
    • return = sqlpsolve('set_upbo', lp, column, value)
    • return = sqlpsolve('set_upbo', lp, [values])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_use_names
    • sqlpsolve('set_use_names', lp, isrow, use_names)
    • No special considerations.
  • set_var_branch
    • return = sqlpsolve('set_var_branch', lp, column, branch_mode)
    • return = sqlpsolve('set_var_branch', lp, [branch_mode])
    • In Sysquake, this routine has two formats. The first format is identical to the API. The second format allows setting a matrix of all variables.
  • set_var_weights
    • return = sqlpsolve('set_var_weights', lp, [weights])
    • No special considerations.
  • set_verbose
    • sqlpsolve('set_verbose', lp, verbose)
    • No special considerations.
  • set_XLI
    • return = sqlpsolve('set_XLI', lp, filename)
    • No special considerations.
  • solve
    • result = sqlpsolve('solve', lp)
    • No special considerations.
  • str_add_column
    • Not implemented.
  • str_add_constraint
    • Not implemented.
  • str_set_obj_fn
    • Not implemented.
  • str_set_rh_vec
    • Not implemented.
  • time_elapsed
    • return = sqlpsolve('time_elapsed', lp)
    • No special considerations.
  • unscale
    • sqlpsolve('unscale', lp)
    • No special considerations.
  • write_basis
    • sqlpsolve('write_basis', lp, filename)
    • No special considerations.
  • write_freemps, write_freeMPS
    • return = sqlpsolve('write_freemps', lp, filename)
    • return = sqlpsolve('write_freeMPS', lp, filename)
    • In the lpsolve API, write_freeMPS needs a FILE handle. In Sysquake it needs the filename and thus acts the same as write_freemps.
  • write_lp, write_LP
    • return = sqlpsolve('write_lp', lp, filename)
    • return = sqlpsolve('write_LP', lp, filename)
    • In the lpsolve API, write_LP needs a FILE handle. In Sysquake it needs the filename and thus acts the same as write_lp.
  • write_mps, write_MPS
    • return = sqlpsolve('write_mps', lp, filename)
    • return = sqlpsolve('write_MPS', lp, filename)
    • In the lpsolve API, write_MPS needs a FILE handle. In Sysquake it needs the filename and thus acts the same as write_mps.
    • No special considerations.
  • write_XLI
    • return = sqlpsolve('write_XLI', lp, filename {, options {, results}})
    • No special considerations.

Extra Sysquake routines

These routines are not part of the lpsolve API, but are added for backwards compatibility. Most of them exist in the lpsolve API with another name.

  • [names] = sqlpsolve('get_col_names', lp)
    • The same as get_col_name. Implemented for backwards compatibility.
  • [constr_type] = sqlpsolve('get_constr_types', lp)
    • The same as get_constr_type. Implemented for backwards compatibility.
  • [int] = sqlpsolve('get_int', lp)
    • The same as is_int. Implemented for backwards compatibility.
  • return = sqlpsolve('get_no_cols', lp)
    • The same as get_Ncolumns. Implemented for backwards compatibility.
  • return = sqlpsolve('get_no_rows', lp)
    • The same as get_Nrows. Implemented for backwards compatibility.
  • name = sqlpsolve('get_objective_name', lp)
    • The same as get_row_name with row=0. Implemented for backwards compatibility.
  • [row_vec, return] = sqlpsolve('get_obj_fn', lp)
    [row_vec, return] = sqlpsolve('get_obj_fun', lp)
    • The same as get_row with row 0. Implemented for backwards compatibility.
  • name = sqlpsolve('get_problem_name', lp)
    • The same as get_lp_name. Implemented for backwards compatibility.
  • [costs] = sqlpsolve('get_reduced_costs', lp)
    • The same as get_dual_solution. Implemented for backwards compatibility.
  • [names] = sqlpsolve('get_row_names', lp)
    • The same as get_row_name. Implemented for backwards compatibility.
  • [obj, x, duals, return] = sqlpsolve('get_solution', lp)
    • Returns the value of the objective function, the values of the variables and the duals. Implemented for backwards compatibility.
    • The return code of the call is the last value.
  • value = sqlpsolve('mat_elm', lp)
    • The same as get_mat. Implemented for backwards compatibility.
  • [handle_vec] = sqlpsolve('print_handle')
    • Returns a vector with open handles. Can be handy to see which handles aren't closed yet with delete_lp or free_lp.
  • lp_handle = sqlpsolve('read_lp_file', filename {, verbose {, lp_name}})
    • The same as read_LP. Implemented for backwards compatibility.
  • lp_handle = sqlpsolve('get_handle', lp_name)
    • Get the handle for this model from the models name. If an unknown model name is given (or already deleted), -1 is returned.
  • return_constants = sqlpsolve('return_constants'[, return_constants])
    • Returns the setting of return_constants and optionally sets its value.

Compile the sqlpsolve driver

Under Windows, the sqlpsolve Sysquake driver is a dll: sqlpsolvext.dll
Under Unix/Linux, the sqlpsolve Sysquake driver is a shared library.: sqlpsolvext.so
This driver is an interface to the lpsolve library lpsolve55.dll/liblpsolve55.so that contains the implementation of lp_solve. lpsolve55.dll/liblpsolve55.so is distributed with the lp_solve package (archive lp_solve_5.5.2.11_dev.zip/lp_solve_5.5.2.11_dev.tar.gz). The sqlpsolve Sysquake driver is just a wrapper between Sysquake and lp_solve to translate the input/output to/from Sysquake and the lp_solve library.

Compilation

The sqlpsolve Sysquake driver is written in C. To compile this code, under Windows the Microsoft visual C compiler is needed and under Unix/Linux the standard cc compiler.
The needed commands are in a batch file/script.
Under Windows it is called cvc.bat, under Unix/Linux ccc.
In a command prompt/shell, go to the lpsolve Sysquake directory and enter cvc.bat/sh ccc and the compilation is done. The result is sqlpsolvext.dll/sqlpsolvext.so.

See also Using lpsolve from MATLAB, Using lpsolve from O-Matrix, Using lpsolve from Scilab, Using lpsolve from Octave, Using lpsolve from FreeMat, Using lpsolve from Euler, Using lpsolve from Python, Using lpsolve from Sage, Using lpsolve from PHP, Using lpsolve from R, Using lpsolve from Microsoft Solver Foundation

./time_elapsed.htm000666 000000 000000 00000004536 10237106466 012547 0ustar00000000 000000 time_elapsed

time_elapsed

Gets the time elapsed since start of solve.

REAL time_elapsed(lprec *lp);

Return Value

time_elapsed returns the number of seconds after solve and lag_solve has started.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The time_elapsed function returns the time in seconds since solve and lag_solve has started.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  long timeelapsed;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  solve(lp);

  timeelapsed = time_elapsed(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_timeout, set_timeout, solve, lag_solve

./unscale.htm000666 000000 000000 00000004517 10237106466 011545 0ustar00000000 000000 unscale

unscale

Unscales the model.

void unscale(lprec *lp);

Return Value

unscale has no return value.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

Remarks

The unscale function unscales the model. Scaling can influence numerical stability considerably. It is advisable to always use some sort of scaling.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  unscale(lp);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, set_scaling, get_scaling, is_integerscaling, set_scalelimit, get_scalelimit, is_scalemode, is_scaletype

./Win32/000777 000000 000000 00000000000 13751300670 010271 5ustar00000000 000000 ./write_basis.htm000666 000000 000000 00000007116 10617306662 012426 0ustar00000000 000000 write_basis

write_basis

Writes current basis to a file.

unsigned char write_basis(lprec *lp, char *filename);

Return Value

Returns TRUE if basis could be written to filename and FALSE if not.
A FALSE return value indicates an error. Specifically file could not be opened or not able to write in file.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

Filename to write the basis to.

Remarks

The write_basis function writes the current basis to filename.
This basis can later be reused by read_basis to reset a basis. Setting an initial basis can speed up the solver considerably. It is the starting point from where the algorithm continues to find an optimal solution.
When a restart is done, lp_solve continues at the last basis, except if set_basis, default_basis, guess_basis or read_basis is called.

The basis in the file is written in MPS bas file format.

When filename is NULL, then output is written to output set by set_outputstream, set_outputfile. By default this is stdout.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;
  int ret;

  /* Read LP model */
  lp = read_LP("model.lp", NORMAL, "test model");
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  ret = solve(lp);

  ret = write_basis(lp, "model.bas", NULL);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, get_basis, set_basis, default_basis, read_basis, guess_basis, get_basiscrash, set_basiscrash

./write_lp.htm000666 000000 000000 00000010560 10661766044 011740 0ustar00000000 000000 write_lp, write_LP, write_lpex

write_lp, write_LP, write_lpex

Write an lp model to a file or via a routine.

unsigned char write_LP(lprec *lp, FILE *stream);

unsigned char write_lp(lprec *lp, char *filename);

unsigned char write_lpex(lprec *lp, void *userhandle, (void *userhandle, char *buf) write_modeldata_routine);

Return Value

The routines return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
write_LP and write_lp write in a file. write_lpex calls routine write_modeldata_routine to pass the data to that must be written. In this routine you can do anything you want with the data. Note that data is provided in undefined shrunks.
Note that row entry mode must be off, else this function also fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

stream

Pointer to FILE structure.

filename

Filename to write the lp model to.

write_modeldata_routine

Routine to write the lp model to. The routine has following definition:
typedef int (__WINAPI write_modeldata_func)(void *userhandle, char *buf);
userhandle is the second parameter passed to write_lpex
buf is a shrunk of data.

Remarks

The write_lp and write_LP functions write the model to filename. write_LP needs a file pointer to an already opened file. write_lp accepts the name of the file. The latter function will generally be more convenient. write_lpex writes the model via a user defined routine.

When stream or filename are NULL, then output is written to output set by set_outputstream, set_outputfile. By default this is stdout.

The model in the file will be in lp-format.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"
int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  write_lp(lp, "model.lp");

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex

./write_mps.htm000666 000000 000000 00000011601 10661767074 012125 0ustar00000000 000000 write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex

write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex

Write an mps model.

unsigned char write_MPS(lprec *lp, FILE *stream);

unsigned char write_freeMPS(lprec *lp, FILE *stream);

unsigned char write_mps(lprec *lp, char *filename);

unsigned char write_freemps(lprec *lp, char *filename);

unsigned char MPS_writefileex(lprec *lp, int typeMPS, void *userhandle, (void *userhandle, char *buf) write_modeldata_routine);

Return Value

The routines return TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.
Note that row entry mode must be off, else this function also fails. See set_add_rowmode

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

stream

Pointer to FILE structure.

filename

Filename to write the mps model to.

typeMPS

type of the MPS file. Can be one of the following values:

MPSFIXED (1) Fixed MPS format
MPSFREE (2) Free MPS format

write_modeldata_routine

Routine to write the MPS model to. The routine has following definition:
typedef int (__WINAPI write_modeldata_func)(void *userhandle, char *buf);
userhandle is the second parameter passed to write_lp_ex
buf is a shrunk of data.

Remarks

The write_mps, write_freemps, write_MPS, write_freeMPS functions write the model to filename. write_MPS, write_freeMPS need a file pointer to an already opened file. write_mps, write_freemps accept the name of the file. The latter function will generally be more convenient. MPS_writefileex writes the model via a user defined routine.

When stream or filename are NULL, then output is written to output set by set_outputstream, set_outputfile. By default this is stdout.

The model in the file will be in mps-format. The write_free* routines write files in free MPS format. The other routines write files in fixed MPS format.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"
int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  write_mps(lp, "model.mps");

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp,read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, read_lp, read_LP, write_lp, write_LP, write_lpex, read_lp, read_LP

./write_params.htm000666 000000 000000 00000010737 10252334124 012600 0ustar00000000 000000 write_params

write_params

Write settings to a parameter file.

unsigned char write_params(lprec *lp, char *filename, char *options);

Return Value

Returns TRUE (1) if parameters could be written, else FALSE (0).

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

Filename to write the parameters to.

options

Optional options. Can be:
-h header: Write parameters at specified header. By default this is Default

Remarks

All lp_solve parameters (options) are written to a parameter file. This file has an ini-format as used by Windows applications. All parameters are written under a header. This is by default [Default]. The header can be specified in the options parameter. Other headers are preserved.

Example parameter file:

[Default]
; lp_solve version 5.5 settings

anti_degen=ANTIDEGEN_FIXEDVARS + ANTIDEGEN_STALLING + ANTIDEGEN_INFEASIBLE
basiscrash=CRASH_NONE
improve=IMPROVE_DUALFEAS + IMPROVE_THETAGAP
maxpivot=250
negrange=-1e+006
pivoting=PRICER_DEVEX + PRICE_ADAPTIVE
presolve=PRESOLVE_NONE
presolveloops=2147483647
scalelimit=5
scaling=SCALE_GEOMETRIC + SCALE_EQUILIBRATE + SCALE_INTEGERS
simplextype=SIMPLEX_DUAL_PRIMAL
bb_depthlimit=-50
bb_floorfirst=BRANCH_AUTOMATIC
bb_rule=NODE_PSEUDONONINTSELECT + NODE_GREEDYMODE + NODE_DYNAMICMODE + NODE_RCOSTFIXING
;break_at_first=0
;break_at_value=-1e+030
mip_gap_abs=1e-011
mip_gap_rel=1e-011
epsint=1e-007
epsb=1e-010
epsd=1e-009
epsel=1e-012
epsperturb=1e-005
epspivot=2e-007
infinite=1e+030
;debug=0
;obj_bound=1e+030
;print_sol=0
;timeout=0
;trace=0
;verbose=NORMAL

Note that there are some options commented out (;). This is done because these options can not be used in general for all models or because they are debug/trace/print options. These options can be made active and will be read by read_params but note again that they are possible dangerous to be used in general (except for the debug/trace/print options). Note that there are two kind of entries:

  • Numerical values
  • Options

Numercial values can be integer values like maxpivot or floating point values like epsel

Options are a combination of constants as defined in the manual. Multiple options are added with +. For example option anti_degen.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"

int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  write_params(lp, "a.ini", "-h MyParams"); /* Will write parameters in file a.ini under section MyParams */

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, read_params, reset_params

./write_XLI.htm000666 000000 000000 00000006213 10661575034 011756 0ustar00000000 000000 write_XLI

write_XLI

Write a model to a file via the External Language Interface.

unsigned char write_XLI(lprec *lp, char *filename, char *options, unsigned char results);

Return Value

write_XLI returns TRUE (1) if the operation was successful. A return value of FALSE (0) indicates an error.

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

Filename to write the model to.

options

Extra options that can be used by the writer.

results

FALSE to generate a model file and TRUE to generate a solution file.

Remarks

The write_XLI function writes the model to filename via the External Language Interface. Note that set_XLI must be called before this routine to set an XLI.

See External Language Interfaces for a complete description on XLIs.

Example

#include <stdio.h>
#include <stdlib.h>
#include "lp_lib.h"
int main(void)
{
  lprec *lp;

  /* Create a new LP model */
  lp = make_lp(0, 0);
  if(lp == NULL) {
    fprintf(stderr, "Unable to create new LP model\n");
    return(1);
  }

  set_XLI(lp, "xli_MathProg");

  write_XLI(lp, "model.mod", "", FALSE);

  delete_lp(lp);
  return(0);
}

lp_solve API reference

See Also delete_lp, free_lp, make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI, write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex, read_XLI, has_XLI, is_nativeXLI, set_XLI

./XLI.htm000666 000000 000000 00000043053 10474035744 010550 0ustar00000000 000000 External Language Interface

External Language Interfaces

To facilitate the development of other model language interfaces, a quite simple "eXternal Language Interface" (XLI) has been defined, which allows lp_solve to be dynamically configured (at run-time) to use alternative means to read and write the MIP model or write a solution file in a specific format. lp_solve has several build-in interfaces to models: mps, lp. XLI allows implementing a custom reader and writer for other model layouts and a solution layout.
This feature again gives a unique flexibility and openness to the user and developer community that we have quite some expectations for.
If you write your own XLI, we would be glad if you would share your code with the lp_solve community. We are very interested in providing as many different XLIs as possible to the community.

Under Windows, an XLI is provided as DLL (xli_*.dll), under UNIX/LINUX as a dynamic linked library (libxli_*.so). These libraries are loaded/linked at runtime with lp_solve.

Under Unix/Linux it is standard that a library has the lib prefix and a .so postfix.
For example libxli_MathProg.so
Under Windows there is no prefix and the postfix is .dll
For example xli_MathProg.dll

To make the calling structure for XLIs uniform across different types of OS, lp_solve automatically adds the prefix and postfix if not provided. So for example under all platforms, the MathProg XLI may be referenced as xli_MathProg. It is advised to call the XLIs as such.

To locate the XLI on the file system, the following search order is used if no path is provided:

Windows
  1. Current directory.
  2. A semi-colon-separated (;) list of directories in the user's PATH environment variable.
Unix/Linux
  1. A colon-separated (:) list of directories in the user's LD_LIBRARY_PATH environment variable.
  2. The list of libraries specified in /etc/ld.so.cache (which is generated from /etc/ld.so.conf).
  3. /lib, followed by /usr/lib. Note the order here; this is the reverse of the order used by the old a.out loader. The old a.out loader, when loading a program, first searched /usr/lib, then /lib (see the man page ld.so(8)). This shouldn't normally matter, since a library should only be in one or the other directory (never both), and different libraries with the same name are a disaster waiting to happen.

Note again that this search path is only used if no path is specified for the XLI.

Using an XLI with the lp_solve stand-alone program

The lp_solve program provides a way to specify an XLI for reading a model, an XLI for writing the model and an XLI for writing the solution file. These can be different so that a model in one format can be converted to another format. It is still possible to both read and write the models with the build-in formats (mps, lp) and you can combine with the XLI.

Read a model

With the lp_solve program, to set the XLI to read the model, use the option
-rxli xliname filename

filename is the name (with optional path) of the model name to read. If no path is specified, the file is read from the current directory.

Depending on the XLI, an optional data file name can be provided. Use the option
-rxlidata datafilename

For example for the MathProg XLI, there is a possible optional datafilename containing the data. Note that this name may not start with a minus sign (-)

Depending on the XLI, options can be provided to change the behaviour of the routine. Use the option
-rxliopt "options"

So the following commands are valid for both Windows and Unix/Linux:

lp_solve -rxli xli_MathProg input.mod -rxlidata input.dat
lp_solve -rxli ./xli_MathProg input.mod -rxlidata input.dat

The latter makes sure that the XLI is searched in the current directory, especially for Unix/Linux.

Write a model

With the lp_solve program, to set the XLI to write the model, use the option
-wxli xliname filename

filename is the name (with optional path) of the model name to write. If no path is specified, the file is written in the current directory.

Depending on the XLI, options can be provided to change the behaviour of the routine. Use the option
-wxliopt "options"

So the following commands are valid for both Windows and Unix/Linux:

lp_solve input.lp -wxli xli_MathProg output.mod
lp_solve input.lp -wxli ./xli_MathProg output.mod

The latter makes sure that the XLI is searched in the current directory, especially for Unix/Linux.

Write a solution

With the lp_solve program, to set the XLI to write the solution, use the option
-wxlisol xliname filename

filename is the name (with optional path) of the solution name to write. If no path is specified, the file is written in the current directory.

Depending on the XLI, options can be provided to change the behaviour of the routine. Use the option
-wxlisolopt "options"

So the following commands are valid for both Windows and Unix/Linux:

lp_solve -rxli xli_DIMACS maxflow.net -wxlisol xli_DIMACS maxflow.sol
lp_solve -rxli ./xli_MathProg maxflow.net -wxlisol xli_DIMACS maxflow.sol

The latter makes sure that the XLI is searched in the current directory, especially for Unix/Linux.

Using an XLI from the lpsolve API

Read a model

The read_XLI reads a model via an XLI.
See the API call for its usage.

Write a model

To write a model, two API calls are needed:

First use set_XLI to set the XLI library
See the API call for its usage.

Then use write_XLI to write the model.
See the API call for its usage. Note that the last argument, results must FALSE.

Write a solution

To write a model, two API calls are needed:

First use set_XLI to set the XLI library
See the API call for its usage.

Then use write_XLI to write the model.
See the API call for its usage. Note that the last argument, results must TRUE.

Creating an XLI

This section is only for people who will create their own XLI because you have a model file type that is not supported by lp_solve. The developers would appreciate it if you would make this XLI public.

To create your own XLI, you have to create a DLL/shared library that implements the following routines:

char * XLI_CALLMODEL xli_name(void)

Return Value

xli_name must return a string describing the XLI library.

Parameters

None

MYBOOL XLI_CALLMODEL xli_readmodel(lprec *lp, char *model, char *data, char *options, int verbose);

Return Value

Must return TRUE or FALSE to indicate if successful (TRUE) or not (FALSE).

Parameters

lp

An initial lp structure created via make_lp(0, 0).

model

Filename to read the model from.

data

Optional data to read data from. For example used by the MathProg XLI.

options

Extra options that can be used by the reader.

verbose

The verbose level. Can be used to output more or less information while creating the model.

Remarks

This routine is called when the read_XLI API is called.
Via the provided lp variable all lpsolve API routines can be accessed to create the model.
Note that xli_readmodel already provides an lp structure. You must use this one to build the model. The lp structure is created via make_lp(0, 0). So it contains 0 rows and 0 columns.

MYBOOL XLI_CALLMODEL xli_writemodel(lprec *lp, char *filename, char *options, MYBOOL results);

Return Value

Must return TRUE or FALSE to indicate if successful (TRUE) or not (FALSE).

Parameters

lp

Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI

filename

The filename argument of write_XLI. Filename to write the model/solution to.

options

The options argument of write_XLI. Extra options that can be used by the writer.

results

The results argument of write_XLI. When FALSE, the XLI should create a model file and when TRUE is should create a solution file.

Remarks

This routine is called when the write_XLI API is called.
This routine must be used to write the model/solution. Via the provided lp variable all lpsolve API routines can be accessed to do the job.

lp_XLI1.c must be included at the beginning of the source file. This to include an extra routine xli_compatible needed by the lpsolve library to check the compatibility.

If you want to create XLIs yourself, make sure that under Windows, you use 8 byte alignments. This is needed for the XLIs to work correctly with the general distribution of lp_solve and also to make sharing XLIs as uncomplicated as possible. If not, it will likely crash. It doesn't matter which calling convention is used to compile the library. The XLI_CALLMODEL directive makes sure that the calling convention of the needed routines is always ok independent of the calling convention specified in the project.
Also under windows, a definition file must be added. If this is not done, it will not work. The definition file should have extension .def and contain the following:

EXPORTS
  xli_compatible           @1
  xli_name                 @2
  xli_readmodel            @3
  xli_writemodel           @4

The definition file must be added to the project. How to do this depends on the version.
For Visual Studio 6: Project, Add to Project, Files, Files of type: Definition files (.def) and choose the created .def file
For Visual Studio .NET: Project, Properties, Linker, Input, Module Definition file. There you enter the name (with optional path) of the .def file.

XLI prototype
/* Generic include libraries */
#include <malloc.h>
#include <string.h>
#include "lp_lib.h"
#ifdef FORTIFY
# include "lp_fortify.h"
#endif

/* Include routines common to language interface implementations */

#include "lp_XLI1.c"

char * XLI_CALLMODEL xli_name(void)
{
  return("XLI_xxx v1.0" );  /* return the name and version */
}

MYBOOL XLI_CALLMODEL xli_readmodel(lprec *lp, char *model, char *data, char *options, int verbose)
{
  MYBOOL status = FALSE;

  /* implement the code here to read the model */

  return(status); /* status says if the model could be read or not. TRUE is ok, FALSE is not ok */
}

MYBOOL XLI_CALLMODEL xli_writemodel(lprec *lp, char *filename, char *options, MYBOOL results)
{
  MYBOOL status = FALSE;

  /* implement the code here to write the model */

  return( status ); /* status says if the model could be written or not. TRUE is ok, FALSE is not ok */
}
Working example:
demo.c:
/*  Modularized external language interface module - w/interface for lp_solve v5.0+
   ----------------------------------------------------------------------------------
    Author:        Peter Notebaert
    Contact:       lpsolve@peno.be
    License terms: LGPL.

    Template used:
    Requires:

    Release notes:
    v1.0.0  28 June 2004        First implementation.

   ---------------------------------------------------------------------------------- */

/* Generic include libraries */
#include <malloc.h>
#include <string.h>
#include "lp_lib.h"

/* Include libraries for this language system */
#include <math.h>

#ifdef FORTIFY
# include "lp_fortify.h"
#endif

/* Include routines common to language interface implementations */
#include "lp_XLI1.c"

char * XLI_CALLMODEL xli_name(void)
{
  return( "xli_demo v1.0" );
}

MYBOOL XLI_CALLMODEL xli_readmodel(lprec *lp, char *model, char *data, char *options, int verbose)
{
  MYBOOL status = FALSE;
  REAL row[1+2]; /* must be 1 more then number of columns ! */

  lp->add_columnex(lp, 0, NULL, NULL); /* add empty column */
  lp->add_columnex(lp, 0, NULL, NULL); /* add empty column */
  lp->set_add_rowmode(lp, TRUE);
  row[1] = 1.0;
  row[2] = 2.0;
  lp->add_constraint(lp, row, GE, 3.0); /* constructs the row: +v_1 +2 v_2 >= 3 */
  lp->set_add_rowmode(lp, FALSE);
  status = TRUE;

  return(status);
}

MYBOOL XLI_CALLMODEL xli_writemodel(lprec *lp, char *filename, char *options, MYBOOL results)
{
  if (!results)
    return(lp->write_lp(lp, filename));
  else {
    lp->print_objective(lp);
    lp->print_solution(lp, 1);
    lp->print_constraints(lp, 1);
    return(TRUE);
  }
}
demo.def:
EXPORTS
  xli_compatible           @1
  xli_name                 @2
  xli_readmodel            @3
  xli_writemodel           @4

This example is not very practical. It is only useful for demonstration purposes. Let's assume that the name of this library is xli_demo.
xli_readmodel creates the model. It doesn't even read from a file in this example. xli_writemodel uses write_lp to write the model to filename and some print_* functions to print the solution.

This XLI can be called from lp_solve via the following syntax:

lp_solve -S0 -rxli xli_demo "" -wxli xli_demo output.txt -wxlisol xli_demo ""

An empty ("") filename is provided because it isn't used by this demo. This command will create a file output.txt with contents:

/* Objective function */
min: ;

/* Constraints */
+C1 +2 C2 >= 3;

Because we didn't provide the option -parse_only, the model is also solved. However the lp_solve option -S0 disables showing the results. Results are generated via the -wxlisol option:

Value of objective function: 0

Actual values of the variables:
C1                              3
C2                              0

Actual values of the constraints:
R1                              3
./xli_MPS.htm000666 000000 000000 00000012037 11235563746 011431 0ustar00000000 000000 MPS XLI (xli_MPS)

MPS XLI (xli_MPS)

lp_solve supports the MPS format natively via API calls read_mps, read_freemps, read_MPS, read_freeMPS, write_mps, write_freemps, write_MPS, write_freeMPS, MPS_writefileex, read_basis, write_basis

This accoring to the following MPS format

Two issues are addressed in above document:

Objective constant

The objective can have a constant. This optional constant is specified in the RHS section. There are 2 interpretations of this constant. Some solvers see this as the constant that would be really in the RHS and when brought into the objective (LHS), it is negated. Other solvers, as lp_solve natively does, use the specified value in the MPS file as the value for the objective and don't negate it.
This XLI allows lp_solve to interprete the constant as the other solvers do, ie negate it.
This via the option -negobjconst

Integer/binary variables

A mixed integer program requires the specification of which variables are required to be integer. Markers are used to indicate the start and end of a group of integer variables. The start marker has its name in field 2, 'MARKER' in field 3, and 'INTORG' in field 5. The end marker has its name in field 2, 'MARKER' in field 3, and 'INTEND' in field 5. These markers are placed in the COLUMNS section. When there are BOUNDS on the variables, then these are used as lower and upper bound of these integer variables and there is no confusion possible. Even a lower bound of 0 is already enough. In that case, if there is no upper bound, infinite is used. However there is an interpretation problem if there are no bounds at all on these variables. Some solvers then use 0 as lower bound and 1 as upper bound. So the variables are treated as binary variables. That is the original IBM interpretation. Other solvers, like lp_solve by default, use the default bounds on variables in that case. That is 0 as lower bound and infinite as upper bound. When lp_solve writes an MPS file, it will write the default lower bound of 0 if there are no lower/upper bounds set on the variable. As such, there is no confusion. However when lp_solve reads an MPS file and there are no bounds on variables between INTORG/INTEND, by default it interpretes the variables as integer and not binary as some other solvers do. That could result in another solution than expected.
This XLI allows lp_solve to interprete these integer variables as binary as in the original ibm specification.
This via the option -ibm

Free format

This XLI also supports the free format via the option -free

Basis

read_basis and write_basis allow to read and write a basis in MPS format as described in MPS bas file format. This XLI also allows to read and write a basis in this format. This via the option -bas. This can be combined with option -free to read/write in a free format.

Reading and writing the basis with this XLI is a bit awkward. This because these operations must be done at a different moment than reading and writing of a model file.

Reading the basis must be done after reading the model, but before solve. The read routine of the XLI cannot be used for reading the basis because reading creates a new lp structure. Therefore, the write function of the XLI is (mis)used. With the lp_solve command line program, this can be done as follows:

lp_solve lpfile -wxli xli_MPS.dll basfile -wxliopt "-free"

Writing the basis must be done after solve. Therefore, the write function of the XLI is again used, but now with the results parameter on TRUE as if the results of a model must be written. This is also a bit of a misuse of the XLI, but it must be done to be sure that it is done after solve. With the lp_solve command line program, this can be done as follows:

lp_solve lpfile -wxlisol xli_MPS.dll basfile -wxlisolopt "-free"

Options summary

  -free          Read/write in free format.
  -ibm           Interprete integer variables as in the original ibm specifications
  -negobjconst   Negate the objective constant.
  -bas           Read/write a basis file
./Xpress-format.htm000666 000000 000000 00000050240 10724440642 012655 0ustar00000000 000000 Xpress lp files

Xpress lp files

The Xpress LP file format provides a facility for entering a problem in a natural, algebraic LP formulation from the keyboard. The problem can be modified and saved from within lpsolve. This procedure is one way to create a file in a format that lpsolve can read. An alternative technique is to create a similar file using a standard text editor and to read it into lpsolve.

The Xpress LP format is provided as an input alternative to the MPS file format. An LP format file may be easier to generate than an MPS file if your problem already exists in an algebraic format or if you have an application that generates the problem file more readily in algebraic format (such as a C application).

Note that the Xpress LP format is not the same as the lpsolve LP format. See LP file format for a description about the native lpsolve lp format. To read/write this format from lpsolve, you need an XLI (see External Language Interfaces). The XLI for the Xpress format is called xli_Xpress.

Options

The XLI accepts several options:

Reading

  -objconst      Allow constants in the objective (default).
  -noobjconst    Don't allow constants in the objective.

From the documentation of the format it is not sure if Xpress allows a constant in the objective. Tests have shown that it allows a constant as first term in the objective function. Note that the lp_solve XLI allows a constant in the objective by default and it can be anywere in the objective. Use the option -noobjconst if this should not be allowed. The parser will then give an error.

Writing

  -objconst      Allow constants in the objective.
  -noobjconst    Don't use constants in the objective (default).

From the documentation of the format it is not sure if Xpress allows a constant in the objective. Tests have shown that it allows a constant as first term in the objective function. The lp_solve XLI writes the constant as first term when the option -objconst is active. By default or when the option -noobjconst is used, a constant in the objective is translated to a variable objconst_term with a bound equal to the constant set to it. So no error is generated when there is a constant.

Example

lp_solve -rxli xli_Xpress input.lp
lp_solve -mps input.mps -wxli xli_Xpress output.lp -wxliopt "-objconst"

Syntax Rules of LP File Format

lpsolve will accept any problem saved in an ASCII file provided that it adheres to the following syntax rules.

  1. Comments and blank lines

    Text following a backslash (\) and up to the subsequent carriage return is treated as a comment. Blank lines are ignored. Blank lines and comments may be inserted anywhere in an .lp file. For example, a common comment to put in LP files is the name of the problem:

    \Problem name: prob01
    
  2. File lines, white space and identifiers

    White space and carriage returns delimit variable names and keywords from other identifiers. Keywords are case insensitive. Variable names are case sensitive. Although it is not strictly necessary, for clarity of your LP files it is perhaps best to put your section keywords on their own lines starting at the first character position on the line. No line continuation character is needed when expressions are required to span multiple lines. Lines may be broken for continuation wherever you may use white space.

  3. Sections

    The LP file is broken up into sections separated by section keywords. The following are a list of section keywords you can use in your LP files. A section started by a keyword is terminated with another section keyword indicating the start of the subsequent section.

    Section keywordsSynonymsSection contents
    maximize or minimizemaximum
    max
    minimum
    min
    One linear expression describing the objective function.
    subject tosubject to:
    such that
    st
    s.t.
    st.
    subjectto
    suchthat
    subject
    such
    A list of constraint expressions.
    boundsboundA list of bounds expressions for variables.
    integersinteger
    ints
    int
    A list of variable names of integer variables. Unless otherwise specified in the bounds section, the default relaxation interval of the variables is [0, 1].
    generalsgeneral
    gens
    gen
    A list of variable names of integer variables. Unless otherwise specified in the bounds section, the default relaxation interval of the variables is [0, infinite].
    binariesbinary
    bins
    bin
    A list of variable names of binary variables.
    semi-continuoussemi
    continuous
    semis
    semi
    s.c.
    A list of variable names of semicontinuous variables.
    semi integers.i.A list of variable names of semiinteger variables.
    partial integerp.i.A list of variable names of partial integer variables.
    Not supported by lp_solve

    Variables that do not appear in any of the variable type registration sections (i.e., integers, generals, binaries, semi-continuous, semi integer, partial integer) are defined to be continuous variables by default. That is, there is no section defining variables to be continuous variables.

    With the exception of the objective function section (maximize or minimize) and the constraints section (subject to), which must appear as the first and second sections respectively, the sections may appear in any order in the file. The only mandatory section is the objective function section. Note that you can define the objective function to be a constant in which case the problem is a so-called constraint satisfaction problem. The following two examples of LP file contents express empty problems with constant objective functions and no variables or constraints.

    Empty problem 1:

    Minimize
    
    End
    

    Empty problem 2:

    Minimize
    
    0
    
    End
    

    The end of a matrix description in an LP file can be indicated with the keyword end entered on a line by itself. This can be useful for allowing the remainder of the file for storage of comments, unused matrix definition information or other data that may be of interest to be kept together with the LP file.

  4. Variable names

    Variable names can use any of the alphanumeric characters (a-z, A-Z, 0-9) and any of the following symbols:

    !"#$%&/,.;?@_`{}()|~'
    

    A variable name can not begin with a number or a period. Care should be taken using the characters E or e since these may be interpreted as exponential notation for numbers.

  5. Linear expressions

    Linear expressions are used to define the objective function and constraints. Terms in a linear expression must be separated by either a + or a - indicating addition or subtraction of the following term in the expression. A term in a linear expression is either a variable name or a numerical coefficient followed by a variable name. It is not necessary to separate the coefficient and its variable with white space or a carriage return although it is advisable to do so since this can lead to confusion. For example, the string " 2e3x" in an LP file is interpreted using exponential notation as 2000 multiplied by variable x rather than 2 multiplied by variable e3x. Coefficients must precede their associated variable names. If a coefficient is omitted it is assumed to be 1.

  6. Objective function

    The objective function section can be written in a similar way to the following examples using either of the keywords maximize or minimize. Note that the keywords maximize and minimize are not used for anything other than to indicate the following linear expression to be the objective function. Note the following two examples of an LP file objective definition:

    Maximize
    - 1 x1 + 2 x2 + 3x + 4y
    

    or

    Minimize
    - 1 x1 + 2 x2 + 3x + 4y
    

    Generally objective functions are defined using many terms and thus the objective function definitions are typically always broken with line continuations. No line continuation character is required and lines may be broken for continuation wherever you may use white space.

    The objective function can be named in the same way as for constraints (see later).

  7. Constraints

    The section of the LP file defining the constraints is preceded by the keyword subject to. Each constraint definition must begin on a new line. A constraint may be named with an identifier followed by a colon before the constraint expression. Constraint names must follow the same rules as variable names. If no constraint name is specified for a constraint then a default name is assigned. Constraint names are trimmed of white space before being stored. The constraints are defined as a linear expression in the variables followed by an indicator of the constraint's sense and a numerical right-hand side coefficient. The constraint sense is indicated intuitively using one of the tokens: >=, <=, or =. For example, here is a named constraint:

    depot01: - x1 + 1.6 x2 - 1.7 x3 <= 40
    

    Note that tokens > and < can be used, respectively, in place of the tokens >= and <=.

    Generally, constraints are defined using many terms so the constraint definitions are typically broken with line continuations. No line continuation character is required and lines may be broken for continuation wherever you may use white space.

  8. Bounds

    The list of bounds in the bounds section are preceded by the keyword bounds. Each bound definition must begin on a new line. Single or double bounds can be defined for variables. Double bounds can be defined on the same line as 10 <= x <= 15 or on separate lines in the following ways:

    10 <= x
    15 >= x
    

    or

    x >= 10
    x <= 15
    

    If no bounds are defined for a variable, default lower and upper bounds are used. An important point to note is that the default bounds are different for different types of variables. For continuous variables the interval defined by the default bounds is [0, infinity] while for variables declared in the integers and generals section (see later) the relaxation interval defined by the default bounds is [0, 1] and [0, infinity], respectively.

    If a single bound is defined for a variable the appropriate default bounds are used as the second bound. Note that negative upper bounds on variables must be declared together with an explicit definition of the lower bound for the variable. Also note that variables can not be declared in the bounds section. That is, a variable appearing in a bounds section that does not appear in a constraint in the constraint section is ignored.

    Bounds that fix a variable can be entered as simple equalities. For example, x6 = 7.8 is equivalent to 7.8 <= x6 <= 7.8. The bounds +inf (positive infinity) and -inf (negative infinity) must be entered as strings (case insensitive):

    +infinity, -infinity, +inf, -inf.
    

    Note that the keywords infinity and inf may not be used as a right-hand side coefficient of a constraint.

    A variable with a negative infinity lower bound and positive infinity upper bound may be entered as free (case insensitive). For example, x9 free in an LP file bounds section is equivalent to:

    - infinity <= x9 <= + infinity
    

    or

    - infinity <= x9
    

    In the last example here, which uses a single bound is used for x9 (which is positive infinity for continuous example variable x9).

  9. Generals, Integers and binaries

    The generals, integers and binaries sections of an LP file is used to indicate the variables that must have integer values in a feasible solution. The difference between the variables registered in each of these sections is in the definition of the default bounds that the variables will have. For variables registered in the generals section the default bounds are 0 and infinity. For variables registered in the integers section the default bounds are 0 and 1. The bounds for variables registered in the binaries section are 0 and 1.

    The lines in the generals, integers and binaries sections are a list of white space or carriage return delimited variable names. Note that variables can not be declared in these sections. That is, a variable appearing in one of these sections that does not appear in a constraint in the constraint section is ignored.

  10. Semi-continuous and semi-integer

    The semi-continuous and semi integer sections of an LP file relate to two similar classes of variables and so their details are documented here simultaneously.

    The semi-continuous (or semi integer) section of an LP file are used to specify variables as semi-continuous (or semi-integer) variables, that is, as variables that may take either (a) value 0 or (b) real (or integer) values from specified thresholds and up to the variables' upper bounds.

    The lines in a semi-continuous (or semi integer) section are a list of white space or carriage return delimited entries that are either (i) a variable name or (ii) a variable name-number pair. The following example shows the format of entries in the semi-continuous section.

    Semi-continuous
    x7 >= 2.3
    x8
    x9 >= 4.5
    

    The following example shows the format of entries in the semi integer section.

    Semi integer
    x7 >= 3
    x8
    x9 >= 5
    

    Note that you can not use the <= token in place of the >= token.

    The threshold of the interval within which a variable may have real (or integer) values is defined in two ways depending on whether the entry for the variable is (i) a variable name or (ii) a variable name-number pair. If the entry is just a variable name, then the variable's threshold is the variable's lower bound, defined in the bounds section (see earlier). If the entry for a variable is a variable name-number pair, then the variable's threshold is the number value in the pair.

    It is important to note that if (a) the threshold of a variable is defined by a variable namenumber pair and (b) a lower bound on the variable is defined in the bounds section, then:

    Case 1) If the lower bound is less then zero, then the lower bound is zero.

    Case 2) If the lower bound is greater than zero but less than the threshold, then the value of zero is essentially cut off the domain of the semi-continuous (or semi-integer) variable and the variable becomes a simple bounded continuous (or integer) variable.

    Case 3) If the lower bound is greater than the threshold, then the variable becomes a simple lower bounded continuous (or integer) variable.

    If no upper bound is defined in the bounds section for a semi-continuous (or semi-integer) variable, then the default upper bound that is used is the same as for continuous variables, for semi-continuous variables, and generals section variables, for semi-integer variables.

  11. Partial integers

    The partial integers section of an LP file is used to specify variables as partial integer variables, that is, as variables that can only take integer values from their lower bounds up to specified thresholds and then take continuous values from the specified thresholds up to the variables' upper bounds.

    lp_solve does not support partial integers. An error will be generated by the parser if a partial integer section is found.

  12. Special ordered sets

    Special ordered sets are defined as part of the constraints section of the LP file. The definition of each special ordered set looks the same as a constraint except that the sense is always = and the right hand side is either S1 or S2 (case sensitive) depending on whether the set is to be of type 1 or 2, respectively. Special ordered sets of type 1 require that, of the non-negative variables in the set, one at most may be non-zero. Special ordered sets of type 2 require that at most two variables in the set may be non-zero, and if there are two non-zeros, they must be adjacent. Adjacency is defined by the weights, which must be unique within a set given to the variables. The weights are defined as the coefficients on the variables in the set constraint. The sorted weights define the order of the special ordered set. It is perhaps best practice to keep the special order sets definitions together in the LP file to indicate (for your benefit) the start of the special ordered sets definition with the comment line \Special Ordered Sets as is done when a problem is written to an LP file. The following example shows the definition of a type 1 and type 2 special ordered set.

    Sos101: 1.2 x1 + 1.3 x2 + 1.4 x4 = S1
    Sos201: 1.2 x5 + 1.3 x6 + 1.4 x7 = S2
    

Some examples

Example 1

Minimize
 COST:    XONE + 4 YTWO + 9 ZTHREE + 2
Subject To
 LIM1:    XONE + YTWO <= 5
 LIM2:    XONE + ZTHREE >= 10
 MYEQN:   - YTWO + ZTHREE  = 7
Bounds
 0 <= XONE <= 4
-1 <= YTWO <= 1
End

Example 2

Minimize
obj: - 2 x3

Subject To
c1: x2 - x1 <= 10
c2: x1 + x2 + x3 <= 20

Bounds
x1 <= 30
2 <= x3 <= 3

s.i.
x3
x1 >= 2.1

End

Example 3

Minimize
obj: - 2 x3

Subject To
c1: x2 - x1 <= 10

\SOS
sos101: 4 x2 + 2 x3 = S2

c2: x1 + x2 + x3 <= 20

sos102: x1 + x2 + x3 = S1
sos201: 1.2 x3 +1.3 x2 + 1.4 x1 = S2

Bounds
x1 <= 30
2 <= x3 <= 3

End
./Zimpl.htm000666 000000 000000 00000017133 11235534266 011206 0ustar00000000 000000 Zimpl

Zimpl

Zimpl is a language to translate the mathematical model of a problem into a linear or (mixed-) integer mathematical program expressed in .lp or .mps file format which can be read and (hopefully) solved by a LP or MIP solver.

See http://www.zib.de/koch/zimpl/ for the home page of this tool and examples.

On the above page, a command line tool is provided to read a model written in the Zimpl language and it creates a CPLEX lp file. lp_solve is able to read this generated CPLEX lp file via the xli_CPLEX XLI driver, but that would require an extra step.
lp_solve can read/write and solve these Zimpl models directly via the xli_Zimpl XLI driver (see External Language Interfaces). It reads such a model in above format and can solve it then.
Also note that the XLI driver depends on an external dll: zlib1.dll. When it cannot be found on the system, an appropriate message will be given. This dll must be in a directory specified by the Path environment variable. A common place is c:\windows\system32. The dll is distributed with the package. The latest version can be found at http://www.zlib.net/

For example:

lp_solve -rxli xli_Zimpl chvatal_diet.zpl

This gives as result:

Value of objective function: 97

Actual values of the variables:
x$Oatmeal                       4
x$Chicken                       0
x$Eggs                          0
x$Milk                          5
x$Pie                           2
x$Pork                          0

Options

The XLI accepts several options:

  -b             Enable Bison (Lex parser) debugging output.
  -D name=value  Sets the parameter name to the specified value.
                 This is equivalent with having this line in the ZIMPL program: param name:=val.
  -f             enable flex debugging output.
  -n cm|cn|cf    name column make/name/full
  -O             Try to reduce the generated LP by doing some presolve analysis.
  -s seed        Positive seed number for the random number generator.
  -v[0-5]        Set the verbosity level. 0 is quiet, 1 is default, 2 is verbose, 3 and 4 are chatter, and 5 is debug.
  -V             show version info

These options are the same as the stand-alone zimpl program.

The lp_solve command line program can provide these parameters via the -rxliopt argument.

For example:

lp_solve -rxli xli_Zimpl chvatal_diet.zpl -rxliopt "-v0 -O"

Generating ZIMPL models

The XLI can also create a ZIMPL model, however it doesn't use the strength of the language. Constraints are written out line per line. But it can be a starter. For example:

lp_solve model.lp -wxli xli_Zimpl model.zpl

This gives as model.zpl:

# Variable definitions
var x >= 0;
var y >= 0;

# Objective function
maximize obj: +143*x +60*y;

# Constraints
subto R1: +120*x +210*y <= 15000;
subto R2: +110*x +30*y <= 4000;
subto R3: +x +y <= 75;

API

Use the lpsolve API call read_XLI to read a model and write_XLI to write a model. See also External Language Interfaces.

IDE

Also from within the IDE, this XLI can be used. However, some entries must be added in LpSolveIDE.ini (in the folder where the IDE is installed).

In the [XLI] section the following must be added:

lib5=xli_ZIMPL

And a new section for the ZIMPL XLI must also be added:

[xli_ZIMPL]
extension=.zpl
language=ZIMPL

Then make sure that the xli_ZIMPL.dll is available for the IDE. This must be done by placing this dll in the IDE folder or in the Windows system32 folder.

Example models

chvatal_diet.zpl
# $Id: chvatal_diet.zpl,v 1.2 2003/10/02 08:20:12 bzfkocht Exp $
#
# From V. Chvatal: Linear Programming
# Chapter 1, Page 3ff.
#
# A diet problem
#
set Food      := { "Oatmeal", "Chicken", "Eggs", "Milk", "Pie", "Pork" };
set Nutrients := { "Energy", "Protein", "Calcium" };
set Attr      := Nutrients + {"Servings", "Price"};

param needed[Nutrients] := <"Energy"> 2000, <"Protein"> 55, <"Calcium"> 800;

param data[Food * Attr] :=
           | "Servings", "Energy", "Protein", "Calcium", "Price" |
|"Oatmeal" |         4 ,     110 ,        4 ,        2 ,      3  |
|"Chicken" |         3 ,     205 ,       32 ,       12 ,     24  |
|"Eggs"    |         2 ,     160 ,       13 ,       54 ,     13  |
|"Milk"    |         8 ,     160 ,        8 ,      284 ,      9  |
|"Pie"     |         2 ,     420 ,        4 ,       22 ,     20  |
|"Pork"    |         2 ,     260 ,       14 ,       80 ,     19  |;
#                          (kcal)        (g)        (mg)  (cents)

var x[<f> in Food] integer >= 0 <= data[f, "Servings"];

minimize cost: sum <f> in Food : data[f, "Price"] * x[f];

subto need :
  forall <n> in Nutrients do
    sum <f> in Food : data[f, n] * x[f] >= needed[n];
model.lp
/* model.lp */

max: 143 x + 60 y;

120 x + 210 y <= 15000;
110 x + 30 y <= 4000;
x + y <= 75;
./Win32/HTML Help/000777 000000 000000 00000000000 13751300670 011706 5ustar00000000 000000 ./SpecialOrderedSetsOfTypeTwo_files/bsscdhtm.js000666 000000 000000 00000214323 07755132440 020275 0ustar00000000 000000 //////////BSSCDHTML Section 1////////// // RoboHELP Dynamic HTML Effects Script // Copyright 1998-2000 eHelp Corporation. All rights reserved. // Version=3.72 // Warning: Do not modify this file. It is generated by RoboHELP and changes will be overwritten. //{{HH_SYMBOL_SECTION var HH_ChmFilename = ""; var HH_WindowName = ""; var HH_GlossaryFont = ""; var HH_Glossary = ""; var HH_Avenue = ""; var HH_ActiveX = false; //}}HH_SYMBOL_SECTION var gbNav4 = false; var gbIE4 = false; var gbIE = false; var gbIE5 = false; var gbIE55 = false; var gAgent = navigator.userAgent.toLowerCase(); var gbMac = (gAgent.indexOf("mac") != -1); var gbWindows = ((gAgent.indexOf("win") != -1) || (gAgent.indexOf("16bit") != -1)); var error_count = 0; gbIE = (navigator.appName.indexOf("Microsoft") != -1); if (parseInt(navigator.appVersion) >= 4) { gbNav4 = (navigator.appName == "Netscape"); gbIE4 = (navigator.appName.indexOf("Microsoft") != -1); if (gbIE4) { if (gAgent.indexOf("msie 5.0") != -1) { gbIE5 = true; } if (gAgent.indexOf("msie 5.5") != -1) { // curently IE 5.5 has some buggy stuff. we need do some remedy to our code. gbIE55 = true; } } } function HHActivateComponents() { if (HH_ActiveX && (HH_ChmFilename != "") && ((self == top) || (self == top.frames[0]))) { var objBody = document.all.tags("BODY")[0]; if( typeof(objBody) == "object" ) { objBody.insertAdjacentHTML("beforeEnd", ''); if (HHComponentActivator.object) { HHComponentActivator.Activate(HH_ChmFilename, HH_WindowName, HH_GlossaryFont, HH_Glossary, HH_Avenue); } } } } var gAmc = new Array(); var BSSCSequenceIndex = 0; function animationContext(el, progressAnimation, finishAnimiation, animationDuration, animationPeriod) { this.el = el; this.progressAnimation = progressAnimation; this.finishAnimiation = finishAnimiation; this.animationDuration = parseFloat(animationDuration); this.animationPeriod = animationPeriod; this.animationStartTime = (new Date()).getTime(); this.continueAnimation = true; } function progressFade(ndx) { if( typeof( gAmc[ndx].el.filters.alpha ) != "object" ) return; percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0){ percent = 1.0; gAmc[ndx].continueAnimation = false; } gAmc[ndx].el.filters.alpha.opacity = gAmc[ndx].initialOpacity*(1.0-percent) + gAmc[ndx].finalOpacity*percent; } function finishFade(ndx) { if( typeof( gAmc[ndx].el.filters.alpha ) == "object" ) gAmc[ndx].el.filters.alpha.opacity = parseInt(gAmc[ndx].finalOpacity); } function progressTranslation(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } gAmc[ndx].el.style.pixelLeft = gAmc[ndx].startX*(1.0-percent) + gAmc[ndx].finalX*percent; gAmc[ndx].el.style.pixelTop = gAmc[ndx].startY*(1.0-percent) + gAmc[ndx].finalY*percent; } function progressSpiral(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf = 1.0 - percent t = percent * 2.0*Math.PI rx = Math.max(Math.abs(gAmc[ndx].el.initLeft), 200) ry = Math.max(Math.abs(gAmc[ndx].el.initTop), 200) gAmc[ndx].el.style.pixelLeft = Math.ceil(-rf*Math.cos(t)*rx) gAmc[ndx].el.style.pixelTop = Math.ceil(-rf*Math.sin(t)*ry) gAmc[ndx].el.style.visibility="visible" } function progressElasticFromRight(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf=Math.exp(-percent*7) t = percent * 1.5*Math.PI rx =Math.abs(gAmc[ndx].el.initLeft) gAmc[ndx].el.style.pixelLeft = rf*Math.cos(t)*rx gAmc[ndx].el.style.pixelTop = 0 gAmc[ndx].el.style.visibility="visible" } function progressElasticFromBottom(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf=Math.exp(-percent*7) t = percent * 1.5*Math.PI rx =Math.abs(gAmc[ndx].el.initTop) gAmc[ndx].el.style.pixelLeft = 0 gAmc[ndx].el.style.pixelTop = rf*Math.cos(t)*rx gAmc[ndx].el.style.visibility="visible" } function progressZoomIn(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1; gAmc[ndx].continueAnimation = false; } for (var index=0; index= 1.0) { finishZoom(ndx); } } function progressZoomOut(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } for (var index=0; index= 1.0) { finishZoom(ndx); } } function finishTranslation(ndx) { gAmc[ndx].el.style.pixelLeft = parseInt(gAmc[ndx].finalX); gAmc[ndx].el.style.pixelTop = parseInt(gAmc[ndx].finalY); } function finishZoom(ndx) { for (i=0; i BSSCSequenceIndex && (!bFound || objectOrder < minBSSCSequenceIndexFound)) { minBSSCSequenceIndexFound = objectOrder; bFound = true; } } } if (bFound) { BSSCSequenceIndex = minBSSCSequenceIndexFound; bStarted = startAnimationSet(BSSCSequenceIndex); } } function getOffsetFromTopOfBrowser(el) { if (null == el.offsetParent) return el.offsetTop; else return el.offsetTop + getOffsetFromTopOfBrowser(el.offsetParent); } function startAnimationSet(ndx) { var m = 0; bStarted = false; // Find document elements with "BSSCAnimationType" attribute divElements = document.all.tags("DIV"); for (var index = 0; index < divElements.length; index++) { el = divElements[index]; animationType = el.getAttribute("BSSCAnimationType", false); if(null != animationType) { framePeriod = el.getAttribute("BSSCFramePeriod", false); frameCount = el.getAttribute("BSSCFrameCount", false); sequenceIndex = el.getAttribute("BSSCObjectOrder", false); // Stop any currently running RevealTrans filters if ("RevealTrans" == animationType && parseInt(sequenceIndex) == ndx-1 && gbWindows) el.filters.RevealTrans.stop(); // Filter on ndx if (0 == ndx && null == sequenceIndex || ndx == parseInt(sequenceIndex)) { if ("FlyInFromRight" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s gAmc[m] = new animationContext(el, progressTranslation, finishTranslation, animationDuration, 10); gAmc[m].startX = document.body.clientWidth + document.body.scrollLeft; gAmc[m].startY = 0; gAmc[m].finalX = 0; gAmc[m].finalY = 0; animationPump(m++); bStarted = true; } if ("FlyOutToRight" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s gAmc[m] = new animationContext(el, progressTranslation, finishTranslation, animationDuration, 10); gAmc[m].startX = 0; gAmc[m].startY = 0; gAmc[m].finalX = document.body.clientWidth + document.body.scrollWidth; gAmc[m].finalY = 0; animationPump(m++); bStarted = true; } if ("FlyInFromLeft" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s for (childIndex=0; childIndex 0) && (document.images[0].src.indexOf('bsscnav1.gif') != -1)) { document.links[0].href = "javascript:void(null);"; } } } return; } ////////////////////////////////////////////////////////////////////////////////////////////// // // Begin DHTML Popup Functions // ////////////////////////////////////////////////////////////////////////////////////////////// //variables used to isolate the browser type var gBsDoc = null; var gBsSty = null; var gBsHtm = null; var gBsStyVisShow = null; var gBsStyVisHide = null; var gBsClientWidth = 640; var gBsClientHeight = 480; var gBsBrowser = null; // here is the varible for judge popup windows size. these parameter is for IE5.0, it may need adjust for others. var gBRateH_W = 0.618; // 1.618 Golden cut. var gBMaxXOfParent = 0.8; var gBMaxYOfParent = 0.8; var gBscrollHeight = 16; var gBscrollWidth = 16; var gBpermitXDelta = 3; var gBpermitYDelta = 3; //the browser information itself function _BSPSBrowserItself() { var agent = navigator.userAgent.toLowerCase(); this.major = parseInt(navigator.appVersion); this.minor = parseFloat(navigator.appVersion); this.ns = ((agent.indexOf('mozilla') != -1) && ((agent.indexOf('spoofer') == -1) && (agent.indexOf('compatible') == -1))); this.ns2 = ((this.ns) && (this.major == 2)); this.ns3 = ((this.ns) && (this.major == 3)); this.ns4 = ((this.ns) && (this.major >= 4)); this.ie = (agent.indexOf("msie") != -1); this.ie3 = ((this.ie) && (this.major == 2)); this.ie4 = ((this.ie) && (this.major >= 4)); this.op3 = (agent.indexOf("opera") != -1); if (this.ns4) { gBsDoc = "document"; gBsSty = ""; gBsHtm = ".document"; gBsStyVisShow = "show"; gBsStyVisHide = "hide"; } else if (this.ie4) { gBsDoc = "document.all"; gBsSty = ".style"; gBsHtm = ""; gBsStyVisShow = "visible"; gBsStyVisHide = "hidden"; } } //Here is the browser type function _BSPSGetBrowserInfo() { gBsBrowser = new _BSPSBrowserItself(); } //Get client size info function _BSPSGetClientSize() { if (gBsBrowser.ns4) { gBsClientWidth = innerWidth; gBsClientHeight = innerHeight; } else if (gBsBrowser.ie4) { gBsClientWidth = document.body.clientWidth; gBsClientHeight = document.body.clientHeight; } } var gstrPopupID = 'BSSCPopup'; var gstrPopupShadowID = 'BSSCPopupShadow'; var gstrPopupTopicID = 'BSSCPopupTopic'; var gstrPopupIFrameID = 'BSSCPopupIFrame'; var gstrPopupIFrameName = 'BSSCPopupIFrameName'; var gstrPopupSecondWindowName = 'BSSCPopup'; var gPopupDiv = null; var gPopupDivStyle = null; var gPopupShadow = null; var gPopupTopic = null; var gPopupIFrame = null; var gPopupIFrameStyle = null; var gPopupWindow = null; var gnPopupClickX = 0; var gnPopupClickY = 0; var gnPopupScreenClickX = 0; var gnPopupScreenClickY = 0; var gbPopupTimeoutExpired = false; var gbScriptName = "EHELP_DHTM"; var gbPathofJS = ""; if (gbIE4) { var aScripts = document.scripts; var aScript = null; var i = 0; for (i = 0; i < aScripts.length ; i ++ ) { if (aScripts[i].name == gbScriptName) { aScript = aScripts[i]; break; } } if (aScript != null) { var nPathPos = 0; var strCurrentSrc = ""; strCurrentSrc = aScript.src; var nPathPos1 = strCurrentSrc.lastIndexOf("\\"); var nPathPos2 = strCurrentSrc.lastIndexOf("/"); if (nPathPos1 > nPathPos2) nPathPos = nPathPos1 + 1; else nPathPos = nPathPos2 + 1; gbPathofJS = strCurrentSrc.substring(0, nPathPos); } } // Replace point - Used by SingleSource // var gbBlankPageForIFrame = gbPathofJS + "_blank.htm"; var gbBlankPageForIFrame = "about:blank"; if (BSSCPopup_IsPopup()) { document.write(""); } function DHTMLPopupSupport() { if ((gbIE4) && (!gbMac)) { return true; } return false; } function BSSCPopup_IsPopup() { if (DHTMLPopupSupport() && (this.name == gstrPopupIFrameName)) { return true; } else if ((gbNav4 || gbIE4) && (this.name == gstrPopupID)) { return true; } else { return false; } } function _BSSCCreatePopupDiv() { if (gPopupDiv == null) { if (DHTMLPopupSupport()) { document.write(""); var tempColl = document.all.tags("DIV"); for (var iDiv = 0; iDiv < tempColl.length; iDiv++) { if (tempColl(iDiv).id == gstrPopupID) { gPopupDiv = tempColl(iDiv); } if (tempColl(iDiv).id == gstrPopupShadowID) { gPopupShadow = tempColl(iDiv); } if (tempColl(iDiv).id == gstrPopupTopicID) { gPopupTopic = tempColl(iDiv); } } gPopupIFrame = eval("gPopupDiv.document.frames['" + gstrPopupIFrameName + "']"); gPopupDivStyle = eval("gPopupDiv" + gBsSty); gPopupIFrameStyle = eval(gBsDoc + "['" + gstrPopupIFrameName + "']" + gBsSty); } } } function BSSCPopup_Timeout() { if ((gPopupIFrame.document.readyState == "complete") && (gPopupIFrame.document.body != null) && (gPopupIFrame.location.href.indexOf(gbBlankPageForIFrame) == -1)) { BSSCPopup_TimeoutReal(); } else { setTimeout("BSSCPopup_Timeout()", 100); } } function BSSCPopup_TimeoutReal() { window.gbPopupTimeoutExpired = true; if (gPopupIFrame.document) { BSSCPopup_ChangeTargettoParent(gPopupIFrame.document); gPopupIFrame.document.body.onclick = BSSCPopupClicked; } document.onmousedown = BSSCPopupParentClicked; } function BSSCPopup_ChangeTargettoParent(tagsObject) { var collA = tagsObject.all.tags("A"); var j = 0; if (collA != null) { for (j = 0; j < collA.length; j ++ ) { collA[j].target = "_parent"; } } } function BSPSPopupTopicWinHelp(strURL) { _BSSCPopup(strURL); return; } function _BSSCPopup(strURL) { if (DHTMLPopupSupport()) { // If we are already in a popup, replace the contents if (BSSCPopup_IsPopup()) { location.href = strURL; parent.window.gbPopupTimeoutExpired = false; if (gbMac) { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 400); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 100); } } else { // Load the requested URL into the IFRAME gPopupIFrame.location.href = strURL; window.gbPopupTimeoutExpired = false; if (gbMac) { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 400); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 100); } } } else { _BSSCPopup2(strURL); } return; } function _BSSCPopup2(strURL) { if (window.name == gstrPopupSecondWindowName) { window.location = strURL; } else { BSSCHidePopupWindow(); var nX = 0; var nY = 0; var nHeight = 300; var nWidth = 400; _BSPSGetClientSize(); if (gBsBrowser.ns4) { nX = window.screenX + (window.outerWidth - window.innerWidth) + window.gnPopupClickX; nY = window.screenY + (window.outerHeight - window.innerHeight) + window.gnPopupClickY; if (nY + nHeight + 40 > screen.availHeight) { nY = screen.availHeight - nHeight - 40; } if (nX + nWidth + 40 > screen.availWidth) { nX = screen.availWidth - nWidth - 40; } } else { nX = window.gnPopupScreenClickX; nY = window.gnPopupScreenClickY; } // Launch a separate window var strParam = "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes"; if (gBsBrowser.ns) { strParam += ",OuterHeight=" + nHeight + ",OuterWidth=" + nWidth; strParam += ",screenX=" + nX + ",screenY=" + nY; strParam += ",dependent=yes"; } else { strParam += ",height=" + nHeight + ",width=" + nWidth; strParam += ",left=" + nX + ",top=" + nY; } window.gPopupWindow = window.open(strURL, gstrPopupSecondWindowName, strParam); if (gBsBrowser.ns4) { window.gPopupWindow.captureEvents(Event.CLICK | Event.BLUE); window.gPopupWindow.onclick = NonIEPopup_HandleClick; window.gPopupWindow.onblur = NonIEPopup_HandleBlur; } else if (gBsBrowser.ie4) { window.gPopupWindow.focus(); } } return; } function NonIEPopup_HandleBlur(e) { window.gPopupWindow.focus(); } function NonIEPopup_HandleClick(e) { // Because navigator will give the event to the handler before the hyperlink, let's // first route the event to see if we are clicking on a Popup menu in a popup. document.routeEvent(e); // If a popup menu is active then don't do anything with the click if (window.gPopupWindow.gbInPopupMenu) { window.gPopupWindow.captureEvents(Event.CLICK); window.gPopupWindow.onclick = NonIEPopup_HandleClick; return false; } // Close the popup window if (e.target.href != null) { window.location.href = e.target.href; if (e.target.href.indexOf("BSSCPopup") == -1) { this.close(); } } else { this.close(); } return false; } function BSSCPopup_AfterLoad(strURL) { if (typeof(window.gPopupIFrame.document) == "unknown") { _BSSCPopup2(strURL); return; } if ((window.gPopupIFrame.document.readyState == "complete") && (window.gPopupIFrame.document.body != null) && (window.gPopupIFrame.location.href.indexOf(gbBlankPageForIFrame) == -1)) { BSSCPopup_ResizeAfterLoad(strURL); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 200); } } function BSSCPopup_ResizeAfterLoad(strURL) { window.gPopupDivStyle.visibility = gBsStyVisHide; // Determine the width and height for the window //var size = new BSSCSize(0, 0); //BSSCGetContentSize(window.gPopupIFrame, size); //var nWidth = size.x; //var nHeight = size.y; _BSPSGetClientSize(); var size = new BSSCSize(0, 0); BSSCGetContentSize(window.gPopupIFrame, size); // Determine the width and height for the window var nWidth = size.x; var nHeight = size.y; window.gPopupDivStyle.width = nWidth; window.gPopupDivStyle.height = nHeight; // Determine the position of the window var nClickX = window.gnPopupClickX; var nClickY = window.gnPopupClickY; var nTop = 0; var nLeft = 0; if (nClickY + nHeight + 20 < gBsClientHeight + document.body.scrollTop) { nTop = nClickY + 10; } else { nTop = (document.body.scrollTop + gBsClientHeight) - nHeight - 20; } if (nClickX + nWidth < gBsClientWidth + document.body.scrollLeft) { nLeft = nClickX; } else { nLeft = (document.body.scrollLeft + gBsClientWidth) - nWidth - 8; } if (nTop < document.body.scrollTop ) nTop = document.body.scrollTop + 1; if (nLeft< document.body.scrollLeft) nLeft = document.body.scrollLeft + 1; window.gPopupDivStyle.left = nLeft; window.gPopupDivStyle.top = nTop; // Set the location of the background blocks window.gPopupShadow.style.left = 6; window.gPopupShadow.style.top = 6; if (gbIE55) { window.gPopupShadow.style.left = 4; window.gPopupShadow.style.top = 4; } window.gPopupShadow.style.width = nWidth; window.gPopupShadow.style.height = nHeight; window.gPopupTopic.style.width = nWidth; window.gPopupTopic.style.height = nHeight; if (gbIE55) { window.gPopupShadow.style.width = nWidth + 2; window.gPopupShadow.style.height = nHeight + 2; window.gPopupTopic.style.width = nWidth + 2; window.gPopupTopic.style.height = nHeight + 2; } if (gbMac) { // Total hack on the iMac to get the IFrame to position properly window.gPopupIFrameStyle.pixelLeft = 100; window.gPopupIFrameStyle.pixelLeft = 0; // Explicitly call BSSCOnLoad because the Mac doesn't seem to do it window.gPopupIFrame.window.BSSCOnLoad(); } //var nOriWidth = window.gPopupIFrameStyle.width window.gPopupIFrameStyle.width = nWidth; window.gPopupIFrameStyle.height = nHeight; if (gbIE55) { window.gPopupIFrameStyle.top = 0; window.gPopupIFrameStyle.left = 0; } gPopupIFrame.location.href = strURL; // reload again, this will fix the bookmark misunderstand in IE5. window.gPopupDivStyle.visibility = gBsStyVisShow; setTimeout("BSSCPopup_Timeout();", 100); return false; } function BSSCSize(x, y) { this.x = x; this.y = y; } function BSSCGetContentSize(thisWindow, size) { if (!((gBsBrowser.ie4) || (gBsBrowser.ns4))) return; if (gbMac) { size.x = 300; size.y = 300; return; } // Resize the width until it is wide enough to handle the content // The trick is to start wide and determine when the scrollHeight changes // because then we know a scrollbar is necessary. We can then go back // to the next widest size (for no scrollbar) var ClientRate = gBsClientHeight / gBsClientWidth; var GoldenSize = new BSSCSize(0,0); GoldenSize.x = gBsClientWidth * gBMaxXOfParent; GoldenSize.y = gBsClientHeight *gBMaxYOfParent ; if (ClientRate > gBRateH_W) { GoldenSize.y = GoldenSize.x * gBRateH_W; } else { GoldenSize.x = GoldenSize.y / gBRateH_W; } // Try to using parent specified max x. var x = 0; var maxgoldx = GoldenSize.x; var maxx = gBsClientWidth * gBMaxXOfParent; // This double resize causes the document to re-render (and we need it to) thisWindow.moveTo(10000,10000); // this is used to fix the flash on IE4. thisWindow.resizeTo(1, 1); thisWindow.resizeTo(1, 1); thisWindow.resizeTo(maxgoldx, thisWindow.document.body.scrollHeight + gBscrollHeight); thisWindow.resizeTo(maxgoldx, thisWindow.document.body.scrollHeight + gBscrollHeight); var miny = thisWindow.document.body.scrollHeight + gBscrollHeight; if (miny > GoldenSize.y) // the popup does not fix in the parent wanted golden area. so try to expand itself as large as it can { thisWindow.resizeTo(maxx , thisWindow.document.body.scrollHeight + gBscrollHeight); thisWindow.resizeTo(maxx , thisWindow.document.body.scrollHeight + gBscrollHeight); miny = thisWindow.document.body.scrollHeight + gBscrollHeight; maxy = gBsClientHeight * gBMaxYOfParent; if (miny > maxy) { // the popup must have a scroll, OK let it be. miny = maxy; size.x = maxx; size.y = maxy; } else { // popup still can fit in the parent area by someway. now we choose the same h/w rate as parent. size.y = miny; // downsize from maxx , now I try to using binary divide. x = maxx; deltax = -maxx/2; //j = 0; while (true) { x = x + deltax; thisWindow.resizeTo(x, miny); thisWindow.resizeTo(x, miny); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * ClientRate; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -gBpermitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //j ++; } size.x = thisWindow.document.body.scrollWidth; //+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight;// + gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. // Handle absurd cases just in case IE flakes // if (size.y < 100) { // size.y = 100; // } } } else { // downsize from maxgoldx , now I try to using binary divide. x = maxgoldx; deltax = -maxgoldx/2; //i = 0; while (true) { x = x + deltax; thisWindow.resizeTo(x, miny); thisWindow.resizeTo(x, miny); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * gBRateH_W; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -gBpermitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //i ++; } size.x = thisWindow.document.body.scrollWidth ;//+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight ;//+ gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. } if ((gbIE4) && (!gbIE5)) { size.x = size.x + 16; //reserve a width for scrollbar (IE 4.0 only) } thisWindow.resizeTo(size.x, size.y); thisWindow.resizeTo(size.x, size.y); return; } function BSSCPopupParentClicked() { BSSCPopupClicked(); return; } function BSSCPopupClicked() { if (!window.gbPopupTimeoutExpired) { return false; } if (gPopupIFrame.window.gbInPopupMenu) { return false; } // Give the user a message about javascript calls through objects. if ((gPopupIFrame.window.event != null) && (gPopupIFrame.window.event.srcElement != null) && (gPopupIFrame.window.event.srcElement.tagName == "A") && (gPopupIFrame.window.event.srcElement.href.indexOf("javascript:") == 0) && (gPopupIFrame.window.event.srcElement.href.indexOf(".") != -1)) { gPopupIFrame.window.event.cancelBubble = true; alert('Hyperlinks to objects do not work in popups.'); return false; } if (gPopupIFrame.document) { gPopupIFrame.document.body.onclick = null; } document.onclick = null; document.onmousedown = null; // Simply hide the popup gPopupDivStyle.visibility = gBsStyVisHide; gPopupIFrame.location.href = gbBlankPageForIFrame; return true; } //trace the mouse over's position for hotspot function BSPSPopupOnMouseOver(event) { if (gBsBrowser.ie4) { window.gnPopupClickX = event.clientX + document.body.scrollLeft; window.gnPopupClickY = event.clientY + document.body.scrollTop; window.gnPopupScreenClickX = event.screenX; window.gnPopupScreenClickY = event.screenY; } else if (gBsBrowser.ns4) { window.gnPopupClickX = event.pageX; window.gnPopupClickY = event.pageY; } } function BSSCHidePopupWindow() { if (window.gPopupWindow != null) { if (gBsBrowser.ns4) { if ((typeof window.gPopupWindow != "undefined") && (!window.gPopupWindow.closed)) { window.gPopupWindow.close(); window.gPopupWindow = null; } } } return; } var gbPopupMenuTimeoutExpired = false; var gbInPopupMenu = false; var gbPopupMenuTopicList = null; ////////////////////////////////////////////////////////////////////////////////////////// // // Popup Menu code // ////////////////////////////////////////////////////////////////////////////////////////// function _WritePopupMenuLayer() { if (gbNav4) { //Do not try to write ininle styles for NS! NS can not handle it and will not stop downloading the html page... document.write("
"); } else { document.write(""); if (gbIE4) { document.write(""); } } } //Define variable arguments as: strTitle, strUrl function PopupMenuTopicEntry() { this.strTitle = PopupMenuTopicEntry.arguments[0]; this.strURL = PopupMenuTopicEntry.arguments[1]; } // If the topic list is set, it is an array of TopicEntry objects (defined in WebHelp3.js) function PopupMenu_SetTopicList(aPopupTopicArray) { gbPopupMenuTopicList = aPopupTopicArray; } //Seek for the bsscright frame function _SeekFrameByName( cRoot, strName ) { if( cRoot == null ) return null; if( cRoot.frames == null ) return null; if( cRoot.frames[strName] != null ) return cRoot.frames[strName]; for (var i=0; i"); wndPopupLinks.document.write(""); var strParaLine = ""; for (var i = 0; i < (argLen - 2) / 2; i++) { strParaLine = ""; strParaLine += ""); wndPopupLinks.document.close(); window.gbInPopupMenu = true; if (!gbIE) { wndPopupLinks.focus(); } return false; } // Make sure we have reasonable arguments var argLen = fn_arguments.length; if (argLen < 3) { return false; } // Check to see if we only have one target var strTarget = ""; if (((argLen < 5) && ((isNaN(fn_arguments[2])) || (gbPopupMenuTopicList == null))) || ((argLen < 4) && ((!isNaN(fn_arguments[2])) && (gbPopupMenuTopicList != null)))) { // Get the place that we will be putting the topic into var targetDoc = null; if (fn_arguments[1] == '') { targetDoc = window.document; } else { targetDoc = _GetFrameByName( parent, fn_arguments[1] ); if (targetDoc == null) { targetDoc = window.document; } //if (gbIE4) { // targetDoc = eval("top.document.frames['" + fn_arguments[1] + "']"); // } else if (gbNav4) { // targetDoc = eval("window.top." + fn_arguments[1] + ".document"); //} strTarget = "TARGET='" + fn_arguments[1] + "'"; } if (isNaN(fn_arguments[2]) || (gbPopupMenuTopicList == null)) { targetDoc.location.href = fn_arguments[3]; } else { targetDoc.location.href = gbPopupMenuTopicList[fn_arguments[2]].strURL; } return false; } var strMenu = ""; if (gbNav4) { strMenu = ''; } else { strMenu = '
'; } else { strMenu += '' + gbPopupMenuTopicList[fn_arguments[i]].strTitle + ''; } strMenu += ''; if (isNaN(fn_arguments[i]) || (gbPopupMenuTopicList == null)) { i += 2; } else { i += 1; } } strMenu += "
"; if (gbMac) { // totally hack. because ie5 in mac need something. is one of them. mac is mad. strMenu +="
"; } var layerPopup = null; var stylePopup = null; var nEventX = 0; var nEventY = 0; var nWindowWidth = 0; if (gbIE4) { layerPopup = document.all["PopupMenu"]; layerPopup.innerHTML = strMenu; stylePopup = layerPopup.style; _BSPSGetClientSize(); // Get the position of the item causing the event (relative to its parent) //if (gbMac) { if (true) { nEventX = window.event.clientX; nEventY = window.event.clientY; } else { //??? YJ: Can not remember why we calculate envent position by following code... //but it is wrong in a case like: CENTER->P->TABLE: //the offset positions of TABLE, P and CENTER are same (same offsetTop,offsetLeft) //so we get triple times of offset of x and y as we expect... nEventX = window.event.srcElement.offsetLeft - document.body.scrollLeft; nEventY = window.event.srcElement.offsetTop - document.body.scrollTop; // Get the location of the parent var nParentLocX = 0; var nParentLocY = 0; var ParentItem = window.event.srcElement.offsetParent; while (ParentItem != null) { if (ParentItem.offsetLeft) { nParentLocX += ParentItem.offsetLeft; nParentLocY += ParentItem.offsetTop; } ParentItem = ParentItem.parentElement; } // Adjust the location of the item using the location of the parent(s) nEventX += nParentLocX; nEventY += nParentLocY; } if (nEventY + layerPopup.scrollHeight + 10 < gBsClientHeight) { nEventY += document.body.scrollTop + 10; } else { nEventY = (document.body.scrollTop + gBsClientHeight) - layerPopup.scrollHeight - 20; } stylePopup.top = nEventY; if (nEventX + layerPopup.scrollWidth + 20 > gBsClientWidth) { if (gBsClientWidth - layerPopup.scrollWidth < 5) { stylePopup.left = 5; } else { stylePopup.left = gBsClientWidth - layerPopup.scrollWidth - 5; } } else { stylePopup.left = nEventX + document.body.scrollLeft + 20; } stylePopup.visibility = "visible"; document.onclick = PopupMenu_HandleClick; } else if (gbNav4) { layerPopup = document.layers.PopupMenu; layerPopup.visibility = "hide"; stylePopup = layerPopup.document; stylePopup.write(strMenu); stylePopup.close(); var e = fn_arguments[0]; nEventX = e.pageX; nEventY = e.pageY; _BSPSGetClientSize(); if (nEventY + layerPopup.clip.height + 20 < window.pageYOffset + gBsClientHeight) { nEventY += 20; } else { nEventY = gBsClientHeight + window.pageYOffset- layerPopup.clip.height - 20; } layerPopup.top = nEventY; if (nEventX + layerPopup.clip.width + 20 > gBsClientWidth + window.pageXOffset) { if (gBsClientWidth + window.pageXOffset - layerPopup.clip.width < 20) { nEventX = 5; } else { nEventX = gBsClientWidth + window.pageXOffset - layerPopup.clip.width - 20; } } else { nEventX += 20; } layerPopup.left = nEventX; layerPopup.visibility = "show"; // window.captureEvents(Event.CLICK | Event.MOUSEDOWN); window.captureEvents(Event.MOUSEDOWN); // window.onclick = PopupMenu_HandleClick; window.onmousedown = PopupMenu_HandleClick; } window.gbInPopupMenu = true; window.gbPopupMenuTimeoutExpired = false; setTimeout("PopupMenu_Timeout();", 100); return false; } function PopupMenu_Timeout() { window.gbPopupMenuTimeoutExpired = true; } function PopupMenu_Over(e) { if (gbIE4) { e.srcElement.className = "PopupOver"; } else if (gbNav4) { // this.bgColor = "red"; // e.target.document.className = "PopupOver"; } return; } function PopupMenu_Out(e) { if (gbIE4) { e.srcElement.className = "PopupNotOver"; } else if (gbNav4) { this.bgColor = "#f0f0f0"; } return; } function PopupMenu_HandleClick(e) { if (!window.gbPopupMenuTimeoutExpired) { return; } window.gbInPopupMenu = false; if (gbNav4) { // window.releaseEvents(Event.CLICK); window.releaseEvents(Event.MOUSEDOWN); } var layerPopup = null; var stylePopup = null; if (gbIE4) { layerPopup = document.all["PopupMenu"]; stylePopup = layerPopup.style; stylePopup.visibility = "hidden"; } else if (gbNav4) { layerPopup = document.layers.PopupMenu; layerPopup.visibility = "hide"; } return; } // This function should be deleted when all old projects are cleaned up function BSPSWritePopupFrameForIE4() { return false; } ///////////////////////////////////////////////////////////////////// function BSSCPopup_ClickMac() { if ((!DHTMLPopupSupport()) && (gbIE4)) { var bClickOnAnchor = false; var el; if ((window.event != null) && (window.event.srcElement != null)) { el = window.event.srcElement; while (el != null) { if ((el.tagName == "A") || (el.tagName == "AREA")) { bClickOnAnchor = true; break; } if (el.tagName == "BODY") { break; } el = el.parentElement; } } if (BSSCPopup_IsPopup()) { if (!bClickOnAnchor) { parent.window.gPopupWindow = null; self.close(); } } else { bClosePopupWindow = true; if ((bClickOnAnchor) && (el.href) && (el.href.indexOf("javascript:BSSCPopup") != -1)) { bClosePopupWindow = false; } if (bClosePopupWindow) { if (window.gPopupWindow != null) { var strParam = "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=300,width=400"; window.gPopupWindow = window.open("", gstrPopupSecondWindowName,strParam); window.gPopupWindow.close(); window.gPopupWindow = null; } } } } } ////////////////////////////////////////////////////////////////////// _BSPSGetBrowserInfo(); function _BSSCOnLoad() { if (!gbIE4 && !gbNav4) return; // Make everything visible in navigator if (gbNav4) { // Make some special effects items visible for (var iLayer = 0; iLayer < document.layers.length; iLayer++) { document.layers[iLayer].visibility = gBsStyVisShow; document.layers[iLayer].left = 0; } } // Remove the NavBar if necessary RemoveNavBar(); // Don't continue without IE4 if (gbIE4) { HHActivateComponents(); doStaticEffects(); startAnimationSet(0); } } function _BSSCOnUnload() { } function _BSSCOnClick() { if (!gbIE4) return; BSSCPopup_ClickMac(); startNextAnimationSet(); } function _BSSCOnError(message) { if(-1 != message.indexOf("denied") || -1 != message.indexOf("Object required")) return true; } function ResizeBasedonRate(thisWindow, size, rate, maxx, maxy) { x = maxx; y = maxy; deltax = -maxx/2; while (true) { x = x + deltax; thisWindow.resizeTo(x, y); thisWindow.resizeTo(x, y); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * rate; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -permitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //j ++; } size.x = thisWindow.document.body.scrollWidth; //+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight;// + gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. } //////////BSSCDHTML Section Embedded Code////////// var s_strAgent = navigator.userAgent.toLowerCase(); var s_nVer = parseInt(navigator.appVersion); var s_bIE = (s_strAgent.indexOf('msie') != -1); var s_bNS = (s_strAgent.indexOf('mozilla') != -1) && ((s_strAgent.indexOf('spoofer') == -1) && (s_strAgent.indexOf('compatible') == -1)); var s_bOpera = (s_strAgent.indexOf('opera') != -1); var s_bIE3Before = ((s_bIE) && (s_nVer <= 2)); var s_bNS3Before = ((s_bNS) && (s_nVer <= 3)); var s_bNS2 = ((s_bNS) && (s_nVer <= 2)); var s_bNS3 = ((s_bNS) && (s_nVer == 3)); var s_bIE300301 = ((s_bIE) && (s_nVer == 2) && ((s_strAgent.indexOf("3.00") != -1)||(s_strAgent.indexOf("3.0a") != -1)||(s_strAgent.indexOf("3.0b")!=-1)||(s_strAgent.indexOf("3.01")!=-1))); var s_bIE302 = ((s_bIE) && (s_nVer == 2) && (s_strAgent.indexOf("3.02") != -1)); function HasExtJs() { if (s_bIE3Before) { return false;} if (s_bNS3Before) { return false;} if (typeof (_BSSCOnLoad) == "undefined"){ return false; } return true; } function BSSCOnLoad() { if (HasExtJs()) { _BSSCOnLoad(); } } function BSSCOnUnload() { if (HasExtJs()) { _BSSCOnUnload(); } } function BSSCOnClick() { if (HasExtJs()) { _BSSCOnClick(); } } function BSSCOnError(message) { if (HasExtJs()) { return _BSSCOnError(message); } } function WritePopupMenuLayer() { if (HasExtJs()) {_WritePopupMenuLayer();} } function BSSCCreatePopupDiv() { if (HasExtJs()) {_BSSCCreatePopupDiv(); } } function BSSCPopup(strURL) { if (HasExtJs()) { _BSSCPopup(strURL); }else{ //Create a temporary window first to ensure the real popup comes up on top var wndTemp = null; if (!s_bNS3) { wndTemp = window.open("", "temp", "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=3,width=4"); } // Create the real popup window var wndPopup = window.open(strURL, "BSSCPopup", "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=300,width=400"); // Close the temporary if (!s_bNS3) { wndTemp.close(); } else { wndPopup.focus(); } } } var gbWndTemp = null, gbWndPopupLinks = null; var gbstrParaTotal = ""; function PopupMenu_Invoke() { if (HasExtJs()) { return _PopupMenu_Invoke(PopupMenu_Invoke.arguments); } if (s_bNS3Before || s_bIE3Before ) { var argLen = PopupMenu_Invoke.arguments.length; if (argLen < 5) { window.document.location.href = PopupMenu_Invoke.arguments[3]; return false; } gbWndTemp = null; gbWndPopupLinks = null; gbstrParatotal = ""; for (var i = 0; i < (argLen - 2) / 2; i++) { var strParaLine = ""; if (s_bNS2 || s_bOpera){ strParaLine += "
" strParaLine += PopupMenu_Invoke.arguments[2 * i + 2]; strParaLine += ""; } else { strParaLine += ""); if (s_bNS2 || s_bOpera) { gbWndPopupLinks.document.write(""); } else { //YJ: IE301,302 and NS3.x works fine gbWndPopupLinks.document.write("<"); gbWndPopupLinks.document.write("script>"); gbWndPopupLinks.document.write("function gotoUrl(aUrl) {opener.window.location=aUrl; close();}"); gbWndPopupLinks.document.write("<"); gbWndPopupLinks.document.write("/script>"); } gbWndPopupLinks.document.write(""); gbWndPopupLinks.document.write(gbstrParaTotal); gbWndPopupLinks.document.write(""); gbWndPopupLinks.document.close(); // Close the temporary if (!s_bNS3 && gbWndTemp != null) { gbWndTemp.close(); }else { gbWndPopupLinks.focus(); } return true; } return false; } onload = BSSCOnLoad; document.onclick = BSSCOnClick; onunload = BSSCOnUnload; onerror = BSSCOnError;./SpecialOrderedSetsOfTypeTwo_files/img00348.gif000666 000000 000000 00000001632 07755133320 017765 0ustar00000000 000000 GIF89a%!,%wH*\ȰÇH,@aŇ/ ԘB<rdG98qIGlҢA,)Ir͝0V fOBDӧ=*jHAԚ$͏/!Kك;./SpecialOrderedSetsOfTypeTwo_files/img00349.gif000666 000000 000000 00000002120 07755133320 017757 0ustar00000000 000000 GIF89a!,H*\ȰÇ#JHŋ3jȱǏ CII'!hKarl)̇7 r'ž%%Tr& i$iB8?, T5f*4E9WR*slCGy*V%ϘVQ=;ۡ6mhnA^-\NMq۩Aq%EKBuiػ5:m\7jֶvsḘٺ.ԓ zRn::vsۥ>FG5Yk.cjkr΀9ˎ^xǷ,XϿ(hG;./SpecialOrderedSetsOfTypeTwo_files/img00350.gif000666 000000 000000 00000002116 07755133320 017754 0ustar00000000 000000 GIF89a!,H*\ȰÇ#JHŋ3jȱǏ C OD9PA`BtyQfƓ(qڌ2'Ia 4hʚ49 EHRO#61gөPMlG LP'זcFuXюmʤJcmנNvֵ ]Ef)ƁX|ɾXXִ1M,cq}lt5^Ѯa'E ;v=l:rk+89ڡ}&^Z'Wݚvޝ_,$VWN|g{GW>Ͽ(_@;./SpecialOrderedSetsOfTypeTwo_files/img00351.gif000666 000000 000000 00000011022 07755133320 017751 0ustar00000000 000000 GIF89a$a!,$aH*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ NȱX<FNt׫k={^:x{Gݮ_>ߪUt~AXu6 g|MHliAz7g9, '">XP7ҨN6ߎգ?V"DYCxPFcPK>b9Fx.B9`jy5"Ydf)idh¹h*H%thb*湡3'(JfJ"ђx**dEWy([JjgsuUi)תjea! #]zdOZQ ʟ>,CJl-,{2 ٱ%\6C^EiQkKضuK޲k&.KpD˯HG0w&0I?U1< Xo*HpI3U%&J2R3ӷ{W.;#n1Ypر-z#.<~|UKs[p5{?a}_'{5wϦ"=K2SNZHwO4lḔ1'@Dc$<΂-qG2։n ^H>*Uq+`hȩ ^ w9-\Np#:&VbȤpK#t^XxqgaVDXˁV;u0{|&=1rk4@PٴFCStx ˑ|ĈkI"Sd@I% Гnd">2t;Y)JFrSާ_x)=i$"y˅QH i)0`2)cJ# ̚"D>Db +?陵8yV"g,n(IX2ԉxtBI@Sr!jIφ(: *E$ HRFԣJզ>Ҏ&)f*Җ(;C*^y@fRMjbN% *65YRA&T|YFmVիr*"V|RuC'MEVhm!ZǶԔxkGZU:uQ] u<`qJĘ+% YcӟUjg&ٯR -W5KHβ6'TZZNUgllGx5-Qm&6Ǖ(f59JkJEݖ(6}nʪE[;RĮmwZ񚗚٥n~+_BNY|_؆W}?z[Wv05Y#8n xD/l]X*F,pƤNu_qd8Ja#M}#K8X2,[l-9jż`:Oa6n5'Y$<zys ]e>Gxϊ%f'yv>#}eL;%Ov. K/:q4AljI^qW425OkY'nr)jkmgYif{9S&oZڜOY(=evHkݹj|9. v<6kB<(ZtS,$h#x4&}/wxMJnqS~e pKr2Fi΅7ژ+=.Q8qosbvĹKsԹ3T<6#YLS?][$/iߙ d~qmHƳ{>XHQslgvwʋ_W.mQ]etOݝ:ҫmVl[q;Ey(u]Xg=雾~_X]~s]")8z{ 7otW?tVEρy?oQufsT}WwrW{ysXbO8{=q&}wt}&V~q!tw8-xYTu~|,H{c)ۇ5xw9+'wkVLs×}FԂvM8}pQCjiC!4!_ƷFHkMȆ}g_jYVTlFm~HoxkhFz6pjvV)gwi[dC熉<nH{戾hȇȉcy(Q_(jȈhnmHfhŸH5JXdXB8Hx5ŎƨZ%؋8eh7Xxy~U yHiy yxz6Ɋih+IXq݈%& $YXȓ=B;I'ْؑGqWYgJ9UYy3I,y 3GIicɔ&ŕ.ɖ)fKy &H0؁qYCwi:9h9xِٔx|)`Jَni~k畞ٙ)9Ysg٘iɚ Y)ewH_I鏼 i("ɘǹIlYM\ٚA9IVYiG89䉞ʩOٝY} )8  ٠Zz#ir(i )Yiɟ0y 6ʣ &آ9MJYԙNJZH:D]9ɤ阝ڜQazߨ`2,Zo{FP:^jmO}ZꝈ:y\t_Zڥ(joY@(ʦIz7=J~EJE詿iڨ"Hm Aj9z:Jκ'ӺZګJJjtX)Uڭ+t5Pi 5]A;[{ / ;;C8=uV۱ :+G3uSwʹ@,O?-/ '6{8+*wWQ=]g ;2A&wRXKK`IOO=5 X8 WS[3MZ@V<_+N3 6j{I)73o+)d~#KmkMe;s:)2Ҫ)*Q1t}1(TD'B[c4 g2r/e(7+WjHKD9[{ۻ;[{țʻۼ;B;./SpecialOrderedSetsOfTypeTwo_files/img00352.gif000666 000000 000000 00000001524 07755133320 017760 0ustar00000000 000000 GIF89a!,1H*,! tqB+fŽ d8rɓ(;./SpecialOrderedSetsOfTypeTwo_files/img00353.gif000666 000000 000000 00000001726 07755133320 017765 0ustar00000000 000000 GIF89a>!,>H*\ȰÇ#JA1J`Nj>R 9qH'M(2%K%c:LRF6]΄iM>H%$yTNN;:](UҞLGNmx#ͭ&Y:&$ u)Lgl[iܰuzweؠY%5(G EZgT} (Z23k9@@;./SpecialOrderedSetsOfTypeTwo_files/img00354.gif000666 000000 000000 00000002061 07755133320 017757 0ustar00000000 000000 GIF89a~!,~H*\ȰÇ#JHŋ3jȱ"3~ I H%)Le,B6'3bϏ8y Ϟ2Z܉KLMM%,QT)ϋXю}zkY7ϪJV&;wۯc-*x*[MiYR2&lǃu* kX1Ya- ytі/E+Ƭ5uf8O=L:dƉ2lޥs?IwǨ@5.4ylၫqeZo1Kz]9ӫ_^`@;./SpecialOrderedSetsOfTypeTwo_files/img00355.gif000666 000000 000000 00000002176 07755133320 017767 0ustar00000000 000000 GIF89a!,H*\ȰÇ#JHŋ3jȱǏ CI (S,x2#+\rf̑57ڼIs'ˁ>-9TbQ_"S : Uԩ'>֨^ iS*ՈEl *ֶncٟIM(bͿf z}j0ܮbT|wC딩x |XQ*<s.fFVb9K4kz굍Wٞώ:xmxy^ͦn.dX!~u52wu\/=ٹ˼1Gvc{>}뫁Mqk7t '_ARtfa~Qh($;./SpecialOrderedSetsOfTypeTwo_files/img00356.gif000666 000000 000000 00000001632 07755133320 017764 0ustar00000000 000000 GIF89a%!,%wH*\ȰÇH,@aŇ/ ԘB<rdG98qIGlҢA,)Ir͝0V fOBDӧ=*jHAԚ$͏/!Kك;./SpecialOrderedSetsOfTypeTwo_files/img00357.gif000666 000000 000000 00000002317 07755133320 017766 0ustar00000000 000000 GIF89a!,H*\ȰÇ#JHŋ3jȱG|0$ɏ!ETŔ]tɁ0WH4})0N o `iыB=TJVECIR,Ӄf_LT&KZ%]Yo6;wgݢi[28l\uZ;8᳅>ױڧ'70[A;=XtYͦI^ly@鲮ngs9L1=ZgZѽɾ.6o;5G˖y։cG}˓Y{l}=y_~w^MrwysIݧ)H]&! ~7zؒ$b.1'܇ {+faQ5}auhR8~\Jg#VHeYecD[f`\9a^ihlV;./SpecialOrderedSetsOfTypeTwo_files/img00358.gif000666 000000 000000 00000001632 07755133320 017766 0ustar00000000 000000 GIF89a%!,%wH*\ȰÇH,@aŇ/ ԘB<rdG98qIGlҢA,)Ir͝0V fOBDӧ=*jHAԚ$͏/!Kك;./SpecialOrderedSetsOfTypeTwo_files/img00359.gif000666 000000 000000 00000001736 07755133320 017774 0ustar00000000 000000 GIF89ad!,dH*\ȰÇ#JHŋ3jQ#Av QdI#I^,R@-aV$͎7'\)p'ˏAR(CsWago:S_2yot|c~R|vf xȞy%A7`A4]WWV*(g Hہ"&݇(VHߋi^|"NA"*%c rᙶ:귕N{MfkX~)Fady&fr؜PH`^ ؞EՕYgTtٖoߟ:Y-(&|oXm6i-#np56ᠢ:m؉jH!7i_)ykp;+k;./SpecialOrderedSetsOfTypeTwo_files/img00361.gif000666 000000 000000 00000002351 07755133320 017757 0ustar00000000 000000 GIF89a!,H*\ȰÇ#JHŋ3jȱǏ '2Ȓ(!Lɲ%F$])@6s,s˞=w*4ȕ*<ӧP"m)©?uRMVy :j٭bU 4ɚ[ךl6\i%ekPߘn;W``>DVW/~+#WկW'^R"MdzT3Ԝ;yhLGۖmO-pv]'Ӭr=SƬ7Bgz+n9cߙE__r|Σޗ`{6a EgU-e8yךa1~y )ȚvHbU}~ŷcq,(_B޸֥lȣܩw$F:yaC/q-^?Fx~hlei$ jws|矀S@;./SpecialOrderedSetsOfTypeTwo_files/img00362.gif000666 000000 000000 00000002324 07755133320 017760 0ustar00000000 000000 GIF89a !, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ%I\ʜISc̐7gEwݸ3hњHqTaΡN/%jƪR+HW;Nc=4Tb5{\۾]v-՞nmTZcҥpWi&cQrK8!'W*8(ˁ1mh.i?~f칶+6ǐ#6Zpq̚CT6h V]i#-y\~Wxɦ;ܰaZd2^~EZcI~I[X֟ICvW^jEW xuxe9[QMWRq^6‡~Q.8id>HcO@'\N'sJD\J%dm_&c?hlp^;./SpecialOrderedSetsOfTypeOne_files/bsscdhtm.js000666 000000 000000 00000214323 07755132440 020245 0ustar00000000 000000 //////////BSSCDHTML Section 1////////// // RoboHELP Dynamic HTML Effects Script // Copyright 1998-2000 eHelp Corporation. All rights reserved. // Version=3.72 // Warning: Do not modify this file. It is generated by RoboHELP and changes will be overwritten. //{{HH_SYMBOL_SECTION var HH_ChmFilename = ""; var HH_WindowName = ""; var HH_GlossaryFont = ""; var HH_Glossary = ""; var HH_Avenue = ""; var HH_ActiveX = false; //}}HH_SYMBOL_SECTION var gbNav4 = false; var gbIE4 = false; var gbIE = false; var gbIE5 = false; var gbIE55 = false; var gAgent = navigator.userAgent.toLowerCase(); var gbMac = (gAgent.indexOf("mac") != -1); var gbWindows = ((gAgent.indexOf("win") != -1) || (gAgent.indexOf("16bit") != -1)); var error_count = 0; gbIE = (navigator.appName.indexOf("Microsoft") != -1); if (parseInt(navigator.appVersion) >= 4) { gbNav4 = (navigator.appName == "Netscape"); gbIE4 = (navigator.appName.indexOf("Microsoft") != -1); if (gbIE4) { if (gAgent.indexOf("msie 5.0") != -1) { gbIE5 = true; } if (gAgent.indexOf("msie 5.5") != -1) { // curently IE 5.5 has some buggy stuff. we need do some remedy to our code. gbIE55 = true; } } } function HHActivateComponents() { if (HH_ActiveX && (HH_ChmFilename != "") && ((self == top) || (self == top.frames[0]))) { var objBody = document.all.tags("BODY")[0]; if( typeof(objBody) == "object" ) { objBody.insertAdjacentHTML("beforeEnd", ''); if (HHComponentActivator.object) { HHComponentActivator.Activate(HH_ChmFilename, HH_WindowName, HH_GlossaryFont, HH_Glossary, HH_Avenue); } } } } var gAmc = new Array(); var BSSCSequenceIndex = 0; function animationContext(el, progressAnimation, finishAnimiation, animationDuration, animationPeriod) { this.el = el; this.progressAnimation = progressAnimation; this.finishAnimiation = finishAnimiation; this.animationDuration = parseFloat(animationDuration); this.animationPeriod = animationPeriod; this.animationStartTime = (new Date()).getTime(); this.continueAnimation = true; } function progressFade(ndx) { if( typeof( gAmc[ndx].el.filters.alpha ) != "object" ) return; percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0){ percent = 1.0; gAmc[ndx].continueAnimation = false; } gAmc[ndx].el.filters.alpha.opacity = gAmc[ndx].initialOpacity*(1.0-percent) + gAmc[ndx].finalOpacity*percent; } function finishFade(ndx) { if( typeof( gAmc[ndx].el.filters.alpha ) == "object" ) gAmc[ndx].el.filters.alpha.opacity = parseInt(gAmc[ndx].finalOpacity); } function progressTranslation(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } gAmc[ndx].el.style.pixelLeft = gAmc[ndx].startX*(1.0-percent) + gAmc[ndx].finalX*percent; gAmc[ndx].el.style.pixelTop = gAmc[ndx].startY*(1.0-percent) + gAmc[ndx].finalY*percent; } function progressSpiral(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf = 1.0 - percent t = percent * 2.0*Math.PI rx = Math.max(Math.abs(gAmc[ndx].el.initLeft), 200) ry = Math.max(Math.abs(gAmc[ndx].el.initTop), 200) gAmc[ndx].el.style.pixelLeft = Math.ceil(-rf*Math.cos(t)*rx) gAmc[ndx].el.style.pixelTop = Math.ceil(-rf*Math.sin(t)*ry) gAmc[ndx].el.style.visibility="visible" } function progressElasticFromRight(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf=Math.exp(-percent*7) t = percent * 1.5*Math.PI rx =Math.abs(gAmc[ndx].el.initLeft) gAmc[ndx].el.style.pixelLeft = rf*Math.cos(t)*rx gAmc[ndx].el.style.pixelTop = 0 gAmc[ndx].el.style.visibility="visible" } function progressElasticFromBottom(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf=Math.exp(-percent*7) t = percent * 1.5*Math.PI rx =Math.abs(gAmc[ndx].el.initTop) gAmc[ndx].el.style.pixelLeft = 0 gAmc[ndx].el.style.pixelTop = rf*Math.cos(t)*rx gAmc[ndx].el.style.visibility="visible" } function progressZoomIn(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1; gAmc[ndx].continueAnimation = false; } for (var index=0; index= 1.0) { finishZoom(ndx); } } function progressZoomOut(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } for (var index=0; index= 1.0) { finishZoom(ndx); } } function finishTranslation(ndx) { gAmc[ndx].el.style.pixelLeft = parseInt(gAmc[ndx].finalX); gAmc[ndx].el.style.pixelTop = parseInt(gAmc[ndx].finalY); } function finishZoom(ndx) { for (i=0; i BSSCSequenceIndex && (!bFound || objectOrder < minBSSCSequenceIndexFound)) { minBSSCSequenceIndexFound = objectOrder; bFound = true; } } } if (bFound) { BSSCSequenceIndex = minBSSCSequenceIndexFound; bStarted = startAnimationSet(BSSCSequenceIndex); } } function getOffsetFromTopOfBrowser(el) { if (null == el.offsetParent) return el.offsetTop; else return el.offsetTop + getOffsetFromTopOfBrowser(el.offsetParent); } function startAnimationSet(ndx) { var m = 0; bStarted = false; // Find document elements with "BSSCAnimationType" attribute divElements = document.all.tags("DIV"); for (var index = 0; index < divElements.length; index++) { el = divElements[index]; animationType = el.getAttribute("BSSCAnimationType", false); if(null != animationType) { framePeriod = el.getAttribute("BSSCFramePeriod", false); frameCount = el.getAttribute("BSSCFrameCount", false); sequenceIndex = el.getAttribute("BSSCObjectOrder", false); // Stop any currently running RevealTrans filters if ("RevealTrans" == animationType && parseInt(sequenceIndex) == ndx-1 && gbWindows) el.filters.RevealTrans.stop(); // Filter on ndx if (0 == ndx && null == sequenceIndex || ndx == parseInt(sequenceIndex)) { if ("FlyInFromRight" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s gAmc[m] = new animationContext(el, progressTranslation, finishTranslation, animationDuration, 10); gAmc[m].startX = document.body.clientWidth + document.body.scrollLeft; gAmc[m].startY = 0; gAmc[m].finalX = 0; gAmc[m].finalY = 0; animationPump(m++); bStarted = true; } if ("FlyOutToRight" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s gAmc[m] = new animationContext(el, progressTranslation, finishTranslation, animationDuration, 10); gAmc[m].startX = 0; gAmc[m].startY = 0; gAmc[m].finalX = document.body.clientWidth + document.body.scrollWidth; gAmc[m].finalY = 0; animationPump(m++); bStarted = true; } if ("FlyInFromLeft" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s for (childIndex=0; childIndex 0) && (document.images[0].src.indexOf('bsscnav1.gif') != -1)) { document.links[0].href = "javascript:void(null);"; } } } return; } ////////////////////////////////////////////////////////////////////////////////////////////// // // Begin DHTML Popup Functions // ////////////////////////////////////////////////////////////////////////////////////////////// //variables used to isolate the browser type var gBsDoc = null; var gBsSty = null; var gBsHtm = null; var gBsStyVisShow = null; var gBsStyVisHide = null; var gBsClientWidth = 640; var gBsClientHeight = 480; var gBsBrowser = null; // here is the varible for judge popup windows size. these parameter is for IE5.0, it may need adjust for others. var gBRateH_W = 0.618; // 1.618 Golden cut. var gBMaxXOfParent = 0.8; var gBMaxYOfParent = 0.8; var gBscrollHeight = 16; var gBscrollWidth = 16; var gBpermitXDelta = 3; var gBpermitYDelta = 3; //the browser information itself function _BSPSBrowserItself() { var agent = navigator.userAgent.toLowerCase(); this.major = parseInt(navigator.appVersion); this.minor = parseFloat(navigator.appVersion); this.ns = ((agent.indexOf('mozilla') != -1) && ((agent.indexOf('spoofer') == -1) && (agent.indexOf('compatible') == -1))); this.ns2 = ((this.ns) && (this.major == 2)); this.ns3 = ((this.ns) && (this.major == 3)); this.ns4 = ((this.ns) && (this.major >= 4)); this.ie = (agent.indexOf("msie") != -1); this.ie3 = ((this.ie) && (this.major == 2)); this.ie4 = ((this.ie) && (this.major >= 4)); this.op3 = (agent.indexOf("opera") != -1); if (this.ns4) { gBsDoc = "document"; gBsSty = ""; gBsHtm = ".document"; gBsStyVisShow = "show"; gBsStyVisHide = "hide"; } else if (this.ie4) { gBsDoc = "document.all"; gBsSty = ".style"; gBsHtm = ""; gBsStyVisShow = "visible"; gBsStyVisHide = "hidden"; } } //Here is the browser type function _BSPSGetBrowserInfo() { gBsBrowser = new _BSPSBrowserItself(); } //Get client size info function _BSPSGetClientSize() { if (gBsBrowser.ns4) { gBsClientWidth = innerWidth; gBsClientHeight = innerHeight; } else if (gBsBrowser.ie4) { gBsClientWidth = document.body.clientWidth; gBsClientHeight = document.body.clientHeight; } } var gstrPopupID = 'BSSCPopup'; var gstrPopupShadowID = 'BSSCPopupShadow'; var gstrPopupTopicID = 'BSSCPopupTopic'; var gstrPopupIFrameID = 'BSSCPopupIFrame'; var gstrPopupIFrameName = 'BSSCPopupIFrameName'; var gstrPopupSecondWindowName = 'BSSCPopup'; var gPopupDiv = null; var gPopupDivStyle = null; var gPopupShadow = null; var gPopupTopic = null; var gPopupIFrame = null; var gPopupIFrameStyle = null; var gPopupWindow = null; var gnPopupClickX = 0; var gnPopupClickY = 0; var gnPopupScreenClickX = 0; var gnPopupScreenClickY = 0; var gbPopupTimeoutExpired = false; var gbScriptName = "EHELP_DHTM"; var gbPathofJS = ""; if (gbIE4) { var aScripts = document.scripts; var aScript = null; var i = 0; for (i = 0; i < aScripts.length ; i ++ ) { if (aScripts[i].name == gbScriptName) { aScript = aScripts[i]; break; } } if (aScript != null) { var nPathPos = 0; var strCurrentSrc = ""; strCurrentSrc = aScript.src; var nPathPos1 = strCurrentSrc.lastIndexOf("\\"); var nPathPos2 = strCurrentSrc.lastIndexOf("/"); if (nPathPos1 > nPathPos2) nPathPos = nPathPos1 + 1; else nPathPos = nPathPos2 + 1; gbPathofJS = strCurrentSrc.substring(0, nPathPos); } } // Replace point - Used by SingleSource // var gbBlankPageForIFrame = gbPathofJS + "_blank.htm"; var gbBlankPageForIFrame = "about:blank"; if (BSSCPopup_IsPopup()) { document.write(""); } function DHTMLPopupSupport() { if ((gbIE4) && (!gbMac)) { return true; } return false; } function BSSCPopup_IsPopup() { if (DHTMLPopupSupport() && (this.name == gstrPopupIFrameName)) { return true; } else if ((gbNav4 || gbIE4) && (this.name == gstrPopupID)) { return true; } else { return false; } } function _BSSCCreatePopupDiv() { if (gPopupDiv == null) { if (DHTMLPopupSupport()) { document.write(""); var tempColl = document.all.tags("DIV"); for (var iDiv = 0; iDiv < tempColl.length; iDiv++) { if (tempColl(iDiv).id == gstrPopupID) { gPopupDiv = tempColl(iDiv); } if (tempColl(iDiv).id == gstrPopupShadowID) { gPopupShadow = tempColl(iDiv); } if (tempColl(iDiv).id == gstrPopupTopicID) { gPopupTopic = tempColl(iDiv); } } gPopupIFrame = eval("gPopupDiv.document.frames['" + gstrPopupIFrameName + "']"); gPopupDivStyle = eval("gPopupDiv" + gBsSty); gPopupIFrameStyle = eval(gBsDoc + "['" + gstrPopupIFrameName + "']" + gBsSty); } } } function BSSCPopup_Timeout() { if ((gPopupIFrame.document.readyState == "complete") && (gPopupIFrame.document.body != null) && (gPopupIFrame.location.href.indexOf(gbBlankPageForIFrame) == -1)) { BSSCPopup_TimeoutReal(); } else { setTimeout("BSSCPopup_Timeout()", 100); } } function BSSCPopup_TimeoutReal() { window.gbPopupTimeoutExpired = true; if (gPopupIFrame.document) { BSSCPopup_ChangeTargettoParent(gPopupIFrame.document); gPopupIFrame.document.body.onclick = BSSCPopupClicked; } document.onmousedown = BSSCPopupParentClicked; } function BSSCPopup_ChangeTargettoParent(tagsObject) { var collA = tagsObject.all.tags("A"); var j = 0; if (collA != null) { for (j = 0; j < collA.length; j ++ ) { collA[j].target = "_parent"; } } } function BSPSPopupTopicWinHelp(strURL) { _BSSCPopup(strURL); return; } function _BSSCPopup(strURL) { if (DHTMLPopupSupport()) { // If we are already in a popup, replace the contents if (BSSCPopup_IsPopup()) { location.href = strURL; parent.window.gbPopupTimeoutExpired = false; if (gbMac) { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 400); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 100); } } else { // Load the requested URL into the IFRAME gPopupIFrame.location.href = strURL; window.gbPopupTimeoutExpired = false; if (gbMac) { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 400); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 100); } } } else { _BSSCPopup2(strURL); } return; } function _BSSCPopup2(strURL) { if (window.name == gstrPopupSecondWindowName) { window.location = strURL; } else { BSSCHidePopupWindow(); var nX = 0; var nY = 0; var nHeight = 300; var nWidth = 400; _BSPSGetClientSize(); if (gBsBrowser.ns4) { nX = window.screenX + (window.outerWidth - window.innerWidth) + window.gnPopupClickX; nY = window.screenY + (window.outerHeight - window.innerHeight) + window.gnPopupClickY; if (nY + nHeight + 40 > screen.availHeight) { nY = screen.availHeight - nHeight - 40; } if (nX + nWidth + 40 > screen.availWidth) { nX = screen.availWidth - nWidth - 40; } } else { nX = window.gnPopupScreenClickX; nY = window.gnPopupScreenClickY; } // Launch a separate window var strParam = "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes"; if (gBsBrowser.ns) { strParam += ",OuterHeight=" + nHeight + ",OuterWidth=" + nWidth; strParam += ",screenX=" + nX + ",screenY=" + nY; strParam += ",dependent=yes"; } else { strParam += ",height=" + nHeight + ",width=" + nWidth; strParam += ",left=" + nX + ",top=" + nY; } window.gPopupWindow = window.open(strURL, gstrPopupSecondWindowName, strParam); if (gBsBrowser.ns4) { window.gPopupWindow.captureEvents(Event.CLICK | Event.BLUE); window.gPopupWindow.onclick = NonIEPopup_HandleClick; window.gPopupWindow.onblur = NonIEPopup_HandleBlur; } else if (gBsBrowser.ie4) { window.gPopupWindow.focus(); } } return; } function NonIEPopup_HandleBlur(e) { window.gPopupWindow.focus(); } function NonIEPopup_HandleClick(e) { // Because navigator will give the event to the handler before the hyperlink, let's // first route the event to see if we are clicking on a Popup menu in a popup. document.routeEvent(e); // If a popup menu is active then don't do anything with the click if (window.gPopupWindow.gbInPopupMenu) { window.gPopupWindow.captureEvents(Event.CLICK); window.gPopupWindow.onclick = NonIEPopup_HandleClick; return false; } // Close the popup window if (e.target.href != null) { window.location.href = e.target.href; if (e.target.href.indexOf("BSSCPopup") == -1) { this.close(); } } else { this.close(); } return false; } function BSSCPopup_AfterLoad(strURL) { if (typeof(window.gPopupIFrame.document) == "unknown") { _BSSCPopup2(strURL); return; } if ((window.gPopupIFrame.document.readyState == "complete") && (window.gPopupIFrame.document.body != null) && (window.gPopupIFrame.location.href.indexOf(gbBlankPageForIFrame) == -1)) { BSSCPopup_ResizeAfterLoad(strURL); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 200); } } function BSSCPopup_ResizeAfterLoad(strURL) { window.gPopupDivStyle.visibility = gBsStyVisHide; // Determine the width and height for the window //var size = new BSSCSize(0, 0); //BSSCGetContentSize(window.gPopupIFrame, size); //var nWidth = size.x; //var nHeight = size.y; _BSPSGetClientSize(); var size = new BSSCSize(0, 0); BSSCGetContentSize(window.gPopupIFrame, size); // Determine the width and height for the window var nWidth = size.x; var nHeight = size.y; window.gPopupDivStyle.width = nWidth; window.gPopupDivStyle.height = nHeight; // Determine the position of the window var nClickX = window.gnPopupClickX; var nClickY = window.gnPopupClickY; var nTop = 0; var nLeft = 0; if (nClickY + nHeight + 20 < gBsClientHeight + document.body.scrollTop) { nTop = nClickY + 10; } else { nTop = (document.body.scrollTop + gBsClientHeight) - nHeight - 20; } if (nClickX + nWidth < gBsClientWidth + document.body.scrollLeft) { nLeft = nClickX; } else { nLeft = (document.body.scrollLeft + gBsClientWidth) - nWidth - 8; } if (nTop < document.body.scrollTop ) nTop = document.body.scrollTop + 1; if (nLeft< document.body.scrollLeft) nLeft = document.body.scrollLeft + 1; window.gPopupDivStyle.left = nLeft; window.gPopupDivStyle.top = nTop; // Set the location of the background blocks window.gPopupShadow.style.left = 6; window.gPopupShadow.style.top = 6; if (gbIE55) { window.gPopupShadow.style.left = 4; window.gPopupShadow.style.top = 4; } window.gPopupShadow.style.width = nWidth; window.gPopupShadow.style.height = nHeight; window.gPopupTopic.style.width = nWidth; window.gPopupTopic.style.height = nHeight; if (gbIE55) { window.gPopupShadow.style.width = nWidth + 2; window.gPopupShadow.style.height = nHeight + 2; window.gPopupTopic.style.width = nWidth + 2; window.gPopupTopic.style.height = nHeight + 2; } if (gbMac) { // Total hack on the iMac to get the IFrame to position properly window.gPopupIFrameStyle.pixelLeft = 100; window.gPopupIFrameStyle.pixelLeft = 0; // Explicitly call BSSCOnLoad because the Mac doesn't seem to do it window.gPopupIFrame.window.BSSCOnLoad(); } //var nOriWidth = window.gPopupIFrameStyle.width window.gPopupIFrameStyle.width = nWidth; window.gPopupIFrameStyle.height = nHeight; if (gbIE55) { window.gPopupIFrameStyle.top = 0; window.gPopupIFrameStyle.left = 0; } gPopupIFrame.location.href = strURL; // reload again, this will fix the bookmark misunderstand in IE5. window.gPopupDivStyle.visibility = gBsStyVisShow; setTimeout("BSSCPopup_Timeout();", 100); return false; } function BSSCSize(x, y) { this.x = x; this.y = y; } function BSSCGetContentSize(thisWindow, size) { if (!((gBsBrowser.ie4) || (gBsBrowser.ns4))) return; if (gbMac) { size.x = 300; size.y = 300; return; } // Resize the width until it is wide enough to handle the content // The trick is to start wide and determine when the scrollHeight changes // because then we know a scrollbar is necessary. We can then go back // to the next widest size (for no scrollbar) var ClientRate = gBsClientHeight / gBsClientWidth; var GoldenSize = new BSSCSize(0,0); GoldenSize.x = gBsClientWidth * gBMaxXOfParent; GoldenSize.y = gBsClientHeight *gBMaxYOfParent ; if (ClientRate > gBRateH_W) { GoldenSize.y = GoldenSize.x * gBRateH_W; } else { GoldenSize.x = GoldenSize.y / gBRateH_W; } // Try to using parent specified max x. var x = 0; var maxgoldx = GoldenSize.x; var maxx = gBsClientWidth * gBMaxXOfParent; // This double resize causes the document to re-render (and we need it to) thisWindow.moveTo(10000,10000); // this is used to fix the flash on IE4. thisWindow.resizeTo(1, 1); thisWindow.resizeTo(1, 1); thisWindow.resizeTo(maxgoldx, thisWindow.document.body.scrollHeight + gBscrollHeight); thisWindow.resizeTo(maxgoldx, thisWindow.document.body.scrollHeight + gBscrollHeight); var miny = thisWindow.document.body.scrollHeight + gBscrollHeight; if (miny > GoldenSize.y) // the popup does not fix in the parent wanted golden area. so try to expand itself as large as it can { thisWindow.resizeTo(maxx , thisWindow.document.body.scrollHeight + gBscrollHeight); thisWindow.resizeTo(maxx , thisWindow.document.body.scrollHeight + gBscrollHeight); miny = thisWindow.document.body.scrollHeight + gBscrollHeight; maxy = gBsClientHeight * gBMaxYOfParent; if (miny > maxy) { // the popup must have a scroll, OK let it be. miny = maxy; size.x = maxx; size.y = maxy; } else { // popup still can fit in the parent area by someway. now we choose the same h/w rate as parent. size.y = miny; // downsize from maxx , now I try to using binary divide. x = maxx; deltax = -maxx/2; //j = 0; while (true) { x = x + deltax; thisWindow.resizeTo(x, miny); thisWindow.resizeTo(x, miny); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * ClientRate; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -gBpermitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //j ++; } size.x = thisWindow.document.body.scrollWidth; //+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight;// + gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. // Handle absurd cases just in case IE flakes // if (size.y < 100) { // size.y = 100; // } } } else { // downsize from maxgoldx , now I try to using binary divide. x = maxgoldx; deltax = -maxgoldx/2; //i = 0; while (true) { x = x + deltax; thisWindow.resizeTo(x, miny); thisWindow.resizeTo(x, miny); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * gBRateH_W; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -gBpermitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //i ++; } size.x = thisWindow.document.body.scrollWidth ;//+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight ;//+ gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. } if ((gbIE4) && (!gbIE5)) { size.x = size.x + 16; //reserve a width for scrollbar (IE 4.0 only) } thisWindow.resizeTo(size.x, size.y); thisWindow.resizeTo(size.x, size.y); return; } function BSSCPopupParentClicked() { BSSCPopupClicked(); return; } function BSSCPopupClicked() { if (!window.gbPopupTimeoutExpired) { return false; } if (gPopupIFrame.window.gbInPopupMenu) { return false; } // Give the user a message about javascript calls through objects. if ((gPopupIFrame.window.event != null) && (gPopupIFrame.window.event.srcElement != null) && (gPopupIFrame.window.event.srcElement.tagName == "A") && (gPopupIFrame.window.event.srcElement.href.indexOf("javascript:") == 0) && (gPopupIFrame.window.event.srcElement.href.indexOf(".") != -1)) { gPopupIFrame.window.event.cancelBubble = true; alert('Hyperlinks to objects do not work in popups.'); return false; } if (gPopupIFrame.document) { gPopupIFrame.document.body.onclick = null; } document.onclick = null; document.onmousedown = null; // Simply hide the popup gPopupDivStyle.visibility = gBsStyVisHide; gPopupIFrame.location.href = gbBlankPageForIFrame; return true; } //trace the mouse over's position for hotspot function BSPSPopupOnMouseOver(event) { if (gBsBrowser.ie4) { window.gnPopupClickX = event.clientX + document.body.scrollLeft; window.gnPopupClickY = event.clientY + document.body.scrollTop; window.gnPopupScreenClickX = event.screenX; window.gnPopupScreenClickY = event.screenY; } else if (gBsBrowser.ns4) { window.gnPopupClickX = event.pageX; window.gnPopupClickY = event.pageY; } } function BSSCHidePopupWindow() { if (window.gPopupWindow != null) { if (gBsBrowser.ns4) { if ((typeof window.gPopupWindow != "undefined") && (!window.gPopupWindow.closed)) { window.gPopupWindow.close(); window.gPopupWindow = null; } } } return; } var gbPopupMenuTimeoutExpired = false; var gbInPopupMenu = false; var gbPopupMenuTopicList = null; ////////////////////////////////////////////////////////////////////////////////////////// // // Popup Menu code // ////////////////////////////////////////////////////////////////////////////////////////// function _WritePopupMenuLayer() { if (gbNav4) { //Do not try to write ininle styles for NS! NS can not handle it and will not stop downloading the html page... document.write("
"); } else { document.write(""); if (gbIE4) { document.write(""); } } } //Define variable arguments as: strTitle, strUrl function PopupMenuTopicEntry() { this.strTitle = PopupMenuTopicEntry.arguments[0]; this.strURL = PopupMenuTopicEntry.arguments[1]; } // If the topic list is set, it is an array of TopicEntry objects (defined in WebHelp3.js) function PopupMenu_SetTopicList(aPopupTopicArray) { gbPopupMenuTopicList = aPopupTopicArray; } //Seek for the bsscright frame function _SeekFrameByName( cRoot, strName ) { if( cRoot == null ) return null; if( cRoot.frames == null ) return null; if( cRoot.frames[strName] != null ) return cRoot.frames[strName]; for (var i=0; i"); wndPopupLinks.document.write(""); var strParaLine = ""; for (var i = 0; i < (argLen - 2) / 2; i++) { strParaLine = ""; strParaLine += "
"); wndPopupLinks.document.close(); window.gbInPopupMenu = true; if (!gbIE) { wndPopupLinks.focus(); } return false; } // Make sure we have reasonable arguments var argLen = fn_arguments.length; if (argLen < 3) { return false; } // Check to see if we only have one target var strTarget = ""; if (((argLen < 5) && ((isNaN(fn_arguments[2])) || (gbPopupMenuTopicList == null))) || ((argLen < 4) && ((!isNaN(fn_arguments[2])) && (gbPopupMenuTopicList != null)))) { // Get the place that we will be putting the topic into var targetDoc = null; if (fn_arguments[1] == '') { targetDoc = window.document; } else { targetDoc = _GetFrameByName( parent, fn_arguments[1] ); if (targetDoc == null) { targetDoc = window.document; } //if (gbIE4) { // targetDoc = eval("top.document.frames['" + fn_arguments[1] + "']"); // } else if (gbNav4) { // targetDoc = eval("window.top." + fn_arguments[1] + ".document"); //} strTarget = "TARGET='" + fn_arguments[1] + "'"; } if (isNaN(fn_arguments[2]) || (gbPopupMenuTopicList == null)) { targetDoc.location.href = fn_arguments[3]; } else { targetDoc.location.href = gbPopupMenuTopicList[fn_arguments[2]].strURL; } return false; } var strMenu = ""; if (gbNav4) { strMenu = ''; } else { strMenu = '
'; } else { strMenu += '' + gbPopupMenuTopicList[fn_arguments[i]].strTitle + ''; } strMenu += ''; if (isNaN(fn_arguments[i]) || (gbPopupMenuTopicList == null)) { i += 2; } else { i += 1; } } strMenu += "
"; if (gbMac) { // totally hack. because ie5 in mac need something. is one of them. mac is mad. strMenu +="
"; } var layerPopup = null; var stylePopup = null; var nEventX = 0; var nEventY = 0; var nWindowWidth = 0; if (gbIE4) { layerPopup = document.all["PopupMenu"]; layerPopup.innerHTML = strMenu; stylePopup = layerPopup.style; _BSPSGetClientSize(); // Get the position of the item causing the event (relative to its parent) //if (gbMac) { if (true) { nEventX = window.event.clientX; nEventY = window.event.clientY; } else { //??? YJ: Can not remember why we calculate envent position by following code... //but it is wrong in a case like: CENTER->P->TABLE: //the offset positions of TABLE, P and CENTER are same (same offsetTop,offsetLeft) //so we get triple times of offset of x and y as we expect... nEventX = window.event.srcElement.offsetLeft - document.body.scrollLeft; nEventY = window.event.srcElement.offsetTop - document.body.scrollTop; // Get the location of the parent var nParentLocX = 0; var nParentLocY = 0; var ParentItem = window.event.srcElement.offsetParent; while (ParentItem != null) { if (ParentItem.offsetLeft) { nParentLocX += ParentItem.offsetLeft; nParentLocY += ParentItem.offsetTop; } ParentItem = ParentItem.parentElement; } // Adjust the location of the item using the location of the parent(s) nEventX += nParentLocX; nEventY += nParentLocY; } if (nEventY + layerPopup.scrollHeight + 10 < gBsClientHeight) { nEventY += document.body.scrollTop + 10; } else { nEventY = (document.body.scrollTop + gBsClientHeight) - layerPopup.scrollHeight - 20; } stylePopup.top = nEventY; if (nEventX + layerPopup.scrollWidth + 20 > gBsClientWidth) { if (gBsClientWidth - layerPopup.scrollWidth < 5) { stylePopup.left = 5; } else { stylePopup.left = gBsClientWidth - layerPopup.scrollWidth - 5; } } else { stylePopup.left = nEventX + document.body.scrollLeft + 20; } stylePopup.visibility = "visible"; document.onclick = PopupMenu_HandleClick; } else if (gbNav4) { layerPopup = document.layers.PopupMenu; layerPopup.visibility = "hide"; stylePopup = layerPopup.document; stylePopup.write(strMenu); stylePopup.close(); var e = fn_arguments[0]; nEventX = e.pageX; nEventY = e.pageY; _BSPSGetClientSize(); if (nEventY + layerPopup.clip.height + 20 < window.pageYOffset + gBsClientHeight) { nEventY += 20; } else { nEventY = gBsClientHeight + window.pageYOffset- layerPopup.clip.height - 20; } layerPopup.top = nEventY; if (nEventX + layerPopup.clip.width + 20 > gBsClientWidth + window.pageXOffset) { if (gBsClientWidth + window.pageXOffset - layerPopup.clip.width < 20) { nEventX = 5; } else { nEventX = gBsClientWidth + window.pageXOffset - layerPopup.clip.width - 20; } } else { nEventX += 20; } layerPopup.left = nEventX; layerPopup.visibility = "show"; // window.captureEvents(Event.CLICK | Event.MOUSEDOWN); window.captureEvents(Event.MOUSEDOWN); // window.onclick = PopupMenu_HandleClick; window.onmousedown = PopupMenu_HandleClick; } window.gbInPopupMenu = true; window.gbPopupMenuTimeoutExpired = false; setTimeout("PopupMenu_Timeout();", 100); return false; } function PopupMenu_Timeout() { window.gbPopupMenuTimeoutExpired = true; } function PopupMenu_Over(e) { if (gbIE4) { e.srcElement.className = "PopupOver"; } else if (gbNav4) { // this.bgColor = "red"; // e.target.document.className = "PopupOver"; } return; } function PopupMenu_Out(e) { if (gbIE4) { e.srcElement.className = "PopupNotOver"; } else if (gbNav4) { this.bgColor = "#f0f0f0"; } return; } function PopupMenu_HandleClick(e) { if (!window.gbPopupMenuTimeoutExpired) { return; } window.gbInPopupMenu = false; if (gbNav4) { // window.releaseEvents(Event.CLICK); window.releaseEvents(Event.MOUSEDOWN); } var layerPopup = null; var stylePopup = null; if (gbIE4) { layerPopup = document.all["PopupMenu"]; stylePopup = layerPopup.style; stylePopup.visibility = "hidden"; } else if (gbNav4) { layerPopup = document.layers.PopupMenu; layerPopup.visibility = "hide"; } return; } // This function should be deleted when all old projects are cleaned up function BSPSWritePopupFrameForIE4() { return false; } ///////////////////////////////////////////////////////////////////// function BSSCPopup_ClickMac() { if ((!DHTMLPopupSupport()) && (gbIE4)) { var bClickOnAnchor = false; var el; if ((window.event != null) && (window.event.srcElement != null)) { el = window.event.srcElement; while (el != null) { if ((el.tagName == "A") || (el.tagName == "AREA")) { bClickOnAnchor = true; break; } if (el.tagName == "BODY") { break; } el = el.parentElement; } } if (BSSCPopup_IsPopup()) { if (!bClickOnAnchor) { parent.window.gPopupWindow = null; self.close(); } } else { bClosePopupWindow = true; if ((bClickOnAnchor) && (el.href) && (el.href.indexOf("javascript:BSSCPopup") != -1)) { bClosePopupWindow = false; } if (bClosePopupWindow) { if (window.gPopupWindow != null) { var strParam = "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=300,width=400"; window.gPopupWindow = window.open("", gstrPopupSecondWindowName,strParam); window.gPopupWindow.close(); window.gPopupWindow = null; } } } } } ////////////////////////////////////////////////////////////////////// _BSPSGetBrowserInfo(); function _BSSCOnLoad() { if (!gbIE4 && !gbNav4) return; // Make everything visible in navigator if (gbNav4) { // Make some special effects items visible for (var iLayer = 0; iLayer < document.layers.length; iLayer++) { document.layers[iLayer].visibility = gBsStyVisShow; document.layers[iLayer].left = 0; } } // Remove the NavBar if necessary RemoveNavBar(); // Don't continue without IE4 if (gbIE4) { HHActivateComponents(); doStaticEffects(); startAnimationSet(0); } } function _BSSCOnUnload() { } function _BSSCOnClick() { if (!gbIE4) return; BSSCPopup_ClickMac(); startNextAnimationSet(); } function _BSSCOnError(message) { if(-1 != message.indexOf("denied") || -1 != message.indexOf("Object required")) return true; } function ResizeBasedonRate(thisWindow, size, rate, maxx, maxy) { x = maxx; y = maxy; deltax = -maxx/2; while (true) { x = x + deltax; thisWindow.resizeTo(x, y); thisWindow.resizeTo(x, y); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * rate; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -permitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //j ++; } size.x = thisWindow.document.body.scrollWidth; //+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight;// + gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. } //////////BSSCDHTML Section Embedded Code////////// var s_strAgent = navigator.userAgent.toLowerCase(); var s_nVer = parseInt(navigator.appVersion); var s_bIE = (s_strAgent.indexOf('msie') != -1); var s_bNS = (s_strAgent.indexOf('mozilla') != -1) && ((s_strAgent.indexOf('spoofer') == -1) && (s_strAgent.indexOf('compatible') == -1)); var s_bOpera = (s_strAgent.indexOf('opera') != -1); var s_bIE3Before = ((s_bIE) && (s_nVer <= 2)); var s_bNS3Before = ((s_bNS) && (s_nVer <= 3)); var s_bNS2 = ((s_bNS) && (s_nVer <= 2)); var s_bNS3 = ((s_bNS) && (s_nVer == 3)); var s_bIE300301 = ((s_bIE) && (s_nVer == 2) && ((s_strAgent.indexOf("3.00") != -1)||(s_strAgent.indexOf("3.0a") != -1)||(s_strAgent.indexOf("3.0b")!=-1)||(s_strAgent.indexOf("3.01")!=-1))); var s_bIE302 = ((s_bIE) && (s_nVer == 2) && (s_strAgent.indexOf("3.02") != -1)); function HasExtJs() { if (s_bIE3Before) { return false;} if (s_bNS3Before) { return false;} if (typeof (_BSSCOnLoad) == "undefined"){ return false; } return true; } function BSSCOnLoad() { if (HasExtJs()) { _BSSCOnLoad(); } } function BSSCOnUnload() { if (HasExtJs()) { _BSSCOnUnload(); } } function BSSCOnClick() { if (HasExtJs()) { _BSSCOnClick(); } } function BSSCOnError(message) { if (HasExtJs()) { return _BSSCOnError(message); } } function WritePopupMenuLayer() { if (HasExtJs()) {_WritePopupMenuLayer();} } function BSSCCreatePopupDiv() { if (HasExtJs()) {_BSSCCreatePopupDiv(); } } function BSSCPopup(strURL) { if (HasExtJs()) { _BSSCPopup(strURL); }else{ //Create a temporary window first to ensure the real popup comes up on top var wndTemp = null; if (!s_bNS3) { wndTemp = window.open("", "temp", "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=3,width=4"); } // Create the real popup window var wndPopup = window.open(strURL, "BSSCPopup", "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=300,width=400"); // Close the temporary if (!s_bNS3) { wndTemp.close(); } else { wndPopup.focus(); } } } var gbWndTemp = null, gbWndPopupLinks = null; var gbstrParaTotal = ""; function PopupMenu_Invoke() { if (HasExtJs()) { return _PopupMenu_Invoke(PopupMenu_Invoke.arguments); } if (s_bNS3Before || s_bIE3Before ) { var argLen = PopupMenu_Invoke.arguments.length; if (argLen < 5) { window.document.location.href = PopupMenu_Invoke.arguments[3]; return false; } gbWndTemp = null; gbWndPopupLinks = null; gbstrParatotal = ""; for (var i = 0; i < (argLen - 2) / 2; i++) { var strParaLine = ""; if (s_bNS2 || s_bOpera){ strParaLine += "
" strParaLine += PopupMenu_Invoke.arguments[2 * i + 2]; strParaLine += ""; } else { strParaLine += ""); if (s_bNS2 || s_bOpera) { gbWndPopupLinks.document.write(""); } else { //YJ: IE301,302 and NS3.x works fine gbWndPopupLinks.document.write("<"); gbWndPopupLinks.document.write("script>"); gbWndPopupLinks.document.write("function gotoUrl(aUrl) {opener.window.location=aUrl; close();}"); gbWndPopupLinks.document.write("<"); gbWndPopupLinks.document.write("/script>"); } gbWndPopupLinks.document.write(""); gbWndPopupLinks.document.write(gbstrParaTotal); gbWndPopupLinks.document.write(""); gbWndPopupLinks.document.close(); // Close the temporary if (!s_bNS3 && gbWndTemp != null) { gbWndTemp.close(); }else { gbWndPopupLinks.focus(); } return true; } return false; } onload = BSSCOnLoad; document.onclick = BSSCOnClick; onunload = BSSCOnUnload; onerror = BSSCOnError;./SpecialOrderedSetsOfTypeOne_files/img00341.gif000666 000000 000000 00000010546 07755132500 017731 0ustar00000000 000000 GIF89a$a!,$aH*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ NȱX<FNt׫k={^:x{Gݮ_>ߪUtU`֜\`׃B[sEavhӂuGyhOg^+x:X-3"Z$8cqrYوW%9XB@-I\ _cA~&O9!D`nVaBgT$w`xĨGh>J*NꕧI9^t%)seZu kZJKre뭩߮&lVڱH,iV 質E[VkBm~ .R*gSע{;MFo<,L>0gV9m'鿛64pSO\תw+UqD'+282V0S%3D7s*ܐ1@/TtPG+ II3f2zGԩ4XǪ76MjUW|iPWسR-lwo͍v/{-L~y6axxi?56wf'9<+wݙ#|k䥆m]_:[[;\{&qquC3lj-1^9w=s_.Y}췴=n4b_eHlsJ?̭+!Bخ|c(X~ _=aSUJcgPH;$!ch;aB k ]%!:P"bœ/Fl^6*DM\Xaу;SC_11]gZ6F jP# сЋH"1#z|سљ0%z$XI8G@t, J7f{ HL%%HBFd'S.eW22*cB&ba?`vG e1K1v&&&l7wIL33 4mN6LEg#x'+{Ѓpd+$Ie(YQQ3e)O~t ('QOW&4)I;^4Pt~jJu5)RR.R+Ԛ>!*;aRm)KS̬E?հb5GMU:dXz֮'^(֛o^XֵnlQ%XRvjO\wZVpVAm)UMkg U*S]mi1 Y^6ebukVkC۵_D.SR;Y]q+v.GKvu^swY\})Dž=w.zŻ_VmƗK/{`Z2v,\Vظܝջa*ãm0,`p=Xv0{5ܶXoO\fzEI$?GC Y4&-0qQ:fEQTܪ'ز@;\3y"YrH|ѢY|RD/n&k y RY:w6B;֤, :3XnDK47=eE:"Lu@]jMIDTZ3@ΗN.mO3mئَ`md{0JovHԣX5bvb$ ԳT4nY#&4]ikn}]%kQa{5Jky^mLKw nkdT[$nzjS}r}7UQ>n5]sG~-wYG׻bJY*M? jD^v>Y#eA};#{I~zg{]ڲO \CDŽ_^j7Z$tlz[{v{*~&|J{_ܿ$<=(1!&e3\lZ.`gf4c 6|z*րL}h(](WGb%Ex%,xy1Yƀ!8gn'e#8P%5)Z;^7`3HC$XL hSxӦ˕Pу16LRdex"nHDX((Ņugzah}wkhmh7NW?؂|ȈqH臖[2&8cXww(hX+h芙X3^8T8ȋ؉X؁ȆhX88XJHވhȌ͸MȉH稂8툎Cȏ8g݈Xr8thX`)) iՑԐ>W$Y Ix!9 yxԸ`>Ƀ-EƘxGm5Oٔ7TVIxX)i_iKy:NIɐoxe=) ȖULj)s m/ٖ1蒇1&مq|Z)(62i@V%YGz)d٘6i~Iٗ]IsuIFtyx7{\ _wd9yg) 9 vٜyY9CIdɗEKɓyHٚIp)ɝƙi+g`iיfڞzy:鉛j %'|ٟٙIjzy ٩թ .zc3Zj|fȤF~O)Qj~+Jj1JHzZaj{2e$T:KZ]}Cy:Zzڨ3:Z<.ؒB:2F&iH" dzsz媾"Czj:Sg:ob{jJFeW?Ǭz- 9ȡc7ںS8WsUʭL0 ncus:$ƭ gE97ǃ«7&گ1fgwi:eڰ yl |CvV;2kO dwX'|f !Q e# 8$$婲B;D[F{HJL۴NPR;T[V{XZ\۵^`K;./SpecialOrderedSetsOfTypeOne_files/img00342.gif000666 000000 000000 00000001773 07755132500 017734 0ustar00000000 000000 GIF89aL!,LH*\ȰÇ#JH"A`xp@ =$FGfTBSt)ʙe2 QM k $PAKҼqc҆Ivt:'˥LY!ҝXحg[ZMRק8/v-KO.Oڹp弧*=;u1^=U6^ݶx}z|rjKJ{zCYfDSj ]UYy *߁6]e6GsVaΖb{Sh gӅp8 ݸy#`+X})Yv=ډ=_F2tw5HcZu7Qa'MB Qy_ic|n$ejZY+di&ԖyhkIg<&&`#b(ik#F7i&ނz'3bGp5brJ_JYk&*;./SpecialOrderedSetsOfTypeOne_files/img00344.gif000666 000000 000000 00000002342 07755132500 017727 0ustar00000000 000000 GIF89a!,H*\ȰÇ#JHŋ3jȱǏiP$ɓM\ɲȑ+_9P&͛8 Ξ9? Q$PG%ʴӉC9LeR3>-JPũ: ϲa-y֫@RJĺP6K(Ф*\5 n ӮX 1ܿz춪No*<t䚟.3"%YntjcCSM|{ukp޹iߕm\9ڔcNi3D`6#bG;.>zX6m:;HcO@'\N'sJD\J%dm_&c?hlp^;./SpecialOrderedSetsOfTypeOne_files/img00346.gif000666 000000 000000 00000001536 07755132500 017735 0ustar00000000 000000 GIF89a!,;H*\C6$`a^h#C;T#ǑGqcď0c~ ;./SpecialOrderedSetsOfTypeOne_files/img00347.gif000666 000000 000000 00000001546 07755132500 017737 0ustar00000000 000000 GIF89a!,CH*\ȰÇ (q‰J C 7~$ȎE$B]H3J8;./Semi-ContinuousVariables_files/bsscdhtm.js000666 000000 000000 00000214323 07755132440 017622 0ustar00000000 000000 //////////BSSCDHTML Section 1////////// // RoboHELP Dynamic HTML Effects Script // Copyright 1998-2000 eHelp Corporation. All rights reserved. // Version=3.72 // Warning: Do not modify this file. It is generated by RoboHELP and changes will be overwritten. //{{HH_SYMBOL_SECTION var HH_ChmFilename = ""; var HH_WindowName = ""; var HH_GlossaryFont = ""; var HH_Glossary = ""; var HH_Avenue = ""; var HH_ActiveX = false; //}}HH_SYMBOL_SECTION var gbNav4 = false; var gbIE4 = false; var gbIE = false; var gbIE5 = false; var gbIE55 = false; var gAgent = navigator.userAgent.toLowerCase(); var gbMac = (gAgent.indexOf("mac") != -1); var gbWindows = ((gAgent.indexOf("win") != -1) || (gAgent.indexOf("16bit") != -1)); var error_count = 0; gbIE = (navigator.appName.indexOf("Microsoft") != -1); if (parseInt(navigator.appVersion) >= 4) { gbNav4 = (navigator.appName == "Netscape"); gbIE4 = (navigator.appName.indexOf("Microsoft") != -1); if (gbIE4) { if (gAgent.indexOf("msie 5.0") != -1) { gbIE5 = true; } if (gAgent.indexOf("msie 5.5") != -1) { // curently IE 5.5 has some buggy stuff. we need do some remedy to our code. gbIE55 = true; } } } function HHActivateComponents() { if (HH_ActiveX && (HH_ChmFilename != "") && ((self == top) || (self == top.frames[0]))) { var objBody = document.all.tags("BODY")[0]; if( typeof(objBody) == "object" ) { objBody.insertAdjacentHTML("beforeEnd", ''); if (HHComponentActivator.object) { HHComponentActivator.Activate(HH_ChmFilename, HH_WindowName, HH_GlossaryFont, HH_Glossary, HH_Avenue); } } } } var gAmc = new Array(); var BSSCSequenceIndex = 0; function animationContext(el, progressAnimation, finishAnimiation, animationDuration, animationPeriod) { this.el = el; this.progressAnimation = progressAnimation; this.finishAnimiation = finishAnimiation; this.animationDuration = parseFloat(animationDuration); this.animationPeriod = animationPeriod; this.animationStartTime = (new Date()).getTime(); this.continueAnimation = true; } function progressFade(ndx) { if( typeof( gAmc[ndx].el.filters.alpha ) != "object" ) return; percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0){ percent = 1.0; gAmc[ndx].continueAnimation = false; } gAmc[ndx].el.filters.alpha.opacity = gAmc[ndx].initialOpacity*(1.0-percent) + gAmc[ndx].finalOpacity*percent; } function finishFade(ndx) { if( typeof( gAmc[ndx].el.filters.alpha ) == "object" ) gAmc[ndx].el.filters.alpha.opacity = parseInt(gAmc[ndx].finalOpacity); } function progressTranslation(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } gAmc[ndx].el.style.pixelLeft = gAmc[ndx].startX*(1.0-percent) + gAmc[ndx].finalX*percent; gAmc[ndx].el.style.pixelTop = gAmc[ndx].startY*(1.0-percent) + gAmc[ndx].finalY*percent; } function progressSpiral(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf = 1.0 - percent t = percent * 2.0*Math.PI rx = Math.max(Math.abs(gAmc[ndx].el.initLeft), 200) ry = Math.max(Math.abs(gAmc[ndx].el.initTop), 200) gAmc[ndx].el.style.pixelLeft = Math.ceil(-rf*Math.cos(t)*rx) gAmc[ndx].el.style.pixelTop = Math.ceil(-rf*Math.sin(t)*ry) gAmc[ndx].el.style.visibility="visible" } function progressElasticFromRight(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf=Math.exp(-percent*7) t = percent * 1.5*Math.PI rx =Math.abs(gAmc[ndx].el.initLeft) gAmc[ndx].el.style.pixelLeft = rf*Math.cos(t)*rx gAmc[ndx].el.style.pixelTop = 0 gAmc[ndx].el.style.visibility="visible" } function progressElasticFromBottom(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } rf=Math.exp(-percent*7) t = percent * 1.5*Math.PI rx =Math.abs(gAmc[ndx].el.initTop) gAmc[ndx].el.style.pixelLeft = 0 gAmc[ndx].el.style.pixelTop = rf*Math.cos(t)*rx gAmc[ndx].el.style.visibility="visible" } function progressZoomIn(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1; gAmc[ndx].continueAnimation = false; } for (var index=0; index= 1.0) { finishZoom(ndx); } } function progressZoomOut(ndx) { percent = ((new Date()).getTime() - gAmc[ndx].animationStartTime)/gAmc[ndx].animationDuration; if (percent > 1.0) { percent = 1.0; gAmc[ndx].continueAnimation = false; } for (var index=0; index= 1.0) { finishZoom(ndx); } } function finishTranslation(ndx) { gAmc[ndx].el.style.pixelLeft = parseInt(gAmc[ndx].finalX); gAmc[ndx].el.style.pixelTop = parseInt(gAmc[ndx].finalY); } function finishZoom(ndx) { for (i=0; i BSSCSequenceIndex && (!bFound || objectOrder < minBSSCSequenceIndexFound)) { minBSSCSequenceIndexFound = objectOrder; bFound = true; } } } if (bFound) { BSSCSequenceIndex = minBSSCSequenceIndexFound; bStarted = startAnimationSet(BSSCSequenceIndex); } } function getOffsetFromTopOfBrowser(el) { if (null == el.offsetParent) return el.offsetTop; else return el.offsetTop + getOffsetFromTopOfBrowser(el.offsetParent); } function startAnimationSet(ndx) { var m = 0; bStarted = false; // Find document elements with "BSSCAnimationType" attribute divElements = document.all.tags("DIV"); for (var index = 0; index < divElements.length; index++) { el = divElements[index]; animationType = el.getAttribute("BSSCAnimationType", false); if(null != animationType) { framePeriod = el.getAttribute("BSSCFramePeriod", false); frameCount = el.getAttribute("BSSCFrameCount", false); sequenceIndex = el.getAttribute("BSSCObjectOrder", false); // Stop any currently running RevealTrans filters if ("RevealTrans" == animationType && parseInt(sequenceIndex) == ndx-1 && gbWindows) el.filters.RevealTrans.stop(); // Filter on ndx if (0 == ndx && null == sequenceIndex || ndx == parseInt(sequenceIndex)) { if ("FlyInFromRight" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s gAmc[m] = new animationContext(el, progressTranslation, finishTranslation, animationDuration, 10); gAmc[m].startX = document.body.clientWidth + document.body.scrollLeft; gAmc[m].startY = 0; gAmc[m].finalX = 0; gAmc[m].finalY = 0; animationPump(m++); bStarted = true; } if ("FlyOutToRight" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s gAmc[m] = new animationContext(el, progressTranslation, finishTranslation, animationDuration, 10); gAmc[m].startX = 0; gAmc[m].startY = 0; gAmc[m].finalX = document.body.clientWidth + document.body.scrollWidth; gAmc[m].finalY = 0; animationPump(m++); bStarted = true; } if ("FlyInFromLeft" == animationType) { animationDuration = el.getAttribute("BSSCDuration", false); if (null == animationDuration) animationDuration = 1000; // default to 1s for (childIndex=0; childIndex 0) && (document.images[0].src.indexOf('bsscnav1.gif') != -1)) { document.links[0].href = "javascript:void(null);"; } } } return; } ////////////////////////////////////////////////////////////////////////////////////////////// // // Begin DHTML Popup Functions // ////////////////////////////////////////////////////////////////////////////////////////////// //variables used to isolate the browser type var gBsDoc = null; var gBsSty = null; var gBsHtm = null; var gBsStyVisShow = null; var gBsStyVisHide = null; var gBsClientWidth = 640; var gBsClientHeight = 480; var gBsBrowser = null; // here is the varible for judge popup windows size. these parameter is for IE5.0, it may need adjust for others. var gBRateH_W = 0.618; // 1.618 Golden cut. var gBMaxXOfParent = 0.8; var gBMaxYOfParent = 0.8; var gBscrollHeight = 16; var gBscrollWidth = 16; var gBpermitXDelta = 3; var gBpermitYDelta = 3; //the browser information itself function _BSPSBrowserItself() { var agent = navigator.userAgent.toLowerCase(); this.major = parseInt(navigator.appVersion); this.minor = parseFloat(navigator.appVersion); this.ns = ((agent.indexOf('mozilla') != -1) && ((agent.indexOf('spoofer') == -1) && (agent.indexOf('compatible') == -1))); this.ns2 = ((this.ns) && (this.major == 2)); this.ns3 = ((this.ns) && (this.major == 3)); this.ns4 = ((this.ns) && (this.major >= 4)); this.ie = (agent.indexOf("msie") != -1); this.ie3 = ((this.ie) && (this.major == 2)); this.ie4 = ((this.ie) && (this.major >= 4)); this.op3 = (agent.indexOf("opera") != -1); if (this.ns4) { gBsDoc = "document"; gBsSty = ""; gBsHtm = ".document"; gBsStyVisShow = "show"; gBsStyVisHide = "hide"; } else if (this.ie4) { gBsDoc = "document.all"; gBsSty = ".style"; gBsHtm = ""; gBsStyVisShow = "visible"; gBsStyVisHide = "hidden"; } } //Here is the browser type function _BSPSGetBrowserInfo() { gBsBrowser = new _BSPSBrowserItself(); } //Get client size info function _BSPSGetClientSize() { if (gBsBrowser.ns4) { gBsClientWidth = innerWidth; gBsClientHeight = innerHeight; } else if (gBsBrowser.ie4) { gBsClientWidth = document.body.clientWidth; gBsClientHeight = document.body.clientHeight; } } var gstrPopupID = 'BSSCPopup'; var gstrPopupShadowID = 'BSSCPopupShadow'; var gstrPopupTopicID = 'BSSCPopupTopic'; var gstrPopupIFrameID = 'BSSCPopupIFrame'; var gstrPopupIFrameName = 'BSSCPopupIFrameName'; var gstrPopupSecondWindowName = 'BSSCPopup'; var gPopupDiv = null; var gPopupDivStyle = null; var gPopupShadow = null; var gPopupTopic = null; var gPopupIFrame = null; var gPopupIFrameStyle = null; var gPopupWindow = null; var gnPopupClickX = 0; var gnPopupClickY = 0; var gnPopupScreenClickX = 0; var gnPopupScreenClickY = 0; var gbPopupTimeoutExpired = false; var gbScriptName = "EHELP_DHTM"; var gbPathofJS = ""; if (gbIE4) { var aScripts = document.scripts; var aScript = null; var i = 0; for (i = 0; i < aScripts.length ; i ++ ) { if (aScripts[i].name == gbScriptName) { aScript = aScripts[i]; break; } } if (aScript != null) { var nPathPos = 0; var strCurrentSrc = ""; strCurrentSrc = aScript.src; var nPathPos1 = strCurrentSrc.lastIndexOf("\\"); var nPathPos2 = strCurrentSrc.lastIndexOf("/"); if (nPathPos1 > nPathPos2) nPathPos = nPathPos1 + 1; else nPathPos = nPathPos2 + 1; gbPathofJS = strCurrentSrc.substring(0, nPathPos); } } // Replace point - Used by SingleSource // var gbBlankPageForIFrame = gbPathofJS + "_blank.htm"; var gbBlankPageForIFrame = "about:blank"; if (BSSCPopup_IsPopup()) { document.write(""); } function DHTMLPopupSupport() { if ((gbIE4) && (!gbMac)) { return true; } return false; } function BSSCPopup_IsPopup() { if (DHTMLPopupSupport() && (this.name == gstrPopupIFrameName)) { return true; } else if ((gbNav4 || gbIE4) && (this.name == gstrPopupID)) { return true; } else { return false; } } function _BSSCCreatePopupDiv() { if (gPopupDiv == null) { if (DHTMLPopupSupport()) { document.write(""); var tempColl = document.all.tags("DIV"); for (var iDiv = 0; iDiv < tempColl.length; iDiv++) { if (tempColl(iDiv).id == gstrPopupID) { gPopupDiv = tempColl(iDiv); } if (tempColl(iDiv).id == gstrPopupShadowID) { gPopupShadow = tempColl(iDiv); } if (tempColl(iDiv).id == gstrPopupTopicID) { gPopupTopic = tempColl(iDiv); } } gPopupIFrame = eval("gPopupDiv.document.frames['" + gstrPopupIFrameName + "']"); gPopupDivStyle = eval("gPopupDiv" + gBsSty); gPopupIFrameStyle = eval(gBsDoc + "['" + gstrPopupIFrameName + "']" + gBsSty); } } } function BSSCPopup_Timeout() { if ((gPopupIFrame.document.readyState == "complete") && (gPopupIFrame.document.body != null) && (gPopupIFrame.location.href.indexOf(gbBlankPageForIFrame) == -1)) { BSSCPopup_TimeoutReal(); } else { setTimeout("BSSCPopup_Timeout()", 100); } } function BSSCPopup_TimeoutReal() { window.gbPopupTimeoutExpired = true; if (gPopupIFrame.document) { BSSCPopup_ChangeTargettoParent(gPopupIFrame.document); gPopupIFrame.document.body.onclick = BSSCPopupClicked; } document.onmousedown = BSSCPopupParentClicked; } function BSSCPopup_ChangeTargettoParent(tagsObject) { var collA = tagsObject.all.tags("A"); var j = 0; if (collA != null) { for (j = 0; j < collA.length; j ++ ) { collA[j].target = "_parent"; } } } function BSPSPopupTopicWinHelp(strURL) { _BSSCPopup(strURL); return; } function _BSSCPopup(strURL) { if (DHTMLPopupSupport()) { // If we are already in a popup, replace the contents if (BSSCPopup_IsPopup()) { location.href = strURL; parent.window.gbPopupTimeoutExpired = false; if (gbMac) { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 400); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 100); } } else { // Load the requested URL into the IFRAME gPopupIFrame.location.href = strURL; window.gbPopupTimeoutExpired = false; if (gbMac) { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 400); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 100); } } } else { _BSSCPopup2(strURL); } return; } function _BSSCPopup2(strURL) { if (window.name == gstrPopupSecondWindowName) { window.location = strURL; } else { BSSCHidePopupWindow(); var nX = 0; var nY = 0; var nHeight = 300; var nWidth = 400; _BSPSGetClientSize(); if (gBsBrowser.ns4) { nX = window.screenX + (window.outerWidth - window.innerWidth) + window.gnPopupClickX; nY = window.screenY + (window.outerHeight - window.innerHeight) + window.gnPopupClickY; if (nY + nHeight + 40 > screen.availHeight) { nY = screen.availHeight - nHeight - 40; } if (nX + nWidth + 40 > screen.availWidth) { nX = screen.availWidth - nWidth - 40; } } else { nX = window.gnPopupScreenClickX; nY = window.gnPopupScreenClickY; } // Launch a separate window var strParam = "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes"; if (gBsBrowser.ns) { strParam += ",OuterHeight=" + nHeight + ",OuterWidth=" + nWidth; strParam += ",screenX=" + nX + ",screenY=" + nY; strParam += ",dependent=yes"; } else { strParam += ",height=" + nHeight + ",width=" + nWidth; strParam += ",left=" + nX + ",top=" + nY; } window.gPopupWindow = window.open(strURL, gstrPopupSecondWindowName, strParam); if (gBsBrowser.ns4) { window.gPopupWindow.captureEvents(Event.CLICK | Event.BLUE); window.gPopupWindow.onclick = NonIEPopup_HandleClick; window.gPopupWindow.onblur = NonIEPopup_HandleBlur; } else if (gBsBrowser.ie4) { window.gPopupWindow.focus(); } } return; } function NonIEPopup_HandleBlur(e) { window.gPopupWindow.focus(); } function NonIEPopup_HandleClick(e) { // Because navigator will give the event to the handler before the hyperlink, let's // first route the event to see if we are clicking on a Popup menu in a popup. document.routeEvent(e); // If a popup menu is active then don't do anything with the click if (window.gPopupWindow.gbInPopupMenu) { window.gPopupWindow.captureEvents(Event.CLICK); window.gPopupWindow.onclick = NonIEPopup_HandleClick; return false; } // Close the popup window if (e.target.href != null) { window.location.href = e.target.href; if (e.target.href.indexOf("BSSCPopup") == -1) { this.close(); } } else { this.close(); } return false; } function BSSCPopup_AfterLoad(strURL) { if (typeof(window.gPopupIFrame.document) == "unknown") { _BSSCPopup2(strURL); return; } if ((window.gPopupIFrame.document.readyState == "complete") && (window.gPopupIFrame.document.body != null) && (window.gPopupIFrame.location.href.indexOf(gbBlankPageForIFrame) == -1)) { BSSCPopup_ResizeAfterLoad(strURL); } else { setTimeout("BSSCPopup_AfterLoad('" + strURL + "')", 200); } } function BSSCPopup_ResizeAfterLoad(strURL) { window.gPopupDivStyle.visibility = gBsStyVisHide; // Determine the width and height for the window //var size = new BSSCSize(0, 0); //BSSCGetContentSize(window.gPopupIFrame, size); //var nWidth = size.x; //var nHeight = size.y; _BSPSGetClientSize(); var size = new BSSCSize(0, 0); BSSCGetContentSize(window.gPopupIFrame, size); // Determine the width and height for the window var nWidth = size.x; var nHeight = size.y; window.gPopupDivStyle.width = nWidth; window.gPopupDivStyle.height = nHeight; // Determine the position of the window var nClickX = window.gnPopupClickX; var nClickY = window.gnPopupClickY; var nTop = 0; var nLeft = 0; if (nClickY + nHeight + 20 < gBsClientHeight + document.body.scrollTop) { nTop = nClickY + 10; } else { nTop = (document.body.scrollTop + gBsClientHeight) - nHeight - 20; } if (nClickX + nWidth < gBsClientWidth + document.body.scrollLeft) { nLeft = nClickX; } else { nLeft = (document.body.scrollLeft + gBsClientWidth) - nWidth - 8; } if (nTop < document.body.scrollTop ) nTop = document.body.scrollTop + 1; if (nLeft< document.body.scrollLeft) nLeft = document.body.scrollLeft + 1; window.gPopupDivStyle.left = nLeft; window.gPopupDivStyle.top = nTop; // Set the location of the background blocks window.gPopupShadow.style.left = 6; window.gPopupShadow.style.top = 6; if (gbIE55) { window.gPopupShadow.style.left = 4; window.gPopupShadow.style.top = 4; } window.gPopupShadow.style.width = nWidth; window.gPopupShadow.style.height = nHeight; window.gPopupTopic.style.width = nWidth; window.gPopupTopic.style.height = nHeight; if (gbIE55) { window.gPopupShadow.style.width = nWidth + 2; window.gPopupShadow.style.height = nHeight + 2; window.gPopupTopic.style.width = nWidth + 2; window.gPopupTopic.style.height = nHeight + 2; } if (gbMac) { // Total hack on the iMac to get the IFrame to position properly window.gPopupIFrameStyle.pixelLeft = 100; window.gPopupIFrameStyle.pixelLeft = 0; // Explicitly call BSSCOnLoad because the Mac doesn't seem to do it window.gPopupIFrame.window.BSSCOnLoad(); } //var nOriWidth = window.gPopupIFrameStyle.width window.gPopupIFrameStyle.width = nWidth; window.gPopupIFrameStyle.height = nHeight; if (gbIE55) { window.gPopupIFrameStyle.top = 0; window.gPopupIFrameStyle.left = 0; } gPopupIFrame.location.href = strURL; // reload again, this will fix the bookmark misunderstand in IE5. window.gPopupDivStyle.visibility = gBsStyVisShow; setTimeout("BSSCPopup_Timeout();", 100); return false; } function BSSCSize(x, y) { this.x = x; this.y = y; } function BSSCGetContentSize(thisWindow, size) { if (!((gBsBrowser.ie4) || (gBsBrowser.ns4))) return; if (gbMac) { size.x = 300; size.y = 300; return; } // Resize the width until it is wide enough to handle the content // The trick is to start wide and determine when the scrollHeight changes // because then we know a scrollbar is necessary. We can then go back // to the next widest size (for no scrollbar) var ClientRate = gBsClientHeight / gBsClientWidth; var GoldenSize = new BSSCSize(0,0); GoldenSize.x = gBsClientWidth * gBMaxXOfParent; GoldenSize.y = gBsClientHeight *gBMaxYOfParent ; if (ClientRate > gBRateH_W) { GoldenSize.y = GoldenSize.x * gBRateH_W; } else { GoldenSize.x = GoldenSize.y / gBRateH_W; } // Try to using parent specified max x. var x = 0; var maxgoldx = GoldenSize.x; var maxx = gBsClientWidth * gBMaxXOfParent; // This double resize causes the document to re-render (and we need it to) thisWindow.moveTo(10000,10000); // this is used to fix the flash on IE4. thisWindow.resizeTo(1, 1); thisWindow.resizeTo(1, 1); thisWindow.resizeTo(maxgoldx, thisWindow.document.body.scrollHeight + gBscrollHeight); thisWindow.resizeTo(maxgoldx, thisWindow.document.body.scrollHeight + gBscrollHeight); var miny = thisWindow.document.body.scrollHeight + gBscrollHeight; if (miny > GoldenSize.y) // the popup does not fix in the parent wanted golden area. so try to expand itself as large as it can { thisWindow.resizeTo(maxx , thisWindow.document.body.scrollHeight + gBscrollHeight); thisWindow.resizeTo(maxx , thisWindow.document.body.scrollHeight + gBscrollHeight); miny = thisWindow.document.body.scrollHeight + gBscrollHeight; maxy = gBsClientHeight * gBMaxYOfParent; if (miny > maxy) { // the popup must have a scroll, OK let it be. miny = maxy; size.x = maxx; size.y = maxy; } else { // popup still can fit in the parent area by someway. now we choose the same h/w rate as parent. size.y = miny; // downsize from maxx , now I try to using binary divide. x = maxx; deltax = -maxx/2; //j = 0; while (true) { x = x + deltax; thisWindow.resizeTo(x, miny); thisWindow.resizeTo(x, miny); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * ClientRate; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -gBpermitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //j ++; } size.x = thisWindow.document.body.scrollWidth; //+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight;// + gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. // Handle absurd cases just in case IE flakes // if (size.y < 100) { // size.y = 100; // } } } else { // downsize from maxgoldx , now I try to using binary divide. x = maxgoldx; deltax = -maxgoldx/2; //i = 0; while (true) { x = x + deltax; thisWindow.resizeTo(x, miny); thisWindow.resizeTo(x, miny); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * gBRateH_W; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -gBpermitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //i ++; } size.x = thisWindow.document.body.scrollWidth ;//+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight ;//+ gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. } if ((gbIE4) && (!gbIE5)) { size.x = size.x + 16; //reserve a width for scrollbar (IE 4.0 only) } thisWindow.resizeTo(size.x, size.y); thisWindow.resizeTo(size.x, size.y); return; } function BSSCPopupParentClicked() { BSSCPopupClicked(); return; } function BSSCPopupClicked() { if (!window.gbPopupTimeoutExpired) { return false; } if (gPopupIFrame.window.gbInPopupMenu) { return false; } // Give the user a message about javascript calls through objects. if ((gPopupIFrame.window.event != null) && (gPopupIFrame.window.event.srcElement != null) && (gPopupIFrame.window.event.srcElement.tagName == "A") && (gPopupIFrame.window.event.srcElement.href.indexOf("javascript:") == 0) && (gPopupIFrame.window.event.srcElement.href.indexOf(".") != -1)) { gPopupIFrame.window.event.cancelBubble = true; alert('Hyperlinks to objects do not work in popups.'); return false; } if (gPopupIFrame.document) { gPopupIFrame.document.body.onclick = null; } document.onclick = null; document.onmousedown = null; // Simply hide the popup gPopupDivStyle.visibility = gBsStyVisHide; gPopupIFrame.location.href = gbBlankPageForIFrame; return true; } //trace the mouse over's position for hotspot function BSPSPopupOnMouseOver(event) { if (gBsBrowser.ie4) { window.gnPopupClickX = event.clientX + document.body.scrollLeft; window.gnPopupClickY = event.clientY + document.body.scrollTop; window.gnPopupScreenClickX = event.screenX; window.gnPopupScreenClickY = event.screenY; } else if (gBsBrowser.ns4) { window.gnPopupClickX = event.pageX; window.gnPopupClickY = event.pageY; } } function BSSCHidePopupWindow() { if (window.gPopupWindow != null) { if (gBsBrowser.ns4) { if ((typeof window.gPopupWindow != "undefined") && (!window.gPopupWindow.closed)) { window.gPopupWindow.close(); window.gPopupWindow = null; } } } return; } var gbPopupMenuTimeoutExpired = false; var gbInPopupMenu = false; var gbPopupMenuTopicList = null; ////////////////////////////////////////////////////////////////////////////////////////// // // Popup Menu code // ////////////////////////////////////////////////////////////////////////////////////////// function _WritePopupMenuLayer() { if (gbNav4) { //Do not try to write ininle styles for NS! NS can not handle it and will not stop downloading the html page... document.write("
"); } else { document.write(""); if (gbIE4) { document.write(""); } } } //Define variable arguments as: strTitle, strUrl function PopupMenuTopicEntry() { this.strTitle = PopupMenuTopicEntry.arguments[0]; this.strURL = PopupMenuTopicEntry.arguments[1]; } // If the topic list is set, it is an array of TopicEntry objects (defined in WebHelp3.js) function PopupMenu_SetTopicList(aPopupTopicArray) { gbPopupMenuTopicList = aPopupTopicArray; } //Seek for the bsscright frame function _SeekFrameByName( cRoot, strName ) { if( cRoot == null ) return null; if( cRoot.frames == null ) return null; if( cRoot.frames[strName] != null ) return cRoot.frames[strName]; for (var i=0; i"); wndPopupLinks.document.write(""); var strParaLine = ""; for (var i = 0; i < (argLen - 2) / 2; i++) { strParaLine = ""; strParaLine += "
"); wndPopupLinks.document.close(); window.gbInPopupMenu = true; if (!gbIE) { wndPopupLinks.focus(); } return false; } // Make sure we have reasonable arguments var argLen = fn_arguments.length; if (argLen < 3) { return false; } // Check to see if we only have one target var strTarget = ""; if (((argLen < 5) && ((isNaN(fn_arguments[2])) || (gbPopupMenuTopicList == null))) || ((argLen < 4) && ((!isNaN(fn_arguments[2])) && (gbPopupMenuTopicList != null)))) { // Get the place that we will be putting the topic into var targetDoc = null; if (fn_arguments[1] == '') { targetDoc = window.document; } else { targetDoc = _GetFrameByName( parent, fn_arguments[1] ); if (targetDoc == null) { targetDoc = window.document; } //if (gbIE4) { // targetDoc = eval("top.document.frames['" + fn_arguments[1] + "']"); // } else if (gbNav4) { // targetDoc = eval("window.top." + fn_arguments[1] + ".document"); //} strTarget = "TARGET='" + fn_arguments[1] + "'"; } if (isNaN(fn_arguments[2]) || (gbPopupMenuTopicList == null)) { targetDoc.location.href = fn_arguments[3]; } else { targetDoc.location.href = gbPopupMenuTopicList[fn_arguments[2]].strURL; } return false; } var strMenu = ""; if (gbNav4) { strMenu = ''; } else { strMenu = '
'; } else { strMenu += '' + gbPopupMenuTopicList[fn_arguments[i]].strTitle + ''; } strMenu += ''; if (isNaN(fn_arguments[i]) || (gbPopupMenuTopicList == null)) { i += 2; } else { i += 1; } } strMenu += "
"; if (gbMac) { // totally hack. because ie5 in mac need something. is one of them. mac is mad. strMenu +="
"; } var layerPopup = null; var stylePopup = null; var nEventX = 0; var nEventY = 0; var nWindowWidth = 0; if (gbIE4) { layerPopup = document.all["PopupMenu"]; layerPopup.innerHTML = strMenu; stylePopup = layerPopup.style; _BSPSGetClientSize(); // Get the position of the item causing the event (relative to its parent) //if (gbMac) { if (true) { nEventX = window.event.clientX; nEventY = window.event.clientY; } else { //??? YJ: Can not remember why we calculate envent position by following code... //but it is wrong in a case like: CENTER->P->TABLE: //the offset positions of TABLE, P and CENTER are same (same offsetTop,offsetLeft) //so we get triple times of offset of x and y as we expect... nEventX = window.event.srcElement.offsetLeft - document.body.scrollLeft; nEventY = window.event.srcElement.offsetTop - document.body.scrollTop; // Get the location of the parent var nParentLocX = 0; var nParentLocY = 0; var ParentItem = window.event.srcElement.offsetParent; while (ParentItem != null) { if (ParentItem.offsetLeft) { nParentLocX += ParentItem.offsetLeft; nParentLocY += ParentItem.offsetTop; } ParentItem = ParentItem.parentElement; } // Adjust the location of the item using the location of the parent(s) nEventX += nParentLocX; nEventY += nParentLocY; } if (nEventY + layerPopup.scrollHeight + 10 < gBsClientHeight) { nEventY += document.body.scrollTop + 10; } else { nEventY = (document.body.scrollTop + gBsClientHeight) - layerPopup.scrollHeight - 20; } stylePopup.top = nEventY; if (nEventX + layerPopup.scrollWidth + 20 > gBsClientWidth) { if (gBsClientWidth - layerPopup.scrollWidth < 5) { stylePopup.left = 5; } else { stylePopup.left = gBsClientWidth - layerPopup.scrollWidth - 5; } } else { stylePopup.left = nEventX + document.body.scrollLeft + 20; } stylePopup.visibility = "visible"; document.onclick = PopupMenu_HandleClick; } else if (gbNav4) { layerPopup = document.layers.PopupMenu; layerPopup.visibility = "hide"; stylePopup = layerPopup.document; stylePopup.write(strMenu); stylePopup.close(); var e = fn_arguments[0]; nEventX = e.pageX; nEventY = e.pageY; _BSPSGetClientSize(); if (nEventY + layerPopup.clip.height + 20 < window.pageYOffset + gBsClientHeight) { nEventY += 20; } else { nEventY = gBsClientHeight + window.pageYOffset- layerPopup.clip.height - 20; } layerPopup.top = nEventY; if (nEventX + layerPopup.clip.width + 20 > gBsClientWidth + window.pageXOffset) { if (gBsClientWidth + window.pageXOffset - layerPopup.clip.width < 20) { nEventX = 5; } else { nEventX = gBsClientWidth + window.pageXOffset - layerPopup.clip.width - 20; } } else { nEventX += 20; } layerPopup.left = nEventX; layerPopup.visibility = "show"; // window.captureEvents(Event.CLICK | Event.MOUSEDOWN); window.captureEvents(Event.MOUSEDOWN); // window.onclick = PopupMenu_HandleClick; window.onmousedown = PopupMenu_HandleClick; } window.gbInPopupMenu = true; window.gbPopupMenuTimeoutExpired = false; setTimeout("PopupMenu_Timeout();", 100); return false; } function PopupMenu_Timeout() { window.gbPopupMenuTimeoutExpired = true; } function PopupMenu_Over(e) { if (gbIE4) { e.srcElement.className = "PopupOver"; } else if (gbNav4) { // this.bgColor = "red"; // e.target.document.className = "PopupOver"; } return; } function PopupMenu_Out(e) { if (gbIE4) { e.srcElement.className = "PopupNotOver"; } else if (gbNav4) { this.bgColor = "#f0f0f0"; } return; } function PopupMenu_HandleClick(e) { if (!window.gbPopupMenuTimeoutExpired) { return; } window.gbInPopupMenu = false; if (gbNav4) { // window.releaseEvents(Event.CLICK); window.releaseEvents(Event.MOUSEDOWN); } var layerPopup = null; var stylePopup = null; if (gbIE4) { layerPopup = document.all["PopupMenu"]; stylePopup = layerPopup.style; stylePopup.visibility = "hidden"; } else if (gbNav4) { layerPopup = document.layers.PopupMenu; layerPopup.visibility = "hide"; } return; } // This function should be deleted when all old projects are cleaned up function BSPSWritePopupFrameForIE4() { return false; } ///////////////////////////////////////////////////////////////////// function BSSCPopup_ClickMac() { if ((!DHTMLPopupSupport()) && (gbIE4)) { var bClickOnAnchor = false; var el; if ((window.event != null) && (window.event.srcElement != null)) { el = window.event.srcElement; while (el != null) { if ((el.tagName == "A") || (el.tagName == "AREA")) { bClickOnAnchor = true; break; } if (el.tagName == "BODY") { break; } el = el.parentElement; } } if (BSSCPopup_IsPopup()) { if (!bClickOnAnchor) { parent.window.gPopupWindow = null; self.close(); } } else { bClosePopupWindow = true; if ((bClickOnAnchor) && (el.href) && (el.href.indexOf("javascript:BSSCPopup") != -1)) { bClosePopupWindow = false; } if (bClosePopupWindow) { if (window.gPopupWindow != null) { var strParam = "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=300,width=400"; window.gPopupWindow = window.open("", gstrPopupSecondWindowName,strParam); window.gPopupWindow.close(); window.gPopupWindow = null; } } } } } ////////////////////////////////////////////////////////////////////// _BSPSGetBrowserInfo(); function _BSSCOnLoad() { if (!gbIE4 && !gbNav4) return; // Make everything visible in navigator if (gbNav4) { // Make some special effects items visible for (var iLayer = 0; iLayer < document.layers.length; iLayer++) { document.layers[iLayer].visibility = gBsStyVisShow; document.layers[iLayer].left = 0; } } // Remove the NavBar if necessary RemoveNavBar(); // Don't continue without IE4 if (gbIE4) { HHActivateComponents(); doStaticEffects(); startAnimationSet(0); } } function _BSSCOnUnload() { } function _BSSCOnClick() { if (!gbIE4) return; BSSCPopup_ClickMac(); startNextAnimationSet(); } function _BSSCOnError(message) { if(-1 != message.indexOf("denied") || -1 != message.indexOf("Object required")) return true; } function ResizeBasedonRate(thisWindow, size, rate, maxx, maxy) { x = maxx; y = maxy; deltax = -maxx/2; while (true) { x = x + deltax; thisWindow.resizeTo(x, y); thisWindow.resizeTo(x, y); diffy = thisWindow.document.body.scrollHeight + gBscrollHeight - x * rate; if (diffy > gBpermitYDelta ) // it is higher than wanted, so x need to be wide a little bitter deltax = Math.abs(deltax) /2; else if (diffy < -permitYDelta) // it is shorter than wanted, so x need to be narrow a little bitter deltax = -Math.abs(deltax) /2; else // the y is close enough to wanted. break; if (Math.abs(deltax) < gBpermitXDelta) // the next change is too slight and it can be ignore. break; //j ++; } size.x = thisWindow.document.body.scrollWidth; //+ gBscrollWidth; size.y = thisWindow.document.body.scrollHeight;// + gBscrollHeight; thisWindow.document.body.scroll = 'no'; // At this time we do not want to show scroll any more. so it will looks better a little. } //////////BSSCDHTML Section Embedded Code////////// var s_strAgent = navigator.userAgent.toLowerCase(); var s_nVer = parseInt(navigator.appVersion); var s_bIE = (s_strAgent.indexOf('msie') != -1); var s_bNS = (s_strAgent.indexOf('mozilla') != -1) && ((s_strAgent.indexOf('spoofer') == -1) && (s_strAgent.indexOf('compatible') == -1)); var s_bOpera = (s_strAgent.indexOf('opera') != -1); var s_bIE3Before = ((s_bIE) && (s_nVer <= 2)); var s_bNS3Before = ((s_bNS) && (s_nVer <= 3)); var s_bNS2 = ((s_bNS) && (s_nVer <= 2)); var s_bNS3 = ((s_bNS) && (s_nVer == 3)); var s_bIE300301 = ((s_bIE) && (s_nVer == 2) && ((s_strAgent.indexOf("3.00") != -1)||(s_strAgent.indexOf("3.0a") != -1)||(s_strAgent.indexOf("3.0b")!=-1)||(s_strAgent.indexOf("3.01")!=-1))); var s_bIE302 = ((s_bIE) && (s_nVer == 2) && (s_strAgent.indexOf("3.02") != -1)); function HasExtJs() { if (s_bIE3Before) { return false;} if (s_bNS3Before) { return false;} if (typeof (_BSSCOnLoad) == "undefined"){ return false; } return true; } function BSSCOnLoad() { if (HasExtJs()) { _BSSCOnLoad(); } } function BSSCOnUnload() { if (HasExtJs()) { _BSSCOnUnload(); } } function BSSCOnClick() { if (HasExtJs()) { _BSSCOnClick(); } } function BSSCOnError(message) { if (HasExtJs()) { return _BSSCOnError(message); } } function WritePopupMenuLayer() { if (HasExtJs()) {_WritePopupMenuLayer();} } function BSSCCreatePopupDiv() { if (HasExtJs()) {_BSSCCreatePopupDiv(); } } function BSSCPopup(strURL) { if (HasExtJs()) { _BSSCPopup(strURL); }else{ //Create a temporary window first to ensure the real popup comes up on top var wndTemp = null; if (!s_bNS3) { wndTemp = window.open("", "temp", "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=3,width=4"); } // Create the real popup window var wndPopup = window.open(strURL, "BSSCPopup", "titlebar=no,toolbar=no,status=no,location=no,menubar=no,resizable=yes,scrollbars=yes,height=300,width=400"); // Close the temporary if (!s_bNS3) { wndTemp.close(); } else { wndPopup.focus(); } } } var gbWndTemp = null, gbWndPopupLinks = null; var gbstrParaTotal = ""; function PopupMenu_Invoke() { if (HasExtJs()) { return _PopupMenu_Invoke(PopupMenu_Invoke.arguments); } if (s_bNS3Before || s_bIE3Before ) { var argLen = PopupMenu_Invoke.arguments.length; if (argLen < 5) { window.document.location.href = PopupMenu_Invoke.arguments[3]; return false; } gbWndTemp = null; gbWndPopupLinks = null; gbstrParatotal = ""; for (var i = 0; i < (argLen - 2) / 2; i++) { var strParaLine = ""; if (s_bNS2 || s_bOpera){ strParaLine += "
" strParaLine += PopupMenu_Invoke.arguments[2 * i + 2]; strParaLine += ""; } else { strParaLine += ""); if (s_bNS2 || s_bOpera) { gbWndPopupLinks.document.write(""); } else { //YJ: IE301,302 and NS3.x works fine gbWndPopupLinks.document.write("<"); gbWndPopupLinks.document.write("script>"); gbWndPopupLinks.document.write("function gotoUrl(aUrl) {opener.window.location=aUrl; close();}"); gbWndPopupLinks.document.write("<"); gbWndPopupLinks.document.write("/script>"); } gbWndPopupLinks.document.write(""); gbWndPopupLinks.document.write(gbstrParaTotal); gbWndPopupLinks.document.write(""); gbWndPopupLinks.document.close(); // Close the temporary if (!s_bNS3 && gbWndTemp != null) { gbWndTemp.close(); }else { gbWndPopupLinks.focus(); } return true; } return false; } onload = BSSCOnLoad; document.onclick = BSSCOnClick; onunload = BSSCOnUnload; onerror = BSSCOnError;./Semi-ContinuousVariables_files/img00340.gif000666 000000 000000 00000004302 07755132440 017301 0ustar00000000 000000 GIF89a!,H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ ,È{0cK22˘?.gMzaҨS YάEM96ےc{ݽ-pƓZsK}uկkO}wݿ~yϫ~{_}'Mh d&ȟjmZ RjFnUhSMu8ڇ *܈%؄nR"z$6V㌊h#蘏<\p@ Ӑi$KH(5iܓP$erTV ҕe%G\:ܘd&lidukЛ)'Btjgݞ|m _*P*:A:j3Jz%Zj z*:J$* ٺ%x%Z*{b2;NBl) V&Ur[-lNjnXn;&adi 0u +++5 q/{i r<{ %׉Ϯ.eNIsDޜGrE<@64Ev4IS4N38--uY}5֙i5׵QMd^LjvIe"-ܾM`_v]qWD'];8t_]BK\yoţVWqg-::\mN{Kh;^;[ ?<5g;7ԉѿű[ˏ=8yw6'Zr |d09I(FT$'BMjgdOYT򕰌,gIZ̥.w^d\(72ʩGD'8Fͬ+C=1T4OcV2,CB3m9րr~\';g"Ow&VEM1GE ՇyJR,0z>)ԙJ(Y2hF4GR`c% Avepդ::=r24M 3R]+d~ T4C9*LNtOERBEuWeOV2Um<_m(r*ҖE<ֶ$ ;./IDE/IDE1.gif000666 000000 000000 00000070107 11247233276 011153 0ustar00000000 000000 GIF87aw,! !&&&!(1101!J! Z1 Z18B1$sixr!y!AJAJQZY{aZB!J 1B81R(9Z8JRA!{a!HGHBIRBQZRQBVUVRQcZYsZiscYJcYRdbdeissiswrt (0!&!01(10!410181EB0B8B8BIBIBYBUZIZSBaReRqRiRiRykigq{yZVkYkc{iki{i{q$$3399DDss1{cx{cccss{{Khxai!q!A)I1Q9yqIJQJSTacycy{uwaJqckƊ֌!111ֆs֮RֶsBBRRcs猌眖眜Ɯք瘦画ޭȥ޼Ƶ޵ǔ׽޽Ƽݬޖޞƾަƾ瞌瞔쫜鶭ƶDŽǔϵτ܄ǽץƸXF=0qۻ*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2Q5P͗͛8sɳϟ@ JѣH*]ʴӧPJJիXjӜ5KٳhӪ]˶۷p3Qɛݻx˷߿ LÈ+^̸ǐ#KL˘3k 87ΠCMӨS^ͺk}M۸sͻ Nȓ+_μУKN{νËOӫ}˟Oǿ(h& 6F(Vhfv h~"h(,0ƈ/db8㍜;)d?(8 @PF 2ViXf\v饄bΘdid aj)tzß (i衈&袌6裐F*餔Vj饘f馜v駠*ꨤh&0ETꡱ%Jkz'g&ZĒC& {BFˬ:[춈n+z{(&kmv,~z9L:Y#lNIpNp+,SÈ֊(tkJ*/KFmNJK28|r/CD\4ڻ)PG-5+q7+0<09iqbųs1@)r7~< AЂtjԠ=BAC "&zذ [9YMoJ3L'hF;GQuaM([; tv#HuG(cYv=_˰lbKXv,^"}_ +R_#͂E-c#ZѮ,eY6mmKҒv-fK.VukK:ЍtKZͮvV{BbO)WWt=FIrO ]|+tVJR%.m<ػ&p |;'_M#S&/ ×p}J(N1Wb /0eL8.'@ XHN2$;KL*[Xβ$/`L2;fN6p398:xγ9AYπ4L@΃rlF;ѐ'MJ[Ҙδ7EsӠGMRԨN5=VհgMZӚ>w^MbNf;ЎMj[ζn{AuMrNvnxyη~]{O;/8!N[ϸ7n9t=y<"?Krg-wý=i|5ˍkߜЇNtj{<׾yϓ7K'vԏraO彾:Inut;=EN]}`̓ek]f9ۿ ug}n;^>:Ծwwqs+~U:#g:#or#߼;?z'N/zГ3k@?YF `F P EH@lp l0ehy lٖn ȑjWwQ%Ʀ"$ssk,k+F`AJٍ  JW6>Dpvel lol9ؑ& ĆƗ~ɒ"&ɘ)1 A` ᘏɌkR ܰ k陿 6X ĆcОcll)¦{fytl)l'IG9ɜ&ʸkR0ېڠ )l0Wky<`Z;\б\:֚:Z*lWj*CzȤ<(rکQ;Rxb : (kh`Ʀ ٰ@ t:   lYYU@IPC0vK V:zpBjڲ2k4z]i,sIɋxs tcuiyhƤL~{/& kI@BpA;P<ȍ\ſKj[qG_kbj<<͸ћfyImn@B=D]F}BJ'xP՟kL]VpN-Z^`b=d]f}I}j<O}I)b\=t}]mx |Tւm#P Ձ=o+n؃p=ٞ}؋-o}vP 3 @ֆٚ [SۿM)ǹ"Wu͎)mmϯ}ܽl  ׆ۺ  ]{}M`eݺ)f,ܐݟp 1 }ޝW ܺޗ$1),r >ޜ~<) ŀ\')ޥ3p0n{}n1~˾䏾F]PPu "/5>=uEoP'%O&_5_P*o500 ' * g36*VDNM.`_46&'&/r7?)-.y߉tn/j5  14p_(_WkROުn_鄻o'O,oPl{_r$޺S޹`h?jP?_>bG4(p%KNe NmܘOE6Dؐ Ò'>K1eΤYM9uOA%ZQIT)x*Wc~ M+sS!?ۃ- 0w“pB +B 3pC;t6hAK,ʺC1KpFs1ӣQ=E%X 5´+"w2UJ,rK.K0sL24L4TsM/ J8 ŨTlN^trO,FO>TAi\PΚ`sRJ+RL3t2SP[Ӻ4UnRUuUV[uUXcU=YkV\5W^{mP_JN5XdUv+1XhISZlv[n[pw\r5\tEzu]x㕗KPF^|w_|G] Pw` 6ݪjva#x؝b3֘RqZp韷>瀠u:ˮqW}z^}y~`fPԫJ (&p^@P/ac+Ac`=X1z~HhBP~}_ ]BP5qCDsh N{d_G 6eELD(} +o3bE0ȸCXF>k\Fdrp`f J.ױ D;R4c/ yH\$" FF2Td%-yILfRd'=IPR$e)E9Frq<$6/ 1b@=ωK(JP eBЃFThE-zQfThG=Qp LzeH)ZVpR:;wRTXiz'Pozԛ# =hBԇ"4RiUzUfU[E? BU, A֕UϘ@kTwJP:}a>iTjȯ'\ "vUelcXFle-{YV4aS=T@^y6_%DzVJldm{[V]'[W'DR ]RZ>jc T{Z۽nrKV%oyu K']-#^Mjw׵.1_}J5o |`n|19^'ЍtO^BfwE X#&qM|bX+fq]bX3qmwTp̫ @AD45 ,T;AKA?&@ A>&*A. B |d4+žJCB-d@2A.C7TCCr3˰;q|"3D C |BB)C+E0AB*Ec< ,OQDTcĝжz-K,DDM4^\DǃW$- EX7OE ;+3/:SF4ƉbN|'gT@+FfF Yo4p=z3S#H3|ŋtGD1H",wHKH|Ē,GH KxyHSAjI,AHBF$ȠD@K2I|¯Č Ft԰ ˮ"Eʆ/a|zɡpE1\VUCICɛ\Ƶde4D ,H)3ʑCJۺJsK/Jt<]`eL`v ` ? N]12Xm]>,_aTKba*_+b\?G+N(b@`bf ^``9.ͺF7v '!M=mbcBN- cA `:cFFdD6/N.d3&c:NMGNG>JcEdJadv"XTAF2BRNeIn0νTa\]d_J>ₛ8{ CSM93V^u룄6^N.=l#l5]MlŶkGelu0Flʖ6Z[MՎhTP~Y66Mm\(j35@m"~k>f &0,y ᦺR,GHLT[nͻ&`mLI PMP3ȓ$PPzĺ{mFo.fo.7.`ޮNJ p̰J^ɖtn9]6DpŬ,] /Ԃnn8O⸛e E\/wTUGV'WuBYZ[S^?_`dbb"^?pKv[v?g4cvGt\lhheZSTt;ZC5ntsFR_Vf]؆٪|}Y`%Y 1x]+w|w6tAuWb=-;Vx8 xoUZ[pµx"dz:zVgXwV ZyvxwOx5_Dw^xHU/-Kׅz{yը7tQ{/{?{O{_{o{{{{{{7{olpVOz `x_Xy >zk[Yw'|=yUXeZ;t~p,yyǧW }ݰ/ͣA:ZX Vڃ }Q6ӯgt5~ Vk׉@wĹd=@u_w/&,h B2l!Ĉ'Rh"ƌ1+Ȑ"G,i$ʔ*Wl(z@i<6g!y/-j(ҤJ2m#J%H*֬ZrbǏNǒ-2&O5qUfЭAҭk.޼cVCS]x¯3nbX'IS-[o}J3ТG+` D=DzgӮ52w^֙YZ.n8r%|p⃱Y;qڍ{;x3$óo~/K!סlE{gyف\(%VR"^jh !-}]A7]b"-b$ Dvx-\$G"HAdK=8Xs9gYj%A0>$ը`[e$eA4dRH&EI ()M>d}\ :(\y|j7o7x'gv@tJrt&H*E %x:+thC79ZMjЃx wdjƆlʦZXkq6zy-x[9 @!lIFk!*7)G|2ky[Ѱizj(]ذv0)0B , )F䮞-EZ \Q{ZuP*;c,rҟŌnzƛv{Oiyoա-M)qH691V8ͪ;6s~WRDx]7:6^nD?l9Acc1^9]3z>{17蜟;WgDO#:A8žKO7ndbo}Eo~8)?R? ]>s~}߯9 0w`(@ D (/% Vy~FQĞ7KPp Ұ !wP-XCِ;!HC#KTxD&oK#, _™OrYb`4'χ$cD)>{Hl F5h4GQ8.02/odz]cGEG#݈FHIaXIqr:d7GMF %8FdY Y)l l>d$XDMҒm_$xLR%1752",JU%zѼg=;s)LSe9D ଠ:v`.Ch0Ubl ~T4ڔJM$t6U4^C zd?&=)JSҕ.})Lc*Ӕ>,4U8q >H%*ԡV?UINJN%KP*թ"ĨO5IR7J6^mS-oGձu VH:Ƈl͚h}k ugZ7µѲ\*Xy7I} *r`P+-E>˿>t#mh%"ٯRv}2[r^cΘslDzFd^m a ۨ6.n9D=mGZ!ƽ*rK徕 <+M]P9>NQt/7ׂ%' E{ϓ499_tx"}jxV^ռ,.iGaVfcÿ!.y6tI9̇<ةɄ)T +433]#')&ep ^wӇ#$KBS7HuSKr?n?4'̽u&%8_Yc.[V3/k$b)beD/ټ:[YrcLy$ִ9f.tΈ5ph8 ]7쯀ӘGu9X]Sݖg(J'8 fI^G `)vox17H=WwPmn־Эn+ٷhu \7Iɢ{8#.S/j]mKkWzt,Ixpv GnvC浪O=Yn%7 ;tLvɵt}R:ӧkY/9׻~ruӞ2T Gپ;]Mwzw}sǻem!?x}[j>5WC k.wﻹnt/]G z':eNj=wdh᳈ u{tZ)O!o}ͷ=I_?Ga~H;[⓿P(C֋G}~DMy+bXב]յYezօ~` Ʌa$[^ >ưUk` ŤYzLgO!!P ^` Bc`&j<\zNIxVT`QaF!ab DaYu!A - 1!aTuቴa"^ i$BG:ގ !abF#B*b+ja-N +Z.bϹ"S V(b(U) bja^3*"/b,>'.,Bf/ڡ5bqz\W%,Z,22";.-ʣ2c>5R0^S1::z:n+b>ҢB"d-*$>U8#>n 5cBcd4 ld"`#q;F"/ "N+BcJc*c"&_5fK`GΒG]E`JNROZO˄ɨ$P%c%+%ebDŽM@eHZYV2΁\ S eЈ%Jeᜥ^FZ.R٢, t%ɵ| |] YN^Nfc%!%fI\f̲Ѐ`>&T%Pj~efj `vPgiFed%InE,2"QoLfBDp8NV9"VaqfΦg pfn& W#7f`xg xMk~k#tG`G c&u"ƌ朔fv2PgL.FxgBgrPgݛhb\'b'R$އ̤;b4xc~#.K%$'k-(xcFjZw6$?b=f#;Rw 'J^B,/bFOs!4nʊ)lz*hmX7:%*ii`D)zN)xUi (ni4ќCNd#pb=fcK2i;:"ViOU6*RT)mXL2*$DjjBrѕNj M(j *Kh䡪toVcjFLUl\,N.ǾDzȆ^,ɚPʪY˾O,UҬNO,.O mmN*-18Ӣ쵎n-v~-؆؎-ٖٞ-ڦڮ-۶۾mצk IN m^ZR*&M-Pߒs+.^k". !JnnJzaf#v.~..rnǕx(Lb^a nb !FD o(.an!Ƿ(2/1:F o`jhG5hƩp~4nv.:J"%/%¨ڇ~Ljp$0+\rn癣/I;0H[KR G0 pZ6jpp0 G 0/00pư0 /M p ;0 k?,/c'J1o"oq o~݄IJ nVqqPˆjwJ0 OZVV!3Zj#g[$$S2^2e rr'!r(grmrr1*(' )r#r,*+S-1.rr0,L-#3x(2'(11o.4Q0OV3Z0f!W2rz"9k93: :.8s1m^:X@-;;/Zo"$Dj6]39ŝcIjyZk(UGm$:*)"Lvcctk+u=YuEZ6'F$,;sk"/icOxaYd{;;w;vmg;Qph뇼)F*[(hao{>wP#Z*y+<VoҺB%j{ggz͚U{T<_<:#sg=b|$C o=[8e"EtՃU8nxzAw+ͻ,k}EۻcQ=X}{LT~P~ ~+$ŧEn8{@~*gIkוc9]y>}>ķMWSҽz>>|~<@:S_>Zq_UC|;zu ?>i<6zOzat϶w/(ósiփSy $8aB 6t%ΫXѢBRG 1%Ǒ&YNTRG!\8]Lu'uۇ}f}~وw? {'N.z6ܓ^ͦ>)ftſ?߫~t3џwg?z_-_u#?,&k5 )2=s  ~ЂAuv TaQ.HBR̄CVXC9LW _7C8}@TD\tH۔HA&:*VW EuOEHF7ˌCcqFnG? ƲMs$N8>< *7EJ#ɔMҍ%1HMR`$@IFQ1)Jb+̒ópi1]f[%`L iŬ1L-37D 4{&MQӉ֤6'01Mg)As[O(C "w UC1к^"6'oh42 ƣ턨HYjJ+=]KQ'j*:O/S5 ,rsWU 5EYUɕԫ-*WN//niZWΕdu=^kN Y~%!`G&؜ݕZk,Ŏs, ٤M`e3هmk@/抴4PK>Ӱ |-b6aQm_ZV]o ff[]^vrp1MK/y[_Rsk_r*~G70f\020% H v׆9Y7qH\b֞81ΊbG2ֱ`h-ߘdqX3̿ټ9SA21dYe/a\f3iVf7Slyg;yr{Qu(- ]hCщVhG?ґ)]iK_ӌgYeI]jSթVYjWֱi]k[ׯ;-,Y]lcVlg?і]mkKmo]nsVt_m"_ico Wbp08N,z7{VqمI^1vYr=(Q]^sC9rs\9ʮ۲[IWBҩ^u6~ 5uYOvN],xq^w{=y; N'Wʧ=yx|Ez7W$Oy[/iyӾpy{ԯ[^y=O>|/?W~}K_W<.|_e϶s#ڿO}>ӟ|4Oo\(/O/?2pCP9aSPW[U^PpkCe{oGr4v0 [p 33, P P ǰoRNP א P-[q)z?Mc1aC*/3Q7;?CQGK[ ^Qgюna!a5$WWqQ!t1}1wXQV?S&by1c1NZq 'NQ!Un T` 1PtV!3R#L@ ,&+rf7R%WE:RfBa` QQ%w'#$oR{(6ֱ M2'/2%*2-$Q*+*"e),R()Q'-'*--+.{2.ݑ./2/1ÞJ sJ_')lc21B,H#2!6S3/O:4Y0ESF.Ă4s55E531mVs2Ks,bs-s155_34(36K3`38S5YsF@73kENvn+U<9a7:s<]3>c=a>sFn9S??s; 49<_6~S<379?tEM6s7AtNtFeA3:kt6E5c8 b*533GtA=5T9BmAT)XCIH?J/FݢD3{S7_tI?u4<4\")22TE۴BqT7T=qLITAS1H{NtC7CTO5PIWIKEPi35tKN@{Nas?9GtDuT=etP4TW?a2ٔBKkVN44TE4ZTHCT@]u?O5J=S!uQW5uYuQZY95ܔZ'UZtXZ3YAuLURXZEXL{REVUV];>[>a]QPu\YW1`!ZY1bs[[U`/aP67U[UUS5O[ Wtf_=cteC_Z 6ZSA`qh9cYaE6Ad]14Y3cf#6h=vS'6ickPQVNUŶc5V!}LS7]]6:V\4LUjoon45pL5XT4ŕGqsFIGW۔dpFWXttdj۳p}Zw6up#pE+wJE7_60ARixwSZyxrOwy^/ۤ{z2{wBW||iu|W=Qi&i57A!baÃ{6ge)~)rDwqaԇK)v/5^U^}raD8UYN]7uK7-vQ8iU54_sUtXin{sSgUe-M5TXjUHkZEflRgkvhxYQ58t}Y#jP_urXW/kYr717[L;5l/0u6ovM%6sQ@􊻵ouY`eY_3[isIy#?bCYc֐CEeVcy+َ3Yd9Nmys?eXvd9/ϔY1֔?X?oauMُs=s~5ء6#yz%t;qkwXu7X[ZXpMJa3׸o67SwkTTI?T{x{7wtcV.㖄XQWy'ڭ嚮z:1)R!^TD -;mzr%7DIEv WxDL,%3Zn@5ɇ2ϊ+Uw%UjOY\Zr[XDx^X_g8rEmKX5JxDcuUݻ؀8w[S~m9q{7uciצ%1{)eV/zǹL#?yV]YVْx ڷAzgA7\甒ZYIkٛS5Ȯ?uٲ':56[dCdW f“<ʏVWYv#@-{9i)8kQr{ɷ՗ɳ9vUǫʱZӵ;zۙiɥͭo9s}^QTsXW׹p~;|y4[ނUIS=@YMXۨSum|j =ԹQ]7eٹ]H1K#͝Wi&NsM93ҥL:} 5ԩTZ:֭u;zY.ZxԪ=+lHtD#ޙw/ƾ nɒi.WpQ +Y`-_T|3e|8pӨIf׈-kYɚX{ <]r5lرeM:d[yog˛?>}Z+ZϩU|~H`8 {]}sf5_[ tfaba[fb"H" `|E[c2Hc6ވo'2H[HdFdJ.Ԏ܊kIL^eZne:bQt/zfjf#:Hqgz0%) diԆQ}8"b蘢(5uJzU^$yY㦾 )z(j{ *di6j~[^AFۮ5Ԥ#i߰;-*MZ]SJx6[wJTU~ĪX>tBBq]n"KN>AŻovRmoB*{0cskΊmqȤN۬fɫ5n|, Xˆ.vma2(kƲ=+m2ЇJ+gRBgtFdki! >̯m/57-睶owmݓlx6E波I$om'.G9][6HGJX }'\ƺ䬇]:2okm3:z]3ǎ[ׯh脖^%Bߟp{.ٶs.|_yS>=]}[x%.x5Oۿgl-Ft~9M#\Bm/ L:yC z4O:r6Pß M"^_e9M\!Έv*1k8>1®jyȬHMqg fW#3 aAYƬ16uG=r5]zǼXm CDTb:% <ջQ+gSj+C5\r@&-tKcG+_Ct4eJsԴJ4yf~Pæ7 p)ڄU/ljts,'/Kvs' 6.Ӟ?Y |2l"Q2P~@ @S)nv.9 ji:PC EFQTzEgχtlj Ɠњ*LIx)Qfi2%)v8.~gZ(U2#t;@+ʭHRyˍ; %9&ɲ 03eUQjRծ8NN7SrU@^1f|IO'9jZ Y+ DuxE&Q՝Y"4rajV,ڞ$BR~Mi@@L,"n-*Piؼ&׸mmJ~yؓKtZӊ4 ߖ]KYE9, 7o wpkZ6ya٧e4gXDVǹO?1}׼'b!ͭbs\* e{^e>њ۰;bX"b y8S4U^F!u1Jkn/toL7.S>,7eG^98M:sYdN[+ʥul6h$5^Ug1R듌,0I~TV~KM;Ҷ.e}Ș;& i驅h{5{s&LOfqyݍn;ٔn=plƼ'i{{ ?coE  mFT?Nk8܃ >[M/'3^|D/щ_|ZD-#RSԏޥW'R/s],C9Rceھp駄hA[ 5Wu@,Vv ;^oֈ"ޫ$dO~/KwϱmJԓ>٘&40欰MS&JXwijd򞕛J.>aw_hgI 4._nݦFqv~%_9CWc@~DTedBx}tge^eG4@Z&m kYf|6D_Q=8]2~=ghdIWE\l`âbG17+>m#71evn}WBS/8I?ӁJQφ _L;c7-f8g{F9Q$6Hy=&VceAuvJ^&b`g>v]ȄwH?(x]vh66h=X}SHdCH\|chG6H]xt~r5cdž$')JӖiӗHX#Fjyek&jY&ld|vv>TjAvuEml1sG9jj8HsWPP?hPZҀhttOL1BuRՎX*Honܖ}8ۘIF00 qIY0 yXp(I%ɍ(ng/ @ 3Аɒ'Q=ɑ (\J#hvx Ք+!S7g+)gQy8[&H]y3Guy姖 b 6\jFaycQC;DxmE9Oztڒ Y1f?-Gl[ZefȢI &VH奘VduZ)gZDٵZ{JaZJ8:(4hXXIJxksz̈^јfjlǧiͶkT:L&LjʪŊ:':?)M#Ȭ|ƔA*LcTuӪ˚7:*犮DYMzJZMj:KDxOZuS1RUaRM1§XHLy gX$] CVyFDK8V %{4fjyGv ղIet^CٜΖ}|4}$kHY|ٹlęY٢+yF 蜪i`:dZyC'ED82+f8z^_hK]YgꖃSxKC oۮ}}88P9kz MĘ J-Vap˯XY\[|`l&&1Igo|#blpLu\Ji$S|v}Px'~Lȅr<ȋ|\0 ɐƔڱə  i ǗɥlS* Q,b|ʳLM30e ˀ9˿T l̳ll0\$˃Lۼj|͕,|ͣ,vly,ɼ BLfΨe  Ol  -Mm !-#M%m'),n,-3My*9;=? A-CMB5.xHHPSMUmWY[> OԞGMg[!]mo q-s'`t"L[Q= 0ؕt؋؍؏ Z= wa"`20ֆm00 =щ٫ڭگ ۬*pxz`&`mm=30 =3p-Ѫ $=۝Mɕ}yZ  V-]ޣPRpހ)+ 05 0=?c ǝǶ٭OQ0eT [ݶAa.c` }}/׾q.s WMnsz. :N.sm^!~'L.烎陮>Ԗ =en~7]jKMdQ빮h .Nnǎɮ.N- mLB .Nn/Oo _m:.6?!/#O%o')+-/1/3O5o79;=?>/O< IKMOQ/SOUoWY[]_a/cOK?E|moq/sOuow{}/O|{/Oo{A/?ovl/Oo/Oŏɯoj/Ooirwa}ޯu)n< DPB hp`A VcC=*|HcČ/V\Jy(?SL5my:=ٓɒ-YD4IMTU.ujTbK ZEUkSeVĒ*2mlZuޥ3{ ] ?,Ulb ;5Un6G+yk+r3ZВ3wFZUA,jϞ&J;gxm ގ<-4eŭ_M> -ݔ'o,-|A]xrO?u[/?@z'z-@l;ϣkOB?"<6 DVO/,1>41FA{QƆ(3Q&G,%? ıTt<2H+5Ԏh;ÛJp  R cˤȖGޤC4 V$QM?cLP@'F2 ?cM; + +(דSO|S<5%M,kSJW]P/od4cVYm 5uWvK_51MhV]ŕY[E6 VAWzPZy[V]\Jն\ue]w߅7^y祷^{7_}_8`&`F8afa/'b/8c7c?9dG&dOF9eWfe_9fM.tfo9gwg:h&fbF:ifi:j}yj:kkk&lF;mVm߆;n^';o,o|BtϿ r\$ PރF(Vhf6.($(.N,pdΌ4h4fG@@)dDH&L6PZD:TiXfie:J7`ɥp̙hhr˜tIxgE։ ~ (tg蟂2h.h>:颉(*I覘z::jV 覚"zk+k&u:Ae^s:e%)dh9s̸ǘ-N!Dt@g*k",j[0KW,[,0_¬* $l(2F򷸴|e -<|P "D'[A ֣ད4lqTG2|+մVrYeugoݱ/ tmx߀7|3C)s$A,W[ϢJ#PKmם6v髦q hc 饽.0W+<Ƕb+?g[+~[ 1OL䓻~5h3 v0Dx&8Aj4`%HVp`% ,5zPS!IB06!Q 0:D x*!$7&:PH*ZX̢E):apmAhE41xG G91j_1>xB_=6?)NE!}Cꐈ'$82)JZ0 "r0 ;D!/sJT򖦌 k.L2f:N(NkE4t 6X :tC Ԥ=)G3QjGEZҙԥ5=iL5R48PJԢHMRԦ:P%aXj C'sUͪXjֳǨZת^խHJct@ngC"5(K!JR6iJw ؟Vt]N/*SNVmEӐ”MeRV6-C7 FlgKֶN@ǡ*ָ* ^Enw[6`\`etq׆kCZA IK͊WS%obիPnQ[׼9(yKZ,x;WE0k+gSΰ7a?!DE pGgm fLcfksifT. vH~,Sa&'yNm:'[Xβ;yp0EL0wH6?g%:x޲Z>6MB jG 3ыt:]Odbδ7Lgm^ Mj=ԨrSV0fMZִ6C+k\׺%<b_f;ЎMmdζn{MrNvMoy4η~Nܾ77;'N[ϸ7{ GN(OW07,o2Ϲw@ЇN/;PԧN[GW{`N[]L7pk#Tx>Y./剟N[ ;.S< 5> ?9a.z|}ǼgO;\\S'}/ʑw;7;{<|?z;'_<~s|~}XHt }7ǀ 'h77xg}!؀WW++$x284r hH~X,z')ȁG?yw7~FEJWN85\؅85uԧ{9g}>XrOZ؆W+؄ehGqK؃Xv؇txqV腄Xx{`tudGxPȆ~wX\} Dɵ4H,r,0,'@ wB 9P|,qȥsEȈm MHm9웻ɛmyr3sImy;p@rO=rQ-P]>@Ks[MyM=Sra rcMV-re}j=iqoqq-g-ml}8z-yׂ=؄qZ7Y،؎}q؈=ٍؘْMْ}ٚڢ֜؞ؠ=ڪ[\ړmsڬ=۴=صۼ-ۖ=ڒ0]}ȝʽ=ܽܳw-ێ- K ]y ۟p=]}ٽv] }  P0  v]`UWt'>t݀P (.v xgBWKt2qq}*sߠ ^p / })]m|9s5~&Wws;> h Q+asLTxO=.x .0.s~}yg+^] . n~^6 r~O7n*i.)9(^+y9i)* ." gP >ntN^SJ~ }^ߞGS+/֑02 1`j>(!(>0.Nw>^݉[;y9o+ P P )&_nbho.Y'B/D?qC<D_^opL}N{P5 /af_e*kos V^S[\X5(?@WUȯbU>@/ΟU_ȿگ_P? @  ܮXP  .4hP<%NXE5nG!E$YI)Udc0r1c!(3f0ip~ zOI](ӦLP*yt" orڔUR&ͺѥ"ͥ3Rd͖WmRI v4.%r+Nʇ& @?tgСE&]iaڤY&9Y%9mśާy*m;,MN`oVoZ>}KuT:&{N'Z^sgYND7JGtC`5s"֣5Kd0;χ?}l fveCӦv}mͮ mfK^Ak'[6w=_ 6p=jZq?gM7ȡ)g(Ԍ`-wGnt!Mir01f8@N:]^Ķ }KG\˃+J4Džr7OqⲢF'.䑎a'򤇝Kv 2e@1_#v}Q{!p#]t?rw&hQl; Mg|3f&ӻsN{Xl爆_Q z݉q<ϑ;^}/A;Q'~L3z_g_>Fg7%~_g~_q?bKv?z(@<@L@\@l@|@\@@ @@ ?ȫ8<; @,Ay8A,\ A@Bzc2A A@BɃ LB%4\BlB't@$B*\$#A#B-tA <@.4/t*,B64A(D@C'|C/%B3Bz6C Cz$D%:\B=\DU݃<@Dd@C4$C CFr=DDRJ$C 0DV"PԿ5$EYT@L,D;TZ9lE^ġWTCEa<@S$E[T^\TCa\<;DcDfrDhBDCEl@qXI94I,9J웬,̛\K ʮ,PJ\kә¹DPKNKT5K!KLҜL:ѥMMMMN!NߜMm),O@OA TBTC-ԋӺSEmnbTGUTITDTKTWQ,TMMTTPUUR=2UT]UQUV}UqUXUZUU\UU^ՅԼ8`-VUcMVAVemaVgVˁViȡVkVVmVo WWq-׻!WsMVUWw]Vv}WzexeOW}QWt X~Tb-X]}mXWwXUWXsXWXoXVYk-YVMYg]YUV}YcYVY^YUYZYU ZVZEU=ZRMZUmZM}ZTZIZuTZEZSZ8 [eS-[1=[mR]m[Q[ [mP[[O[[у\\ĥN]W`lO}X}Ý\n\-v\}m\-M,]}LM\]]T5MWם]]J]Ol]%Jޟ,^IM^\^H}^^G^z^EG^m^eF ^_mE=_OL_eDm_=|_5C*_eNM-~U-`<`?^``tSm` F: `` 8 `w`5aQaOT~a6aV3-aV6Fa!0".bR b$#^kb'>0(bb*/+bSb-f[.b0[1-c3[4N]c6[7~c9&K|:cu=~,dBS:>4dE*Fn"LdHFNId|dKf)LPdNNOddQ~P.$eTn%U^I=eWVeEeZTXee]>^^ee`n^af-fc^dNf]ff^g~ffi^jffl._mffo^_pggr_s>gMgu_vng\ygez{V}g}N`~gg~`yぎ|>IhnZhhh`hh.ah.?cĊ>^ iani~iai&i%`F#KifjjF>jxUIkVnkbkFm}kݼ`kDklkvd>HlV^kȎLlNɾllͶl^W3>mzImՖnmδl~ҎَVۦݾ;^ϒ5{m>>mV'm羢ndnNn2nnoo.o>oNofn-mVҶ/oooooV.Q;35?g3_p p p p p66O4ĭq/q? Bqoqq/7qqa/q r!.)!Or%_r&"'nr)r*G'7#*r.r2 $r2/s3078sc3s8sIsI7?s=s>G :P3|7"7|GR6b|׿ȗ|w||,>̏z7(ʟpc |~}R|X@W}|pI_7\7mB~{O8O>?|o+?6|Џ}^|ˇpҧow|WoS=Ikp *\p!ƌ7r#Ȑ"G,i$ʔ*Wl%̘2gҬi&Μ:wDPhaʼn !JX ϨRRj*֬ZrGA-z4B}z,ܸrҭk.޼z];QIUv/Ċ3n1}|vN13ТG.r2YC%-gӲ5FmcĹン﫨-Ⱥ׆c|syzGlZ9t}qsx,GӃEx_wa߄մ!z&5^QIbI~GV硸BRef`GtcKLJNN䊸XaDE`\f)ie#)e>&EQ8抵"z(2*xaHނ0#Yh*Uj)XXߥ`h(cfJ#{~'"xv)f%ʢJy"1j{:V.eFg0}H%Wne|ګem*, S Z.먈.f*+{뼨R.ʋk*=R+`Bj-nk 0'fgn;Kp@r9/|ɢLEtUGCs:3:#y yrAl.|uz7Z볹 eR]roy߷D8olae gN8sg937Ƭ]HޭԎt۹a.~/=Q+ok3oϴw&(O 9***fD; 5˹([dִ=T7Vl (u0=,B.\EO09_JG-kMM>a!$8֏vx6N|()'~HG6%,"(1q#GL_ׇe|#(GǜQ[N=~t)nQ#"E!)IRqbj-qMt'-)Jra$yƫtV %]Z3Y0S\V7px) 5IkR R+eZ~gAlM[i@&Zh0)8eF3gJInĞYrbE=`1H\ש k0|/g~ѥ Є TDitzӔ(z,6 | VTCTIQK}~i /_dz.rY57ڸtU{6ib؝ICS{F/m:%.q9;]NƦ87֡v)>*pS3ޤj5{ 67u=xo|:AVAYUe[ kX˂Ƭ??M4uo#NA{XX5#SGgBֹ`krw_t]o +/-W&5b\ك6Y /(SDԿ]%<{U mo=?Վ{ſ|";e<g/38N AIX>.(z"%6$,er3 7{TZ^ܴf>e4nq9ӹΞ~̛,+}MH2j>s-c ƅvn=x{Bnol<]{"Om~½Uz=_p5oU '%}kx/خAGxqM궝-e~sr~@rm]-mbOՂޯ!I8}}Z{$pE՚qXҗ6a͛umXd7guGJEm^GVӕ}m5#9_u9PEZ v`  Op !L&.H !>!.F[5Z zB a*1_ؘRmlZ!#ma)!h3 ~NH HI6EK"Q`[b1i͐]b^ ٍΥlu`eګYv5^ULIU܇ x.URkZ+چaX,t!oE E^1N$&] Qޕ^ ңU>b62mcݔ`/KUuW$ D1&V%dN&e !?aen&gZf7`fbg&iJd&joji`cvkbzEmV-`TԠՁX)cRnZmf]Br绔#0$pd xWr& ƞelURss!vb ׆ [o]w"I`.iAgx,fa ̊I ]_&^egWvmK9\`=MYn\ bЅJeD%fG&h5_dtJFΎgI}gOyR!X|zr]'\jr(|jUMuL.)ym|'\I'}Nޱ\Ɲ^yOb'DVյq#QCVU)qꅝbW|<\;e4&)EҍNzf=+)pF VEQ㤺dDZi2šZA +jFƨj$m2Mk-$؞mkPPB$>bd\jP$c3uQciƦML!TNg_^a2bLfݰ2,J%<:*I-b" [qi#bZ(Ğ!쁘-]Z[b&"VRcj]R Qy~by6kN-f-?j-؆^\ؖnٞڮmThJlƦ:%-iqbX`.5g--VZ曰J=M=Ӧg|F.9-6>'(bF䶞n~+]֨6.uM *lTEc)ֳU,H1.WMݘܻQ(b"Xthn \Z[v^&\讒bݵaT.,_KB).37s?A?otAOtH PE>C74t7ƚ}#0~PZBB WܩQh&0FWr1*kWC:.0OF*{SÜTy('^1Cv8:嵔uvS.PF/sQWo5+8f&p>o50f,ɔXj34l{''5z `OzH;nB;j4A=v;;F ĀO'` SwF&x7oR@X;:3i{y淇z'7|+'[Y RWS7~59esl|+<)ז-;/|=8v~pϩryQo 8K}8-qܔgJrgZ<#v~Ez^d?k;[iG.7By;}z X \!Ĉ'6X"B 6cF!#n,1EI<%K)9T9fN;yhP}w\ntަzzuWsă&ARG22TMgx͵8 [Vo]5 - -Jo)Vᾍx-Yl朑 ,BYvPF*eԮ[f;Xרb.~ܠ_n?-㋛OO}1tګG_s_ɽ-SVqџW;z=RZ;K$ˎ" [bې=iyz')pjv7em5‘}6Hي6oKQXԊ*2< Ē. 0 qOME'j1J`8<ē$dr*5r+)<D]FeOmC1@{B|N=PE5R3t5 jQ]}XeVJ&3tW `bUIJ565X:lmh}l?QU}mFOH;?52^^ KvnO]8gY\Lzt8Ocߞ60*S NV`eu-Xȥ1[0NtCb-k2ŔYCRkk>R:驯ͪ2D =5>%Q[YKog`4U^]L%qpwי{O]rW;yrKvD{<[R?On_g<@rthtU2r1gX>4a!yabW@UxCG sh.WC ;ԢG;Hp{:qCzD7Pi\ G 9 P6-Yhjr> 2lQSv " PdxIy%{q_a81 WԈ)6GK_K@Lj"#`lSI]FєfIw"Ji}89jǬ%7or9t"sd|.Obg1u n BPh,:}F9J(_;;ZRZSi=0'RNUka7V,JWd` [X 3\?>u ءΕf9VS%E;[ZӚ]zZ׾ְll"R̶YUXVJ%ph"Ur\Rѕt[]^v]~x[^Uz^v{6ZDj_ \` V`?׵Q[U*}G* I\b)VYb1i\c9ycX0IE rIVBc'?Q\e+_Yid Y%-m2s6.O5G,n2\g;yr\1Qy@ 8hs~9iOԡ<`f˂y33:Dy$@S)/C9GSD;T6D1E/19E!#{r 23 SrB+)r$Do48+T$s@#Hͳ8ْ"OE1GJu2KcrKSSJ4%TLJKSLQ2MKLt_TNB[MwMLOU4P8 PQUQQQR#UR'R+R/S3US7S;S?TCUTGTKuRŠdLUUWU[U_VcUVgVkVoW1U%W{WXUXXX5VwYYYZUZXZ[U[[[mZU\Ǖ\\]Uŀ]]^U^^^_U___`V`` `aVaaab#_b+b/c3Vc7c;c?dCVdGdKdOeSVeWe[e_fcVfg8;./IDE/IDE3.gif000666 000000 000000 00000046603 11247233440 011152 0ustar00000000 000000 GIF87aw,! !&&&!(1101181989!J! Z1 Z18B1$sixr!y!AJY{aZB!J 1B81R(9Z8JRA!{a!BABJIJBIXBQZRQBUUVRQcZYsZiscYJcYRdbdeissiswrt (0!&!01(10!410181EB0B8B8BIBIBYBUZIZSBaYhZqRqRiRiRykicqix{yZVkYkc{iki{i{q$$3399DDss)k{scx{cccss{ai!q!A)I1Q9yqIJQJSTacycy{uwaJqckƊ֌!111ֆs֮RֶsBBRRcs猌眖眜ƛ͜ք瘦画ޭȥݼƵ޵ǔ׽޽ƻڬޖޞƾަƾ瞌瞔쫜箥維ᄉƶDŽǔϵτ܄ǽץXF=@0q]*\ȰÇ#JHŋ3jȱǏ CIɓ(S\R!: XB͛8sɳϟ@ JѣH*]ʴӧPJJիXjݩΗ [ÊKٳhӪ]˶۷PKݻx˷_` LÈ+;oǐ#KLz3k̹1MӨSװcF[/۸sͻ Nȓ+_μУKNإBä{Gvӓić˟'޵w!@d'h& 6MK:VhVI nhc(≝o!4H@%<@)dMΑH&HӄmE2)NA;d\ve;˘dIhf7 n 'dftީrgvg9yΙ'F*I碈::~R:i 碊Byjwb꫰*무j뭸eNa&cd&,$09s̴ X,R{ֳ'Ц辙z饬;*oJ˫Λn*;7/+WlgLvl.'ɂC,8Kl.*#Ă߆;n=[ *4Hk M{2=J[u s^k,dmٯ*ll-3N2| 1 뀫z3Ό32(O pXO ) {)B\р [j^4/LNG5m'|s<'7vR=8Wcb+>/~_?ߜG@_ѧ6 ؿ Ѐ̠"D+(B2 KhB Z0#̟@8̡w@ H"HƑ&:Q [HqL|KbYw\hE}wHȇ0zkc1>pP}:SșnB 4! 'HЏ= !Bޏ1l%9". 7̤(#I,gIZ%Pm!,I9 ^2ax4 ,49:8FҹtsT7IyӞg=O}3?w4Bυ6t(B#jЁ Tu>P>G#QRԣ'HҖ0LgJӚ8ͩN]:rPʂݐc OԢ1@ժA*8Xzg=8̤e(<-Oԭ+=(G'ZҴlkEIP֕{=:ה.TmDVԯbIؼuͬf7z:UnUO@*0DKZ3Ajmmwˌs,kC94 DV*WQe\KO&5K:׹#U'sX-,rFW҅oeӪ]aQL`S!D{ |N_Ϻ=ew8mN \kwp]^;~o'|;񐏼waYwm~w~]<? 7='ֻ蕿Wuc~kG{xVօ?pU|XȁG~#8xX{؄2|}hWX'腉r>'Ghvvr mq(xX1(،s8X֘ڸnsqy׍8X8+g긎؎ 8X V r8(y(oI)؍!p-p{|7fDw44` (0# qlmV @ 2y 0 6YXo`oǐ Ion7oKoyI9QIo}viЕ^`b9dYfy4ogٖni) .F @ FIop o0 Y YICE9y1oSo!zl& ]9Yyi o Y 0ol wYpМ9oK9oPi o?٘vIT FiHyVH)9oU)'Wyonٟ94 Y9I9oU0ְ ۠  o9 [0epepoIə91 )|hoɔioOɔ){#y9iH*J * V Jp  @ v X@dЦdV Џ&֢ oS)4*~5ڧoMo?oEzN:9P`pZ@o  0 o ;nf7`jzo_on0v ox:ozj|ڙ)L9RB}p}lQٚZIC5Mjʎ :Zoʥtگ6 `:`GbJ % ouɚoZ*JJYoAJɉrr8voʮ0*T搜  Pz 0 {p H@ /P VF=7F%^oYf)6:2ZF;ʶz`zg{k}˭e⺚j+TF 8刊lPK@;؀ {` 3I s[WF@\_pcof[hkojt n9v|(}s|l;-\92`[s > o@ F P`oY@ @ ((-0>p%  _dK Z㩶o NɼGȋ7'Uiy ׻tUo0 o p$poXпs.>n  9Kûu gx*ۺ]Vtnp0o@`íp=L@P+@ħк(R 99żUl rƎ'xջɊX[o|ʁxG'o1lwplz`u0v8] 9pPmɼ;o\q́w\}y\G'Ψ<e

&)n7q=v}z"N a* fh  2 ;~2k.֬hr.(9'0{1PPO~*^v~P-00 l`Y*h>,' lp)B>hI봞z^IoK{">n!>캾 qiG)^ y] 10 PNfNnr~~0M^|^_ 쯉qϞ @1@! k^y* llﰉ>^rE^砎:onu.Hn]4N2/#<9ZE @`2@/1:*n>L.`%TsT?TB~^]HMTiW//LE1 ( +Z4zmnۀ?T2_)o?T(/[KnʏoZ_B4Ń'#B8sp* p%0"E/^(G,#YI)UdK1eΤYM9uOAm #Wh=E9\%N5GN7zdWYYWlY`;<=k]ѪKYKNfTyX]9~qqؐN$+,B@`+(b:+"fkرeϦ]6NI&])Vn*b{eغv0ٵox"qď.t[;O,rPƱDn J$cnT@TpAt"g7z{/"j*-#@1<Q"hE3EN"X2 M<1)ɪMI_~VH[lJ/2B,rK.܌'2ɴPȉj898fM>Ӽ9=S :` 6ZQ\\)4+RL3tS)1?=7?KtRTJOV[N0b%oSSR24 &x7I[RNUvYfuvO? QClEcUnSJQ[m E̓*b8a@#Udw^z뵗h˜L_x` 6`Wv;-Aa# 'bwc;|A4a$3dSVye[vdcekfsyg{gzh6hVziW.+t%Yajzkk{l6l~zdKNm{nn{Sm|p 7pW|f{ddr+r3|s;sC}tK7tSW}u[wuc}vkvq\ZWq~x7x}w}{7w~Oz~{_wQ}G~}w}no%_{/|ϻ_%P d ԧ"i,KՒAW]#$a MZ;`EwdX,:܋nxB QC|Q z@KdbD(FQK D\QSb=,~QF4b1c|bF8ƑF6t|ZC^͏8XCV Rdd#GǨ/qSdiȵJ0} ? Ntd)MyAp)?XHNbZ#&hH\ɕe/})7UJis%ob^z,]RӤ&ׂiDz yD uRoe&IN4uNlcg=yϝLyu\!+͓x3:Nd7:DhE-zQ{GI6"D1zRT]64r6QӐԦ8i9VSUi0b CJ߻TFUSjUzUfU[jWUE]RZVVSkek[Ug]qWU{k_zU%,^[X&ְelaXFV;+]JflgYφmgE(YԦ֗-egzliX6moW W׺֮e,iXU`O[F]p1\ͭ^5]zt7Ůt{ R׬r}xvj_s_OsepWMxW.p7`/H};L.X n\bfq_W!ޯiXJ 1wSXCj80^Gd ~U_"gY˅32Zeo70F}3wf8߭ugLS>n|?q&t6jw1lf 6,z0\CgZaCt{Oo6~s7}jT_H5`[WH7MumUգݵ^K _&v O׮^]gfӦV{ۖ^mow}nsVwnw߮vok [6'9l}{gxõπwx] qD 6Z\Ǹ6qV[S1YN|3Gmcȏ)^yzNs 9snj˳&G]C_XщgmR-sG!_5w]:o-r_{ vr*yٽ\Z&cK|OxWbKNG^&=u~[fzЧW}]8[}i{}?B^ï[Nz#౱}dV2_[S|==Phy<cɍg_'cKg:C5,2\C7$639C4|C<8C> =@=A DBDC,mCET5+$0,̾EDCID~DKjDM~kd@OőDROO\>O=Om=+P<M[P<}P8ЬІЯЉ GP@QzDQTQ%}ѨQ:љQ9ъQm8 RR"D=R4R%7&mMLR('bR+B,K)R S1-u.]25L2]uR76S6=PSxS<-4=8S?}3@ ԇSBA=!KTE8CmgdTH0IT TKGTTN MOT UQ=MR-UdDNdEABb\YdIdJF1JdOdddP>eTNe{eR^SVeYeZRBWVXe_e`V>B]>(^fe^ffa!.Kxkfflfnfofpdnfr.gs։gKں挸wgyosg|HgZg|jx~xflFh.h^hh{ghrg\䎀gh~mmhkh^iev@nAj֊؈q)!(i9OfPXhS jjD~ikh ikc!0i iik[&BZk.eBNlŶޚo+^lɞljlW̖ly쬁dm.m>mNm^mV-RS+b4ڮL\ mmmnn.n`܆6^t@nw@ ZmnNnnmn&+&Znk-&oF/f6 nomo)FSyX"nEoXX/FVpnpK 7p X-_PBa._+'g" . q& S$Or%~Qrr+0gr/2r(6gyÑs Jsn =: sŻj2s9C:A@/?:/{vkP,JwtB< ;9@TTtӋSUt=tukFLF'Ms ZR'[O[X/\?; ;j׻VV]Ycu!:v#A?\jva$cB쀡OtW}Na_takw}_xQtW/t@'f$lxw` Hi_Lwv89?fovxvBtuwSzyVr6$_@ogm_zw~oy{/z\#y?`~zW@@ WzKg'vbz\? f z{IG?q 8 x 7Yzg{z%Xkj!zH 8"%߂e5 zo%zTxmx#9#=)Yhׄwd!$QJ9%UZye|BUy-Fd3b9&ey&i9+vid셹uy'y'mr1)#|z(*(~t͙hॕjgz, { M**PٸwBj~6YaoRښt_Ef۵C]eݲ8ZݥN}+ 调*&}4U]Uk,ڋkAqb+oR+u;R%&q=5X`h)_'/\L\"eırZA5RLZq<|0%\¤Rh|YSJG$Tǜ`[uJR۪ڮLnK1ovռ}$j'Ґ0Be=xNլU6=n9R+uy^T>ppo.יt|}m7讋0lnp⣂iÞ~z`iKz$l |ZNFTl+[_>&VMŜW[qpDe?`LggU.ka]JY(ˬvEv^˺yѻ\&9=ɂ]lj%PTt-[!n0kj.jI/s@)˵zvֶlE_ݞк]s( Z'rVw.L"Z˂ ! |F[a[]bXTwC^v.F%̯R"C?lJȜۢv0Ʋ!אS{dyR*k2O)sƴr83*PEأ~j!hf=-=Jx3(F:*ъ4-=kʫ9&tqV%SU'e5c-k:Zg]zMs-aז&6w$i]٣463)d gPB[=$N:|ô$^lU93u]" u,&jJ\53uzwӠ.W+:Vyn&yIz*Xtr*@Xlayܔ.fk_mX icзR]K.|gBuPꨥğ[EQO2%(N0x֝Oj[ӽ6;kFWWBwt͖ЕFup2?x/Os{衃~%k [ģ={#cF~Qq=+f7795㐱LdFLb잗d+XǷSgZL)}͕ɬxUU{ɏД_OmrCQ ՓL$6FN^`U n Zv  +} `~ _ށڇ0`-!\Yt BԅĜ ` O zHܑQ Xae `-Xoy ^5! ƛ@؅Z-_:MWSe(a݄Digޖ4]ݡ\eZ] їEiaAMɗ)B] ] ٔ""t_VT& !]H]bĖ&f!pJ"m!UPTb" \)&265r1cإ\_!TDmai!`y1>E#=^6 cٱS~BXczIU}evPtHAI!b(bsyoEK3Zc,6RT>(&$)mؿcЕDOO;QGfiG↭zJB=u!2ثeMV#A֜!D66m˽ՃeΥ$Qa+b1 cv O $QV1c#e aMm8Q&$:=dv _¡JbJbfd&DY b &g%J~sޟi rӶ1gD n'>i1"U#wyvz'{'|"{'}''MgXrڧ*dT'p'!@E x|}Y&rZ ԃb$P%EIQoyh0cсF"t ( FTFƼX]Z )Iҡsb+%c& \uWFx$Ɲb]].je%2&n\I,YJQi恓gYY }ܕfia"7])K)L:N_%W5!p%%]VzjCNUVj._q)E&nt?έ&(n`HƙbόQQ6B%4.'n*ң$>+W%SMMҥqSYYFn#ZNecF)7kp(V(píu$ݡv݄qkޟ>]Q#~ Rqݿދe$ N'멪:",Y.Oˎ\% (X(lul}ј=:PemOji(q$&Xm"ln-ւgjن&Ya۴•*bcobKզ߯\E988\Zy Li~8ZCJ.7P:~.&e)qn~YC7n7nҭ..'>J.*(f.'n//t&o//.n &BoίeEZpR+Ih.^/(TBICJ#)Wlk6p;!iGhJ _ gpfNb0fT5-f_6B \YKPނVhV m2 pZ2~,\v}K3N"j4%]:$rh&!Z"+Qp\%P ͆}⩂V+0pkp.XMs9evkD%Aek?n'SBޗTّ^jT$Ħ@J_0W(ƑKj,EM3_*9dm0ϋBs +R3!5c7vXE x(Lpb[;fu]]CXfvY`av[96l'FdBe_vV&ℂY;TKw8:vt<|vh &nC=<`sxK&6aӀahn2)"s*swwQ~!ZT(S.{{+#6|`+2̉hqw?Kb%1Uh49f+*\e^n0$O-k-MT(w97t^'8͆CN^V,WlwNd 錭i[%aFrA9L8tbA[yIr;䗢Kc9*-?rV̌ni7,94V:սC{"+9 @dC#e&3wy#iv5z| CQ 攺!?"O7i3 Dk2aϩa^j;c<69pɣAp\sByk=l&Y{e~ɮVٓt|t"M_bxgYuu Ukݾ-o"+֚>j!~dkB2Eb{l//slv|`ԖGZȿ|<6߼<}|==vc0kO: pҷOs#5~aԓi=:0||/U}f}:~׉<̚*^.k7T$}|=4eDc| Si.ĿTθZIxķ0r@fUjL1Bxx*yL/ӟ 6c{{ :9?>Oy*k4*W;=S:|j铡:ط8Jo-::dn= .a.xD= 4xaB 6tbD/ͳ#8pݸqһzY( ez)SHrbLg.)f4yBgœ?{Qwt:P)T@iReHTjOA:1VTXˢmVZMo^{_? l@ˏD+ AP@P 9L«RnC q,mLB@ 2@$ēc 2li,k.02tH0l1%μO<=@4|7<1)׫H%I-L5T;CL't42H9=TU]V]@uSFUzWuݕ^}@ceQEkSRs f}hbCVSnpY/mMv}^v=uӟyELOey!pa b$cu2%-TbWX&=t!M>cP}9mp3P`y[8碍>Sw9_Z}xhꪭSME:dY쾺Zkg~Fڐzݸޛo禛k 8C%[n5BOM?&\]emuߝ}?_y-s5'IwO~F?_?vY/ޢ赥9w1g X@ T@>)XA ^`'?Q)W?Z; YB1 iXC:h7ǁp1 s$p Kb X""P9XE+^Y58`y8O8xp(H@5EyG?Y<#Ce$1N`: D1JHO~(IyAiziC@ t\\H 9[̥(ryZG'KYLcTf)KQ{dW`J<._js2YNs`= {A3{Ҝ^=gJdrH7OӟJЁ hGƩN>2ݘBч8k0HIZRe('(4bR LiZSԆieȠo}%IUjROndQ,dS^YjwO34%YiUZVU\ZWB=z`[U'/͌u!,< {\f9YrI'hI[ZӞUjYZ׾li[[ձ{<[^rUr&ѕt[]^v]~x[^Uz^|[ָ s_d \Sx=P`?)\a _9a!I\b)VYbk2i\H-%ycA\d#IVd'?Q\e+ڲe1e1\f3iV3q\g8yֳg?} gAщVhGYpRz|hJ_И47i6[ӡ3E]jSՃJRjRzүe=kF֊uyk_/zw=l?zFvlfϖ0h6,h G>mnۙ Ŝmv;N ol{63gn{O}{ Wx]#| O3n1./7-m"5-^pyg.G7^i7<)~r޹|G>y7>c|5n|5'W_x;_п_i۾_GoNpRO -"do NR-mm<N: 6.%nkPCXܔ0脐 9pp U 0 L ǐ  P א PPQ Y#Q'+/3Qp7?CQGKO%S[_cQgAqksQw{oπhQQQǑQבQ R  !R!!!"#R"'!;./IDE/IDE4.gif000666 000000 000000 00000071551 11247233502 011152 0ustar00000000 000000 GIF87aw,! !&&&!(1101181989!J! Z1 Z18B1$sixr!y!AJY{aZB!J 1B81R(9Z8JRA!{a!BABJIJBIXBQZRQBUUVRQcZYsZiscYJcYRdbdeissiswrt (0!&!01(10!410181EB0B8B8BIBIBYBUZIZSBaYhZqRqRiRiRykicqix{yZVkYkc{iki{i{q$$3399DDss1)k{scx{cccss{ai!q!A)I1Q9yqIJQJSTacycy{uwaJqckƊ֌!111ֆs֮RֶsBBRRcs猌眖眜ƛ͜ք瘦画ޭȥݼƵ޵ǔ׽޽ƻڬޖޞƾަƾ瞌瞔쫜箥維ᄉƶDŽǔϵτ܄ǽץXF=@0q\*\ȰÇ#JHŋ3jȱǏ CIɓ(S\Ra: \2͛8sɳϟ@ JѣH*]ʴӧPJJիXjݹ [ÊKٳhӪ]˶۷PKݻx˷_` LÈ+Koǐ#KLz3k̹1MӨSװcF[O۸sͻ Nȓ+_μУKNإJä{Ovӓ jć˟(޵w!@d'h& 6M:VhVI nhc(≞o!4H%<@)dM#ΑH&HӄmE2)N;d\v;˘dIhf7 n 'dftީrgvg9yΙ'F*I碈::~R:i 碊Byjwb꫰*무j뭸eNa&c&,$09̴ X,R{ֳ'Ц辙z饬;*oJ˫Λn*;7/+WlgLv.'ɂC,8K..#Ă߆;n=k *4Hk M{2=J[u s^k,dmٯ:ll-32| 1쀫z3Ό32(O pXO ) {)B\р [j^4/LNG5m'|s<'7vR=8[cb+~/~_?ߜG@_ѧ6 ؿ Ѐ̠"D+(B2 KhB Z0#̟@8̡w@ H"Hȡ&:q [HErL|KbYx\hE}xH؇0zk1>pP}:SșnB 4! 'HЏ= !Bޏ1l%9". 7̤(#I,gIZ%m!,Љ9 ^0G̜ ӌȃ4? 359:8F ҹtsT7IyӞg=O}3?w4Bυ6t(B#jЁ Tu>P>G#QRԣ'HҖ0LgJӚ8ͩN]:rPʂݔc OԢ2@ժAj8Xzg=8̤e(<-Oԭ+=(G'ZҴlkEIP֕{=:ה.TmDVԯbIؼuͬf7zB:Ăoeҁ`jڨ6miM@,ȭp{emY9'FVrhtJ*ӕkv}ixVw.\R^}.uk^7lZË_~=u7:^N`*Ý2qOuPEawZ8(Gd%Wc Ku`1K"HNA&` <Xβ,?鄱;-A2JN6oLgaB ʳxoYπV)OЈNhO@u+J#Ȗδ7YY GMPAtWS g N@Ӹεw^i=LbNf;ЎMj[ζn{6MrNv6zη~NO;'N[ϸ76zm GN(OWgN8Ϲwx'샟{x>g</[>Op+x5.z|~gO/wϋ]o;o´rz>v_>?|G}_w}﷾}_㷽~~G~7|cg}X}7}Wz۷whW* ~xhqW~v؀~ ٧} '}Ǘ~7ǂ6؀ׂ؃>3x2H~C8h8'&x9!QhYwx b8dHB(v4xiappTqx5{1(uCPeXgWG\Ȉ#}8 8L(T~h槉}H}؉(|X{؊e('XXtmW*qNj''ryH%WG̈s،XF֘ڸ8{؍86x䘎긎s(s8qXH`o)G؏Hr)Gcg qz7x yot@"I&r *  m0o` p Г\XFr9I)Gv#& f o^0 dYfyhjlٖnIVctYm 'i)o59qNPm No0o`I @GyoٙKɔzx~Q7oayoEyٛVyYyɐ  Y&K&?0E0goo)ٔoYƕr6V9ZIY` ڛʹ؜Vxpp ۠ 0 ڹo0\o=CpP.ZǞ鞣I 7SfS Pz Q oU@ ۠ڠ Po0Zo'z=+o@tJ_ p2oo469Yʣj?GgrǤNZڠj OzXZ I^oڰP Pv ֦pV^^gcЧ9ٚYo:ښ⇌xw7w劅6 Z40T@J:o񐪪ڪcZ|0[|o0VЫp$6B]P]ƧaGi('|J7pXzI8;j`گ٠ P P  `H`?=pk<^P^|ڶo ۞)ۣo;*sۨ?ʲ}ו ^Wf*ڳФ@ˎlڰpo P J Vo\@\XpJ`D0rk׶|(kYv*'Njxs-cI2`ˏtE kpP M+* PoYP P (P(->p,  _ k ʬ";p%{U9N87'\ ٟ.+ ,u00;Upo@ [pҀ $oX0t.> ,u q^:Nt,&yr.vKNL7C Y-no . P _ns]r.]Iyқsr nR^-w'\^>ݐ{9 30 bmns0r^^u~CBhRn~Jv v뻮ǹ m[~).+sҾ.߸E L j襞4뷉z^޳n.'~ʅ >ݸ P4`B >n>nh>ΛNo]DP~oz~J|X~nNX.@`2P$?1Pmvr>1OMLnLTs"TACϼdW?TRϮ[T4P  _*Oow)mBU?C>?B%iEbTȎz]UZCE2dDwNN^ɑp J"EJ%z!E$YI)UdK1eΤYM9ua 7T谐 !Sȸt)ƍvԚjJ'F$P8ze Ы:V+֭oV\z]w<`)ߋ\OawV便fP{תp,ȟUfkرeϦM3ѢF~適?@+i\-ʍjvd[p3W_ŏyկKXp*G̾|v;V:ʈ 4@TpAʨrrj7¦ o /PD -C4/DP무BaTqsF /K4"LI&ѻGK6&*_ZAB s qG1otL4TsM6,Qg9):=O@$ UtQ!ϳ$0HkrRJzhNsSaQR5MTSUuUV[Up:3V;$DKuK*1R`wF+5&/q*8x".L\v[n[`uV:kU^\@Ev^z-*b8aA>wSx` 6x5q$Τa#xb+bxc;XzC>K6Vye[f9aYcUg^kfsyg{gYdhVzivizjjz`VgA.zl6lV{mvm{nv;no|p 7pċ[fNq#|r+r^|\k3}tK7tSg{s;qaW}vkvsWi}oЃ~xu7xW^=޿v/!髧zs{^v_~|7?>mτ.?~ן=°1:4z/~@F^ 0D3@1P|$a Mh> w CV@P'aH>xD"THj'$bil!b$\$=BqE,YE01^"H+QkdE8nxG`ͶHcB$?NzA.7[dp0b ~p^3\5&[@QotW\᩽]n@%~C|!q')'Coߐ((o<6 NzHGapizn{VWGIzt/˱^uo8a^v7|p{Ζg(50o60R߽9/~[ N}n9^o=Sw+/{||G8Mkz_= -Z݆I|$GU}}]a_;w2׾*{ϟs`ޒ #O 7~2KD[˸sL 1{,@y@K[@ 4 \ 9tVCD (`L],aL,8E;ı[?[] +(4dD3,Fg$n3dFps+˫;F<]A@D'GAE*Zr|C4CUu4TCiGj3RDR$FW\HDŽ$' D~DƃDEO„Zv\{HFkA)cɎIULStȡ۱I%zBlbH_|4AJQ\dIqč¯FJ$3K440yûA!KG,4LYKJğKK~J9?Ɍ7+TƼHˣ̛̔LΤG2>d˘&ͷ#D,,L ьAEMM&a;̓@ԔȚl<4cA`4LNL ALJI|MڄZ#?NO=R$EP4U'0MR&\Nm+QyRdR~Y'*]S SM'uP(%\eS;x%6m#7m#D\ y]ӲiJ«TITJTKT!}S*GՎ*K-US L+-,eKtAmL/4MR)u#DUPE%F+R,(:Ub-VcT껷U!O}TPmcVHV R@DjCBke=N9-[re?^)r+VkWy p-N8=z`PVTWcW]V--=9JWYW(rWXuefv V*+XSXQQlS_b":FBٸib/%}>1Z2١U%ǃ]̄%`+E+XzLMVu=ZZ][@Dc[5@XLOʊ%Vl{e[ĝں|zH\ ϫ̬mԏ%Yj%]Í\u߼J5^)v͜-\]ϳ$c6\ O aa~_bS!"#V$ac&'^(#+.-)b0^1_VEc 5670ݢ:b'c?F=b$MzIdJd:GNd_Z&cCKc5E-ڥ=&e0eDG+gI^4TVeeeueA* YFZfGdiD]$I9DDf]d3acqKXfgC&hFiej;ACm>?nov"IȂAX 6stuLH.eD|œÕgYN-FtfRtP\i @,dhv㘆K]KETiHLj΋ed)k h= l!H.HjJƮd>Cgɮffᗤk[e|Ce.kNVfp8 oeͶ雮޸Ƌ/_d^-]eL,9ppoe놔'f,qFF$lGv6 og>qn|qgJII}s)/n9riq6cHnzxrgŎgI8IzL+†D.68'7s?$/q*q~ʠHJ7F|mlFy t u~̮!1sH~siJjo uǾd׆m1W?.inez14rNvqu%3kv.pZ\MnutIA_mT,}i~L||wR7Elj@l_5)?.ItlNw ?|gFUurVx'Cur vj^?DtsdfkDxx&W,d&^_?=y DvofzlxDzQkgozE?oYpVzoIyxa\p_Z;W6ʹӤEknyc&DV{bnŸ~VvWqwo'!mm&;coyΗẋ}ȗ;2ICYeWG4t^7{|nyHw~r7R"w/46[?moG'MowM?_s7y~& m~kzG>C#JtX"ƌ7r#Q}LhE$)R,)%Ę.gHN:u'О 9(ѣH2 ԨP4)&֬Z^صްb ًUgJm+u+ܸr^}Z$F'È;_-lXnȑwm/`'X/Ȅ7Ya7smTiPMMzSQ>vܳ_ˆ%[VƵ.emHěN9' :v%2輢VNӠ(j)HS ! J Y*ɍȖ){+:\&j('{"gJ*贐NjiV[v-lݩjЉZ!t:ݛ:ۗ_~hm.+u6('YkJm^6m;nYzeoM}<ݱnB]3[9 oC@YZM;qK?u$wjr[M.GZ o34ds la\]tq&tno  w~.7:>;~߄+8;[8(7\_Sz3Aby[f]u0k*Sq~{AtZ;޸c ?<|噗5y>%2}sVzͲk ,:7oTF3Eli}A҃\ϠʢIqe/f?JD  Viޫ4 Q9ˬBLA> b{cjjӄ'4)y֦yMUQU >MT"ę'RoEM>2kCll&Tz#@BBc] AzNV W߳T3jL:ubxjHGxNߎ_-('n":D;s)^s){aOx+N'_@v BvwVa1 Tݾ>w/;YKCdlf޼$%cδBɕ{my?> P2o-cy"2!!"~R?w!#긑ڧ ߵAar౎}g޹x!S%%v萟Zqr `eՉfuW!e4!M5"'b.&)vb]`ꜙq0F fu\c:3!6"V .z#b$><-Q? נc/9#AbU".Y\a_,b=Q!2S3A#?ZQcI^ס_]V_Y)Nd7cѝӯcTHޓAzHT-"1b2UК,OUP!&A`ZJZ<*e'cR%%B%HW Thd$+NWX^ZUYJeZ Z^z^\j$dy__UH _a``Za^UM)!݊9~IEf^feY-N;2dMQ`E$Nud%mvXFOҟq'r&r_ffZ[E&2e&w Br]`$ JgCᰐ=&Pwn5"I{wr^g@`gJ`C6lq|0fevngsQ5 vaBcm!Zhxf;fpjrV~8py"zW攐~{jz$e6Bnpaa㍦ t#rN%/"6j$dކOfnb lt Ձcc&aR̓Nod$"e_n.J#vܠȚBlPvҞ._<*E aߗڥfCFdu*j[V>ݧieQe]$kOjQ5i*~g"# kׄ)q':%Q# `kkЧnd9$fk\e&6þzQk(cUiHF,MlU꼊+] cmcݨR,ql^yTb]jJog&my~N>,l)fzɺz(}->dnFԾ跂5ϹK"9ZPZZ\E-mš Dl헵lR+:2YV.~IWF:*h ,^%*n>.9%^V]nQڒH-=30vqQ`bJz^ ܆2IC'8w2,73O01[\JSnU5bd͵7uv]4Rtfy5fcE~LbOn\waV?Vg±VvƊ55X"ut[WXc4d?:Tqֹ-Kin!眕mTsNio wj?343)mرԺ;(n/sPoQJ.A~"Q1' V.urԹI02^'3"7G6U+/w0boWxc/>!)j3]7A*c_:c837:zlƶCxBx fs" @ֲ_97x37׳C-?w\'p#˸<߷6>v+5ߦ9B6v|yXwzF*8(ㆁc4tXW(u;Ro[v1R"t?rYF:/']f9g$;z( /'{*oleS{yIp!cF-5ﰿy//M[h6d,9sk:7782y>:DLگį{ hŃ׮ɇٴ<ůŧ=]!H[~F>wM?:f7kG+04f>z75bv~hL}z2{%Dz 4xaB 6tbD)VHoE9Vdca#I$92d !$(˂2 4(A9mhzHާy@TOR}NQcU(QF5"UʐiKTJ5TUg޴ o^{lʐ'G<)!Y8„b;v|_+]ڔUʢźgܹ1_|3EhAߵ|UҸunxpIÐ7mzt >8{aڪG^[ZnnoKK]j=.s6k#_%#ror c--,՛.j,*|-B0\k390iQ ],dzkJ$%$c*z"?ْ.LNK/D24q5-R9¦$:kړ>3G?=t&m–s,FJ-L5ݔN=T<B ]JR/2OT]=TWjt)mtNRYu3< ->uR΂sd5YZmh%:5UYSU4jW,V[oea}V*7\"=Cp'R/7tu]WvXXy#?5Zxa@^/ءa ]Jvz4cHYE@9͍9y8B^>גS& Qs b>8\z#9U8hJhތ_]:@hlDKR>_LţH𱾯Lee^P87rT-ozA7.Wjl=}yQ?v1%>%.yRL2m/puoF4}ӧ7{Ys_tw+ܴ=|5COɎvĊX$-s>[f=|a&5s\")FI[ܖ.HmAg֎̅mYҦB,U{ -rPsiw9VwXo\␁}i_CWY_h}SQic!8Y X:z- \.v^tbX к5=:-74v6֪:͌cհ#e2TT@&2{ٶI1% 2Y=~nm\bdTUE3o-7 LT91lƦ[J hGCX$qxlπ#i^C7ld +7tw]M3~qAm,؟\:im>I S}6gk7lbJס5?a'ylp3n*D`k_{3~M_+۝y6PSw{Ht g)q;0br%mEi&jQ}%$/+i7z9.yN[0_g|nj?d?D l͝kA*uW>;L>qn2;4}O/zatUxݞahu?O=Q^3|߈_ KYcv y{+ꀗ;=[t<#ksi_Mԫz[zGc}Bc^;?Q^N|sɾk7<=|oWR]n5W~T_PoVlPM#0SM+/30M>BKpFSP W_ZgJksnP{Pv  P] P :o P lय Ќ.  ӰP E  ߐ0?P0"F Q#Q'+/3Q7;?CQGKOW"ZQg#^Q/sQ iPQQEaVv!mPQǑӑQqQ R q !R!!! "+"/#3R#/"q#CR$G$K$# c"O%_&cR&1%Y2Ub&sR'w'{j%'}()2'&R)R**)I(*,R,*KbA-֒-.R..+/R/2Rp,M2*r00s./11/$"-ݲ020ے-933S3?3/S14O522nC0169s4a362i6R6ղ4S78_r5h218 9-93:S9Sa9*;;-/ю<":<:3=9:;A;>>,'-;ѳ=?=S@S>>TAg2s:3*(BB+0BA?DC/.NESTEWE[4EESt>EFkF W20bG{EGaFoHHYDDIEHTJo4I]KTKKKJTLTA4/>MTMהMMNMctm4 OTTPYPMQUQQQR#UR'R+R/S3US7S;S?TCUTGTKTOUSUUWT+ UV0V UbuVs5 OjNpUWUyWOX;PZ}YWuX]USY\gZ2[u[mXU]ap\ղ\ZN/[^I]Y\U^6`5ZS`a?] `"^a3)V@bbuZ5dZN .BWUZodkRvhBa`vdg6]mh.e`%fVai-_Udeij,juj6G cl+kk_^mUll͵lknŶWUk)jV 6nVaX/ovk_ Wqupm[g0lrrr$sqcqV[$.ct$sA!T}JWȆFu,^uӬJ&vS rWl7^pcxm:iv[oof2q~bs}ev~D ªbbW?gwZBtp" u㦜v zxl#*׆K{8JR0H籸w."| XSkD}9wnɵn=qKӲ4kxy7}!T} y)UʈTgw+׆ExFXZwgX嫆wܴu{8o87+uׄwKwvwةn|}?7q'o@ +XĬn&{#g"}|'؎ww{is؆A[׃Jwx5Fwlx' //x7~Vj)J!Swi8kxoؐqTkKٍߣد0ryK8wNuU_3fg L x~,ݸXy}{b97טw.UyZזaJ!ٝ;z홟C\bCW2/yWױWY9՗MC9:9~|˕UYz5Aڀ:uI7?$dCݘk:uIl %Êz)Mz:ګs؉Zzza`Xww׸⢺ѷW9[!eũVp #.j5׳b WoW$G G9oDyWk/^mc۶wۗprIۑ|tV;;y{W?Y_֛3:[:h;Y2X7 {uQ5yPJڥwڡCJ[Oڹ;{/|w9@OܺXg[緉ڈp:zW7,({7{uX_|{K<8l 5<۹5ْEz <11}&CĖػ[y >{ؔ[ɠ<_[j{ʏM:x8];(ۘٗ#=u|{|'[|u·)#=C<2y\<̓ _gZ ܘw?]{ԍ;թX ]'| kI{|y=wW]*]ոy,Z,O+G\é:^]\zg8]Z ^#ު]'ēYZZ y>_jUZ wsA su\-ekx;\ y>}FWC~s~{=ꯞa>w捣u%'{ٶQvԷ屗ca<>+c,˅LY^F"b^mol _?H:?z:A Y8{w9I:Wu[Wnyi??MP?%p)] ]AZY;@` :|:DHbB2xѢĆEVܸ"Ň&;.eʕ.?,Iȕ%sfM#5V<*4ҥL:} 5*MsYJ\Uad+[V@E,0ʶq{fTeݹ,dԤ_t{ݩm[ #^޽hQ-TÝ;:9gjЬ-'eY'ͩE.#i{ իXrZd2Wqlٸw̫bֵ{^S-C~[Ѱ'v?{z˻nM{w_n߱Wv_p>a G\V!r9tl7߀ v冠J fB ~c#3zHX)'"kvgI)MtIe^*EU^\Xcm0ugmqZgd͹"gyyy':ddGnɝE6Zhm1*}j i1M W*ק訣:)jn(_ʫawaVia.lRv2'^\·mqǕaimˮ2Ȯ}k-ڋo96w.Lp3Jz pS]j z"tjNdD|;^$c&uZ&E[ 8ƮH]_C%\PK.a WYQro]KYvr(^ `H-y 0sHU%3e<22[u$SP}-$7xXˢFl\8F V:aϫZ1Dl3cΗ?5ؚM_D0RG7nZs;by,ы\(q˽WSk_TƿL0Z]J/6`5xk/k_Z 3ðI᳿!1ly+ʋM.~"v $L帋/n?b•7f!UK;O϶SްW :QI(%CӲw oO|C{ާQ׼$;CɠP@GP%2TC\)Fwn1JS2VTo#J">+b^ƞ!9YhsQ*wD,FNc/‡VpZN|&T6.Z&o_>4E&6|<9rp }Dg^}R^kj‹z}P^-R}lBl,eU3϶elݮ!}^fj\j_;fU}s fMqk stE_ޮNnn*.0ģ[<)2޽]LygwvGfȞj;ۭ޵maXmx8OZz9r,}Gv2\}eC7Ԋ|`^zwۙ/qIfQB?f{K~9G75m|WHw_xqiqvv:2dx'gI84KdYn}'[VFIm.\35t'6 i HEDuXzd"dbe9xlvnfbEG*xxijh$HH!5'k$~05 q( qp䴆|FS}ej'Xf&`gio]`FjXheZa<.Ɔ~U>Fxc4^H9`drT p%nm'*{Q*g=]ף^B_fo&*m&K=8=.ʸV~1w usz4\HWcBTȋDw] Bp߀ o3tu@ r6u)2u6)NaYaPްА*Su%iIdgΒW5iّ6xA)7В/96M.WGɓ2,W+; = D?sRc#`&3mfxYY5[SXt%H3gye)*8aW&vvBǖHjR|=U76fbxB#c\P"yH(^b2Yq8wTM]IAo$V@Bo|{|[tzu7|H|Ly[bwmɈczDC+G]g{#l<{clIyWUhice/CXg5lgJ)?fFEBؙמ~8:ub$e:Yd h^@c m(ifm(ƠHZx%W8)H{nbøH=gd"I>ȄWXbWa|o_GWjz^/"aJȆOCE7U 쵤j$9ZxBˆ[ݶ ٥hEs;xGc fj?jzIlz$Lx|oW~hxOXoJj}|inʛ6_H%ȎkȫJLo3z* HU j@A:1*Z-J*:z?#ɭખ(i0L\\hޔ4 m =0 {@ڭ[1Xʔ+#;5;{~$/1 +*[,{p?eVȗ" |=UJ3бPqӪ9ZghYu_~Ј/Kx5m cK;RuVxsM\ z9+5;b8 `ضDJ7O盽'WʖvZl2sj_nkY*̩Cmincˉr9;ʮմO˔qgqŞU%9 xJ*y@VzgZYԃһE);x4X{[s犡T F6)huj#RqX2|<˼6zKڿV~3{FɕAgK~g6[hdīL:b]6ʷdk]+7(ld:f`s; ܤM2aJ#e<ꥊxK[P:Ju<܉$Tnaڵ'GsDmdSWjmo8ͷTی@{J¹U&KZrW;GۈX{ 0hxtՄfl(T0|օeV1}Mή pCV%lzdK~ʙ՟٥oHЋUfSa4PsNx.$ [q^ā>~n艮qˎn [hr+nꢞ4.Y>\nM Zo6)Onn Hn׎ٮ.Nn.N2*No bMkVa.#O%o')+-/1/3O5o79;=?&#@OQ/SOUoWY[I&CO&[jjo f!sOuowy{N/O4Vi߰1 U!}o_).B p 40 Qy2>P/04p /Ooˏ_a?>ͯOoOMoكPB >QD-^ĘQF=~RH%MDRJz>uLzhĉzT(PA}p5b7U^j\knDVZmݾW\u7ҋ4͜}ihPEv8sS̅FVdʔÅ2p={>`hҥMFZju]ɗl9yY^q׽xGyz쩮~vC^'_|'}`}O{׃$8<- $@vt0j'ػi\_"Ⱦod BY0~?a8AЈa=H#:n:,"xB#p$W'C"9J0Xa&qr<4`lLj>7o2d ?q!KhFFZ{88Iə#r\V#ޑXۣB+n`PHn2|%DAeJ^Г|%!s9R#XKC\$ gi5fVs]+8Elkd2goWe21WFoRf9 7KΣT_gGӑ"FIP`BQ V h,WE>EnsiPO^j”.BjLkUժWjVUlM57_kX:VլgEkZպVխok\:Wծwk^Wկmk;XְElbX6ֱld*XVֲlf5YvֳM,eA;ZҖִEmjUˊmleN;[ֶumu[ַe0\׸Enr\6׹υnt;]V׺nv]v׻ox;^׼Es;