API Reference¶
The package contains two modules to model and solve problems.
The eut.peerless.model is used to model the problem
and eut.peerless.solver is used to solve it.
Step by step¶
Lets model the following problem taken from here
Create the model¶
All the variables, constraints, objective and expressions must belong to a model. It will hold the representation of the problem to be solved.
model = eut.peerless.model.Model("Townsend")
Create the variables¶
In this example we only have two variables. Notice that the first argument in the constructor is the model. The variables are added to the model at construction, you don’t have to add them yourself.
At construction time we specify the lower and upper bound too. These are extremely important and the tighter the bounds of the variables, the better the performance of most of the algorithms in Peerless.
x = eut.peerless.model.Variable(model, "x", -10, 0)
y = eut.peerless.model.Variable(model, "y", -6.5, 0)
Add constraints¶
Constraints are created and must be added to the model, they are not added at construction time as variables or the objective function.
Variables and expression have the comparison operators,
<=, >= and ==, overriden to facilitate the creation of constraints.
model.add_constraint((x + 5)**2 + (y + 5)**2 <= 25, "ct1")
Add the objective¶
The objective function is created using an expression at construction. Like variables, the model is the first argument and the objetive is set in the model once it is constructed.
eut.peerless.model.Minimize(model, "objective",
mdl.sin(y) * mdl.exp((1-mdl.cos(x))**2) +
mdl.cos(x) * mdl.exp((1-mdl.sin(y))**2) + (x - y)**2)
Solve the model¶
In order to solve the model we must create the parameters, and optionaly, the environment. If the environment is ommitted, Peerless will send the problem to Eve Utils public servers.
Notice that the size of the problems that can be solved in the public service is limited and that you might encounter delays because your problem might be queued. In case of requiring more performance, contact Eve Utils to get a dedicated server dimensioned to your needs, or maybe to discuss an on premises solution.
parameters = mdl.Parameters()
environment = solver.Environment("your@email.com", "password")
ans = solver.solve(model, parameters, environment)
# Print the solution
print(ans.solution)
Solution and output¶
The value returned by the solver is an instance of
eut.peerless.solver.OptimizationResult. The possible statuses are
defined in eut.abba.processor.statuses.Statuses.
In this case the output is
$ python tests/test_townsend.py
INFO:eut.peerless.solver:Sending problem to the jobstore
INFO:eut.peerless.solver:..job's key is 159534646712651717ed83179cb1fcbd8aa2bb4eff7338b
INFO:eut.peerless.solver:..pooling every 2 seconds
INFO:eut.peerless.solver:..|159534646712651717ed83179cb1fcbd8aa2bb4eff7338b|20200721T11:47:47|created: ''
INFO:eut.peerless.solver:..|159534646712651717ed83179cb1fcbd8aa2bb4eff7338b|20200721T11:47:48|processing: ''
INFO:eut.peerless.solver:..|159534646712651717ed83179cb1fcbd8aa2bb4eff7338b|20200721T11:47:50|executed: 'Objective: -106.76453674926478. Feasibility: 0.0. Iterations: 57. Elapsed: 0.150143996'
{x: -3.130246801712496, y: -1.5821421805049385}
Complete program¶
import logging
logging.basicConfig(level=logging.DEBUG)
import eut.peerless.model as mdl
import eut.peerless.solver as solver
# Create the model
model = mdl.Model("Townsend")
# Add the variables
x = mdl.Variable(model, "x", -10, 0)
y = mdl.Variable(model, "y", -6.5, 0)
# Add the objective function
mdl.Minimize(model, "objective",
mdl.sin(y) * mdl.exp((1-mdl.cos(x))**2) +
mdl.cos(x) * mdl.exp((1-mdl.sin(y))**2) + (x - y)**2)
# Add the constraints
model.add_constraint((x + 5)**2 + (y + 5)**2 <= 25, "ct1")
# Configure the parameters
parameters = mdl.Parameters()
# Solve the model
ans = solver.solve(model, parameters)
# Print the solution
print(ans.solution)
eut.peerless¶
Peerless is a library to model and solve Global Mixed-Integer General Nonlinear Programming problems.
To use the library, model the problem using the classes and functions
in the eut.peerless.model module, and solve the problem
using the classes and function in the eut.peerless.solver module.
eut.peerless.model¶
This module contains the classes and function needed to model a problem.
The principal class is eut.peerless.model.Model, it will hold
the variables, constraints and the objective function.
Almost all classes extend eut.peerless.model.Function, and this class
has some special methods overriden so creating expressions is as close
as possible as to writting algebraic expressions. The overriden special
methods are:
__add__(self, other):
__radd__(self, other):
__sub__(self, other):
__rsub__(self, other):
__mul__(self, other):
__rmul__(self, other):
__truediv__(self, other):
__rtruediv__(self, other):
__mod__(self, other):
__pow__(self, other):
__neg__(self):
__le__(self, other):
__ge__(self, other):
__eq__(self, other):
The last three methods return eut.peerless.model.Constraint instead of
a function. These constraints can then be added to a model.
-
eut.peerless.model.Expression(constant=0)¶ Returns a constant function initialized the given value
- Parameters
constant – the value to initialize the expression to
- Returns
a number function
-
class
eut.peerless.model.Function(*arguments, tag='unknown')¶ Base class for all other functions in the module. A function can be evaluated on a
eut.peerless.model.Solution.-
__add__(other)¶ - Returns
self + other
- Return type
-
__eq__(other)¶ - Returns
the constraint self = other
- Return type
-
__ge__(other)¶ - Returns
the constraint self >= other
- Return type
-
__le__(other)¶ - Returns
the constraint self <= other
- Return type
-
__mod__(other)¶ - Returns
self % other
- Return type
-
__mul__(other)¶ - Returns
self * other
- Return type
-
__neg__()¶ - Returns
-self
- Return type
-
__pow__(other)¶ - Returns
self**other
- Return type
-
__radd__(other)¶ - Returns
other + self
- Return type
-
__rmul__(other)¶ - Returns
other * self
- Return type
-
__rsub__(other)¶ - Returns
-self + other
- Return type
-
__rtruediv__(other)¶ - Returns
other * (1 / self)
- Return type
-
__sub__(other)¶ - Returns
self - other
- Return type
-
__truediv__(other)¶ - Returns
self / other
- Return type
-
property
is_linear¶ - Returns
True if the function and all its arguments are linear
-
The following are the available functions in the library:
-
class
eut.peerless.model.add(x, y)¶
-
class
eut.peerless.model.sub(x, y)¶
-
class
eut.peerless.model.mul(x, y)¶
-
class
eut.peerless.model.truediv(x, y)¶
-
class
eut.peerless.model.pow(x, y)¶
-
class
eut.peerless.model.abs(x)¶
-
class
eut.peerless.model.remainder(x, y)¶
-
class
eut.peerless.model.mod(x, y)¶ x % y
-
class
eut.peerless.model.sign(x, y)¶ copysign(x, y)
-
class
eut.peerless.model.min(x, y)¶
-
class
eut.peerless.model.max(x, y)¶
-
class
eut.peerless.model.sin(x)¶
-
class
eut.peerless.model.cos(x)¶
-
class
eut.peerless.model.tan(x)¶
-
class
eut.peerless.model.sqrt(x)¶
-
class
eut.peerless.model.exp(x)¶
-
class
eut.peerless.model.log(x)¶
-
class
eut.peerless.model.round(x, y)¶
-
class
eut.peerless.model.ceil(x)¶
-
class
eut.peerless.model.floor(x)¶
-
class
eut.peerless.model.Model(name)¶ A model is the main class of the module and it is used to store the representation of the problem at hand.
The structure is simple, it is a container that holds variables and, possibly, constraints and an objective function.
Variables and the objective are added to the model at construction of these. Constraints, on the other hand, must be added to the model using the
eut.peerless.model.Model.add_constraint().- Parameters
name – the name of the model
-
__call__(solution)¶ Evaluates the model at the solution
- Parameters
solution (eut.peerless.model.Solution) – the solution to evaluate the residual on
- Returns
the objective, residual and bound residual of the model at solution
- Return type
-
add_constraint(constraint, name=None)¶ Adds constraint to the model. If name is not None, it is assigned to the constraint. If name is None and the constraint’s name is also None, the constraint is assigned a generic name of the form ct_n where n is the number of constraints in the model.
- Parameters
constraint – the constraint to add to the model
name – the name to assign to the constraint if the constraint’s name is None
-
bounds_residual(solution)¶ Evaluates and returns the residual of the variables’ bounds, that is, \(\sum_{v} (v_{lb} - solution(v))^+ + (solution(v) - v_{ub})^+\)
- Parameters
solution (eut.peerless.model.Solution) – the solution to evaluate the residual on
-
property
constraints¶ - Returns
a list of constraints sorted by name
-
cts_residual(solution)¶ Evaluates and returns the residual of the model, that is, \(\sum_{ct} ct(solution)\). Notice that constraints always return a positive number.
- Parameters
solution (eut.peerless.model.Solution) – the solution to evaluate the residual on
-
get_variable(name)¶ - Returns
the variable of that name
-
property
is_linear¶ - Returns
True if the objective and constraints of the model are linear
-
property
variables¶ - Returns
a list of variables sorted by name
-
class
eut.peerless.model.ModelMeasures(objective, cts_residual, bounds_residual)¶ A namedtuple holding the objective, constraint residual and bound residual
-
eut.peerless.model.Variable(model, name, lb=None, ub=None)¶ Represents a variable in the model.
Even thought it isn’t required to define lower and upper bounds on a variable, the algorithms will perform better the thighter the bounds of the variables are.
Variables can be continuous, integer and binary.
Variables are added to the model at construction time
A variable is a
eut.peerless.model.Functionthat evaluates to the value at the given solution.
To create a continuous variable use this class without specifying
- Parameters
model – the model to which the variable will be added
name – the name of the variable
lb – lower bound
ub – upper bound
-
eut.peerless.model.IntegerVariable(model, name, lb=None, ub=None)¶ Represents an integer variable. See
eut.peerless.model.Variable()for more information.
-
eut.peerless.model.BinaryVariable(model, name)¶ Represents a binary variable. See
eut.peerless.model.Variable()for more information.
-
class
eut.peerless.model.Constraint(lhs, sense, rhs, name=None)¶ A constraint represent a relation between variables that must be satisfied by the solutions. Constraints are generally created usign the overriden operators of
eut.peerless.model.Function, <=, >=, ==. Constraints can also be created directly using the constructor of the class.Constraints must be added to the model using
eut.peerless.model.Model.add_constraint().Creates the constraint: lhs sense rhs
- Parameters
lhs – a function or number
sense – one of
eut.peerless.model.Constraint.le,eut.peerless.model.Constraint.georeut.peerless.model.Constraint.eqrhs – a function or number
name – the name of the constraint
-
__call__(solution)¶ Evaluates the constraint according to the sense: * eq: abs(ct(solution)) * le: max(0, lhs(solution) - rhs(solution)) * ge: -min(0, lhs(solution), rhs(solution))
- Parameters
solution (eut.peerless.model.Solution) – a solution
-
eq= '='¶ Equal constraint tag
-
ge= '>='¶ Greater or equal constraint tag
-
property
is_linear¶ - Returns
True if lhs and rhs are linear
-
le= '<='¶ Less or equal constraint tag
-
eut.peerless.model.Maximize(model, name, function)¶ Creates a maximization objective function and set it in the model
- Parameters
model – the model to set objective to
name – the name of the objective
function – the function representing the objective
- Returns
a callable receiving a solution as argument
-
eut.peerless.model.Minimize(model, name, function)¶ Creates a minimization objective function and set it in the model. See
eut.peerless.model.Maximize().
-
class
eut.peerless.model.Solution¶ A solution is a class emulating a container used to set and get the value of variables in the solution.
-
__getitem__(variable)¶ Allows the following: solution[variable]
-
__setitem__(variable, value)¶ Allows the following: solution[variable] = value
-
items()¶ Returns a list of pairs (variable, value)
-
-
class
eut.peerless.model.Parameters(max_seconds=3600, objective_goal=None)¶ Class to specify the parameters used by the solver.
- Parameters
max_seconds – stop the solve process after max_seconds. The current best solution is returned if available.
objective_goal – stop the solve process if found a feasible solution with an objective less or equals to this value.
eut.peerless.solver¶
-
class
eut.peerless.solver.Environment(username, password, *, jobstore='http://eveutils.services/peerless/', pooling_gap=2, only_log_status_changes=True, priority=100)¶ An environment is used to define the way the client will interact with the solve service.
- Parameters
username – a username authorize to send jobs
password – the password
jobstore – the url of the jobstore
pooling_gap – nb. seconds between requests for job status
only_log_status_changes – if True, only status changes will be logged, else, show a log every time the server is poolled.
priority – the priority of the job. A positive number. The lower the value the higher the priority. It is overriden by the priority specified in the user, if any.
-
class
eut.peerless.solver.OptimizationResult(solution=None, statuses=[], log='')¶ This is the object returned by
eut.peerless.solver.solve(). It has the following attributes:solution: an instance of
eut.peerless.model.Solutionstatuses: a list of the statuses (
eut.abba.processor.statuses.StatusStamp) the solve process went through.log: the output of the solve process
-
eut.peerless.solver.solve(model, parameters, environment)¶ Sends the model and parameters to the jobstore specified in the environment.
- Parameters
model (eut.peerless.model.Model) – the model to be solved
parameters (eut.peerless.model.Parameters) – the solver parameters
environment (eut.peerless.solver.Environment) – jobstore, username, password and server interaction configuration.
- Returns
the best solution found by the solver
- Return type
The job service¶
The jobs are stored in a eut.abba.processor.jobstore.JobStore.
A JobStore is registered in a eut.abba.rpc.Server, with
the server extending
xmlrpc.server.DocXMLRPCServer.
The jobstore is self-documenting and is located at
http://eveutils.services/peerless/
A xmlrpc.client.ServerProxy can be used to query the JobStore, it
must be created using allow_none=True.
eut.abba.processor.jobstore.JobStore¶
-
class
eut.abba.processor.jobstore.JobStore(dbpath, guardian_url, config)¶ A JobStore is a class that manages jobs. It is published in a
eut.abba.rpc.Serverand can be used by a xmlrpc.client.ServerProxy to cancel a job, get partial solutions, the result and statuses of a job-
cancel(username, password, key)¶ Cancels the job with key
-
cancelled(username, password, key)¶ Returns True if the job with key is cancelled
-
get_partials(username, password, key)¶ Returns the list of partial solutions of the job with key. Each item in the list is a
eut.abba.processor.statuses.PartialSolution
-
get_result(username, password, key)¶ Returns the tuple (result, stdout) of the job with key. In the case of Peerless, result is a serialized
eut.peerless.model.Solution. A Solution object can be obtained deserializing the result using eut.peerless.model.Solution.deserialize(model, result) where model is an instance ofeut.peerless.model.Modelto which the solution belongs to.
-
get_statuses(username, password, key)¶ Returns the list of statuses of the job with key. Each item in the list is a
eut.abba.processor.statuses.StatusStamp
-
eut.abba.processor.statuses¶
-
class
eut.abba.processor.statuses.PartialSolution(date, result)¶ A partial solution
- Parameters
date – datetime.datetime when the partial solution was created
result – the result, see
eut.abba.processor.jobstore.JobStore.get_result()
-
class
eut.abba.processor.statuses.StatusStamp(date, status, message)¶ A status stamp
- Parameters
date – datetime.datetime of the stamp
status – one of the attributes of
eut.abba.processor.statuses.Statusesmessage – the message associated to the stamp
-
class
eut.abba.processor.statuses.Statuses¶ Possible job statuses
-
acquired= 'acquired'¶ The job was acquired by a worker
-
created= 'created'¶ The job was created and is waiting for a worker to start processing it
-
executed= 'executed'¶ This status is used when a job has been processed
-
failure= 'failure'¶ Status used when an error ocurrs
-
finals= ('optimum', 'infeasible', 'failure', 'executed')¶ List of possible final statuses of a job
-
infeasible= 'infeasible'¶ Indicates that a solution in infeasible
-
optimum= 'optimum'¶ Indicates that a solution is optimal
-
partial= 'partial'¶ Status associated to a partial solution
-
processing= 'processing'¶ The job is beign processed by a worker
-
eut.abba.rpc.Server¶
-
class
eut.abba.rpc.Server(addr, log_requests=True, encoding=None, bind_and_activate=True, use_builtin_types=True, nb_concurrent_requests=30)¶ -
process_request(request, client_address)¶ Start a new thread to process the request.
-
shutdown()¶ Stops the serve_forever loop.
Blocks until the loop has finished. This must be called while serve_forever() is running in another thread, or it will deadlock.
-