:- module(eplex).
:- reexport eplex_ except add_constraint / 1, lp_eq / 3, lp_ge / 3, lp_le / 3, lp_interval / 3, reals / 2, integers / 2, optimize_pool / 3, optimize_pool_body / 4, optimize_pool / 4, optimize_pool_body / 5, suspend_on_change / 3, get_changeable_value / 3, lp_var_non_monotonic_set_bounds / 4, piecewise_linear_hull / 4, eplex_add_constraints / 3, eplex_get / 3, eplex_cleanup / 1, eplex_probe / 3, eplex_solve / 2, eplex_solver_setup / 2, eplex_solver_setup_cbody / 5, eplex_solver_setup_cbody / 6, eplex_var_get / 4, eplex_var_get_bounds / 4, eplex_set / 3, eplex_read / 3, eplex_verify_solution / 3, eplex_write / 3, eplex_get_iis / 5.
:- comment(categories, ["Constraints", "Interfacing"]).
:- comment(summary, "Interface to external Simplex or MIP solvers").
:- comment(author, "Joachim Schimpf and Kish Shen").
:- comment(date, "$Date: 2012/08/08 23:08:43 $").
:- comment(copyright, "Cisco Systems, Inc.").
:- comment(include, eplex_comments).
:- comment(desc, html("<P>\n   This library lets you use an external Mathematical Programming solver \n   from within ECLiPSe.  Solvers that can be connected through eplex\n   include the open source solvers\n   <UL>\n   <LI>CLP/CBC from the COIN-OR open-source project (eplex_osi)</LI>\n   <LI>GLPK (eplex_glpk)</LI>\n   <LI>HiGHS (eplex_highs)</LI>\n   </UL>\n   and the commercial solvers\n   <UL>\n   <LI>CPLEX (eplex_cplex)</LI>\n   <LI>Gurobi (eplex_gurobi)</LI>\n   <LI>XPRESS-MP (eplex_xpress)</LI>\n   </UL>\n   For the commercial solvers, this library provides just the interface, \n   and does not include the solver or any required licence to use them.\n</P><P>\n    The constraints provided are:\n    <DL>\n    <DT>reals(Xs)</DT><DD>the variables Xs all take real values</DD>\n    <DT>integers(Xs)</DT><DD>the variables Xs all take integer values</DD>\n    <DT>Xs $:: Lwb..Upb</DT><DD>the variables Xs have the given bounds</DD>\n    <DT>X $= Y</DT><DD>equality over linear expressions</DD>\n    <DT>X $&gt;= Y</DT><DD>inequality over linear expressions</DD>\n    <DT>X $=&lt; Y</DT><DD>inequality over linear expressions</DD>\n    </DL>\n    Depending on the capabilities of the external solver, the following\n    may also be supported:\n    <DL>\n    <DT>sos1(Xs)</DT><DD>all but one are zero</DD>\n    <DT>sos2(Xs)</DT><DD>all but two consecutive values are zero</DD>\n    <DT>Cond=>Linear</DT><DD>indicator constraint (some solvers only)</DD>\n    </DL>\n    The operational behaviour of the linear constraints is as follows:\n</P><UL>\n    <LI>When they contain no variables, they simply succeed or fail.\n\n    <LI>When they contain exactly one variable, they are translated into a\n    bound update on that variable for the external solver instance. This\n    can lead to immediate failure if the lower bound is greater than the upper.\n\n    <LI>Otherwise, the constraint is transferred to the external solver\n    immediately (or as soon as the solver is set up).\n</UL><P>\nThe following arithmetic expression can be used inside the constraints:\n<DL>\n<DT><STRONG>X</STRONG>\n<DD>Variables. If X is not yet a problem variable for the external solver\n    instance, it  is turned into one via an implicit declaration \n    <TT>X $:: -inf..inf</TT> or <TT>reals([X])</TT>.\n\n<P>\n<DT><STRONG>123, 3.4</STRONG>\n<DD>Integer or floating point constants.\n\n<P>\n<DT><STRONG>+Expr</STRONG>\n<DD>Identity.\n\n<P>\n<DT><STRONG>-Expr</STRONG>\n<DD>Negation.\n\n<P>\n<DT><STRONG>E1+E2</STRONG>\n<DD>Addition.\n\n<P>\n<DT><STRONG>E1-E2</STRONG>\n<DD>Subtraction.\n\n<P>\n<DT><STRONG>E1*E2</STRONG>\n<DD>Multiplication.\n\n<P>\n<DT><STRONG>sum(Vector)</STRONG>\n<DD>Equivalent to the sum of all vector elements. The vector can be a list,\narray or any of the vector expressions supported by eval_to_list/2.\n\n<P>\n<DT><STRONG>sum(Vector1*Vector2)</STRONG>\n<DD>Scalar product: The sum of the products of the corresponding\nelements in the two vectors.   The vectors can be lists, arrays or any\nof the vector expressions supported by eval_to_list/2.  If the vectors\nare of different length, the shorter one is padded with trailing zeros.\n\n</DL>\n</P><P>\nThe external solver can either be explicitly invoked to solve the\nproblem represented by the constraints, or be invoked in response to\ncertain trigger conditions. This mechanism makes it possible to tailor\nthe solving behaviour for a particular application's needs.\n</P>\n")).
:- comment(eg, "\n    % Linear Programming example: transport problem\n\n    :- lib(eplex).\n\n    main(Cost, Supply) :-\n        data(PlantCapacities, ClientDemands, TranspCosts),\n        dim(TranspCosts, [NClients,NPlants]),   % get dimensions\n\n        dim(Supply, [NClients,NPlants]),        % make variables\n        Supply :: 0.0..inf,                     % initial bounds\n\n        ( for(J,1,NClients), param(ClientDemands,Supply) do\n            sum(Supply[J,*]) $= ClientDemands[J]\n        ),\n\n        ( for(I,1,NPlants), param(PlantCapacities,Supply) do\n            sum(Supply[*,I]) $=< PlantCapacities[I]\n        ),\n\n        Objective = sum(concat(TranspCosts)*concat(Supply)),\n\n        optimize(min(Objective), Cost).         % solve\n\n    data(\n        [](500, 300, 400),              % PlantCapacities\n        [](200, 400, 300, 100),         % ClientDemands\n        []([](10, 7, 11),               % TranspCosts\n           []( 8, 5, 10),\n           []( 5, 5,  8),\n           []( 9, 3,  7))\n    ).\n\n\n    % Sample run\n\n    ?- main(Cost, Supply).\n    Cost = 6600.0\n    Supply = []([](100.0, 0.0, 100.0),\n                [](100.0, 300.0, 0.0),\n                [](300.0, 0.0, 0.0),\n                [](0.0, 0.0, 100.0))\n    Yes (0.00s cpu)\n\n").
:- comment($:: / 2, [amode : $::(?, ++), template : ["?Vars $:: ++Lo..Hi", "EplexInstance: (?Vars $:: ++Lo..Hi)"], args : ["Vars" : "Variable, number, or (possibly nested) collection of such", "Lo..Hi" : "Lo, Hi are numbers or arithmetic expressions"], see_also : [integers / 1, reals / 1, #:: / 2, _501706 : $:: / 2], summary : "Constrains all collection elements to lie between the given bounds.", exceptions : [5 : "Lo..Hi is not in correct form"], desc : html("\tConstrain a variable (or all variables in a collection) to take only\n\tvalues in a given range for the eplex instance EplexInstance. Any\n\tvariables that are not already problem variables for EplexInstance\n\twill be added to the problem. The range information is passed to\n\tthe external solver state associated with EplexInstance as floats.\n\t<P>\n\tNo type information is implied by the bounds: if the bounds are\n\tgiven as integers, this information is <STRONG>not</STRONG> passed\n\tto the external solver.  Unless eplex:integers/1 is invoked, any\n\tinvocation of the eplex external solver (whether via eplex_solve/1,\n\tlp_solve/2, lp_demon_setup/5 or optimize/2) will only solve a\n\tcontinuous relaxation, even when problem variables have been\n\tdeclared as integers in other solvers (e.g. ic).\n        <P>\n        No propagation is done at the ECLiPSe level with the bounds. In\n        particular, the variable is not instantiated even if the lower and\n        upper bounds are identical. The bounds may be inconsistent with the\n        bounds given for the variables in other EplexInstances or solvers\n        (i.e. this will not result in immediate failure).")]).
:- comment($= / 2, [template : ["?X $= ?Y", "EplexInstance:(?X $= ?Y)"], args : ["X" : "Linear expression", "Y" : "Linear expression"], see_also : [(=:=) / 2, (=<) / 2, (>=) / 2, $>= / 2, _509612 : $= / 2, $=< / 2, eplex_solver_setup / 1, eplex_solver_setup / 4, eplex_probe / 2, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, eplex_cleanup / 0], summary : "Constrains X to be equal to Y.", desc : html("\tLogically: Constrains X to be equal to Y.\n\tX and Y are linear expressions.\n\tOperationally, the constraint gets delayed until the external\n        solver state for EplexInstance is invoked.\n        </P><P>\n        The $ version of the arithmetic constraints are provided to allow \n        code to be written which does not specify the solver. They are\n        equivalent to their eplex instance counterparts without the $ prefix.\n    ")]).
:- comment($=< / 2, [template : ["?X $=< ?Y", "EplexInstance:(?X $=< ?Y)"], args : ["X" : "Linear expression", "Y" : "Linear expression"], see_also : [(=:=) / 2, (=<) / 2, (>=) / 2, $>= / 2, $= / 2, _508459 : $=< / 2, eplex_solver_setup / 1, eplex_solver_setup / 4, eplex_probe / 2, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, eplex_cleanup / 0], summary : "Constrains X to be less than or equal to Y.", desc : html("\tLogically: Constrains X to be less than or equal to Y.\n\tX and Y are linear expressions.\n\tOperationally, the constraint gets delayed until the external\n        solver state for EplexInstance is invoked.\n        </P><P>\n        The $ version of the arithmetic constraints are provided to allow \n        code to be written which does not specify the solver. They are\n        equivalent to their eplex instance counterparts without the $ prefix.\n    ")]).
:- comment($>= / 2, [template : ["?X $>= ?Y", "EplexInstance:(?X $>= ?Y)"], args : ["X" : "Linear expression", "Y" : "Linear expression"], see_also : [(>=) / 2, (=:=) / 2, (=<) / 2, _507291 : $>= / 2, $= / 2, $=< / 2, eplex_solver_setup / 1, eplex_solver_setup / 4, eplex_probe / 2, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, eplex_cleanup / 0], summary : "Constrains X to be greater than or equal to Y.", desc : html("\tLogically: Constrains X to be greater than or equal to Y.\n\tX and Y are linear expressions.\n\tOperationally, the constraint gets delayed until the external\n        solver state for EplexInstance is invoked.\n        </P><P>\n        The $ version of the arithmetic constraints are provided to allow \n        code to be written which does not specify the solver. They are\n        equivalent to their eplex instance counterparts without the $ prefix.\n")]).
:- comment(=> / 2, [template : ["Ind => LinCon", "EplexInstance:(Ind => LinCon)"], args : ["Ind" : "A binary variable or negated binary variable", "LinCon" : "A linear constraint"], see_also : [_510750 : => / 2, $>= / 2, $= / 2, $=< / 2, eplex_add_constraints / 2], summary : "Linear constraint conditional on binary variable", desc : html("<P>\tLogical implication Ind =&ge; LinCon.  The linear constraint LinCon\n\tis enforced when the indicator Ind is 1, and violation of LinCon\n\tforces the indicator Ind to 0.\n</P><P>\n\tInd can be a variable, or a subscript expression resulting in a\n\tvariable.  It can also be negated using the neg/1 prefix operator.\n\tCorrespondingly, LinCon is either enforced by the binary being 0 or 1.\n</P><P>\n\tLinCon is any linear constraint accepted by eplex, i.e. an equality\n\tor inequality constraint over linear expressions.\n</P><P>\n\tThis constraint does not implicitly impose bounds or a type on the\n\tbinary variable in Ind.  It will usually make sense to separately\n\timpose bounds of 0..1 and invoke integers/1.\n</P><P>\n\tIndicator constraints are not supported by every external solver.\n\tUse lp_get(has_indicator_constraints,yes) to check availability.\n</P>\n    "), eg : "\n    B => ( X1 $>= X2+8 )\n    neg B => ( X1+5 $=< X2 )\n    B[12] => ( sum(Costs) $= 42 )\n"]).
:- comment(eplex_add_constraints / 2, [template : ["eplex_add_constraints(+Constraints,+Integers)", "EplexInstance: eplex_add_constraints(+Constraints,+Integers)"], args : ["Constraints" : "A (possibly empty) list of equality or inequality constraints", "Integers" : "A (possibly empty) list of variables to be considered as integers"], see_also : [lp_add_constraints / 3, lp_demon_setup / 5, lp_add / 3, lp_add_constraints / 4, $= / 2, $=< / 2, $>= / 2, (=:=) / 2, (=<) / 2, (>=) / 2, sos1 / 1, sos2 / 1, => / 2], resat : no, fail_if : "Any ground (no variable) or bound constraints (one variable) is self-inconsistent.", exceptions : [4 : "Constraints or Integers uninstantiated.", 5 : "Some constraint in Constraints is non-linear.", 40 : "Solver state had been previously destroyed."], summary : "Add new constraints to the eplex instance EplexInstance, possibly triggering it.", desc : html("<P>\n  Add new constraints (with possibly new variables) to the eplex instance\n  EplexInstance.  Cstrs is a list of equality or inequality constraints; \n  NewIntegers is a list of (possibly new) variables that should be\n  consider as integers  This is logically the same as posting the\n  constraints one by one to the solver, but it may be more convenient if \n  the constraints are already collected as a list.\n</P><P>\n  Operationally, if a solver state has been associated with the eplex\n  instance, the constraints are added to the solver state in one go. \n  For some solvers, this can be more efficient than adding the constraints\n  incrementally. \n</P><P>\n  If the new_constraint trigger option was selected, then the solver will\n  be invoked after the adding of the constraints if these constraints are \n  not already satisfied.  The constraints will be removed on backtracking.\n</P><P>\n  The constraints are normalised and simplified before being passed to\n  the external solver. If any constraint is ground, they are tested for\n  consistency.\n</P><P>\n  The constraints can be linear equalities and inequalities, sos/1 and\n  sos2/1 constraints, and =&ge;/2 indicator constraints.\n</P><P>\n  Note that variables in NewIntegers can be any problem variables. In\n  previous versions of ECLiPSe, there was a restriction that the variables\n  be new problem variables; this restriction has been removed.\n</P><P>\n\n </P>")]).
:- comment(eplex_cleanup / 0, [template : ["eplex_cleanup", "EplexInstance:eplex_cleanup"], summary : "Destroy the external solver associated with EplexInstance.", desc : html("<P>\n    Destroy the specified solver, free all memory, etc.  Note that ECLiPSe\n    will normally do the cleanup automatically, for instance when execution\n    fails across the solver setup. The solver is disassociated with \n    EplexInstance, and any outstanding constraints not yet collected by the\n    solver are removed, with a warning to the user. In effect, EplexInstance\n    is reinitialised and can now be associated with a new solver without\n    backtracking. Note that this last behaviour is unlike lp_cleanup/1, which\n    also destroy the solver and disassociate it from the eplex instance (if \n    any), but does not remove any outstanding constraints.\n</P><P>\n    This predicate should be used with caution as the information from the\n    solver state will no longer be available. In particular, if the program\n    backtracks to a point between the problem set up and clean up,\n    accessing the solver state directly or indirectly (e.g. unifying a\n    problem variable) will result in a stale handle error. \n\n</P>")]).
:- comment(eplex_get / 2, [template : ["eplex_get(++ParamName, -Value)", "EplexInstance:eplex_get(++ParamName, -Value)"], args : ["ParamName" : "Name of parameter (atom)", "Value" : "Returned value for ParamName"], summary : "Retrieve information about solver state and results for eplex instance EplexInstance.", exceptions : [5 : "EplexInstance does not a solver setup for it.", 40 : "Solver state had been previously destroyed."], see_also : [eplex_solver_setup / 4, eplex_set / 2, lp_set / 3, lp_get / 3, lp_add_constraints / 4], desc : html("<P>\n   Retrieve information about solver state and the logically most recent\n   results for the eplex instance <TT>EplexInstance</TT>. <TT>ParamName</TT> \n   is the same as that for lp_get/3, which retrieves the same information \n   via the solver state.\n</P>\n\n<DL>\n<P>  \n     <DT><STRONG><TT>vars</TT></STRONG>\n     <DD>Returns a term ''(X1,...,Xn) whose arity is the number of\n         variables involved in the solver's constraint set, and whose\n         arguments are these variables.\n\n<P>\n     <DT><STRONG><TT>ints</TT></STRONG>\n     <DD>Returns a list [Xi1,...,Xik] which is the subset of the problem\n         variables that the solver considers to be integers.\n\n<P>\n     <DT><STRONG><TT>constraints_norm</TT></STRONG>\n     <DD>Returns a list of the problem constraints (excluding any cutpool\n         constraints) in normalised form.  They may be simplified with\n         respect to the originals that were passed to the problem.\n\n<P>\n     <DT><STRONG><TT>constraints</TT></STRONG>\n     <DD>Returns a list of the problem constraints (excluding any cutppol\n         constraints) in denormalised (readable) form.  They may be\n         simplified with respect to the originals that were passed to the\n         problem.\n\n<P>\n     <DT><STRONG><TT>objective</TT></STRONG>\n     <DD>Returns a term min(E) or max(E), representing objective function\n         and optimisation direction. E is a linear expression: any\n         quadratic components will not be retrieved.\n\n<P>\n     <DT><STRONG><TT>num_cols</TT></STRONG>\n     <DD>Returns the number of columns (i.e. variables) in the matrix of the\n     solver state.\n\n<P>\n     <DT><STRONG><TT>num_rows</TT></STRONG>\n     <DD>Returns the number of rows (i.e. constraints) in the matrix of the\n     solver state.\n\n<P>\n     <DT><STRONG><TT>num_nonzeros</TT></STRONG>\n     <DD>Returns the number of non-zero coefficients in the matrix of the\n     solver state.\n\n<P>\n     <DT><STRONG><TT>num_ints</TT></STRONG>\n     <DD>Returns the number of columns (i.e. variables) constrained to be\n     integers in the matrix of the solver state.\n\n<P>\n     <DT><STRONG><TT>num_quads</TT></STRONG>\n     <DD>Returns the number of non-zero coefficients in the quadratic\n     coefficient matrix (Q-matrix) of the solver state.\n\n<P>\n     <DT><STRONG><TT>method</TT></STRONG>\n     <DD>Returns the method that is specified to solve the problem. If an\n     auxiliary  method can be given for the method, and this auxiliary\n     method is not <TT>default</TT>, the method will be returned as \n     Method(Aux), e.g. <TT>barrier(none)</TT>. The method will be \n     <TT>default</TT> unless otherwise specified by the the user (at setup or \n     via eplex_setup/2 or lp_setup/3).  In that case, the external solver's\n     defaults and any settings done via optimizer_param(_) will be used.\n\n<P>\n     <DT><STRONG><TT>node_method</TT></STRONG>\n     <DD>Applicable to MIP problems only. Returns the method that is\n     specified to solve the problem at the nodes of the branch-and-bound\n     tree. If an auxiliary method can be given for the method, and this\n     auxiliary method is not <TT>default</TT>, the method will be returned\n     as Method(Aux), e.g. <TT>barrier(none)</TT>. The method will be\n     <TT>default</TT> unless otherwise specified by the the user (at setup\n     or via eplex_setup/2 or lp_setup/3).  In that case, the external solver's\n     defaults and any settings done via optimizer_param(_) will be used.\n\n<P>\n     <DT><STRONG><TT>status</TT></STRONG>\n     <DD>Status that was returned by the most recent invocation of the \n         external solver.\n\n<P>\n     <DT><STRONG><TT>cost</TT></STRONG>\n     <DD>Objective value (i.e. cost/profit) of the current solution.\n         Fails if no solution has been computed yet.\n\n<P>\n     <DT><STRONG><TT>best_bound</TT></STRONG>\n     <DD>The best bound (for minimisation, the lower bound) on the optimal \n         objective value for the current problem. Together with the\n         worst_bound, this specifies the range for the optimal objective\n         value. Note that a non-empty range does not mean that the problem\n         is feasible unless an objective value (cost) is also\n         available. The best_bound is the same as the current objective\n         value if the problem has been solved to optimality. It can be\n         better than the objective value either because a) (for MIP\n         problems only) the problem has been optimised to within the\n         mipgap tolerance, or b) the problem was not solved to optimality,\n         i.e. it was aborted before the optimal solution was found.\n<P>\n     <DT><STRONG><TT>worst_bound</TT></STRONG>\n     <DD>The worst bound (for minimisation, the upper bound) on the optimal \n         objective value for the current problem. Together with the\n         best_bound, this specifies the range for the optimal objective\n         value. Note that a non-empty range does not mean that the problem\n         is feasible unless an objective value (cost) is also\n         available. The worst_bound is the same as the current objective\n         value if a solution has been computed for the problem, whether\n         the problem was solved to optimality or not. Depending on the \n         problem type and method used to solve the problem, a worst bound\n         can be returned for a problem even if the solving of the problem\n         was aborted before a solution was obtained. \n<P>\n     <DT><STRONG><TT>typed_solution</TT></STRONG>\n     <DD>Returns a term ''(X1,...,Xn) whose arguments are the properly\n         typed (integer or float) solution values for the corresponding\n         problem variables (<TT>vars</TT>).  The floating point solutions\n         are the same as returned by <TT>solution</TT>, the integers are\n         obtained by rounding the corresponding floating-point solution to\n         the nearest integer.  To instantiate the problem variables to\n         their solutions, unify this term with the corresponding term\n         containing the variables. Note that this unification could fail\n         if two problem variables Xa and Xb were unified after the solution \n         was lasted computed, as the solutions values in the Xa and Xb\n         positions could be different, even though they are now represented \n         by one variable.\n         Fails if no solution has been computed yet.\n\n<PRE>\n    instantiate_solution(Handle) :-\n        lp_get(Handle, vars, Vars),\n        lp_get(Handle, typed_solution, Values),\n        Vars = Values.\n</PRE>\n\n<P>\n    <DT><STRONG><TT>slack</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the constraint\n        slacks in the logically last solve. The problem consists of normal\n        constraints followed by any added cutpool constraints, and the\n        order corresponds to the list order in <TT>constraints</TT> for\n        normal constraints, and to cutpool_info(last_added,Info) for the\n        cutpool constraints.  Fails if no solution has been computed yet.\n\n<P>\n    <DT><STRONG><TT>slack(Indexes)</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the slack\n        values for the constraints represented by Indexes. Indexes are a\n        list of constraint indices (as returned by lp_add_constraints/4 for\n        normal constraints, and lp_add_cutpool_constraints/4 for cutpool\n        constraints), and the order of the returned list corresponds to the\n        order in <TT>Indexes</TT>.  Fails if no slack value has been\n        computed yet for any of the constraints in Indexes -- note that \n        values are only computed for cutpool constraints if they were added\n        to the problem.\n\n<P>\n    <DT><STRONG><TT>dual_solution</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the dual\n        solutions in the logically last solve. The problem consists of\n        normal constraints followed by any added cutpool constraints, and\n        the order corresponds to the list order in <TT>constraints</TT> for\n        normal constraints, and to cutpool_info(last_added,Info) for the\n        cutpool constraints.  Fails if no solution has been computed yet.\n\n<P>\n    <DT><STRONG><TT>dual_solution(Indexes)</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the dual\n        solutions for the constraints represented by Indexes. Indexes are a\n        list of constraint indices (as returned by lp_add_constraints/4\n        normal constraints, and lp_add_cutpool_constraints/4 for cutpool\n        constraints), and the order of the returned list corresponds to the\n        order in <TT>Indexes</TT>.  Fails if no dual solution has been\n        computed yet for any of the constraints in Indexes -- note that\n        values are only computed for cutpool constraints if they were added\n        to the problem.\n\n<P>\n    <DT><STRONG><TT>constraints(Indexes)</TT></STRONG>\n    <DD>Returns a list of problem constraints as specified by\n        Indexes in denormalised form. The constraints can be either \n        normal constraints or cutpool constraints.\n<P>\n    <DT><STRONG><TT>constraints_norm(Indexes)</TT></STRONG>\n    <DD>Returns a list of problem constraints as specified by\n        Indexes in normalised form. The constraints can be either \n        normal constraints or cutpool constraints.\n<P>\n    <DT><STRONG><TT>cutpool_info(Select,Info)</TT></STRONG>\n    <DD>Returns the information specified by Info for the cutpool constraints\n        specified by Select. The returned information is either\n        i) a pair of lists Indexes-Values where Indexes is the index for\n        the constraint in the corresponding position of Values, or \n        ii) a list of Indexes if the information requested is index. Info \n        can be:\n<DL>\n           <DT><STRONG><TT>index</TT></STRONG>\n               <DD>the indexes for the selected constraints. A list\n                   of Indexes are returned.\n           <DT><STRONG><TT>active</TT></STRONG>\n               <DD>the current active status of the selected constraints. \n                   The status is either 0 (not active) or 1 (active).\n                   A pair of lists Indexes-ActiveStatus is returned.\n           <DT><STRONG><TT>add_initially</TT></STRONG>\n               <DD>the current add_initially status of the selected \n                   constraints. The status is either 0 (not add) or 1 (add).\n                   Note that although inactive constraints have a\n                   add_initially status, they will not be added to a problem.\n                   A pair of lists Indexes-AddInitially is returned.\n           <DT><STRONG><TT>binding_state</TT></STRONG>\n               <DD>the binding state for the selected constraints in the\n                   logically last solve for the problem. A pair of lists\n                   Indexes-BindingStates is returned. To get this\n                   information, the slack values must be available from the\n                   last solve.\n                   The state can be:\n                   a) binding - the constraint was satisfied and binding, i.e.\n                      it is within tolerance of its RHS value in the\n                      normalised form. \n                   b) satisfied - the constraint was satisfied but not\n                      binding. \n                   c) inactive - the constraint was inactive.\n           <DT><STRONG><TT>constraints_norm</TT></STRONG>\n               <DD>the normalised form of the constraints for the selected \n                   constraints is returned in a pair of lists \n                   Indexes-Constraints.\n           <DT><STRONG><TT>constraints</TT></STRONG>\n               <DD>the denormalised form of the constraints for the selected \n                   constraints is returned in a pair of lists \n                   Indexes-Constraints.\n</DL>\n\n    The constraints are selected by Select, which can be:\n<DL>\n           <DT><STRONG><TT>cstr(Idx)</TT></STRONG>\n               <DD>The cutpool constraint as specified by <TT>Idx</TT>. \n           <DT><STRONG><TT>group(Name)</TT></STRONG>\n               <DD>The cutpool constraints in the group <TT>Name</TT>. Both\n                   active and non-active constraints are returned. Note that\n                   the name of the default group is the atom nil (<TT>[]</TT>).\n           <DT><STRONG><TT>last_added</TT></STRONG>\n               <DD>The cutpool constraints that were added to the\n                   problem in the logically previous solve of the problem. \n                   The constraints were either added initially, or were\n                   added because they were violated in an intermediate\n                   invocation. \n           <DT><STRONG><TT>last_notadded</TT></STRONG>\n               <DD>The cutpool constraints that were not added to the\n                   problem in the logically previous solve of the problem,\n                   i.e. they were not violated.\n           <DT><STRONG><TT>last_inactive</TT></STRONG>\n               <DD>The cutpool constraints that were inactive during the\n                   logically last solve of the problem. This does not\n                   include any constraints that were added since the last\n                   solve. \n</DL>\n<P>\n    <DT><STRONG><TT>demon_tolerance</TT></STRONG>\n    <DD>Returns a comma-separated pair <TT>(RealTol,IntTol)</TT> of\n        floating-point values which specify how far outside a variable's\n        range an lp-solution can fall before lp_demon_setup/5\n        re-triggers. The tolerances differ for real (default 0.00001) and\n        integer (default 0.5) variables.\n\n<P>\n    <DT><STRONG><TT>simplex_iterations</TT></STRONG>\n    <DD>Returns the external solver's count of simplex iterations.\n\n<P>\n    <DT><STRONG><TT>node_count</TT></STRONG>\n    <DD>Returns the external MIP solver's node count. Note that this may \n        or may not include the initial root node.\n<P>\n    <DT><STRONG><TT>statistics</TT></STRONG>\n    <DD>Returns a list of counter values <TT>[Successes, Failures,\n        Aborts]</TT>, indicating how often lp_solve/2 was invoked on the\n        Handle, and how many invocations succeeded, failed and aborted\n        respectively.\n\n<P>\n    <DT><STRONG><TT>timeout</TT></STRONG>\n    <DD>Returns the time-out value for the solver state. This is the amount\n        of CPU time in seconds that the external solver will be allow to\n        spend solving the problem before timing out. The value is 0 if \n        no time-out has been set.\n<P>\n     <DT><STRONG><TT>optimizer_param(Param)</TT></STRONG>\n     <DD>Returns the value of the external solver's parameter Param\n         for the problem represented by Handle. The external solver \n         has a number of parameters that affect the way they work, and \n         this queries their values. If Param is not a valid parameter for\n         the solver, an out of range exception is raised. See below for \n         more details on the parameters.\n<P>\n    <DT><STRONG><TT>post_equality_when_unified</TT></STRONG>\n    <DD>Returns the value (yes or no) if an equality constraint will be\n        posted to a solver if two variables in the solver's problem are \n        unified. \n<P>\n    <DT><STRONG><TT>pool</TT></STRONG>\n    <DD>Returns the name of the eplex instance (if any) associated with \n        the solver state. Fails otherwise. Only useful if called with \n        lp_get/3.\n<P>\n    <DT><STRONG><TT>handle</TT></STRONG>\n    <DD>Returns the solver state handle (if any) associated with the eplex \n        instance. Fails otherwise. Only useful if called with eplex_get/2.\n<P>\n</DL>\nNote that reduced_cost, slack, dual_solution can only be retrieved\nwhen previously requested in the option list of lp_setup/4 or with lp_set/3.\nAn out of range error will be raised otherwise.\n\n<P>\nFor the external solver's control parameter specified by\noptimizer_param(Param), Param must be an atom. The Value returned is\neither an integer, float or atom, depending on the parameter. The parameter\nis generally specific to a solver and version, and also, they may be\nproblem specific, or global, again depending on the solver version. In all\ncases, the value returned by lp_get/3 is the current value for the parameter\nfor the problem Handle. Refer to the solver documentation for details on the \nparameters. The names of the parameters are derived from the names of the \nparameters in the external solver. For CPLEX, take the parameter name from \nthe CPLEX manual (or cplex.h), remove the CPX_PARAM_ prefix and convert the \nrest to lower case, e.g.\n\n<PRE>\n        CPX_PARAM_NODELIM becomes nodelim. \n</PRE>\nFor XPRESS-MP (version 13 and newer), take the parameter name from the \nmanual (or xpresso.h), remove the XPRS_ prefix (if present) and convert \nthe rest to lower case, e.g.\n<PRE>\n\tXPRS_MAXNODE becomes maxnode. \n</PRE>\n<P>\nFor Gurobi, take the parameter name from the manual and convert it to\nall lower case, e.g.\n<PRE>\n\tIntFeasTol becomes intfeastol. \n</PRE>\n<P>\nFor solvers used via the OSI, there are a few generic parameters supported \nvia OSI, and depending on the actual solver, there may be some additional\nsolver-specific parameters. For the generic parameters, take the parameter\nname, remove the Osi prefix and convert the rest to lower case, e.g.\n<PRE>\n        OsiPrimalTolerance becomes primaltolerance\n</PRE>\n<P>\nFor GLPK, use the names of the parameter structure fields, e.g.\n<PRE>\n        tol_bnd     from glp_smcp\n        ord_alg     from glp_iptcp\n        tol_int     from glp_iocp\n        msg_lev     for all components\n</PRE>\n<P>\n    The following parameter names are additional aliases that work for\n    most solvers:\n<DL>\n    <DT><TT>feasibility_tol</TT> - float\n\t<DD>CPX_PARAM_EPRHS (CPLEX), XPRS_FEASTOL (XPRESS-MP),\n            OsiPrimalTolerance (OSI), FeasibilityTol (Gurobi) or tol_bnd (GLPK)\n    <DT><TT>integrality</TT> - float\n\t<DD>CPX_PARAM_EPINT (CPLEX), XPRS_MIPTOL (XPRESS-MP),\n            CbcIntegerTolerance (OSI,Cbc specific), IntFeasTol (Gurobi)\n            or tol_int (GLPK)\n    <DT><TT>iteration_limit</TT> - integer\n\t<DD>CPX_PARAM_ITLIM (CPLEX), XPRS_LPITERLIMIT (XPRESS-MP),\n            OsiMaxNumIteration (OSI), IterationLimit (Gurobi) or it_lim (GLPK)\n    <DT><TT>mipgap</TT> - float\n\t<DD>CPX_PARAM_EPGAP (CPLEX), XPRS_MIPRELSTOP (XPRESS-MP),\n            SolverAllowableFractionGap (OSI), MIPGap (Gurobi) or mip_gap (GLPK)\n    <DT><TT>node_limit</TT> - integer\n\t<DD>CPX_PARAM_NODELIM (CPLEX), XPRS_MAXNODE (XPRESS-MP),\n            CbcMaxNumNode (OSI, Cbc specific), NodeLimit (Gurobi)\n            or limit on tree node creation (GLPK)\n    <DT><TT>objdifference</TT> - float\n\t<DD>CPX_PARAM_OBJDIF (CPLEX), XPRS_MIPADDCUTOFF (XPRESS-MP) or\n            CbcCutoffIncrement (OSI, Cbc specific)\n</DL>\n")]).
:- comment(eplex_get_iis / 4, [summary : "Returns an IIS for an infeasible problem associated with EplexInstance.", template : ["eplex_get_iis(-NumConstraints, -NumVars, -ConstraintIdxs, -VarInfos)", "EplexInstance:eplex_get_iis(-NumConstraints, -NumVars, -ConstraintIdxs, -VarInfos)"], exceptions : [141 : "External solver does not support finding IIS", 3 : "Error in external solver while getting IIS"], args : ["NumConstraints" : "Number of constraints in the IIS", "NumVars" : "Number of variables in the IIS", "ConstraintIdxs" : "List of Indexes of the constraints in the IIS", "VarInfos" : "List of Variable:Status pairs where Variables are the variables in the IIS and Status is the status of that variable"], amode : eplex_get_iis(-, -, -, -), see_also : [lp_get_iis / 5, eplex_solver_setup / 4, eplex_solve / 1, eplex_probe / 2, eplex_get / 2, eplex_set / 2, lp_add_constraints / 4, lp_add_cutpool_constraints / 4], eg : "\n % simple inconsistency, get the constraints with constraints option of eplex_get/2\n [eclipse 6]: eplex:(X=:=Y),\n        eplex:(X+Y>=3),\n        eplex:(X+Y=<2),\n        eplex_solver_setup(min(X)),\n        eplex_set(cache_iis, yes),\n        eplex_set(infeasible_handler,\n             eplex_get_iis(NC,BV, Is, Vs),\n             eplex_get(constraints(Is), Cs))),\n        eplex_solve(C).\n  CPLEX Error  1217: No solution exists.\n \n  X = X{-1e+20 .. 1e+20}\n  Y = Y{-1e+20 .. 1e+20}\n  NC = 2\n  BV = 0\n  Is = [0, 1]\n  Vs = []\n  Cs = [X{-1e+20 .. 1e+20} + Y{-1e+20 .. 1e+20} =< 2.0, X + Y >= 3.0]\n  C = C\n  Yes (0.00s cpu)\n  [eclipse 7]:\n\n  % simple example using cutpool constraints and cache_iis option\n  [eclipse 7]:         eplex:(X=:=Y), eplex_solver_setup(min(X)),\n        eplex_set(cache_iis, yes), eplex_set(infeasible_handler, eplex_get_iis(NC,NV,Is,Vs)),\n        eplex_get(handle, H),\n        lp_add_cutpool_constraints(H, [(X+Y>=4),(2*X =:= 2*Y), (X+Y=<3)], [], Idxs),\n        eplex_solve(C).\n  \n                                CPLEX Error  1217: No solution exists.\n \n  X = X{-1e+20 .. 1e+20}\n  Y = Y{-1e+20 .. 1e+20}\n  NC = 2\n  NV = 0\n  Is = [g(2, 0), g(2, 2)]\n  Vs = []\n  H = lp_handle(0)\n  Idxs = [g(2, 0), g(2, 1), g(2, 2)]\n  C = C\n  Yes (0.00s cpu)\n  [eclipse 8]:\n  ", desc : html("    <P>\n    If the solver found that the problem was infeasible, this predicate\n    will return an IIS (Irreducible Infeasible Subsystem or Irreducible\n    Inconsistent Subsystem) for the problem, if supported by the solver. \n<P>\n    This predicate must be called from within a user defined \n    infeasible_handler, and with the cache_iis option set to yes (both\n    can be set during solver set-up or using eplex_set/2). The reason for\n    this is the IIS must be computed by the solver before the failed\n    solver state changes, and backtracking pass the failure (the normal \n    behaviour when a problem is infeasible) will logically remove the failed \n    state. cache_iis is needed because the default setting for this\n    option is no, as the IIS need to be computed as an extra step, so\n    IIS is normally not computed.\n<P>\n    An IIS is a subset of the problem constraints and variables which\n    defines an infeasible subproblem. It is usually irreducible in that\n    any proper subset of the IIS is feasible. Finding an IIS allows the\n    diagnostic analysis of the infeasible problem. Note that a problem\n    may have more than one infeasibility, and thus more than one IIS, \n    but this predicate only returns one. \n    </P><P>\n    NumConstraints and NumVars are the number of constraints and variables\n    that are in the IIS. ConstraintIdxs is a list of the constraint indexes\n    of the constraints in the IIS, these indexes are the indexes that are\n    returned by lp_add_constraints/4 and lp_add_cutpool_constraints/4, and can \n    also be used to retrieve the constraint with the constraints_norm(Indexes)\n    and constraints(Indexes) options of eplex_get/2 and lp_get/3. VarInfos gives\n    information for the variables in the IIS, and is a list of Var:Status\n    pair, where Var is a variable in the IIS, and Status is its status.\n    Status is a one character string, and can be:\n<DL>\n       <DT>\"b\": <DD>if both bounds of the variable are involved in the infeasibility\n       <DT>\"u\": <DD>if the upper bound of the variable is involved in the infeasibility\n       <DT>\"l\": <DD>if the lower bound of the variable is involved in the infeasibility\n       <DT>\"x\": <DD>if it is unknown which bound is involved in the infeasibility\n</DL><P>\n    An IIS is returned only if finding IIS is supported by the external\n    solver. In addition, the solver may limit the type of problems and the\n    information returned by the IIS, for example, finding an IIS may be\n    limited to linear problems, and/or bound status information may be\n    unavailable for the variables (hence the need for the \"x\" status).\n    Consult the solver's manual entry for infeasibility analyses for more detail.   \n</P><P>\n    For some external solvers, and for problems on the boundary between\n    feasible and infeasible, it is possible that the routine that finds\n    the IIS will conclude that the problem is feasible, even though it was\n    considered infeasible when the problem was solved. In such cases, an\n    empty IIS will be returned.\n")]).
:- comment(eplex_instance / 1, [amode : eplex_instance(++), args : ["EplexInstance" : "Eplex instance name (atom)"], summary : "Initialises the eplex instance EplexInstance.", desc : html("  <P>\n  Initialises the eplex instance EplexInstance. An eplex instance is an\n  instance of the eplex solver, to which eplex linear arithmetic and \n  integrality constraints can be posted, and to which an external LP/MIP\n  solver can be associated and used to optimise the posted constraints\n  with respect to some objective. \n  </P><P>\n  If EplexInstance is not an already existing eplex instance, a new eplex\n  instance will be created and initialised. If it is an existing eplex\n  instance, and it is not currently being used (having no outstanding posted\n  constraints and no associated solver), it is effectively reinitialised.\n  Otherwise, the predicate aborts with an error. Note that an eplex instance\n  is a module, and each eplex instance can be associated with at most one\n  solver at any time and vice versa. An eplex instance should NOT be\n  erased (e.g. using erase_module/1), as this would only erase the module,\n  but not the information that eplex keeps on it as an eplex instance.\n  </P>\n  "), see_also : [$= / 2, $=< / 2, $>= / 2, $:: / 2, integers / 1, reals / 1, eplex_solver_setup / 1, eplex_solver_setup / 4, eplex_probe / 2, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, eplex_cleanup / 0]]).
:- comment(eplex_probe / 2, [template : ["eplex_probe(+Probes, -Cost)", "EplexInstance:eplex_probe(+Probes, -Cost)"], args : ["Probes" : "Temporary probe specification(s)", "Cost" : "Value of solution"], summary : "Invoke EplexInstance's external solver, probing the problem temporarily modified by the probe specifications.", see_also : [eplex_solve / 1, eplex_solver_setup / 1, eplex_solver_setup / 4, eplex_get / 2, eplex_var_get / 3, eplex_set / 2, lp_add_constraints / 4], desc : html("<P>\n   Similar to eplex_solve/1, but the problem is first temporarily modified\n   as specified in Probes. Probes is a list of one or more probe\n   specifications that specifies how the problem is modified. The\n   objective value of the modified problem is unified with Cost\n   after the solve. Cost should be a free variable.\n</P><P>\n   After the call to this predicate, the problem is restored for the \n   external solver. However, the results from the probe (obtainable from\n   eplex_var_get/3 and eplex_get/2) are retained.\n</P><P>\n   The following probe specifications are allowed:\n<DL>\n    <DT>min(Expr)/max(Expr)</DT><DD>\n        Minimise/maximise the problem with the objective function Expr.\n        Only existing problem variables can be given in Expr. Cannot be\n        used in conjunction with objsense, objexpr or perturb_obj.</DD>\n    <DT>objsense(Sense)</DT><DD>\n        Sense is either min or max. Solves the problem with the original\n        objective function, but with the sense given in Sense rather than\n        that specified at setup. If only the sense of the objective is to \n        be changed, this changes the objective more efficiently than using\n        min(Expr)/max(Expr). Cannot be used in conjunction with min/max.</DD>\n    <DT>objexpr(Expr)</DT><DD>\n        Optimise the problem with respect to the objective function Expr,\n        without changing the optimisation direction specified at problem\n        setup. Cannot be used in conjunction with min/max or perturb_obj.</DD>\n    <DT>perturb_obj(ObjDeltas)</DT><DD>\n        Perturb the existing linear objective coefficients as specified by\n        ObjDeltas. ObjDeltas is a (possibly empty) list of specifications\n        Var : Delta, where Var is a problem variable and Delta is the\n        amount its existing objective coefficient should be changed by. For\n        example, if the existing objective is 2*X + 3*Y + Z, \n        perturb_obj([X : 1, Y : -0.5]) will modify the objective to \n        3*X + 2.5*Y + Z for the probe. If a variable occurs more than once in\n        ObjDeltas, the change to the objective coefficient is cumulative.\n        Perturb_obj is not strictly needed, as its effect can be achieved\n        by constructing the whole objective and then probing with that.\n        However, this can be expensive if most of the objective stays \n        unchanged, with only a few of its coefficients changed. It is \n        recommended that perturb_obj probe be used in such cases. \n        Cannot be used in conjunction with objexpr or min/max.</DD>\n    <DT>rhscoeffs(RhsCoeffs)</DT><DD>\n        Alter the rhs coefficients of the matrix as specified by RhsCoeffs.\n        RhsCoeffs is a (possibly empty) list of rhs coefficient\n        specifications of the form Idx : Rhs, where Idx is the index of the\n        expandable constraint obtained from using lp_add_constraints/4, and\n        Rhs is the value for the right-hand side constant to use during the\n        probe. Any constraints not specified in RhsCoeffs remain unchanged\n        during the probe. If Idx occurs more than once in RhsCoeffs, the\n        result is undefined.</DD>\n    <DT>bounds(BoundsChanges)</DT><DD>\n        Alter the bounds of problem variables as specified by\n        BoundsChanges. BoundsChanges is a (possibly empty) list of bounds\n        changes of the form Var $:: Lo..Hi, where Var is a problem variable\n        and Lo and Hi are the new lower and upper bounds to use for the\n        variable during the probe. Unlike normal bound changes, the bounds\n        can be widened as well narrowed, although failure will still occur\n        if Hi &lt; Lo. Variables not specified in BoundsChanges retain their\n        bounds during the probe. If Var occurs more than once in \n        BoundsChanges, the result is undefined.</DD>\n    <DT>fixed</DT><DD>\n        The problem is solved as an LP problem by `fixing' the integer\n        variables to their optimal MIP solution values. If there is an\n        existing MIP solution for the problem, eplex will try to use that;\n        otherwise, a MIP solution is obtained first.\n        `Fixed' probing is useful for providing reduced costs for\n        MIP problems. Note that reduced costs for the variables will only be\n        available if the reduced_cost option for the problem is set to yes\n        (this can be done either at problem setup, or by using\n        eplex_set/2). For a problem without integer variables, the original\n        problem is solved without change.  Note that this probe\n        specification is not available if the mip_use_copy option is set to\n        no for external solvers that cannot modify a MIP problem.  Cannot\n        be used in conjunction with `relaxed'.</DD>\n    <DT>relaxed</DT><DD>\n        The problem is solved as an LP problem by relaxing all the integer\n        constraints.  For a problem with integer variables, this should be\n        equivalent to the initial relaxation solved at the start of the MIP\n        search. Depending on the solver, the discreteness of the integer\n        variables may still be taken into account during presolve. To\n        ensure that the problem solved is exactly the LP problem without\n        any integer constraints, presolve should be off. For a problem\n        without integer variables, the original problem is solved without\n        change. Note that this probe specification is not available if the\n        mip_use_copy option is set to no for external solvers that cannot\n        modify a MIP problem. Cannot be used in conjunction with `fixed'.</DD>\n\n</DL>\n</P>"), fail_if : "External solver was unable to find a solution, or bounds probe used and the specified interval for some variable is empty", exceptions : [5 : "EplexInstance does not have a solver setup for it.", eplex_suboptimal : "Solution was found, but is possibly suboptimal", eplex_unbounded : "Problem is unbounded, no solution values", eplex_unknown : "Result is unknown (infeasible or unbounded)", eplex_abort : "External solver aborted for some reason", abort : "Incorrect specification for the probe(s)", 6 : "mip_use_copy option was set to no (solver dependent) for probes that require yes.", 40 : "Solver state had been previously destroyed."]]).
:- comment(eplex_read / 2, [template : ["eplex_read(++Format,++File)", "EplexInstance:eplex_read(++Format,++File)"], args : ["Format" : "lp or mps", "File" : "File name"], see_also : [eplex_write / 2, lp_write / 3, lp_setup / 4, eplex_probe / 2], summary : "Read a problem from a file into eplex instance EplexInstance.", exceptions : [5 : "EplexInstance already has a solver setup for it."], desc : html("\n   Read a problem from a file and setup a solver for it in EplexInstance.\n   A solver should not already be setup for EplexInstance. Format is lp or\n   mps. Note that minimisation of the objective is assumed for mps format,\n   as the sense of the objective is not included in the mps format.\n   Minimisation is also assumed for external solvers that ignore the\n   optimisation direction of the lp file (e.g. Xpress).  Note also that\n   although quadratic problems can be read in correctly if supported by the\n   external solver, the quadratic objective coefficients are not extracted\n   from the problem by eplex. These coefficients are used to set/reset the\n   objective when a problem is probed with a different objective in\n   eplex_probe/2 or lp_probe/3, so the objective will not be changed or\n   restored correctly in this case.  \n")]).
:- comment(eplex_set / 2, [template : ["eplex_set(++ParamName, +Value)", "EplexInstance:eplex_set(++ParamName, +Value)"], args : ["ParamName" : "Name of parameter (atom)", "Value" : "New value for ParamName"], resat : no, summary : "Change initial options for solver state associated with EplexInstance", exceptions : [5 : "EplexInstance does not a solver setup for it.", 40 : "Solver state had been previously destroyed."], see_also : [eplex_solver_setup / 4, eplex_set / 2, eplex_get_iis / 4, lp_set / 3, lp_get / 3], desc : html("<P>\nThis primitive can be used to change some of the initial options\neven after setup of a solver for eplex instance <EM>EplexInstance</EM>.\n<EM>What</EM> can be one of the following:\n\n<DL>\n    <DT><STRONG><TT>method</TT></STRONG>\n        <DD>Set the method that will be used to solve the problem.  Value\n        is one of <TT>default, auto, primal, dual, net, net(Simplex), barrier,\n        barrier(Crossover), sifting, sifting(SubMethod), concurrent,\n\tconcurrent_det</TT>.  Simplex can be one of <TT>default, auto, primal, dual</TT>,\n\tspecifying the Simplex method to use in the Network Simplex algorithm.\n\tCrossover can be one of <TT>default, auto, primal, dual, none</TT>,\n\tspecifying the crossover method to use for the barrier method.\n\tSubMethod could be one of default, auto, primal, dual, net, barrier</TT>,\n\tspecifying the method to use for the subproblems in the sifting method.\n\tNote that not every method is available on every external solver.\n\tIn case of MIP solving, this is the start algorithm (the one that\n\tis used to solve the initial relaxation). This method setting will\n\toverride similar settings done via optimizer_param(_).\n\n<P>\n    <DT><STRONG><TT>node_method</TT></STRONG>\n        <DD>Applicable to MIP problems only. Set the method that will be\n        used to solve the problem at the nodes (except the root) of the \n        branch-and-bound tree. Note that the method for solving the root\n        node is controlled by the <TT>method</TT> option. Value can be set\n        to the same values as in the <TT>method</TT> option, although \n        there may be more restrictions on what the actual methods/auxiliary\n        methods that are allowed in combination with the root method,\n        due to limitations/restrictions from the external solver. A warning\n        will be given when the problem is solved if this is the case, and \n        the default method used instead.  This node_method setting will\n\toverride similar settings done via optimizer_param(_).\n\n<P>\n    <DT><STRONG><TT>solution</TT></STRONG>\n        <DD>Make the solutions available each time the problem has been\n        (re-)solved successfully.\n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>reduced_cost</TT></STRONG>\n        <DD>Make the reduced costs available each time the problem has been\n        (re-)solved successfully. If the problem is a MIP, then depending on\n        the external solver, this is either unavailable or are the values\n        for the optimal LP node. \n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>slack</TT></STRONG>\n        <DD>Make the constraint slacks available each time the problem has been\n        (re-)solved successfully.\n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>dual_solution</TT></STRONG>\n        <DD>Make the dual solutions available each time the problem has been\n        (re-)solved successfully. If the problem is a MIP, then depending on\n        the external solver, this is either unavailable or are the values\n        for the optimal LP node. \n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>keep_basis</TT></STRONG>\n        <DD>Store the basis each time the problem has been solved successfully,\n        and use this basis as a starting point for re-solving next time.\n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>mipstart</TT></STRONG>\n        <DD>Use the previous solution values as a warm-start heuristics for\n\tthe MIP search.  This only has an effect for certain solvers (e.g.\n\tGurobi), if there are integrality constraints, and if there is a \n\tprevious solution available.  Possible values are <TT>none</TT>\n\t(no mipstart values, the default), <TT>all</TT> (use previous\n\tsolution for all variables), or <TT>integers</TT> (use previous\n\tsolution for all variables that are now constrained to be integral).  \n\n<P>\n    <DT><STRONG><TT>cache_iis</TT></STRONG>\n        <DD>When a problem is found to be infeasible, compute an IIS for the problem\n        (if supported by the external solver), and store it so that it can bee retrieved\n        by eplex_get_iis/4 or lp_get_iis/5. This will be done before the problem can\n        be modified and make the computing of the IIS impossible. The IIS will only\n        be available before the problem is solved again, and before the infeasible  \n        solve is backtracked. This option has no effect if the external solver does not \n        support the finding of IIS. Note that if this option is set, eplex will always ask\n        for an IIS to computed for an infeasible problem, even if it is immediately backtracked \n        by the infeasible handler failing, and that the option is only needed if the problem \n        instance in the external solver is modified before eplex_get_iis/4 or lp_get_iis/5 is called. \n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>demon_tolerance</TT></STRONG>\n        <DD>Specify how far outside a variable's range an lp-solution\n        can fall before lp_demon_setup/5 re-triggers.\n        Value is a comma-separated pair <TT>(RealTol,IntTol)</TT> of \n        floating-point values (default <TT>(0.00001,0.5)</TT>).\n\n<P>\n    <DT><STRONG><TT>use_var_names</TT></STRONG>\n        <DD>Specify if variable names (set using <TT>set_var_name/2</TT> of the\n        var_name library) should be passed to the external solver. If a\n        particular variable does not have a name, a solver's default name\n        would be used. Note that for XPRESS-MP, there is a limit on the\n        length of the name, which can be changed between 8 and 64 in steps\n        of 8 with the parameter <TT>N_NAMLEN</TT>. Variable names longer\n        than this limit are truncated to the limit. Note also that only \n        new variables from constraints added after the <TT>lp_set/3</TT> call \n        will pass their names to the external solver.\n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n<P>\n    <DT><STRONG><TT>timeout</TT></STRONG>\n        <DD>Set the external solver to time-out after <TT>Value</TT>\n        seconds.  The solver will abort (in either the abort or suboptimal\n        state, depending on if a suboptimal solution was found) if the\n        optimal solution was not found within the time limit. In cases\n        where the solver expects an integer for the time-out interval, the\n        time given is rounded up to the next integer value. This should be\n        used instead of the solver specific optimizer_param(Param) for\n        setting timeouts, as eplex sets these parameter(s) itself. Note\n        that the exact behaviour of the timeout setting is solver dependent.\n        Value is a positive number.\n<P>\n<DT><STRONG><TT>suboptimal_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver returned a suboptimal solution (because the problem\n        was aborted). Value would replace any existing suboptimal handler,\n        and would also be run in place of raising the default\n        <TT>eplex_suboptimal</TT> event.\n<P>\n<DT><STRONG><TT>unbounded_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        problem is unbounded. Value would replace any existing unbounded\n        handler, and would be run in place of raising the default\n        <TT>eplex_unbounded</TT> event.\n<P>\n<DT><STRONG><TT>infeasible_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver found the problem to be infeasible. Value would\n        replace any existing infeasible handler, and would be run in place\n        of raising the default <TT>eplex_infeasible</TT> event. Note that\n        the default and logically correct behaviour is to fail, this\n        handler is provided to allow the user to analyse the cause of the\n        infeasibility. It is recommended that the handler should also fail\n        after performing the analysis.\n<P>\n<DT><STRONG><TT>unknown_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver was not able to determine if the problem is\n        unbounded Value would replace any existing unknown handler, and\n        would be run in place of raising the default <TT>eplex_unknown</TT>\n        event.\n<P>\n<DT><STRONG><TT>abort_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver aborted without finding any solution.  Value would\n        replace any existing abort handler, and would be run in place of\n        raising the default <TT>eplex_abort</TT> event.\n<P>\n    <DT><STRONG><TT>optimizer_param(Param)</TT></STRONG>\n        <DD>Set the external solver's control parameter Param for the problem\n        <TT>Handle</TT>. If the solver's parameters are global and not\n        problem specific, an unimplemented functionality exception would\n        be raised. See lp_get/3 for more details on the external solver's\n        parameters. Note that the new setting is <EM>not</EM> undone on \n        backtracking.\n<P>\n    <DT><STRONG><TT>write_before_solve</TT></STRONG>\n       <DD>Value can be the pair (Format,File) or the atom no. If\n       (Format,File) is given, Eplex will ask the external solver to dump\n       the problem each time the solver is solved. This allows the problem\n       in an <TT>eplex_probe/2</TT> or <TT>lp_probe/3</TT> to be dumped. As\n       in <TT>lp_write/3</TT>, <TT>Format</TT> is the format of the dumped\n       problem, and File is the filename. See for more details. Note that\n       the problem is dumped each time the external solver is invoked if\n       the problem has cutpool constraints, where there may be multiple\n       invocations of the solver per solver call.  `no' for Value will turn\n       off this dumping.\n<P>\n    <DT><STRONG><TT>post_equality_when_unified</TT></STRONG>\n        <DD>Value can be the atoms yes or no. Determines if an equality\n        constraint will be posted to a solver when two of its variables are\n        unified. Setting Value to no means that the constraint will not be\n        posted. Note that this could mean that the\n        solver's problem may become inconsistent with ECLiPSe's. \n<P>\n</DL>\n  Making solutions available means that they can be retrieved using\n  lp_get/3 or lp_var_get/4 after the solver has been run successfully.\n</P><P>\n  All settings apart from optimizer_param(Param) will be undone on backtracking!\n</P>")]).
:- comment(eplex_solve / 1, [template : ["eplex_solve(-Cost)", "EplexInstance:eplex_solve(-Cost)"], args : ["Cost" : "Value of returned solution"], summary : "Explicitly invoke the external solver associated with EplexInstance.", fail_if : "External solver was unable to find a solution (default behaviour)", see_also : [eplex_solver_setup / 4, eplex_solver_setup / 1, eplex_var_get / 3, eplex_get / 2, $= / 2, $=< / 2, $>= / 2, $:: / 2, integers / 1, reals / 1], desc : html("<P>\n   Explicitly triggers the solver associated with the eplex instance \n   EplexInstance. If the solver was set up without any trigger conditions,\n   then it needs to be explicitly triggered via a call to this predicate.\n   The objective value of the solve is unified with Cost, which should be a\n   free variable.\n</P><P>\n   The external solver's LP, QP or MIP solver is applied to the\n   problem represented by the eplex instance.  Precisely which method is used\n   depends on the options given at set up.  eplex_solve/1 fails if\n   there is no solution or succeeds if an optimal solution is found,\n   returning the solution's cost in Cost. After a success, various\n   solution and status information can be retrieved using eplex_get/2\n   and eplex_var_get/3.\n</P><P>\n   Normally, the external solver is invoked once per call in this\n   predicate, but if the problem contain cutpool constraints (see\n   lp_add_cutpool_constraints/4), then the external solver may be invoked\n   repeatedly to produce a solution which does not violate the cutpool\n   constraints. \n</P><P>\n   When a solver is triggered repeatedly, each invocation will\n   automatically take into account the current variable bounds.  The set of\n   constraints considered by the solver is the one given when the solver\n   was created plus any new constraints that were posted in the\n   meantime.\n</P><P>\n   The user can define their own handlers (per eplex instance/problem) to\n   handle cases where there was some  error condition, or some limits were \n   exceeded during the solving of the problem. If no handler was defined,\n   by default an event would be raised. These are:\n<DL>\n    <DT>suboptimal handler (eplex_suboptimal event)<DD>\n    \tThis means that a solution was found but it may be suboptimal.\n\tThe default behaviour is to print a warning and succeed.\n    <DT>unbounded_handler (eplex_unbounded event)<DD>\n\tThis means that the problem is unbounded. The default\n\tbehaviour is to bind Cost to infinity (positive or negative\n\tdepending on the optimisation direction), print a warning and\n\tsucceed.  CAUTION: No solution values are computed when the\n\tproblem is unbounded, so unless the problem was set up with\n\tthe solution(no) option, an error will occur when trying to\n\tcontinue as if the optimisation had succeeded.\n    <DT>infeasible_handler (eplex_infeasible event)<DD>\n    \tThis means that the problem is infeasible. The default\n\tbehaviour is to fail. Redefining this handler allows the \n        examination of the failed problem, e.g. obtaining an IIS for it.\n    <DT>unknown_handler (eplex_unknown event)<DD>\n    \tThis means that due to the solution method chosen, it is unknown\n\twhether the problem is unbounded or infeasible. The default\n\tbehaviour is to print a warning and fail (even though this\n\tmay be logically wrong!).\n    <DT>abort_handler (eplex_abort event)<DD>\n    \tSome other error condition occurred during optimisation.\n\tThe default behaviour is to print an error and abort.\n</DL>\n</P><P>\n   Note that the events are raised for the low-level primitive lp_solve/2,\n   which is called by eplex_solve/1.\n</P>"), exceptions : [5 : "EplexInstance does not a solver setup for it.", eplex_suboptimal : "Solution was found, but is possibly suboptimal", eplex_unbounded : "Problem is unbounded, no solution values", eplex_unknown : "Result is unknown (infeasible or unbounded)", eplex_abort : "External solver aborted for some reason", 40 : "Solver state had been previously destroyed."]]).
:- comment(eplex_solver_setup / 1, [template : ["eplex_solver_setup(+Objective)", "EplexInstance:eplex_solver_setup(+Objective)"], args : ["Objective" : "Objective function: min(CostExpr) or max(CostExpr)"], summary : "Setup an external solver state for eplex instance EplexInstance", see_also : [$= / 2, $=< / 2, $>= / 2, $:: / 2, integers / 1, reals / 1, eplex_solver_setup / 4, eplex_probe / 2, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, optimize / 2, optimize / 3], desc : html("<P>\n  Setup a new external solver state for the eplex instance EplexInstance. \n  The solver state will be associated with EplexInstance;\n  EplexInstance must not already have a solver state associated with it.\n  Once the solver state is setup, it can be invoked (e.g. via eplex_solve/1 \n  or eplex_probe/2) to optimise the Objective function. \n</P><P>\n    CostExpr is a linear expression\n    (or quadratic if supported by the external solver).\n</P><P>\n  Declaratively, this can be seen as a compound constraint representing all\n  the individual linear constraints that have been set so far and are going\n  to be set up later for <TT>EplexInstance</TT>. The invoking of this \n  constraint is done explicitly by the user, usually via eplex_solve/1.\n  Operationally, when the external solver is invoked, the delayed \n  constraints posted to <TT>EplexInstance</TT> are collected and taken into\n  account.\n</P><P>\n  This is a simplified version of eplex_solver_setup/4, it is equivalent to\n  calling eplex_solver_setup/4 with the following defaults:\n<PRE>\n       eplex_solver_setup(Objective, _, [], [])\n</PRE>\n")]).
:- comment(eplex_solver_setup / 4, [template : ["eplex_solver_setup(+Objective, ?Cost, ++ListOfOptions, +TriggerModes)", "EplexInstance:eplex_solver_setup(+Objective, ?Cost, ++ListOfOptions, +TriggerModes)"], args : ["Objective" : "Objective function: min(CostExpr) or max(CostExpr)", "Cost" : "Variable bounded by the optimal solution", "ListOfOptions" : "List of solver options", "TriggerModes" : "List of conditions for re-triggering solver"], summary : "Setup an external solver state for eplex instance EplexInstance", see_also : [$= / 2, $=< / 2, $>= / 2, $:: / 2, integers / 1, reals / 1, eplex_solver_setup / 1, eplex_probe / 2, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, eplex_get_iis / 4, lp_demon_setup / 5, lp_setup / 4, optimize / 2, optimize / 3], desc : html("<P>\n  Setup a new external solver state for the eplex instance EplexInstance. \n  The solver state will be associated with EplexInstance;\n  EplexInstance must not already have a solver state associated with it.\n  This predicate allow various options to be specified when setting up the\n  solver state. <TT>ListOfOptions</TT> allows a list of solver options to \n  be specified, and <TT>TriggerModes</TT> allows the \n  solver state to be set up as a demon so that the external solver is \n  automatically invoked when the conditions for re-triggering specified in\n  <TT>TriggerModes</TT> are met. The external solver can also be invoked \n  explicitly via eplex_solve/1. \n</P><P>\n  Declaratively, this can be seen as a compound constraint representing all\n  the individual linear constraints that have been set so far and are going\n  to be set up later for <TT>EplexInstance</TT>. Operationally, when the\n  external solver is invoked, the delayed constraints posted to \n  <TT>EplexInstance</TT> are collected and taken into account.\n</P><P>\n  <TT>CostExpr</TT> is a linear cost expression (or quadratic, if supported\n  by the external solver).\n</P><P>\n  The external solver's best objective bound will be exported as a bound\n  for <TT>Cost</TT>: For a minimisation problem, each solution's best bound\n  becomes a lower bound, for maximisation an upper bound on Cost.  This\n  technique allows for repeated re-solving with reduced bounds or added\n  constraints. Note that Cost is not automatically made a problem variable\n  (it can be a problem variable if there are constraints that involve it),\n  and thus may not have bounds associated with in. In order for the bounds\n  information not to be lost, some bounds should be given to <TT>Cost</TT>\n  (e.g. making it a problem variable (but this might introduce unnecessary\n  self-waking on bounds change), or via another solver with bounds\n  (e.g. ic)).\n</P><P>\n  <TT>ListOfOptions</TT> is the same as in the low-level primitive \n  lp_demon_setup/5, except that EplexInstance is implicitly associated with\n  the new external solver state, so the <TT>collect_from</TT> option of\n  lp_demon_setup/5 is not allowed (it is set to <TT>\n  collect_from(pool(EplexInstance))</TT> by the predicate). See \n  below for more details.\n</P><P>\n  <TT>TriggerModes</TT> specifies under which conditions the external solver\n  will be re-triggered. If no condition is specified, then the solver must\n  be explicitly triggered, usually via eplex_solve/1. The conditions are the\n  same as in the low-level primitive lp_demon_setup/5 called by this predicate.\n  See below (after <TT>ListOfOptions</TT> descriptions) for more details.\n</P><P>\n  Note: Some external solvers need to write temporary files when they\n  are solving a problem. These are written to the temporary directory\n  specified in ECLiPSe's tmp_dir setting (get_flag/2, set_flag/2).\n\n</P><P>\nListOfOptions are (unless explicitly specified otherwise, each option should \noccur no more than once):\n\n<DL>\n\n<P>\n<DT><STRONG><TT>initial_solve(+YesNo)</TT></STRONG>\n    <DD>Specifies if an initial solve (call to the external solver) should\n    be performed immediately after problem setup.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>yes</TT> if any trigger condition is specified in TriggerModes, \n    <TT>no</TT> if no trigger condition is specified.\n\n<P>\n<DT><STRONG><TT>method(+Method)</TT></STRONG>\n    <DD>Use the specified method (<TT>primal, dual, net, barrier, sifting,\n    default, auto, concurrent, concurrent_det</TT>) (representing Primal\n    Simplex, Dual Simplex, Network Simplex, Barrier, etc) to solve\n    the problem. For MIP problems, this specifies only the start algorithm \n    (the one that is used to solve the initial relaxation). The option\n    node_method should be used to specify the method for the other nodes. \n<P> \n    For some of the methods, an additional `auxiliary' method may be \n    specified in brackets. These are:\n<DL>\n<P>\n      <DT><TT>net(Simplex)</TT>: \n      <DD>specifies the Simplex method (<TT>primal</TT> or <TT>dual</TT>) to \n      follow the network optimisation. For LP problems only.\n<P>\n      <DT><TT>barrier(Crossover)</TT>: \n      <DD>specifies how the crossover to a basic solution from the barrier\n      solution is performed. <TT>Crossover</TT> can be <TT>primal</TT>, \n      <TT>dual</TT>, or <TT>none</TT>. <TT>none</TT> means no crossover is\n      performed. \n<P>\n      <DT><TT>sifting(SubMethod)</TT>: \n      <DD>specifies the method for solving the sifting subproblem. \n      <TT>SubMethod</TT> can be <TT>primal, dual, net, barrier</TT>.\n<P>\n</DL>\n    For all the auxiliary methods, <TT>default</TT> can also be specified.\n    This is equivalent to not specifying an auxiliary method at all. \n<P>\n    Note that not every method is available on every external solver.\n    The default method would use the solver's default method, or any\n    selections done via solver-specific optimizer_param(_) settings.\n\n<P>\n<DT><STRONG><TT>node_method(+Method)</TT></STRONG>\n    <DD>For MIP problems only. Use the specified method (<TT>default, primal,\n    dual, net, barrier, sifting</TT>) to solve the subproblem at each node\n    of the MIP search-tree, except the root node, which is specified by\n    <TT>method</TT> option above. See method option for more description of\n    the methods. Note that there are less choices in the specifications of\n    the auxiliary methods that in the method option, due to limitations in\n    the solvers. If a specified auxiliary method cannot be used, `default'\n    will be used instead.\n<P>\n<DT><STRONG><TT>solution(+YesNo)</TT></STRONG>\n    <DD>Make the solutions available each time the problem has been (re-)solved\n    successfully.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>yes</TT>.\n\n<P>\n<DT><STRONG><TT>dual_solution(+YesNo)</TT></STRONG>\n    <DD>Make the dual solutions available each time the problem has been \n    (re-)solved successfully. If the problem is a MIP, then depending on\n    the external solver, this is either unavailable or are the values for\n    the optimal LP node. \n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>slack(+YesNo)</TT></STRONG>\n    <DD>Make the constraint slacks available each time the problem has been \n    (re-)solved successfully.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>reduced_cost(+YesNo)</TT></STRONG>\n    <DD>Make the reduced costs available each time the problem has been \n    (re-)solved successfully. If the problem is a MIP, then depending on\n    the external solver, this is either unavailable or are the values for\n    the optimal LP node. \n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>keep_basis(+YesNo)</TT></STRONG>\n    <DD>Store the basis each time the problem has been solved successfully,\n    and use this basis as a starting point for re-solving next time.\n    This option only affects performance.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>mipstart(+Option)</TT></STRONG>\n    <DD>Use the previous solution values as a warm-start heuristics for\n    the MIP search.  This only has an effect for certain solvers (e.g.\n    Gurobi), if there are integrality constraints, and if there is a \n    previous solution available.  Possible values are <TT>none</TT>\n    (no mipstart values, the default), <TT>all</TT> (use previous\n    solution for all variables), or <TT>integers</TT> (use previous\n    solution for all variables that are now constrained to be integral).  \n\n<P>\n    <DT><STRONG><TT>cache_iis(YesNo)</TT></STRONG>\n     <DD>Specify if an IIS should be computed immediately for an infeasible problem\n     (if supported by the external solver), and store it so that it can bee retrieved by\n     eplex_get_iis/4 or lp_get_iis/5 (called from within a user-defined infeasible \n     handler). This will be done before the problem can be modified and make the computing \n     of the IIS impossible. The IIS will only be available before the problem is solved\n     again, and also before the infeasible solve is backtracked. This option has no effect  \n     if the external solver does not support the computation of an IIS. Note that if this \n     option is set, eplex will always ask for an IIS to computed for an infeasible problem, \n     even if it is immediately backtracked by the infeasible handler failing, and that the \n     option is only needed if the problem instance in the external solver is modified \n     before eplex_get_iis/4 or lp_get_iis/5 is called. \n     YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>demon_tolerance(RealTol, IntTol)</TT></STRONG>\n    <DD>Specify how far outside a variable's range an lp-solution\n    can fall before lp_demon_setup/5 re-triggers.\n    <TT>RealTol</TT> and <TT>IntTol</TT> are floats and default to\n    0.00001 and 0.5 respectively.\n\n<P>\n<DT><STRONG><TT>sos1(VarList)</TT></STRONG> - deprecated, use sos1/1 constraint\n    <DD><TT>VarList</TT> is a list of variables which the solver should\n    treat as variables of a type 1 special ordered set (SOS), i.e. at most\n    one of the variables in the set can be non-zero. This can occur multiple\n    times, for different sets of variables.\n\n<P>\n<DT><STRONG><TT>sos2(VarList)</TT></STRONG> - deprecated, use sos2/1 constraint\n    <DD><TT>VarList</TT> is a list of variables which the solver should\n    treat as variables of a type 2 special ordered set (SOS), i.e. at most\n    two of the variables in the set can be non-zero. This can occur multiple\n    times, for different sets of variables.\n\n<P>\n<DT><STRONG><TT>presolve(+YesNo)</TT></STRONG>\n    <DD>Specify if the external solver should perform presolve for this\n    problem. With presolving, the external solver will transform the\n    problem before solving it. This can lead to significantly faster times\n    to find solutions. However, as the problem has been transformed, some\n    external solvers have restriction on accessing or changing the problem\n    state. In addition, if the solver is repeatedly called because the\n    problem is frequently modified, then presolve may not be an advantage.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    determined by the global setting of <TT>presolve</TT>, which can be\n    changed via <TT>lp_set/2</TT>. The initial default is <TT>yes</TT>.\n    Note that the presolve setting cannot be changed for a problem once it\n    is set.  If the external solver supports per-problem optimizer_params, \n    their global defaults will be used for presolve(yes).\n<P>\n<DT><STRONG><TT>timeout(+TimeOut)</TT></STRONG>\n    <DD>Set the external solver to time-out after <TT>TimeOut</TT> seconds.\n    <TT>TimeOut</TT> is a positive number. The solver will abort (in either\n    the abort or suboptimal state, depending on if a suboptimal solution\n    was found) if the optimal solution was not found within the time\n    limit. This should be used instead of setting the solver-specific\n    parameter for time-out directly. In cases where the solver expects an\n    integer for the time-out interval, the time given is rounded up to the\n    next integer value. The timeout is set by setting the external\n    solver's timeout settings, and the exact behaviour may be solver dependent.\n<P>\n<DT><STRONG><TT>suboptimal_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver returned a suboptimal solution (because the problem\n    was aborted). Goal would be run in place of raising the default \n    <TT>eplex_suboptimal</TT> event.\n<P>\n<DT><STRONG><TT>unbounded_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    problem is unbounded. Goal would be run in place of raising the  \n    default <TT>eplex_unbounded</TT> event.\n<P>\n<DT><STRONG><TT>infeasible_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver found that the problem is infeasible. Goal would be run\n    in place of raising the default <TT>eplex_infeasible</TT> event.  Note\n    that the default and logically correct behaviour is to fail, this\n    handler is provided to allow the user to analyse the cause of the\n    infeasibility. It is recommended that the handler should also fail\n    after performing the analysis.\n<P>\n<DT><STRONG><TT>unknown_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver was not able to determine if the problem is unbounded\n    or infeasible. Goal would be run in place of raising the default \n    <TT>eplex_unknown</TT> event.\n<P>\n<DT><STRONG><TT>abort_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver aborted without finding any solution. Goal would be \n    run in place of raising the default <TT>eplex_abort</TT> event.\n<P>\n<DT><STRONG><TT>use_var_names(+YesNo)</TT></STRONG>\n    <DD>Specify if variable names (set using <TT>set_var_name/2</TT> of the \n    var_name library) should be passed to the external solver. If a \n    particular variable does not have a name when it is first passed to the\n    external solver, a default name determined by the solver would be used.\n    Note that for XPRESS-MP, there is a limit on the length of the name,\n    which can be changed between 8 and 64 in steps of 8 with the \n    parameter <TT>mpsnamelength (XPRS_MPSNAMELENGTH)</TT>. Variable \n    names longer than this limit are truncated to the limit. \n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n<P>\n<DT><STRONG><TT>priority(+Prio)</TT></STRONG>\n  <DD><TT>Prio</TT> is the scheduling priority with which the solver gets\n  woken up.  This priority determines whether the solver is run before or\n  after other constraints. By default, if no priority is specified, the\n  default priority (0, mapped to 5 unless changed) is used. Normally, the\n  default priority should be sufficient and this option is not needed,\n  unless there is a specific need to have the external solver invoked with\n  higher or lower priority than some other constraints.\n<P>\n<DT><STRONG><TT>mip_use_copy(+YesNo)</TT></STRONG>\n    <DD>Some external solvers do not allow a MIP problem to be modified\n    once the MIP search has been started. Eplex works around this\n    problem by making a copy of the problem and solving that, so that\n    the original problem can still be modified. This can be turned off to\n    avoid the overhead of making this copy, in which case the MIP\n    problem cannot be modified. This option is used only when solving a\n    MIP problem, and the external solver does not allow a MIP problem to\n    be modified; otherwise it is ignored.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default \n    is <TT>yes</TT> so that the problem can be modified.\n<P>\n<DT><STRONG><TT>write_before_solve(+Format,+File)</TT></STRONG>\n    <DD>This option is most useful for debugging purposes. If given, Eplex\n    will ask the external solver to dump the problem each time the problem\n    is solved. This allows the problem in an <TT>eplex_probe/2</TT> or\n    <TT>lp_probe/3</TT> to be dumped. As in <TT>lp_write/3</TT>,\n    <TT>Format</TT> is the format of the dumped file and <TT>File</TT> is\n    its name. Note that the problem is dumped each time the external solver\n    is invoked if the problem has cutpool constraints, where there may be\n    multiple invocations of the solver per solver call. \n    The default without this option is that the problem would not be dumped.\n<P>\n<DT><STRONG><TT>post_equality_when_unified(+YesNo)</TT></STRONG>\n    <DD>This option determines if an equality constraint between two\n    variables will be posted to the solver when these variables are\n    unified. Setting <TT>YesNo</TT> to no means that the constraint \n    will <EM>not</EM> be posted. Note that this can lead to the\n    solver's problem becoming inconsistent with ECLiPSe's. \n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>yes</TT>.\n<P>\n<DT><STRONG><TT>sync_bounds(+YesNo)</TT></STRONG>\n    <DD>This option determines if the bounds of the problems variables are\n    synchronised with other solvers (i.e. the generic bounds are obtained\n    with get_var_bounds/3 and then passed to the external solver) before\n    the external solver is invoked. This was always done for previous\n    non-standalone version of eplex. For standalone eplex, as the bounds\n    are communicated directly to the external solver, the synchronisation\n    of variable bounds is not needed unless the user is using eplex\n    co-operatively with other solvers (e.g. ic). Even in such cases, it may\n    be more efficient to communicate these bounds changes by explicitly\n    programming it, especially if the problem has many variables and bounds\n    changes happen only to a few of the variables. Setting <TT>YesNo</TT>\n    to yes should increase compatibility with previous code (but note that\n    previous eplex obtained the bounds from a specific bounds keeper like\n    ic rather than the generic bounds).  YesNo is one of the atoms\n    <TT>yes</TT> or <TT>no</TT>, the default is <TT>no</TT>.\n\n</DL>\n<P>\n<TT>TriggerModes</TT> can be a list of the following specifiers:\n\n<DL>\n\n  <DT><STRONG><TT>inst</TT></STRONG>\n  <DD>re-trigger if a problem variable gets instantiated.\n\n  <DT><STRONG><TT>ModuleName:Index</TT></STRONG>\n  <DD>re-trigger when the  suspension list given by ModuleName:Index is woken\n  for any of the problem variables.\n  The format for <TT>ModuleName:Index</TT> is the same as for specifying\n  the suspension list in suspend/3,4.\n\n  <DT><STRONG><TT>deviating_inst</TT></STRONG>\n  <DD>re-trigger if a problem variable gets instantiated\n      to a value that differs from its lp-solution more than a tolerance.\n\n  <DT><STRONG><TT>bounds</TT></STRONG>\n  <DD>re-trigger each time a variable bound for the solver instance changes.\n\n  <DT><STRONG><TT>deviating_bounds</TT></STRONG>\n  <DD>re-trigger each time a variable's solver instance bound changes\n      such that its lp-solution gets excluded more than a tolerance.\n\n  <DT><STRONG><TT>new_constraint</TT></STRONG>\n  <DD>re-trigger each time a new (arithmetic or integral) constraint is\n      added to the solver instance. Note that adding integral constraint\n      on new problem variables, or adding bounds constraint, or adding \n      constraints to the cutpool will *not* re-trigger.\n\n  <DT><STRONG><TT>trigger(Atom)</TT></STRONG>\n  <DD>re-trigger each time the symbolic trigger Atom is pulled by invoking \n      schedule_suspensions/1\n\n  <DT><STRONG><TT>pre(Goal)</TT></STRONG>\n  <DD>an additional condition to be used together with other triggers. When \n      the demon is triggered, it first executes <TT>PreGoal</TT>. Only if \n      that succeeds, does the appropriate external solver get invoked.\n      This provides a way of reducing the number of (possibly expensive)\n      solver invocations when given preconditions are not met.\n\n  <DT><STRONG><TT>post(Goal)</TT></STRONG>\n  <DD>this is not a trigger condition, but specifies a goal to be executed\n      after solver success, but before the Cost variable gets\n      constrained. It is intended as a hook for exporting solution\n      information, e.g. copying solutions from the solver state into\n      variable attributes (eg. tentative value), or computing weights for\n      labelling heuristics from the solver state.  \n  <DT><STRONG><TT>suspension(Susp)</TT></STRONG>\n  <DD>this is not a trigger condition, but instead is used to access the \n      demon used to trigger the solver. Susp is instantiated to\n      the suspension that triggers the solver: by waking Susp, the solver\n      is triggered. Susp is a demon in that it stays around after being\n      woken. Accessing Susp allows the user to specify arbitrary conditions \n      for triggering the solver.\n</DL>\n\n  The tolerances mentioned can be specified in lp_setup/4 or lp_set/3\n  as <TT>demon_tolerance</TT>.\n\n</P><P>\n  If several trigger conditions are specified, then any of them will trigger\n  the solver.\n\n</P><P>\n  When a solver demon runs frequently on relatively small problems,\n  it can be important for efficiency to switch off the presolve option\n  to reduce overheads.\n\n</P>")]).
:- comment(eplex_solver_setup / 5, hidden).
:- comment(eplex_var_get / 3, [template : ["eplex_var_get(+Var, ++What, -Value)", "EplexInstance:eplex_var_get(+Var, ++What, -Value)"], args : ["Var" : "A solver problem variable for solver associated with EplexInstance", "What" : "Specification for information wanted (atom)", "Value" : "Returned value of What"], summary : "Obtain information for an individual solver problem variable Var.", exceptions : [6 : "What is not a valid value.", 6 : "Var is not a problem variable for EplexInstance.", 6 : "What is unavailable; the information was not requested at solver setup.", 40 : "Solver state had been previously destroyed."], desc : html("<P>\n   Retrieve information about the (logically) most recent solver state and\n   results related to a particular variable, for the eplex instance\n   EplexInstance.  Fails if no solution has been computed yet.  What can\n   take one of the following values:\n\n<DL>\n    <DT><TT>solution</TT>\n    <DD>Returns the floating-point solution for variable Var.\n<P>\n\n    <DT><TT>typed_solution</TT>\n    <DD>Returns the properly typed (integer or float) solution for variable\n        Var, depending on if the variable was constrained to be an integer\n        or not for EplexInstance.\n<P>\n\n    <DT><TT>reduced_cost</TT>\n    <DD>Returns the reduced cost for variable Var. If the problem is a MIP, \n        then depending on the external solver, this is either unavailable\n        or is the value at the optimal LP node. \n        Note that reduced cost is defined as the minimal amount the\n        objective value will be changed by if the variable's value is\n        increased by 1 from its solution value.\n\n    <DT><TT>type</TT>\n    <DD>Returns the type the variable Var is constrained to in\n        EplexInstance. Possible values are integer or real.\n</DL>\n<P>\n  Note that solution or reduced_cost can only be retrieved\n  when previously requested in the option list of eplex_solver_setup/4,\n  lp_demon_setup/5, lp_setup/4 or with lp_set/3.\n</P>")]).
:- comment(eplex_var_get_bounds / 3, [template : ["eplex_var_get_bounds(+Var, -Lo, -Hi)", "EplexInstance:eplex_var_get_bounds(+Var, -Lo, -Hi)"], args : ["Var" : "A problem variable for EplexInstance", "Lo" : "Lower bound for Var", "Hi" : "Upper bound for Var"], summary : "Returns the bounds stored in the solver state for Var in eplex instance EplexInstance.", resat : no, exceptions : [5 : "EplexInstance does not a solver setup for it.", 6 : "Var is not a problem variable for EplexInstance.", 40 : "Solver state had been previously destroyed."], see_also : [lp_var_get_bounds / 4, eplex_solver_setup / 1, eplex_solver_setup / 4], desc : html("\n    <P>\n    Returns the numeric bounds for Var stored in the solver state\n    associated with the eplex instance EplexInstance. The bounds are\n    returned as floats. Var must be an existing problem variable for\n    EplexInstance. ")]).
:- comment(eplex_verify_solution / 2, [summary : "Verifies the current solution for the problem associated with EplexInstance.", template : ["eplex_verify_solution(-ViolatedCstrs,-ViolatedVars)", "EplexInstance:eplex_verify_solution(-ViolatedCstrs,-ViolatedVars)"], args : ["ViolatedCstrs" : "List of violated Constraints.", "ViolatedVars" : "List of violated variables."], amode : eplex_verify_solution(-, -), desc : html("<P>\n This predicate checks the current solution for the problem associated with\n EplexInstance. It verifies that all the constraints are satisfied by the\n solution values for the problem variables, and that the solution values do\n not violate their bounds, and the values are integral for integer variables.\n Violated Constraints are returned in ViolatedCstrs, and violated variables in \n ViolatedVars.\n</P><P>\n Under normal circumstances, if the external solver produces a solution, it \n should produce no violations. Any violation probably indicates a problem\n with the external solver. However, because the external solver is a complex\n piece of software and may contain problems, it is a good idea to verify the\n solution, and this predicate provides an easy way to do this.\n</P><P>\n Each violation is returned as a structure of the following form:\n <PRE>  vio(type,delta,idx,item) </PRE>\n where\n<DL>\n       <DT>type:   <DD>the type of violation:\n          <DL>\n              <DT>norm:   <DD>the violated item is a normal constraint.\n              <DT>condcp: <DD>the violated item is an active cutpool constraint.\n              <DT>int:    <DD>the violated item is an integer variable whose \n                      solution value is not integral.                    \n              <DT>lower:  <DD>the violated item is a variable whose solution value\n                      is less than the lower bound.                     \n              <DT>upper:  <DD>the violated item is a variable whose solution value\n                      is greater than the upper bound.                     \n           </DL>\n        <DT>delta: <DD>the absolute value of the violation. \n        <DT>idx:   <DD>the index used by the external solver for the item (most\n               likely the row/column number in the problem matrix). This \n               is needed to locate the violation in the solver for reporting\n               or investigating the problem.\n         <DT>item:  <DD>the violated item, i.e. the constraint or variable.\n</DL><P>\n For checking of constraints, a fresh copy of the constraint is made with\n the solution values, as this avoids binding the original variables. Any active\n cutpool constraints in the (logically) last solve of the problem are checked,\n along with the normal constraints. A constraint is considered to be  violated\n if the difference between the sum of the left-hand side and the right-hand side \n for the constraint is greater than the feasibility tolerance (feasibility_tol)\n parameter for the instance. For variables, a bound is considered violated if\n the solution value falls outside the bound by more than feasibility tolerance,\n and integrality is considered to be violated if the fractional part of the\n soltuion is greater than the integrality parameter for the instance. \n"), fail_if : "no solution values are available."]).
:- comment(eplex_write / 2, [template : ["eplex_write(++Format,++File)", "EplexInstance:eplex_write(++Format,++File)"], args : ["Format" : "lp or mps", "File" : "File name"], see_also : [eplex_read / 2, lp_write / 3, lp_setup / 4], summary : "Write the problem in the solver for eplex instance  EplexInstance to a file.", exceptions : [5 : "EplexInstance does not a solver setup for it.", 40 : "Solver state had been previously destroyed."], desc : html("\n   Write the problem in the solver for EplexInstance to a file. The set of\n   supported formats depends on the actual external solver which is used.\n   All solvers support the mps format. Some solvers on some operating\n   system platforms may change or append a suffix to the filename. \n   Note that the mps format does not specify the sense (min or max) of the\n   objective function. Minimisation is also assumed for external solvers\n   that ignore the optimisation direction of the lp file (e.g. Xpress).\n   Note also that any active cutpool constraints in the problem will be \n   included in the dump, even though they could be left out of the problem\n   that the external solver actually solves.\n")]).
:- comment(get_changeable_value / 2, [template : ["get_changeable_value(?Var, -Val)", "EplexInstance:get_changeable_value(?Var, -Val)"], args : ["Var" : "A solver problem variable for solver associated with EplexInstance", "Val" : "The typed_solution value for this variable"], summary : "Interface predicate to access the `changeable' value for this variable."]).
:- comment(instantiation_deviates / 1, [amode : instantiation_deviates(+), args : ["Handle" : "Handle to a solver state"], see_also : [lp_demon_setup / 5], summary : "A trigger goal for lp_demon_setup/5.", desc : html("<P>\n\n  This is intended as a useful pre(Goal) for lp_demon_setup/5 in connection\n  with the <TT>inst</TT> trigger mode.  It succeeds if any of the variables\n  originally involved in Handle have been instantiated to a value that is\n  not within +/- tolerance from the latest simplex solution for that\n  variable.  The admissible tolerances can be specified in lp_setup/4 or\n  lp_set/3 as <TT>demon_tolerance</TT>.\n\n</P>")]).
:- comment(integers / 1, [template : ["integers(?Vars)", "EplexInstance:integers(?Vars)"], args : ["Vars" : "Collection or nested collection of variables and numbers"], see_also : [_499152 : integers / 1, reals / 1, $:: / 2], summary : "Constrains Vars to integers for eplex instance EplexInstance.", desc : html("<P>\tConstrains the variables and numbers in the collection Vars to\n\tintegers in the eplex instance EplexInstance.  If a variable\n\tin Vars is not already a problem variable for EplexInstance,\n\tit will be added as a new problem variable.  The external\n\tsolver will then take the integrality into account, i.e.\n\tsolve a MIP/MIQP rather than a relaxed LP/QP problem.\n\t<P>\n\tNote that even when problem variables have been declared as\n        integers in other solvers (ic or other external solver\n        states), if the integrality constraint is not made known to this\n        EplexInstance, any invocation of the eplex external solver (e.g. via\n        eplex_solve/1) will only solve a continuous relaxation.\n\t<P>\n\t")]).
:- comment(lp_add / 3, [amode : lp_add(+, +, +), args : ["Handle" : "Handle to a solver state", "NewNormCons" : "List of new normalised constraints", "NewIntegers" : "List of variables to be considered as integers"], see_also : [lp_setup / 4], resat : no, summary : "Add new constraints to a solver state Handle.", desc : html("<P>\n  Add new normalised constraints (with possibly new variables) to a solver.\n  This is a lower level predicate called by lp_add_constraints/3 and when\n  constraints are collected from the constraints pool by the solver. The\n  constraints are not simplified and must already be normalised, so\n  constraints which would otherwise be simplified away by the higher level\n  predicates can be added to the external solver. The constraints will be\n  removed on backtracking. Note that the solver will not be invoked directly.\n</P><P>\n  Note that variables in NewIntegers can be any problem variables. In\n  previous versions of ECLiPSe, there was a restriction that the variables\n  be new problem variables; this restriction has been removed.\n</P>\n")]).
:- comment(lp_add_columns / 2, [amode : lp_add_columns(+, +), args : ["Handle" : "Handle to a solver state", "Columns" : "A list of Variable:ColumnSpecification pairs."], summary : "Add new variables as columns to the external solver's matrix.", exceptions : [4 : "Handle or Columns are uninstantiated.", 5 : "A Variable in Columns is already a problem variable for problem represented by Handle.", 40 : "Handle not valid: solver state had been destroyed by cleanup", abort : "Handle is an eplex instance problem, or trigger conditions have been specified."], desc : html("<P>\n   Add new variables as columns to the external solver's matrix. This \n   allows non-zero coefficients for the objective and existing constraints\n   to be specified for these variables. \n</P><P>\n   Each column is specified as a Variable:ColumnSpecification pair.\n   Variable is the variable that is being added to the problem, and\n   ColumnSpecification is the specification for the non-zero coefficients\n   for the column representing the variable in the external solver matrix:\n   this is a list of Index:Coefficient pairs. Where index is the index of an\n   existing constraint (obtained when the constraint was added using\n   lp_add_constraints/4), and coefficient is its coefficient.\n</P><P>\n   The ColumnSpecification list can optionally start with a special element\n   'obj':Coeff, in which case the coefficient is the objective coefficient\n   for the column (otherwise zero).  This can be optionally followed by two\n   entries of the form 'lo':Lwb,'hi':Upb, which specify initial lower and\n   upper bound on the column variable (otherwise unbounded).  Each\n   constraint coefficient should only occur once. Any index not specified\n   is given a zero value.\n</P><P>\n   Note that lp_add_columns/2 essentially modifies the problem represented\n   by Handle. This is not compatible with the view of the problem as a\n   compound constraint, and therefore, lp_add_columns/2 can only be used\n   for problems that are not eplex instances, and/or have no trigger\n   conditions for triggering the external solver. \n</P>\n  ")]).
:- comment(lp_add_constraints / 3, [amode : lp_add_constraints(+, +, ++), args : ["Handle" : "Handle to a solver state", "Constraints" : "A (possibly empty) list of equality or inequality constraints", "Integers" : "A (possibly empty) list of variables to be considered as integers in the problem"], see_also : [lp_demon_setup / 5, lp_add / 3, lp_add_constraints / 4, eplex_add_constraints / 2, $= / 2, $=< / 2, $>= / 2, (=:=) / 2, (=<) / 2, (>=) / 2, sos1 / 1, sos2 / 1, => / 2], resat : no, fail_if : "Any ground (no variable) or bound constraints (one variable) is self-inconsistent.", exceptions : [4 : "Handle, Constraints or Integers uninstantiated.", 5 : "Some constraint in Constraints is non-linear.", 40 : "Handle not valid: solver state had been destroyed by cleanup"], summary : "Add new constraints to the solver Handle, possibly triggering it.", desc : html("<P>\n  Add new constraints (with possibly new variables) to a solver.\n  NewIntegers is a list of variables that the external solver should\n  consider as integers  The new constraints will be taken into\n  account the next time the solver is run: if the new_constraint option of\n  lp_demon_setup was turned on, then the solver will be invoked after the\n  adding of the constraints, unless they are already satisfied.  The \n  constraints will be removed on backtracking.\n</P><P>\n  The constraints are normalised and simplified before being passed to\n  the external solver. If any constraint is ground, they are tested for\n  consistency.\n</P><P>\n  The constraints can be linear equalities and inequalities, sos/1 and\n  sos2/1 constraints, and =&ge;/2 indicator constraints.\n</P><P>\n  Note that variables in NewIntegers can be any problem variables. In\n  previous versions of ECLiPSe, there was a restriction that the variables\n  be new problem variables; this restriction has been removed.\n</P><P>\n\n </P>")]).
:- comment(lp_add_constraints / 4, [amode : lp_add_constraints(+, +, ++, -), args : ["Handle" : "Handle to a solver state", "Constraints" : "A (possibly empty) list of expandablelinear equality or inequality constraints", "Integers" : "A (possibly empty) list of problem variables to be considered as integers", "Indices" : "Indices for the constraints in Constraints"], see_also : [lp_add_constraints / 3, lp_demon_setup / 5, lp_add / 3, lp_add_columns / 2, $= / 2, $=< / 2, $>= / 2, (=:=) / 2, (=<) / 2, (>=) / 2], resat : no, exceptions : [4 : "Handle, Constraints or Integers uninstantiated.", 5 : "Some constraint in Constraints is ground.", 5 : "Some constraint in Constraints is non-linear.", 40 : "Handle not valid: solver state had been destroyed by cleanup"], summary : "Add new expandable constraints to the demon solver Handle.", desc : html("<P>\n  Add new expandable constraints (with possibly new variables) to a solver.\n  An expandable constraint can be expanded when new variables are added to\n  the problem. These constraints are in the form of having a constant on\n  the right-hand side, and coefficients for the problem variables on the\n  left. When new variables are added (via lp_add_columns/2), the\n  coefficients for these variables can be given for the expandable\n  constraints. Note that the constraints can only be expanded if there are\n  no trigger conditions (i.e. the problem must be solved explicitly), or if\n  the problem is not associated with an eplex instance. Otherwise, the\n  added constraints are treated as normal (non-expandable) constraints.\n</P><P>\n  Constraints is a list of expandable constraints.  NewIntegers is a list\n  of variables that the external solver should consider as integers,\n  Indices is a list of the indices for the added constraints. It is\n  returned by the predicate, and has the same length as Constraints. Each\n  element in Indices is the index for the constraint in Constraints at the\n  same position in the list. This index is used to refer to the constraint\n  in lp_add_columns/2.\n</P><P>\n  Operationally lp_add_constraints/4 behaves like lp_add_constraints/3,\n  except that it never triggers the solver as a demon:\n  The new constraints will be taken into account the next time the solver\n  is run, and  removed on backtracking. The constraints are normalised \n  before being passed to the external solver. Unlike lp_add_constraints/3,\n  they are not simplified, and no consistency checks are performed. If any\n  of the constraints are ground, a type error is raised. \n</P><P>\n  Note that variables in NewIntegers can be any problem variables.\n </P>")]).
:- comment(lp_add_cutpool_constraints / 4, [amode : lp_add_cutpool_constraints(+, +, +, -), args : ["Handle" : "Handle to a solver state", "Constraints" : "A (possibly empty) list of equality or inequality constraints", "Options" : "A (possibly empty) list of Option:Value pairs", "Indices" : "Indices for the constraints in CstrSpecs"], resat : no, summary : "Add constraints to the cutpool associated  with solver state Handle.", exceptions : [6 : "Constraints contains variable(s) that is not in the problem during setup.", 5 : "A constraint in Constraints is ground."], see_also : [lp_get / 3, lp_set / 3], desc : html("<P>\n  Add constraints to the cutpool associated with solver state Handle.\n  Unlike normal constraints, cutpool constraints are not added directly to\n  the problem, and are *NOT* removed on backtracking. Logically, cutpool\n  constraints are valid for all solves of the problem, regardless of when\n  a constraint is added to the pool -- they are `globally valid'. The \n  purpose of the cutpool is to give the user more flexibility on how\n  constraints are used by the external solver.\n</P><P>\n  <TT>Constraints</TT> is the list of constraints to be added to the\n  cutpool. As they are not removed on backtracking, they can only involve\n  variables that are present at problem setup. Otherwise, an out of range\n  error is raised. Variables can be created for a problem before setup by\n  posting normal constraints involving the variables, in particular, using\n  reals/1. The constraints are normalised before being passed to the\n  external solver.  They are not simplified, and no consistency checks\n  are performed. If any of the constraints are ground, a type error is\n  raised. Instantiated variables are treated as constants (i.e. the value\n  they are instantiated to when the predicate is called), even when the\n  execution backtracks to a point before the instantiations.\n</P><P> \n  <TT>Options</TT> is a possibly empty list of Option:Value pairs specifying \n  the options. Valid options are:\n<DL>\n<P>\n<DT><STRONG><TT>add_initially</TT></STRONG>\n   <DD>specifies if the constraints should be added to the problem matrix\n   before the external solver is invoked. Valid values are <TT>1</TT> for\n   adding the constraints before solving, and <TT>0</TT> for not adding.\n   The default is <TT>1</TT>.\n<DT><STRONG><TT>active</TT></STRONG>\n   <DD>specifies if the constraints should be active. Valid values are \n   <TT>1</TT> for active, and <TT>0</TT> for non-active. The default is <TT>1</TT>.\n<DT><STRONG><TT>group</TT></STRONG>\n   <DD>specifies the cutpool constraints group that the constraints will be\n   added to. <TT>Value</TT> must be an existing group name for the cutpool,\n   i.e. the default group, or a group name previously created with \n   the cutpool_group option of lp_set/3. The default is the default group\n   name ([]).\n</DL>\n</P><P>\n  Operationally, the cutpool constraints are taken into account when the\n  external solver is invoked, and the user can specify how they are taken\n  into account by setting the status of these constraints: by default,\n  cutpool constraints are active, and are taken into account during solver\n  invocation: none of these constraints will be violated in the solution\n  produced: they are either part of the problem matrix solved by the\n  external solver, or they have been explicitly checked for non-violation. \n  This is done as follows: active cutpool constraints that are labelled as \n  `add_initially' (the default) are added to the problem matrix, and the \n  external solver is invoked. When a solution is produced, the unadded\n  active cutpool constraints are checked to see if they are violated. Any\n  violated constraints are added to the problem matrix and the problem is\n  resolved by the external solver. This is repeated until there are no\n  violated constraints. This approach allows the user to leave out\n  constraints that might be expensive (i.e. slow down the solving) unless\n  they usefully constrain the problem. \n</P><P>\n  Checking for violations require the solution values of the problem\n  variables. Thus, if the <TT>solution</TT> option is turned off and no\n  solution value is available, and there are unadded active cutpool \n  constraints, an out of range error would be raised when the solver tries\n  to solve the problem.\n</P><P>\n  The violation checking is only done if the external solver produces a \n  solution with solution values. If the problem is unbounded (or unknown,\n  i.e. the solver cannot determine if the problem is infeasible or\n  unbounded), then all the active cutpool constraints are added to the\n  problem without checking for violations, and the problem is resolved once\n  more. This is done because adding constraints to the problem can make the\n  problem become bounded.\n</P><P>\n  The user can change a cutpool constraint's status to non-active, in which\n  case it is neither checked for violations nor added to the problem.\n  For logical  correctness, the user should only make a constraint non-active\n  if it is certain that the constraint will not be violated, e.g. if it is\n  superceded by a stronger constraint. \n</P><P>\n  Cutpool constraints are organised into named groups, allowing multiple\n  constraints to be referred to as a unit, e.g. with the cutpool_info\n  option of lp_get/3.\n</P><P>\n  Note that as the constraints are added to the cutpool, and not to the\n  problem directly, this is not considered as adding new constraints, and\n  will not cause the solver to trigger with the new_constraint trigger\n  condition set.\n  ")]).
:- comment(lp_add_indexed / 4, hidden).
:- comment(lp_add_vars / 2, [amode : lp_add_vars(+, +), args : ["Handle" : "Handle to a solver state", "Vars" : "A list of variables or numbers"], summary : "Declare Vars to be problem variables for the solver state Handle", see_also : [lp_setup / 4, lp_demon_setup / 5], desc : html("<P>\n   Declares variables in Vars as problem variables for the solver state\n   represented by Handle. Any of the variables that are not existing \n   problem variables for Handle are added to the problem. The new\n   variables' bounds are constrained to -infinity..infinity (infinity as \n   defined by the external solver).\n"), fail_if : "Vars contain elements which are neither variables or numbers."]).
:- comment(lp_cleanup / 1, [amode : lp_cleanup(+), args : ["Handle" : "Handle to a solver state"], summary : "Destroy the specified solver Handle and clean up.", desc : html("<P>\n    Destroy the specified solver, free all memory, etc.  Note that ECLiPSe\n    will normally do the cleanup automatically, for instance when execution\n    fails across the solver setup, or when a solver handle gets garbage\n    collected.\n</P><P>\n    This predicate should be used with caution as the information from the\n    solver state will no longer be available. In particular, if the program\n    backtracks to a point between the problem set up and clean up,\n    accessing the solver state directly or indirectly (e.g. unifying a\n    problem variable) will result in a stale handle error. \n</P>")]).
:- comment(lp_demon_setup / 5, [amode : lp_demon_setup(+, ?, ++, ++, -), args : ["Objective" : "Objective function: min(CostExpr) or max(CostExpr)", "Cost" : "Variable bounded by the optimal solution", "ListOfOptions" : "List of solver options", "TriggerModes" : "List of conditions for re-triggering solver", "Handle" : "handle to solver state"], see_also : [lp_solve / 2, lp_set / 3, lp_setup / 4, lp_get_iis / 5, solution_out_of_range / 1, schedule_suspensions / 1, library(constraint_pools)], summary : "Setup the external solver as a simplex demon.", eg : "   Some common invocations patterns for this predicate are the following.\n   The first triggers the solver only on instantiation of variables to\n   values that don't fit with the simplex solution:\n\n      lp_demon_setup(min(Expr), C, [], [deviating_inst], H)\n\n", desc : html("<P>\n  Setup the external solver as a simplex demon. A simplex demon collects\n  linear constraints and re-solves the problem whenever the triggering\n  conditions in TriggerModes are met.\n\n</P><P>\n  Declaratively, this can be seen as a compound constraint representing all\n  the individual linear constraints that have been set so far and are going\n  to be set up later.  Operationally, the delayed constraints are collected\n  and an external solver is set up (as with lp_setup/4).  Then the problem\n  is solved once initially (if <TT>initial_solve</TT> option is yes) and a\n  delayed goal lp_demon is set up which will re-trigger the solver when \n  certain  conditions are met.\n\n</P><P>\n  <TT>CostExpr</TT> is a linear cost expression (or quadratic, if supported\n  by the external solver).\n\n</P><P>\n  <TT>Handle</TT> refers to the created solver state (as in lp_setup/4 or\n  lp_read/3 described below). It can be used to access and modify the state\n  of the solver, retrieve solution information etc. \n\n</P><P>\n  Unlike with lp_solve/2, <TT>Cost</TT> will not be instantiated to a\n  solution's cost, but only be bounded by the best-bound on cost:\n  For a minimisation problem, each solution's best-bound becomes a lower bound,\n  for maximisation an upper bound on Cost.  This technique allows for\n  repeated re-solving with reduced bounds or added constraints. Note that\n  Cost is not automatically made a problem variable (it can be a problem\n  variable if there are constraints that involve it), and thus may not have\n  bounds associated with in. In order for the bounds information not to be\n  lost, some bounds should be given to <TT>Cost</TT> (e.g. making it a\n  problem variable (but this might introduce unnecessary self-waking on\n  bounds change), or via another solver with bounds (e.g. ic)).\n</P><P>\n  <TT>ListOfOptions</TT> is a list of solver options as described for\n  lp_setup/4. In addition, the following extra options are also available:\n   \n<DL>\n\n<DT><STRONG><TT>collect_from(+Pool)</TT></STRONG>\n    <DD>Specifies if this solver state should be associated with an eplex\n    instance. If Pool is <TT>none</TT>, then the solver is not associated\n    with an eplex instance. If Pool is <TT>pool(Instance)</TT>, where\n    Instance is the (atomic) name of an existing eplex instance, then this\n    eplex instance would be associated with the solver state, i.e. when the\n    solver is invoked, it will collect constraints posted to\n    <TT>Instance</TT>.  Note that <TT>Instance</TT> must not be associated\n    with any other solver state already.\n    The default value for <TT>Pool</TT> is pool(eplex) (for backward\n    compatibility).\n\n<DT><STRONG><TT>initial_solve(+YesNo)</TT></STRONG>\n    <DD>Specifies if an initial solve (call to the external solver) should\n    be performed immediately after problem setup.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>yes</TT> if any trigger condition is specified in TriggerModes, \n    <TT>no</TT> if no trigger condition is specified.\n\n<DT><STRONG><TT>priority(+Prio)</TT></STRONG>\n    <DD><TT>Prio</TT> is the scheduling priority with which the solver gets\n    woken up.  This priority determines whether the solver is run before or\n    after other constraints. By default, if no priority is specified, the\n    default priority (0, mapped to 5 unless changed) is used. Normally, the\n    default priority should be sufficient and this option is not needed,\n    unless there is a specific need to have the external solver invoked with\n    higher or lower priority than some other constraints.\n</DL>\n   \n</P><P>\n\n  <TT>TriggerModes</TT> specifies under which conditions the solver demon\n  will be re-triggered. It can be a list of the following specifiers\n\n<DL>\n\n  <DT><STRONG><TT>inst</TT></STRONG>\n  <DD>re-trigger if a problem variable gets instantiated.\n\n  <DT><STRONG><TT>ModuleName:Index</TT></STRONG>\n  <DD>re-trigger when the  suspension list given by ModuleName:Index is woken\n  for any of the problem variables.\n  The format for <TT>ModuleName:Index</TT> is the same as for specifying\n  the suspension list in suspend/3,4.\n\n  <DT><STRONG><TT>deviating_inst</TT></STRONG>\n  <DD>re-trigger if a problem variable gets instantiated\n      to a value that differs from its lp-solution more than a tolerance.\n\n  <DT><STRONG><TT>bounds</TT></STRONG>\n  <DD>re-trigger each time a variable bound for the solver instance changes.\n\n  <DT><STRONG><TT>deviating_bounds</TT></STRONG>\n  <DD>re-trigger each time a variable's solver instance bound changes\n      such that its lp-solution gets excluded more than a tolerance.\n\n  <DT><STRONG><TT>new_constraint</TT></STRONG>\n  <DD>re-trigger each time a new (arithmetic or integral) constraint is\n      added to the solver instance. Note that adding integral constraint\n      on new problem variables, or adding bounds constraint, or adding \n      constraints to the cutpool will *not* re-trigger.\n\n  <DT><STRONG><TT>trigger(Atom)</TT></STRONG>\n  <DD>re-trigger each time the symbolic trigger Atom is pulled by invoking \n      schedule_suspensions/1\n\n  <DT><STRONG><TT>pre(Goal)</TT></STRONG>\n  <DD>an additional condition to be used together with other triggers. When \n      the demon is triggered, it first executes <TT>PreGoal</TT>. Only if \n      that succeeds, does the appropriate external solver get invoked.\n      This provides a way of reducing the number of (possibly expensive)\n      solver invocations when given preconditions are not met.\n\n  <DT><STRONG><TT>post(Goal)</TT></STRONG>\n  <DD>this is not a trigger condition, but specifies a goal to be executed\n      after solver success, but before the Cost variable gets\n      constrained. It is intended as a hook for exporting solution\n      information, e.g. copying solutions from the solver state into\n      variable attributes (eg. tentative value), or computing weights for\n      labelling heuristics from the solver state.  \n  <DT><STRONG><TT>suspension(Susp)</TT></STRONG>\n  <DD>this is not a trigger condition, but instead is used to access the \n      demon used to trigger the solver. Susp is instantiated to\n      the suspension that triggers the solver: by waking Susp, the solver\n      is triggered. Susp is a demon in that it stays around after being\n      woken. Accessing Susp allows the user to specify arbitrary conditions \n      for triggering the solver.\n</DL>\n\n  The tolerances mentioned can be specified in lp_setup/4 or lp_set/3\n  as <TT>demon_tolerance</TT>.\n\n</P><P>\n  If several trigger conditions are specified, then any of them will trigger\n  the solver.\n\n</P><P>\n  When a solver demon runs frequently on relatively small problems,\n  it can be important for efficiency to switch off the presolve option\n  to reduce overheads.\n\n</P><P>\n  The solver demon calls lp_solve/2 when it wakes up. See the description\n  of lp_solve/2 for the handling of exceptions.\n</P><P>\n  Note: Some external solvers need to write temporary files when they\n  are solving a problem. These are written to the temporary directory\n  specified in ECLiPSe's tmp_dir setting (get_flag/2, set_flag/2).\n</P>")]).
:- comment(lp_get / 2, [amode : lp_get(++, -), amode : lp_get(++, +), args : ["ParamName" : "Atom or structure", "Value" : "Variable, integer, float or atom"], summary : "Obtain the value of a global parameter.", see_also : [lp_set / 2], desc : html("    Eplex has a number of global (i.e. not specific to a\n    particular problem) parameters. These can be queried using this \n    predicate.\n<DL>\n    <DT><TT>has_indicator_constraints</TT>\n\t<DD>Returns 'yes' if the solver supports =&ge;/2 indicator constraints,\n\telse 'no'.\n    <DT><TT>has_miqp</TT>\n\t<DD>Returns 'yes' if the solver supports mixed integer problems\n\twith quadratic objectives, else 'no'.\n    <DT><TT>has_qp</TT>\n\t<DD>Returns 'yes' if the solver supports quadratic objectives,\n\telse 'no'.\n    <DT><TT>has_sos</TT>\n\t<DD>Returns 'yes' if the solver supports special ordered sets (SOS),\n        i.e. the sos1/1 and sos2/1 constraints.\n\telse 'no'.\n    <DT><TT>optimizer</TT>\n\t<DD>Returns the name of the external solver, currently\n\t'cplex', 'glpk', 'gurobi', 'highs', 'osi' or 'xpress'.\n        Fails if none of the solver interfaces has been installed!\n    <DT><TT>optimizer_version</TT>\n\t<DD>Returns an integer derived from the version of the\n\texternal solver (for osi, the version is the actual solvers\n        used, including any significant third-party packages such as \n        sparse matrix ordering packages required by the barrier solver)\n    <DT><TT>presolve</TT>\n\t<DD>Returns the default presolve setting for solver setup, i.e. the\n        presolve setting that a solver state would be given if it was not\n        directly specified during setup. A value of 0 disables presolving.\n\tA value of 1 either enables presolving (for external solvers that\n\thave only global parameters), or uses the default optimizer_param\n\tsettings (for external solvers with per-problem parameters).\n    <DT><TT>timeout</TT>\n        <DD>Returns the default time-out setting that a solver state would\n        be given if it was not directly specified during setup. Value is\n        0 if there is no time-out.\n    <DT><TT>optimizer_param(Param)</TT>\n        <DD>Get the Value of the external solver's parameter <TT>Param</TT>.\n        The exact behaviour and available parameters are dependent on the \n        external solver: if the external solver has only problem specific \n        parameters (e.g. XPRESS-MP 13 and later), this gets the default \n        setting that would be used for new problems; if the external solver\n        has global parameters, this gets the global value for the parameter.\n        If Param is not a valid parameter for the solver, an out of range \n        error is raised. See lp_get/3 for more details on the parameters. \n</DL>\n")]).
:- comment(lp_get / 3, [amode : lp_get(+, ++, -), args : ["Handle" : "Handle to an existing solver state", "ParamName" : "Name of parameter (atom or structure)", "Value" : "Returned value for ParamName"], summary : "Retrieve information about solver state and results for solver state Handle.", see_also : [lp_setup / 4, lp_set / 3, eplex_get / 2, lp_add_constraints / 4], desc : html("<P>\n   Retrieve information about solver state and results for the (logically) \n   most recent solved solver state represented by <TT>Handle</TT>. \n   <TT>ParamName</TT> is the same as that for eplex_get/2, which retrieves \n   the same information via the EplexInstance.\n   It can  be one of:\n</P>\n\n<DL>\n<P>  \n     <DT><STRONG><TT>vars</TT></STRONG>\n     <DD>Returns a term ''(X1,...,Xn) whose arity is the number of\n         variables involved in the solver's constraint set, and whose\n         arguments are these variables.\n\n<P>\n     <DT><STRONG><TT>ints</TT></STRONG>\n     <DD>Returns a list [Xi1,...,Xik] which is the subset of the problem\n         variables that the solver considers to be integers.\n\n<P>\n     <DT><STRONG><TT>constraints_norm</TT></STRONG>\n     <DD>Returns a list of the problem constraints (excluding any cutpool\n         constraints) in normalised form.  They may be simplified with\n         respect to the originals that were passed to the problem.\n\n<P>\n     <DT><STRONG><TT>constraints</TT></STRONG>\n     <DD>Returns a list of the problem constraints (excluding any cutpool\n         constraints) in denormalised (readable) form.  They may be\n         simplified with respect to the originals that were passed to the\n         problem.\n\n<P>\n     <DT><STRONG><TT>objective</TT></STRONG>\n     <DD>Returns a term min(E) or max(E), representing objective function\n         and optimisation direction. E is a linear expression: any\n         quadratic components will not be retrieved.\n\n<P>\n     <DT><STRONG><TT>num_cols</TT></STRONG>\n     <DD>Returns the number of columns (i.e. variables) in the matrix of the\n     solver state.\n\n<P>\n     <DT><STRONG><TT>num_rows</TT></STRONG>\n     <DD>Returns the number of rows (i.e. constraints) in the matrix of the\n     solver state.\n\n<P>\n     <DT><STRONG><TT>num_nonzeros</TT></STRONG>\n     <DD>Returns the number of non-zero coefficients in the matrix of the\n     solver state.\n\n<P>\n     <DT><STRONG><TT>num_ints</TT></STRONG>\n     <DD>Returns the number of columns (i.e. variables) constrained to be\n     integers in the matrix of the solver state.\n\n<P>\n     <DT><STRONG><TT>num_quads</TT></STRONG>\n     <DD>Returns the number of non-zero coefficients in the quadratic\n     coefficient matrix (Q-matrix) of the solver state.\n\n<P>\n     <DT><STRONG><TT>method</TT></STRONG>\n     <DD>Returns the method that is specified to solve the problem. If an\n     auxiliary  method can be given for the method, and this auxiliary\n     method is not <TT>default</TT>, the method will be returned as \n     Method(Aux), e.g. <TT>barrier(none)</TT>. The method will be \n     <TT>default</TT> unless otherwise specified by the the user (at setup or \n     via eplex_setup/2 or lp_setup/3).  In that case, the external solver's\n     defaults and any settings done via optimizer_param(_) will be used.\n\n<P>\n     <DT><STRONG><TT>node_method</TT></STRONG>\n     <DD>Applicable to MIP problems only. Returns the method that is\n     specified to solve the problem at the nodes of the branch-and-bound\n     tree. If an auxiliary method can be given for the method, and this\n     auxiliary method is not <TT>default</TT>, the method will be returned\n     as Method(Aux), e.g. <TT>barrier(none)</TT>. The method will be\n     <TT>default</TT> unless otherwise specified by the the user (at setup or\n     via eplex_setup/2 or lp_setup/3).  In that case, the external solver's\n     defaults and any settings done via optimizer_param(_) will be used.\n\n<P>\n     <DT><STRONG><TT>status</TT></STRONG>\n     <DD>Status that was returned by the most recent invocation of the \n         external solver.\n\n<P>\n     <DT><STRONG><TT>cost</TT></STRONG>\n     <DD>Cost of the current solution.\n         Fails if no solution has been computed yet.\n\n<P>\n     <DT><STRONG><TT>best_bound</TT></STRONG>\n     <DD>The best bound (for minimisation, the lower bound) on the optimal \n         objective value for the current problem. Together with the\n         worst_bound, this specifies the range for the optimal objective\n         value. Note that a non-empty range does not mean that the problem\n         is feasible unless an objective value (cost) is also\n         available. The best_bound is the same as the current objective\n         value if the problem has been solved to optimality. It can be\n         better than the objective value either because a) (for MIP\n         problems only) the problem has been optimised to within the\n         mipgap tolerance, or b) the problem was not solved to optimality,\n         i.e. it was aborted before the optimal solution was found.\n<P>\n     <DT><STRONG><TT>worst_bound</TT></STRONG>\n     <DD>The worst bound (for minimisation, the upper bound) on the optimal \n         objective value for the current problem. Together with the\n         best_bound, this specifies the range for the optimal objective\n         value. Note that a non-empty range does not mean that the problem\n         is feasible unless an objective value (cost) is also\n         available. The worst_bound is the same as the current objective\n         value if a solution has been computed for the problem, whether\n         the problem was solved to optimality or not. Depending on the \n         problem type and method used to solve the problem, a worst bound\n         can be returned for a problem even if the solving of the problem\n         was aborted before a solution was obtained. \n<P>\n     <DT><STRONG><TT>typed_solution</TT></STRONG>\n     <DD>Returns a term ''(X1,...,Xn) whose arguments are the properly\n         typed (integer or float) solution values for the corresponding\n         problem variables (<TT>vars</TT>).  The floating point solutions\n         are the same as returned by <TT>solution</TT>, the integers are\n         obtained by rounding the corresponding floating-point solution to\n         the nearest integer.  To instantiate the problem variables to\n         their solutions, unify this term with the corresponding term\n         containing the variables:\n\n<PRE>\n    instantiate_solution(Handle) :-\n        lp_get(Handle, vars, Vars),\n        lp_get(Handle, typed_solution, Values),\n        Vars = Values.\n</PRE>\n<P>\n         Note that this unification could fail if two problem variables Xa\n         and Xb were unified after the solution was lasted computed, as the\n         solutions values in the Xa and Xb positions could be different,\n         even though they are now represented by one variable.\n         Fails if no solution has been computed yet.\n\n</P><P>\n    <DT><STRONG><TT>slack</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the constraint\n        slacks in the logically last solve. The problem consists of normal\n        constraints followed by any added cutpool constraints, and the\n        order corresponds to the list order in <TT>constraints</TT> for\n        normal constraints, and to cutpool_info(last_added,Info) for the\n        cutpool constraints.  Fails if no solution has been computed yet.\n\n<P>\n    <DT><STRONG><TT>slack(Indexes)</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the slack\n        values for the constraints represented by Indexes. Indexes are a\n        list of constraint indices (as returned by lp_add_constraints/4 for\n        normal constraints, and lp_add_cutpool_constraints/4 for cutpool\n        constraints), and the order of the returned list corresponds to the\n        order in <TT>Indexes</TT>.  Fails if no slack value has been\n        computed yet for any of the constraints in Indexes -- note that \n        values are only computed for cutpool constraints if they were added\n        to the problem.\n\n<P>\n    <DT><STRONG><TT>dual_solution</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the dual\n        solutions in the logically last solve. The problem consists of\n        normal constraints followed by any added cutpool constraints, and\n        the order corresponds to the list order in <TT>constraints</TT> for\n        normal constraints, and to cutpool_info(last_added,Info) for the\n        cutpool constraints.  Fails if no solution has been computed yet.\n\n<P>\n    <DT><STRONG><TT>dual_solution(Indexes)</TT></STRONG>\n    <DD>Returns a list of floating-point values representing the dual\n        solutions for the constraints represented by Indexes. Indexes are a\n        list of constraint indices (as returned by lp_add_constraints/4\n        normal constraints, and lp_add_cutpool_constraints/4 for cutpool\n        constraints), and the order of the returned list corresponds to the\n        order in <TT>Indexes</TT>.  Fails if no dual solution has been\n        computed yet for any of the constraints in Indexes -- note that\n        values are only computed for cutpool constraints if they were added\n        to the problem.\n\n<P>\n    <DT><STRONG><TT>constraints(Indexes)</TT></STRONG>\n    <DD>Returns a list of problem constraints as specified by\n        Indexes in denormalised form. The constraints can be either \n        normal constraints or cutpool constraints.\n<P>\n    <DT><STRONG><TT>constraints_norm(Indexes)</TT></STRONG>\n    <DD>Returns a list of problem constraints as specified by\n        Indexes in normalised form. The constraints can be either \n        normal constraints or cutpool constraints.\n<P>\n    <DT><STRONG><TT>cutpool_info(Select,Info)</TT></STRONG>\n    <DD>Returns the information specified by Info for the cutpool constraints\n        specified by Select. The returned information is either\n        i) a pair of lists Indexes-Values where Indexes is the index for\n        the constraint in the corresponding position of Values, or \n        ii) a list of Indexes if the information requested is index. Info \n        can be:\n<DL>\n           <DT><STRONG><TT>index</TT></STRONG>\n               <DD>the indexes for the selected constraints. A list\n                   of Indexes are returned.\n           <DT><STRONG><TT>active</TT></STRONG>\n               <DD>the current active status of the selected constraints. \n                   The status is either 0 (not active) or 1 (active).\n                   A pair of lists Indexes-ActiveStatus is returned.\n           <DT><STRONG><TT>add_initially</TT></STRONG>\n               <DD>the current add_initially status of the selected \n                   constraints. The status is either 0 (not add) or 1 (add).\n                   Note that although inactive constraints have a\n                   add_initially status, they will not be added to a problem.\n                   A pair of lists Indexes-AddInitially is returned.\n           <DT><STRONG><TT>binding_state</TT></STRONG>\n               <DD>the binding state for the selected constraints in the\n                   logically last solve for the problem. A pair of lists\n                   Indexes-BindingStates is returned. To get this\n                   information, the slack values must be available from the\n                   last solve.\n                   The state can be:\n                   a) binding - the constraint was satisfied and binding, i.e.\n                      it is within tolerance of its RHS value in the\n                      normalised form. \n                   b) satisfied - the constraint was satisfied but not\n                      binding. \n                   c) inactive - the constraint was inactive.\n           <DT><STRONG><TT>constraints_norm</TT></STRONG>\n               <DD>the normalised form of the constraints for the selected \n                   constraints is returned in a pair of lists \n                   Indexes-Constraints.\n           <DT><STRONG><TT>constraints</TT></STRONG>\n               <DD>the denormalised form of the constraints for the selected \n                   constraints is returned in a pair of lists \n                   Indexes-Constraints.\n</DL>\n\n    The constraints are selected by Select, which can be:\n<DL>\n           <DT><STRONG><TT>cstr(Idx)</TT></STRONG>\n               <DD>The cutpool constraint as specified by <TT>Idx</TT>. \n           <DT><STRONG><TT>group(Name)</TT></STRONG>\n               <DD>The cutpool constraints in the group <TT>Name</TT>. Both\n                   active and non-active constraints are returned. Note that\n                   the name of the default group is the atom nil (<TT>[]</TT>).\n           <DT><STRONG><TT>last_added</TT></STRONG>\n               <DD>The cutpool constraints that were added to the\n                   problem in the logically previous solve of the problem. \n                   The constraints were either added initially, or were\n                   added because they were violated in an intermediate\n                   invocation. \n           <DT><STRONG><TT>last_notadded</TT></STRONG>\n               <DD>The cutpool constraints that were not added to the\n                   problem in the logically previous solve of the problem,\n                   i.e. they were not violated.\n           <DT><STRONG><TT>last_inactive</TT></STRONG>\n               <DD>The cutpool constraints that were inactive during the\n                   logically last solve of the problem. This does not\n                   include any constraints that were added since the last\n                   solve. \n</DL>\n\n<P>\n    <DT><STRONG><TT>demon_tolerance</TT></STRONG>\n    <DD>Returns a comma-separated pair <TT>(RealTol,IntTol)</TT> of\n        floating-point values which specify how far outside a variable's\n        range an lp-solution can fall before lp_demon_setup/5\n        re-triggers. The tolerances differ for real (default 0.00001) and\n        integer (default 0.5) variables.\n\n<P>\n    <DT><STRONG><TT>simplex_iterations</TT></STRONG>\n    <DD>Returns the external solver's count of simplex iterations.\n\n<P>\n    <DT><STRONG><TT>node_count</TT></STRONG>\n    <DD>Returns the external MIP solver's node count.\n\n<P>\n    <DT><STRONG><TT>statistics</TT></STRONG>\n    <DD>Returns a list of counter values <TT>[Successes, Failures,\n        Aborts]</TT>, indicating how often lp_solve/2 was invoked on the\n        Handle, and how many invocations succeeded, failed and aborted\n        respectively.\n\n<P>\n    <DT><STRONG><TT>timeout</TT></STRONG>\n    <DD>Returns the time-out value for the solver state. This is the amount\n        of CPU time in seconds that the external solver will be allow to\n        spend solving the problem before timing out. The value is 0 if \n        no time-out has been set.\n<P>\n     <DT><STRONG><TT>optimizer_param(Param)</TT></STRONG>\n     <DD>Returns the value of the external solver's parameter Param\n         for the problem represented by Handle. The external solver \n         has a number of parameters that affect the way they work, and \n         this queries their values. If Param is not a valid parameter for\n         the solver, an out of range exception is raised. See below for \n         more details on the parameters.\n<P>\n    <DT><STRONG><TT>post_equality_when_unified</TT></STRONG>\n    <DD>Returns the value (yes or no) if an equality constraint will be\n        posted to a solver if two variables in the solver's problem are \n        unified. \n<P>\n    <DT><STRONG><TT>pool</TT></STRONG>\n    <DD>Returns the name of the eplex instance (if any) associated with \n        the solver state. Fails otherwise. Only useful if called with \n        lp_get/3.\n<P>\n    <DT><STRONG><TT>handle</TT></STRONG>\n    <DD>Returns the solver state handle (if any) associated with the eplex \n        instance. Fails otherwise. Only useful if called with eplex_get/2.\n<P>\n</DL>\nNote that reduced_cost, slack, dual_solution can only be retrieved\nwhen previously requested in the option list of lp_setup/4 or with lp_set/3.\nAn out of range error would be raised otherwise.\n\n<P>\nFor the external solver's control parameter specified by\noptimizer_param(Param), Param must be an atom. The Value returned is\neither an integer, float or atom, depending on the parameter. The parameter\nis generally specific to a solver and version, and also, they may be\nproblem specific, or global, again depending on the solver version. In all\ncases, the value returned by lp_get/3 is the current value for the parameter\nfor the problem Handle. Refer to the solver documentation for details on the \nparameters. The names of the parameters are derived from the names of the \nparameters in the external solver. For CPLEX, take the parameter name from \nthe CPLEX manual (or cplex.h), remove the CPX_PARAM_ prefix and convert the \nrest to lower case, e.g.\n\n<PRE>\n        CPX_PARAM_NODELIM becomes nodelim. \n</PRE>\nFor XPRESS-MP (version 13 and newer), take the parameter name from the \nmanual (or xpresso.h), remove the XPRS_ prefix (if present) and convert \nthe rest to lower case, e.g.\n<PRE>\n\tXPRS_MAXNODE becomes maxnode. \n</PRE>\nFor Gurobi, take the parameter name from the manual and convert it to\nall lower case, e.g.\n<PRE>\n\tIntFeasTol becomes intfeastol. \n</PRE>\n<P>\nFor solvers used via the OSI, there are a few generic parameters supported \nvia OSI, and depending on the actual solver, there may be some additional\nsolver-specific parameters. For the generic parameters, take the parameter\nname, remove the Osi prefix and convert the rest to lower case, e.g.\n<PRE>\n        OsiPrimalTolerance becomes primaltolerance\n</PRE>\n<P>\nFor GLPK, use the names of the parameter structure fields, e.g.\n<PRE>\n        tol_bnd     from glp_smcp\n        ord_alg     from glp_iptcp\n        tol_int     from glp_iocp\n        msg_lev     for all components\n</PRE>\n<P>\n    The following parameter names are additional aliases that work for\n    most solvers:\n<DL>\n    <DT><TT>feasibility_tol</TT> - float\n\t<DD>CPX_PARAM_EPRHS (CPLEX), XPRS_FEASTOL (XPRESS-MP),\n            OsiPrimalTolerance (OSI), FeasibilityTol (Gurobi) or tol_bnd (GLPK)\n    <DT><TT>integrality</TT> - float\n\t<DD>CPX_PARAM_EPINT (CPLEX), XPRS_MIPTOL (XPRESS-MP),\n            CbcIntegerTolerance (OSI,Cbc specific), IntFeasTol (Gurobi)\n            or tol_int (GLPK)\n    <DT><TT>iteration_limit</TT> - integer\n\t<DD>CPX_PARAM_ITLIM (CPLEX), XPRS_LPITERLIMIT (XPRESS-MP),\n            OsiMaxNumIteration (OSI), IterationLimit (Gurobi) or it_lim (GLPK)\n    <DT><TT>mipgap</TT> - float\n\t<DD>CPX_PARAM_EPGAP (CPLEX), XPRS_MIPRELSTOP (XPRESS-MP),\n            SolverAllowableFractionGap (OSI), MIPGap (Gurobi) or mip_gap (GLPK)\n    <DT><TT>node_limit</TT> - integer\n\t<DD>CPX_PARAM_NODELIM (CPLEX), XPRS_MAXNODE (XPRESS-MP),\n            CbcMaxNumNode (OSI, Cbc specific), NodeLimit (Gurobi)\n            or limit on tree node creation (GLPK)\n    <DT><TT>objdifference</TT> - float\n\t<DD>CPX_PARAM_OBJDIF (CPLEX), XPRS_MIPADDCUTOFF (XPRESS-MP) or\n            CbcCutoffIncrement (OSI, Cbc specific)\n</DL>\n")]).
:- comment(lp_get_changeable_value / 3, [template : "lp_get_changeable_value(+Handle, ?Var, -Val)", args : ["Handle" : "Handle to a solver state", "Var" : "A solver problem variable for solver state represented by Handle", "Val" : "The typed_solution value for this variable"], summary : "Interface predicate to access the `changeable' value for this variable."]).
:- comment(lp_get_iis / 5, [summary : "Returns an IIS for an infeasible problem.", args : ["Handle" : "Handle to a solver state", "NumConstraints" : "Number of constraints in the IIS", "NumVars" : "Number of variables in the IIS", "ConstraintIdxs" : "List of Indexes of the constraints in the IIS", "VarInfos" : "List of Variable:Status pairs where Variables are the variables in the IIS and Status is the status of that variable"], amode : lp_get_iis(+, -, -, -, -), exceptions : [141 : "External solver does not support finding IIS"], see_also : [eplex_get_iis / 4, lp_setup / 4, lp_demon_setup / 5, lp_solve / 2, lp_probe / 3, lp_get / 3, lp_set / 3, lp_add_constraints / 4, lp_add_cutpool_constraints / 4], desc : html("    <P>\n    If the solver found that the problem was infeasible, this predicate\n    will return an IIS (Irreducible Infeasible Subsystem or Irreducible\n    Inconsistent Subsystem) for the problem, if supported by the solver. \n    </P><P>\n    This predicate must be called from within a user defined \n    infeasible_handler, and with the cache_iis option set to yes (both\n    can be set during solver set-up or using lp_set/2). The reason for\n    this is the IIS must be computed by the solver before the failed\n    solver state changes, and backtracking pass the failure (the normal \n    behaviour when a problem is infeasible) will logically remove the failed \n    state. cache_iis is needed because the default setting for this\n    option is no, as the IIS need to be computed as an extra step, so\n    IIS is normally not computed.\n    </P><P>\n    An IIS is a subset of the problem constraints and variables which\n    defines an infeasible subproblem. It is usually irreducible in that\n    any proper subset of the IIS is feasible. Finding an IIS allows the\n    diagnostic analysis of the infeasible problem. Note that a problem\n    may have more than one infeasibility, and thus more than one IIS, \n    but this predicate only returns one. \n    </P><P>\n    NumConstraints and NumVars are the number of constraints and variables\n    that are in the IIS. ConstraintIdxs is a list of the constraint indexes\n    of the constraints in the IIS, these indexes are the indexes that are\n    returned by lp_add_constraints/4 and lp_add_cutpool_constraints/4, and can \n    also be used to retrieve the constraint with the constraints_norm(Indexes)\n    and constraints(Indexes) options of eplex_get/2 and lp_get/3. VarInfos gives\n    information for the variables in the IIS, and is a list of Var:Status\n    pair, where Var is a variable in the IIS, and Status is its status.\n    Status is a one character string, and can be:\n<DL>\n       <DT>\"b\": <DD>if both bounds of the variable are involved in the infeasibility\n       <DT>\"u\": <DD>if the upper bound of the variable is involved in the infeasibility\n       <DT>\"l\": <DD>if the lower bound of the variable is involved in the infeasibility\n       <DT>\"x\": <DD>if it is unknown which bound is involved in the infeasibility\n</DL><P>\n    An IIS is returned only if finding IIS is supported by the external\n    solver. In addition, the solver may limit the type of problems and the\n    information returned by the IIS, for example, finding an IIS may be\n    limited to linear problems, and/or bound status information may be\n    unavailable for the variables (hence the need for the \"x\" status).\n    Consult the manual entry for infeasibility analyses for more detail.   \n</P><P>\n    For some external solvers, and for problems on the boundary between\n    feasible and infeasible, it is possible that the routine that finds\n    the IIS will conclude that the problem is feasible, even though it was\n    considered infeasible when the problem was solved. In such cases, an\n    empty IIS will be returned.\n")]).
:- comment(lp_get_license / 0, [summary : "Get a runtime license token for the external solver.", fail_if : "Fails if no license can (currently) be obtained", see_also : [lp_get_license / 2, lp_release_license / 0], desc : html("    \tThe eplex-library interfaces to an external simplex/MIP solver\n\twhich might require a license to run (e.g. CPLEX, XPRESS-MP, Gurobi).\n\tWhen the eplex-library is loaded, it tries to obtain a license\n\timmediately.  If this is not possible, for example because the\n\tlicense pool is temporarily empty, a warning is printed. The\n\tapplication program should then call lp_get_license/0 later\n\tto obtain a license before any eplex functionality is used.\n\tIf a license is successfully obtained or already held,\n\tlp_get_license succeeds, otherwise it fails.\n    <P>\n    \tThis predicate uses information from the file eplex_lic_info.ecl\n\tin the ECLiPSe library directory, or solver specific environment\n\tvariable settings to locate the licensing information.\n    ")]).
:- comment(lp_get_license / 2, [amode : lp_get_license(+, +), args : ["LicStr" : "String or Atom", "LicNum" : "Integer"], summary : "Get a runtime license token for the external solver.", fail_if : "Fails if no license can (currently) be obtained", see_also : [lp_get_license / 0, lp_release_license / 0, lp_get_license_challenge / 1], desc : html("    \tThe eplex-library interfaces to an external simplex/MIP solver\n\twhich might require a license to run (e.g. CPLEX, XPRESS-MP, Gurobi).\n\tWhen the eplex-library is loaded, it tries to obtain a license\n\timmediately.  However, this might not be possible, either\n\tbecause no licenses are currently available, or because\n\tspecific licensing information needs to be supplied.\n    <P>\n\tIn the latter case, lp_get_license/2 must be called explicitly\n\tby the programmer, and the relevant licensing information must\n\tbe supplied as arguments.  The meaning of the arguments is\n\tspecific to the solver used:\n    <PRE>\n                                LicStr          LicNum\n\n        CPLEX development       unused          unused\n        CPLEX runtime           licenvstring    serialnum\n        XPRESS-MP development   xpress_path     unused\n        XPRESS-MP runtime       xpress_path     response\n        Gurobi                  license_file    unused\n        OSI                     unused          unused\n    </PRE>\n        If LicStr is a file or directory name, it is expected to be in\n\tthe native operating system syntax.\n    ")]).
:- comment(lp_get_license_challenge / 1, [amode : lp_get_license_challenge(-), args : ["Challenge" : "Variable"], summary : "Get parameter for computing license key (some external solvers only)", fail_if : "Fails if the solver doesn't use a challenge-response licensing system", see_also : [lp_get_license / 2], eg : "\n     ?- ( lp_get_license_challenge(Challenge) ->\n\t    magic_formula(Challenge, Response),\n\t    lp_get_license(RuntimeLicenseString, Response)\n\t;\n\t    lp_get_license(DevelopmentLicensePath, 0)\n\t).\n    ", desc : html("\tThis is only needed for certain OEM versions of external solvers!\n    <P>\n    \tThe eplex-library interfaces to an external simplex/MIP solver\n\twhich might require a license to run (e.g. CPLEX, XPRESS-MP).\n\tCertain versions of these external solvers use a challenge-\n\tresponse licensing system. Only in such cases is this predicate\n\tneeded. lp_get_license_challenge/1 returns a value which is used to\n\tcompute a license key. This key is then passed into lp_get_license/2.\n\tFor the details of this procedure you will need to consult the\n\tdocumentation of the solver vendor.\n    <P>\n        Be aware that the magic formula supplied by the vendor is usually\n        designed to be performed in a language like C, and may rely on the\n        behaviour of overflowing with 32 bit integers. In ECLiPSe, no\n        overflow will occur because of bignums, and this has to be\n        taken into account if the magic formula is calculated in ECLiPSe.\n    <P>\n\tIf you have a development license of CPLEX or XPRESS-MP, this\n\tpredicate does not need to be called. If called anyway, it fails.\n    ")]).
:- comment(lp_probe / 3, [amode : lp_probe(+, +, -), args : ["Handle" : "Handle to existing solver state", "Probes" : "Temporary probe specification(s)", "Cost" : "Value of solution"], summary : "Invoke external solver, probing the problem temporarily modified by the probe specifications.", see_also : [lp_solve / 2, lp_setup / 4, lp_var_get / 4, lp_get / 3, lp_set / 3, lp_add_constraints / 4], desc : html("<P>\n   Similar to lp_solve/2, but the problem is first temporarily modified\n   as specified in Probes. Probes is a list of one or more probe\n   specifications that specifies how the problem is modified. After the call\n   to this predicate, the problem is restored for the external\n   solver. However, the results from the probe (obtainable from\n   lp_var_get/4 and lp_get/3) are retained.\n</P><P>\n   The following probe specifications are allowed:\n<DL>\n    <DT>min(Expr)/max(Expr)</DT><DD>\n        Minimise/maximise the problem with the objective function Expr.\n        Only existing problem variables can be given in Expr. Cannot be\n        used in conjunction with objsense, objexpr or perturb_obj.</DD>\n    <DT>objsense(Sense)</DT><DD>\n        Sense is either min or max. Solves the problem with the original\n        objective function, but with the sense given in Sense rather than\n        that specified at setup. If only the sense of the objective is to \n        be changed, this changes the objective more efficiently than using\n        min(Expr)/max(Expr). Cannot be used in conjunction with min/max.</DD>\n    <DT>objexpr(Expr)</DT><DD>\n        Optimise the problem with respect to the objective function Expr,\n        without changing the optimisation direction specified at problem\n        setup. Cannot be used in conjunction with min/max or perturb_obj.</DD>\n    <DT>perturb_obj(ObjDeltas)</DT><DD>\n        Perturb the existing linear objective coefficients as specified by\n        ObjDeltas. ObjDeltas is a (possibly empty) list of specifications\n        Var : Delta, where Var is a problem variable and Delta is the\n        amount its existing objective coefficient should be changed by. For\n        example, if the existing objective is 2*X + 3*Y + Z, \n        perturb_obj([X : 1, Y : -0.5]) will modify the objective to \n        3*X + 2.5*Y + Z for the probe. If a variable occurs more than once in\n        ObjDeltas, the change to the objective coefficient is cumulative.\n        Perturb_obj is not strictly needed, as its effect can be achieved\n        by constructing the whole objective and then probing with that.\n        However, this can be expensive if most of the objective stays \n        unchanged, with only a few of its coefficients changed. It is \n        recommended that perturb_obj probe be used in such cases. \n        Cannot be used in conjunction with objexpr or min/max.</DD>\n    <DT>rhscoeffs(RhsCoeffs)</DT><DD>\n        Alter the rhs coefficients of the matrix as specified by RhsCoeffs.\n        RhsCoeffs is a (possibly empty) list of rhs coefficient\n        specifications of the form Idx : Rhs, where Idx is the index of the\n        expandable constraint obtained from using lp_add_constraints/4, and\n        Rhs is the value for the right-hand side constant to use during the\n        probe. Any constraints not specified in RhsCoeffs remain unchanged\n        during the probe. If Idx occurs more than once in RhsCoeffs, the\n        result is undefined.</DD>\n    <DT>bounds(BoundsChanges)</DT><DD>\n        Alter the bounds of problem variables as specified by\n        BoundsChanges. BoundsChanges is a (possibly empty) list of bounds\n        changes of the form Var $:: Lo..Hi, where Var is a problem variable\n        and Lo and Hi are the new lower and upper bounds to use for the\n        variable during the probe. Unlike normal bound changes, the bounds\n        can be widened as well narrowed, although failure will still occur\n        if Hi &lt; Lo. Variables not specified in BoundsChanges retain their\n        bounds during the probe. If Var occurs more than once in \n        BoundsChanges, the result is undefined.</DD>\n    <DT>fixed</DT><DD>\n        The problem is solved as an LP problem by `fixing' the integer\n        variables to their optimal MIP solution values. If there is an\n        existing MIP solution for the problem, eplex will try to use that;\n        otherwise, a MIP solution is obtained first.\n        `Fixed' probing is useful for providing reduced costs for\n        MIP problems. Note that reduced costs for the variables will only be\n        available if the reduced_cost option for the problem is set to yes\n        (this can be done either at problem setup, or by using\n        eplex_set/2). For a problem without integer variables, the original\n        problem is solved without change.  Note that this probe\n        specification is not available if the mip_use_copy option is set to\n        no for external solvers that cannot modify a MIP problem.  Cannot\n        be used in conjunction with `relaxed'.</DD>\n    <DT>relaxed</DT><DD>\n        The problem is solved as an LP problem by relaxing all the integer\n        constraints.  For a problem with integer variables, this should be\n        equivalent to the initial relaxation solved at the start of the MIP\n        search. Depending on the solver, the discreteness of the integer\n        variables may still be taken into account during presolve. To\n        ensure that the problem solved is exactly the LP problem without\n        any integer constraints, presolve should be off. For a problem\n        without integer variables, the original problem is solved without\n        change. Note that this probe specification is not available if the\n        mip_use_copy option is set to no for external solvers that cannot\n        modify a MIP problem. Cannot be used in conjunction with `fixed'.</DD>\n\n</DL>\n</P>"), fail_if : "External solver was unable to find a solution, or bounds probe used and the specified interval for some variable is empty", exceptions : [5 : "EplexInstance does not have a solver setup for it.", eplex_suboptimal : "Solution was found, but is possibly suboptimal", eplex_unbounded : "Problem is unbounded, no solution values", eplex_unknown : "Result is unknown (infeasible or unbounded)", eplex_abort : "External solver aborted for some reason", abort : "Incorrect specification for the probe(s)", 6 : "mip_use_copy option was set to no (solver dependent) for probes that require yes.", 40 : "Handle not valid: solver state had been destroyed by cleanup"]]).
:- comment(lp_read / 3, [amode : lp_read(+, ++, -), args : ["File" : "File name", "Format" : "lp or mps", "Handle" : "Returns a handle to the new solver state"], see_also : [lp_write / 3, lp_setup / 4, eplex_read / 2, eplex_write / 2, lp_probe / 3], summary : "Read a problem from a file and setup a solver for it.", desc : html("\n   Read a problem from a file and setup a solver for it.  Format is\n   lp or mps. The result is a handle similar to the one obtained by \n   lp_setup/4. Note that minimisation of the objective is assumed \n   for mps format, as the sense of the objective is not included in \n   the mps format. Minimisation is also assumed for external solvers\n   that ignore the optimisation direction of the lp file (e.g. Xpress).\n   Note also that although quadratic problems can be read in correctly if\n   supported by the external solver, the quadratic objective coefficients\n   are not extracted from the problem by eplex. These coefficients are\n   used to set/reset the objective when a problem is probed with a\n   different objective in eplex_probe/2 or lp_probe/3, so the objective\n   will not be changed or restored correctly in this case.\n")]).
:- comment(lp_release_license / 0, [summary : "Release a runtime license token for the external solver.", see_also : [lp_get_license / 0, lp_get_license / 2], desc : html("    \tThe eplex-library interfaces to an external simplex/MIP solver\n\twhich might require a license to run (e.g. CPLEX, XPRESS-MP, Gurobi).\n\tWhen the eplex-library is loaded, it tries to obtain a license\n\timmediately, or a license can be obtained by calling\n\tlp_get_license/0.  A held license can then be released using\n\tlp_release_license/0.  The predicate always succeeds, even\n\tif no license was held.\n    ")]).
:- comment(lp_set / 2, [amode : lp_set(++, ++), args : ["ParamName" : "Atom or structure", "Value" : "Integer, float, string or structure"], see_also : [lp_get / 2], resat : no, summary : "Set a global parameter for the external solver.", desc : html("\n<P>\n    Set a global parameter. The parameter names are the same as described\n    in lp_get/2. For the timeout parameter, Value can be of any numeric\n    type. Note that for the external solver's parameters (set via\n    optimizer_param(Param)), the exact behaviour is solver dependent: if\n    the solver has global parameters, this sets the value of the parameter\n    globally; otherwise, this sets the default value of the parameter that\n    would be assigned to a new problem. The setting is <EM>not</EM> undone \n    on backtracking.\n</P><P>\n    In addition, lp_set/2 is used to control the output from the external \n    solver:\n<DL>\n    <DT><TT>lp_set(SolverChannel, +(Stream))</TT>\n       <DD>Send output from SolverChannel to the ECLiPSe I/O stream Stream.\n    <DT><TT>lp_set(SolverChannel, -(Stream))</TT>\n       <DD>Stop sending output from SolverChannel to the ECLiPSe I/O stream \n       Stream.\n</DL>\n    SolverChannel is one of <TT>result_channel, error_channel, warning_channel, \n    log_channel</TT>, and Stream is an ECLiPSe stream identifier (e.g. \n    <TT>output</TT>, or the result of an open/3 operation).\n<P>\n    By default, <TT>error_channel</TT> is directed to ECLiPSe's\n    <TT>error</TT> stream, <TT>warning_channel</TT> to <TT>warning_output</TT>\n    while <TT>result_channel</TT> and <TT>log_channel</TT> are suppressed.\n    To see the output on these channels, do\n</P>\n<TT><PRE>\n   :- lp_set(result_channel, +output).\n   :- lp_set(log_channel, +log_output).\n</PRE></TT>\n<P>\nSimilarly, to create a log file:\n<TT><PRE>\n   :- open('mylog.log', write, logstream), lp_set(log_channel, +logstream).\n</PRE></TT>\nand to stop logging:\n<TT><PRE>\n   :- lp_set(log_channel, -logstream), close(logstream).\n</PRE></TT>\n</P>")]).
:- comment(lp_set / 3, [amode : lp_set(+, ++, +), args : ["Handle" : "Handle to a solver state", "What" : "Option to set", "Value" : "Value being set"], resat : no, summary : "Change initial options for solver state Handle.", see_also : [lp_setup / 4, lp_get / 3, lp_var_get / 4, lp_get_iis / 5, eplex_set / 2], desc : html("<P>\nThis primitive can be used to change some of the initial options\neven after setup. \n<EM>Handle</EM> refers to an existing solver state,\n<EM>What</EM> can be one of the following:\n\n\n<DL>\n    <DT><STRONG><TT>method</TT></STRONG>\n        <DD>Set the method that will be used to solve the problem.  Value\n        is one of <TT>default, auto, primal, dual, net, net(Simplex), barrier,\n        barrier(Crossover), sifting, sifting(SubMethod), concurrent,\n\tconcurrent_det</TT>.  Simplex can be one of <TT>default, auto, primal, dual</TT>,\n\tspecifying the Simplex method to use in the Network Simplex algorithm.\n\tCrossover can be one of <TT>default, auto, primal, dual, none</TT>,\n\tspecifying the crossover method to use for the barrier method.\n\tSubMethod could be one of default, auto, primal, dual, net, barrier</TT>,\n\tspecifying the method to use for the subproblems in the sifting method.\n\tNote that not every method is available on every external solver.\n\tIn case of MIP solving, this is the start algorithm (the one that\n\tis used to solve the initial relaxation). This method setting will\n\toverride similar settings done via optimizer_param(_).\n\n<P>\n    <DT><STRONG><TT>node_method</TT></STRONG>\n        <DD>Applicable to MIP problems only. Set the method that will be\n        used to solve the problem at the nodes (except the root) of the \n        branch-and-bound tree. Note that the method for solving the root\n        node is controlled by the <TT>method</TT> option. Value can be set\n        to the same values as in the <TT>method</TT> option, although \n        there may be more restrictions on what the actual methods/auxiliary\n        methods that are allowed in combination with the root method,\n        due to limitations/restrictions from the external solver. A warning\n        will be given when the problem is solved if this is the case, and \n        the default method used instead.  This node_method setting will\n\toverride similar settings done via optimizer_param(_).\n\n<P>\n    <DT><STRONG><TT>solution</TT></STRONG>\n        <DD>Make the solutions available each time the problem has been\n        (re-)solved successfully.\n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>reduced_cost</TT></STRONG>\n        <DD>Make the reduced costs available each time the problem has been\n        (re-)solved successfully. If the problem is a MIP, then depending on\n        the external solver, this is either unavailable or are the values for\n        the optimal LP node. \n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>slack</TT></STRONG>\n        <DD>Make the constraint slacks available each time the problem has been\n        (re-)solved successfully.\n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>dual_solution</TT></STRONG>\n       <DD>Make the dual solutions available each time the problem has been\n       (re-)solved successfully.  If the problem is a MIP, then depending on\n        the external solver, this is either unavailable or are the values for\n        the optimal LP node. \n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>keep_basis</TT></STRONG>\n        <DD>Store the basis each time the problem has been solved successfully,\n        and use this basis as a starting point for re-solving next time.\n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>mipstart</TT></STRONG>\n        <DD>Use the previous solution values as a warm-start heuristics for\n\tthe MIP search.  This only has an effect for certain solvers (e.g.\n\tGurobi), if there are integrality constraints, and if there is a \n\tprevious solution available.  Possible values are <TT>none</TT>\n\t(no mipstart values, the default), <TT>all</TT> (use previous\n\tsolution for all variables), or <TT>integers</TT> (use previous\n\tsolution for all variables that are now constrained to be integral).  \n\n<P>\n    <DT><STRONG><TT>cache_iis</TT></STRONG>\n        <DD>When a problem is found to be infeasible, compute an IIS for the problem\n        (if supported by the external solver), and store it so that it can bee retrieved\n        by eplex_get_iis/4 or lp_get_iis/5. This will be done before the problem can\n        be modified and make the computing of the IIS impossible. The IIS will oulu\n        be available before the problem is solved again, and before the infeasible  \n        solve is backtracked. This option has no effect if the external solver does not \n        support the finding of IIS. Note that if this option is set, eplex will always ask\n        for an IIS to computed for an infeasible problem, even if it is immediately backtracked \n        by the infeasible handler failing, and that the option is only needed if the problem \n        instance in the external solver is modified before eplex_get_iis/4 or lp_get_iis/5 is called. \n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>demon_tolerance</TT></STRONG>\n        <DD>Specify how far outside a variable's range an lp-solution\n        can fall before lp_demon_setup/5 re-triggers.\n        Value is a comma-separated pair <TT>(RealTol,IntTol)</TT> of \n        floating-point values (default <TT>(0.00001,0.5)</TT>).\n\n<P>\n    <DT><STRONG><TT>use_var_names</TT></STRONG>\n        <DD>Specify if variable names (set using <TT>set_var_name/2</TT> of\n        the var_name library) should be passed to the external solver. If a\n        particular variable does not have a name, a solver's default name\n        would be used. Note that for XPRESS-MP, there is a limit on the length\n        of the name, which can be changed between 8 and 64 in steps of 8 with\n        the parameter <TT>N_NAMLEN</TT>. Variable names longer than this limit\n        are truncated to the limit.  \n        Value is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default \n        is <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>timeout</TT></STRONG>\n        <DD>Set the external solver to time-out after <TT>Value</TT>\n        seconds.  The solver will abort (in either the abort or suboptimal\n        state, depending on if a suboptimal solution was found) if the\n        optimal solution was not found within the time limit. In cases\n        where the solver expects an integer for the time-out interval, the\n        time given is rounded up to the next integer value. This should be\n        used instead of the solver specific optimizer_param(Param) for\n        setting timeouts, as eplex sets these parameter(s) itself. Note\n        that the exact behaviour of the timeout setting is solver dependent.\n        Value is a positive number.\n<P>\n    <DT><STRONG><TT>cutpool_option(Idx,Option)</TT></STRONG>\n        <DD>Set the option Option as specified by Value for the cutpool\n        constraint with index Idx. Option is one of the following:\n<DL>\n           <DT><STRONG><TT>active</TT></STRONG>\n               <DD>Set the active status for the constraint Idx to Value.\n                   Value can be 0 or 1. 0 is non-active, 1 is active.\n           <DT><STRONG><TT>add_initially</TT></STRONG>\n               <DD>Specify if the constraint Idx should be added to a\n                   problem before the solver is invoked. \n                   Value can be 0 or 1. 1 is to add initially, 0 not.\n</DL>\n</P><P>\n        Note that the option is <STRONG>not</STRONG> undone on\n        backtracking.\n</P><P>\n    <DT><STRONG><TT>cutpool_group</TT></STRONG>\n        <DD>Value is an atom, and is used to specify the name of a group of\n        cutpool constraints. If Name is not a current group name, a new\n        group with that name is created. Once created, a named group exists\n        until the problem is destroyed. The default group (with the atom\n        nil (<TT>[]</TT>) as its name) is predefined and does not need to\n        be created with <TT>cutpool_group</TT>.\n<P>\n    <DT><STRONG><TT>suboptimal_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver returned a suboptimal solution (because the problem\n        was aborted). Value would replace any existing suboptimal handler,\n        and would also be run in place of raising the default\n        <TT>eplex_suboptimal</TT> event.\n<P>\n    <DT><STRONG><TT>unbounded_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        problem is unbounded. Value would replace any existing unbounded\n        handler, and would be run in place of raising the default\n        <TT>eplex_unbounded</TT> event.\n<P>\n    <DT><STRONG><TT>infeasible_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver found the problem to be infeasible. Value would\n        replace any existing infeasible handler, and would be run in place\n        of raising the default <TT>eplex_infeasible</TT> event. Note that\n        the default and logically correct behaviour is to fail, this\n        handler is provided to allow the user to analyse the cause of the\n        infeasibility. It is recommended that the handler should also fail\n        after performing the analysis.\n<P>\n    <DT><STRONG><TT>unknown_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver was not able to determine if the problem is\n        unbounded Value would replace any existing unknown handler, and\n        would be run in place of raising the default <TT>eplex_unknown</TT>\n        event.\n<P>\n    <DT><STRONG><TT>abort_handler</TT></STRONG>\n        <DD>Value is a user defined goal to handle the case when the\n        external solver aborted without finding any solution.  Value would\n        replace any existing abort handler, and would be run in place of\n        raising the default <TT>eplex_abort</TT> event.\n<P>\n    <DT><STRONG><TT>optimizer_param(Param)</TT></STRONG>\n        <DD>Set the external solver's control parameter Param for the problem\n        <TT>Handle</TT>. If the solver's parameters are global and not\n        problem specific, an unimplemented functionality exception would\n        be raised. See lp_get/3 for more details on the external solver's\n        parameters. Note that the new setting is <EM>not</EM> undone on \n        backtracking.\n<P>\n    <DT><STRONG><TT>write_before_solve</TT></STRONG>\n       <DD>Value can be the pair (Format,File) or the atom no. If\n       (Format,File) is given, Eplex will ask the external solver to dump\n       the problem each time the solver is solved. This allows the problem\n       in an <TT>eplex_probe/2</TT> or <TT>lp_probe/3</TT> to be dumped. As\n       in <TT>lp_write/3</TT>, <TT>Format</TT> is the format of the dumped\n       problem, and File is the filename. See for more details. Note that\n       the problem is dumped each time the external solver is invoked if\n       the problem has cutpool constraints, where there may be multiple\n       invocations of the solver per solver call.  `no' for Value will turn\n       off this dumping.\n<P>\n    <DT><STRONG><TT>post_equality_when_unified</TT></STRONG>\n        <DD>Value can be the atoms yes or no. Determines if an equality\n        constraint between two solver variables will be posted to the\n        solver when these variables are unified. Setting Value to no means\n        that the constraint will <EM>not</EM> be posted. Note that this can\n        lead to the solver's problem becoming inconsistent with\n        ECLiPSe's. \n<P>\n</DL>\n  Making solutions available means that they can be retrieved using\n  lp_get/3 or lp_var_get/4 after the solver has been run successfully.\n</P><P>\n  All settings apart from optimizer_param(Param) and cutpool settings \n  will be undone on backtracking!\n</P>")]).
:- comment(lp_setup / 4, [amode : lp_setup(+, +, ++, -), args : ["NormConstraints" : "normalised constraints", "Objective" : "Objective function: min(CostExpr) or max(CostExpr)", "ListOfOptions" : "List of solver options", "Handle" : "handle to solver state"], summary : "Create a new external solver state for the constraints NormConstraints.", see_also : [lp_add / 3, lp_set / 3, lp_add_vars / 2, lp_add_constraints / 3, lp_solve / 2, lp_probe / 3, lp_get / 3, lp_get_iis / 5, normalise_cstrs / 3, lp_write / 3], desc : html("<P>\n    Create a new solver state for the set of constraints NormConstraints\n    (see normalise_cstrs/3 for how to obtain a set of normalised\n    constraints).  Apart from the explicitly listed constraints, the\n    variable's ranges will be taken into account as the variable bounds for\n    the simplex algorithm.  Undeclared variables are implicitly declared as\n    reals.\n\n</P><P>\n    However, when variables have been declared integers by other solvers (e.g.\n    integers/1 of the ic library) that is not taken into account by the\n    solver by default.  This means that the solver will only work on the\n    <EM>relaxed problem</EM> (ie. ignoring the integrality constraints),\n    unless specified otherwise in the options.\n\n</P><P>\n    CostExpr is a linear expression\n    (or quadratic if supported by the external solver).\n\n</P><P>\n    Options is a list of options (see below). Unless explicitly specified\n    otherwise, each option should occur no more than once.\n\n\n</P><P>\n    A solver-handle Handle is returned which is used to refer to the solver\n    subsequently.\n\n</P><P>\n    Note: Some external solvers need to write temporary files when they\n    are solving a problem. These are written to the temporary directory\n    specified in ECLiPSe's tmp_dir setting (get_flag/2, set_flag/2).\n\n</P><P>\nThe solver Options are:\n<DL>\n<DT><STRONG><TT>integers(+ListOfVars)</TT></STRONG>\n    <DD>Consider the specified variables to be integers (whether or not\n    they have been declared such).\n    This option will instruct the external solver to use its own MIP solver\n    (ie. branch-and-bound search happens within the external solver).\n<P>\n<DT><STRONG><TT>reals(+ListOfVars)</TT></STRONG>\n    <DD>Consider the specified variables to be problem variables, but does\n    not otherwise constrain the variables. This option allows variables to\n    be added to the problem without requiring them to occur in other\n    constraints. \n<P>\n<DT><STRONG><TT>method(+Method)</TT></STRONG>\n    <DD>Use the specified method (<TT>primal, dual, net, barrier, sifting,\n    default, auto, concurrent, concurrent_det</TT>) (representing Primal\n    Simplex, Dual Simplex, Network Simplex, Barrier, etc) to solve\n    the problem. For MIP problems, this specifies only the start algorithm \n    (the one that is used to solve the initial relaxation). The option\n    node_method should be used to specify the method for the other nodes. \n<P> \n    For some of the methods, an additional `auxiliary' method may be \n    specified in brackets. These are:\n<DL>\n<P>\n      <DT><TT>net(Simplex)</TT>: \n      <DD>specifies the Simplex method (<TT>primal</TT> or <TT>dual</TT>) to \n      follow the network optimisation. For LP problems only.\n<P>\n      <DT><TT>barrier(Crossover)</TT>: \n      <DD>specifies how the crossover to a basic solution from the barrier\n      solution is performed. <TT>Crossover</TT> can be <TT>primal</TT>, \n      <TT>dual</TT>, or <TT>none</TT>. <TT>none</TT> means no crossover is\n      performed. \n<P>\n      <DT><TT>sifting(SubMethod)</TT>: \n      <DD>specifies the method for solving the sifting subproblem. \n      <TT>SubMethod</TT> can be <TT>primal, dual, net, barrier</TT>.\n<P>\n</DL>\n    For all the auxiliary methods, <TT>default</TT> can also be specified.\n    This is equivalent to not specifying an auxiliary method at all. \n<P>\n    Note that not every method is available on every external solver.\n    The default method would use the solver's default method, or any\n    selections done via solver-specific optimizer_param(_) settings.\n\n<P>\n<DT><STRONG><TT>node_method(+Method)</TT></STRONG>\n    <DD>For MIP problems only. Use the specified method (<TT>default, primal,\n    dual, net, barrier, sifting</TT>) to solve the subproblem at each node\n    of the MIP search-tree, except the root node, which is specified by\n    <TT>method</TT> option above. See method option for more description of\n    the methods. Note that there are less choices in the specifications of\n    the auxiliary methods that in the method option, due to limitations in\n    the solvers. If a specified auxiliary method cannot be used, `default'\n    will be used instead.\n\n<P>\n<DT><STRONG><TT>solution(+YesNo)</TT></STRONG>\n    <DD>Make the solutions available each time the problem has been (re-)solved\n    successfully.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>yes</TT>.\n\n<P>\n<DT><STRONG><TT>dual_solution(+YesNo)</TT></STRONG>\n    <DD>Make the dual solutions available each time the problem has been \n    (re-)solved successfully. If the problem is a MIP, then depending on\n    the external solver, this is either unavailable or are the values for\n    the optimal LP node. \n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>slack(+YesNo)</TT></STRONG>\n    <DD>Make the constraint slacks available each time the problem has been \n    (re-)solved successfully.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>reduced_cost(+YesNo)</TT></STRONG>\n    <DD>Make the reduced costs available each time the problem has been\n    (re-)solved successfully. If the problem is a MIP, then depending on\n    the external solver, this is either unavailable or are the values for\n    the optimal LP node. \n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>keep_basis(+YesNo)</TT></STRONG>\n    <DD>Store the basis each time the problem has been solved successfully,\n    and use this basis as a starting point for re-solving next time.\n    This option only affects performance.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n    <DT><STRONG><TT>mipstart(+Option)</TT></STRONG>\n    <DD>Use the previous solution values as a warm-start heuristics for\n    the MIP search.  This only has an effect for certain solvers (e.g.\n    Gurobi), if there are integrality constraints, and if there is a \n    previous solution available.  Possible values are <TT>none</TT>\n    (no mipstart values, the default), <TT>all</TT> (use previous\n    solution for all variables), or <TT>integers</TT> (use previous\n    solution for all variables that are now constrained to be integral).  \n\n<P>\n    <DT><STRONG><TT>cache_iis(YesNo)</TT></STRONG>\n     <DD>Specify if an IIS should be computed immediately for an infeasible problem\n     (if supported by the external solver), and store it so that it can bee retrieved by\n     eplex_get_iis/4 or lp_get_iis/5 (called from within a user-defined infeasible \n     handler). This will be done before the problem can be modified and make the computing \n     of the IIS impossible. The IIS will only be available before the problem is solved\n     again, and also before the infeasible solve is backtracked. This option has no effect  \n     if the external solver does not support the computation of an IIS. Note that if this \n     option is set, eplex will always ask for an IIS to computed for an infeasible problem, \n     even if it is immediately backtracked by the infeasible handler failing, and that the \n     option is only needed if the problem instance in the external solver is modified \n     before eplex_get_iis/4 or lp_get_iis/5 is called. \n     YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n\n<P>\n<DT><STRONG><TT>demon_tolerance(RealTol, IntTol)</TT></STRONG>\n    <DD>Specify how far outside a variable's range an lp-solution\n    can fall before lp_demon_setup/5 re-triggers.\n    <TT>RealTol</TT> and <TT>IntTol</TT> are floats and default to\n    0.00001 and 0.5 respectively.\n\n<P>\n<DT><STRONG><TT>sos1(VarList)</TT></STRONG>\n    <DD><TT>VarList</TT> is a list of variables which the solver should\n    treat as variables of a type 1 special ordered set (SOS), i.e. at most\n    one of the variables in the set can be non-zero. This can occur multiple\n    times, for different sets of variables.\n\n<P>\n<DT><STRONG><TT>sos2(VarList)</TT></STRONG>\n    <DD><TT>VarList</TT> is a list of variables which the solver should\n    treat as variables of a type 2 special ordered set (SOS), i.e. at most\n    two of the variables in the set can be non-zero. This can occur multiple\n    times, for different sets of variables.\n\n<P>\n<DT><STRONG><TT>presolve(+YesNo)</TT></STRONG>\n    <DD>Specify if the external solver should perform presolve for this\n    problem. With presolving, the external solver will transform the\n    problem before solving it. This can lead to significantly faster times\n    to find solutions. However, as the problem has been transformed, some\n    external solvers have restriction on accessing or changing the problem\n    state. In addition, if the solver is repeatedly called because the\n    problem is frequently modified, then presolve may not be an advantage.\n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    determined by the global setting of <TT>presolve</TT>, which can be\n    changed via <TT>lp_set/2</TT>. The initial default is <TT>yes</TT>.\n    Note that the presolve setting cannot be changed for a problem once it\n    is set.  If the external solver supports per-problem optimizer_params, \n    their global defaults will be used for presolve(yes).\n<P>\n<DT><STRONG><TT>timeout(+TimeOut)</TT></STRONG>\n    <DD>Set the external solver to time-out after <TT>TimeOut</TT> seconds.\n    <TT>TimeOut</TT> is a positive number. The solver will abort (in either\n    the abort or suboptimal state, depending on if a suboptimal solution\n    was found) if the optimal solution was not found within the time\n    limit. This should be used instead of setting the solver-specific\n    parameter for time-out directly. In cases where the solver expects an\n    integer for the time-out interval, the time given is rounded up to the\n    next integer value. The timeout is set by setting the external solver's\n    timeout settings, and the exact behaviour may be solver dependent.\n<P>\n<DT><STRONG><TT>suboptimal_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver returned a suboptimal solution (because the problem\n    was aborted). Goal would be run in place of raising the default \n    <TT>eplex_suboptimal</TT> event.\n<P>\n<DT><STRONG><TT>unbounded_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    problem is unbounded. Goal would be run in place of raising the  \n    default <TT>eplex_unbounded</TT> event.\n<P>\n<DT><STRONG><TT>infeasible_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver found that the problem is infeasible. Goal would be run\n    in place of raising the default <TT>eplex_infeasible</TT> event.  Note\n    that the default and logically correct behaviour is to fail, this\n    handler is provided to allow the user to analyse the cause of the\n    infeasibility. It is recommended that the handler should also fail\n    after performing the analysis.\n<P>\n<DT><STRONG><TT>unknown_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver was not able to determine if the problem is unbounded\n    or infeasible. Goal would be run in place of raising the default \n    <TT>eplex_unknown</TT> event.\n<P>\n<DT><STRONG><TT>abort_handler(+Goal)</TT></STRONG>\n    <DD>Specifies a user defined goal Goal to handle the case when the\n    external solver aborted without finding any solution. Goal would be \n    run in place of raising the default <TT>eplex_abort</TT> event.\n<P>\n<DT><STRONG><TT>use_var_names(+YesNo)</TT></STRONG>\n    <DD>Specify if variable names (set using <TT>set_var_name/2</TT> of the \n    var_name library) should be passed to the external solver. If a \n    particular variable does not have a name when it is first passed to the\n    external solver, a default name determined by the solver would be used.\n    Note that for XPRESS-MP, there is a limit on the length of the name,\n    which can be changed between 8 and 64 in steps of 8 with the \n    parameter <TT>mpsnamelength (XPRS_MPSNAMELENGTH)</TT>. Variable \n    names longer than this limit are truncated to the limit. \n    YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default is \n    <TT>no</TT>.\n<P>\n    <DT><STRONG><TT>mip_use_copy(YesNo)</TT></STRONG>\n        <DD>Some external solvers do not allow a MIP problem to be modified\n        once the MIP search has been started. Eplex works around this\n        problem by making a copy of the problem and solving that, so that\n        the original problem can still be modified. This can be turned off to\n        avoid the overhead of making this copy, in which case the MIP\n        problem cannot be modified. This option is used only when solving a\n        MIP problem, and the external solver does not allow a MIP problem to\n        be modified; otherwise it is ignored.\n        YesNo is one of the atoms <TT>yes</TT> or <TT>no</TT>, the default \n        is <TT>yes</TT> so that the problem can be modified.\n<P>\n    <DT><STRONG><TT>write_before_solve(Format,File)</TT></STRONG>\n        <DD>This option is most useful for debugging purposes. If given,\n        Eplex will ask the external solver to dump the problem each time\n        the problem is solved. This allows the problem in an\n        <TT>eplex_probe/2</TT> or <TT>lp_probe/3</TT> to be dumped. As in\n        <TT>lp_write/3</TT>, <TT>Format</TT> is the format of the dumped\n        file and <TT>File</TT> is its name. Note that the problem is dumped\n        each time the external solver is invoked if the problem has cutpool\n        constraints, where there may be multiple invocations of the solver\n        per solver call. \n        The default without this option is that the problem would not be \n        dumped.\n<P>\n    <DT><STRONG><TT>post_equality_when_unified(+YesNo)</TT></STRONG>\n        <DD>This option determines if an equality constraint between two\n        variables will be posted to the solver when these variables are\n        unified. Setting <TT>YesNo</TT> to no means that the constraint \n        will <EM>not</EM> be posted. Note that this can lead to the\n        solver's problem becoming inconsistent with ECLiPSe's. \n<P>\n<DT><STRONG><TT>sync_bounds(+YesNo)</TT></STRONG>\n    <DD>This option determines if the bounds of the problems variables are\n    synchronised with other solvers (i.e. the generic bounds are obtained\n    with get_var_bounds/3 and then passed to the external solver) before\n    the external solver is invoked. This was always done for previous\n    non-standalone version of eplex. For standalone eplex, as the bounds\n    are communicated directly to the external solver, the synchronisation\n    of variable bounds is not needed unless the user is using eplex\n    co-operatively with other solvers (e.g. ic). Even in such cases, it may\n    be more efficient to communicate these bounds changes by explicitly\n    programming it, especially if the problem has many variables and bounds\n    changes happen only to a few of the variables. Setting <TT>YesNo</TT>\n    to yes should increase compatibility with previous code (but note that\n    previous eplex obtained the bounds from a specific bounds keeper like\n    ic rather than the generic bounds).  YesNo is one of the atoms\n    <TT>yes</TT> or <TT>no</TT>, the default is <TT>no</TT>.\n\n</DL>\n")]).
:- comment(lp_solve / 2, [amode : lp_solve(+, -), args : ["Handle" : "Handle to a solver state", "Cost" : "Value of returned solution"], summary : "Explicitly invoke the external solver.", fail_if : "External solver was unable to find a solution.", see_also : [lp_setup / 4, lp_add / 3, lp_get / 3, lp_var_get / 4, lp_add_cutpool_constraints / 4], desc : html("<P>\n   A solver that was setup manually with lp_solve/2 needs to be \n   triggered explicitly using this predicate. \n</P><P>\n   The external solver's LP, QP or MIP solver is applied to the\n   problem represented by Handle.  Precisely which method is used\n   depends on the options given to lp_setup/4.  lp_solve/2 fails if\n   there is no solution or succeeds if an optimal solution is found,\n   returning the solution's cost in Cost (unlike with lp_demon_setup/5,\n   Cost gets instantiated to a number).  After a success, various\n   solution and status information can be retrieved using lp_get/3\n   and lp_var_get/4.\n</P><P>\n   Normally, the external solver is invoked once per call in this\n   predicate, but if the problem contain cutpool constraints (see\n   lp_add_cutpool_constraints/4), then the external solver may be invoked\n   repeatedly to produce a solution which does not violate the cutpool\n   constraints. \n</P><P>\n   When a solver is triggered repeatedly, each invocation will\n   automatically take into account the current variable bounds.  The set of\n   constraints considered by the solver is the one given when the solver\n   was created plus any new constraints that were added (lp_add/3) in the\n   meantime.\n</P><P>\n   The user can define their own handlers (per eplex instance/problem) to\n   handle cases where there was some  error condition, or some limits were \n   exceeded during the solving of the problem. If no handler was defined,\n   by default an event would be raised. These are:\n<DL>\n    <DT>suboptimal handler (eplex_suboptimal event)<DD>\n    \tThis means that a solution was found but it may be suboptimal.\n\tThe default behaviour is to print a warning and succeed.\n    <DT>unbounded_handler (eplex_unbounded event)<DD>\n\tThis means that the problem is unbounded.  The default\n\tbehaviour is to bind Cost to infinity (positive or negative\n\tdepending on the optimisation direction), print a warning and\n\tsucceed.  CAUTION: No solution values are computed when the\n\tproblem is unbounded, so unless the problem was set up with\n\tthe solution(no) option, an error will occur when trying to\n\tcontinue as if the optimisation had succeeded.\n    <DT>infeasible_handler (eplex_infeasible event)<DD>\n    \tThis means that the problem is infeasible. The default\n\tbehaviour is to fail. Redefining this handler allows the \n        examination of the failed problem, e.g. obtaining an IIS for it.\n    <DT>unknown_handler (eplex_unknown event)<DD>\n    \tThis means that due to the solution method chosen, it is unknown\n\twhether the problem is unbounded or infeasible. The default\n\tbehaviour is to print a warning and fail (even though this\n\tmay be logically wrong!).\n    <DT>abort_handler (eplex_abort event)<DD>\n    \tSome other error condition occurred during optimisation.\n\tThe default behaviour is to print an error and abort.\n</DL>\n</P>"), exceptions : [eplex_suboptimal : "Solution was found, but is possibly suboptimal", eplex_unbounded : "Problem is unbounded, no solution values", eplex_unknown : "Result is unknown (infeasible or unbounded)", eplex_abort : "External solver aborted for some reason", 40 : "Handle not valid: solver state had been destroyed by cleanup"]]).
:- comment(lp_suspend_on_change / 3, [template : "lp_suspend_on_change(+Handle, ?Var, +Susp)", args : ["Handle" : "Handle to a solver state", "Var" : "A solver problem variable for solver state represented by Handle", "Susp" : "Suspension to schedule when the typed solution for this variable changes"], summary : "Record the given suspension to be scheduled whenever a solution is found for the Eplex handle."]).
:- comment(lp_var_get / 4, [amode : lp_var_get(+, +, ++, -), args : ["Handle" : "Handle to a solver state", "Var" : "A solver problem variable for Handle", "What" : "Specification for information wanted (atom)", "Value" : "Returned value of What"], summary : "Obtain information for an individual solver problem variable Var.", see_also : [eplex_var_get / 3], exceptions : [4 : "Handle is not instantiated.", 5 : "Handle is not a compound term.", 6 : "What is not a valid value.", 6 : "Var is not a problem variable for Handle.", 6 : "What is unavailable; the information was not requested at solver setup.", 40 : "Handle not valid: solver state had been destroyed by cleanup"], desc : html("<P>\n   Retrieve information about the (logically) most recent solver state and\n   results related to a particular variable, for the solver state\n   represented by Handle. Fails if no solution has been computed yet. What\n   can take the same values as those in eplex_var_get/3.")]).
:- comment(lp_var_get_bounds / 4, [amode : lp_var_get_bounds(+, ?, -, -), args : ["Handle" : "Handle to a solver state", "Var" : "A solver problem variable for Handle", "Lo" : "Lower bound for Var", "Hi" : "Upper bound for Var"], summary : "Returns the bounds stored in the solver state of Handle for Var.", resat : no, see_also : [eplex_var_get_bounds / 3, lp_var_set_bounds / 4], exceptions : [5 : "Handle is not in the form of a solver handle.", 6 : "Var is not a problem variable for Handle.", 40 : "Handle not valid: solver state had been destroyed by cleanup"], desc : html("\n    <P>\n    Returns the numeric bounds stored in the solver state of Handle for the\n    variable Var. The bounds are returned as floats. Var must be an\n    existing problem variable for Handle, i.e. it must occur in the \n    constraints posted to the solver state. ")]).
:- comment(lp_var_occurrence / 3, [amode : lp_var_occurrence(?, +, -), amode : lp_var_occurrence(?, -, -), args : ["Var" : "Variable", "Handle" : "Handle to a solver state, or a variable", "Index" : "Column number for Var in Handle's matrix (integer)"], summary : "Returns the column number Index for Var in the external solver represented by Handle", resat : "Yes (if Handle is a variable).", desc : html("\n    <P>\n    If Handle is a problem handle, then Index is the column number for the\n    variable Var in the problem matrix of the external solver presented by\n    Handle. If Handle is a variable, then the predicate returns the handles\n    and index for each problem handle the variable non-determinately. \n    </P>\n")]).
:- comment(lp_var_set_bounds / 4, [amode : lp_var_set_bounds(+, ?, +, +), args : ["Handle" : "Handle to a solver state", "Var" : "A solver problem variable for Handle", "Lo" : "New lower bound for Var (number)", "Hi" : "New upper bound for Var (number)"], summary : "Imposes new bounds for Var on the solver state of Handle.", resat : no, see_also : [lp_var_get_bounds / 4], fail_if : "Lo is greater than Hi.", exceptions : [5 : "Handle is not in the form of a solver handle.", 6 : "Var is not a problem variable for Handle.", 40 : "Handle not valid: solver state had been destroyed by cleanup"], desc : html("\n    <P>\n    Imposes numeric bounds on the solver state of Handle for the variable\n    Var. Each bound is only updated if it is more narrow than the current\n    bound for the variable. The bounds are converted to floats before they\n    are imposed, and no typing is implied by the type of the numbers. It is\n    possible to impose incompatible bounds for the same variable on\n    different solver states. Var must be an existing problem variable for\n    Handle, i.e. it must occur in the constraints posted to the solver\n    state. ")]).
:- comment(lp_verify_solution / 3, [summary : "Verifies the current solution for the problem associated with Handle.", args : ["Handle" : "Handle to a solver state", "ViolatedCstrs" : "List of violated Constraints.", "ViolatedVars" : "List of violated variables."], amode : lp_verify_solution(+, -, -), desc : html("<P>\n This predicate checks the current solution for the problem associated with\n Handle. It verifies that all the constraints are satisfied by the\n solution values for the problem variables, and that the solution values do\n not violate their bounds, and the values are integral for integer variables.\n Violated Constraints are returned in ViolatedCstrs, and violated variables in \n ViolatedVars.\n</P><P>\n Under normal circumstances, if the external solver produces a solution, it \n should produce no violations. Any violation probably indicates a problem\n with the external solver. However, because the external solver is a complex\n piece of software and may contain problems, it is a good idea to verify the\n solution, and this predicate provides an easy way to do this.\n</P><P>\n Each violation is returned as a structure of the following form:\n <PRE>  vio(type,delta,idx,item) </PRE>\n where\n<DL>\n       <DT>type:   <DD>the type of violation:\n          <DL>\n              <DT>norm:   <DD>the violated item is a normal constraint.\n              <DT>condcp: <DD>the violated item is an active cutpool constraint.\n              <DT>int:    <DD>the violated item is an integer variable whose \n                      solution value is not integral.                    \n              <DT>lower:  <DD>the violated item is a variable whose solution value\n                      is less than the lower bound.                     \n              <DT>upper:  <DD>the violated item is a variable whose solution value\n                      is greater than the upper bound.                     \n           </DL>\n        <DT>delta: <DD>the absolute value of the violation. \n        <DT>idx:   <DD>the index used by the external solver for the item (most\n               likely the row/column number in the problem matrix). This \n               is needed to locate the violation in the solver for reporting\n               or investigating the problem.\n         <DT>item:  <DD>the violated item, i.e. the constraint or variable.\n</DL><P>\n For checking of constraints, a fresh copy of the constraint is made with\n the solution values, as this avoids binding the original variables. Any active\n cutpool constraints in the (logically) last solve of the problem are checked,\n along with the normal constraints. A constraint is considered to be  violated\n if the difference between the sum of the left-hand side and the right-hand side \n for the constraint is greater than the feasibility tolerance (feasibility_tol)\n parameter for the instance. For variables, a bound is considered violated if\n the solution value falls outside the bound by more than feasibility tolerance,\n and integrality is considered to be violated if the fractional part of the\n soltuion is greater than the integrality parameter for the instance. \n"), fail_if : "no solution values are available."]).
:- comment(lp_write / 3, [amode : lp_write(+, ++, +), args : ["Handle" : "Handle to an existing solver state", "Format" : "lp or mps", "File" : "File name"], see_also : [lp_read / 3, lp_setup / 4], summary : "Write a solver problem to a file.", desc : html("\n   Write the problem which corresponds to Handle to a file. The set of\n   supported formats depends on the actual external solver which is used.\n   All solvers support the mps format. Some solvers on some operating\n   system platforms may change or append a suffix to the filename.  Note\n   that the mps format does not specify the sense (min or max) of the\n   objective function. Note also that any active cutpool constraints in the\n   problem will be included in the dump, even though they could be left out\n   of the problem that the external solver actually solves.")]).
:- comment(normalise_cstrs / 3, [amode : normalise_cstrs(+, -, -), args : ["Constraints" : "List of arithmetic relations", "NormConstraints" : "Linear constraints from Constraints (normalised)", "NonlinConstraints" : "Non-linear constraints from Constraints"], summary : "Normalise the linear constraints in Constraints.", see_also : [$= / 2, $=< / 2, $>= / 2, (=:=) / 2, (=<) / 2, (>=) / 2], desc : html("  Constraints is a list of terms of the form X $= Y, X $>= Y or X $=< Y (or\n  their non-$ equivalents)  where X and Y are arithmetic expressions.  The linear\n  constraints are returned in normalised form in NormConstraints, the\n  nonlinear ones are returned unchanged in NonlinConstr.\n")]).
:- comment(optimize / 2, [template : ["optimize(+Objective, -Cost)", "EplexInstance:optimize(+Objective, -Cost)"], args : ["Objective" : "Objective function: min(CostExpr) or max(CostExpr)", "Cost" : "Output: cost of returned solution"], summary : "Setup problem, solve and instantiate problem variables", see_also : [$= / 2, $=< / 2, $>= / 2, $:: / 2, integers / 1, reals / 1, eplex_solver_setup / 1, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, optimize / 3], desc : html("<P>\n    Take the problem defined by all the constraints that have been set up\n    so far, and solve it for the given objective function.  If successful,\n    instantiate all problem variables to their solution values.\n</P><P>\n    This is a convenience predicate that combines solver setup, invocation\n    and result retrieval.  It is essentially defined as:\n    <PRE>\n    optimize(OptExpr, Cost) :-\n        eplex_solver_setup(OptExpr),\n        eplex_solve(Cost),\n        eplex_get(vars, VArr),\n        eplex_get(typed_solution, SolutionVector),\n        VArr = SolutionVector.                  % do the bindings\n    </PRE>\n</P>\n    "), eg : "\n    :- lib(eplex).\n\n    main(Cost, Supply) :-\n        data(PlantCapacities, ClientDemands, TranspCosts),\n        dim(TranspCosts, [NClients,NPlants]),   % get dimensions\n\n        dim(Supply, [NClients,NPlants]),        % make variables\n        Supply :: 0.0..inf,                     % initial bounds\n\n        ( for(J,1,NClients), param(ClientDemands,Supply) do\n            sum(Supply[J,*]) $= ClientDemands[J]\n        ),\n\n        ( for(I,1,NPlants), param(PlantCapacities,Supply) do\n            sum(Supply[*,I]) $=< PlantCapacities[I]\n        ),\n\n        Objective = sum(concat(TranspCosts)*concat(Supply)),\n\n        optimize(min(Objective), Cost).         % solve\n\n    data(\n        [](500, 300, 400),              % PlantCapacities\n        [](200, 400, 300, 100),         % ClientDemands\n        []([](10, 7, 11),               % TranspCosts\n           []( 8, 5, 10),\n           []( 5, 5,  8),\n           []( 9, 3,  7))\n    ).\n"]).
:- comment(optimize / 3, [template : ["optimize(+Objective, -Cost, +Options)", "EplexInstance:optimize(+Objective, -Cost, +Options)"], args : ["Objective" : "Objective function: min(CostExpr) or max(CostExpr)", "Options" : "List of solver options", "Cost" : "Output: cost of returned solution"], summary : "Setup problem, solve and instantiate problem variables", see_also : [$= / 2, $=< / 2, $>= / 2, $:: / 2, integers / 1, reals / 1, eplex_solver_setup / 4, eplex_solve / 1, eplex_get / 2, eplex_var_get / 3, optimize / 2], desc : html("<P>\n    Take the problem defined by all the constraints that have been set up\n    so far, and solve it for the given objective function.  If successful,\n    instantiate all problem variables to their solution values.\n</P><P>\n    This is a convenience predicate that combines solver setup, invocation\n    and result retrieval.  It is essentially defined as:\n    <PRE>\n    optimize(OptExpr, Cost, Options) :-\n        eplex_solver_setup(Objective, _, Options, [])\n        eplex_solve(Cost),\n        eplex_get(vars, VArr),\n        eplex_get(typed_solution, SolutionVector),\n        VArr = SolutionVector.                  % do the bindings\n    </PRE>\n</P><P>\n    For the solver options, see eplex_solver_setup/4.\n</P>\n    "), eg : "see optimize/2"]).
:- comment(piecewise_linear_hull / 3, [template : ["piecewise_linear_hull(?X, ++Points, ?Y)", "EplexInstance:piecewise_linear_hull(?X, ++Points, ?Y)"], args : ["X" : "Parameter/domain of the piecewise function", "Points" : "List of points defining the piecewise function", "Y" : "Result/range of piecewise the function"], summary : "Relates X and Y according to a piecewise linear function.", see_also : [_556162 : piecewise_linear / 3], desc : html("<P>\nThis predicate is intended for use with hybrid ic/eplex solving. It\nimposes the constraint Y = f(X), where f is a piecewise\nlinear function defined by Points: the piecewise_linear/3 constraint for\n the ic solver, and a linear relaxation of it for the eplex instance\n EplexInstance. Please see the documentation for\npiecewise_linear/3 for details of how the piecewise linear function is\nspecified.\n</P><P>\nThis predicate extends lib(ic)'s piecewise_linear/3 by also computing the convex hull\nof the portions of the constraint which are feasible with respect to the\ncurrent bounds (stored with the IC bounds) of X and Y.  Constraints (and\n bounds) defining this convex hull are then\npassed to the eplex instance.  Changes in the IC bounds of the variables are\n automatically forwarded to the eplex instance, so that these constraints are updated whenever new\nbounds on X or Y change the convex hull. Note that the reverse, i.e. bounds\n  changes on the eplex instance,  are NOT forwarded to the IC bounds. \n</P><P>\nThis implementation of the piecewise\nconstraint accepts bounded reals in its arguments, but it\ndoes not fully support bounded reals of non-zero width (i.e.\nthose which do not correspond to a single floating point value).  As a\nresult, use of such bounded reals is not recommended at this time.</P>\n")]).
:- comment(reals / 1, [template : ["reals(?Vars)", "EplexInstance:reals(?Vars)"], args : ["Vars" : "Collection or nested collection of variables and numbers"], see_also : [_500959 : reals / 1, integers / 1, $:: / 2], summary : "Constraints Vars to the real domain for EplexInstance.", fail_if : "Vars contain elements which are neither variable or number.", desc : html("<P>\tConstrains Vars to the real domain in the eplex instance\n        EplexInstance. Any variables that are not problem variables\n        for EplexInstance are added to the problem, with unconstrained\n        bounds (except by the external solver's idea of infinity).\n</P><P>\n        Note that the notion of real is used here in the pure mathematical\n        sense, where real numbers subsume the integers. If the variables\n        are already instantiated, this call checks that the variable is\n        instantiated to a number.\n</P>\n        ")]).
:- comment(reduced_cost_pruning / 2, [summary : "Prune bounds of all problem variables based on their reduced costs", amode : reduced_cost_pruning(+, ?), args : ["Handle" : "Handle to a (solved) solver state", "GlobalCost" : "Bounded global cost variable"], see_also : [lp_demon_setup / 5], fail_if : "None", desc : html("\n    <P>\n    Handle is a problem handle referring to the linear relaxation of\n    a more complex problem. GlobalCost is the overall cost variable\n    of the complex problem.\n    </P><P>\n    This predicate tries to prune the bounds of all variables that\n    occur in the linear relaxation, based on their reduced costs,\n    the optimum of the relaxation, and the currently known bounds\n    (lower if maximising, upper if minimising) on the global cost.\n    </P><P>\n    This predicate should be called just after the Handle has been solved.\n    In particular, it can be used as the post-goal in an lp-demon.\n    The solver should have been set up with the <TT>reduced_cost(yes)</TT>\n    option.\n    </P><P>\n    Note that the bounds of GlobalCost is obtained using the generic\n    get_var_bounds/3. For correct pruning, GlobalCost should only have\n    bounds that are relevant to this problem. \n\n")]).
:- comment(solution_out_of_range / 1, [amode : solution_out_of_range(+), args : ["Handle" : "Handle to a solver state"], see_also : [lp_demon_setup / 5], summary : "A trigger goal for lp_demon_setup/5.", desc : html("<P>\n  This is intended as a useful pre(Goal) for lp_demon_setup/5 in connection\n  with the <TT>bounds</TT> trigger mode.  It succeeds if any of the\n  solutions (computed by the most recent successful solving) of Handle are\n  more than a tolerance outside the range of the corresponding variables,\n  ie. couldn't be instantiated to this value.  The admissible tolerances\n  can be specified in lp_setup/4 or lp_set/3 as <TT>demon_tolerance</TT>.\n</P>")]).
:- comment(sos1 / 1, [template : ["sos1(?Vars)", "EplexInstance:sos1(?Vars)"], args : ["Vars" : "A collection of variables"], see_also : [sos2 / 1, integers / 1], summary : "Constrains all but one of Vars to be zero.", desc : html("<P>\tConstrains all but one of Vars to be zero.  In MIP terminology\n\tthis is called a Special Ordered Set (SOS) of type 1.\n</P><P>\n\tIf the variables are also required to be integral, this must\n\tbe separately declared using integers/1.  Similarly for bounds.\n</P>\n\t")]).
:- comment(sos2 / 1, [template : ["sos2(?Vars)", "EplexInstance:sos2(?Vars)"], args : ["Vars" : "A collection of variables"], see_also : [sos1 / 1, integers / 1], summary : "Constrains all but two consecutive elements of Vars to be zero.", desc : html("<P>\tConstrains all but two consecutive elements of Vars to be zero.  In\n\tMIP terminology this is called a Special Ordered Set (SOS) of type 2.\n</P><P>\n\tIf the variables are also required to be integral, this must\n\tbe separately declared using integers/1.  Similarly for bounds.\n</P>\n\t")]).
:- comment(suspend_on_change / 2, [template : ["suspend_on_change(?Var, +Susp)", "EplexInstance:suspend_on_change(?Var, +Susp)"], args : ["Var" : "A solver problem variable for solver associated with EplexInstance", "Susp" : "Suspension to schedule when the typed solution for this variable changes"], summary : "Record the given suspension to be scheduled whenever a solution is found for the EplexInstance."]).
