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

\[\begin{split}\begin{eqnarray} \min\; & \sin(y)e^{(1-\cos(x))^2} + \cos(x)e^{(1-\sin(y))^2} + (x-y)^2 \\ s.t.\; & (x+5)^2+(y+5)^2\le 25 \\ & -10 \le x \le 0 \\ & -6.5 \le y \le 0 \end{eqnarray}\end{split}\]

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

eut.peerless.model.add

__eq__(other)
Returns

the constraint self = other

Return type

eut.peerless.model.Constraint

__ge__(other)
Returns

the constraint self >= other

Return type

eut.peerless.model.Constraint

__le__(other)
Returns

the constraint self <= other

Return type

eut.peerless.model.Constraint

__mod__(other)
Returns

self % other

Return type

eut.peerless.model.mod

__mul__(other)
Returns

self * other

Return type

eut.peerless.model.mul

__neg__()
Returns

-self

Return type

eut.peerless.model.mul

__pow__(other)
Returns

self**other

Return type

eut.peerless.model.pow

__radd__(other)
Returns

other + self

Return type

eut.peerless.model.add

__rmul__(other)
Returns

other * self

Return type

eut.peerless.model.mul

__rsub__(other)
Returns

-self + other

Return type

eut.peerless.model.add

__rtruediv__(other)
Returns

other * (1 / self)

Return type

eut.peerless.model.mul

__sub__(other)
Returns

self - other

Return type

eut.peerless.model.sub

__truediv__(other)
Returns

self / other

Return type

eut.peerless.model.truediv

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

eut.peerless.model.ModelMeasures

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.Function that 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
__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:

eut.peerless.solver.solve(model, parameters, environment)

Sends the model and parameters to the jobstore specified in the environment.

Parameters
Returns

the best solution found by the solver

Return type

eut.peerless.solver.OptimizationResult

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.Server and 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 of eut.peerless.model.Model to 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
class eut.abba.processor.statuses.StatusStamp(date, status, message)

A status stamp

Parameters
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.