Operations Research with Python Guide
Operations Research with Python Guide
ECONOMÍA
edUPV
Y
DIRECCIÓN DE EMPRESAS
Francisco Fraile
Fraile Gil, Francisco (2024). Notebooks for Operations Research. A practical guide to operations research with
Python. Valencia: edUPV. [Link]
The contents of this publication have been evaluated by a double –blind system as can be consulted on the following
page [Link]
Autorship
Francisco Fraile Gil
Publisher
Pu
2024, edUPV (Editorial Universitat Politècnica de València)
20
[Link] / Ref.: 6778_01_01_01
ISBN: 978-84-1396-253-5
DOI: [Link]
If the reader detects a mistake in the book or wishes to contact the authors, he can send an email to
edicion@[Link]
Notebooks for Operations research, A practical guide to operations research with Python / edUPV
The reuse of the contents is allowed through the copying, distribution, exhibition and representation of the work, as well as the generation of
derivative works as long as the authorship is acknowledged and it is cited with complete bibliographic information. Commercial use is not
permitted and derivative works must be distributed under the same license as the original work.
AUTHOR
Francisco Fraile holds a PhD in Telecommunications from the Polytechnic University of Valencia, with a
background in research, innovation and teaching. He currently works at the Centre for Research in
Production Management and Engineering (CIGIP), where he leads projects in digital platforms for
manufacturing and logistics, integration of artificial intelligence and robotics, and zero defects
manufacturing. He has coordinated and participated in R&D&I projects, in European, national and
regional calls, standing out in the transfer of sustainable technologies to industry. Associate professor at
EDEM, he is dedicated to training future engineers in operations research and programming. His work
combines applied research and education in automated production systems engineering, pursuing a strong
social and technological impact.
SUMMARY
Notebooks for Operations Research is a practical guide that uses Python and Jupyter Notebooks to teach
the principles and applications of operations research. Designed for both beginning students and
professionals, the text connects theory and practice through interactive tutorials, solved exercises, and the
use of Python libraries to solve problems with a hands-on approach.
Chapters cover topics such as linear programming, combinatorial optimisation, non-linear programming,
decision and game theory, simulation and Markov chains. Each section integrates mathematical concepts
with real-world applications, demonstrating how to solve optimisation and decision-making problems in
complex contexts, especially in supply chain management.
In addition, the book highlights the relationship between operations research and artificial intelligence,
focusing on mathematical reasoning and optimisation techniques, and provides an introduction to
machine learning. It is an interactive book in the sense that all content is available in an interactive online
environment that allows experimentation with the code. It provides fundamentals, tools and open source
resources for those seeking to master operations research in a practical and modern approach.
CONTENTS
7 Bibliography 407
i
Notebooks for Operations Research, Release I
Preamble
Welcome to the Notebooks for Operations Research interactive book! This book contains a collection of Jupyter Notebooks
with tutorials, exercises and Python libraries designed to explain the principles and applications of operations research.
Our primary goal and motivation is to bridge the gap between theoretical background and practical applications, lever-
aging the interactive features of Jupyter Notebook so that learners can engage with the content. Operations research is a
fascinating field with countless real life applications, and we believe that, just as with many other fields, the best way to
learn is to incorporate practical applications and skills. In this sense, Python provides a comprehensive toolset to solve
operations research problems, and a user-friendly programming language that is easy to learn and close to mathematical
language, thus it is perfect match for our objectives!
Before you embark in this educational project, you need to know that the interactive book has been carefully crafted to
introduce operations research to novice students. The chapters are organised to guide readers from the fundamentals of
operations research to the application of complex problem solving methods and techniques in real life scenarios using
Python. The book primarily covers applications related to engineering and management, as its origins root back to the a
course on Operations Research at EDEM, although it is open for the entire community. It is also important to note that
this interactive book is a living document, open for contributions and continuously evolving to adding new content and
advancements in the field.
We happily invite you to join us and learn the fundamentals, challenge yourself with exercises, and learn the Python
libraries to apply operations research in the real world. We have tried to make theory more easy to reach through the
interaction with code. Additionally, the interactive notebooks incorporate questions for analysis and template prompts so
that you can delve into its contents with the help of an AI assistant. We want to provide an integrated environment with
all the tools you need to learn operations research with a practical mindset, at your own path.
CONTENTS 1
CHAPTER
ONE
This chapter contains an introduction to Operations Research, and also covers the fundamentals of Python programming
and Jupyter Notebooks used in the course, including basic tutorials and usage tips for two important libraries: Numpy
and Matplotlib.
1.1.1 Motivation
The main objective of operations research is to support decision making through methods and techniques based on the
scientific method and mathematics. Formally, making a decision is the process of selecting the best alternative between a
set of alternative options. Depending on the problem, there can be a finite set or an infinite set of alternative options. The
connection between Operations Research and management is clear: Managers make decisions and in extension, decision
making is strongly connected to management. From this perspective, Operations Research gathers a set of tools that
identify the best (optimal) alternative in a systematic way, based on a set of assumptions that allows us to model the
decision making process using the mathematical language.
In a nutshell, the objective of OR is to find optimal solutions to management problems, optimizing the performance of
complex systems. In practice, the optimization is achieved using mathematical methods and these methods are imple-
mented using computers and computer science. Although operations research can be applied to different domains, this
book is focused on supply chain management. As illustrated in the figure below, in this book, supply chain management,
applied mathematics, and computer science overlap and interact in a number of ways.
3
Notebooks for Operations Research, Release I
Supply chain management is the process of coordinating the flow of goods, services, and information from suppliers,
through production and distribution, to customers. It involves managing the relationships between different parties in the
supply chain, as well as coordinating the activities and resources needed to move goods and services from one place to
another. Some of the key activities involved in supply chain management include sourcing raw materials and components,
manufacturing and assembling products, warehousing and storing finished goods, and transportation and distribution. The
goal of supply chain management is to ensure that goods and services are produced and delivered efficiently and effectively,
while minimizing costs and risks. Operations research and computer science can both play important roles in the design
and optimization of supply chain systems.
Supply chain models provide a framework for understanding and analyzing the various components and processes involved
in the supply chain, and operations research techniques (a branch of applied mathematics) can be used to design and
analyze algorithms for optimizing the performance of these systems. Once the algorithms have been designed and tested,
computer science can be used to implement the solution, either by building a custom software application or by using a
pre-existing tool or platform.
The next section describes the management framework used in the book, consisted of management levels, and business
processes modelling supply chain management.
Business processes represent the group of activities needed to produce goods or services. From a very fundamental
point of view, any company produces goods or service and delivers these good or services to customers. Likewise, the
company has to purchase the goods or services that are needed to produce and deliver their offer from a set of suppliers.
Obviously, every organisation needs to make good decisions in these processes to remain to be competitive. Normally,
companies are organised into different business units or departments. Some examples are the sourcing department, in
charge of purchases, the engineering department in charge of product design and production, sales, financing, marketing,
human resources. Managing these departments means making decisions, and these decisions must be aligned to meet the
objectives of the company.
The Supply Chain Operations Reference model (SCOR) provides a model for the management processes involved in a
company, the Supply Chain Reference Model, In the SCOR model, we identify six management processes:
• Plan: The first is the Plan, which groups all processes that determines the best course of action to meet the re-
quirements of the rest of the processes.
• Source: The second group are source processes, which are in charge of provisioning resources needed to meet the
demand for our products.
• Make: The third are Make processes, which transform the goods and services of the suppliers into the good or
services that meet the demand of our customers.
• Deliver: Then, we have the deliver processes which imply the needed transportation, and logistics necessary to
deliver our products and services.
• Return: The return processes deal with the returning of products or services from customers because they do not
meet the requirements or the level of service that was agreed, but also the return of good or services to our suppliers
for the same reason.
• Enable: And finally, enable processes which are associated with the management of the supply chain, that is the
management of the relationships with our collaborators, both customers and suppliers.
Operations Research provides tools to support decision making in these management processes. All the problems included
in this interactive book can be mapped to the processes in the SCOR model.
Management levels divide management and therefore decision making into three planes that are traversal to the entire
company: The strategic level, the tactical level and the operational level.
Each level has its own responsibilities and all work towards the same goals, to achieve the same objectives. The main
differences between levels is that they deal with different time scales.
• Strategic level: The strategic level deals with long term business decisions and assurance of business objectives in
the future. Therefore, decisions at this level deal with long time periods or time horizons, in the range of several
years. Consequently, they need to be revisited or updated with a periodicity in the range of months.
• Tactical level: The tactical level on the other hand deals with business decisions to ensure the fulfillment of the
objectives in the near future, for instance, in the next 1 or two years. Tactical level decisions need to be revisited
every few months to ensure mid term performance. Some examples are for instance client acquisition or investment
selection.
• Operational level: Finally, the operational level deals with intermediate-term decisions in processes, rather than
business decisions. Operational management controls how the different processes, or the different units of an
organisation implement the company´s strategic and tactical objectives. The operational level articulate specific
processes and spans management decisions in smaller periods of time, from months to minutes. Consequently,
they need to be revisited rather frequently.
Operations Research provides tools to support decision making in any of the three levels, although the O in OR clearly
refers to the operational level.
Operations Research is strongly connected to Artificial Intelligence (AI). The European Union defines AI as:
"Artificial intelligence (AI) refers to systems that display intelligent behaviour by analysing their environment and
taking actions - with some degree of autonomy - to achieve specific goals"
Therefore, AI systems sense their environment and take optimal decisions to achieve specific goals. Clearly, from this
definition, AI and OR are also interlinked and can be used together to solve complex optimization problems. Fundamen-
tally, both disciplines make use of mathematics, primarily in the field of optimisation, to find the best course of action.
For this reason, and given the importance and impact of AI in solving decision problems, this book will also cover some
of the basics of modern artificial intelligence.
Moreover, as described in the same document referenced above, broadly speaking, all such artificial intelligence techniques
can be grouped in two main groups, related to the capabilities of reasoning and learning.
• Reasoning: These techniques allow an AI system to take as input the data coming from different sources and
propose an action to take, given the goal to achieve.
• Machine learning: These techniques allow an AI system to learn how to solve problems that cannot be precisely
specified, or whose solution method cannot be described by symbolic reasoning rules.
Operations research techniques, such as mathematical modeling and optimization algorithms, can be used to represent and
solve reasoning problems in a way that is amenable to automation and solution by an AI system. In turn, machine learning
can be used to improve the performance and efficiency of operations research models and algorithms. For example, an
AI system might be used to analyze large amounts of data and identify patterns and relationships that are not immediately
apparent to humans. This analysis can then be used to inform the development of more accurate and effective operations
research models, which can be used to optimize the performance of a system. Similarly, an AI system might be used to
automate the solution of operations research models, allowing for faster and more accurate decision making. Overall, the
combination of AI and operations research can be a powerful tool for solving complex optimization problems in a wide
range of fields.
Let us emphasize again that this book in OR is mainly focused on reasoning techniques, and not so on learning techniques
(although it will cover the basics). Reasoning techniques will allow us to find the best decision from a set of alternative
options. The course will discuss extensively optimisation which is an entire field of mathematics dedicated to finding
the optimal (normally the minimum or the maximum) solution among all feasible solutions. Due to the importance
of these definitions, they are formally defined in a section below. The course will also cover searching problems and
Combinatorial Optimization, which is the sub-field of optimisation dedicated to finding an optimal solution from a
finite set of solutions. The course will describe how complex problems in OR, like planning (eg finding the optimal
allocation or resources to accomplish a specific objective) or scheduling (find the optimal order of activities that minimise
the execution of an activity plan, given a limited set of resources), can be modeled and solved using advanced analytic
techniques.
Although it is not a fundamental part of this course, the course will also describe how machine learning is strongly related
to the same techniques and will discuss specific applications of machine learning in OR.
1.3.1 Reasoning
The reasoning capability can be further divided into four basic steps needed to be able to choose the best action (make a
rational decision) to achieve one objective:
• Problem modelling: Obtain a mathematical representation of the decision making problem.
• Input data collection: Transform the available data into a format that can be input to the problem model
• Reason with the input data: (eg find the optimal solution among all possible alternatives)
• Make a decision: based on the provided result (feedback)
The first part of the problem modelling process is to provide a clear definition of the objectives and the scope of man-
agement. In other words, the first question that one needs to answer is:
What are the goals? And, what is the relationship between these goals and the decision or decisions under
analysis?
The answer to these questions will be in the form of a set of variables, and mathematical expressions between these
variables that will express the decision problem as a mathematical problem.
System theory is useful at this point to provide a clear framework to illustrate problem modelling.
Data collection is the process that determines the values of the (technological) coefficients and uncontrollable variables
in our model. In other words, data collection is the process that determines the value of the parameters of our model.
Before data collection, our model is an abstract model that represents any decision problem instance it has been designed
for. For instance, we can derive an abstract model to determine the optimal investments subject to a set of constraints
that model the market. But if we want to use this model to determine the optimal investments for our company, we need
to input into this model our company data and give values to its parameters.
In this sense, there are different types of models depending on the nature of their parameters:
• Deterministic models: All model parameters are known with certainty
• Stochastic models: All model parameters are stochastic variables (ie there is some degree of uncertainty in their
value)
• Mixed models: Models that combine deterministic and stochastic parameters
1.3.4 Reasoning
Finally, once we have a specific instance of a model with our collected data, we are able to apply a technique to find the
solution to the problem.
Types of solutions
There are however different types of solutions that we will be able to find:
• Feasible solution: It meets all the requirements and constraints set by the environment, otherwise the solution is
unfeasible
• Optimal solution: It provides the best result of all feasible solutions. Normally, our objective is to find the optimal
solution, but depending on the complexity of our problem, at times this might just not be possible
• Sub-optimal solution: It provides a bounded feasible solution, that is, a solution that is at a known maximum
distance to the optimal solution.
Types of techniques
Depending on the problem model, we will have different mathematical techniques to find a solution to our problem. These
techniques can be classified into the following categories:
• Numerical Techniques: Numerical techniques test the effectiveness of the different alternatives to find the optimal
solution. Depending on the strategy used to explore the solution space, numerical techniques can be classified into
the following categories:
– Enumeration (Brute force): This is the simplest technique: Test ALL possible solutions.
– Algorithms: Step-by-step procedure to find optimal solution
– Heuristic: Step-by-step procedure to find a sub-optimal solution with a limited number of operations
– Simulation: Test alternatives in a computer representation of the system
– Machine learning: Configure a mathematical model to find a solution based on previous known results
• Analytical Techniques Analytical techniques provide a one-step method to find the solution. They can be further
classified into:
– Optimal: One step method to determine the optimal solution
– Sub-Optimal: One step method to find sub-optimal solutions
Depending on the complexity of the problem, or the type of model, there will be different techniques available. If there
are no techniques that can be applied, then the problem is not workable and we need to find an alternative model. In other
words, workability is a property of our model that determines whether it is possible to solve the problem with available
techniques or not.
Finally, through a technique, we are able to obtain a solution that represents the best alternative of the decision problem.
But, before we are able to implement this decision into the real world, it is important to validate that the model exhibits
some fundamental properties:
• Consistency: verify that the model is valid when parameters are changed to the extreme
• Sensitivity Analysis: How is the response affected by changes in the parameters?
• Plausibility: Is the model consistent with available data?
If we are satisfied with the answer to these questions, we are ready to implement the best alternative in the real world and
monitor the results. This implementation can be automatic (taken by an autonomous system) or supervised (with human
supervision).
Jupyter Notebooks are great to share software and scientific results. In my opinion, the main advantages are:
1. Explainability: Jupyter Notebooks combine software code together with rich multimedia descriptions. This allows
researchers to explain their results, show exactly the code the have used, describe its fundamentals and its results.
This narrative format helps the reader understand and in extension reuse scientific results.
2. Composability: You can easily combine different Jupyter Notebooks into larger project.
3. Community Support: There is a very large user community worldwide supporting Jupyter Notebooks.
Also, there are a growing number of platforms and tools that support it off-the-shelf. Some examples that we will use
during the course are: Anaconda, Google Colabs, JupyterLab, or Pycharm.
From a very basic point of view, a Jupyter Notebook is a file that contains a sequence of cells. There are primarily two
types of cells:
• Code Cells: Code cells contain code in a given programming language (for instance Python) that will be executed
by an interpreter when we execute the Notebook. Code cells have an output section where we can see the result
of the code cell. From this, there are two ways we can use a Notebook. We can view a Notebook using a viewer,
which allows us to render the Notebook, but not to run the code cells. If we have an Interpreter at hand, we can
also run the Notebook to let the interpreter run the code and update the results of code cells.
• Markdown Cells: Markdown cells use Markdown Syntax to explain code cells using a rich language that allows
us to include links, equations, images, any kind of resource we can think of to support our presentation.
Try me
Python is a high level programming language that is particularly suited for data science and operations research. Python
has three main versions labelled 1, 2, and 3. Within each version, there are several minor releases, like 2.2 and 3.3.
Therefore, there are many Python versions labelled 1.x, 2.x, 3.x, where the x is the minor version number. This course
covers 3.x, but it is not difficult to change from one version to another. This notebook provides a quick introduction to
Python in Notebooks. If you are not familiar with this environment, check the partner book on computer programming
in this link
Let us start easy with our first code block. In this cell, we will assign variables and use a function. We will use the
Python function print() that prints a message in the output of the code cell. The message is passed as a string variable.
Let us introduce briefly these two concepts in the context of Jupyter Notebooks.
Basic variables
Variables allow us to store a value and use it in our Notebook through a name. To assign value to a variable, we first type
the name, then the equal sign (=) and then the value:
[1]: x=1
y=0.4
msg= Hello world
There are different types of variables. In the example above, x and y are two numeric variables. We will talk about
numeric variables later in this Notebook. The variable msg is a string variable (text). You can either use quotes or double
quotes to assign a string variable.
Basic functions
In Python, a function takes variables as arguments and return a value. The standard Python library provides many con-
venient functions. Let us start with a simple example.
The first line in the example above is a comment. Comments help us humans read the code and start with a ‘#’. Therefore,
the code cell above has only one comment and two lines of code. The first line of code calls the function print with the
string variable msg. Note that we can use variables in separate code cells of a Notebook. Note also that variables are
declared when we Run a code cell. Cells should be run in the order they are presented in a Notebook. The second line
of code takes a string value as argument, because we do not want to store this value to use it later. You can play around
with the print function to print a different message or several messages, just give it a try! Do not be afraid to change the
values of variables. Variables are mutable, meaning that you can change the value of a variable in your code. But before
you do, note that Python documentation normally includes references to the group comedy Monty Python and the words
“spam” and “eggs” are normally used as fill-in variables. The example below reassigns the value of the variable msg to
print the word “spam”. You can try to add a new line of code to print “spam” and “and eggs!” in two separate lines of the
output in the next cell code.
[3]: msg="spam"
print(msg) #Tip: I can also add a comment to a line of code
# Add a new line to print "spam" and "and eggs!" to the output of this code cell
spam
Numeric Variables
In Python, you can declare variables and do simple operations with them. We are going to do mathematical operations
with variables, so you need to get familiar with the operands and the results, depending on the type of arguments used.
Let us start with numerical variables. Python uses standard variable notations, so the operands +, -, *, / and ** represent
sum, rest, multiply, divide and power operations. You can also use parenthesis to control the order of operations and
declare negative or decimal variables using the - sign or a . (eg -4 or -4.5). In the following block of code you can find
some examples.
[29]: x = 2 #x is a numeric variable, equal to 2.
y = x+4 #y is a numeric variable, equal to x+4 = 6.
z = (x+3)*(y**2)/4 #z is a numeric variable equal to (2+3)*(6**2)/4 = 5
print(x)
print(y)
print(z)
2
6
45.0
Notice that z is different from x and y. While x and y are integers, z is a floating variable. One of the main characteristics of
Python is that it is a weakly typed programming language. Roughly, this means that you can do operations with variables
of different types and Python will make the operation to its best effort to avoid a compilation error. That is why Python
generated a floating variable from the division operation. Also, as in math, the order of the operands is important, and we
can use parenthesis to control it.
Errors
We cannot use any combination of variables. For instance, adding a numeric variable to a string could result in a compi-
lation error. Another important piece of information is that in Jupyter, you can use variables declared in different code
cells as long as you run them first. If you have run the previous cell, you can test the following cell.
[7]: ms = x is + x
print(ms)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-3ada229f534a> in <module>()
----> 1 ms = x is + x
2 print(ms)
Notice that the output of the cell now shows an error message. Do not panic. The message gives you information to
interpret and correct the error. While you program, specially when you are a beginner, it is normal to get errors and very
important to get familiar with the error messages. In this message, Python warns you of a TypeError and the reason why
(you cannot concatenate an int to a string). There are other things that you are not allowed. For instance, you cannot
divide by zero. The only person that can divide by zero is Chuck Norris. If you are not Chuck Norris, you will get a
different error if you try the following cell:
[8]: z = y/0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-8-d81c8fc02de0> in <module>()
----> 1 z = y/0
In this case, the error message is different. In both cases, you get enough context information to identify the line of code
that gave error and the reason why that line resulted in an error. ## Printing results to output Now some tips, if you want
to print a msg with values, you can pass more variables to the print function as comma separated values. As we saw in the
previous example, the print function can also take numeric values, so this is a way to get the expected result. We could
also use the function str to convert a number to a string and use the + operator to concatenate the strings on a message.
We can also use the format function to a string with two parameters to tell the function print how do you want to see them:
[14]: print( x is , x , , y is , y, , z is , z)
print( x is + str(x) + , y is + str(y) + , z is + str(z))
print( x is {x:d}, y is {y:d} and z is {z:.1f} .format(x=x,y=y,z=z))
x is 2 , y is 6 , z is 5.0
x is 2, y is 6, z is 5.0
x is 2, y is 6 and z is 5.0
In Python, there are many ways to achieve the same result, so it is very important to read the docs and experiment to
understand the different trade-offs!.
Lists
We will work quite a lot with lists in this course. Lists are used to store an indexed list of objects. To assign a list variable,
we use brackets, surrounding the values of the objects we want to store. Indexed means that we can get the value of a
specific item in the list using its position in the list. The index is specified again using brackets. Let us see a basic example:
Boolean variables
Another important type in Python is the Boolean type. Boolean variables can take two values, False or True.
[8]: b = True
Boolean logic
Normally, in Python we used logical operands to do operations with boolean variables and build logic into our code. Basic
boolean operators are logic and (and), logic or (or) and negate (not):
[15]: c = not b
print(c)
print(c & b)
print(c and b)
print(c | b)
print(c or b)
False
False
False
True
True
Comparisons are also important operators that return boolean values. Comparators are less (<), less or equal (<=), exactly
equal (==), greater or equal (>=), and greater (>). Normally, they take numerical values:
[21]: x = 5
y = 6
z = 6
print(x < y)
print(y <= z)
print(y == z)
print(y >= z)
print(y > x)
True
True
True
True
True
The in operator is important in the context of lists. It allows us to check if any element of a list contains a specific value.
It can be combined with the not operator if we want the opposite logic.
Control Structures
Control structures allow us to implement complex logic into our programs, creating different execution pathways or
repeating code blocks to make our code more efficient. The next subsections describe basic selection structures (if
else clauses) and repetition structures (for loops) in Python.
If clauses allow us to execute some code if a condition is true. This is the notation of the if clause:
if expression:
sentence(s)
The sentences inside the if clause are only executed if the expression is true. On the other hand, else clauses execute
sentences if the previous clause does not terminate normally. In general, we will use else clauses after if clauses to execute
other clauses when the expression is not true. Therefore, an if clause combined with an else clause looks something like
this:
if expression:
sentence(s)
else:
other_sentence(s)
[20]: if b:
print("b is:")
print(c)
else:
print("False!")
Note that there is an indent (a space from the left margin) in the sentences inside the if and else clauses. This is very
important because it is the way we have to tell Python which lines of codes are inside a clause and which are not.
For loops
For loops iterate over iterable variables like lists (we will see other iterable types later in the course). For loops allow us
to declare a variable and use it inside it to control the sentences it contains. For loops are primarily used to write very
efficient code with few lines. The structure of a for loop is
The for loop declares a (var) variable that can only be used inside the sentences it contains. It will run the sentence(s) it
contains as many times as elements are contained in the (vars) list used in the clause.
Take as example the code we used when we defined lists. We could rewrite it as:
Hello!
spam
eggs
List comprehension
One of the main features of Python lists we will use in the course is list comprehension. List comprehension allows us to
assign list variables very efficiently using for loops inside a bracket. Let us see how it works by example:
Libraries
In Python, we can import libraries using the keyword import. Libraries encapsulate functions and declare variables that
provide additional functionalities and type declarations to provide a specific functionality. In next tutorials, we are going
to introduce two libraries, numpy and matplotlib, but before that, you need to know how to import a library. Imports
work like this:
in the code snippet above, we use the keyword import to ask python to import the library and use the alias lib. Later on our
code, we will be able to use the functions in the library using the alias. Python and Conda allow you to import many useful
libraries through import commands, but not every available library. For some libraries, first we will need to install the
library in our environment, normally using Conda (but we could also use other tools like pip). This is however everything
you need to know for now. You can now check the following tutorials to learn more about numpy and matplotlib.
Try me
The Numpy (Numerical Python) is a package of numerical functions to effectively work with multidimensional data
structures in Python. In Python, it is possible to work with nested lists to work with multidimensional structures (arrays
and matrix), but this is not efficient. The Numpy library defines the numpy array object to provide an efficient and
convenient object to define multidimensional structures.
To use Numpy in your Notebooks and programs, you first need to import the package (in this example we use the alias
np):
The numpy array uses a similar structure to a Python list, although as mentioned above, it provides additional functional-
ities to easily create and manipulate multidimensional data structures. The data in an array are called elements, and they
are accessed using brackets, just as with Python lists. The dimensions of a numpy array are called axes. The elements
within an axe are separated using commas and surrounded by brackets. Axes are also separated by brackets, so that a
numpy array is represented as an nested python list. The rank is the number of axis of an array. The shape is a list
representing the number of elements in each axis. The elements of a numpy array can be of any numerical type.
print("Number of dimensions:")
print([Link]) #number of dimensions or rank
print("Shape of array:")
print([Link]) #shape (eg n rows, m columns)
Numpy includes several functions for creating numpy arrays initialized with convenient ranks, shapes, or elements with
constant or random values.
Some examples:
[[1. 1.]
[1. 1.]
[1. 1.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[0.71574091 0.54968971 0.72723399]
[[12 12]
[12 12]]
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
Creating sequences
Some useful functions for creating lists are arange and linspace:
• arange(start, end, step): creates a numpy array with elements ranging from start to end incrementing by step.
Only end is required, using only end will create an evenly spaced range from 0 to end.
• linspace(start,end,numvalues): creates a numpy array with numvalues elements with evenly distributed values
ranging from start to end. The increment is calculated by the function so that the resulting number of elements
matches the numvalues input parameter.
[10]: a = [Link](0, 10, 2)
print(a)
b=[Link](0,10,6)
print(b)
[0 2 4 6 8]
[ 0. 2. 4. 6. 8. 10.]
Arithmetic operations
You can apply element-wise arithmetic and logical calculations to numpy arrays using arithmetic or logical operators.
The functions [Link](), [Link](), or [Link]() are other examples of functions that operate in the elements of a numpy
array. You can check the entire list of available functions in the official Numpy documentation. Some examples:
[11]: x =[Link]([[1,2,3,4],[5,6,7,8]])
y =[Link]([[9,10,11,12],[13,14,15,16]])
print(x+y)
print(y-x)
print([Link](y))
print([Link](x))
print(x**2)
print(x+5)
[[10 12 14 16]
[18 20 22 24]]
[[8 8 8 8]
[8 8 8 8]]
[[3. 3.16227766 3.31662479 3.46410162]
(continues on next page)
Note that in the last examples, we are adding a scalar value to a numpy array. In general, we can apply arithmetic
operations on array of different dimensions, given that the smallest dimension between the operands is one, or that the
arrays have the same dimensions. When this condition is met, numpy will expand the smaller array to match the shape of
the larger array with an operation called broadcasting.
Array functions
[13]: x =[Link]([[1,2,3,4],[5,6,7,8]])
y =[Link]([[9,10,11,12],[13,14,15,16]])
Other functions take two arrays as arguments and perform element wise operations:
• minimum(): Returns an array with the minimum value in each position of the array
• maximum(): Returns an array with the maximum value in each position of the array
[14]: b=[Link](0,1,10)
r = c=[Link](10)
print([Link](b,r))
[0. 0.11111111 0.22222222 0.0069694 0.44444444 0.3403326
0.19167794 0.71257103 0.78045669 0.64287305]
[ ]:
Try me
The Matplotlib (Mathematical plotting Library) is a Python charting package that allows us to render rich interactive
graphics from Python data structures, including Numpy arrays.
To use Matplotlib in your Notebooks and programs, you first need to import the Pyplot package (in this example we use
the alias plt):
Matplotlib modes
We can use two different modes in Notebooks: - Notebook: This will create interactive graphics where you can zoom-in
and move around the graph as well as export. You can use this mode for experiments, to interact with data directly in the
book, but it is not recommended to use it for presentation.
• Inline: This will create a static graphic with the selected properties. We will work with this mode in this course
[2]: #We set the mode inline of matplotlib to get the result at the output of the cell code
%matplotlib inline
Main Concepts
In this course we will work mainly with bidirectional charts, therefore we will create figures with one axe (or plot) and
two axis. There is a convenient Matplotlib function for this exact purpose:
• plot([x],y,[fmt],[kwargs]): This function takes an optional parameter x, a parameter y and optional parameters to
format the line and pass additional formatting parameters to matplotlib.
For instance,
plot(y)
plot(x,y)
plot(x,y, o-- )
will plot y versus x using a dotted line and circular markers and create a label for y with the text “random data”. Note that
for the label parameter we can use expressions, for instance to write equations. For instance, using:
`python label= $x_{1}=f(y,\phi)$
will create a label displayed as 𝑥1 = 𝑓 (𝑦, 𝜑)
Note that the plot function will not render the title or the legend of the plot. We need to use the functions:
• legend([kwargs]): will render the legend, we can provide optional parameters to format the legend.
• title(label): will render the title with the text provided in the label parameter.
There are other signatures and many formatting parameters defined in the matplotlib library, but this is outside the scope
of this tutorial. Check the documentation whenever you want to try to apply a different style.
[3]: import numpy as np
y = 200 + [Link](100)
x = [Link]([Link])
The plot function allows us to effectively chart different lines into the same plot, just adding as many calls to the function
as we want in the same code cell. For instance, in the example below we add two lines by calling twice the plot function
with different data.
[35]: import numpy as np
y = 200 + [Link](100)
y2 = 100 + [Link](100)
x = [Link]([Link])
There are many different ways to format the axis. We will use the following convenient functions:
[Link]((0, 20))
[Link]((0, 15))
[Link](r $x_{1}$ )
[Link](r $x_{2}$ )
• xlim((left, right)): sets the limits of the x axis to the values provided. The limits are provided as a tuple of integer
values, first the limit to the left of the plot (lower value) and then the limit to the right (higher value).
• ylim((bottom, top)): sets the limits of the y axis to the values provided. The limits are provided as a tuple of
integer values, first the limit to the bottom (lower value) and then the limit to the top (higher value).
• xlabel(label): sets the label for the x axis, using the text provided in the label parameter. We can provide expressions
for instance to use equations in the labels (see example below).
• ylabel(label): sets the label for the y axis, using the same parameter as the xlabel function describe above.
# sets limits
[Link]((0,100))
[Link](r $x$ )
(continues on next page)
[Link]((0,310))
[Link](r $y=200 + 50·rand()$ )
Filling areas
The function fill_between allows us to fill the area between any two lines:
fill_between(x, y, y2=0, where=None, kwargs): Fills the area between lines y (upper limit of the area) and y2 (bottom
limit of the area), both versus x. Also, both y and y2 can either be a line or a numerical value. If a scalar value is used,
a horizontal line crossing the y axis at the numerical value provided is used as the bottom limit of the area. The optional
where parameter is used to provide an expression in x to limit the area in the horizontal axis. Additional parameters are
used to format the area. For instance, in the example below, we set up the color of the area and its transparency.
x = [Link]([Link])
y_const = 50 + 0*x
[Link](x,y_rand,label= random data )
[Link](x,y_const, label= a straight line )
#Add legend
[Link]()
[Link]( Random data )
# sets limits
[Link]((0,100))
[Link](r $x$ )
[Link]((0,310))
[Link](r $y=200 + 50·rand()$ )
plt.fill_between(x, y_rand, y2=y_const, where=x<60, color= green , alpha=0.5)
# since y2 is a constant, the line above is equivalent to
#plt.fill_between(x, y_rand, 50, where=x<60, color= green , alpha=0.5)
Note that in the last example, we are drawing the area between a line and a horizontal line and therefore we could just
use y2=50 in the fill_between function call.
x = [Link]([Link])
[Link](x,y_rand,label= random data )
#Add legend
[Link]()
[Link]( Random data )
# sets limits
[Link]((0,100))
[Link](r $x$ )
[Link]((0,310))
[Link](r $y=200 + 50·rand()$ )
plt.fill_between(x, y_rand, 0, where=x<=60, color= green , alpha=0.5)
# since y2 is a constant, the line above is equivalent to
#plt.fill_between(x, y_rand, 50, where=x<60, color= green , alpha=0.5)
As an extra (not needed to complete assigments, but used in the slides), we can annotate a point of the graph with the
function annotate: - **annotate(s, xy, *args, kwargs): Annotates the point xy with the string s
See the example below:
x = [Link]([Link])
#Annotate minimum
[Link]( Min Value ,(xmin[0],ymin))
#Annotate maximum
[Link]( Max value , (xmax[0], ymax))
#Add legend
[Link]()
[Link]( Random data )
# sets limits
[Link]((0,100))
[Link](r $x$ )
[ ]:
Try me
Text can be added to IPython Notebooks using Markdown cells. Markdown is a popular markup language. In this
context, markup refers to the information used to control how the document must be presented, rather than the content
of the document itself. Markdown is therefore a descriptive language in the sense that we use the markup specification
to control how text is presented and do not worry how the web browser actually renders it. Markdown is a superset of
the HyperText Markup Language HTML which is used to build web pages, and in that sense, you will find that you can
create the same type of documents you find over the Internet using Markdown. The specification can be found here:
[Link]
☝ Since you can view the source of a cell just by double-clicking on it, this guide is basically build using
examples, and you can check the code just by clicking on the cell or while the cell is selected in command
mode, press Enter to edit it. Once a cell has been edited, use Shift-Enter to re-render it.
Markdown basics
Code blocks
You can enter block codes in Markdown cells surrounding the text you want to display as code using triple quotes (````)
and adding the language name. For instance, the following code block will display some python code styled using Python
language syntax:
# This is a comment
print("Hello, world!")
Note that you cannot execute the code in a markdown cell, but still, you can render the code in the web-browser. This is
convenient to write documentation for your code embedded in the Markdown cell, or to explain bits of code written in a
programming language not supported by the Notebook Kernel (e.g. SQL).
☝ In this Notebook, we will use code blocks with the Markdown language name so that we can render
Markdown syntax in the web-browser. Keep this in mind when you check the source code of the Markdown
cells below!
You can make text italic or bold, surrounding the text with either ‘*’ or double ‘**’. For instance, the code:
*italics*
will write down the word ‘italics’ in italics, and the code:
**bold text**
Headings
You can use the # character to create a heading. For instance, the code:
# This is a heading
Creates a heading with the text ‘This is a heading’. Headings are organized in levels, with level 1 being the largest and
level 6 the smallest. Therefore, the code:
Lists
You can build itemized lists using the - character, and nested sub-lists using the tabulator or insert some spaces before
the - character. For instance, the code:
1. Here we go
1. Sublist item 1
2. Sublist item 2
2. Here we go again
1. Sublist item 1
2. Sublist item 2
Will create this sublist: 1. Here we go 1. Sublist item 1 2. Sublist item 2 2. Here we go again 1. Sublist item 1 2. Sublist
item 2
While we covered the basics on the section above, this section includes some syntax tips that you can use to enhance the
presentation of your document.
Horizontal rules
Horizontal rules introduce a horizontal separator in your document, for instance: For instance, the code:
---
Block quotes
Block quotes are handy to highlight some text. For instance, the code:
Inline links
You can create links to other pages or to external resources using the following syntax:
Inline images
You can insert images in your Markdown document using the following syntax:
Note that syntax includes an alternative text for the image, which is used when the image is not displayed (for instance
when the content is transcribed by a screen reader). It is important to include a rich description of your image in the
alternative text, so that it can be used by screen readers.
You can also insert images with links. For instance, the code:
Note that basically, the only differences between previous examples is that we wrapped the image in the link description!
LaTeX equations
You can include mathematical expressions using LaTex notation wrapped using the dollar symbol as a delimiter. You can
insert equations inline (in the same line) as text like:
$$e^x=\sum_{i=0}^\infty \frac{1}{i!}x^i$$
You can find a comprehensive cheat sheet for LaTeX equations here. You can also use Overleaf to find tutorials and edit
equations online. However, we hope this table contains the most common LaTeX commands and symbols.
You can just use brackets to insert vectors in LaTex, which is quite convenient. For instance, the code:
x = [1, 2, 3]
\begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9
\end{bmatrix}
Tables
| This | is |
|------|------|
| a | table|
This is
a table
The table cells are delimited by the (|) character. The first row and first column are used to determine the width of the
table, so it is important to insert spaces if you want to control the table width and text alignment across the table. Also,
note that the first row is used as headers, and that there is a separator between the header and the table body.
Note that the text in the table is automatically aligned to the left. You can control the alignment of the text using colons
(:) after the column delimiter. For instance, the code:
markdown
| Right aligned |centered aligned |
|----------------------------------:|:------------------------:|
| This is a right aligned column | and this one is centered |
see:
Local files
If you have local files in your Notebook directory, you can refer to these files in Markdown cells directly:
[subdirectory/]<filename>
For example, you can use this feature to include images that are not publicly available on the internet, but in your local
directory. Say you have an image named my_image.png in a folder named images your notebook directory. You
can then use the following code to include this image in your Markdown document:

You can also embed a video and video controls with the HTML5 video tag:
Note that, since videos are not natively supported in Markdown, we are using HTML5 notation, since Markdown also
supports native HTML.
Note that this means that the Notebook server also acts as a generic file server, and that all the files inside the same folder
as your Notebook are available through the Notebook server. Although we will be mostly using sandbox environments like
Google Colabs or Binder, bear this in mind if you ever use Notebook server in your system and do not run the Notebook
server in a high level directory of your file system, like your home directory).
Extra tips
Youtube videos
You can embed YouTube videos using the share feature of YouTube. In the video you want to share in YouTube, just
click on share and select the embed option:
As mentioned above, since you can embed HTML notation in the notebook, you can just copy it and paste it in your
notebook like this:
˓→iframe>
These do not embed the data into the notebook file, and require that the files exist when you are viewing the notebook.
Some Notebook clients do support ASCII symbols, which are symbols that are encoded (converted into bits) and included
into the set of characters (ASCII) just as letters. For example, the symbol for the heart is the letter ♥, or a pizza slide is
the letter 🍕. You can just copy this special symbols and paste them in your Notebook to use them as icons.
Try me
Introduction
In previous tutorials, we covered few tips to work with lists and Numpy Arrays in Python. This tutorial presents two
python types that will be used in the following tutorials, tuples and dictionaries.
Tuples
Tuples are very similar to lists, except that they are immutable. This means that, once you declare a tuple variable, you
cannot make any changes to it (unless you are Chuck Norris). Tuples are created using parenthesis instead of brackets,
like in the example below:
Since they are immutable, we can use tuples to store values that cannot change in our program. Tuples are iterable. We
can access the values of a tuple using indexes and use them in control functions like for loops.
Dictionaries
Dictionaries allow us to map keys to values. Note that both tuples and lists are ordered and that we can access the values
of the elements using indexes. In dictionaries, we map a value to a key, so that we can use the key to access the value of
an element, instead of its index. The syntax of dictionaries is:
Then, we can access the values in the dictionary using the keys. For instance:
You can access dictionary keys with the method keys(). This is useful to iterate on the keys of a dictionary:
Dictionaries also support comprehension. As with list comprehension, dictionary comprehension allows us to assign keys
and values very efficiently using for loops. Let us see how it works by example:
[37]: keys = ( a , b , c , d )
values = (1, 2, 3, 4)
Try me
Pandas is a powerful library that provides convenient data structures and functions to work with data. Throughout the
course, we will use Pandas for data manipulation and analysis. To use Pandas in your project, you first need to install
it in your environment. Additionally, in this tutorial we will import the display and Markdown libraries to display the
dataframes as tables.
This introduction covers the fundamentals of Pandas data structures used in this course. It is however recommended that
you also take a look to the official documentation.
There are primarily two types of Pandas data structures:
• Dataframes: Dataframes are two-dimensional data structures, similar to a two-dimensional numpy array, a spread-
sheet or an SQL table.
• Series: Series are one-dimensional data structures, similar to one-dimensional numpy arrays
Dataframes
Data frames facilitates the manipulation and analysis of two-dimensional data structures, combining convenient functions
to:
• Extract data from different sources, like CSV files, Excel sheets, or SQL databases
• Transform data, applying functions to change the values, or combining different data sources to prepare the data
for our application
• Load data into output CSV files, Excel sheets or SQL databases
• Analyse Analyse the data
Pandas columns in a dataframe are not necessarily of the same type. In the course, we will primarily work with numeric
types, string types and the datetime type, so we will focus on those two types in this tutorial. We will also store complex
objects, and find convenient Pandas functions to manipulate the dataframe using them, so you can see that Pandas is going
to be very useful throughout the course!
You can create a dataframe from different structures: DataFrame accepts many kinds. Among others, in this course, we
will primarily use:
• A dictionary of one dimensional numpy arrays, lists, dicts, or Series
• CSV, or Excel files
• Another Pandas dataframe
• A Pandas series
Let us start with a simple example, using a dictionary.
display(dataframe)
one two three date
0 1 5 Awesome 2021-01-01
1 2 4 Brutal 2021-01-02
2 3 3 Cool 2021-01-02
3 4 2 Divine 2021-02-03
4 5 1 Exquisite 2021-02-05
Our Pandas dataframe, Pandas, has three columns, with names, ‘one’, ‘two’, and ‘three’. Notice the integer number in the
column to the left. This is the index, and by default, the index has no name.
Another convenient way to create a dataframe is to use a set of records in an array:
This line of code will create a dataset from the file ‘datasets/Online Retail_2.csv’, loading only data from the columns
labeled as ‘InvoiceNo’, ‘StockCode’, ‘Quantity’, and ‘InvoiceDate’.
Accessing data
There are multiple ways to access the data in a dataframe. Dataframe columns are series, the other important data
structure in Pandas. You can access columns in a dataframe using column names as keys:
Notice that series are also indexed, you can access elements or slices just as in numpy:
[5]: print(names[0])
print(names[1])
print(names[0:2])
Awesome
Brutal
0 Awesome
1 Brutal
Name: three, dtype: object
Obviously, you can access the elements directly from the data frame:
Queries
You can use queries to access parts of your dataframe, that is, to filter the data, using python expressions. The function
query() is used to issue the query. For instance, the following query finds all rows where the column ‘one’ is less or equal
than two:
[7]: filtered_df = [Link]( one <= 2 )
display(filtered_df)
one two three date
0 1 5 Awesome 2021-01-01
1 2 4 Brutal 2021-01-02
You can combine different columns in the expressions, for instance, the following example filters data where the column
‘two’ is greater than 3 and the column ‘three’ is equal to “Awesome”. The second example shows values where the column
‘one’ is equal to the column ‘two’
[8]: filtered_df2 = [Link]( two > 3 and three == "Awesome" )
display(filtered_df2)
filtered_df3 = [Link]( one == two )
display(filtered_df3)
one two three date
0 1 5 Awesome 2021-01-01
one two three date
2 3 3 Cool 2021-01-02
Vectorized functions
Pandas series have a huge set of vectorized functions you can apply to the entire series. For instance, the different functions
in the numpy tutorial:
[9]: display(dataframe[ two ].sum())
display(dataframe[ one ].cumsum())
display(dataframe[ two ].mean())
15
0 1
1 3
2 6
3 10
4 15
Name: one, dtype: int64
3.0
One interesting function is describe(), which returns another dataframe with statistical information about the series
or dataframe:
[10]: [Link]()
str provides vectorized access to the string value of the series, and thus you can access parts of every string in a series
using indexes:
[12]: first_character = dataframe[ three ].str[0]
display(first_character)
0 A
1 B
2 C
3 D
4 E
Name: three, dtype: object
Similar to str, dt implements vectorized functions to work with [Link] following examples first transforms column
“date” into a datetime, and then calculates the month.
[13]: month = pd.to_datetime(dataframe[ date ]).dt.to_period("M")
display(month)
0 2021-01
1 2021-01
2 2021-01
3 2021-02
4 2021-02
Name: date, dtype: period[M]
The function pd.to_datetime converts the series in column ‘date’ into a datetime. Then, dt.to_period() transforms this
column into a period, in this case, the letter “M” represents months, and therefore, the period obtained is months.
Finally, apply allows us to apply and lambda function taking all the values of the dataframe or just a series:
[14]: plus_one = dataframe[ one ].apply(lambda x: x +1)
display(plus_one)
0 2
1 3
2 4
3 5
(continues on next page)
In the code above, we apply a newly created lambda function that takes one parameter x and just adds one. apply() will
apply this function to the series in column ‘one’. There is a huge set of functions available, and many things you can do
which are not covered in this tutorial, so you better check the documentation at Pandas Series API Reference
Indexing
By default, the dataframes we have created have an integer index to access data in a raw, but we can define any type of
index. Let us create another dataframe with another type of index:
display(dataframe_3)
client_id postal_code
2021-01-01 003 46021
2021-01-02 005 46022
2021-01-03 007 46022
2021-02-04 003 46021
2021-02-05 003 46027
We have used two new parameters to create our dataframe from a dictionary (from_dict), orient, and columns. When
orient is index, the dictionary keys are used as the index of the created dataframe. In this case, we are using a string. The
columns parameters allow us to give a name to the columns of our dataframe. Now, we can access the data using the new
index:
We can also set the index of an existing dataframe using its columns. Let us change the index of our first dataframe:
Notice, that since our column had a name, now our index also has a name. We can set the name of an index like:
We can use different columns as index to create a dataframe similar to a pivot table:
New columns
To add a new column, you just need to define the column name. For instance, let us to the original dataframe a new
column containing the month:
Grouping
Grouping allows us to group by values that have the same index value:
one two
month
1 6 12
2 9 3
Note that, first, we define the index month, and then we group by this index. Finally, we apply the vectorized function
sum to sum all values of the columns with the same value of the index month. Column three silently disappears since its
type does not support this function.
Joining
Indexes allow us to join different dataframes that have an index with the same name:
TWO
In this chapter, we will cover both theoretical and practical topics related to Continuous Linear Programming (CLP) using
Python. CLP allows us to model, solve and analyse the solution of optimization problems using linear equations. “The
world is not linear” but still, CLP is a really powerful tool to solve a pletora of real world optimisation problems.
2.1 Tutorials
Definition
Continuous Linear Programming (CLP) spans a wide set of OR problems that can be modeled based on the following
assumptions:
• Unknown variables are continuous: The result variable and the decision variables can take any real value. Also, all
the different coefficients can take any real value.
• Objectives and constraints are linear expressions: The relationships between the variables are expressed as linear
expressions.
Clearly, CLP establishes a rather simplified model of real world problems. Many assumptions are needed to represent
real problems as a set of linear expressions. Yet, CLP is a very powerful tool in OR and it can provide valuable insights
to decision-making in different fields. The main reason is that, once these assumptions are taken, linear algebra provides
valuable tools to find an optimal solution and analyse it.
The main types of problems that will be covered in the CLP exercises belong to two problem types:
• Production mix: Production mix problems help us determine the optimal allocation of resources in the production
of good or services to either minimise costs or maximise profits
• Blending problems: In blending problems, the objective is to find the optimal combination of components in a set
of products that either minimise costs or maximise profits
43
Notebooks for Operations Research, Release I
Set up
In CLP, the objective variable, noted as 𝑧, can take any real value:
𝑧∈R
The value of this unknown variable 𝑧 is a function of another set of unknowns, which are called decision variables and
that represent our decisions. These decision variables are noted as 𝑥𝑗 , where 𝑗 is an integer (sub)index that goes from 1
to 𝑛:
𝑧 = f(𝑥1 , 𝑥2 , ..., 𝑥𝑛 )
𝑥1 , 𝑥2 , ..., 𝑥𝑛 ∈ R
Therefore, we will have 𝑛 different decision variables, that are going to be continuous. And, in extension, z is also going
to be continuous. So now we know from where does the C in CLP comes from. Next, in CLP, the function f is a linear
function. What we want is to find the optimal value of 𝑧, which, depending on the type of problem will be either the
maximum value (e.g. maximise profits) or the minimum value (e.g. minimise costs).
Hence, we want to maximise or minimise 𝑧, which as we said is a linear function and therefore can be expressed as the
sum of the product of the decision variables multiplied by a set of coefficients, which are noted as 𝑐1 to 𝑐𝑛 .
max 𝑜𝑟 min 𝑧 = f(𝑥1 , 𝑥2 , ..., 𝑥𝑛 ) = 𝑐1 ·𝑥1 + 𝑐2 ·𝑥2 + ... + 𝑐𝑛 ·𝑥𝑛
Now, we know that linear functions do not have any absolute minimum or maximum, but the objective function is subject
to a set of constraints, which are also linear functions of the decision variables, that is, the sum product of the decision
variables times a set of coefficients noted as 𝑎𝑖𝑗 must be less than, greater than, or equal to another coefficient noted as
𝑏𝑗 .
𝑠.𝑡.
𝑎11 ·𝑥1 + 𝑎12 ·𝑥2 + ... + 𝑎1𝑛 ·𝑥𝑛 ≤ 𝑏1
𝑎21 ·𝑥1 + 𝑎22 ·𝑥2 + ... + 𝑎2𝑛 ·𝑥𝑛 ≤ 𝑏2
...
𝑎𝑚1 ·𝑥1 + 𝑎𝑚2 ·𝑥2 + ... + 𝑎𝑚𝑛 ·𝑥𝑛 ≤ 𝑏𝑚
Note that coefficients 𝑎 have two sub-indexes, the second is equal to the index of the corresponding decision variable, and
the first is equal to the sub-index of b. These new index 𝑖 ranges from 1 to 𝑚 and therefore, our optimisation function
is subject to a set of 𝑚 constraints. We will refer to the expressions to the left of the inequality as the Left Hand Side
(LHS), and to the other side of the relationship as the Right Hand Side (RHS).
Now, note that we can use the sum operator to represent the objective function in a more compressed form, that is, the
LHS is equal to the sum of the product of cj times xj for j equal to 1 up to n. Note that this is can also be represented as
the dot product of two vectors, the vector 𝑥 with the decision variables and the vector 𝑐 of the coefficients.
∑︀𝑛
max 𝑜𝑟 min 𝑧 = 𝑐1 ·𝑥1 + 𝑐2 ·𝑥2 + ... + 𝑐𝑛 ·𝑥𝑛 = 𝑗=1 𝑐𝑗 ·𝑥𝑗 = 𝑐·𝑥
𝑥 = [𝑥1 , 𝑥2 , ..., 𝑥𝑛 ]𝑇
𝑐 = [𝑐1 , 𝑐2 , ..., 𝑐𝑛 ]𝑇
We can do the same transformations to the left hand sides of the constraints, expressing them as the sum product of
the decision variables times the left hand side coefficients. And, we may as well express all the left hand sides of the
constraints as the product of a matrix A that contains all the different coefficients times the decision variable vector.
∑︀𝑛
max 𝑜𝑟 min 𝑧 = 𝑗=1 𝑐𝑗 ·𝑥𝑗
s.t.
∑︀𝑛
𝑗=1 𝑎1𝑗 ·𝑥𝑗 ≤ 𝑏1
∑︀𝑛
𝑗=1 𝑎2𝑗 ·𝑥𝑗 ≤ 𝑏2
...
∑︀𝑛
𝑗=1 𝑎𝑚𝑗 ·𝑥𝑗 ≤ 𝑏𝑚
or
max 𝑜𝑟 min 𝑧 = 𝑐·𝑥
𝑠.𝑡.
𝐴·𝑥 ≤ 𝑏
⎡ ⎤
𝑎11 𝑎12 ... 𝑎1𝑛
⎢ 𝑎21 𝑎22 ... 𝑎2𝑛 ⎥
𝐴=⎣ ⎢ ⎥
... ⎦
𝑎𝑚1 𝑎𝑚2 ... 𝑎𝑚𝑛
𝑏 = [𝑏1 , 𝑏2 , ..., 𝑏𝑚 ]
These alternative compact forms allow us to deal with problems with an arbitrary number of decision variables and an
arbitrary number of constraints.
Problems
This section further explains the types of problems that can be solved with CLP.
In production mix problems, the decision maker needs to create products to satisfy demand using limited resources. The
objective is to maximise the profits, taking into account the demand and the limited availability of resources. Production
mix problems represent the simplest form of optimization problem in operations research, where the objective is to
maximise a utility function (in this case profits) bounded by a set of constraints. Normally, production mix problems are
not found in real world applications, but rather, they are part of larger problems.
Objective function
Let us note the objective variable profits as 𝑧, expressed in a monetary unit (e.g. €).
• 𝑧: profits in €.
The decision maker needs to decide how many units of each product type to manufacture. Let us assume there are 𝑛
different products. Now, let us note the decision variables 𝑥𝑗 ∈ R as the amount of product 𝑗 ∈ [1, ..., 𝑛] to be produced,
in a production unit:
• 𝑥𝑗 : Quantity of product 𝑗 to be produced in product units.
The objective is to maximize profits. Let us note the profit per unit of product 𝑗 as 𝑝𝑗 :
• 𝑝𝑗 : Profit per unit of product 𝑗 to be produced in €/unit.
Now, the objective function is to maximise the sum of the product of the number of units produced times the profit per
unit, for each product type:
∑︀𝑛
max 𝑧 = 𝑥1 * 𝑝1 + 𝑥2 * 𝑝2 + 𝑥3 * 𝑝3 + ... + 𝑥𝑛 * 𝑝𝑛 = 𝑗=1 𝑥𝑗 * 𝑝𝑗
2.1. Tutorials 45
Notebooks for Operations Research, Release I
Demand constraints
As mentioned above, there might be requirements on the demand. Let us note the demand of product j as 𝑑𝑗 . The demand
constraints will be of the type:
𝑥1 ≥ 𝑑1
𝑥2 ≥ 𝑑2
…
𝑥𝑛 ≥ 𝑑 𝑛
We can write the demand constraints in a compact form like:
𝑥𝑗 ≥ 𝑑 𝑗 ∀𝑗 ∈ [1, ..., 𝑛]
Availability constraints
Different limited resources are used to produce each product. Let us assume that we have 𝑚 different resources. Let us
note as 𝑏𝑖 as the quantity available of resource 𝑖 (𝑖 ∈ [1, ..., 𝑚]), expressed in a given unit:
• 𝑏𝑖 : Availability of resource 𝑖 in resource unit.
Further, to produce a unit of a product 𝑗 we will require a given amount of resource 𝑖. Let us note as 𝑎𝑖𝑗 the requirement
of resource 𝑖 to produce a unit of product 𝑗:
• 𝑎𝑖𝑗 : Requirement of resource 𝑖 to produce a unit of product 𝑗 in resource unit / product unit.
Then, for each resource 𝑖, we need to ensure that the total amount used is less or equal the total amount available. The
amount used to produce a specific number of products will be the number of units products (e.g. 𝑥𝑗 ) multiplied by the
amount required to produce one unit 𝑥𝑖𝑗 . If we sum across all products, we obtain the total amount used, which needs to
be lower than the availability. Let’s take the resource indexed 1 as an example:
𝑥1 * 𝑎11 + 𝑥2 * 𝑎12 + ... + 𝑥𝑛 * 𝑎1𝑛 ≤ 𝑏1
Note that we can write this down this constraint in a compact form like:
∑︀𝑛
𝑗=1 𝑥𝑗 * 𝑎1𝑗 ≤ 𝑏1
...
∑︀𝑛
𝑗=1 𝑥𝑗 * 𝑎1𝑗 ≤ 𝑏𝑚
Note that we can write all this m equations in a compact form like:
∑︀𝑛
𝑗=1 𝑥𝑗 * 𝑎𝑖𝑗 ≤ 𝑏𝑖 ∀𝑖 ∈ [1, ..., 𝑚]
That is, for every resource, we need to ensure that the sum of the quantities used to produce each type of product are less
or equal than the total amount available.
Summary
Putting it all together, the generic formulation of the production mix problem as a CLP is:
∑︀𝑛
max 𝑧 = 𝑗=1 𝑥𝑗 * 𝑝𝑗
s.t.
∑︀𝑛
𝑗=1 𝑥𝑗 * 𝑎𝑖𝑗 ≤ 𝑏𝑖 ∀𝑖 ∈ [1, ..., 𝑚]
𝑥𝑗 ≥ 𝑑 𝑗 ∀𝑗 ∈ [1, ..., 𝑛]
Examples
Blending Problems
In blending problems, the decision maker needs to find the optimal blending (mixing or combination) of materials or
resources to create products that satisfy a given demand. Each resource or material will have a different costs and
therefore, in its primary form, the objective is to minimise the overall costs of the materials needed to satisfy the demand.
Additionally, the required materials or resources needed may be subject to availability constraints (i.e. we cannot consider
that the amount of materials or resources available is unlimited).
Objective function
Let us assume that we have 𝑚 different materials or resources to be considered in the problem and 𝑛 different products.
Let us note as 𝑐𝑖 𝑖 ∈ [1, ..., 𝑚] the cost of product 𝑖. Let us also note 𝑥𝑖𝑗 the amount of resource or material 𝑖 used to
produce products 𝑗 𝑗 ∈ [1, ..., 𝑛].
Note that these variables 𝑥𝑖𝑗 represent our decision variables: We are looking for the optimal combination of resources
or materials to manufacture our products. Note also that we have 𝑚 * 𝑛 different decision variables (the combination of
products and materials).
With these definitions, our objective function can be defined as:
∑︀𝑚 ∑︀𝑛
min 𝑧 = 𝑖=1 𝑗=1 𝑐𝑖 * 𝑥𝑖𝑗
That is, the objective is to minimize the overall costs, which is the sum of the cost of the different materials needed to
manufacture all our products.
2.1. Tutorials 47
Notebooks for Operations Research, Release I
Availability constraints
Since the amount of resources or materials available is limited, let us plug in the availability constraints, let as note as 𝑎𝑚
as the availability of the material or resource 𝑚. The total amount used to manufacture all products cannot exceed the
availability of that specific material or resource. For instance, for material or resource 1, the sum of the amount used to
manufacture the different products cannot exceed the availability 𝑎1 , that is:
∑︀𝑛
𝑗=1 𝑥1𝑗 ≤ 𝑎1
...
∑︀𝑛
𝑗=1 𝑥𝑚𝑗 ≤ 𝑎𝑚
We can write this set of constraints in a compact form as:
∑︀𝑛
𝑗=1 𝑥𝑖𝑗 ≤ 𝑎𝑖 𝑖 ∈ [1, ..., 𝑚]
Demand constraint
As mentioned above, we need to satisfy the demand for every product, which means that the total amount of a product
that we need to manufacture needs to be greater or equal than its demand. Let us note 𝑑𝑗 as the demand for product 𝑗.
Note that we do not have explicitly defined a decision variable for the quantity of each product to manufacture, but in
terms of the blending problem, if all the materials are considered, it is equivalent to think of the total amount of a product
as the total amount of the materials needed to manufacture a product. Hence, the demand constraints can be expressed
as:
∑︀𝑚
𝑖=1 𝑥𝑖1 ≥ 𝑑1
∑︀𝑚
𝑖=1 𝑥𝑖2 ≥ 𝑑2
...
∑︀𝑚
𝑖=1 𝑥𝑖𝑛 ≥ 𝑑𝑛
Note that we can express this set of constraints in a compact form as:
∑︀𝑚
𝑖=1 𝑥𝑖𝑗 ≥ 𝑑𝑗 𝑗 ∈ [1, ..., 𝑛]
We may find additional requirements in the problem definition, for instance, we may find a requirement for a minimum
amount of an ingredient. Sometimes the requirement is expressed as a percentage or ratio of the total composition of the
product. As an example, let us define that the minimum amount of material or resource 2 for product 3 needs to be 20%,
or 0.2. If we are dealing with all the materials and resources used, we can again assume that the amount of material or
resource 𝑥23 needs to be at least 20% of the sum of all ingredients used to manufacture product 3, that is:
∑︀𝑚
𝑥23 ≤ 0.2 * 𝑖=1 𝑥𝑖3
We could bring all the dependant coefficients to the left-hand side and express this constraint as:
∑︀𝑚
0 ≤ −1 * 𝑥23 + 0.2 * 𝑖=1 𝑥𝑖3
∑︀𝑚
0 ≤ −0.8 * 𝑥23 + 0.2 * 𝑖=1,𝑖̸=2 𝑥𝑖3
∑︀𝑚
0.8 * 𝑥23 − 0.2 * 𝑖=1,𝑖̸=2 𝑥𝑖3 ≥ 0
Instead of just minimizing the overall cost, our objective can be to maximise profit. This can be regarded as a combination
of the production mix and blending problems. Let us define the unitary selling prices of our 𝑛 products as [𝑝1 , 𝑝2 , ..., 𝑝𝑛 ]
If we focus on one product, e.g. product 1, the profits can be calculated as the difference between the selling price and the
cost obtained for the total amount of the products sold. Again, if we can assume that the total amount of ingredients is
equal to the total amount of products, expressed in the same unit as the unitary selling price, the overall profits for product
1 can be expressed as:
∑︀𝑛 ∑︀𝑛
𝑝1 * 𝑖=1 𝑥𝑖1 − 𝑖=1 𝑐𝑖 * 𝑥𝑖1
Our objective is to maximize the overall profits, so we need to factor in the profits of the rest of the products with a
sumatory:
∑︀𝑛 ∑︀𝑛 ∑︀𝑛
max 𝑧 = 𝑗=1 𝑝𝑗 * 𝑖=1 𝑥𝑖𝑗 − 𝑖=1 𝑐𝑖 * 𝑥𝑖𝑗
Now, we can re-arrange the terms of the summations as:
∑︀𝑛 ∑︀𝑛
max 𝑧 = 𝑗=1 𝑖=1 (𝑝𝑗 − 𝑐𝑖 ) * 𝑥𝑖𝑗
Examples
Standard Form
Some algorithms like the Simplex need to operate with problems formulated in a standard form. Every CLP problem
described in the set-up section can be converted to a standard form where:
• The objective function is of type maximise
• All the constraints are of type equal
That is, any CLP problem can be expressed in the standard form as:
∑︀𝑛
max 𝑧 = 𝑖=1 𝑐𝑖 * 𝑥𝑖 = 𝑐𝑇
s.t. 𝑎11 ·𝑥1 + 𝑎12 ·𝑥2 + ... + 𝑎1𝑛 ·𝑥𝑛 + 𝑠1 = 𝑏1
𝑎21 ·𝑥1 + 𝑎22 ·𝑥2 + ... + 𝑎2𝑛 ·𝑥𝑛 + 𝑠2 = 𝑏2
...
𝑎𝑚1 ·𝑥1 + 𝑎𝑚2 ·𝑥2 + ... + 𝑎𝑚𝑛 ·𝑥𝑛 + 𝑠𝑛 = 𝑏𝑚
which can be expressed using a matrix product as:
𝐴·𝑥 = 𝑏
and
𝑥𝑖 ≥ 0 ∀𝑖
2.1. Tutorials 49
Notebooks for Operations Research, Release I
If we need to convert a problem where the objective function is of type minimize to the standard form, we need just need
to make a change of variable:
𝑧 = −𝑧*
With this change of variable the objective function:
min 𝑧 = 𝑐·𝑥
is equivalent to:
max 𝑧* = −𝑐·𝑥
And now the objective function is of type maximise.
Note that we have introduced a new set of decision variables 𝑠 = [𝑠1 , 𝑠2 , ..., 𝑠𝑛 ] used to make all the constraints of type
equal. These are new variables that are introduced to change the type of constraint to a constraint of type equal. Imagine
for instance that our problem has a constraint of type less or equal:
𝑎11 ·𝑥1 + 𝑎12 ·𝑥2 + ... + 𝑎1𝑛 ·𝑥𝑛 ≤ 𝑏1
Since the left hand side is less or equal than the right hand side, we can make the left hand side equal to the right hand
side by adding a non-negative variable 𝑠1 to the left hand side:
𝑎11 ·𝑥1 + 𝑎12 ·𝑥2 + ... + 𝑎1𝑛 ·𝑥𝑛 + 𝑠1 = 𝑏1
Obviously, we need to add a non-negativity constraint to the new variable to make sure that both constraints are equivalent:
𝑠1 ≥ 0
Equivalently, if we have a constraint of type greater or equal, we can make the same modification, but now, the new
variable needs to be lower or equal than zero to make the problem equivalent. For instance, let us consider without loss
of generality that we have the following constraint in our problem:
𝑎21 ·𝑥1 + 𝑎22 ·𝑥2 + ... + 𝑎2𝑛 ·𝑥𝑛 ≥ 𝑏2
This is equivalent to:
𝑎21 ·𝑥1 + 𝑎22 ·𝑥2 + ... + 𝑎2𝑛 ·𝑥𝑛 + 𝑠2 = 𝑏2
where:
𝑠1 ≤ 0
Also, if our constraint is of type equal, we do not need to introduce any change, but just to make sure we treat all constraints
in the same way, let us introduce again a new variable:
𝑎31 ·𝑥1 + 𝑎32 ·𝑥2 + ... + 𝑎3𝑛 ·𝑥𝑛 = 𝑏3
This is equivalent to:
𝑎31 ·𝑥1 + 𝑎32 ·𝑥2 + ... + 𝑎3𝑛 ·𝑥𝑛 + 𝑠3 = 𝑏3
where:
𝑠1 = 0
Slack variables
These new variables are called slack variables, and they represent the difference between the left hand side and the right
hand side. When slack variables are non-negative (meaning that the constraint is of type less or equal), they are called
surplus variables. Note that normally these constraints represent limited resources, so the slack value will represent the
surplus of resource that we have available in the optimal solution. When slack variables are non-positive (meaning that the
constraint is of type greater or equal), they are called excess variables. Note that these types of constraints will normally
represent additional requirements, so the value of the slack variable will represent the excess of the solution with respect
to the requirement. When slack variables are zero, they are referred to artificial variables. Since they must be zero, they
need to be treated differently by the solvers.
Finally, note that in the standard form, all the decision variables need to be non-negative, we can achieve this with a
change of variable:
𝑥 = 𝑥𝑖 − 𝑥𝑖𝑖
𝑥𝑖 , 𝑥𝑖𝑖 ∈ [0, inf]
That is, we replace the decision variable x by two non-negative decision variables, when 𝑥𝑖𝑖 is greater than 𝑥𝑖 , 𝑥 takes
negative values.
Summary
Now, in order to the standard form to hold, we need to plug in the new variables into the model. We first introduce the
slack variables into our decision variable vector, so that it becomes:
𝑥 = [𝑥1 , 𝑥2 , ..., 𝑥𝑛 , 𝑠1 , 𝑠2 , ..., 𝑠𝑛 ]
Now, to make sure that there is no impact in the objective function, we multiply the non-zero slack variables by a factor
of 0. Since artificial variables are equal to zero, we multiply them by an arbitrarily large negative number −𝑀 . This
number needs to be introduced by algorithms such as the Simplex. Let us assume without loss of generality that we
have 𝑝 non-zero slack variables and 𝑘 artificial variables. Let us note artificial variables as 𝑎1 , 𝑎2 , …, 𝑎𝑘 . Our objective
function becomes:
∑︀𝑛
max 𝑧 = 𝑖=1 𝑐𝑖 * 𝑥𝑖 + 0 * 𝑠1 + 0 * 𝑠2 + ... + 0 * 𝑠𝑝 − 𝑀 * 𝑎1 − 𝑀 * 𝑎2 + ... − 𝑀 * 𝑎𝑘
And the constraints:
𝑎11 ·𝑥1 + 𝑎12 ·𝑥2 + ... + 𝑎1𝑛 ·𝑥𝑛 + 𝑠1 + 0 * 𝑠2 + ... + 0 * 𝑠𝑝 + 0 * 𝑎1 + 0 * 𝑎2 + ... + 0 * 𝑎𝑘 = 𝑏1
𝑎21 ·𝑥1 + 𝑎22 ·𝑥2 + ... + 𝑎2𝑛 ·𝑥𝑛 + 0 * 𝑠1 + 02 + ... + 0 * 𝑠𝑝 + 0 * 𝑎1 + 0 * 𝑎2 + ... + 0 * 𝑎𝑘 = 𝑏2
...
𝑎𝑝1 ·𝑥1 + 𝑎𝑝2 ·𝑥2 + ... + 𝑎𝑝𝑛 ·𝑥𝑛 + 0 * 𝑠1 + 0 * 𝑠2 + ... + 𝑠𝑝 + 0 * 𝑎1 + 0 * 𝑎2 + ... + 0 * 𝑎𝑘 = 𝑏𝑝
𝑎(𝑝+1)1 ·𝑥1 + 𝑎(𝑝+1)2 ·𝑥2 + ... + 𝑎𝑛 ·𝑥𝑛 + 0 * 𝑠1 + 0 * 𝑠2 + ... + 0 * 𝑠𝑝 + 𝑎1 + 0 * 𝑎2 + ... + 0 * 𝑎𝑘 = 𝑏𝑝+1
𝑎(𝑝+2)1 ·𝑥1 + 𝑎(𝑝+2)2 ·𝑥2 + ... + 𝑎(𝑝+2)𝑛 ·𝑥𝑛 + 0 * 𝑠1 + 0 * 𝑠2 + ... + 0 * 𝑠𝑝 + 0 * 𝑎1 + *𝑎2 + ... + 0 * 𝑎𝑘 = 𝑏𝑝+2
...
𝑎𝑚1 ·𝑥1 + 𝑎𝑚2 ·𝑥2 + ... + 𝑎𝑚𝑛 ·𝑥𝑛 + 0 * 𝑠1 + 0 * 𝑠2 + ... + 0 * 𝑠𝑝 + 0 * 𝑎1 + 0 * 𝑎2 + ... + 1 * 𝑎𝑘 = 𝑏𝑚
2.1. Tutorials 51
Notebooks for Operations Research, Release I
Note that we can express the standard form as stated at the beginning of this section as:
max 𝑧 = 𝑐·𝑥
s.t.
𝐴=𝑏
where
𝑥 = [𝑥1 , 𝑥2 , ..., 𝑥𝑛 , 𝑠1 , 𝑠2 , ..., 𝑠𝑝 , 𝑎1 , 𝑎2 , ..., 𝑎𝑘 ]𝑇
𝑐 = [𝑐1 , 𝑐2 , ..., 𝑐𝑛 , 0, ...0, −𝑀, ..., −𝑀 ]𝑇
⎡ ⎤
𝑎11 𝑎12 ... 𝑎1𝑛 1 0 ... 0
⎢ 𝑎21 𝑎22 ... 𝑎2𝑛 0 0 ⎥
𝐴=⎢
⎣ ...
⎥
⎦
𝑎𝑚1 𝑎𝑚2 ... 𝑎𝑚𝑛 0 0 ... 1
𝑥 and 𝑐 are two 𝑛 + 𝑚 vectors and 𝐴 is a mx(n+m) matrix where the right most n columns represent the original LHS
coefficients and the right most n columns represent the nxn identity matrix.
Now, if we move all the dependent terms to the LHS, the objective function becomes:
𝑧 − 𝑐1 * 𝑥1 − 𝑐2 * 𝑥2 − ... − 𝑐𝑛 * 𝑥𝑛 − 0 * 𝑠1 − 0 * 𝑠2 + ... − 0 * 𝑠𝑝 + 𝑀 * 𝑎1 + 𝑀 * 𝑎2 + ... + 𝑀 * 𝑎𝑘 = 0
We can write all the coefficients in a data frame where each column represents the coefficients of a variable and each row
represents an equation:
Try me
Introduction
In this notebook we analyse the graphic method to solve CLP problems of two variables. First, we will derive a CLP
model of our problem, and then, we will use the Python plotting library matplotlib to obtain a graphical representation
that we will use to find the optimal solution.
The graphic method is not really a practical method to solve CLP problems, but rather, a quite didactic mean to gain
understanding on the CLP. Later in the course, we will cover the Simplex algorithm, one of the most successful algorithms
in history, which is an extension of this method. To put it into practice, we will use a simple blending problem defined
below.
Problem Definition
Model
2.1. Tutorials 53
Notebooks for Operations Research, Release I
Solution
We will use the numpy library to create the decision space and the pyplot library to represent the decision space. Numpy
provides useful functions to create multidimensional arrays. Below, some tips of the functions we are going to use.
Numpy Functions
The following subsections describe some functions of the Numpy Python package that are used in this example. The
Numpy Tutorial includes comprehensive information about this package, but as a reminder and for the sake of complete-
ness, here you can find a brief description of the functions used in this tutorial.
Linspace
We will use the function linspace to create the x-axis that represents the 𝑥1 decision variable. Linspace receives as
arguments the minimum and maximum values of the axis and the number of elements that we want in our axis.
We will use the functions maximum and minimum to obtain the lines that delimit the feasibility region. Minimum and
maximum take two (multidimensional) arrays and provide an array with the element-wise minimum or maximum at each
position.
Pyplot Functions
Likewise, the following subsections describe some functions of the Matplotlib Python package that we have used. The
Matplotlib Tutorial provides more information and sample codes of the library, but here is a brief guide of the main
functions used in this tutorial.
plot
We will use the function plot to draw lines. Plot takes two arrays as parameters and uses the values of each position of
the array as coordinates. We can add additional parameters as described here. We will use one parameter to represent
the labels.
fill_between
We will use the function fill_between to fill the area between two lines. Since we can only use two lines to call fill, we
will need to use the numpy functions maximum and minimum to create the lines that we want to draw
xlim, ylim
We will use these functions to add labels to the different axis and a legend to the figure
Feasibility region
Let us determine the feasibility region by iteratively representing the different constraints in the decision space. We start
by representing the possible values of 𝑥1 and 𝑥2 just taking into account the physical constraints:
𝑥1 > 0
𝑥2 > 0
𝑥1 + 𝑥2 ≤ 100
[1]: #Import the numpy and pyplot libraries, we set the aliases np and plt so that it is␣
˓→easier to use
import numpy as np
import [Link] as plt
#We set the mode inline of matplotlib to get the result at the output of the cell code
%matplotlib inline
# Construct lines, in our coordinate system x represents our decision variable x1 and␣
˓→y represents our decision variable x2
#y2 represents the line of constraint y > 0 (we need this function to call fill␣
˓→between)
y2 = x*0
plt.fill_between(x, y1, y2, where=y1>y2, color= grey , alpha=0.5) #fill where y1 is␣
˓→greater than y2
2.1. Tutorials 55
Notebooks for Operations Research, Release I
Introducing constraints
# x > 0
x = [Link](0, 100, 2000) #2000 numbers from 0 to 100
# y2 represents the line of constraint y <= 100 - x
y1 = 100 - x
y2 = x*0+2;
plt.fill_between(x, y1, y2, where=y1>y2, color= grey , alpha=0.5) #fill where y1 is␣
˓→greater than y2
(continues on next page)
# x > 0
x = [Link](0, 100, 2000) #2000 numbers from 0 to 100
# y2 represents the line of constraint y <= 100 - x
y1 = 100 - x
y2 = x*0+2;
y3 = (50-3*x)/3.0
2.1. Tutorials 57
Notebooks for Operations Research, Release I
plt.fill_between(x, y3, y2, where=y3>y2, color= grey , alpha=0.5) #fill where y3 is␣
˓→greater than y2
We can see that now the physical constraint 𝑥1 + 𝑥2 ≤ 100 does not have any impact on the feasibility region. We can
focus on narrower intervals of 𝑥1 and 𝑥2 to search for the best solution. Let’s also introduce the next constraint.
𝑥1 > 0
𝑥2 ≥ 2
𝑥1 + 𝑥2 ≤ 100
3𝑥1 + 3𝑥2 ≤ 50
8𝑥1 + 2𝑥2 ≥ 80
Now the feasibility region is:
# x > 0
x = [Link](0, 100, 2000) #2000 numbers from 0 to 100
The feasible region (in grey) contains all possible solutions to the objective function.
Minima and maxima of linear programming problems are found at the vertices of the feasible region. Therefore, the
solution is the minimum of the objective function between the three vertices.
The three corners are the intersections between the lines:
2.1. Tutorials 59
Notebooks for Operations Research, Release I
Line 1 Line 2
3x +3y ≤ 50 8x +2y ≥ 80
8x +2y ≥ 80 y≥2
y≥2 3x +3y ≤ 50
# x > 0
x = [Link](0, 100, 2000) #2000 numbers from 0 to 100
y6 = (451.5 - 45*x)/12
We have successfully calculated that the minimum value for Z (451.5), when 𝑥1 is 9.5 and 𝑥2 is 2.
This method of testing every vertex is only feasible for a small number of variables and constraints. As the numbers of
constraints and variables increase, it becomes far more difficult to graph these problems and work out all the vertices. For
example, if there were a third variable:
Z = Ax + By + Cz
We would have to graph in three dimensions (x, y and z).
In the next few notebooks, we’ll take a look at how we can use the graphical method to solve other CLP problems:
• Making Chappie solved with the graphical method
• Making weapons solved with the graphical method
2.1. Tutorials 61
Notebooks for Operations Research, Release I
Try me
Introduction
In this notebook, you can experiment with the graphic representation of a linear programming problem. The objective
is to gain understanding on the graphic method, how constraints affect the boundaries of the feasibility region and why
the solution to a problem is always at a vertex of the feasibility region. In this notebook you will be able to change the
objective variable and add or remove constraints to experiment and reflect on these questions.
Requirements
This script uses Numpy, Matplotlib, and Ipywidgets. They are provided off-the-shelf in Colabs. Otherwise, run the
following cell to install in your Kernel:
Problem model
The problem model is taken from the Making weapons problem. You can find the solution here: (Making weapons)
max 𝑧 = 40𝑥1 + 5𝑥2
s.t.
𝑥1 + 0.5𝑥2 ≤ 125 (Beskar constraint)
𝑥1 + 𝑥2 ≤ 225 (Tungsten constraint)
3𝑥1 + 𝑥2 ≤ 300 (Titanium constraint)
𝑥2 ≥ 100 (Demand constraint)
The code cell below allows you to add the constraints one by one to see how to modify the feasibility region. The slider
allows to modify the objective variable z to find the optimal value in each case. Remember, the optimal value will be
always the highest value of z where the objective function intersects with the feasibility region.
[3]: #Import the numpy and pyplot libraries, we set the aliases np and plt so that it is␣
˓→easier to use
import numpy as np
import [Link] as plt
import ipywidgets as widgets
from ipywidgets import interactive
#We set the mode inline of matplotlib to get the result at the output of the cell code
%matplotlib inline
#Construct lines, in our coordinate system x represents our decision variable x1 and␣
(continues on next page)
if tungsten_constraint:
[Link](x,y3,label=r $x_{1}+x_{2}\leq225$ )
y_max = [Link](y3, y_max)
if titanium_constraint:
[Link](x,y5,label=r $3x_{1}+x_{2}\leq300$ )
y_max = [Link](y5, y_max)
if demand_constraint:
[Link](x,y4,label=r $x_{2}\geq100$ )
y_min = y4
# 2. Adjust axis
[Link]((0,150))
[Link]((0,250))
[Link]((r $x_{1}$ ))
[Link]((r $x_{2}$ ))
# 5. Plot legend
[Link](bbox_to_anchor=(1.05,1), loc=2, borderaxespad=0.)
[Link]()
˓→= False)
output = interactive_plot.children[-1]
[Link] = 350px
interactive_plot
2.1. Tutorials 63
Notebooks for Operations Research, Release I
Try me
In this notebook we will analyse the Simplex algorithm alternating between the graphical and the algebraic representation
and using a problem as an example:
Problem Definition
Model
2𝑥1 + 𝑥2 ≤ 40
𝑥1 + 3𝑥2 ≤ 45
𝑥1 ≤ 12
Where:
𝑠1 : Slack variable of the operator man hour constraint (𝑠1 ≥ 0)
𝑠2 : Slack variable of the machining time constraint (𝑠2 ≥ 0)
𝑠3 : Slack variable of the operator man hour constraint (𝑠3 ≥ 0)
And thus, by entering the slack variables, we can now express the constraints as:
2𝑥1 + 𝑥2 + 𝑠1 = 40
𝑥1 + 3𝑥2 + 𝑠2 = 45
𝑥1 + 𝑠3 = 12
Solution
We will use the Simplex Method and iterate between the graphical and the algebraic form of the problem to describe the
results. First let us represent the problem:
# x > 0
x = [Link](0, 100, 2000) #2000 numbers from 0 to 100
# y1 represents the line of constraint 2x1 + x2 <= 40
y1 = -2*x + 40
# y2 represents the line of the constraint x1 + 3x2 <= 45
y2 = (45-x)/3.0
# x2 represents a constraint at y2 <12 used for convenience
x2 = (12 - x*0)
2.1. Tutorials 65
Notebooks for Operations Research, Release I
#5 Annotate graph
[Link]( A , xy=(0, 0))
[Link]( B , xy=(0, 15))
[Link]( D ,xy=(12, 0))
[Link]( E , xy=(12,11))
[1]: Text(12, 11, E )
The feasible region (in grey) contains all possible solutions to the objective function.
Let us now represent the same problem in a basic Tableau:
z 𝑥1 𝑥2 𝑠1 𝑠2 𝑠3 RHS
1 -300 -250 0 0 0 0
0 2 1 1 0 0 40
0 1 3 0 1 0 45
0 1 0 0 0 1 12
From the Tableau, we can easily find a first Feasible Basic Solution (FSB), by making 𝑥1 and 𝑥2 non basic (=0). The
three equations of the constraints provide us the value of the slack variables in this solution:
𝑥1 = 0
𝑥2 = 0
𝑠1 = 40
𝑠2 = 45
𝑠3 = 12
Let us note this solution as (0,0,40,45,12) and z=0. Note that this FSB corresponds to Vertex A in the figure. How can we
know if it is optimal? We have 2 non basic variables 𝑥1 and 𝑥2 which have negative coefficients in the objective function
and positive values of this variables would increase z. If we increase 𝑥1 in one unit, z would increase 300 units and if we
increase 𝑥2 in one unit z would increase 250. Therefore, the solution is not optimal, since we could find a higher z for
a positive value of these variables in the objective function. Hence, this is not the optimal solution and we need to look
for it in another vertex. From point A, we could either move to vertex B or to vertex D. Moving towards D would mean
making 𝑥1 higher than zero, thus making it a basic variable. Likewise, moving towards B would mean making 𝑥2 higher
than zero and basic (enter the base). We select 𝑥1 as the entering basic variable, since its coefficient (300) is higher and
therefore z will increase at a higher rate when we move towards D. We have just selected the pivot variable and the pivot
column in the Tableau.
Now, we are going to move towards D, which is equivalent to make 𝑥1 = 𝛿. As this value increases, the objective value
will also increase, but we have to bear in mind that all variables must be positive and therefore 𝛿 cannot take any given
value: we have to make sure the solution is feasible. If we write down all the constraints in algebraic form, we can find
the possible values of 𝛿
2 * 𝛿 + 1 * 0 + 𝑠1 = 40
1 * 𝛿 + 3 * 0 + 𝑠2 = 45
1 * 𝛿 + 𝑠3 = 12
To ensure that all the surplus variables are positive 𝛿 cannot exceed the maximum positive value that guarantees that all the
surplus variables are non negative. Out strategy to find a feasible solution is to make on slack variable non-basic (equal
to zero), but making sure that all the constraints are met. Since we only have 𝛿 and a slack variable in each expression,
making the corresponding slack variable equal to zero is equivalent to making $:nbsphinx-math:delta equal to the RHS
divided by the coefficient, which means that the maximum value it can take is 𝛿 = 𝑚𝑖𝑛(40/2, 45/1, 12/1). Any value
above this makes the solution unfeasible. This is called the Ratio test. If we make 𝑥1 = 𝛿 = 12 then that implies that
𝑠3 is now a non-basic variable. With the Ratio test, we have selected 𝑠3 as the leaving variable which will no longer be
basic in the FSB. Let us add two new columns to the basic Tableau, one to the right to indicate which variable is the basic
variable in the equation and another one to the left to express this Ratio test.
• 1 -300 -250 0 0 0 0 •
𝑠1 0 2 1 1 0 0 40 40/2=20
𝑠2 0 1 3 0 1 0 45 45/1=45
𝑠3 0 1 0 0 0 1 12 12/1=12
Now, notice that from the Ratio test, we have easily determined that the variable that leaves the basic solution is 𝑠3 and
using the last equation we can easily determine that 𝑥1 = 12 in the new solution. We will move to another solution
(12,0,?,?,0) which corresponds exactly to point D. Now notice that in the first iteration, the problem was expressed in a
very convenient way since we had only a non-zero (1) value for each basic variable in every row. To accomplish this, we
are going to transform the different rows. Since the equations are linearly independent, we can make linear operations in
the different equations and still obtain a linear independent system of equations. We want to obtain a system like this:
• 1 0 ? 0 0 ? ? •
𝑠1 0 0 ? 1 0 ? ? ?
𝑠2 0 0 ? 0 1 ? ? ?
𝑥1 0 1 ? 0 0 ? ? ?
Note that when the problem is in this form, we will have each basic variable in a row with coefficient 1 and the rest with
coefficient 0 and we will be able to obtain the value for each basic variable rather easily. First we transform the leaving
equation, by dividing the entire raw by the coefficient of the entering variable in that equation (in this case is 1) and the
raw remains unaltered:
2.1. Tutorials 67
Notebooks for Operations Research, Release I
• 1 0 ? 0 0 ? ? •
𝑠1 0 0 ? 1 0 ? ? ?
𝑠2 0 0 ? 0 1 ? ? ?
𝑥1 0 1/1=1 0/1=0 0/1=0 0/1=0 1/1=1 12/1=12 ?
Now, for the rest of the row, we need to make a linear operation that gives a zero in the cell corresponding to the entering
variable. To accomplish this, we substract the entering equation multiplied by the value of the coefficient that multiplies
the entering variable 𝑥1 .
• 1 -300-(-300·1)=0
-250-(-300·0)=0
0-(-300·0)=00-(-300·0)=00-(-300·1)=300
0-(-300·12)=3600•
𝑠1 0 0 1 1 0 -2 16 ?
𝑠2 0 0 3 0 1 -1 33 ?
𝑥1 0 1 0 0 0 1 12 ?
And the new FSB solution is (12, 0, 16, 32, 0) which as noted corresponds to point D.
At this point, z has increased from 0 to 3600, but we still have a coefficient in 𝑥2 that is lower than zero and therefore
we could find a higher value if again we move from D to E by increasing 𝑥2 , just as we did with 𝑥1 . We have selected
the next entering variable and the pivot column and we can perform the Ratio test again to select the variable leaving the
basic solution:
𝑠1 0 0 1 1 0 -2 16 16
𝑠2 0 0 3 0 1 -1 33 11
𝑥1 0 1 0 0 0 1 12 12
The minimum value that makes all variables positive is 11. Therefore, the variable leaving the solution is 𝑠2 . We first
transform the new entering row:
• 1 ? 0 0 ? ? ? •
𝑠1 0 0 0 1 ? ? ? ?
𝑥2 0 0 1 0 1/3 -1/3 11 ?
𝑥1 0 1 0 0 ? ? ? ?
And then the rest of the rows using linear transformations as we did before we obtain.
• 1 0-(-250·0)=0-250-(-250·1)=0
0-(-250·0)=00-(-250·1/3)=250/3
300-(-250·-1/3)=650/3
3600-(-250·11)=6350
•
𝑥2 0 0 1 0 1/3 -1/3 11 •
𝑥1 0 1 0 0 0 1 12 •
Now we obtain a new solution (12, 11, 5, 0, 0) where z = 6350 and we know for sure that this is a maximum because
there are no negative coefficients for any of the non-basic variables that could yield to a higher value of z.
[2]: # Alias to use numpy library functions
import numpy as np
import matplotlib
# Alias to use matplotlib
import [Link] as plt
# Inline is used to get the output of matplotlib to the output of the cell
%matplotlib inline
# x > 0
x = [Link](0, 100, 2000) #2000 numbers from 0 to 100
# y1 represents the line of constraint 2x1 + x2 <= 40
y1 = -2*x + 40
# y2 represents the line of the constraint x1 + 3x2 <= 45
y2 = (45-x)/3.0
2.1. Tutorials 69
Notebooks for Operations Research, Release I
#5 Annotate graph
[Link]( A , xy=(0, 0))
[Link]( B , xy=(0, 15))
[Link]( D ,xy=(12, 0))
[Link]( E , xy=(12,11))
[2]: Text(12, 11, E )
2.1.5 Duality
Introduction
The duality principle states that every optimization problem can be represented and analysed in two different formulations,
the primal and the dual. This means that every problem that we have analysed so far has a dual problem formulation
with the following characteristics:
• The dual has an optimal solution if and only if the primal has an optimal solution (and vice versa)
• The optimal value of the objective function both cases (respective optimal solutions) is the same (strong duality
principle)
• The dual of dual is the primal
• The solution of the dual problem can be obtained from the solution of the primal and vice versa (using algorithms
like the like Simplex)
Summary
Simple example
Let us consider the following generic problem with two decision variables:
max 𝑧 = 𝑐1 * 𝑥1 + 𝑐2 * 𝑥2
s.t.
𝑎11 * 𝑥1 + 𝑎12 * 𝑥2 ≤ 𝑏1
𝑎21 * 𝑥1 + 𝑎22 * 𝑥2 ≤ 𝑏2
𝑎31 * 𝑥1 + 𝑎32 * 𝑥2 ≤ 𝑏3
Applying the rules above, the objective function of the dual is of type minimise, there are 3 decision variables, as the
primal has 3 constraints, and the coefficients of the objective function of the dual are the RHS of the primal, hence, the
objective function of the dual becomes:
2.1. Tutorials 71
Notebooks for Operations Research, Release I
min 𝑧 = 𝑏1 * 𝑢1 + 𝑏2 * 𝑢2 + 𝑏3 * 𝑢3
Now, we have two constraints, one per every decision variable. The RHS are the coefficients of the objective function,
and the dependent coefficient are obtained by transposing the coefficients of the primal, hence the dual problem is subject
to the following constraints:
𝑎11 * 𝑢1 + 𝑎21 * 𝑢2 + 𝑎31 * 𝑢3 ≥ 𝑐1 𝑎12 * 𝑢1 + 𝑎22 * 𝑢2 + 𝑎32 * 𝑢3 ≥ 𝑐2
Now, since the constraints of the primal are of type 𝑙𝑒𝑞, the three decision variables are non-negative:
𝑢1 , 𝑢2 , 𝑢3 ≥ 0
Bounding explanation
One way to deduct the dual is by acknowledging that, if the objective function of the primal is of type maximize and all
the constraints are of type less or equal, linear combinations of the constraints provide upper bounds for the objective
function. For instance, let us consider the following problem:
max 𝑧 = 4 * 𝑥1 + 𝑥2 + 5 * 𝑥3 + 3 * 𝑥4
s.t.
𝑥1 − 𝑥2 − 𝑥3 + 4 * 𝑥4 ≤ 1
5 * 𝑥1 + 𝑥2 + 3 * 𝑥3 + 8 * 𝑥4 ≤ 55
−𝑥1 + 2 * 𝑥2 + 3 * 𝑥3 + 5 * 𝑥4 ≤ 3
Note that, if we multiply the second constraint by a factor of 2, we obtain an equivalent constraint:
10 * 𝑥1 + 2 * 𝑥2 + 6 * 𝑥3 + 16 * 𝑥4 ≤ 110
Note also that all the LHS coefficients of this constraint are higher or equal than the coefficients of the objective function,
and therefore:
max 𝑧 = 4 * 𝑥1 + 𝑥2 + 5 * 𝑥3 + 3 * 𝑥4 ≤ 10 * 𝑥1 + 2 * 𝑥2 + 6 * 𝑥3 + 16 * 𝑥4 ≤ 110
This constraint is an upper bound for the objective function, we do not know yet which is the maximum value of z, but
we know that it cannot be higher than 110.
Note that we can find another upper bound using a linear combination of the second of third constraint, just by adding
both constraints, we obtain:
4 * 𝑥1 + 3 * 𝑥2 + 6 * 𝑥3 + 13 * 𝑥4 ≤ 58
Again, this linear combination is an upper bound of the objective function, since all the coefficients are higher or equal
the coefficients of the objective value, for any value of the decision variables, we have:
max 𝑧 = 4 * 𝑥1 + 𝑥2 + 5 * 𝑥3 + 3 * 𝑥4 ≤ 4 * 𝑥1 + 3 * 𝑥2 + 6 * 𝑥3 + 13 * 𝑥4 ≤ 58
Therefore, even if we do not know which is the optimal value of the objective function, 58 is an upper bound, the optimal
value cannot exceed this bound.
Note that finding the maximum value of 𝑧, is equivalent to finding the minimum upper bound, hence, the minimum
linear combination of the constraints, or equivalently, the minimum linear combination of the RHSs:
𝑚𝑖𝑛𝑧* = 1 * 𝑢1 + 55 * 𝑢2 + 4 * 𝑢3
which yields coefficients that are higher or equal the coefficients of the objective function for every decision variable:
𝑢1 + 5 * 𝑢2 − 𝑢3 ≥ 4
−𝑢1 + 𝑢2 + 2 * 𝑢3 ≥ 1
−𝑢1 + 3 * 𝑢2 + 3 * 𝑢3 ≥ 5
4 * 𝑢1 + 8 * 𝑢2 + 5 * 𝑢3 ≥ 3
Complementary slackness
Following the reasoning of the previous section, note that the decision variables of the dual are equivalent to the La-
grangian multipliers of the constraints in the Lagrangian of the primal:
∑︀𝑛
max 𝑧 = 𝑖=1 𝑐𝑖 * 𝑥𝑖 + 𝑢1 * (𝑎11 * 𝑥1 + 𝑎12 * 𝑥2 + ... + 𝑎1𝑛 * 𝑥𝑛 ) + 𝑢2 * (𝑎21 * 𝑥1 + 𝑎22 * 𝑥2 + ... + 𝑎2𝑛 * 𝑥𝑛 ) + ...
Maximizing the objective function is equivalent to minimizing the part of the Lagrangian multipliers.
But most importantly, Dual variables represent changes in the primal objective function per unit of constraint, that is, if
an RHS of a constraint 𝑖 is modified in 1 unit, the objective function is going to change in 𝑢𝑖 units.
For this reason, the decision variables of the dual are referred to as the shadow prices of the constraints. The term shadow
highlights that they are not factored in the objective function, and the term price means that they represent the impact in
the objective function.
It follows that if a constraint is non-binding, meaning that the corresponding slack variable is non-zero, then the corre-
sponding decision variable, or shadow price must necessarily be zero (that is, the shadow price must be zero, because we
have a surplus or excess, and a change in the RHS of the constraint is not going to change the objective variable, just
the value of the surplus or excess). Conversely, if a constraint is binding (meaning that the corresponding slack variable
is zero), then the corresponding dual variable (shadow price) is basic (non-zero), because a change in the RHS of the
constraint can cause a change in the objective variable.
Same applies for the dual: If a constraint of the dual is binding (meaning that the slack variable is zero, or non-basic),
then the corresponding primal variable is basic. Also, if a constraint of the dual is non-binding (meaning that the slack
variable is non-zero, or basic), then the corresponding primal variable is non-basic.
This principle is called complementary slackness meaning that the slack values or slackness of dual and primal are
complementary.
Let us start with the Production Mix Problem example, which in the standard form is:
𝑚𝑎𝑥𝑍 = 300𝑥1 + 250𝑥2 + 0𝑠1 + 0𝑠2 + 0𝑠3
subject to:
2𝑥1 + 𝑥2 + 𝑠1 = 40
𝑥1 + 3𝑥2 + 𝑠2 = 45
𝑥1 + 𝑠3 = 12
2.1. Tutorials 73
Notebooks for Operations Research, Release I
𝑠1 0 0 0 1 -1/3 -5/3 5 •
𝑥2 0 0 1 0 1/3 -1/3 11 •
𝑥1 0 1 0 0 0 1 12 •
Let us assume we want to make a change in coefficient 𝑐1 of Δ𝑐1 . The objective function becomes:
𝑚𝑎𝑥𝑍 = (300 + Δ𝑐1 )·𝑥1 + 250𝑥2
It can be proved that the final Tableau now becomes:
𝑠1 0 0 0 1 -1/3 -5/3 5 •
𝑥2 0 0 1 0 1/3 -1/3 11 •
𝑥1 0 1 0 0 0 1 12 •
The Simplex method requires that the Tableau is in canonical form. Thus, we need to add the last row times Δ𝑐1 to the
first row to fulfill this:
𝑥2 0 0 1 0 1/3 -1/3 11 •
𝑥1 0 1 0 0 0 1 12 •
And taking into account that the coefficient of 𝑠3 needs to be positive for 𝑥1 to remain in the basis, Δ𝑐1 cannot be lower
than -650/3 and can increase up to infinity.
Let us now assume we want to make a change in coefficient 𝑐2 of Δ𝑐2 . The objective function becomes:
𝑚𝑎𝑥𝑍 = 300·𝑥1 + (250 + Δ𝑐2 )·𝑥2
The final Tableau now becomes:
𝑠1 0 0 0 1 -1/3 -5/3 5 •
𝑥2 0 0 1 0 1/3 -1/3 11 •
𝑥1 0 1 0 0 0 1 12 •
Again, the Simplex method requires that the Tableau is in canonical form. Thus, we need to add the second last row times
Δ𝑐2 to the first row to fulfill this:
𝑥2 0 0 1 0 1/3 -1/3 11 •
𝑥1 0 1 0 0 0 1 12 •
And taking into account that the coefficients of 𝑠2 and 𝑠3 need to be positive for 𝑥2 to remain in the basis, Δ𝑐2 cannot
be lower than -250 nor higher than 650.
Now let us see what is the effect of changing b, for instance decreasing 𝑏1 an amount equal to Δ𝑏1 . In the original problem
formulation, this means:
2𝑥1 + 𝑥2 + 𝑠1 = 40 − Δ𝑏1
𝑥1 + 3𝑥2 + 𝑠2 = 45
𝑥1 + 𝑠3 = 12
Changing the Right Hand Side by Δ𝑏1 is equivalent to changing 𝑠1 an amount of Δ𝑏1 . Note that 𝑠1 is in the basis, thus
for it to remain in the basis, it must satisfy:
𝑠1 = 5 + Δ𝑏1 ≥ 0
Δ𝑏1 ≥ −5
Now, take the second constraint and let us apply the same change:
2𝑥1 + 𝑥2 + 𝑠1 = 40
𝑥1 + 3𝑥2 + 𝑠2 = 45 − Δ𝑏2
𝑥1 + 𝑠3 = 12
Again, this is equivalent to:
2.1. Tutorials 75
Notebooks for Operations Research, Release I
2𝑥1 + 𝑥2 + 𝑠1 = 40
𝑥1 + 3𝑥2 + 𝑠2 + Δ𝑏2 = 45
𝑥1 + 𝑠3 = 12
Which can be regarded as a change of Δ𝑏2 in 𝑠2 . Now, if we change 𝑠2 from 𝑠2 = 0 to 𝑠2 = Δ𝑏2 in the final Tableau:
𝑥1 0 1 0 0 0 ·Δ𝑏2 1 12 •
The basis remains unchanged as long as all the constraints are still met:
𝑠1 − 1/3·Δ𝑏2 = 5
𝑥2 + 1/3·Δ𝑏2 = 11
𝑥1 + 0·Δ𝑏2 = 12
Try me
Introduction
In this notebook, you can experiment with the graphic representation of a linear programming problem. The objective is
to assess the impact that the changes in the problem coefficient have in the optimal solution.
Problem model
2𝑥1 + 𝑥2 + 𝑠1 = 40
𝑥1 + 3𝑥2 + 𝑠2 = 45
𝑥1 + 𝑠3 = 12
The code cell below allows you to modify the coefficients of the objective function through sliders, to see how these changes
modify the slope of the objective function. Depending on the changes, the optimal solution might be at another vertex, so
the objective function slider allows to modify the objective variable z to find the optimal value in these cases. Remember,
the optimal value will be always the highest value of z where the objective function intersects with the feasibility region.
[1]: #Import the numpy and pyplot libraries, we set the aliases np and plt so that it is␣
˓→easier to use
import numpy as np
import [Link] as plt
import ipywidgets as widgets
from ipywidgets import interactive
#We set the mode inline of matplotlib to get the result at the output of the cell code
%matplotlib inline
#Construct lines, in our coordinate system x represents our decision variable x1 and␣
˓→y represents our decision variable x2
[Link](1)
2.1. Tutorials 77
Notebooks for Operations Research, Release I
#4 Annotate graph
[Link]( A , xy=(0, 0))
[Link]( B , xy=(0, 15))
[Link]( D ,xy=(12, 0))
[Link]( E , xy=(12,11))
# 6. Plot legend
[Link](bbox_to_anchor=(1.05,1), loc=2, borderaxespad=0.)
[Link]()
output = interactive_plot.children[-1]
[Link] = 350px
interactive_plot
Analysis questions
1. Keep the objective function coefficient of the second variable to 250 and decrease the coefficient of the first variable.
What happens to the slope of the objective function? Adjust the value of z until you find again the optimal value of
the objective function. What happens to the optimal value of the objective function? Will it be always at the same
vertex?
2. Now, repeat the experiment in the first question and increase the coefficient of the first variable. What happens
to the slope of the objective function? Adjust the value of z until you find again the optimal value of the objective
function. What happens to the optimal value of the objective function? Do you think it will always be at the same
vertex?
3. Repeat the experiment in the first two questions but now changing the coefficient of the second variable and write
down your conclusions.
The code cell below allows you to modify the independent terms of the constraints. The changes are going to change the
feasibility region and again, if they are too extreme, the solution might change to another vertex.
[2]: #Import the numpy and pyplot libraries, we set the aliases np and plt so that it is␣
˓→easier to use
import numpy as np
import [Link] as plt
import ipywidgets as widgets
from ipywidgets import interactive
#We set the mode inline of matplotlib to get the result at the output of the cell code
%matplotlib inline
#Construct lines, in our coordinate system x represents our decision variable x1 and␣
˓→y represents our decision variable x2
[Link](1)
# 6. Plot legend
[Link](bbox_to_anchor=(1.05,1), loc=2, borderaxespad=0.)
[Link]()
output = interactive_plot.children[-1]
[Link] = 350px
interactive_plot
2.1. Tutorials 79
Notebooks for Operations Research, Release I
Analysis questions
1. Keep the Right Hand Side (RHS) coefficients of the second and third constraint unchanged and increase the RHS
coefficient of the first constraint. What happens to the feasibility region? Now adjust z so that you find again the
optimal value of the objective function. What happens to the optimal value of the objective function? Will it be
always at the same vertex?
2. Keep the Right Hand Side (RHS) coefficients of the second and third constraint unchanged and decrease the RHS
coefficient of the first constraint. What happens now to the feasibility region? And what happens to the optimal
value of the objective function? Will it be always at the same vertex as before?
3. Now repeat the experiment in the first two questions but now changing the RHS coefficients of the second and third
constraints and write down your conclusions.
As you have seen, changing the coefficients of the objective function and the constraints can have a significant impact on
the solution of the linear programming problem. In a nutshell, a sensitivity analysis explores the impact of changes of
the coefficients of the objective function and the constraints on the solution of the linear programming problem. A solver
providing a sensitivity analysis normally provides the following information:
• Objective function coefficients: The sensitivity analysis provides the range of values for the coefficients of the
objective function for which the current optimal solution remains optimal. Normally, a solver will provide the
upper and lower bounds for the coefficients of the objective function. If the coefficients are within these bounds,
the current optimal value of decision variables and constraint slack values will remain optimal. If the coefficients
are outside these bounds, the current optimal solution will not be optimal anymore. In the graphic representation,
this will mean that the optimal solution will no longer be at the same vertex.
• Right Hand Side (RHS) coefficients: Similarly, a sensitivity analysis provides the range of values for the Right
Hand Side (RHS) coefficients for which the current optimal solution remains optimal. Normally, a solver will
provide the upper and lower bounds for the RHS coefficients. If the coefficients are within these bounds, the
current optimal value of decision variables and constraint slack will value remain optimal. If the coefficients are
outside these bounds, the current optimal solution will not be optimal anymore. Again, in the graphic representation,
this will mean that the optimal solution will no longer be at the same vertex.
Sensitivity analysis is a powerful tool to understand how the changes in the coefficients of the objective function and the
constraints affect the solution of the linear programming problem. It is important to understand that the sensitivity analysis
is a local analysis, meaning that the conclusions are valid only for small changes in the coefficients, and unitary changes
that we apply to one and only one coefficient at a time.
The following tables provide the results of a sensitivity analysis applied to the problem at hand in this interactive tutorial:
Con- Right Hand Slack (primal prob- Shadow price (dual prob- RHS lower RHS upper
straint Side (RHS) lem solution) lem solution) bound bound
1 40 5 0 35 Infinity
2 45 0 83.3 12 60
3 12 0 216.67 0 15
Now, run the colab and try to set the coefficients of the objective function and the constraints to the values in the upper
and lower bound values in the tables. You will see that the optimal solution remains the same while the coefficients are
within the bounds. However, if you set the coefficients outside the bounds, the optimal solution will no longer be optimal.
If you set the first coefficient exactly to 83.3 you will notice that the objective function will be parallel to the constraint
line. This means that any change below this point will shift the optimal towards the vertex to the right. A similar effect
will happen if you set the second coefficient to 900.
On the other hand, if you shift the first constraint to 35, you will notice that now the three constraints intersect at the same
point. If you make any changes to 𝑏1 below this point, the optimal solution will no longer be at the same vertex. The
same thing happens if you try any RHS lower bound and upper bound in the table.
Do you want to learn more about sensitivity analysis? Check the following tutorial for a more detailed explanation of the
algebraic concepts behind sensitivity analysis
• Sensitivity analysis tutorial
2.2 Exercises
A gold seeker needs to find at least 2 kg of bronze and 3 kg of copper to pay his gambling debts. There are two rivers in
which the miner can find these precious metals. Each day the miner spends in river A, he finds 0.3 kg of bronze and 0.3
kg of copper while each day he spends in river B, he finds 0.2 kg of bronze and 0.4 kg of copper.
Can you help this gold seeker decide how many days to spend in each day to pay his debts as soon as possible?
“The Fog Ltd” is a modern furniture company that makes tables and chairs. The selling price of a table is 30€ and the
selling price of chairs is 10€. The carpenter at the company works up to 40 hours and needs 6 hours to make a table and
3 hours to make a chair. Customer demand requires that he makes at least 3 times as many chairs as tables. Tables take
up four times as much storage space as chairs and there is room for at most four tables each week.
What is the optimal weekly production plan that optimises revenues?
Formulate this problem as a linear programming problem.
2.2. Exercises 81
Notebooks for Operations Research, Release I
Problem Definition
Ski Patrol Ltd. manufactures two different models of snowboards branded Normal and Deluxe with a weekly production
plan and inventory. They sell their material to local shops. The company obtains a profit of 300€ per Normal snowboard
and 400€ per Deluxe snowboard. The manufacturing process consists of roughing and polishing. The Normal snowboard
model requires 20 minutes of roughing and 2/3 minutes of polishing. The Deluxe snowboard model requires 40 minutes
of roughing and 1 minute of polishing. The roughing equipment is available for 1000 minutes per week and the polishing
equipment for 800 minutes per week. Ski Patrol has already signed a contract with a local shop called Downhill Racer to
deliver 18 Normal snowboards per week.
Ski Patrol hires you to formulate a Linear Programming Problem to help them determine the best production mix to
maximise benefits.
Write a CLP problem to maximize profits
Problem Definition
Model
2𝑥1 + 𝑥2 ≤ 40
𝑥1 + 3𝑥2 ≤ 45
𝑥1 ≤ 12
2𝑥1 + 𝑥2 + 𝑠1 = 40
𝑥1 + 3𝑥2 + 𝑠2 = 45
𝑥1 + 𝑠3 = 12
Din Djarin is a retired bounty hunter that now runs a small factory specialised in making classic weapons in a colony
recently restablished in Mandalore. The factory manufactures two different types of weapons, swords and spears. Din
uses special alloys, mixtures of metals and rare materials, which have made a name for the endurance of his weapons
across the colony. The table below shows the weight in pounds of each material needed to make each type of weapon:
And the table below shows the total amount of each metal available, also in pounds:
Metal Amount
Beskar 125
Tungsten 225
Titanium 300
The price of a spear is 40 credits and the price of a sword is 5 credits. Din has already sold 100 swords, so he needs to
manufacture at least that many.
Write a CLP problem to find the optimal number of spades and swords that maximise revenues
2.2. Exercises 83
Notebooks for Operations Research, Release I
Problem description
Cremanet is an energy drink that is inspired in the typical Valencian drink “Cremaet”. The main ingredients of Cremaet
are:
• Coffee: Coffee has a strong flavor and a high caffeine content. The specific type of coffee grain used in Cremaet
yields a cost of 4€ per liter, and it contains 170 mg of caffeine per liter.
• Rum mix: The rum mix is a blend of rum, sugar, and orange peel. The cost of the rum mix is 15€ per liter, and it
contains 9% alcohol (which corresponds to 9 grams of ethanol per 100ml of rum mix).
Cremanet wants to position itself as a premium energy drink with a mild level of alcohol, according to the following
specifications:
Problem Definition
The company Tetravaal located in Johannesburg manufactures two types of robots, Model 𝑃1 and Model 𝑃2 . The pro-
duction plant is consisted of four different sections: metal machining, plastic moulding, electrical work and assembly.
The metal machining section has a capacity of 7500 units of 𝑃1 or 6000 units of 𝑃2 per month.
Plastic moulding can process 5000 units of 𝑃1 or 9000 units of 𝑃2 per month.
Electrical work can process 6000 units of 𝑃1 or 7000 units of 𝑃2 per month.
In Assembly, there are two assembly lines that work in parallel, one per each robot model.
The first assembly line can process 4000 units of 𝑃1 per month
The second assembly line can process 5000 units of 𝑃2 per month
Knowing that the unitary profit of 𝑃1 is 500€ and that the unitary profit of 𝑃2 is 600€, and that both robots have a great
demand and therefore all manufactured robots are sold, Michelle Bradley, CEO of Tetravaal, asks his engineering team:
Calculate the number of units of each robot that needs to be manufactured to maximise profit for the company.
Write a CLP problem to calculate the number of units of each robot that needs to be manufactured
to maximise profit for the company.
Problem Definition
Duff Beer is an american brewery that sells alcoholic beverages worldwide. Duff beer has a very large market share in
the US. One of the new business lines of Duff Beer is in the craft beer sector. Duff beer buys 3 types of wort from local
suppliers. The availability of wort (in liters) and the price for each of them is specified in Table 1.
Table 1: daily availability and cost of wort
The blend of the three types of wort must comply with the following quality requirements:
• For Beer Angels, no less than 60% of Type 3 and no more of 20% of Type 2. The price of one bottle of Beer
Angel is 4.10€s/liter.
• For Beer Beast, no less than 15% of Type 3 and no more than 60% of Type 2. The price of one bottle of Beer
Beast is 2.80€s/liter.
2.2. Exercises 85
Notebooks for Operations Research, Release I
• For Beer Cactus, no more than 50% of type 2. The selling price is 2.45 €/liter.
Write a linear program to find the most profitable blend of wort to elaborate the three kinds of beers
Problem definition
The Kahuna company manufactures sausages using three kinds of meat. The relevant information about the ingredients
is provided in the table below:
The company makes two types of sausages: * Economy (>=40% Pork) * Premium (>=60% Pork)
One sausage is 50 grams (0.05 kg)
According to government regulations, the most starch we can use in our sausages is 25%
We have a contract with a butcher, and have already purchased 23 kg pork, that will go bad if it’s not used.
We have a demand for 350 economy sausages and 500 premium sausages.
Write a linear program to figure out the most cost-effective recipe to manufacture our sausages.
Problem Definition
Harry Stamper is an engineer working on a petroleum company. The company produces three grades of motor oil –
super, premium, and extra. The three grades are made from the same 3 ingredients, named component 1, component 2
and component 3. The company wants to determine the optimal mix of the 3 components in each grade of motor oil that
will maximize profit.
The maximum availability of each component and their cost per barrel are as follows:
To ensure the appropriate blend, each grade must have a minimum amount of component 1 plus a combination of other
components as follows:
The company wants to make at least 3000 barrels of each blend. Formulate an LP to help Harry Stamper find the optimal
blend that maximises profit.
Analysis questions (Do this part once you have reviewed CLP analysis including sensitivity analysis questions). You can
check the solution in the Notebook Petroleum Blending (Solved CBC)
• Which is the total profit obtained by the company with the Extra grade with the solution provided by the solver?
• Which is the maximum value that the profit per barrel of component 2 in the Extra grade can take without changing
the base of the optimal solution?
• If the cost of the barrel of component 3 increased 1€, will the optimal composition change? Motivate your response
• Do we use every barrel available of every component in the optimal solution? Or do we have any surplus availability
for any component? Motivate your response
• The provider of Component 2 may have a problem with the delivery and the availability may be reduced in 400
barrels. Will this shortage affect the optimal composition? Motivate your response*
• Grace wants to use the results to renegotiate the terms and conditions with the suppliers of the different components.
Which component is a better candidate to increase the availability? How would you use the model to negotiate new
terms with the provider, assuming you do not want any change in the base of the optimal solution? Motivate your
response
Problem I
You have read an article about the benefits of fasting. This article publishes a series of findings around the fasting diet
method. Specifically, the article states that:
• Decreasing the number of meals to three, two heavier meals and a light meal in between has significant benefits for
the health
• The study reveals that the optimal amount of daily calories for an adult is higher than 1800
• and also lower than 2200 calories
• The study also reveals that the light meal should not represent more than 10% of the number of daily calories
• And that the last meal should not provide more than 700 calories
You think you can design a Linear Programming Problem where the decision variables represent the calories of each
meal to find and optimal diet that fulfils all these requirements, while at the same time provide the maximum number of
calories. For such a model, define:
a. The objective function
b. The constraints
2.2. Exercises 87
Notebooks for Operations Research, Release I
[ ]:
Problem definition
[ ]:
Problem Definition
Weyland Corp is a British firm that manufactures solar panel cells. This firm supplies three different types of cell called:
fast, normal and ultra. There are three operations involved in the manufacturing process. The following table describes
the hours/month required to manufacture each model:
Table 1: hours/month requirements
And the following table describes the total hours available for each operation:
Operation Hours/Month
1 400
2 600
3 600
The profit per each model is specified in the following table: Table 3: Unit of profit per model
Model Profit/Unit
Normal 30
Economic 20
Luxury 40
Analysis questions
The following solution has been obtained using PuLP and the CBC solver.
The value for the overall profit is:
z = 9666.67
The following table shows the values of the decision variables and their corresponding reduced costs:
The following table shows the slack values of the constraints and their corresponding shadow prices:
Based on this solution, try to answer the following analysis questions ### Question 1 Peter Weyland believes that, for
the reputation of the company, Weyland should manufacture at least 40 ultra cells per month. If this plan goes ahead,
how would it affect the current profit?
Question 2
The engineer informed management that due to maintenance operations, the capacities of Operation 1, 2, and 3 have
changed to 360, 600 and 500 respectively. How would this affect the profit?
2.2. Exercises 89
Notebooks for Operations Research, Release I
Question 3
Mr. Weyland insisted that the company needs to change the strategy towards producing ultra-fast cells to position Weyland
Corp in this segment. The company reviewed the prices of the ultra-fast cells and changed them to 30€, 10€ and 50€
per fast, normal and ultra cells. With the new prices, would it be profitable to produce ultra-fast cells?
Question 4
What is the impact in the new profit if we opted for this new prices?
Question 5
The engineer is studying a new type of fast cells that would require 2 hours of operation 1, 0 hours of operation 2 and 1
hour of operation 3. The estimated market price is 20€. How would this affect the production plan?
Question 6
Mr. Weyland thinks that the operation time for Operation 2 for the normal cells can be cut to only 3h. How would this
improve the production plan?
Problem definition
Spellman´s Ltd is a company that manufactures chilling soft drinks. They want to manufacture two types of drinks A,
and B. Both beverages use a semi-elaborate C, another expensive ingredient D and other ingredients that are not relevant
for production planning. Sabrina is a young student of engineering and management doing an internship at Spellman´s.
She needs to formulate a Continuous Linear Program to configure the optimal daily production plan for the company.
The selling price of drink A is 3€/liter and the selling price of drink B is 2€/liter.
1 liter of drink A uses 3 grams of ingredient D. A liter of drink B uses 1 gram of ingredient D. There are only 3 grams
of ingredient D available per day.
The factory only has one mixer to elaborate both drink types and the semi-elaborate. It takes 1 hour to process a liter
of drink A, 1 hour to process 1 liter of drink B, and 1 hour to process 1cl of semi-elaborate C. The mixer is available 6
hours per day.
Drink A uses 2cl of semi-elaborate C and drink B uses 1cl of semi-elaborate C. The company has 3cl of semi-elaborate
C plus the amount they decide to produce available per day.
1. Write a Continuous Linear Problem to help Sabrina design the optimal production plan that maximises revenues for
the company.
2. Write the dual problem
3. Given the following solution:
• 0 Liters of drink A
• 3 Liters of drink B
• 3 cl of semi-elaborate C
Verify the solution. Is the solution feasible? What are the values of the slack variables?
4. Use complementary slackness to find the dual solution corresponding to this vertex. Is the dual solution feasible? Is
the solution optimal? Motivate your response
Problem II
You are the production manager of a company. You have used the following programming model to define the optimal
production plan. The problem is expressed in the standard form. Objective function:
Max z = 3X1+4X2-MA1+0S2+0S3 subject to: X1+0X2+A1+0S2+0S3=18 20X1+40X2+0A1+S2+0S3=1000
26.67X1+20X2+0A1+0S2+S3=800 *The slack variables are indexed in order of appearance.
The intern submitted the following data describing the solution obtained by a solver. This solver provides the solution of
both the primal and the dual and a sensitivity analysis in a table, but your intern handled you the following handwritten
report:
X1 -> Solution value: 18 Reduced Cost: ? Status: basic Objective coefficient: ? Objective Lower Bound: -Inf Objective
Upper Bound: 5.334
X2 -> Solution value: 15.997 Reduced Cost: ? Status: ? Objective coefficient: 4 Objective Lower Bound: 2.2497
Objective Upper Bound: Inf
A1-> RHS= 18 Slack = 0 Sense = ? Shadow price= -2.334 Min RHS= 17.9964 Max RHS= 29.9963
S2-> RHS= 1000 Slack = 0.12 Sense = less or equal Shadow price= 0 Min RHS= 999. Max RHS= Inf
S3-> RHS= ? Slack = ? Sense = less or equal Shadow price= 0 Min RHS= 480.06 Max RHS= 800.06
a. You analise the solution and notice that there are some missing values noted as ? (You are going to fire this intern!).
Write down the values missing in the solution. Motivate your response in each case
b. Which of the two decision variables has a larger contribution to the optimal solution? Motivate your response.
c. The first constraint determines the value of one of the decision variables (X1). What would happen to the objective
function if the right hand side of this constraint changes to 19? and to 31? Motivate your response
d. What would happen to the solution if the objective function coefficient of X1 changes to 5? And what if the coefficient
of X2 changes to 3? Motivate your response
[ ]:
Problem Definition
You are using a legacy software to solve a production mix Continuous Linear Programming (CLP) problem in your
company where the objective is to maximise profits. The following table provides the solution of the primal, dual and a
sensitivity analysis for the three decision variables that represent the quantities to produce of each product
Variables Solution Reduced cost Objective Coefficient Lower bound Upper bound
𝑥1 300.00 ? 30.00 24.44 Inf
𝑥2 33.33 ? 20.00 -0.00 90.00
𝑥3 0 -8.33 40.00 -Inf 48.33
2.2. Exercises 91
Notebooks for Operations Research, Release I
b. According to the provided solution, which of the three products has the highest impact in your objective function?
Motivate your response.
c. What does the model tell you about product 𝑥3 ? Is it profitable to manufacture under the current conditions modeled
in the problem? Provide quantitative values to motivate your response.
d. Recall that in this type of problem, the objective coefficient represents the marginal profit per unit of product. What
would happen if the objective function of variable 𝑥3 is increased over 50? Describe what would be the impact in the
obtained solution The following table represents the value obtained for the decision variables related to the constraints:
Constraint Right Hand Side Shadow Price Slack Min RHS Max RHS
𝑠1 400.00 6.67 0.00 300.00 525.00
𝑠2 600.00 11.67 0.00 0.00 800.00
𝑠3 600.00 0.00 166.67 433.33 Inf
Bearing in mind that the constraints represent the availability of 3 limited resources (operating time in minutes) and that
the type of constraints is in every case “less or equal” answer the following questions:
e. Which decision variables are basic? How many are there and, is this result expected? Motivate your response.
f. Imagine that you had to cut down costs by reducing the availability of the limited resources in the model. Which one
would you select? How much could you cut down without changing the production mix? Motivate your response
g. Now, with the money saved, you could invest to increase the availability of other limited resources. Again, indicate
which one would you select and by how much you would increase the availability of this resource without changing the
production mix. Motivate your response
h. How do the columns of the two tables relate to the primal and dual problem? Moreover, for each column, not
considering upper and lower bounds, write down a brief description of each column and the relationship it has with the
primal and dual problem
Problem Definition
Invincible Ltd makes two types of nutritional supplements. The recip of both supplements is based on three ingredients
for which the company has limited availability. The table below shows the daily availability of the three ingredients and
their costs:
Table 1: daily availability and cost of ingredients
The selling prices are 3€/gram for supplement Awesome (product A) and 3.5€/gram for supplement Beast (product B).
The recip must comply with the following requirements:
• Both products must contain at least 25% of ingredient 3.
• Product B must have at least 10% more of ingredient 2 than product A.
• The minimum quantity of any ingredient in any product is 10%
The factory has a production line that operates for 10 hours per day. The production speed of the line is 300 grams per
hour for product A and 175 grams per hour for product B.
Indices
We can define the following indices to express the problem in a compact form:
• i: Ingredient 𝑖 ∈ [1, 2, 3]
• j: Product 𝑗 ∈ [𝐴, 𝐵]
Decision variables
Objective Function
Constraints
2.2. Exercises 93
Notebooks for Operations Research, Release I
a Write the expressions of the missing constraints. You may use indices to write your expressions in a compact form
b Write down the objective function of the dual problem and provide an economic interpretation of the dual variables
c What is the maximum price for ingredient 3 that the company can pay without changes in the optimal solution? Motivate
your response
d The company can improve the daily capacity of the line in 1 hour for 50000€. How would this affect the profits and
how long will it take for the company to make this investment profitable, considering only the increase in the daily profits
e Is the availability of ingredient 1 a binding constraint? How would you optimise the procurement of ingredients (daily
amounts that are available) according to the provided solution?
Problem Definition
Consider the following solution to a daily production mix optimization problem where:
• The decision variables are the number of units to produce of three different types of products
• The objective function coefficients (Objective coefficient in table) are the unitary profits (difference between pro-
duction costs and sell price per unit) in euros
• The three constraint represent the total availability of three sections in minutes
Decision variables
Decision variable Solution Reduced cost Objective Coefficient Lower bound Upper bound
product 1 units 300 0 30 24.44 inf
product 2 units 33.33 0 20 -0 90
product 3 units 0 -8.33 40 -inf 48.33
Constraints
Constraint Right Hand Side Shadow Price Slack Min RHS Max RHS
Section 1 availability 400 6.67 0 300 525
Section 2 availability 600 11.67 0 0 800
Section 3 availability 600 0 166.67 433.33 inf
Answer the following questions. Motivate your response based on the provided results:
• Is it profitable to produce units of the three types of products? If any of the products is not profitable, what changes
are needed to make it profitable?
• In the actual economic context, the production costs are rising. Discuss how the rise of the production costs can
affect your profit and identify the maximum unitary production cost increase that your daily production mix can
support without changes in the base solution
• In order to increase your production capacity, you need to evaluate 2 different improvement proposals from an
external consultant. The first one considers a 12% increase of the availability of section 1, and the second a 7.5%
increase of the availability of section 2. Which one is more profitable for the company?
[ ]:
Problem Definition
Suppose you are a financial advisor at March & Sanchis Investments Ltd. and your client has €1,000,000 to invest in four
different types of assets: stocks, bonds, real estate, and crypto assets, with the Expected Returns and risk (an estimation
of the risk per euro invested) expressed in the table below:
2.2. Exercises 95
Notebooks for Operations Research, Release I
Your task is to help the client select the optimal portfolio of investments, maximizing the Expected Return. Assume that
the investments are independent and take into account the following constraints:
• Budget: The total investment cannot exceed the budget of the client (€1,000,000)
• Personal Preferences: The client wants to invest at least €200,000 in real estate due to personal interests in
owning property, and does not want to invest more than €400,000 in crypto assets as she would like to be cautious
and limit exposure.
• Risk: The overall risk estimation cannot exceed 12% of the expected return
Model this problem as a continuous linear programming problem. What are the decision variables? What is the objective
function? What are the constraints?
Problem Definition
You are an investment analyst at March & Sanchis Investments Ltd. and you need are analysing the portfolio of a customer,
based on the investment case described and solved here
A solver provides this solution:
Decision Variables:
Vari- Solution Reduced cost Objective Coeffi- Objective Lower Objective Upper
ables (GRB) (GRB) cient (GRB) bound (GRB) bound (GRB)
1 x_1 116129.03 0.00 0.10 0.08 0.12
2 x_2 0.00 -0.02 0.06 -Inf 0.08
3 x_3 483870.97 0.00 0.08 0.05 0.10
4 x_4 400000.00 0.00 0.15 0.12 inf
Constraints:
Answer the following questions and motivate all of your responses based on the data provided in the solution
• How sensitive is the solution to changes in the expected return of the different types of assets? Describe how
changes in the expected return of each asset could affect the solution.
• What is the minimum expected return of bonds that would render this asset profitable for your customer?
• Based on the solution provided, would you recommend your customer to consider increasing or decreasing the
exposure to crypto assets?
Problem definition
Chappie Ltd. has 3 production lines (A, B, and C) to make 4 different types of metal sheets of width 0.4, 05, 0.6, and 0.7
mm. The company needs to meet the monthly demand for each kind of product (in Tons) expressed in the next table:
The production lines do not have the same overall efficiency for all types of sheets. Furthermore, due to design constraints,
not all the lines are capable of manufacturing all types of sheets. The table below indicates the manufacturing costs in €
of the different products in the different lines: a dash “-“ means that it is not possible to manufacture a product in a line:
The different lines have the following capacities (in hours) in the planning period:
A B C
500 480 370
And the following table represents the manufacturing time (hours) per ton of product required for each type of metal
sheet in the different lines:
Formulate a linear programming problem to obtain the monthly production plan (quantity of metal sheet in tons
of each type of metal sheet to be manufactured in each production line)
[ ]:
2.2. Exercises 97
Notebooks for Operations Research, Release I
Spellman´s Ltd is a company that produces two types of chilling soft drinks: A, and B. Both beverages use a semi-elaborate
C, another expensive ingredient D and other ingredients that are not relevant for production planning.
The selling price of drink A is 3€/liter and the selling price of drink B is 2€/liter.
1 liter of drink A uses 3 grams of ingredient D. A liter of drink B uses 1 gram of ingredient D. There are only 3 grams
of ingredient D available per day.
The factory only has one mixer to elaborate both drink types and the semi-elaborate. It takes 1 hour to process a liter
of drink A, 1 hour to process 1 liter of drink B, and 1 hour to process 1cl of semi-elaborate C. The mixer is available 6
hours per day.
Drink A uses 2cl of semi-elaborate C and drink B uses 1cl of semi-elaborate C. The company has 3cl of semi-elaborate
C plus the amount they decide to produce every day.
The following problem model provides the optimal daily production:
Decision variables: - 𝑥𝐴 : Production of drink A in liters - 𝑥𝐵 : Production of drink B in liters - 𝑥𝐶 : Production of
semi-elaborate C in centiliters
𝑥𝐴 , 𝑥 𝐶 , 𝑥 𝐵 ∈ R
Objective function
max 𝑧 = 3 * 𝑥𝐴 + 2 * 𝑥𝐵
z is the profit in euros.
Constraints
• Availability of ingredient D in grams:
3 * 𝑥𝐴 + 𝑥𝐵 ≤ 3
• Availability of mixer in hours:
𝑥𝐴 + 𝑥𝐵 + 𝑥𝐶 ≤ 6
• Availability of semi-elaborate C in centiliters:
2 * 𝑥𝐴 + 𝑥𝐵 − 𝑥𝐶 ≤ 3
• Logical constraint
$ x_A, x_C, x_B :nbsphinx-math:`geq 0`$
A solver provides the following solution:
Optimal
Total profit is 6.00 €
The following table shows the decision variables:
j Constraint Slack Shadow Right Hand Side Min RHS Max RHS
Price
0 Availability of ingredient D (Liters) 0 2 3 0 4.5
1 Availability of mixer (hours) 0 0 6 3 inf
2 Availability of semi-elaborate (Liters) 3 0 3 0 inf
Duality
Problem Extension
1. Spellman’s Ltd wants to evaluate the possibility of subcontracting part of the production of semi-elaborate C to an
external provider, at a cost of 0.35€ per cl. With the new set-up, the daily availability of semi-elaborate C will be
the sum of the semi-elaborate C produced at Spellman’s plus the amount purchased from the new provider. What
changes are needed in the problem to evaluate the subcontracting of semi-elaborate C? (1.5 points)
Problem Description
Will Robinson and his crew are lost in space and have crashed their spaceship in an alien planet. They need to collect
metals to repair the engine of their spaceship. More specifically, the piece to repair is made of a metal alloy of chrome,
aluminium, and titanium. To build the new piece, Will needs to collect 1 kilogram of chrome, 800 grams of aluminium
and 1.5 kilograms of titanium. Will and his crew can gather these metals from 3 different mining locations they have
identified around the camp. Will has estimated the average kg/hour that can be extracted in each location:
2.2. Exercises 99
Notebooks for Operations Research, Release I
Write down a Continuous Linear Programming model to minimize the total time used to collect the materials needed to
build the part needed to fix the engine.
A gold seeker needs to find at least 2 kg of bronze and 3 kg of copper to pay his gambling debts. There are two rivers in
which the miner can find these precious metals. Each day the miner spends in river A, he finds 0.3 kg of bronze and 0.3
kg of copper while each day he spends in river B, he finds 0.2 kg of bronze and 0.4 kg of copper.
Can you help this gold seeker decide how many days to spend in each day to pay his debts as soon as possible?
Problem Model
Decision variables
𝑥𝐴 Days spent in river A
𝑥𝐵 Days spent in river B
Objective function
min 𝑧 = 𝑥𝐴 + 𝑥𝐵
Constraints
0.3 * 𝑥𝐴 + 0.2 * 𝑥𝐵 ≥ 2 Bronze constraint
0.3 * 𝑥𝐴 + 0.4 * 𝑥𝐵 ≥ 3 Copper constraint
Problem definition
“The Fog Ltd” is a modern furniture company that makes tables and chairs. The selling price of a table is 30€ and the
selling price of chairs is 10€. The carpenter at the company works up to 40 hours and needs 6 hours to make a table and
3 hours to make a chair. Customer demand requires that he makes at least 3 times as many chairs as tables. Tables take
up four times as much storage space as chairs and there is room for at most four tables each week.
What is the optimal weekly production plan that optimises revenues?
Solution
Decision variables
The decision variables in the problem is the number of chairs and tables per week to manufacture:
• 𝑥𝑇 : Number of tables per week
• 𝑥𝐶 : Number of chairs per week
Let us assume that they are both continuous, i.e: 𝑥𝑇 , 𝑥𝐶 ∈ R
Objective function
Constraints
Problem Definition
Ski Patrol Ltd. manufactures two different models of snowboards branded Normal and Deluxe with a weekly production
plan and inventory. They sell their material to local shops. The company obtains a profit of 300€ per Normal snowboard
and 400€ per Deluxe snowboard. The manufacturing process consists of roughing and polishing. The Normal snowboard
model requires 20 minutes of roughing and 2/3 minutes of polishing. The Deluxe snowboard model requires 40 minutes
of roughing and 1 minute of polishing. The roughing equipment is available for 1000 minutes per week and the polishing
equipment for 800 minutes per week. Ski Patrol has already signed a contract with a local shop called Downhill Racer to
deliver 18 Normal snowboards per week.
Ski Patrol hires you to formulate a Linear Programming Problem to help them determine the best production mix to
maximise benefits.
Write a CLP to maximise profits
Decision Variables
𝑥1 : Units of Normal snowboards per week
𝑥2 : Units of Premium snowboards per week
Objective Function
Problem Definition
Model
2𝑥1 + 𝑥2 ≤ 40
𝑥1 + 3𝑥2 ≤ 45
𝑥1 ≤ 12
2𝑥1 + 𝑥2 + 𝑠1 = 40
𝑥1 + 3𝑥2 + 𝑠2 = 45
𝑥1 + 𝑠3 = 12
The company Tetravaal located in Johannesburg manufactures two types of robots, Model 𝑃1 and Model 𝑃2 . The pro-
duction plant is consisted of four different sections: metal machining, plastic moulding, electrical work and assembly.
The metal machining section has a capacity of 7500 units of 𝑃1 or 6000 units of 𝑃2 per month.
Plastic moulding can process 5000 units of 𝑃1 or 9000 units of 𝑃2 per month.
Electrical work can process 6000 units of 𝑃1 or 7000 units of 𝑃2 per month.
In Assembly, there are two assembly lines that work in parallel, one per each robot model.
The first assembly line can process 4000 units of 𝑃1 per month
The second assembly line can process 5000 units of 𝑃2 per month
Knowing that the unitary profit of 𝑃1 is 500€ and that the unitary profit of 𝑃2 is 600€, and that both robots have a great
demand and therefore all manufactured robots are sold, Michelle Bradley, CEO of Tetravaal, asks his engineering team:
Calculate the number of units of each robot that needs to be manufactured to maximise profit for the company.
Model
Problem Definition
Din Djarin is a retired bounty hunter that now runs a small factory specialised in making classic weapons in a colony
recently re-established in Mandalore. The factory manufactures two different types of weapons, swords and spears. Din
uses special alloys, mixtures of metals and rare materials, which have made a name for the endurance of his weapons
across the colony. The table below shows the weight in pounds of each material needed to make each type of weapon:
And the table below shows the total amount of each metal available, also in pounds:
Metal Amount
Beskar 125
Tungsten 225
Titanium 300
The price of a spade is 40 credits and the price of a sword is 5 credits. Din has already sold 100 swords, so he needs to
manufacture at least that many.
Find the optimal number of spades and swords that maximise revenues
Model
The objective is to maximise the revenues obtained with the sales of both types of weapons. The objective function can
be modeled as:
max 𝑧 = 40𝑥1 + 5𝑥2
where z represents the objective variable (profits) and the decision variables are:
• 𝑥1 : units of spears
• 𝑥2 : units of swords
Let us for now consider that they are real and non-negative.
The objective function is subject to the following constraints:
Metal availability constraints:
𝑥1 + 0.5𝑥2 ≤ 125
𝑥1 + 𝑥2 ≤ 225
3𝑥1 + 𝑥2 ≤ 300
And the demand on swords:
𝑥2 ≥ 100
Problem Definition
Duff Beer is an american brewery that sells alcoholic beverages worldwide. Duff beer has a very large market share in
the US. One of the new business lines of Duff Beer is in the craft beer sector. Duff beer buys 3 types of wort from local
suppliers. The availability of wort (in liters) and the price for each of them is specified in Table 1.
Table 1: daily availability and cost of wort
The blend of the three types of wort must comply with the following quality requirements:
• For Beer Angels, no less than 60% of Type 3 and no more of 20% of Type 2. The price of one bottle of Beer
Angel is 4.10€s/liter.
• For Beer Beast, no less than 15% of Type 3 and no more than 60% of Type 2. The price of one bottle of Beer
Beast is 2.80€s/liter.
• For Beer Cactus, no more than 50% of type 2. The selling price is 2.45€/liter.
Write a linear program to find the most profitable blend of wort to elaborate the three kinds of beers
Problem Model
Indices
We can define the following indices to express the problem in a compact form: - i: wort type 𝑖 ∈ [1, 2, 3] - j: Beer brand
𝑗 ∈ [𝐴, 𝐵, 𝐶] where A notes Angels, B notes Beast, and C notes Cactus
Decision variables
Objective Function
Constraints
Or
′
, 𝑗′
∑︀
𝑥𝑖′ 𝑗 ′ ≥ 𝑅𝑚𝑖𝑛𝑖′ 𝑗′ * 𝑖 (𝑥𝑖𝑗 ′ )∀𝑖
If we take the denominator to the RHS. We can obtain a similar expression for the maximum proportion 𝑅𝑚𝑎𝑥𝑖′ 𝑗′ :
𝑥𝑖′ 𝑗 ′ ≥ 𝑅𝑚𝑎𝑥𝑖′ 𝑗′ * 𝑖 (𝑥𝑖𝑗 ′ )∀𝑖′ , 𝑗 ′
∑︀
From these expressions, we can derive the constraints for every type of beer:
Angels quality requirement constraints
𝑥3𝐴 ≥ 0.6(𝑥1𝐴 + 𝑥2𝐴 + 𝑥3𝐴 )
𝑥2𝐴 ≤ 0.2(𝑥1𝐴 + 𝑥2𝐴 + 𝑥3𝐴 )
Beast quality requirement constraints
𝑥3𝐵 ≥ 0.15(𝑥1𝐵 + 𝑥2𝐵 + 𝑥3𝐵 )
𝑥2𝐵 ≤ 0.6(𝑥1𝐵 + 𝑥2𝐵 + 𝑥3𝐵 )
Cactus quality requirement constraints
𝑥2𝐶 ≤ 0.5(𝑥1𝐶 + 𝑥2𝐶 + 𝑥3𝐶 )
Problem definition
The Kahuna company manufactures sausages using three kinds of meat. The relevant information about the ingredients
is provided in the table below:
The company makes two types of sausages: * Economy (>=40% Pork) * Premium (>=60% Pork)
One sausage is 50 grams (0.05 kg)
According to government regulations, the most starch we can use in our sausages is 25%
We have a contract with a butcher, and have already purchased 23 kg pork, that will go bad if it’s not used.
We have a demand for 350 economy sausages and 500 premium sausages.
Write a linear program to figure out how to most cost effectively blend our sausages.
Let’s model our problem
pe + we + se = 350 * 0.05
pp + wp + sp = 500 * 0.05
pe ≥ 0.4(pe + we + se)
pp ≥ 0.6(pp + wp + sp)
se ≤ 0.25(pe + we + se)
sp ≤ 0.25(pp + wp + sp)
pe + pp ≤ 30
we + wp ≤ 20
se + sp ≤ 17
pe + pp ≥ 23
Problem Definition
Harry Stamper is an engineer working on a petroleum company. The company produces three grades of motor oil –
super, premium, and extra. The three grades are made from the same 3 ingredients, named component 1, component 2
and component 3. The company wants to determine the optimal mix of the 3 components in each grade of motor oil that
will maximize profit.
The maximum availability of each component and their cost per barrel are as follows:
To ensure the appropriate blend, each grade must have a minimum amount of component 1 plus a combination of other
components as follows:
The company wants to make at least 3000 barrels of each blend. Formulate an LP to help Harry Stamper find the optimal
blend that maximises profit.
Problem Model
Constraints
• Which is the total profit obtained by the company with the Extra grade with the solution provided by the solver?
Just multiply the value of every basic (non-zero) decision variable times the objective function coefficient.
• Which is the maximum value that the profit per barrel of component 2 in the Extra grade can take without changing
the base of the optimal solution?
The profit per barrel of component two in the extra grade is 8.00 (look at the second last row of the first table). The
maximum value that it can take is the upper bound of the objective function in that row, which is 25. The profit per barrel
of component 2 could change from 8.00 to 25 without changing the base. Since there are no changes in the constraint,
there are no changes in the feasible region and the optimal solution will be the same point and same quantities. Therefore,
if we were able to raise the profit by 1 eur per barrel of component 2 in extra grade, the total profit (objective function)
will increase 12000 (because this is the quantity of this component in the extra grade in the optimal solution).
• If the cost of the barrel of component 3 increased 1€, will the optimal composition change? Motivate your response
In this case an increase of the cost of barrel of component 3 means that the profit per component 3 in the three grades
is going to decrease by 1 eur. Since the lower bound of the profit per component 3 in the “Super” grade is equal to the
objective function coefficient, there will be a change in the optimal composition.
• Do we use every barrel available of every component in the optimal solution? Or do we have any surplus availability
for any component? Motivate your response
If we look at the components availability, we can clearly see that we have a slack of 1700 barrels of component 3.
• The provider of Component 2 may have a problem with the delivery and the availability may be reduced in 400
barrels. Will this shortage affect the optimal composition? Motivate your response*
If the component 2 is short in 4000 barrels (from 2700 to 2300) the availability will still be higher than the lower bound
of the component 2 available constraint which is 2250, so this shortage in principle will not affect the optimal solution.
• Grace wants to use the results to renegotiate the terms and conditions with the suppliers of the different components.
Which component is a better candidate to increase the availability? How would you use the model to negotiate new
terms with the provider, assuming you do not want any change in the base of the optimal solution? Motivate your
response
Now, this is a quite an interesting question. If we were to increase the availability, we can first discard component 3,
because we have the aforementioned slack, which means that we are not using all the available material, so the candidates
are component 1 and 2. Now, comparing both components, component 1 has a much larger shadow price, which means
that for every change of one unit on the right hand side, we will have an increase of 20 eur in the profit. So this is
definitively the best candidate. We could try to negotiate the terms and conditions and try to tell the provider that we
want more units of this component. We could use up to 6200 units (upper right hand side) without changes in the optimal
composition. Now, since we are buying more units, we may as well ask for a lower price. If we look at the profits of
component 1 in the first table, we could increase the profits of Premium, component 1 by 3 euros (from 8 to 11 which is
the upper bound) so we could try to renegotiate the price from 12 down to 9.
Problem I
You have read an article about the benefits of fasting. This article publishes a series of findings around the fasting diet
method. Specifically, the article states that:
• Decreasing the number of meals to three, two heavier meals and a light meal in between has significant benefits for
the health
• The study reveals that the optimal amount of daily calories for an adult is higher than 1800
• and also lower than 2200 calories
• The study also reveals that the light meal should not represent more than 10% of the number of daily calories
• And that the last meal should not provide more than 700 calories
You think you can design a Linear Programming Problem where the decision variables represent the calories of each
meal to find and optimal diet that fulfils all these requirements, while at the same time provide the maximum number of
calories. For such a model, define:
a. The objective function
Maximise the calories intake in the three mails:
𝑚𝑎𝑥𝑧 = 𝑥1 + 𝑥2 + 𝑥3
where: - 𝑥1 : Calories of first meal
• 𝑥2 : Calories of second meal (light meal)
• 𝑥3 : Calories of third meal
b. The constraints Now, given the results of the study:
Optimal daily amount
𝑥1 + 𝑥2 + 𝑥3 ≥ 1800
𝑥1 + 𝑥2 + 𝑥3 ≤ 2200
Calories of light meal (less than 10% of total calories):
𝑥2 ≤ 0.1(𝑥1 + 𝑥2 + 𝑥3 )
Calories of third meal (less than 700):
𝑥3 ≤ 700
c. The dual problem
We can write the problem as:
max 𝑧 = 𝑥1 + 𝑥2 + 𝑥3
s.t.
𝑥1 + 𝑥2 + 𝑥3 ≥ 1800
𝑥1 + 𝑥2 + 𝑥3 ≤ 2200
−0.1·𝑥1 + 0.9·𝑥2 − 0.1·𝑥3 ≤ 0
0·𝑥1 + 0·𝑥2 + 1·𝑥3 ≤ 700
Hence, the dual becomes:
min 𝑧 = 1800·𝑢1 + 2200·𝑢2 + 0·𝑢3 + 700·𝑢4
s.t
𝑢1 + 𝑢2 − 0.1 * 𝑢3 + 0·𝑢4 ≥ 1
𝑢1 + 𝑢2 + 0.9·𝑢3 + 0·𝑢4 ≥ 1
𝑢1 + 𝑢2 − 0.1·𝑢3 + 𝑢3 ≥ 1
Since the primal is a maximisation problem, 𝑢1 ≤ 0 because the first constraint is of type ≥. On the other hand,
𝑢2 , 𝑢3 , 𝑢4 ≤ 0 because the rest of constraints are of type ≤.
Problem definition
Problem Definition
Weyland Corp is a British firm that manufactures solar panel cells. This firm supplies three different types of cell called:
fast, normal and ultra. There are three operations involved in the manufacturing process. The following table describes
the hours/month required to manufacture each model:
Table 1: hours/month requirements
And the following table describes the total hours available for each operation:
Table 2: Total hours/month available
Operation Hours/Month
1 400
2 600
3 600
The profit per each model is specified in the following table: Table 3: Unit of profit per model
Model Profit/Unit
Fast 30
Normal 20
Ultra 40
Problem Model
Decision variables
Objective Function
Constraints
Solution
The following solution has been obtained using PuLP and the Gurobi solver.
Total profit is 9666.67 €
The following table shows the values of the decision variables, the reduced costs and the sensitivity analysis of the objective
coefficients:
The following table shows the slack and shadow prices of the constraints, together with a sensitivity analysis of the RHS:
Constraint Right Hand Side Shadow Price Slack Min RHS Max RHS
0 Operation_1 400 6.67 0 300 525
1 Operation_2 600 11.67 0 0 800
2 Operation_3 600 0 166.67 433.33 inf
Question 1
Peter Weyland believes that, for the reputation of the company, Weyland should manufacture at least 40 ultra cells per
month. If this plan goes ahead, how would it affect the current profit?
In the current optimal solution, ultra cells are not part of the solution and therefore using resources to manufacture this
type of cells will decrease the profits. The reduced costs for ultra cells are -8.33, meaning that the profits are going to
decrease 8.33 for every extra cell that is manufactured. Therefore, 40 extra units of ultra would lower the profits: 333.33
Question 2
The engineer informed management that due to maintenance operations, the capacities of Operation 1, 2, and 3 have
changed to 360, 600 and 500 respectively. How would this affect the profit?
We need to analyse the cases one by one. Regarding operation 1, the slack is 0 and the shadow price is 6.67, meaning that
having 1 unit less will lower the profits 6.67€. The minimum RHS is 300, which is lower than 360 and therefore there is
no change in the basic solution. With this, A decrease of 40 units will cause a decrease in the budget of 266.67€.
There is no impact on the capacity of Operation 2, the RHS is still 600.
Operation 3 has a slack of 166.67, which is higher than the 100 decrease due to maintenance operations, so there will be
no impact on the profits.
Question 3
Mr. Weyland insisted that the company needs to change the strategy towards producing ultra fast cells to position Weyland
Corp in this segment. The company reviewed the prices of the ultra fast cells and changed them to 30€, 10€ and 50€
per fast, normal and ultra cells. With the new prices, would it be profitable to produce ultra fast cells?
We need to verify the bounds for the objective coefficients for the three variables, case by case.
For fast cells, there is no change in the price.
For normal cells, the new price of 10€ is higher than the lower bound of the solution, therefore, there will be no change
caused by these decrease.
For ultra cells, the new price is over the maximum lower price, so this change will cause a change in the basic solution:
Using the tableau we can verify that the entering variable is the ultra cell and conclude that it is profitable to produce ultra
fast cells with the new prices.
Question 4
What is the impact in the new profit if we opted for this new prices?
We need to define the new problem and solve it. Using PuLP and CBC, the solution obtained is: - Total profit is 10000.00
€ per month
Therefore, the profit would change in 333.33 € per month
Question 5
The engineer is studying a new type of fast cells that would require 2 hours of operation 1, 0 hours of operation 2 and 1
hour of operation 3. The estimated market price is 20€. How would this affect the production plan?
We need to define a new problem model to introduce the new standard cell type and solve it. The following solution has
been obtained with PuLP and Gurobi.
The total profit is 10000.00 € per month
The following tables show the values obtained:
Decision Variable Solution value Unit profit Reduced cost Lower bound Upper bound
0 cells_fast 300 30 0 23.3333 inf
1 cells_normal 0 20 -10 -inf 30
2 cells_standard 50 20 0 13.3333 60
3 cells_ultra 0 40 -10 -inf 50
Question 6
Mr. Weyland thinks that the operation time for Operation 2 for the normal cells can be cut to only 3 hours per cell. How
would this improve the production plan?
This will mean a change in a LHS coefficient of a constraint, we would need to build a new model with this new coefficient
and solve it again with a solver.
Problem definition
Spellman´s Ltd is a company that manufactures chilling soft drinks. They want to manufacture two types of drinks A,
and B. Both beverages use a semi-elaborate C, another expensive ingredient D and other ingredients that are not relevant
for production planning. Sabrina is a young student of engineering and management doing an internship at Spellman´s.
She needs to formulate a Continuous Linear Program to configure the optimal daily production plan for the company.
The selling price of drink A is 3€/liter and the selling price of drink B is 2€/liter.
1 liter of drink A uses 3 grams of ingredient D. A liter of drink B uses 1 gram of ingredient D. There are only 3 grams
of ingredient D available per day.
The factory only has one mixer to elaborate both drink types and the semi-elaborate. It takes 1 hour to process a liter
of drink A, 1 hour to process 1 liter of drink B, and 1 hour to process 1cl of semi-elaborate C. The mixer is available 6
hours per day.
Drink A uses 2cl of semi-elaborate C and drink B uses 1cl of semi-elaborate C. The company has 3cl of semi-elaborate
C plus the amount they decide to produce available per day.
1. Write a Continuous Linear Problem to help Sabrina design the optimal production plan that maximises revenues for
the company.
Decision variables: - 𝑥𝐴 : Production of drink A in liters - 𝑥𝐵 : Production of drink B in liters - 𝑥𝐶 : Production of
semi-elaborate C in centiliters
𝑥𝐴 , 𝑥 𝐶 , 𝑥 𝐵 ∈ R
Objective function
max 𝑧 = 3 * 𝑥𝐴 + 2 * 𝑥𝐵
z is the profit in euros.
Constraints s.t.
• Availability of ingredient D in grams:
3 * 𝑥𝐴 + 𝑥𝐵 ≤ 3
• Availability of mixer in hours:
𝑥𝐴 + 𝑥𝐵 + 𝑥𝐶 ≤ 6
• Availability of semi-elaborate C in centiliters:
2 * 𝑥𝐴 + 𝑥𝐵 − 𝑥𝐶 ≤ 3
• Logical constraint
$ x_A, x_C, x_B :nbsphinx-math:`geq 0`$
2. Write the dual problem The dual is:
min 𝑧 = 3 * 𝑢1 + 6 * 𝑢2 + 3 * 𝑢3
s.t.
3 * 𝑢1 + 𝑢2 + 2 * 𝑢3 ≥ 3
𝑢1 + 𝑢2 + 𝑢3 ≥ 2
𝑢2 − 𝑢3 ≥ 0
3. Given the following solution:
• 0 Liters of drink A
• 3 Liters of drink B
• 3 cl of semi-elaborate C
Verify the solution. Is the solution feasible? What are the values of the slack variables?
We plug in the values of the solution in our constraints: - Availability of ingredient D in grams:
3 * 𝑥𝐴 + 𝑥𝐵 ≤ 3
3*0+3≤3
3 + 𝑠1 = 3
𝑠1 = 0
• Availability of mixer in hours:
𝑥𝐴 + 𝑥𝐵 + 𝑥𝐶 ≤ 6
0+3+3≤6
6 + 𝑠2 = 6
𝑠2 = 0
• Availability of semi-elaborate C in centiliters:
2 * 𝑥𝐴 + 𝑥𝐵 − 𝑥𝐶 ≤ 3
2*0+3−3≤3
0 + 𝑠3 = 3
𝑠3 = 3
• Logical constraint
$ s_1, s_2, s_3 :nbsphinx-math:`geq 0`$
The solution is feasible because it meets all constraints and slack variables are non-negative.
4. Use complementary slackness to find the dual solution corresponding to this vertex. Is the dual solution feasible? Is
the solution optimal? Motivate your response.
By complementary slackness, since 𝑠3 = 3, we know that 𝑢3 = 0, and also, since 𝑥𝐶 is greater than zero, we know that
the third constraint of the dual is binding. By plugging this information into the third constraint we obtain:
𝑢2 − 𝑢3 = 0
𝑢2 = 0
We can plug this value into the second constraint of the dual, which is also binding since 𝑥𝐵 is non-zero, to obtain:
𝑢1 + 𝑢2 + 𝑢3 = 2
𝑢1 = 2
All values are non-negative, so the solution is feasible and since both primal and dual are feasible, the solution is optimal.
Gurobi provides the following solution:
Optimal
Total profit is 6.00 €
The following table shows the decision variables:
j Constraint Slack Shadow Price Right Hand Side Min RHS Max RHS
0 Availability_of_ingredient_A 0 2 3 0 4.5
1 Availability_of_mixer_hours 0 0 6 3 inf
2 Availability_of_semi_elaborate 3 0 3 0 inf
Problem Definition
You are the production manager of a company. You have used the following programming model to define the optimal
production plan. The problem is expressed in the standard form. Objective function:
max 𝑧 = 3 * 𝑥1 + 4 * 𝑥2 − 𝑀 * 𝑎1 + 0 * 𝑠2 + 0 * 𝑠3
s.t
𝑥1 + 0 * 𝑥2 + 𝑎1 + 0 * 𝑠2 + 0 * 𝑠3 = 18
20 * 𝑥1 + 40 * 𝑥2 + 0 * 𝑎1 + 𝑠2 + 0 * 𝑠3 = 1000
26.67 * 𝑥1 + 20 * 𝑥2 + 0 * 𝑎1 + 0 * 𝑠2 + 𝑠3 = 800
where M is a very large number and artificial and slack variables are indexed in order of appearance.
The intern submitted the following data describing the solution obtained by a solver. This solver provides the solution of
both the primal and the dual and a sensitivity analysis in a table, but your intern handled you the following handwritten
report:
X1 -> Solution value: 18 Reduced Cost: ? Status: basic Objective coefficient: ? Objective Lower Bound: -Inf Objective
Upper Bound: 5.334
X2 -> Solution value: 15.997 Reduced Cost: ? Status: ? Objective coefficient: 4 Objective Lower Bound: 2.2497
Objective Upper Bound: Inf
A1-> RHS= 18 Slack = 0 Sense = ? Shadow price= -2.334 Min RHS= 17.9964 Max RHS= 29.9963
S2-> RHS= 1000 Slack = 0.12 Sense = less or equal Shadow price= 0 Min RHS= 999. Max RHS= Inf
S3-> RHS= ? Slack = ? Sense = less or equal Shadow price= 0 Min RHS= 480.06 Max RHS= 800.06
a. You analise the solution and notice that there are some missing values noted as ? (You are going to fire this intern!).
Write down the values missing in the solution. Motivate your response in each case.
For decision variable 𝑥1 Since the value is non-zero (it is a basic decision variable), by complementary slackness, the
reduced cost is 0. The objective function indicates that the objective coefficient is 3.
For decision variable 𝑥1 Also, by complementary slackness, the reduced cost is 0 and since the value is greater than zero,
the decision variable is basic.
For slack, 𝑎1 If we note the coefficient in the objective function, (-M) we know that this is an artificial variable that must
be always 0 and the sense is ‘equal’.
For 𝑠3 , The Right Hand Side for the third constraint is 800 looking at the problem.
We can calculate the slack by substituting the values of X1 and X2 in the expression:
26.67X1+20X2+0A1+0S2+S3=800 26.67·18 + 20·15.997 + S3 = 800 S3 = 0
We could have also argued that since the solution is a Feasible Basic Solution, only 3 decision variables (in this case X1,
X2, and S2) can be basic (as many as constraints) and therefore S3 must be non-basic (0).
b. Which of the two decision variables has a larger contribution to the optimal solution? Motivate your response (1 point).
If we multiply the value times the objective function:
3·𝑥1 = 3·18 = 54
4·𝑥2 = 4·15.997 = 63.998
Clearly 𝑥2 has a larger contribution to the objective function
c. The first constraint determines the value of one of the decision variables (𝑥1 ). What would happen to the objective
function if the right hand side of this constraint changes to 19? and to 31? Motivate your response
The maximum RHS for the first constraint is 29.993. If the RHS changes to 19, the basic decision variables would remain
the same, although the values in the optimal solution might change. If the value changes to 31 then the basic decision
variables would certainly change.
d. What would happen to the solution if the objective function coefficient of X1 changes to 5? And what if the coefficient
of X2 changes to 3? Motivate your response
The Upper bound for the objective coefficient of 𝑥1 is 5.334 and therefore, the solution would not change if the objective
5 increased to 5.
The lower bound for the objective coefficient of 𝑥2 is 2.2497 and therefore, the solution would not change if the coefficient
decreases down to 3.
Problem Definition
You are using a legacy software to solve a production mix Continuous Linear Programming (CLP) problem in your
company where the objective is to maximise profits. The following table provides the solution of the primal, dual and a
sensitivity analysis for the three decision variables that represent the quantities to produce of each product
Variables Solution Reduced cost Objective Coefficient Lower bound Upper bound
𝑥1 300.00 ? 30.00 24.44 Inf
𝑥2 33.33 ? 20.00 -0.00 90.00
𝑥3 0 -8.33 40.00 -Inf 48.33
Constraint Right Hand Side Shadow Price Slack Min RHS Max RHS
𝑠1 400.00 6.67 0.00 300.00 525.00
𝑠2 600.00 11.67 0.00 0.00 800.00
𝑠3 600.00 0.00 166.67 433.33 Inf
Bearing in mind that the constraints represent the availability of 3 limited resources (operating time in minutes) and that
the type of constraints is in every case “less or equal” answer the following questions:
e. Which decision variables are basic? How many are there and, is this result expected? Motivate your response
The basic decision variables are 𝑥1 , 𝑥2 , and 𝑠3 , as many basic decision variables as constraints, since this is a Feasible
Basic Solution (FBS).
f. Imagine that you had to cut down costs by reducing the availability of the limited resources in the model. Which one
would you select? How much could you cut down without changing the production mix? Motivate your response
If the Right Hand Sides represent availability of resources, we could reduce the availability of the third constraint in 166.7
units (slack) without any change in the base.
g. Now, with the money saved, you could invest to increase the availability of other limited resources. Again, indicate
which one would you select and by how much you would increase the availability of this resource without changing the
production mix. Motivate your response
The best option is to invest in the resource of the second constraint, since it has the largest shadow price. The RHS can
increase up to 800 units without a change in the base.
h. How do the columns of the two tables relate to the primal and dual problem? Moreover, for each column, not
considering upper and lower bounds, write down a brief description of each column and the relationship it has with the
primal and dual problem
In the first table, the column solution contains the values of the decision variables of the primal and the column reduced
costs represents the slack variables of the dual. In the second table, the column slack represents the values of the slack
variables in the primal solution and the column shadow prices, represent the values of the decision variables of the dual.
Problem Definition
Invincible Ltd makes two types of nutritional supplements. The recip of both supplements is based on three ingredients
for which the company has limited availability. The table below shows the daily availability of the three ingredients and
their costs:
Table 1: daily availability and cost of ingredients
The selling prices are 3€/gram for supplement Awesome (product A) and 3.5€/gram for supplement Beast (product B).
The recip must comply with the following requirements:
• Both products must contain at least 25% of ingredient 3.
• Product B must have at least 10% more of ingredient 2 than product A.
Indices
We can define the following indices to express the problem in a compact form: - i: Ingredient 𝑖 ∈ [1, 2, 3]
• j: Product 𝑗 ∈ [𝐴, 𝐵]
Decision variables
Objective Function
Constraints
a Write the expressions of the missing constraints. You may use indices to write your expressions in a compact form
The minimum quantity of any ingredient in any product is 10%, this means that the quantity of ingredient i in product j
must be at least 10% of the total amount of ingredients used for product j, which is the sum of the three ingredients:
𝑥𝑖𝑗 ≥ 0.1 * (𝑥1𝑗 + 𝑥2𝑗 + 𝑥3𝑗 ) ∀𝑖, 𝑗
As for the production capacity constraint, let us express the production speed for product j 𝑣𝑗 as the ratio between the
quantity of product j produced and the production time of product j, 𝑡𝑗 in hours:
grams of product j 𝑥1𝑗 +𝑥2𝑗 +𝑥3𝑗
𝑣𝑗 = production hours j = 𝑡𝑗
Now, the problem states that the production speeds are 𝑣𝐴 = 300 grams/hour and 𝑣𝐵 = 175 grams/hour. The problem
also states that the production time available is 10 hours, that is:
𝑡𝐴 + 𝑡𝐵 ≤ 10
Plugging in the expressions for the speeds and the values given yields:
𝑥1𝐴 +𝑥2𝐴 +𝑥3𝐴 𝑥1𝐵 +𝑥2𝐵 +𝑥3𝐵
300 + 175 ≤ 10
b Write down the objective function of the dual problem and provide an economic interpretation of the dual variables
The objective coefficients of the dual are the same as the RHS of the primal and are given in the RHS column given by
the solver:
min 𝑧* = 1500 * 𝑢1 + 1300 * 𝑢2 + 2000 * 𝑢3 + 10 * 𝑢12
• 𝑢1 : Shadow price of the availability of constraint 1 (non-negative). It indicates the increase in the objective function
per every additional gram of ingredient 1.
• 𝑢2 : Shadow price of the availability of constraint 1 (non-negative). It indicates the increase in the objective function
per every additional gram of ingredient 2.
• 𝑢3 : Shadow price of the availability of constraint 1 (non-negative). It indicates the increase in the objective function
per every additional gram of ingredient 3.
• 𝑢4 : Shadow price of the quality requirement that the quantity of ingredient 3 must be higher than 25% in product
A (non-positive). It indicates the decrease in the objective function if the required amount of ingredient 3 increases
• 𝑢5 : Shadow price of the quality requirement that the quantity of ingredient 3 must be higher than 25% in product
B (non-positive). It indicates the decrease in the objective function if the required amount of ingredient 3 increases
• 𝑢6 − 𝑢11 : Shadow price of the quality requirement that the quantity of any ingredient in any product must be
higher than 10% (non-positive). It indicates the decrease in the objective function if the minimum amount required
increases
• 𝑢12 : Shadow price of the production line capacity constraint (non-negative) It indicates the increase in the objective
function for any additional hour of production capacity in the line
c What is the maximum price for ingredient 3 that the company can pay without changes in the optimal solution? Motivate
your response
The coefficient of 𝑥3𝐴 can decrease at most 14€ cents (from 1.75 to 1.61 euros) without changing the optimal solution.
Since this coefficient is the price of product A minus the cost of ingredient 3, this is the maximum increase in the price
of ingredient 3 without changes in the optimal solution. Thus, the maximum price is 139€cents.
d The company can improve the daily capacity of the line in 1 hour for 50000€. How would this affect the profits and
how long will it take for the company to make this investment profitable, considering only the increase in the daily profits
The daily profits would increase in 512.58 euros. The company would need:
50000
512.8 = 97.5
operation days to return this investment with the additional profits obtained
e Is the availability of ingredient 1 a binding constraint? How would you optimise the procurement of ingredients (daily
amounts that are available) according to the provided solution? (2 points)
The constraint is binding because the slack is zero. The company can reduce the availability of ingredient 2 in 811.67
grams and the availability of ingredient 3 in 1269.42 grams
Problem Definition
Consider the following solution to a daily production mix optimization problem where:
• The decision variables are the number of units to produce of three different types of products
• The objective function coefficients (Objective coefficient in table) are the unitary profits (difference between pro-
duction costs and sell price per unit) in euros
• The three constraint represent the total availability of three sections in minutes
Decision variables
Decision variable Solution Reduced cost Objective Coefficient Lower bound Upper bound
product 1 units 300 0 30 24.44 inf
product 2 units 33.33 0 20 -0 90
product 3 units 0 -8.33 40 -inf 48.33
Constraints
Constraint Right Hand Side Shadow Price Slack Min RHS Max RHS
Section 1 availability 400 6.67 0 300 525
Section 2 availability 600 11.67 0 0 800
Section 3 availability 600 0 166.67 433.33 inf
Answer the following questions. Motivate your response based on the provided results:
• Is it profitable to produce units of the three types of products? If any of the products is not profitable, what changes
are needed to make it profitable?
• In the actual economic context, the production costs are rising. Discuss how the rise of the production costs can
affect your profit and identify the maximum unitary production cost increase that your daily production mix can
support without changes in the base solution
• In order to increase your production capacity, you need to evaluate 2 different improvement proposals from an
external consultant. The first one considers a 12% increase of the availability of section 1, and the second a 7.5%
increase of the availability of section 2. Which one is more profitable for the company?
Solution
• Is it profitable to produce units of the three types of products? If any of the products is not profitable, what changes
are needed to make it profitable?
Since the reduced cost of product 3 is negative, it is not profitable to produce product 3. To make it profitable, the objective
coefficient of product 3 should be increased to at least 48.33.
• In the actual economic context, the production costs are rising. Discuss how the rise of the production costs can
affect your profit and identify the maximum unitary production cost increase that your daily production mix can
support without changes in the base solution
If the production costs increase, we can increase the selling costs ensuring that the resulting unitary profits is within the
lower and upper bounds of the objective function coefficients. Note that in this case, product 2 provides the smaller margin
to modify the selling price, since the difference between the upper and lower bounds is 90.
We might also consider keeping the selling price constant, and analyze the difference between the objective coefficient and
its lower bound to see how much the production costs can increase. In this case, product 1 provides the smaller margin
to increase the production costs, since the difference between the objective coefficient and its lower bound is 30 - 24.44
= 5.56.
• In order to increase your production capacity, you need to evaluate 2 different improvement proposals from an
external consultant. The first one considers a 12% increase of the availability of section 1, and the second a 7.5%
increase of the availability of section 2. Which one is more profitable for the company? (1 point)
Let us first consider the first proposal. The new availability of section 1 is 400 * 1.12 = 448. The new capacity is within
the Minimum and Maximum values for the RHS, so this change is not going to change the base solution. The objective
function is going to increase proportionally to the shadow price of section 1, which is 6.67. Therefore, the profit is going
to increase by 6.67 * 400 * 0.12 = 6.67 * 48 = 320.16€.
In the second proposal, on the other hand, the new availability of section 2 is 600 * 1.075 = 645. The new capacity is
within the Minimum and Maximum values for the RHS, so this change is not going to change the base solution either.
The objective function is going to increase proportionally to the shadow price of section 2, which is 11.67. Therefore, the
profit is going to increase by 11.67 * 45 = 525,15€.
Therefore, the second proposal is more profitable for the company.
You are an investment analyst at March & Sanchis Investments Ltd. and you need are analysing the portfolio of a customer,
based on the investment case described and solved here
A solver provides this solution:
Decision Variables:
Vari- Solution Reduced cost Objective Coeffi- Objective Lower Objective Upper
ables (GRB) (GRB) cient (GRB) bound (GRB) bound (GRB)
1 x_1 116129.03 0.00 0.10 0.08 0.12
2 x_2 0.00 -0.02 0.06 -Inf 0.08
3 x_3 483870.97 0.00 0.08 0.05 0.10
4 x_4 400000.00 0.00 0.15 0.12 inf
Constraints:
Answer the following questions and motivate all of your responses based on the data provided in the solution
• How sensitive is the solution to changes in the expected return of the different types of assets? Describe how
changes in the expected return of each asset could affect the solution.
• What is the minimum expected return of bonds that would render this asset profitable for your customer?
• Based on the solution provided, would you recommend your customer to consider increasing or decreasing the
exposure to crypto assets?
2.3.18 Solution
For the sake of clarity, and as a reminder, the decision variables are: - 𝑥1 : amount to invest in stocks - 𝑥2 : amount to
invest in bonds - 𝑥3 : amount to invest in real estate - 𝑥4 : amount to invest in crypto assets
• How sensitive is the solution to changes in the expected return of the different types of assets? Describe how
changes in the expected return of each asset could affect the solution.
Changes in the market can cause the expected return of the different types of assets to change. The lower and upper
bounds of the Objective coefficient provide the range of values of the expected return of each asset that would not change
the basic solution (meaning that the resulting profit would change, but not the optimal amount to invest in each asset). For
example, if we pay attention to the specific values, the expected return of stocks can increase by 0.02 (from 0.10 to 0.12)
or decrease by 0.02 (from 0.10 to 0.08) without changes in the optimal solution. This represents a change of +/- 20% in
the expected return of bonds, which is a significant change.
Overall, we get the following ranges: - Stocks: -20% decrease, and +20% increase - Bonds: unlimited decrease, and
+33.33% increase - Real estate: -37.5% decrease, and +25% increase - Crypto assets: -20% decrease, and unlimited
increase
The optimal solution is more sensitive to changes in the expected return of stocks and real state, and less sensitive to
changes in the expected return of bonds and crypto assets. In general, the ranges obtained in percentage are wide, and
we can conclude that the solution is not particularly sensitive to changes in the expected return of the different types of
assets.
• What is the minimum expected return of bonds that would render this asset profitable for your customer?
Currently, we can note that it is not profitable to invest in bonds, as the reduced cost is negative (-0.02), and the solution
is zero. We should increase the expected return of bonds until the reduced cost is positive, which would mean that the
solution is no longer zero. The minimum expected return of bonds that would render this asset profitable for the customer
is therefore 0.08.
• Based on the solution provided, would you recommend your customer to consider increasing or decreasing the
exposure to crypto assets?
The shadow price of crypto assets is positive, meaning that it would be profitable for our customer to increase the exposure
to crypto assets. The shadow price is 0.03, which means that for every additional euro invested in crypto assets, the profit
would increase by 0.03 euros. We could increase the exposure up to the maximum right hand side of the constraint, which
is 464285.71 euros without changes in the base solution.
Problem definition
Chappie Ltd. has 3 production lines (A, B, and C) to make 4 different types of metal sheets of width 0.4, 05, 0.6, and 0.7
mm. The company needs to meet the monthly demand for each kind of product (in Tons) expressed in the next table:
The production lines do not have the same overall efficiency for all types of sheets. Furthermore, due to design constraints,
not all the lines are capable of manufacturing all types of sheets. The table below indicates the manufacturing costs in €
of the different products in the different lines: a dash “-“ means that it is not possible to manufacture a product in a line:
The different lines have the following capacities (in hours) in the planning period:
A B C
500 480 370
And the following table represents the manufacturing time (hours) per ton of product required for each type of metal
sheet in the different lines:
Formulate a linear programming problem to obtain the monthly production plan (quantity of metal sheet in tons
of each type of metal sheet to be manufactured in each production line)
indexes
i: Manufacturing lines (A,B,C)
j: Product types Sheet (0.4, 0.5, 0.6, 0.7) mm
Decision Variables
𝑥𝑖𝑗 = Quantity of product 𝑗 to produce in line 𝑖
**Objective function Minimize cost
min 𝑧 = 𝑖 𝑗 𝑐𝑖𝑗 * 𝑥𝑖𝑗
∑︀ ∑︀
where 𝑐𝑖𝑗 is the cost of manufacturing product 𝑗 in line 𝑖 as expressed in the second table.
Constraints Capacity
Where 𝑎𝑖𝑗 represent the manufacturing time required to manufacture product 𝑗 in line 𝑖 as expressed in the last table and
b_{i} represents the capacity of line i for the planning period
Demand
∑︀
𝑖 𝑥𝑖𝑗 >= 𝑑𝑗 , ∀𝑗
Spellman´s Ltd is a company that produces two types of chilling soft drinks: A, and B. Both beverages use a semi-elaborate
C, another expensive ingredient D and other ingredients that are not relevant for production planning.
The selling price of drink A is 3€/liter and the selling price of drink B is 2€/liter.
1 liter of drink A uses 3 grams of ingredient D. A liter of drink B uses 1 gram of ingredient D. There are only 3 grams
of ingredient D available per day.
The factory only has one mixer to elaborate both drink types and the semi-elaborate. It takes 1 hour to process a liter
of drink A, 1 hour to process 1 liter of drink B, and 1 hour to process 1cl of semi-elaborate C. The mixer is available 6
hours per day.
Drink A uses 2cl of semi-elaborate C and drink B uses 1cl of semi-elaborate C. The company has 3cl of semi-elaborate
C plus the amount they decide to produce every day.
The following problem model provides the optimal daily production:
Decision variables: - 𝑥𝐴 : Production of drink A in liters - 𝑥𝐵 : Production of drink B in liters - 𝑥𝐶 : Production of
semi-elaborate C in centiliters
𝑥𝐴 , 𝑥 𝐶 , 𝑥 𝐵 ∈ R
Objective function
max 𝑧 = 3 * 𝑥𝐴 + 2 * 𝑥𝐵
z is the profit in euros.
Constraints
• Availability of ingredient D in grams:
3 * 𝑥𝐴 + 𝑥𝐵 ≤ 3
• Availability of mixer in hours:
𝑥𝐴 + 𝑥𝐵 + 𝑥𝐶 ≤ 6
• Availability of semi-elaborate C in centiliters:
2 * 𝑥𝐴 + 𝑥𝐵 − 𝑥𝐶 ≤ 3
• Logical constraint
$ x_A, x_C, x_B :nbsphinx-math:`geq 0`$
A solver provides the following solution:
Optimal
Total profit is 6.00 €
The following table shows the decision variables:
j Constraint Slack Shadow Right Hand Side Min RHS Max RHS
Price
0 Availability of ingredient D (Liters) 0 2 3 0 4.5
1 Availability of mixer (hours) 0 0 6 3 inf
2 Availability of semi-elaborate (Liters) 3 0 3 0 inf
Duality
Problem Extension
1. Spellman’s Ltd wants to evaluate the possibility of subcontracting part of the production of semi-elaborate C to an
external provider, at a cost of 0.35€ per cl. With the new set-up, the daily availability of semi-elaborate C will be
the sum of the semi-elaborate C produced at Spellman’s plus the amount purchased from the new provider. What
changes are needed in the problem to evaluate the subcontracting of semi-elaborate C? (1.5 points)
Decision variables: We need to introduce a new decision variable:
• 𝑥𝐶𝑠𝑢𝑏 : Amount of semi-elaborate C purchased from the new provider
Objective function The objective function will also change to include the cost of purchasing the semi-elaborate C:
max 𝑧 = 3 * 𝑥𝐴 + 2 * 𝑥𝐵 − 0.35 * 𝑥𝐶𝑠𝑢𝑏
Constraints The new constraint to evaluate the availability of semi-elaborate C will be:
2 * 𝑥𝐴 + 𝑥𝐵 − 𝑥𝐶 − 𝑥𝐶𝑠𝑢𝑏 ≤ 3
The availability of the mixer constraint will also change to include the production of the semi-elaborate C purchased from
the new provider:
𝑥𝐴 + 𝑥𝐵 + 𝑥𝐶 + 𝑥𝐶𝑠𝑢𝑏 ≤ 6
And obviously, the logical constraint will also change to include the new decision variable:
$ x_A, x_C, x_B, x_{C_{sub}} :nbsphinx-math:`geq 0`$
Problem Description
Will Robinson and his crew are lost in space and have crashed their spaceship in an alien planet. They need to collect
metals to repair the engine of their spaceship. More specifically, the piece to repair is made of a metal alloy of chrome,
aluminium, and titanium. To build the new piece, Will needs to collect 1 kilogram of chrome, 800 grams of aluminium
and 1.5 kilograms of titanium. Will and his crew can gather these metals from 3 different mining locations they have
identified around the camp. Will has estimated the average kg/hour that can be extracted in each location:
Write down a Continuous Linear Programming model to minimize the total time used to collect the materials needed to
build the part needed to fix the engine.
Decision Variables:
Let 𝑥1 , 𝑥2 , and 𝑥3 be the number of hours spent in each location (1, 2, and 3) respectively. 𝑥1 , 𝑥2 , and 𝑥3 are continuous
variables (non-negative real numbers).
Objective Function:
Minimize the total time spent collecting the materials:
min 𝑧 = 𝑥1 + 𝑥2 + 𝑥3
Constraints: Ensure that the amount of each metal collected is enough to build the part needed to fix the engine:
• Chrome (kg):
0.1𝑥1 + 0.05𝑥2 + 0.02𝑥3 ≥ 1
• Aluminium (Kg):
0.3𝑥1 + 0.2𝑥2 + 0.15𝑥3 ≥ 0.8
• Titanium (Kg):
0.05𝑥1 + 0.1𝑥2 + 0.2𝑥3 ≥ 1.5
Likewise, we could define the matrix 𝐴 containing the coefficients of the constraints and the vector 𝑏 containing the
right-hand side of the constraints, and the vector 𝑐 containing the coefficients of the objective function as follows:
⎡ ⎤
0.1 0.05 0.02
𝐴 = ⎣ 0.3 0.2 0.15⎦
0.05 0.1 0.2
⎡ ⎤
1
𝑏 = ⎣0.8⎦
1.5
⎡ ⎤
1
𝑐 = ⎣1⎦
1
The problem model can be written as:
min 𝑧 = 𝑐𝑇 𝑥
subject to:
𝐴𝑥 ≥ 𝑏
⎡ ⎤
𝑥1
Where 𝑥 = ⎣𝑥2 ⎦
𝑥3
Try me
Requirements
Pip Installation
The simplest way to install PuLP in your environment is using pip. If you have installed Python and pip in your environ-
ment, just open a terminal and try:
Conda Installation
Run the following code cell to try this notebook in Google Colabs:
Binder installation
In this tutorial, we will learn to model and solve Linear Programming Problems using the Python open source Linear
Programming library PuLP.
To guide this example, we will use a simple LPP formulated in class:
maximise 𝑧 = 300𝑥 + 250𝑦
Subject to:
2𝑥 + 𝑦 ≤ 40
𝑥 + 3𝑦 ≤ 45
𝑥 ≤ 12
In Pulp this problem can be solved with the following code cell:
[3]: # Let s start importing the library PuLP to solve linear programs
import pulp
Code Explanation
The next sections explain step by step the main functions involved in the code above and how they work together to solve
a CLP problem.
PuLP uses classes providing different methods to model and solve LPPs. The class that will contain our model is the
LpProblem class. To create a new LpProblem we use the pulp LpProblem function:
• LpProblem(name=’None’, sense=1): Creates a new Linear Programming Problem. The parameter name (default
‘None’) assigns a name to the problem. The parameter sense (either [Link] or [Link]) sets
the type of objective function. The default is minimise.
So, the line code:
Created a problem called “Production_Mix_example” and set the objective function to maximise.
The definition of a LPP program with PuLP is very similar to the standard procedure used to model a problem. First,
we need to define the unknown variables in our problem. For this purpose we use the class LpVariable. The function
LpVariable allows us to create a variable:
• LpVariable(name, lowBound=None, upBound=None, cat=’Continuous’, e=None): Creates an instance of
variable with the following properties:
– Name: The name of the variable to be used in the solution.
– lowBoud: The lower bound of the variable, the default is unsrestricted (-Inf).
– upBound: The upper bound of the variable. The default is unrestricted (Inf).
– cat: Either ‘Continuous’ for continuous variables, ‘Binary’ for binary variables or ‘Integer’ for Integer variables.
We will see in detail binary and integer variables in the course unit for Mixed Integer Programming, but now
you know that you will be able to model and solve this type of problems with PuLP. The default is ‘Continuous’.
– e: This parameter is outside the scope of this course and can be neglected for now.
We can define the variables of our problem using the LpVariable function:
Note that we have created two variables, x and y, with lower bound 0 and type continuous. We could have also use
upBound to set the upper bound of the variables. For instance, if we wanted to set the upper bound of x to 12, we could
have used this parameter.
Adding expressions
In PuLP, both objective function and constraints are expressions (algebraic expressions containing variables) that have
to be added to the instance problem using the standard operand ‘+=’. For instance, to add the objective function in this
example, we could write:
With this line of code, we have added a new expression with name “Profit” that multiplies the technological coefficients
to the variables x and y (as defined in the code snippet in the previous section).
Note that we have used the operand ‘+=’ to add the expression to the model variable. We can use the same procedure
to add the constraints:
Note that we added names to the constraints. This is not mandatory, but it is a good practice to do so. Note also that we
needed one line of code per constraint. This is not a problem for this simple example, but it can be a problem for more
complex problems. We will see how to solve this issue in the next section.
Once we have defined the problem, we can solve it using the solve method of the LpProblem class:
Note that we have not specified any solver. PuLP will use the default solver (CBC) to solve the problem. We will see in
next chapters how to use other solvers.
Once the problem has been solved, we can check the status of the solution using the LpStatus method of the LpProblem
class:
[Link][[Link]]
Once the problem has been solved, we can retrieve the solution using the varValue method of the LpVariable class:
print([Link])
In this section, we will see how to make PuLP programs more scalable. We will use some Python basic concepts related
to iterables. You can check these tutorials if you need a refresher:
• Basic Python Iterators
• Intermediate Python Iterators
Note however that if we use the script above, the problem just does not scale up because we need a line of code for
every unknown. What if we have hundreds of unknowns? Luckily for us, PuLP provides a convenient method to write
more efficient codes for our program, the [Link] method, which basically allows us to create a set of variables
with the same category, upper bounds and lower bounds at once:
• [Link](name, index, lowBound=None, upBound=None, cat=’Continuous’): Creates a dictionary
containing variables of type cat (default ‘Continuous’), indexed with the keys contained in the iterable index and
bounded by lowBound (default -Inf) and upBound (default Inf).
For instance, we can define our variables using the [Link] method like this:
Note that we used a tuple with the variable names to create both variables in a single line of code. If we had 20 variables,
we could have used a tuple with the 20 variable names and created all the variables in a single line of code. This is a much
more scalable way to create variables in PuLP!
Using lpSum
We can also use the lpSum function to create linear expressions from a vector of variables, just as we can use summations
to express the objective function and constraints in a more compact mathematical form. For instance, we can write the
objective function like this:
𝐶 = [𝑐1 , 𝑐2 ] = [300, 250]
𝑋 = [𝑥1 , 𝑥2 ]
max 𝑧 = 300𝑥1 + 250𝑥2 =
∑︀
𝑗=1 2𝑐𝑗 * 𝑥𝑗
PuLP provides a convenience function named lpSum to achieve the same result efficiency. lpSum takes an array of
expressions and returns the summation of the elements in the array. Let us see it action:
Notice that we have used list comprehension to create the array where every element is the product of a coefficient times
the corresponding decision variable, and passed this array to the lpSum function using an index array. We have used
range and length to go through all decision variables.
We can also use matrices and arrays to define the constraints of the problem. For instance, we can write the constraints
of the problem like this:
⎡ ⎤ ⎡ ⎤
𝑎11 𝑎12 2 1
𝐴 = ⎣𝑎21 𝑎22 ⎦ = ⎣1 3⎦
𝑎31 𝑎32 1 0
⎡ ⎤ ⎡ ⎤
𝑏1 40
𝑏 = ⎣𝑏2 ⎦ = ⎣45⎦
𝑏3 12
∑︀2
𝑗=1 𝑎𝑖𝑗 * 𝑥𝑗 ≤ 𝑏𝑖 ∀𝑖
In Python, we can achieve the same compactness defining the coefficients of the constraints in of a matrix, the LHS
coefficients in a vector, and use a for loop to add the constraints to the model:
# And vector b
b = [40, 45, 12] #limits of the three constraints
for i in range(len(A)):
model += [Link]([
A[i][j] * X[variable_names[j]]
for j in range(len(variable_names))]) <= b[i] , constraint_names[i]
Here we just put all data in iterables, and used a for loop to add the constraints to the model. This is a much more scalable
way to add constraints to a model!
Let’s put everything together and solve the problem:
# We use the function lpSum to generate the linear expression from the coeeficients␣
˓→and variables
model += (
[Link]([
coefficients[i] * X[variable_names[i]]
for i in range(len(X))])
), "Profit"
# And vector b
b = [40, 45, 12] #limits of the three constraints
for i in range(len(A)):
model += [Link]([
A[i][j] * X[variable_names[j]]
for j in range(len(variable_names))]) <= b[i] , constraint_names[i]
˓→ _
Pandas is a great library to manipulate tables. You can find a basic tutorial here.
We can use Pandas to display the solution in a nice table. First we need to import Pandas:
import pandas as pd
We are also going to use the library display to show styled output using Markdown notation.
Now, let us display the solution in a nice table using Pandas. We are going to first display the solution value using
markdown and then we will use Pandas to create a table with the results.
[12]: # We are going to use panda to display the results as tables using Panda
import pandas as pd
#And we will use numpy to perform array operations
import numpy as np
#We will use display and Markdown to format the output of code cells as Markdown
from [Link] import display, Markdown
# Solution
max_z = [Link]([Link])
#We use display and Mardown to show the value using markdown
display(Markdown("The value of the objective function is **%.2f**"%max_z))
# place the different values provided by the solver in the data frame.
var_df = [Link].from_dict(X, orient="index",
columns = ["Variables"])
# First we add the solution. We apply a lambda function to get only two decimals:
var_df["Solution"] = var_df["Variables"].apply(lambda item: "{:.2f}".
˓→format(float([Link])))
#Now we add columns for the solution, the slack and shadow price
Analysis questions
1. Search for the exercise “The Good Carpenter” and try to model it.
2. Ask an AI assistant to model the problem and to provide a Python script to solve it. You can use this sample prompt:
Provide the problem model and a Python script using PuLP to solve the problem definition below assuming
that decision variables are continuous: [Copy the problem definition from the exercise “The Good Carpenter”
here]
3. Try the solution provided by the AI assistant. Does it work?
4. Is the solution provided by the AI assistant scalable? If the answer is not, ask it to provide a solution that is more
scalable and explain its solution, using the following prompt template:
The Python script provided does not scale up well if the number of decision variables or the number of
constraints increase. Can you provide a more scalable solution using PulP? Please describe the changes you
made and motivate why
Did the AI assistant use the same methods explained in this tutorial?
5. Ask the assistant to use the problem you provided as an example to demonstrate how indices, summations, and
“for all” expressions can make mathematical models more compact and scalable. Also, ask the assistant if these
mathematical expressions are conceptually similar to the PuLP functions used in the scalable solution.
Solved exercises
The following notebooks include exercises solved with PuLP, using different solvers, do not forget to check them out!
• Making Chappie solved with CBC
• Blending problem solved with CBC
• Blending Craft Beer solved with CBC
• Blending Craft Beer solved with GRB
• Chappie II solved with CBC
• Manufacturing solar cell panels solved with CBC
• Manufacturing solar cell panels solved with GRB
Try me
Requirements
Scipy Installation
The simplest way to install SciPy in your environment is using pip. If you have installed Python and pip in your environ-
ment, just open a terminal and try:
Conda Installation
Binder installation
In this tutorial, we will learn to model and solve Linear Programming Problems using the Python open source scientific
library Scipy. SciPy is an awesome library extensively used for scientific and technical computing. It is built on top of
NumPy and provides a wide range of functionality including optimization, signal processing, interpolation, and more.
It also contains modules for linear algebra, optimization, and integration. SciPy is widely used in the scientific and
engineering communities and is a powerful tool for data analysis and visualization.
In this tutorial, we will learn how to use SciPy to model and solve CLP problems. Just as with the previous tutorial, to
guide this example, we will use a simple CLP formulated in class:
maximise 𝑧 = 300𝑥 + 250𝑦
Subject to:
2𝑥 + 𝑦 ≤ 40
𝑥 + 3𝑦 ≤ 45
𝑥 ≤ 12
[10]: # Let s start importing the linprog function of the optimize package of SciPy
from [Link] import linprog
# We are going to use panda to display the results as tables using Panda
import pandas as pd
#And we will use numpy to perform array operations
import numpy as np
#We will use display and Markdown to format the output of code cells as Markdown
from [Link] import display, Markdown
The function linprog of the Scipy package can be used to solve continuous linear programming problems expressed
in the form:
min 𝑧 = 𝑐𝑇 * 𝑥
s.t.
𝐴𝑢𝑏 * 𝑥 ≤ 𝑏𝑢𝑏
𝐴𝑢𝑐 * 𝑥 = 𝑏𝑢𝑐
𝑙≤𝑥≤𝑢
Where 𝑥 is a (column) vector with the decision variables, 𝑐 is a (column) vector with the objective function coefficients,
𝑧 is the objective variable (scalar), 𝐴𝑢𝑏 is a matrix with the LHS coefficients of the constraints of type less or equal, and
𝑏𝑢 𝑏 is a vector that contains the corresponding RHS coefficients of the same constraints, and finally, 𝐴𝑢𝑐 is a matrix with
the LHS coeffients of type equal, and 𝑏𝑢 𝑏 is a vector that contains the corresponding RHS coefficients.
This means that we need to convert our problem to comply with the format expected by linprog. In our example, we
can convert the objective function as:
min 𝑧* = −𝑧 = −300 * 𝑥 − 250𝑦 = [−300, −250]𝑇 * [𝑥, 𝑦]
That is, since our objective function is of type maximize, we use the equivalent minimization problem and the solution will
be the negative of our original objective variable. As for the constraint, we need to express all the constraint (except the
bounds) as of type less_or_equal. In our case, we do not need to apply any transformation, and our matrix 𝐴𝑢𝑏 becomes:
⎡ ⎤
2 1
𝐴𝑢𝑏 = ⎣1 3⎦
1 0
Note that the each rows correspond to a constraint, therefore, the vector 𝑏𝑢𝑏 is:
𝑏𝑢𝑏 = [40, 45, 12]𝑇
Now, 𝑙 is going to contain the minimum values of the decision variables, or lower bound. Since both variables need to
be non-negative:
𝑙 = [0, 0]
and finally, 𝑢 is going to contain the maximum values or upper bound, since x cannot be higher than 12, the upper bounds
are:
𝑢 = [12, ∞]
Note that the upper bound for x is already expressed in the third constraint. We could remove this constraint and just use
the upper bound, but this make it more difficult to obtain the shadow prices from the solution, so for now, we will use this
formulation.
linprog function
The documentation of linprog can be found here, but in short, it takes the following arguments:
linprog (c, A_ub=None, b_ub=None, A_eq=None, b_eq=None, bounds=None, method=’highs’)
• c: 1-D array containing the coefficients of the linear objective function to be minimized.
• A_ub: 2-D array (optional). The inequality constraint matrix. Each row of A_ub specifies the coefficients of a
linear inequality constraint on x.
• b_ub: 1-D array (optional). The inequality constraint vector. Each element represents an upper bound on the
corresponding value of A_ub @ x.
• A_eq: 2-D array (optional). The equality constraint matrix. Each row of A_eq specifies the coefficients of a linear
equality constraint on x.
• b_eq: 1-D array (optional). The equality constraint vector. Each element of A_eq @ x must equal the correspond-
ing element of b_eq.
• bounds: sequence: (optional). A sequence of (min, max) pairs for each element in x, defining the minimum and
maximum values of that decision variable. Use None to indicate that there is no bound. By default, bounds are (0,
None) (all decision variables are non-negative). If a single tuple (min, max) is provided, then min and max will
serve as bounds for all decision variables.
• method: string (optional). This is the method-specific documentation for ‘highs’, which chooses automatically
between ‘highs-ds’ and ‘highs-ipm’. ‘interior-point’ (default), ‘revised simplex’, and ‘simplex’ (legacy) are also avail-
able.
[11]: # objective coefficient vector
c = [Link]([-300, -250])
# Inequality constraints LHS matrix
A = [Link]([[2, 1], [1, 3], [1, 0]])
# Inequality constraints RHS
b = [Link]([40, 45, 12])
(continues on next page)
#Bounds for x
x_bounds = (0, None) # Here we may as well use 12 as upper bound, but then, we need␣
˓→to read the marginal of the upper bound to learn the shadow price!
# Bounds for y
y_bounds = (0, None)
print([Link])
Now, let us display the solution in a nice table using Pandas. We are going to first display the solution value using
markdown and then we will use Pandas to create a table with the results.
display(var_df)
solution coefficients reduced costs
x 12.0 300 0.0
y 11.0 250 0.0
Solved exercises
THREE
This chapter covers basic theoretical and practical aspects of Mixed integer Programming (MIP) both theoretical and
practical topics related to Continuous Linear Programming (CLP) and Network Theory using Python. Like, Continuous
Linear Programming, MIP uses linear equations to model optimization problems. However, some of the decision vari-
ables can only take Integer values. Feasible solutions are no longer found at vertices of the feasibility region, and this
fundamental fact drastically increases the complexity of MIP problems. Network Theory provides a framework rather
useful to solve MIP problems, and therefore it is also introduced in this course. CLP allows us to model, solve and analyse
the solution of optimization problems using linear equations. “The world is not linear” but still, CLP is a really powerful
tool to solve a plethora of real world optimisation problems.
3.1 Tutorials
Introduction
Combinatorial optimization gathers different types of optimization problems where the decision maker needs to select an
alternative from a finite set of possible alternatives with different outcomes, given a set of requirements (i.e. constraints).
Some examples of problems in combinatorial optimization are:
• Grouping: Find a subset of members within a set that optimizes an objective function (e.g. minimises costs or
maximises profits) given a set of constraints. For instance, select the best starting 11 in a football team given their
performance statistics.
• Ordering: Find the optimal ordering of the members of a set that maximise or minimise an objective function
with some constraints. For instance the optimal sequence of production orders that minimises production time.
• Assignment: Assign members of a set to members of another set to optimise an objective function given a set of
constraints. For instance, assign tasks to employees at a minimum cost
Combinatorial optimization is strongly connected with set theory and the concept of search, or (iteratively) explore the
set to find the optimal solution. Heuristics will explore the set of alternatives looking for the optimal solution.
The following types of problems are outstanding instances of combinatorial optimization problems:
• Integer Programming: Any Linear Programming Problems with Integer or binary variables. When this happens,
the feasibility region and objective function are no longer convex, and we cannot apply the same principles and
methods as with CLP. When we combine Integer, Binary and Continuous variables, we are dealing with Mixed
147
Notebooks for Operations Research, Release I
Integer Programming (MIP). MIP covers a wide range of OR problems, which we will be covering extensively in
this unit.
• Travelling salesman problems: In the classic formulation of the Travelling Salesman Problem (TSP), a salesman
needs to visit a set of cities and wants to find the optimal route that would take him through all cities and back to
his/her original departure city. Thus, given a list of cities and the distances between each pair of cities, the TSP
aims to determine what is the shortest possible route that visits each city and returns to the origin city. The TSP
is thus an ordering problem. There are many OR problems, specially in logistics and manufacturing that can be
modeled as TSP.
• Knapsack problems: In knapsack problems, given a set of items, each with a weight and a value, we need to
determine the number of each item to include in a collection so that the total value is maximised while the total
weight is less than or equal than the maximum weight the knapsack can hold.
• Minimum Spanning tree: Minimum Spanning Trees (MST) problems have a wide number of applications in
fields like logistics or telecommunications when we deal with networks that interconnect different objects or edges
through vertices. In this context, MST are grouping problems where we want to find a subset of edges in a graph
that interconnects certain vertices at a minimum cost. We will address MST problems, among others, in Network
Theory.
As you can already imagine by now, there is a really wide range of applications for combinatorial optimization. Some
examples are Planning and Scheduling of activities, product and process design, portfolio selection, networking and
routing (Internet traffic, airlines routes, logistics).
Types of techniques
Given the importance of the field, scientist have developed many techniques to solve combinatorial optimization problems
over the years. They can be classified into the following categories:
• Numeric Techniques: Numeric techniques gather algorithms that provide an optimal solution by exploring all
possible options. The simplest example is brute force, although there are many other algorithms that fall into
this category. Whenever you use numeric functions like Python´s Numpy to compute a minimum, maximum, or
ordering of a set, internally the library is applying a numeric technique to compute the result. As we will soon
see, for problem instances where the set is large, it might not be computationally efficient to rely solely on numeric
techniques, and that is why we have other methods. Numeric techniques are out of the scope of this unit.
• Problem-solving heuristics: These techniques find a (sub-)optimal solution in a given number of steps. We will
focus on some of these techniques in this unit. Some examples are:
– State space search: These algorithms test successive combinations (or states) of the decision variables itera-
tively, in such a way that at every step the solution is closer to the optimal solution, until the optimum solution
is found. One example of search heuristic is the Branch and Bound algorithm that will be covered in this unit.
– Greedy algorithms: Greedy algorithms first sort the members of the set according to their impact in the
objective function, and add them to the solution iteratively.
– Genetic algorithms: Explore the possible solutions combining the features of an initial set of possible solu-
tions, selecting the fittest candidates to combine their features in the next iteration.
• Graph Theory: Graph theory is not really a type of technique, but rather, a separate field of mathematics dedicated
to the study of relations between objects through mathematical structures known as graphs. Many combinatorial
optimization problems can be easily modeled through these structures, and there are many efficient algorithms that
effectively compute graph-like structures to find MSTs or shortest paths which provide the optimal solution to our
problem.
148 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Efficiency of Techniques
But why do we need this plethora of techniques in the first place? The main reason is that it is not feasible to use numeric
techniques in relatively large instances of problems, because the number of possible combinations grows exponentially
with the number of members in the sets. The image below, taken from Dynamic logic by Harel et al., 2000 highlights
this fact:
As shown in the graph, for relatively medium instances of combinatorial optimization problems like Integer Programming,
the time required to explore all possible combinations might be larger than time itself! We need techniques that need
fewer operations to find an optimal solution, or that at least can provide a suboptimal solution in a given interval of time.
Not all techniques provide results in the same number of operations, that is, not all techniques are equally efficient. An
informal definition of an efficient algorithm is an algorithm in which the time required to solve a problem instance does
not increase too fast as the problem size increases. Below, there is a formal definition of efficiency:
An algorithm is efficient (good, polynomial ) if the time necessary to solve any instance of input size L is
bounded above by a polynomial function of L. (Thus it does not increase as fast as an exponential function
such as 2𝐿 .)
The Big O Notation is very handy to compare the efficiency of algorithms. For instance, an algorithm that solves a problem
of size 𝐿 in a time proportional to the square of 𝐿 is a polynomial algorithm in 𝒪(𝑛2 ), where as an algorithm that solves
the same problem in an exponential time proportional to 2𝐿 is noted as 𝒪(2𝐿 ). The latter is less efficient because the time
required to solve the problem increases faster as 𝐿 becomes larger. An important consideration that needs to be made at
this point is that efficiency does not explicitly mention the number of operations, but rather the computing time. This has
different implications. The first is that algorithms are formulated in mathematical language, and we need a computing
model to translate operations into computational time. In complexity theory, which is the field of mathematics dedicated
to the analysis of the complexity of problems, the Turing Machine, which is a mathematical model of a “perfect” machine
is used to define time as a function of the number of operations in the definitions above of efficiency above.
Based on this definition of a computational machine model, problems can be classified according to their complexity, in
a classification or taxonomy of problems.
Based on the definitions above, a problem is as complex as the most efficient algorithm devised to solve it. An algorithm
is considered efficient if it can solve an instance of a problem of input size L in a polynomial function of L. But what
about other problems? Are there different categories of complex problems? Complexity theory is a field of mathematics
that focuses precisely on the analysis of the complexity of problems, and its findings help scientist guide the search for
new algorithms and mathematical techniques. The following sections describe the different problem classes, which are
categories defined for problems according to their complexity.
A problem is in the class P (or polynomially solvable) if it admits a polynomial algorithm. This category gathers all
problems for which we have found an algorithm which is able to find an efficient algorithm, able to solve it in a number
of operations which is a polynomial function of the size of the problem.
A problem is in the class non-deterministic polynomial (NP) if the problem can be verified in polynomial time, meaning
that we can find a bound for the optimal solution in polynomial time. Think for instance of a maximization problem,
if we can find an upper bound for the objective function in polynomial time, we might not know which is the optimal
solution, but we can already use this information in our problem, as we know that the optimal value will not exceed the
upper bound.
From this, we can define the associated decision problem as a problem that allows us to verify if a given number is a
valid bound for our problem. If the result of the associated decision problem is True (meaning, yes, the provided number
is a valid bound), then we can use this information to provide an approximation to the optimal solution.
Problems for which there is an algorithm that solves the associated decision problem in polynomial time are classified as
NP problems.
Class Non-deterministic Polynomial time Hard - Class NP-Hard (Possibly Hard Problems)
Reduction
To understand the NP-Hard category, we first need to introduce the concept of reduction. A reduction is basically an
algorithm that allows us to convert an instance of a problem A into instances of another problem B. That is, we can
use problem B to simulate and possibly fin ##### Formal definition Formally, a problem H is NP-Hard if there is a
Polynomial algorithm to reduce every problem L in class NP to it.
Let us use the following figure to illustrate this:
150 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
If a problem L can be reduced to H in polynomial time, and we can find a solution for H using an algorithm B in one unit
of time, then we can solve L in polynomial time with an algorithm A which basically reduces L to H and then uses B to
solve the problem.
The Traveling Salesman Problem (TSP) is an example of an NP-Hard problem.
Informal definition
Based on the definition above, we can argue that NP-Hard problems are at least as hard as the hardest NP problem, since
we can reduce every problem in NP to it in polynomial time, it follows that algorithms for NP-Hard problems are at least
as efficient as algorithms for NP problems.
Try me
Problem definition
Ordering is not as simple as it seems. Ordering an array of length N implies finding the right sequence of elements out of
N! possible sequences. The exclamation mark is the factorial operator, and this makes the size of the problem increase
really fast with N. To illustrate how fast, just try this script, it will represent the number of possible orderings of a set of
N elements for N from 1 to 10:
[3]: import numpy as np
from [Link] import factorial
from matplotlib import pyplot as plt
from datetime import datetime
import ipywidgets as widgets
from ipywidgets import interactive
#We set the mode inline of matplotlib to get the result at the output of the cell code
%matplotlib inline
152 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Complexity
Informally, complexity relates to how complex it is to solve a problem. Conceptually, this can be estimated by the number
of operations that the computer has to do find a solution. We can assume that in a computer, the time used to do an
operation is more or less constant, so we are going to estimate the complexity by measuring the time used to solve the
problem. To do this, we are going to use the datetime library of Python. This library allows us to take a reference
of the time at the beginning of the execution of a piece of code and another reference at the end of the execution. The
difference between the two references is the time used to execute the code.
Let us see this in action using the library Numpy. First, using the function [Link]() we are going to generate
a random ordering of an array of numbers. Then, we will use the function [Link]() to order the array, and using the
datetimefunction as described above, we are going to measure the time used to sort the array with [Link]():
[4]: N = 10
# Let s generate an array of 10 numbers
x = [Link](0,N)
# Let s change the order of the numbers randomly
[Link](x)
#print(x)
#now, Let s take a reference of the time before sorting
init_time = [Link]()
# Let s sort, note that the right ordering sequence is 1 out of n!
y = [Link](x)
#Let s take another reference of the time after sorting and measure the
#difference in seconds:
end_time = [Link]()
duration = end_time - init_time
print(f"all righty, i ordered the array in {[Link]} microseconds")
# print(y)
all righty, i ordered the array in 0 microseconds
Note that, in the result saved in the notebook, it only took a fraction of a second to order an array of 10 numbers! Ok,
but what happens if we increase the size of the problem? Let’s use the same function to generate arrays of different sizes
and measure how the time used to order them increases with the size of the problem:
# Do the steps in the scripts above for every size in the array n
for i in range(len(n)):
arr_length=n[i]
x_arr = [Link](0,arr_length)
(continues on next page)
This simple script shows that the time needed by the sorting algorithm used by Numpy can be approximated to a linear
function of the size of the set N. This is a very efficient algorithm!
It is not only efficient, also mesmerizing, in the following video you can see it in action:
154 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
We can agree that this problem is not complex, because we have an algorithm that solves it easily. But what would happen
if we did not have this algorithm at hand? Imagine that we have to try for instance all the possible orderings of an array
of numbers to find the right one. This is called brute force. How many operations would we have to do? Let’s try to
estimate it.
Let us assume, that we could generate an ordering and check it, really fast, in one microsecond.
How many orderings would we have to check? Well, we have N! possible orderings, so we would have to do N! operations.
We can use the following script to estimate the computing time needed to solve the problem using brute force, and compare
it with the computing time needed by the sorting algorithm of Numpy:
Wow, what happened here? The time needed to solve the problem using brute force is so big that it is not even visible in
the plot! This is because the factorial function grows so fast that it is not possible to represent it in a number in Python.
By comparison, the time needed by the sorting algorithm is negligible. We could try to plot in a log scale to see the
difference:
156 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Wow, it is still impossible to visualize both functions in the same plot! Now in log scale, the brute force solution is
a straight line, and the sorting algorithm is more or less constant. This means that the time needed by the brute force
algorithm grows exponentially with the size of the problem. Since the time needed by the sorting algorithm increases
linearly with the size of the array to sort, we can conclude that the algorithm is very efficient. In fact, every algorithm that
has a complexity that grows slower than any polynomial is considered efficient, and it is called a polynomial algorithm.
In this case, the sorting algorithm is a linear algorithm, and sorting an array of is a polynomial (or class P) problem.
Analysis questions
Try to answer the following analysis questions. You can use AI assistant to help you, but try to answer them by yourself
first and analyze critically the answers given by the AI assistant.
1. How many microseconds have you lived? Try to find an estimate of the number of microseconds you have lived,
and express it as a factorial number. Based on the results of the previous section, what is the largest array you could
sort using brute force in your whole life (assuming that you can check an ordering in one microsecond)?
2. Repeat the previous exercise, but now think of the number of microseconds that have passed since the big bang.
What is the largest array you could sort using brute force since the big bang (also assuming that you can check an
ordering in one microsecond?
3. The experiments above might not be accurate, because we provided too few values of N. Modify this line of code n
= [10, 100, 1000, 100000] to include more values of N, and repeat the analysis. What do you observe?
4. Note that the time needed by the sorting algorithm might not be exactly constant. Why would you modify the script
to deal with this issue?
Genetic algorithms explore the possible solutions using a method inspired in natural selection. The fundamental compo-
nents of natural selection are the ability to encode information related to the characteristics of individuals into chromo-
somes and genes, allowing individuals to mix this information in pairs (by breeding) so that the next generation inherits
features of both parents, also introducing some mutations so that these new individuals may also have unique features.
Then, selection will select only the fittest individuals to produce the next generation. Genetic Algorithms can be used to
solve a wide range of problems, including Mixed Integer Programming.
158 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Try me
Introduction
Sudoku is a very popular japanese game invented in the 70s. Basically, the objective is to fill in a grid of 9x9 cells with
digits, so that in each column, in each row and in each 3x3 grid there is exactly one digit from 1-9. The following image
shows an example of a Sudoku puzzle.
Requirements
You need to install Numpy in your Python Kernel runtime. Install Numpy if you are running on Binder or you do not
have Numpy install in your system:
Evolutionary algorithms are a family of algorithms that are inspired by the process of natural selection. The main idea is
to represent the solution of the problem as a mathematical object called a genome, and to combine different genomes to
generate new ones. The genomes that are more fit to the problem are more likely to be selected to generate new genomes,
and the process is repeated until a solution is found, or a maximum number of iterations is reached. These are the main
steps of an evolutionary algorithm:
• Initialization: Generate an initial set of genomes. We will call this set the population.
• Evaluation: Evaluate the fitness of each genome in the population.
• Selection: Select the genomes that are more fit to the problem.
• Crossover: Combine the selected genomes to generate new genomes.
• Mutation: Mutate the new genomes.
• Termination: Check if the termination criteria is met. If not, go to step 2.
Evolutionary algorithms are very flexible, and well-fitted to solve many combinatorial optimization problems. They are
also very easy to implement, and they do not require a deep knowledge of the problem to be solved to achieve good results.
However, they are not very efficient, and they are not guaranteed to find the optimal solution.
You can find a slightly more extended explanation of Genetic algorithms in this tutorial
One of the main advantages of genetic algorithms is that we do not need to have a priori an in-depth knowledge of the
problem, we can use simple rules or heuristics to generate the genome of each iteration, and let the fitness function select
the fittest alternative. The simplest way to model the Sudoku as a combinatorial optimization problem would be to regard
the solution as a permutation of the missing digits. For instance, if we look at the solution of the example above:
160 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
𝑐 = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9,
9, 9, 9, 9}
We need to find the right permutation though, and there are 𝑁 ! number of permutations, where 𝑁 is as noted above the
total number of missing digits in our problem. In this case 𝑁 = 51 so there are:
𝑁 ! = 51! = 1551118753287382280224243016469303211063259720016986112000000000000
possible combinations, which are many! Luckily for us, there are repetitions, since some digits are repeated. Considering
that there are 6 1’s, 7 2’s, 6 3’s, 8 4’s, 5 5’s, 4 6’s, 6 7’s, 4 8’s and 5 9’s, we can calculate the number of permutations with
repetitions as:
51!
= 2465536997482928914408092530982635167547392 = 2.47 * 1042
6!·7!·6!·8!·5!·4!·6!·4!·5!
Which is still a really large number of possible combinations! The question is, are they too many for a genetic algorithm
to find a solution? We will find out soon enough, but first, let’s discuss how our genetic algorithm is going to work. Step
by step:
Initialisation
The first step is to generate an initial genome (all genes of a set of possible solutions). A gene is going to represent the
value of a digit in a position of the Sudoku, and all the genes or chromosome of a solution, all the values of all digits missing
in the problem. Basically, to generate the genome of the first population, we can generate just as many permutations of c
as the size of the initial population. Say the initial population size is 𝑃 , so initialising the genome is basically to obtain 𝑃
permutations of 𝑐. Let us define a function 𝜏 (𝑐) that randomly re-arranges the items of an array 𝑐 and therefore returns a
random permutation out of all possible permutations. so, our initial genome 𝐺0 is going to be just a set of permutations
of c:
Fitness function
Now, the second step is to evaluate the fitness function. We can define a fitness function that counts the number of
duplicated digits in every row, in every column, and in every 3x3 block. That is, if a digit appears two times in a row, the
fitness function will add 1, and if a digit appears twice in a column, it will add 1, same if it appears twice in a block. So
let us define this fitness function as 𝑓 (𝑔𝑖𝑘 ) and obviously the result is going to be an integer number. Furthermore, the
𝑓 𝑖𝑡𝑛𝑒𝑠𝑠𝑎𝑟𝑟𝑎𝑦:
will contain the fitness of the different candidate solutions in the initial population, and by extension:
will contain the fitness of the different candidate solutions in the population at generation 𝑖.
Selection function
To select the fittest, we just need to select the candidates that contain fewer mistakes, those where the fitness solution
is lower. We just need to sort the elements of the fitness array in ascending order and select some of them for the next
generation. Let us note the selection function as 𝜎(𝑓𝑖 ) and as 𝑆 the number of individuals that will produce offspring in
the next generation. The set of survivals in a generation 𝑖 is:
whereas described, the elements of s will be the 𝑆 elements of 𝐺𝑖 with the lowest fitness function value.
We could randomly select two parents from the survivals and combine values in the solution, but we need to ensure that
the result is still a permutation of 𝑐, so for the sake of simplicity, let us not implement any crossover function and focus
on the generation of mutations of surviving individuals. To generate a mutation, what we can do is copy some values
randomly from the parent in the exact same position as they are in the parent, and shuffle the remaining values. For
instance, imagine that our problem was very easy and only missing 3 values. We could select randomly 1 out of the 3
values and copy it in the exact same location and generate a permutation of the other two elements. If the parent had all
the digits of a valid solution, so will the children, and if we are lucky, the permutation will yield a valid solution. Let us
note as 𝑅 the number of digits (or genes) of the parent that we copy, and 𝑁 − 𝑅 the number of genes that mutate. Note
that, if we select randomly the (𝑅) genes out of the 𝑁 genes, this is a combination, and therefore, the number of possible
combinations of 𝑅 genes out of the parent is:
𝑁 𝑁!
𝐶𝑅 =
𝑅!(𝑁 − 𝑅)!
And now, we are going to shuffle the (𝑁 − 𝑅) remaining genes, so there are (𝑁 − 𝑅) different permutations of these
genes, that combined with the previous result, yield the following total possible different offspring from a single parent:
𝑁!
𝑅!
For instance, the example above, with 𝑁 = 51 gaps or blank positions, if we set 𝑅 = 49, there are:
51 𝑁! 51! 51 * 50 * 49! 51 * 50
𝐶49 = = = = = 1275
𝑅!(𝑁 − 𝑅)! 49!(51 − 49)! 49! * 2! 2!
possible ways to combine the genes, and if we multiply by 2!, we get 2500 different combinations of a parent. Now, this
is only for 1 parent, if the selection function lets 𝑆 survivals, we need to multiply by this factor as well to get the total size
of the possible offspring, so for instance, if we set it to 10, the possible different members in a generation is 25000.
We really need to fine tune these parameters to make sure that the algorithm is fast, because we need to make sure that
we explore a sufficient proportion of all the possible offspring in the iterations. For instance if 𝑅 is too small, the number
of possible children will be too large compared to the population size, and it will be very difficult for the algorithm to
find the right solution. Additionally, (𝑁 − 𝑅) must be at least 2, so that we can at least switch two digits to generate
another solution. On the other hand, if the population size is too large compared to the possible offspring our algorithm is
inefficient because the population size is too large compared to the possible different offspring, and we will be evaluating
several times the same combination of genes in every generation. As a rule of thumb, You need to make sure that the
total number of different offspring in a generation is larger than the population size but in the same order of magnitude.
162 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Termination
Finally, we will terminate when we reach a maximum number of iterations, or when we have found the optimal solution.
We also need to ensure that we can get rid of bad batches, meaning that something can go wrong in the mutations and our
algorithm can converge to a solution that can not be fixed with a permutation of N-R numbers of all candidate solution,
that is the fitness function can have local minimum and our solution can converge to a local minimum, which is not optimal,
so if we detect for instance that the fitness function does not change in a number of iterations, we just go back to step 1
and initialise the entire population again. We also need to set another parameter to control the reset, which will represent
the maximum number of iterations without improvement in the fitness function.
Implementation
Ok, the following Python script implements this approach. To try it, you just need to provide the values of your Sudoku
as a Python Array where the digits in [1-9] define the clues or filled digits in your Sudoku, and the 0s represent the gaps.
Hyper-parameters
The parameters that control the behaviour of the algorithm, or hyperparameters are as described above: - Number of
genes that are passed to children in each generation (R). Default: N-R = 2 - Population size, the population size of each
generation (P), default: 500 - Number of iterations, default: 1000: - Number of survivals in each generation, default 10 -
Number of iterations without improvement, default 10
# digits from 1 to 9
digits = [Link](1,10)
gaps_idx = [Link](problem == 0)
# are missing. digit_count counts, starting with zero the number of digits present in␣
˓→the problem:
digit_count = [Link]([Link]())
# HYPER-PARAMETERS
# Hyper-parameter R, default: N-R = 2
in_chromosome_size = problem_size -2
# The missing values are going to be 9 - the count of digits, the zeros can be␣
˓→ignored:
missing_count = 9 - digit_count
# Let s create a numpy array with the digits that we need to fill in:
candidate_digits = [Link]([], dtype= int32 )
def is_permutation(elements):
# returns 0 if row is a permutation of digits from 1 to 9
return 9 - len([Link](elements))
def fitness(solution):
res = 0
# check that rows are consistent
for i in range(9):
res += is_permutation(solution[i])
164 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
# our genome consists of shuffling the candidate digits and placing the digits in the
# gaps
for k in range(population_size):
# shuffle the candidates
[Link](candidate_digits)
# The simplest genome generation strategy is however to just fill the zeros with␣
˓→digits
it = 0
iteration_error = [Link](num_iter)
while it < num_iter:
# reset the fitness function
fitness_array = [Link](population_size)
for k in range(population_size):
# calculate fitness function of candidate k
fitness_array[k] = fitness(genome[k,:,:])
iteration_error[it] = fitness_array[fittest[0]]
reset = (it >= reset_it) and (sum(abs(iteration_error[it-reset_it:it] - iteration_
˓→error[it])) == 0)
if reset:
digit_count = [Link]([Link]())
# The missing values are going to be 9 - the count of digits, the zeros can␣
˓→be ignored:
missing_count = 9 - digit_count
# Let s create a numpy array with the digits that we need to fill in:
candidate_digits = [Link]([], dtype= int32 )
for k in range(population_size):
# shuffle the candidates
[Link](candidate_digits)
continue
sol = genome[fittest[0],:,:]
# print( Iteration: + str(it))
# print(iteration_error[it])
# print(sol) # We might have found already a solution
if fitness_array[fittest[0]] == 0:
break
else:
# Let us create the next generation
# take ten survivals
mutations = [Link]((population_size,9,9))
# randomly combine rows of the best solutions
for k in range(population_size):
# Init mutation_k as problem
mutation_k = [Link](problem)
missing_count = 9 - digit_count
candidate_digits = [Link]([], dtype= int32 )
for digit in digits:
candidate_digits = [Link](candidate_digits, [Link](digit,␣
˓→missing_count[digit]))
[Link](candidate_digits)
(continues on next page)
166 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
mutations[k,:,:] = [Link](mutation_k)
end_time = [Link]()
duration = end_time - init_time
print("all righty, i finished the Sudoku in {0} seconds and {1} iterations: ".
˓→format(duration.total_seconds(), it))
all righty, i finished the Sudoku in 84.685776 seconds and 567 iterations:
Best solution is:
[[8. 3. 6. 2. 7. 9. 4. 1. 5.]
[9. 5. 1. 3. 4. 8. 7. 6. 2.]
[4. 7. 2. 1. 5. 6. 3. 8. 9.]
[7. 9. 3. 4. 8. 5. 6. 2. 1.]
[1. 6. 5. 7. 9. 2. 8. 3. 4.]
[2. 8. 4. 6. 1. 3. 9. 5. 7.]
[5. 1. 8. 9. 3. 4. 2. 7. 6.]
[3. 2. 9. 5. 6. 7. 1. 4. 8.]
[6. 4. 7. 8. 2. 1. 5. 9. 3.]]
[3]: Text(0, 0.5, Error )
Questions
1. Run the algorithm above and write down the number of iterations and the execution time. Did the algorithm find
an optimal solution? You can try again if you think the algorithm did not find an optimal solution. Do you think
the algorithm is better than a human? (spoiler alert: the algorithm is not very good and will probably need several
attempts to find a solution)
2. Reason with an AI assistant about the algorithm, and ask for an explanation of the code in the cell above in simple
terms.
3. As described in the explanation of this approach, the algorithm may converge to a local minimum, a solution with
a low number of errors, but that cannot be fixed with a permutation of digits. If the algorithm detects that there
is no improvement, it will reset the entire population and start again (and we will see a drastic increase in the
error). Looking at the graph that shows the error against the iterations, do you think the algorithm reset the entire
population at any time? How many times do you think the reset function was executed?
4. This is a naive approach because to generate the solution, Ask an AI assistant what is the search space of the
problem, and how many possible solutions there are using this naive approach. Now, look for the assessment of
the search space of the problem in the section above and use this prompt template to ask the AI assistant again: > I
found the following information about the search space of the problem: [Look for the assessment of the complexity
of the problem in the section above and paste it here]. Can you tell explain it to me in simple terms?
5. The search space is just vast. As an AI assistant answer how big is it using this prompt:
How extraordinarily large is the number of possible combinations obtained? Can you provide me some
illustrative examples? Be imaginative!
168 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Approach 1 is naive in the sense that it does not require an in-depth knowledge of Sudoku to program the algorithm, but
obviously, if we have some knowledge of the problem at hand, we can deliver more efficient solutions, but they might
come at the expense of complexity, and therefore costs, development costs and/or computational costs.
Let us again look at the solution of the problem above:
|f88b4252b97f45c3b7267a17da84d8cf|Tim Stellmach - public domain, wikipedia
We know that each column is a permutation of the digits in [1-9], so, what if instead of assigning to every unknown cell
an index, we use two indices, one for the columns, and another one for the rows. for instance, now our solution will be
• Column 1: [𝑠31 , 𝑠71 , 𝑠71 , 𝑠71 ] = [1, 9, 2, 3]
• Column 2: [𝑠22 , 𝑠42 , 𝑠52 , 𝑠62 , 𝑠82 , 𝑠92 ] = [7, 5, 2, 1, 8, 4]
• Column 3: [𝑠13 , 𝑠23 , 𝑠43 , 𝑠53 , 𝑠63 , 𝑠73 , 𝑠83 , 𝑠93 ] = [4, 2, 9, 6, 3, 1, 7, 5]
• Column 4: [𝑠14 , 𝑠34 , 𝑠44 , 𝑠64 , 𝑠74 , 𝑠94 ] = [6, 3, 7, 9, 5, 2]
• Column 5: [𝑠35 , 𝑠55 , 𝑠75 ] = [4, 5, 3]
• Column 6: [𝑠16 , 𝑠36 , 𝑠46 , 𝑠56 , 𝑠96 ] = [8, 2, 1, 4, 7, 6]
• Column 7: [𝑠17 , 𝑠27 , 𝑠37 , 𝑠47 , 𝑠57 , 𝑠67 , 𝑠87 , 𝑠97 ] = [9, 3, 5, 4, 7, 8, 6, 1]
• Column 8: [𝑠18 , 𝑠28 , 𝑠48 , 𝑠58 , 𝑠68 , 𝑠88 ] = [1, 4, 2, 9, 5, 3]
• Column 9: [𝑠19 , 𝑠29 , 𝑠39 , 𝑠79 ] = [2, 8, 7, 4]
Again, even if at the beginning of the problem we do not know the exact value that we need to assign to each cell, it is
very easy to know which values are going to be missing in each column, and we know that in the solution, the values in
each column is going to be a permutation of the missing values. So, now, our problem consists of finding 9 permutations
of different sizes! what is now the number of potential solutions, the search space? well, it depends on the problem,
but in this specific case, we need to multiply the number of possible combinations in each row, therefore the number of
candidate solution in this case is:
𝑁1 ! * 𝑁2 ! * 𝑁3 ! * 𝑁4 ! * 𝑁5 ! * 𝑁6 ! * 𝑁7 ! * 𝑁8 ! * 𝑁9 ! = 4! * 6! * 8! * 6! * 3! * 6! * 8! * 3! * 4! = 12582400952578867200000
Compared to alternative 1:
51!
= 2465536997482928914408092530982635167547392
6!·7!·6!·8!·5!·4!·6!·4!·5!
The search space is now tiny!
Initialisation
Again, the first step is to generate an initial genome (all genes of a set of possible solutions). A gene is going to
represent the value of a digit in a position of the Sudoku, and all the genes or chromosome of a solution, all the values of
all digits missing in the problem. Basically, to generate the genome of the first population, we can generate just as many
permutations of the values missing in each column as the size of the initial population. Let us note as 𝑐𝑗 𝑗 ∈ [1 − 9]
the set of missing values in column 𝑗. Basically, we need to obtain 𝑃 permutations of every 𝑐𝑗 .
We can use the same function 𝜏 (𝑐𝑗 ) to re-arranges the items of an array 𝑐 and returns a random permutation out of the
𝑁𝑗 ! possible permutations. so, our initial genome 𝐺0 is going to be P different sets of permutations of the 9 columns:
Fitness function
Selection function
Now, let us take a different approach for the cross-over, what we are going to do is to take a number of columns from the
parent, and copy them, and then create a mutation by shuffling some values of the remaining columns.
Let us note as 𝑅𝑐 the number of columns that are passed to the children without mutations. Again, this is a combination
of the 9 columns, and the number of possible combinations is:
9 9!
𝐶𝑅 𝑐
= 𝑅𝑐 !(9−𝑅𝑐 )!
Possible combinations of genes and (𝑁𝑗 − 𝑅𝑗 )! permutations of the genes that mutate. So, again, there are:
𝑁 𝑁𝑗 !
𝐶𝑅𝑗𝑗 * (𝑁𝑗 − 𝑅𝑗 )! = 𝑅𝑗 !
Again, this is a combination, but note that, now, the index of the column j is random (we did a random selection of
columns), so the maximum number of digits missing are found in columns 3 and 7 that are both missing 8 numbers. So,
for instance, if we set 𝑅𝑐 to 8, so that we copy 8 columns from the parent, there will be 9 combinations of columns to
pass as-is to the next generation. Now, say we fix $(N_j - R_j) to 2, so that we shuffle at most 2 values. We will have, at
most:
8!
9* 6! = 9 * 8 * 7 = 504
Possible ways to mutate a parent if the algorithm selects to mutate column 3 or column 7. And if we select 10 survivals,
we may get an estimation of the total number of offspring as 5040.
There are two things that we need to observe here. First is that the number of combinations is significantly smaller, just
as the search space, so we can deal with smaller populations in every generation, which will make each iteration faster,
or take another strategies, like increasing the number of survivals in each generation, or the number of columns that we
shuffle, to explore the search space faster.
The other important thing is that there is uncertainty in the total number of possible offspring, because not all the columns
are missing the same number of values and, since the parameters of the algorithm are fixed, the algorithm is not going to
be as stable as in the first approach.
170 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Termination
Implementation
Ok, the following Python script implements this approach. To try it, you just need to provide the values of your Sudoku
as a Python Array where the digits in [1-9] define the clues or filled digits in your Sudoku, and the 0s represent the gaps.
Hyper-parameters
The parameters that control the behaviour of the algorithm, or hyperparameters: - Number of columns that are passed
to the next generation (𝑅𝑐 ). Default: 8 - Number of genes that are passed to children in each generation (R). Default: 2 -
Population size, the population size of each generation (P), default: 50 - Number of iterations, default: 1000: - Number
of survivals in each generation, default 10 - Number of iterations without improvement, default 100
[4]: from random import sample
import numpy as np
from matplotlib import pyplot as plt
from datetime import datetime
# digits from 1 to 9
digits = [Link](1,10)
gaps_idx = [Link](problem == 0)
# are missing. digit_count counts, starting with zero the number of digits present in␣
˓→the problem:
digit_count = [Link]([Link]())
# Hyper-parameters
# Population size
population_size = 50
(continues on next page)
# Number of iterations
num_iter = 1000
# number of survivals
num_survivals = 10
# The missing values are going to be 9 - the count of digits, the zeros can be␣
˓→ignored:
missing_count = 9 - digit_count
def get_missing_per_column(column):
column_count = [Link](column)
column_count_padded = [Link](10)
column_count_padded[0:len(column_count)] = column_count
return digits[column_count_padded[1:]==0]
def get_missing(prob):
m_per_column = [Link]((9,9), dtype= int32 )
for j in range(9):
missing_values = get_missing_per_column(prob[:,j])
m_per_column[0:len(missing_values), j] = missing_values
return m_per_column
def is_permutation(elements):
# returns 0 if row is a permutation of digits from 1 to 9
return 9 - len([Link](elements))
def fitness(solution):
res = 0
# check that rows are consistent
for i in range(9):
res += is_permutation(solution[i])
172 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
init_time = [Link]()
# Now our genome consists of shuffling the candidate digits of every row and placing␣
˓→the digits in the
# gaps
for k in range(population_size):
# The simplest genome generation strategy is however to just fill the zeros with␣
˓→digits
it = 0
iteration_error = [Link](num_iter)
while it < num_iter:
# reset the fitness function
fitness_array = [Link](population_size)
for k in range(population_size):
# calculate fitness function of candidate k
fitness_array[k] = fitness(genome[k,:,:])
iteration_error[it] = fitness_array[fittest[0]]
reset = (it >= reset_it) and (sum(abs(iteration_error[it-reset_it:it] - iteration_
˓→error[it])) == 0)
if reset:
genome = [Link]((population_size, 9, 9))
for k in range(population_size):
# init candidate as problem
(continues on next page)
continue
sol = genome[fittest[0],:,:]
# print(sol)
# We might have found already a solution
if iteration_error[it] == 0:
break
else:
# Let us create the next generation
# take ten survivals
mutations = [Link]((population_size,9,9))
# set them to 0
[Link](mutation_k[:,j], [Link](mutation_k[:,j], digits_to_
(continues on next page)
174 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
mutations[k,:,:] = [Link](mutation_k)
end_time = [Link]()
duration = end_time - init_time
print("all righty, i finished the Sudoku in {0} seconds and {1} iterations: ".
˓→format(duration.total_seconds(), it))
Analysis Questions
1. Run the algorithm above and write down the number of iterations and the execution time. Did the algorithm find
an optimal solution? Do you think this approach is faster?
2. Ask an AI assistant to explain this algorithm to you in simple terms, and ask also if this algorithm is more efficient,
and ask for simple explanations of why.
3. Look for the description of the size of the search space in the description above and ask again an AI assistant to
provide some illustrative examples of how big this new search space is.
4. Ask an AI assistant again to describe what hyperparameters are and what are the hyperparameters of this algorithm.
Ask if it can suggest a better set of hyperparameters to solve the problem faster. Try the suggested hyperparameters
and compare the results. This process is called hyperparameter tuning, and it is a very important part of AI. Was
the AI assistant able to suggest a better set of hyperparameters?
5. This strategy exploits the fact that columns are permutations of digits. What other strategies can you think of to
solve the problem faster? How would you improve the algorithm? (Feel free to reason with your AI assistant about
better ways to solve this problem)
176 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Introduction
Mixed Integer Programming (MIP) can be regarded as an extension of Continuous Linear Programming where any of or
all the defined decision variables cannot take fractional values. MIP introduces two new types of variables:
• Integer variables: Integer variables can only take Integer values. Normally, Integer variables are introduced by
logical restrictions that make rational valuables unfeasible. For instance, in some instances of production mix
problems, it does not make sense to produce fractional parts of a product and treating them as real number is just
an approximation.
• Binary variables: Binary variables or Boolean variables can only take values 1 or 0. Normally, binary variables
are used to factor into our model binary decisions, e.g. to decide whether to use a machine configuration or another,
or whether to select one element from a set or not.
In CLP, the continuity of the decision variables ensures that the feasibility region and the objective function intersect
in a vertex of the feasible region at the optimal value. But this is no longer the case when some decision variables are
Integer values. Intuitively, one can think that the optimal value may be found in one of the feasible Integer values around
the theoretical intersection, as long as the solution is feasible. This makes the number of candidate solutions larger and
consequently, MIP problems are more difficult to solve. From a mathematical point of view, when the decision variables
are not continuous, the feasible region and the objective function are no longer convex. Convexity of feasibility region and
objective function ensures that the optimal solution is at one vertex. We will explain this concept further in Non-Linear
Programming. For now, it is sufficient to understand that in MIP, the feasibility region is no longer convex since not all
values are possible and this makes it harder to find a solution.
This limitation makes convergence to an optimal solution more complex. MIP solution is several orders of magnitude
more complex that linear programming. For instance, the assumptions made to design the Simplex algorithm do no longer
hold and although adaptations may find an optimal solution, convergence is so slow that they cannot be applied to practical
problems.
Set up
In general, the set-up of MIP problems is the same as the set-up of CLP problems, except that some decision variables
can only take Integer values. For instance:
decision variables
Let us note our decision variable as 𝑋 = [𝑥1 , 𝑥2 , ..., 𝑥𝑛 ] where 𝑛 is the number of decision variables. In continuous
linear programming, the decision variables could take any real value, in mathematical notation this is expressed as:
𝑥𝑗 ∈ R
Now, in integer programming, decision variables can only take integer numbers. Without loss of generalization, let us
consider that our decision variables can only take positive integers, or natural numbers. We refer to this type of decision
variables as integer variables, and are noted as:
𝑥𝑗 ∈ N
A special type of integer variables are binary variables which are variables that can only take values 0, or 1. These
variables are very convenient to model ‘yes or no’ decisions or ‘true or false’ (boolean) logic decisions into our problem.
We note can use this notation for binary variables:
𝑥𝑗 ∈ [0, 1]
In general, not all decision variables have to be necessarily of the same type. Integer Programming (IP) problems only
have integer or binary decision variables, whereas MIP problems can have any combination of decision variables.
Objective Function
As with CLP, our objective function is a linear function of the decision variables, noted as 𝑧 and which we would like to
maximize or minimize. For instance, if our objective function is of type maximize, we can use:
∑︀𝑛
max 𝑧 = 𝑗=1 𝑐𝑗 ·𝑥𝑗
Constraints
Knapsack Problem
The Knapsack problem is an optimization problem that is often found in practical applications. The classical formulation
reads
Given a set of items, each with a weight and a value, we need to determine the number of each item to
include in a collection so that the total value is maximised while the total weight is less than or equal than
the maximum weight the knapsack can hold.
Just like packing a knapsack for a nice adventure!
Decision variables
The decision variables 𝑥𝑗 are binary decision variables that determine whether we include item 𝑗 in the Knapsack:
𝑥𝑗 ∈ [0, 1] {0: item not included, 1: item included} ∀𝑗
That is, the decision variable can only take values 0, or 1. The value 0 means that the object is not selected and therefore
has no impact in the objective function. Likewise, the value 1 means that the object is selected.
Objective coefficient
Each item 𝑗 will have a different value 𝑣𝑗 . We can express the objective function as the value of the items selected:
∑︀𝑛
max 𝑧 = 𝑗=1 𝑣𝑗 ·𝑥𝑗
178 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Constraints
Now, our only constraint is related to the maximum weight 𝑊 the knapsack can support. Each item will have a different
weight 𝑤𝑗 , and the sum of the weights 𝑤𝑗 of the selected variables has to be less or equal than the maximum weight.
∑︀𝑛
𝑗=1 𝑤𝑗 ·𝑥𝑗 ≤ 𝑊
Note that, if a given 𝑥𝑗 is zero, the product 𝑤𝑗 ·𝑥𝑗 will also be zero and will have no impact on the total value of the left
hand side summation.
Now, it is important to note that in this formulation, weights and values as abstract concepts, and the same formulation
can be applied to many practical problems.
Assignment Problems
Assignment problems are a fundamental class of combinatorial optimization problems. In essence, assignment problems
consists of assigning elements of a set of resources R (like workers, machines, etc.) to a set of tasks T to optimize a
certain objective (like minimizing cost or maximizing efficiency), subject to various constraints.
Indices
Now, since we have two different sets, we will use two different indices to uniquely identify the elements in each set:
• i: We will use index i to identify each element in set R. Let us note the size of set R as 𝑚, therefore, 𝑖 ∈ [1, 2, ..., 𝑚]
• j: We will use index j to identify each element in set T. The size of set R is noted as 𝑛, therefore, 𝑖 ∈ [1, 2, ..., 𝑛]
Decision Variables
Let us define a binary variable 𝑥𝑖𝑗 for each resource i and task j. 𝑥𝑖𝑗 = 1 if resource i is assigned to task j, and 0
otherwise:
𝑥𝑖𝑗 ∈ [0, 1] {0: resource i is not assigned to task j, 1: otherwise} ∀𝑖, ∀𝑗
Note that there are a total of 𝑚 * 𝑛 decision variables!
Objective function
The objective is to minimize costs or maximize benefits associated with assigning a particular resource to a particular
task. As with Knapsack problems, we need to think of costs or benefits as abstract concepts, and the model can be
applied to many practical applications.
For instance, let us note as 𝑐𝑖𝑗 the cost of assigning resource i to task j. The objective function then becomes:
∑︀𝑚 ∑︀𝑛
min 𝑧 = 𝑖=1 𝑗=1 𝑐𝑖𝑗 * 𝑥𝑖𝑗
Constraints
Now, the constraints need to ensure that one element of R is assigned to one element T, that is, we need to ensure that
there are not two or more resources assigned to a task:
∑︀𝑛
𝑗=1 𝑥𝑖𝑗 = 1 ∀𝑖
Note first that the for a given 𝑖, the left hand side 𝑗=1 𝑛𝑥𝑖𝑗 is the sum of all the decision variables associated to a
∑︀
resource 𝑖. Since the different 𝑥𝑖𝑗 can only be 0 or 1, by establishing an upper bound limit of 1 to the sum of all the
elements, we ensure that the resource can only be assigned at most to one task.
Similarly, we need to ensure that a task is only associated to one resource:
∑︀𝑚
𝑖=1 𝑥𝑖𝑗 = 1 ∀𝑗
∑︀𝑚
Note that the expression is similar, but now the left hand side 𝑖=1 𝑥𝑖𝑗 represents the sum of all the decision variables
associated to task 𝑗
Sequencing Problems
180 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Algorithms
There are different techniques used to solve MIP problems, among which we can highlight the following:
Relaxation
Relaxation is basically formulating the MIP problem as if all decision variables where continuous, and therefore reducing
the MIP problem to a CLP problem. Relaxation allows the decision maker to use the Simplex method and perform a
sensitivity analysis. The Solution may be not feasible, but it might provide some insights into the possible solution.
The Gomory´s algorithm is an extension of relaxation. First, the problem is formulated as a CLP. When the solution is
found, new constraints are introduced to cut the fractional part of one of the Integer variables out of the feasibility region.
This yields a new CLP that can be solved with the Simplex method. This process is repeated until a solution is found
where all Integer variables actually take Integer values.
Branch and bound is one of the most common methods to solve combinatorial optimization and MIP problems. This
type of algorithms explore the possible solutions iteratively, by dividing the set of possible solutions into smaller sets, then
finding a bound of the objective function in each subset and selecting the subset, or branch with the optimal bound.
Let us see the set-up for a minimization problem. The objective function is:
min 𝑧 = 𝑓 (𝑥)
where x is the decision variable which can take values from a finite set 𝐶, i.e. 𝑥 ∈ 𝐶.
Let us divide the set 𝐶 into two subsets 𝐶1 , 𝐶2 and find a minimum bound of the objective function in each subset such
that:
𝑓 (𝑥) ≤ 𝑐1 ∀𝑥 ∈ 𝐶1
𝑓 (𝑥) ≤ 𝑐2 ∀𝑥 ∈ 𝐶2
Now, let us assume that 𝑐1 ≤ 𝑐2 . Since we are looking for the minimum value of 𝑧, we can discard the entire set 𝐶2 from
the search and continue looking for the solution in branch 𝐶1 .
Now again, let us divide 𝐶1 into two subsets 𝐶11 , 𝐶12 . We can find again a minimum bound for 𝑓 (𝑥) in each subset:
𝑓 (𝑥) ≤ 𝑐11 ∀𝑥 ∈ 𝐶11
𝑓 (𝑥) ≤ 𝑐12 ∀𝑥 ∈ 𝐶12
Again, we can compare bounds and select the branch with the minimum bound. Note that, at each iteration, we are
selecting a better suboptimal solution. Let us note as 𝛼 the index of the subset of 𝐶 at a given iteration. If 𝐶𝛼 contains
only 1 element 𝛼 and 𝑐𝛼 = 𝑓 (𝛼) is lower than the minimum bound of the other subsets, then 𝛼 is the optimal solution.
182 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Genetic Algorithms
Genetic algorithms can also be used to solve MIP problems. You can find a description here
Try me
Introduction
This tutorial shows how to program and solve Mixed Integer Programming (MIP) problems in Python using the PuLP
library.
This tutorial builds upon the tutorial on PuLP we saw in the previous unit:
Continuous Linear Programming with PuLP
Requirements
To run this tutorial you will need to install PuLP, following the guides in the previous tutorial. For instance, if you are
using this tutorial in Colabs, run the following cell to install PuLP:
[ ]: # Install PuLP
!pip install pulp
Example
We will use the Allocating order to machines problem to guide the tutorial. For convenience, this is the mathematical
formulation:
indices
Coefficients
⎡ ⎤ ⎡16 2 8 3 3
⎤
𝑐11 𝑐12 ··· 𝑐1𝑛
⎢4 14 10 7 6⎥
⎢ 𝑐21 𝑐22 ··· 𝑐2𝑛 ⎥
⎥ ⎢ ⎥
𝐶=⎢ . .. .. .. ⎥ = ⎢
⎢9 7 3 6 8⎥
⎢
⎣ .. . . . ⎦ ⎣5
⎥
5 12 10 11⎦
𝑐𝑚1 𝑐𝑚2 ··· 𝑐𝑚𝑛 6 13 11 5 7
Objective function
Constraints
∑︀
𝑗 𝑥𝑖𝑗 ≤ 1 ∀𝑖
∑︀
𝑖 𝑥𝑖𝑗 ≤ 1 ∀𝑗
Solution in Python
The following script models and solves the problem using PuLP:
[2]: # Import PuLP modeler functions
import pulp
# Define indices
machines = [1, 2, 3, 4, 5]
orders = [1, 2, 3, 4, 5]
# Define constraints
for i in machines:
model += [Link]([x[(i,j)] for j in orders]) == 1
for j in orders:
model += [Link]([x[(i,j)] for i in machines]) == 1
184 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Status: Optimal
Objective value: 20.0
x_(1,_1) = 0.0
x_(1,_2) = 0.0
x_(1,_3) = 0.0
x_(1,_4) = 0.0
x_(1,_5) = 1.0
x_(2,_1) = 1.0
x_(2,_2) = 0.0
x_(2,_3) = 0.0
x_(2,_4) = 0.0
x_(2,_5) = 0.0
x_(3,_1) = 0.0
x_(3,_2) = 0.0
x_(3,_3) = 1.0
x_(3,_4) = 0.0
x_(3,_5) = 0.0
x_(4,_1) = 0.0
x_(4,_2) = 1.0
x_(4,_3) = 0.0
x_(4,_4) = 0.0
x_(4,_5) = 0.0
x_(5,_1) = 0.0
x_(5,_2) = 0.0
x_(5,_3) = 0.0
x_(5,_4) = 1.0
x_(5,_5) = 0.0
C:\Users\franc\PycharmProjects\operations-research-notebooks\venv\Lib\site-packages\
˓→pulp\[Link]: UserWarning: Spaces are not permitted in the name. Converted to
˓→ _
Code Explanation
The code is very similar to the efficient code we used in the previous tutorial. The only difference is in the way we define
the decision variables. Let’s see the differences:
Decision variables
We use the same function [Link] to define the decision variables. There are two main dif-
ferences: - Definition or integer or binary decision variables: We use the parameter cat=[Link] to
define the decision variables as binary. If we wanted to define them as integer, we would use cat=[Link].
- Definition of the indices: We use a list comprehension to define the indices of the decision variables. The list compre-
hension is a very powerful tool in Python that allows us to define lists in a very compact way. The list comprehension we
use is the following:
[(i,j) for i in machines for j in orders]
This list comprehension defines a list of tuples, where each tuple is defined as (i,j), where i takes the values in the list
machines and j takes the values in the list orders. This way we define all the possible combinations of i and j in a
very compact way.
x = [Link]("x",
[(i,j) for i in machines for j in orders],
cat=[Link],
)
Defines a total of 5x5 = 25 decision variables, one for each combination of i and j. The decision variables can be accessed
using a tuple. For instance, x[(1,1)] is the decision variable associated with the combination i=1 and j=1.
In the previous tutorial, we defined the coefficient matrix in the code. However, in real problems, the data is normally
stored in a file. In this case, we will use an Excel file to store the data. We will see how to read the data from the Excel
file and store it in a DataFrame. Then, we will see how to access the data in the DataFrame to define the coefficient
matrix. The following code shows how to load the data from an Excel file named [Link]:
[ ]: import pandas as pd
import pulp
from [Link] import display
# Define indices
machines = [1, 2, 3, 4, 5]
orders = [1, 2, 3, 4, 5]
# Define constraints
for i in machines:
model += [Link]([x[(i,j)] for j in orders]) == 1
for j in orders:
model += [Link]([x[(i,j)] for i in machines]) == 1
186 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Code Explanation
Normally, the data for our problem is going to be stored in tabular format in file formats like Excel. In this case, we
can use the pandas library to read the data from the Excel file and store it in a DataFrame. Then, we can use the
DataFrame to access the data in a very convenient way. First, just copy the following table in an Excel file:
machine order cost
1 1 16
1 2 2
1 3 8
1 4 3
1 5 3
2 1 4
2 2 14
2 3 10
2 4 7
2 5 6
(continues on next page)
Make sure you paste the table in the first sheet of the Excel file as text. It should look like this:
Important! If you notice that all the text of a raw is in the same sure, try to Past As text from the Edit menu
in Excel.
Name the file [Link].
188 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Now, you need to make sure that the Excel file is in the working directory of your Python environment. If you are using
Colabs, you can use the file menu to upload it as shown in this tutorial:
Working with files
Now, we can use the pandas library to load the data in a DataFrame:
import pandas as pd
dataset_df = pd.read_excel("[Link]", index_col=[0,1])
c = dataset_df[ cost ]
The index_col parameter indicates that the first two columns of the Excel file are the indices of the DataFrame.
Note that we have stored the costs in a variable named c. This is because we will use the DataFrame to access the data
in a very convenient way. For instance, if we want to access the cost of machine 1 and order 1, we can use the following
code:
print(c[1,1])
This will print the value of the cell in the first row and first column of the DataFrame, corresponding to machine 1 and
production order 1.
To show the data in a more convenient way, we can pivot the DataFrame:
dataset_df = dataset_df.reset_index()
dataset_df = dataset_df.pivot(index= machine , columns= order , values= cost )
display(dataset_df)
This will show the data in a very convenient way, environments like Colabs provide interactive widgets to further work
with the data.
Now, we can modify the objective function slightly to access the data in the DataFrame:
Note that since the indices of c are the same as the indices of the decision variables, the code is very compact and close
to mathematical notation.
Exporting to Excel
This code first creates a dataframe with the decision variables and then extracts the values of the decision variables using
a lambda function. Pandas will apply the lambda function to each row of the dataframe, passing the decision variable
object as a parameter. The lambda function will return the value of the decision variable.
Finally, we can pivot the dataframe and export it to excel using the following code:
This code will create an Excel file named [Link] with a sheet named X containing the solution. If our problem
has more decision variables, we can create more sheets and store the solutions in different sheets.
Analysis Questions
1. Analyse the solution and explain the assignment of orders to machines that the model has found in your own words.
2. How would you modify the model to allow for the assignment of more than one order to each machine?
3. Use an AI assistant to obtain a Python script to solve the problem using PuLP. Compare the script with the one we
have developed in this tutorial. What are the main differences?
4. Ask an AI assistant to provide a greedy algorithm to solve the problem in Python. Try the algorithm. Does the
algorithm provide an optimal solution? Why?
5. Try to solve different instances of the problem, for instance adding more machines or more production orders.
What changes are needed in the script. How can you make the script more scalable?
Basic Set up
In the Introduction to MIP, we described the wide range of problems that can be modeled and solved with MIP, and
described the setup of some widely used problem models. In this notebook, we introduce the transportation problem, as
a special type of MIP problem particularly important for logistic operations. In the literature, the general transportation
problem deals with the distribution of any commodity (generally goods) from a group of origins of the supply chain, or
source facilities, called sources to the endpoints of the model of the supply chain, the receiving centers, called destinations.
There are different types of goods or services that can be modeled with this model. Sources can be production centers,
or warehouses. Destinations can be warehouse, demand regions or end customers, depending on the model.
However, in the general problem formulation, we have 𝑖 ∈ [1, ..., 𝑛] source nodes and 𝑗 ∈ [1, ..., 𝑚] destination nodes.
The objective is to minimize the overall costs of the distribution of goods at a minimum costs, subject to a set of constraints.
Regarding the constraints, let us consider two types of constraints:
190 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
• supply constraints: These constraints represent the limited capacity of the sources. For instance, production
centers may have a limited production capacity, or source warehouses may have a limited storage capacity. Let us
note 𝑠𝑖 the source capacity of source node 𝑖.
• demand constraints: The demand constraints represent the distribution requirements at the destinations: what are
the quantities of the goods required at each destination. Let us note as 𝑑𝑗 the demand of destination node 𝑗
Now, based on this, let us define our set of decision variables as:
• 𝑥𝑖𝑗 : (Integer) units to transport from source 𝑖 to destination 𝑗
Assuming a distribution cost of 𝑐𝑖𝑗 for each transported unit yields:
∑︀𝑛 ∑︀𝑚
min 𝑧 = 𝑖=1 𝑗=1 𝑐𝑖𝑗 * 𝑥𝑖𝑗
𝑠.𝑡
∑︀𝑚
𝑗=1 𝑥𝑖𝑗 ≤ 𝑠𝑖 ∀𝑖
∑︀𝑛
𝑖=1 𝑥𝑖𝑗 ≥ 𝑑𝑗 ∀𝑗
That is, the total number of units that leave a source cannot exceed the capacity of the source, and the total number of
units that reach a destination must be at least equal to the demand.
Note that the model has a feasible solution only if:
∑︀𝑛 ∑︀𝑚
𝑖=1 𝑠𝑖 ≥ 𝑗=1 𝑑𝑗
That, is, the problem is only feasible if the overall capacity is sufficient to meet the overall demand.
It is important to note that we may allow ourselves less slack by making any of the three inequalities above equalities.
Sourcing design
In the basic set up above, it is assumed that it is possible to transport units from any source node to any destination. This
implies that the design of the distribution network is known. But this may not be always the case. For instance, we may
have different possible locations for source warehouse, each with different associated costs. In this case, our decision
variables are not only the number of units to transport, but also determine from which subset of source nodes they must
be transported. Thus, we can introduce a new set of decision variables:
• 𝑌𝑖 : (Binary) determines whether units to any destination may be delivered from source node 𝑖
We need to introduce new logical constraints to ensure that we do not deliver any units from source nodes that are not
selected:
∑︀𝑚
𝑗=1 𝑥𝑖𝑗 ≤ 𝑀 * 𝑌𝑖 ∀𝑖
Where M is a large number. Since 𝑌𝑖 is binary, this constraint forces that, in case that it is equal to zero, no units are
sourced from source node 𝑖.
This logical constraint can be merged with the source capacity constraint as:
∑︀𝑚
𝑗=1 𝑥𝑖𝑗 ≤ 𝑠𝑖 * 𝑌𝑖 ∀𝑖
This constraint takes into account the logical constraint and the capacity constraint. Since both constraint are equivalent,
but the former is more restrictive and renders the first one irrelevant.
We can now take into account in the objective function fixed costs that do not depend on the number of units. For instance,
let us consider that the source warehouses have a fixed operation costs 𝑓𝑖 . The problem in the basic set up becomes:
∑︀𝑛 ∑︀𝑚 ∑︀𝑛
min 𝑧 = 𝑖=1 𝑗=1 𝑐𝑖𝑗 * 𝑥𝑖𝑗 + 𝑖=1 𝑓𝑖 * 𝑌𝑖
𝑠.𝑡
∑︀𝑚
𝑗=1 𝑥𝑖𝑗 ≤ 𝑠𝑖 * 𝑌𝑖 ∀𝑖
∑︀𝑛
𝑖=1 𝑥𝑖𝑗 ≥ 𝑑𝑗 ∀𝑗
Single source
The single source constraint imposes that all the demand of a destination node is transported from the same origin. With
this constraint, now the decision variables 𝑥𝑖𝑗 become binary:
• 𝑋𝑖𝑗 : (Binary) determines if source 𝑖 delivers all demand to destination 𝑗 {1 if yes, 0 otherwise}
The demand constraint now becomes:
∑︀𝑛
𝑖=1 𝑑𝑗 * 𝑋𝑖𝑗 = 𝑑𝑗 ∀𝑗
Note that we now multiply each binary decision variable times the demand of each destination. We have changed the
type of the constraint from ≥ to = to avoid any slack. Although this change is optional, if not applied, the slack will be
a multiple of the demand. Note that this is exactly the same requirement:
∑︀𝑛
𝑖=1 𝑋𝑖𝑗 = 1 ∀𝑗
We just divided by 𝑑𝑗 the right hand side and the left hand side.
Also, we need to factor this into the objective function as:
∑︀𝑛 ∑︀𝑚
min 𝑧 = 𝑖=1 𝑗=1 𝑐𝑖𝑗 * 𝑑𝑗 * 𝑋𝑖𝑗
Since 𝑋𝑖𝑗 is binary, and only equal to 1 for a destination node.
Network design
In the set up above, we assume that the cost per unit from sources to destinations is fixed. In many cases however, this cost
depends to a great extent on the design considerations taken in the distribution network between sources and destination.
Similar to what we did with the sourcing design, we may be interested on evaluating the impact in the cost of the design
of the distribution network, for instance, the location of intermediate nodes or junctions between the source nodes and
destination nodes. In literature, this is known as the transshipment problem in the literature. Let us come back to the
original problem, and assume that the source nodes are production plants, the destination nodes are retailer regions, and
that we have intermediate warehouses that we can use to optimise costs. Let us assume that the production plants are
fixed (i.e. the sourcing design is known), but that we can select a subset of warehouses from a set of candidate locations.
First, let us modify the indices so that the distribution stages (from production plants through warehouses to regions)
follow an alphabetical order:
• 𝑖: Production plants 𝑖 ∈ [1, ..., 𝑛]
• 𝑗: Possible warehouse locations 𝑗 ∈ [1, ..., 𝑚]
• 𝑘: Retailer regions 𝑘 ∈ [1, ..., 𝑙]
Let us use the following notation for the coefficients of our problem:
• 𝑑𝑘 : yearly demand in retail region k
• 𝑎𝑖𝑗 : cost of transporting 1 unit from plant i to warehouse j
• 𝑏𝑗𝑘 : cost of transporting 1 unit from warehouse j to retailer region k
• 𝐹𝑗 : yearly operation costs of warehouse j
• 𝑐𝑖 : yearly production capacity of plant i
Since we can decide the location of the warehouses, and the units to transport at each stage, the decision variables now
become:
• 𝑌𝑗 : (Binary) { 1 if a warehouse is placed in location j } {0 otherwise}
• 𝑠𝑖𝑗 : integer units transported from plant i to warehouse j
192 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Known variations
Any combinations of the variations above can be found in a problem instance. For instance, we might be interested in
evaluating our network design with a single source constraint on intermediate nodes. Note that when we introduce a single
source constraint in our problem, the decision variable that models the transport of units becomes binary. For instance,
in the network design problem above, the decision variables Any combinations of the variations above can be found in a
problem instance. For instance, we might be interested in evaluating our network design with a single source constraint
on intermediate nodes. Note that when we introduce a single source constraint in our problem, the decision variable that
models the transport of units becomes binary. For instance, in the network design problem above, the decision variables
𝑡𝑗𝑘 become:
• 𝑇𝑗𝑘 : (Binary) {1 units from warehouse j transported to region k, 0 otherwise}
Since the variable are now binary, the single source constraint modifies the demand constraint, which now becomes:
∑︀𝑛
𝑗=1 𝑇𝑗𝑘 = 1 ∀𝑘
Now, since all 𝑇𝑗𝑘 are binary, the logical constraint that rules the construction of warehouses can be written as:
𝑇𝑗𝑘 ≤ 𝑌𝑗 ∀𝑗, ∀𝑘
Other indices
We may also introduce other indices in the problem, most common indices are:
• Type of product: We can have different costs or demands depending on the type of product
• Periods: The costs, or the demands can be dynamic and depend on a discrete time period, like the year, the month,
or the day, so we might be interested in optimising the distribution network for a set of periods.
When we introduce a new index into the model, the size of the problem (number of coefficients and decision variables)
will grow accordingly.
Introduction
Graph theory is a field of mathematics based on mathematical structures called graphs. A graph is just a diagram made
of a set of nodes and a set of edges that join two nodes. The following image illustrates a graph.
Graphs are abstract objects that humans use to model and design many structures. We can easily relate graphs with roads
and other types of distribution networks, like data networks, or pipelines. We use graphs to illustrate the organisation of
personnel or the hierarchy of the departments in a company, or the layout of a warehouse or of the production floor plant,
so in this sense, graph theory can be applied in many fields.
Formally, a graph is a pair of sets 𝐺 = (𝑁, 𝐸), where 𝐸 notes the set of edges and 𝑉 the set of vertices, which have the
following definitions:
• Nodes: The nodes or vertices of the graph. Normally, it is a finite set and the order of a graph is the size of set,
normally noted as N. It can also be infinite, as long as it is numerable, and we can identify and enumerate the nodes.
Nodes can have different properties. For instance, they can have geographical coordinates, or can be grouped into
different groups.
• Edges: Edges or arcs connecting two different nodes of the graph. Nodes are noted according to the indices of
the nodes they connect. For instance, an edge connecting nodes 𝑖 and 𝑗 is noted as 𝑒𝑖𝑗 . Nodes i and j are called
end vertices of 𝑒𝑖𝑗 and they are said to be adjacent. If P is the size of E, we refer to the graph as a P-Graph. For
instance, a graph with 10 edges or arcs is referred to as a 10-Graph.
Another important definition is a path. A path is a set of edges that interconnect different nodes, traversing the graph
possibly through other intermediate nodes.
Types of graphs
Let us introduce the following definitions to classify graphs: - Weighted graph: A weighted graph is a graph where
each edge 𝑒𝑖𝑗 has a different weight 𝑤𝑖𝑗 . The weight represents a real world property associated with the graph, and
that represents the cost associated to the edge. For instance, the weight can represent the distance of an edge in a graph
that represents a distribution network. Edges in a weighted graph can have other attributes, like the capacity 𝑏𝑖𝑗 . These
attributes will be taken into account when selecting the edges to solve a specific optimization problem.
194 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
• Directed graph: In a directed graph, 𝐸 is a set of ordered pairs of distinct vertices. Normally, a directed graph is
also weighted and the weights of the edges connecting to nodes are not symmetric, that is 𝑤𝑖𝑗 not equal to 𝑤𝑗𝑖 .
• Oriented graph: An oriented graph is a directed graph with at most one edge interconnecting any two nodes i, j.
That is, if there is an edge 𝑒𝑖𝑗 , there cannot be an edge $e_{ji}.
Types of problem
Shorter path
Given a directed graph with positive edge weights (e.g. distance, cost), the shortest path problem aims to find a path
between two given nodes that minimizes the total weight of the edges in the path, which is the sum of the weights of the
edges in the path.
This problem is important in routing problems, where we need to determine the shortest path between two nodes, when
there might be more than one possible alternative. It is therefore a partial problem in more complex problems in logistic
applications, for instance if we want to establish the best route that minimises the total distance covered by a fleet. It can
also be used to model other situations like minimising the total cost of a sequence of activities (replacing equipment).
Given a graph with edge weights (e.g. distance, cost), the minimum spanning tree problem aims to find a spanning tree
that minimizes the total weight (i.e. the sum of the weights of its edges).
A spanning tree is a path that interconnects all nodes starting from a root node.
This problem is typically applied to designing telecommunication networks with a minimum total cost, although it can
also be used to design transport networks, cable TV, distributed systems, to interpret climatological data, among other
applications.
196 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Given a directed graph with edge capacities (e.g. volume/second), maximal flow problems aim to find a flow from a given
source node to a given sink node that maximizes the total flow.
The total flow represents the maximum capacity available in the path connecting the source node and the sink node.
Maximal flow problems are applied in logistics and distribution problems, but also in other types of applications like the
commercialisation of products in a production–distribution network, programming employment, etc.
Given a graph with edge weight (e.g. cost) and demands for each node, find a flow satisfying all demands that minimizes
the total cost.
The minimal cost flow problem can be used to model transportation problems using graphs.
Try me
Description
In this notebook, you will learn how to solve network problems using Python. For the set-up, we will use a map of the
city of Valencia, and calculate the shortest distance between two points using the actual street map of the city. We will
use the following libraries:
• Networkx: This Python library implements a lot of network theory utils and algorithms and is the main library
used in the problems.
• Osmnx: This library allows us to create a graph from an Open Street Maps query (similar to what you would use
to find a place in Google Maps).
Additionally, we will use the following libraries to render the maps:
• Folium: This library allows us to render the maps in our Notebooks
Remember you must Trust the notebook to test it. In Colabs, Run the following cell to install the libraries:
Network creation
[ ]: import networkx as nx
import osmnx as ox
from [Link] import IFrame
%matplotlib inline
print("The streets of Valencia can be modeled with a graph of size: " + str(G_nx.
˓→size()))
Code Explanation
We have created a graph that represents the streets of Valencia, Spain, using the function ox.graph_from_place.
The function takes as input a place name, and returns a graph of the streets in that place. The parameter network_type
specifies the type of streets that we want to include in the graph. In this case, we are only interested in streets that
can be used by cars. Other possible values are walk (pedestrian streets), bike (streets that can be used by bikes),
drive_service (service roads), all (all the streets in the place).
Now, the object G_nx is a graph of the city, we do some adaptations that will allow us to work with the map more easily:
# Relabel the nodes with integers. This facilitates handling the tree
G_nx = [Link].convert_node_labels_to_integers(G_nx)
# give each node its original osmid as attribute, since we relabeled them
osmid_values = {k:v for k, v in zip(G_nx.nodes, osmids)}
nx.set_node_attributes(G_nx, osmid_values, osmid )
[ ]: ox.graph_to_gdfs(G_nx, nodes=False).explore()
Code explanation
The function ox.graph_to_gdfs converts the graph to a GeoDataFrame, which is a data structure that allows us to
plot the graph in an interactive map. The parameter nodes=False indicates that we are not interested in plotting the
nodes of the graph (only the edges). Any GeoDataframe can be plotted using the function explore(). As we will see
in the next section, we can also explore routes in the map using this function.
198 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Shortest path
Let us now define a function that uses this map to calculate the shortest path.
-0.3624288516715025)).
Args:
source - A tuple containing latitude and longitude values of the source point.
destination - A tuple containing latitude and longitude values of the source␣
˓→point.
Returns:
route: The shortest path along the map
distance: the minimum distance in meters (summation of great-circle distance␣
˓→between nodes in the shortest path)
"""
# Get the nearest node to source
node_1 = [Link].nearest_nodes(G_nx, X=source[0], Y=source[1])
Code Explanation
The function above uses the following functions from the libraries:
• [Link].nearest_nodes(G_nx, X=source[0], Y=source[1]): This function returns the
nearest node to a given point. The point is specified by its latitude and longitude.
• ox.shortest_path(G_nx, node_1, node_2): This function returns the shortest path between two
nodes in the graph.
The function basically uses the previous functions to first find the nearest nodes to the source and destination points, and
then calculates the shortest path between them. Finally, it returns the shortest path and the nearest nodes of the graph
which are closer to the provided coordinates.
Let us test the function!. From Google Maps, it is very easy to get the coordinates of a point. Just right-click on the map,
and it will show the coordinates. After, you can hover over the coordinates and left click to copy the coordinates to your
clipboard. Now, if you paste in Google Colabs, you will get the coordinates of the point.
Note that the coordinates are in the form (latitude, longitude). However, the function get_route expects the coordi-
nates in the form (longitude, latitude). Therefore, we need to invert the coordinates before passing them to the function.
Here is an example of two points in Valencia:
• EDEM: Coordinates (-0.3288013882525529, 39.46211739713285)
• CIGIP Research Center @ UPV: Coordinates (-0.3344765250611888, 39.46211739713285)
Converting to GeoDataFrame
Now, we can convert the route to a GeoDataFrame, which is a dataframe containing the information of the route. This
will allow us for instance to calculate the total distance or to plot the route in a map. The function used to convert the
route to a GeoDataFrame is ox.utils_graph.route_to_gdf. The function takes as input the graph, the route
and the attribute that we want to use to calculate the distance. In this case, we are using the attribute length, which is
the length of the street in meters.
200 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Now, we can calculate the distance of the route by summing the length of the streets in the route. The length of the streets
is stored in the column length of the GeoDataFrame. Therefore, we can use the function sum to calculate the total
distance.
[ ]: total_distance = sum(route_edges["length"])
print("The total distance between the two points is: " + str(total_distance) + "␣
˓→meters")
Finally, we can plot the route in a map using the function explore of the GeoDataFrame. The function takes as input
the map where we want to plot the route. We can use the argument color to specify the color of the route, the argument
style_kwds to define style properties, and the argument m to specify the map where we want to plot the route. If we
do not specify the map, the function will create a new map. In the example below we set the weight of the route to 5 to
plot it in a thicker line.
[ ]: route_edges.explore( style_kwds={"weight": 5})
We can use the function get_routeand the information contained in Geo Dataframes to get the routes of a distribution
network. For instance, let us calculate the routes for a distribution network with two sources and two destinations in
Valencia.
[ ]: sources = [
{
"id": 1,
"coordinates": (-0.3783881019008758, 39.47875115874353)},
{
"id": 2,
"coordinates": (-0.3929897392129934, 39.4817119703732)
}]
destinations = [
{
"id": 1,
"coordinates": (-0.3346191716152525, 39.47696577364303)},
{
"id": 2,
"coordinates": (-0.3288013882525529, 39.46211739713285)
}]
routes = []
Code Explanation
In the code above, we have defined two dictionaries with the information of sources and destinations, and then we have
iterated over them to calculate the routes and distances, using the get_route function defined before. We have stored
the different routes in a list of GeoDataFrames, and the distances in a list of dictionaries. The dictionaries contain the
information of the source, destination and distance of each route.
Now, we can for instance display a dataframe with the distances:
[ ]: import pandas as pd
[Link](distances)
[ ]: # Define a color map so that the routes have different colors depending on the source
# we use source ids as keys and colors as values. The colors are semi-transparent so␣
˓→that we can see the routes even if they overlap
color_map = {
1: "#ff000055",
2: "#0000ff55"
}
202 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Analysis questions
1. Try the scripts with other points in the map. What is the shortest path between them?
2. What are the main limitations of this approach? How could we improve it?
3. Try to get the distance using a mapping application (e.g. Google Maps). What is the difference between the distance
calculated by the script and the distance calculated by the application? Why?
4. Ask an AI assistant to describe the concept of Manhattan distance to you. Calculate the Manhattan distance between
the two points. What is the difference between the distance calculated by the script and the distance calculated by
the application? Why? Could you use the Manhattan distance to improve the script?
3.2 Exercises
The firm MMM has obtained a contract to tarmac the streets in the centre of Exeter. The Department of Traffic Engi-
neering and Planning estimated that at least the number of employees indicated in the table below are required for each
4-h interval over a standard 24-h period. All of MMM’s members of staff work 8-h ongoing shifts. There are six feasible
shifts which begin on the starting hour of the 4-h intervals indicated in the table. All the members of staff are paid the
same salary per hour, except those working between 20:00 h and 00:00 h, who receive a 50 % increase. Moreover, the
salary per hour is 100 % higher between 00:00 h and 06:00 h.
a) Consider a linear programming model that can determine how many employees are required in all six shifts in order
to minimise the cost of MMM’s salaries to meet the personnel requirements.
b) The temporary work ETS firm offers the members of staff more flexible working hours, with 4-h shifts beginning on
the hour at the start of all the 4-h periods in the table. The cost of using ETS’ staff is the same at all the times considered,
but is 80 % higher than the daily cost of MMM’s members of staff for each shift. MMM wishes to know if there would
be any profit made if ETS was used. Amend the former model to determine the optimum mix of using MMM’s and ETS’
staff in order to minimise the costs incurred to MMM through salaries and to meet the personnel requirements.
Problem Definition
The firm H.G. Welds, dedicated to welding components for the automotive sector, has received five orders (P1, P2, P3,
P4, P5), which have to be carried out. To meet these orders, the company has five welding machines available (M1,
M2, M3, M4,M5). Each machine can carry out every task at the cost shown in the table below. The problem consists
in determining optimum allocation which minimises the total cost of carrying out orders by assuming that each machine
can do only one order and that all the orders must be carried out.
Order/Machine M1 M2 M3 M4 M5
P1 16 4 9 5 6
P2 2 14 7 5 13
P3 8 10 3 12 11
P4 3 7 6 10 5
P5 3 6 8 11 7
Formulate an integer linear programming model to determine the optimum allocation plan. Assume that pro-
cessing each order on each machine requires an average preparation cost of 10 units. How is the model in the
former sector amended?
[ ]:
Consider the production of a single product in a planning horizon in T periods. If production during a given period
𝑡(𝑡 = 1, ..., 𝑇 ) is decided, a fixed cost 𝑐𝑓𝑡 is incurred. Any excess products manufactured during early periods can be
stored to meet the demand for later periods. Besides, all the demand must be met during each period. Production capacity
constraints are not considered.
As t = 1,.., T:
• 𝑑𝑡 is the demand for this product during each period,
• 𝑐𝑝𝑡 are the cost profits of production during each period, and
• 𝑐𝑎𝑡 are the cost profits of storage during each period.
a) Formulate an integer linear programming model which minimizes the total costs of production, storage and fixed costs
b) Assume that delays in deliveries have a cost 𝑐𝑟𝑑𝑡 per demand unit not delivered on time during each period. However,
all the demand must be met during the last period T, or in other words, a delay in the demand during period T must be
null. Amend the model in the former section to contemplate this option.
c) Assume that production can take place in a maximum of five periods, although these periods cannot occur consecutively.
Amend the model in the former section to contemplate this option.
[ ]:
204 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
4 Trucks are available to deliver gas to 5 gas stations. Each truck has a different capacity and if the company decides to
use it to supply to any gas stations, the cost can be modeled by a constant operating cost. The capacity and daily operating
costs of each truck are shown in the table below.
Each gas station can be supplied only by one truck, but a track may deliver to more than one gas station. The daily
demands of each gas station are shown in the table below.
Formulate an Integer Program Problem that can be used to minimise the distribution costs of the logistics operations
needed to satisfy the demand of the five stations.
[ ]:
Problem definition
Arcadia Deliveries wants to determine the best location for their warehouses to supply the different retail regions of their
best customer. There are 5 possible warehouse locations and 10 different retail regions. The following table shows the
capacity and operation costs of the possible warehouse locations:
Region Demand
Region 1 100
Region 2 200
Region 3 300
Region 4 400
Region 5 500
Region 6 600
Region 7 700
Region 8 800
Region 9 900
Region 10 1000
And the following cost contains the transportation costs from warehouses to regions:
Find the optimal location for warehouses and determine which warehouses are going to deliver to every retail location,
knowing that the customer requires that a region is supplied from only one source
[ ]:
Problem Definition
The US Department of Energy conducts a series of experiments in two research facilities located in Hawkins (Atlanta)
and Los Angeles. The department needs to supply these facilities with pharma products that are processed in two factories
in Portland and Flint. The delivery costs are summarised in the following table:
206 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Implement an MILP that determines how to supply the two research facilities at minimum cost.
[ ]:
A firm must transport machines from production plants A, B and C to warehouses X, Y and Z. Five machines are required
in X, 4 in Y and 3 in Z, whereas 8 machines are available in A, 5 in B and 3 in C. The transport costs (in euros) between
sites are provided in the table below.
Plant/Warehouse X Y Z
A 50 60 30
B 60 40 20
C 40 70 30
Problem definition
Patrick “Eel” O’Brian’s (PEOB) Ltd. is a company that manufactures plastic components for the automotive sector. As an
intern at PEOB Ltd, your first assignment is to write an Integer Programming Model to calculate the optimal production
plan for the plastic injection machine. The injection machine heats plastic and injects it into a mould to get a specific
shape. Each mould can thus only be used to manufacture specific component types. Your first version will take into
account the storage costs and the delayed orders cost which are defined below.
Storage costs The storage or inventory costs represent the cost of storing the inventory levels of every component type
at every planning period and are modeled as a fixed cost per unit and planning period. The storage costs are different for
every component type.
Delayed orders costs At every planning period, you may delay part of the demand for the next planning period. Customers
will apply a fixed penalty for every delayed unit at every period. The delayed costs are also different for every component
type.
Your model needs to take into account the following additional data:
Initial Inventory Levels (units): There is an initial inventory level for every component type available at the first planning
period that needs to be taken into account.
Minimum and Maximum Inventory Levels (units): There is a maximum and a minimum inventory level for every
component type.
Machine capacity (units): The machine capacity represents the number of units of a given component type that the
machine can produce using a given mould. If a mould cannot be used to manufacture a component type, the machine
capacity is zero for that combination of component type and mould.
Demand (Units): The company has several confirmed orders for the following periods and therefore, our model needs
to take into account the demand for every product at every planning period.
a. Write down the indexes and decision variables
b. Write down the objective function
c. Write down the constraints
You have successfully validated your model, and it is already providing valuable information for the company. Now the
company would like to extend the model to take into account as well the set-up costs:
Set up costs As explained above, the injection machine uses different moulds to manufacture different parts. Each time
that a mould is changed to make a different component, the operators need to set up the machine. The company estimates
that this setup cost only depends on the mould that is used and is only applied when a product is changed.
d. Modify the model to take into account the set-up costs.
Problem Definition
A firm must transport machines from production plants A, B and C to warehouses X, Y and Z. Five machines are required
in X, four in Y and three in Z and there are eight machines available in A, five in B and three in C. a) Create and solve
a Graph Theory model to determine the maximal flow of the machines that can be transported and the run of this flow.
b) By assuming a mean cost of €45 per transported machine, what would the total cost be of transporting the machines
obtained in the former section?
Problem Definition
A low-cost airline, OrgaAir, operates four daily flights from Valencia to London at 10:00, 12:00, 14:00 and 16:00 hours.
The first two flights hold 100 passengers and the last two can fly up to 150 passengers each. Should overbooking occur,
which implies having sold more seats than the plane actually has, the airline can place a passenger on a later flight.
Evidently each delayed traveller is compensated by being paid €200 plus €20 for each hour delayed. The firm places
delayed travellers on their own operating flights, or on one of the flights from other airlines departing at 20:00 hours, which
always have available seats (a capacity of 999 passengers is always considered) at no extra charge. Let us assume that at
the beginning of the day we know that OrgaAir has sold 110, 160, 100 and 100 seats on its four daily flights, respectively.
Model this problem as a maximal flow model at a minimum cost in order to minimise the airline’s total overbooking cost.
208 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Problem Definition
PLACASA, a supplier of plastic injection parts for the automobile sector, foresees the demand of an article for the
following 4 months of 100, 140, 210 and 180 units, respectively. The firm can maintain only sufficient stock to meet the
demand of each month, or it can have excess stock to meet the demand of two successive months or more with a storage
cost of 1.2€ per month and unit of excessive stock. PLACASA calculates that the production cost for the following
months, is €15, €12, €10 and €14 per unit. A preparation cost of €200 is incurred every time a production order is
placed. The firm wishes to develop a production plan that minimises the total costs of production orders, of production
and of keeping an article in stock. Formulate and solve the shortest path model to find an optimum production plan.
[ ]:
Problem Definition
A manufacturer of the metal sector in Stafford manufactures four types of products in sequence on two machines. The
Table below provides the necessary technical production details. Taking into account only the data on the production times
per product and the maximum daily production capacity of each machine, and taking a maximum daily production of
100 units of each product type, consider and solve a maximal flow model in a graph to determine the maximum number
of minutes during which machines 1 and 2 can operate on a production-in-sequence basis given the existing capacity
constraints.
Problem definition
Planet Express deliveries wants to optimize their transportation network from a set of source warehouses to a set of
destinations. In particular, they want to minimize the transportation costs through a set of intermediate warehouses, so
that items are transported from the source warehouses, through the intermediate warehouses, to the destination regions.
Let us first consider that transportation costs per item from the source warehouse 𝑖 to intermediate warehouse 𝑗 as 𝑠𝑖𝑗
and that the transportation costs per item from intermediate warehouse 𝑗 to destination region 𝑘 is 𝑡𝑗𝑘 . Let us note the
capacity of source warehouses as 𝑎𝑖 items, the capacity of intermediate warehouses 𝑗 as 𝑏𝑗 items, and the demand for
region 𝑘 as 𝑑𝑘 items. Let us also consider that 𝑚 is the number of source warehouses, 𝑛 is the number of intermediate
warehouses and 𝑝 is the number of destination regions.
a Consider that m = p = 3 and n = 5 and draw a network to solve the transportation problem as a maximal flow at minimum
cost problem.
b Model the problem as a Mixed Integer Programming (MIP), not taking into account the values of m,p, and n defined
in the previous section
c Planet Express is now considering the use of warehouses from an external provider. The provider of the service has
a total of 𝑛𝑒 external warehouses. They offer a fixed cost 𝐹𝑙 when an external warehouse 𝑙 is used, plus a cost per item
received and processed in warehouse 𝑙, 𝑟𝑙 . External warehouse 𝑙 has a capacity of 𝑐𝑙 items. Modify your model to
incorporate this offer into your distribution network.
Problem Definition
You work for a company that manufactures high quality polymer parts for OrgoCorp, a galactic bioengineering company.
The quality requirements are so high that you need to use very sophisticated 3D printing machines. You need to develop
a mathematical programming model to organize monthly production considering:
• Fixed operational costs (euros): Each 3D printing machine 𝑚 has a different fixed operational costs 𝐹 𝑚 that
needs to be considered when a printing machine is used to print any units.
• Unitary production costs (euros): Each 3D printing machine 𝑚 produces parts of product type 𝑝 at a different
unitary costs 𝐶𝑚𝑝
• Capacity (minutes): Each 3D printing machine 𝑚 has a different capacity 𝑆𝑚 (minutes)
• Speed (minutes/part): Each 3D printing machine 𝑚 prints a unit of product type 𝑝 at a different unitary speed
• Demand (units): OrgoCorp has confirmed a demand for 𝑑𝑝 units of every product type 𝑝 Build a model that takes
into account these requirements, identifying indices, decision variables, objective function and constraints.
The CEO of OrgoCorp, The High Evolutionary, would like to set up a new contract allowing more flexibility in the
delivery of units, such that:
• Demand per period (units): Now you need to consider that the demand for every product type 𝑝 is not constant
and depends on the planning period 𝑡, 𝐷𝑝𝑡
• Delayed demand (units): You may delay the production for one period. For every unit of product type 𝑝 that is
delayed, OrgoCorp will charge an extra delayed demand cost of 𝐵𝑝𝑡 Modify the model to take into account this
new contract
Spellman’s would like Sabrina to focus on the optimization of their distribution network, to support the distribution of
the 2 types of drinks from 3 sourcing facilities to 4 destination warehouses, through 6 intermediate warehouses. Sabrina
needs to take into account the transportation costs (both from sourcing warehouses to intermediate warehouses and from
intermediate warehouses to final destinations). Additionally, Sabrina can decide how many of the 6 intermediate solutions
to use, given that they have a fixed operational cost that needs to be paid when the warehouse is used.
The following tables contain the transportation problem data:
210 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
From/To I1 I2 I3 I4 I5 I6
S1 2 4 5 7 3 6
S2 3 2 6 8 4 5
S3 1 3 4 6 5 7
From/To D1 D2 D3 D4
I1 5 2 3 4
I2 4 1 5 2
I3 3 4 2 5
I4 5 3 4 1
I5 2 5 3 4
I6 4 2 1 5
Note that the distribution costs are independent of the product type.
1. Help Sabrina write an Integer Programming Problem to model the transportation problem .
2. How would a Greedy algorithm solve the problem? Motivate your response
Problem Definition
Professor Xavier’s School for Gifted Youngsters is organizing a special summer session focusing on enhancing the students’
unique abilities. Students from across the country have been invited, and the school needs to arrange their transportation.
The goal is to ensure that all students can arrive at the school in time for the session while minimizing transportation costs.
1. First, let us consider an abstract model where gifted students reside in 𝑛 different locations, can can be transported in
𝑚 different modes of transport. Each mode of transport from each location to the school has a different associated
cost. Additionally, each transportation mode has a different capacity, and each location has a different number
of gifted students that need transportation to the school. Write down an Integer Programming (IP) problem that
minimizes the overall transportation costs.
2. Given the following number of students:
And the following capacities and costs of transport per student from the different locations for three different modes of
transport:
Mode Capacity L1 L2 L3 L4 L5 L6
T1 50 10 8 12 11 9 7
T2 60 9 7 11 10 8 6
T3 40 8 9 10 12 7 11
Draw a graph that allows to model the transportation problem as a maximum flow at minimum cost transportation problem.
The firm MMM has obtained a contract to pave the streets in the centre of Exeter. The Department of Traffic Engineering
and Planning estimated that at least the number of employees indicated in the table below are required for each 4-h interval
over a standard 24-h period. All of MMM’s members of staff work 8-h ongoing shifts. There are six feasible shifts which
begin on the starting hour of the 4-h intervals indicated in the table. All the members of staff are paid the same salary per
hour, except those working between 20:00 h and 00:00 h, who receive a 50 % increase. Moreover, the salary per hour is
100 % higher between 00:00 h and 06:00 h.
212 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
a) Consider a linear programming model that can determine how many employees are required in all six shifts in order
to minimise the cost of MMM’s salaries to meet the personnel requirements.
Decision variables
In this case, we need to decide how many employees work on each shift. Therefore, the decision variables are:
𝑋𝑗 : (Integer) Number of employees in shift j, 𝑗 = [1, ..., 6]
Objective function
Constraints
Now, we have six constraints, and taking into account that the employees work for two time periods straight:
𝑋6 + 𝑋1 ≥ 70
𝑋1 + 𝑋2 ≥ 20
𝑋2 + 𝑋3 ≥ 80
𝑋3 + 𝑋4 ≥ 30
𝑋4 + 𝑋5 ≥ 10
𝑋5 + 𝑋6 ≥ 10
b) The temporary work ETS firm offers the members of staff more flexible working hours, with 4-h shifts beginning on
the hour at the start of all the 4-h periods in the table. The cost of using ETS’ staff is the same at all the times considered,
but is 80 % higher than the daily cost of MMM’s members of staff for each shift. MMM wishes to know if there would
be any profit made if ETS was used. Amend the former model to determine the optimum mix of using MMM’s and ETS’
staff in order to minimise the costs incurred to MMM through salaries and to meet the personnel requirements.
Now, the ETS employees only work on 4h shifts, their hourly costs are fixed, but at the same time, 80% higher than the
base hourly cost of normal employees. We have again six new shifts, and therefore, 6 new decision variables:
𝑋𝑒𝑗 : (Integer) Number of ETS employees in shift j, 𝑗 = [1, ..., 6]
Now, we need to amend the objective function to account for this new employees, since the hourly costs are fixed, there
is no need to calculate it:
∑︀6 ∑︀6
min 𝑧 = 𝑗=1 𝐶𝑗 * 𝑋𝑗 + 𝑗=1 1.8·𝐶 * 𝑋𝑒𝑗
As for the constraints, we simply introduce the ETS employees in every shift:
𝑋6 + 𝑋1 + 𝑋𝑒1 ≥ 70
𝑋1 + 𝑋2 + 𝑋𝑒2 ≥ 20
𝑋2 + 𝑋3 + 𝑋𝑒3 ≥ 80
𝑋3 + 𝑋4 + 𝑋𝑒4 ≥ 30
𝑋4 + 𝑋5 + 𝑋𝑒5 ≥ 10
𝑋5 + 𝑋6 + 𝑋𝑒6 ≥ 10
Problem definition
Consider the production of a single product in a planning horizon in T periods. If production during a given period
𝑡(𝑡 = 1, ..., 𝑇 ) is decided, a fixed cost 𝑐𝑓𝑡 is incurred. Any excess products manufactured during early periods can be
stored to meet the demand for the next period. Besides, all the demand must be met during each period. Production
capacity constraints are not considered.
As t = 1,.., T:
• 𝑑𝑡 is the demand for this product during each period,
• 𝑐𝑝𝑡 are the cost profits of production per unit during each period, and
• 𝑐𝑎𝑡 are the cost profits of storage per unit during each period.
a) Formulate an integer linear programming model which minimizes the total costs of production, storage and fixed costs
b) Assume that we are allowed to have a delay of one period. Delays in deliveries have a cost 𝑐𝑟𝑑𝑡 per demand unit not
delivered on time during each period. However, all the demand must be met during the last period T, or in other words,
a delay in the demand during period T must be null. Amend the model in the former section to contemplate this option.
c) Assume that production can take place in a maximum of five periods, although these periods cannot occur consecutively.
Amend the model in the former section to contemplate this option.
Problem Model
Decision Variables
214 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Objective function
In section a. we consider production costs, the fixed costs, plus the storage costs:
min 𝑧 = production_cost + fixed_costs + storage costs
The objective function is therefore:
∑︀𝑇 ∑︀𝑇 ∑︀𝑇
min 𝑧 = 𝑡=1 𝑐𝑝𝑡 ·𝑋𝑡 + 𝑡=1 𝑐𝑓𝑡 ·𝑌𝑡 + 𝑡=1 𝐼𝑡 𝑐𝑎𝑡
Constraints
In this case, we need to make sure that we meet the demand in every period, then:
𝐼𝑡−1 + 𝑋𝑡 − 𝐼𝑡 ≥ 𝑑𝑡 , ∀𝑡
We also need to make sure that the binary decision variable makes sense:
𝑋𝑡 ≤ 𝑀 * 𝑌𝑡 , ∀𝑡
(Where M is a large number. If we do not make any units in a period, then the binary decision variable must be zero).
Also, they must be non-negative:
𝑋𝑡 ≥ 0, ∀𝑡
𝐼𝑡 ≥ 0, ∀𝑡
b) Delays
To take into account the delays, we need to introduce a new term in the objective function. We introduce a new decision
variable:
𝐷𝑢𝑡 = Units to delay at period t
And the objective function becomes:
∑︀𝑇 ∑︀𝑇 ∑︀𝑇 ∑︀𝑇
min 𝑧 = 𝑡=1 𝑐𝑝𝑡 ·𝑋𝑡 + 𝑡=1 𝑐𝑓𝑡 ·𝑌𝑡 + 𝑡=1 𝐼𝑡 𝑐𝑎𝑡 + 𝑡=1 𝐷𝑢𝑡 𝑐𝑟𝑑𝑡
We also need to amend the first constraint:
𝐼𝑡−1 + 𝑋𝑡 − 𝐼𝑡 − 𝐷𝑢𝑡−1 + 𝐷𝑢𝑡 ≥ 𝑑𝑡 , ∀𝑡
Also, we need to make sure that there are no delays at the end of the period:
𝐷𝑢𝑇 = 0
If we have a maximum number of periods, we can introduce another constraint using the binary variable:
∑︀𝑇
𝑡=1 𝑌𝑡 ≤ 5
Also, since we cannot produce in two consecutive periods, the sum of two consecutive values of the binary variable cannot
be higher than one:
𝑌𝑡 + 𝑌𝑡−1 ≤ 1, ∀𝑡
[ ]:
Problem Definition
The firm H.G. Welds, dedicated to welding components for the automotive sector, has received five orders (P1, P2, P3,
P4, P5), which have to be carried out. To meet these orders, the company has five welding machines available (M1,
M2, M3, M4,M5). Each machine can carry out every task at the cost shown in the table below. The problem consists
in determining optimum allocation which minimises the total cost of carrying out orders by assuming that each machine
can do only one order and that all the orders must be carried out.
Order/Machine M1 M2 M3 M4 M5
P1 16 4 9 5 6
P2 2 14 7 5 13
P3 8 10 3 12 11
P4 3 7 6 10 5
P5 3 6 8 11 7
Formulate an integer linear programming model to determine the optimum allocation plan. Assume that pro-
cessing each order on each machine requires an average preparation cost of 10 units. How is the model in the
former sector amended?
Problem model
Decision variables
Objective function
It represents the total cost of carrying out tasks, and can be expressed as the sum of all the costs 𝑐𝑖𝑗 which are the elements
of the cost matrix in the table. Note that the rows in the table represent the costs associated to a production order, whereas
in our matrix, each row represents the costs associated to a machine, so we need to transpose the table provided:
⎡ ⎤ ⎡16 2 8 3 3
⎤
𝑐11 𝑐12 · · · 𝑐1𝑛
⎢ 𝑐21 𝑐22 · · · 𝑐2𝑛 ⎥ ⎢ 4 14 10 7 6 ⎥
⎥ ⎢ ⎥
𝐶=⎢ . .. . .. ⎥ = ⎢ 9 7 3 6 8⎥
⎢
. .
⎢
⎣ . . . . ⎦ ⎣5 5 12 10 11⎦
⎥
𝑐𝑚1 𝑐𝑚2 · · · 𝑐𝑚𝑛 6 13 11 5 7
Now, the objective function is to minimize costs, therefore:
min 𝑧 = 𝑖 𝑗 𝑥𝑖𝑗 * 𝑐𝑖𝑗 = 16𝑥11 + 2𝑥12 + 8𝑥13 + 3𝑥14 + 3𝑥15 + ...
∑︀ ∑︀
That is:
216 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
That is:
𝑥11 + 𝑥21 + 𝑥31 + 𝑥41 + 𝑥51 ≥ 1
𝑥12 + 𝑥22 + 𝑥32 + 𝑥42 + 𝑥52 ≥ 1
𝑥13 + 𝑥23 + 𝑥33 + 𝑥43 + 𝑥53 ≥ 1
𝑥14 + 𝑥24 + 𝑥34 + 𝑥44 + 𝑥54 ≥ 1
𝑥15 + 𝑥25 + 𝑥35 + 𝑥45 + 𝑥55 ≥ 1
[ ]:
4 Trucks are available to deliver gas to 5 gas stations. Each truck has a different capacity and if the company decides to
use it to supply to any gas stations, the cost can be modeled by a constant operating cost. The capacity and daily operating
costs of each truck are shown in the table below.
Each gas station can be supplied only by one truck, but a track may deliver to more than one gas station. The daily
demands of each gas station are shown in the table below.
Formulate an Integer Program Problem that can be used to minimise the distribution costs of the logistics operations
needed to satisfy the demand of the five stations.
Model definition
Indexes
• i: Gas stations
• j: Trucks
Decision Variables
Objective Function
Minimise cost:
min 𝑧 = 𝑌𝑗 ·𝐶𝑜𝑗
∑︀
Constraints
Demand constraint
However, we also need to into account the demand, to make sure that we satisfy the daily demand in each gas station:
∑︀
𝑗 𝑑𝑖 * 𝑋𝑖𝑗 = 𝑑𝑖 ∀𝑖
Note that these two constraints (single source delivery constraint and demand constraint) are equivalent. We can just use
the former in our model.
Capacity constraint
We also need to take into account the capacity constraint to make sure that the amount delivered from any truck is lower
than its capacity:
∑︀
𝑖 𝑑𝑖 * 𝑋𝑖𝑗 ≤ 𝑐𝑗 ∀𝑗
Logical constraint
We need to introduce a logical constraint as well, to make sure that the binary decision variables are consistent with each
other. Basically, we need to ensure that we only use one truck (i.e. 𝑌𝑗 = 1) when it delivers to any gas station (i.e. any
𝑋𝑖𝑗 = 1 for the same j):
𝑋𝑖𝑗 ≤ 𝑌𝑗 ∀𝑖, ∀𝑗
Another way to express the logical constraint is:
∑︀
𝑖 𝑋𝑖 𝑗 ≤ 𝑀 * 𝑌𝑗 ∀𝑖, ∀𝑗
Where M is a very large number. In this form, basically what we say is that if a truck is not used (i.e. 𝑌𝑗 = 0), then the
sum of the gas stations it delivers to must be 0. Otherwise, if it is used (i.e. 𝑌𝑗 = 0), the sum has to be lower than a very
large number M.
Note that, we can also merge this logical constraint with the capacity constraint to yield:
∑︀
𝑖 𝑑𝑖 * 𝑋𝑖 𝑗 ≤ 𝑐𝑗 𝑌𝑗 ∀𝑗
218 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
In this form, the right hand side of the logical constraint is modified to take into account the quantity that each truck
delivers when it is used, and the right hand side is modified to take into account the maximum capacity of the truck, when
it is used.
With this, our model can be written as:
min 𝑧 = 𝑌𝑗 ·𝐶𝑜𝑗
∑︀
𝑠.𝑡.
∑︀
𝑗 𝑑𝑖 * 𝑋𝑖𝑗 = 𝑑𝑖 ∀𝑖
∑︀
𝑖 𝑑𝑖 * 𝑋𝑖 𝑗 ≤ 𝑐𝑗 𝑌𝑗 ∀𝑗
Solution in Python
Requirements
trucks = [1, 2, 3, 4]
stations = [1, 2, 3, 4, 5]
# Instantiate model
model = [Link]("Truck Deliveries", [Link])
x_vars = [Link]("X",
[(i, j) for i in stations for j in trucks],
lowBound=0,
cat= Binary )
y_vars = [Link]("Y",
[j for j in trucks],
lowBound=0,
cat= Binary )
model += (
[Link]([
costs[j] * y_vars[trucks[j]]
for j in range(len(trucks))])
), "Fixed operating costs"
# Demand
(continues on next page)
# Capacity constraints
for j in range(len(trucks)):
model += [Link]([
demands[i]*x_vars[(stations[i], trucks[j])]
for i in range(len(stations))]) <= capacities[j]*y_vars[trucks[j]], "truck_"␣
˓→+ str(trucks[j])
# Solution
max_z = [Link]([Link])
print(max_z)
Optimal
155.0
[ ]:
220 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Try me
Problem definition
Arcadia Deliveries wants to determine the best location for their warehouses to supply the different retail regions of their
best customer. There are 5 possible warehouse locations and 10 different retail regions. The following table shows the
capacity and operation costs of the possible warehouse locations:
Region Demand
Region 1 100
Region 2 200
Region 3 300
Region 4 400
Region 5 500
Region 6 600
Region 7 700
Region 8 800
Region 9 900
Region 10 1000
And the following cost contains the transportation costs from warehouses to regions:
Find the optimal location for warehouses and determine which warehouses are going to deliver to every retail location,
knowing that the customer requires that a region is supplied from only one source
Problem model
This is a transportation problem with a single-source facility constraint, where the sources are the sourcing warehouses
and the destination the retail regions.
The objective is to minimize the transportation costs, taking into account transportation costs and the operation costs.
Indices Let us define the following indices:
• 𝑖: warehouse location (𝑖 ∈ [1, ..., 5])
• 𝑗: retail region (𝑗 ∈ [1, ..., 10])
Data Looking at the data, we can define the following vector containing the operation costs:
𝑓 = [𝑓1 , 𝑓2 , ..., 𝑓5 ] = [50, 60, 70, 80, 90]
and the following matrix containing the transportation costs from every warehouse to every retail region:
⎡ ⎤
𝑐11 𝑐12 ... 𝑐15
⎢ 𝑐21 𝑐22 ... 𝑐25 ⎥
𝐶=⎢ ⎣ ...
⎥
⎦
𝑐101 𝑐102 ... 𝑐105
Or, using the values given in the table above:
⎡ ⎤
42 36 58 47 32
⎢73 56 73 78 38⎥
⎢ ⎥
⎢38 41 80 88 69⎥
⎢ ⎥
⎢59 70 77 94 51⎥
⎢ ⎥
𝑇
⎢51 92 79 88 80⎥
𝐶 =⎢ ⎢ ⎥
⎢38 98 57 64 96⎥
⎥
⎢86 53 86 58 44⎥
⎢ ⎥
⎢48 92 40 100 71⎥
⎢ ⎥
⎣62 60 30 31 63⎦
43 43 48 63 55
Besides the costs, each warehouse has a limited sourcing capacity, which can be identified as a vector:
𝑠 = [𝑠1 , 𝑠2 , ..., 𝑠5 ] = [1000, 2000, 3000, 4000, 5000]
And the following vector contains the demand for every region:
𝑑 = [𝑑1 , 𝑑2 , ..., 𝑑10 ] = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
Let us define the following decision variables:
• 𝑋𝑖𝑗 : (Binary) determines if warehouse 𝑖 delivers all demand to retail region 𝑗 {1 if yes, 0 otherwise}
• 𝑌𝑖 : (Binary) determines if warehouse 𝑖 delivers to any retail region {1 if yes, 0 otherwise}
Objective function The objective function is:
∑︀5 ∑︀10 ∑︀5
min 𝑧 = 𝑖=1 𝑗=1 𝑐𝑖𝑗 * 𝑑𝑗 * 𝑋𝑖𝑗 + 𝑖=1 𝑌𝑖 * 𝑓𝑖
Constraints The constraints are:
Sourcing capacity:
∑︀𝑚
𝑗=1 𝑑𝑗 * 𝑋𝑖𝑗 ≤ 𝑠𝑖 * 𝑌𝑖 ∀𝑖
These five constraints represent the limited capacity of the warehouses, we multiply the capacity with the corresponding
𝑌𝑖 variable to make sure the solution is logical and that the right-hand-side is zero if 𝑌𝑖 is zero.
Demand
∑︀𝑛
𝑖=1 𝑋𝑖𝑗 = 1 ∀𝑗
222 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Since we source all the demand from a single source, we only need to make sure that the demand is supplied from 1
location for every warehouse.
Implementation in Python
Requirements
Implementation
X = [Link]("X_",
((i, j) for i in warehouse for j in region),
lowBound=0,
cat= Binary )
# Data
transportation_costs = [Link]([[42, 73, 38, 59, 51, 38, 86, 48, 62, 43], [36, 56,␣
˓→41, 70, 92, 98, 53, 92, 60, 43], [58, 73, 80, 77, 79, 57, 86, 40, 30, 48], [47, 78,␣
˓→88, 94, 88, 64, 58, 100, 31, 63], [32, 38, 69, 51, 80, 96, 44, 71, 63, 55]])
demand = [Link]([100, 200, 300, 400, 500, 600, 700, 800, 900, 1000])
model += [Link]([demand[j]*transportation_costs[i,j]*X[(warehouse[i],region[j])]␣
˓→for i in range(len(warehouse)) for j in range(len(region))]) + pulp.
# Demand constraints
for j in range(len(region)):
model += [Link]([demand[j]*X[(warehouse[i],region[j])] for i in␣
˓→range(len(warehouse))]) >= demand[j], "demand_region_" + str(j)
[Link]()
print([Link][[Link]])
total_cost = [Link]([Link])
display(Markdown("Total cost is **%0.2f €**"%total_cost))
display(Markdown("##Decision Variables##"))
display(Markdown("The following table displays the values of the decision variables
˓→$X_{ij}$. The orientation is the same as in the table that provided the data in the␣
˓→first place"))
for j in range(len(region)):
row_name = region[j]
row_values = {}
for i in range(len(warehouse)):
row_values[warehouse[i]]=int(X[(warehouse[i],region[j])].value())
display(x_df)
y_df = [Link](columns=warehouse)
y_values = {}
for i in range(len(warehouse)):
y_values[warehouse[i]]=int(Y[(warehouse[i])].value())
display(y_df)
display(Markdown("Note that $Y_i$ is only 1 if the warehouse is used to deliver to␣
˓→any region"))
Optimal
Total cost is 235370.00 €
##Decision Variables##
The following table displays the values of the decision variables 𝑋𝑖𝑗 . The orientation is the same as in the table that
provided the data in the first place
1 2 3 4 5
1 0 0 0 0 1
(continues on next page)
224 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Try me
Problem Definition
The US Department of Energy conducts a series of experiments in two research facilities located in Hawkins (Atlanta)
and Los Angeles. The department needs to supply these facilities with pharma products that are processed in two factories
in Portland and Flint. The delivery costs are summarised in the following table:
Implement an MILP that determines how to supply the two research facilities at minimum cost.
Problem Model
Solution in Python
The following scripts implement the problem model and solve it using Python.
Requirements
#coefficients
coefficients = {}
coefficients[ Portland , Los Angeles ] = 30
coefficients[ Portland , Hawkins ] = 40
coefficients[ Flint , Los Angeles ] = 60
coefficients[ Flint , Hawkins ] = 50
(continues on next page)
226 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
# Objective Function
model += (
[Link]([
coefficients[(i,j)] * variables[(i, j)]
for i in supply for j in demand])
)
#Constraints
model += [Link]([variables[ Portland , j] for j in demand]) <= 200, "Supply From␣
˓→Portland"
model += [Link]([variables[i, Los Angeles ] for i in supply]) >= 300, "Demand in␣
˓→Los Angeles"
[ ]:
A firm must transport machines from production plants A, B and C to warehouses X, Y and Z. Five machines are required
in X, 4 in Y and 3 in Z, whereas 8 machines are available in A, 5 in B and 3 in C. The transport costs (in euros) between
sites are provided in the table below.
Plant/Warehouse X Y Z
A 50 60 30
B 60 40 20
C 40 70 30
a) Formulate an integer linear programming model that minimizes transport costs. This is a simple transportation problem,
where the objective is to minimize the transportation costs. Let us note the transportation costs from plant 𝑖 to warehouse
𝑗 as 𝑐𝑖𝑗 , our model is:
Indices
• 𝑖 Production plants, 𝑖 ∈ [𝐴, 𝐵, 𝐶]
• 𝑗 warehouses, 𝑗 ∈ [𝑋, 𝑌, 𝐶]
Decision variables
• 𝑥𝑖𝑗 (Integer) Number of machines to transport from production plant 𝑖 to warehouse 𝑗
Objective function
∑︀ ∑︀
𝑧 = 𝑖 𝑗 𝑐𝑖𝑗 * 𝑥𝑖𝑗
Constraints Demand constraint
∑︀
𝑖 𝑥𝑖𝑗 ≥ 𝑑𝑗 ∀𝑗
b) Assume that the cost of transporting a machine from plant B increases by €10 for all the machines as of the third one;
that is, the 4th, the 5th, etc. Reformulate the model in Section a) by considering this assumption. In this case, we need to
define a new decision variable to factor in the extra costs incurred if we source more than three machines from plant B.
Let us note these new decision variables as 𝑥*𝐵𝑗 and represents the machines that are sourced from factory B from the
third machine. Le us also note as 𝑐*𝐵𝑗 the additional costs incurred from the third machine:
228 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Plant/Warehouse X Y Z
B 70 50 30
𝑥 *𝐵𝑗 +𝑀 * 𝑌 ≥ 0 ∀𝑗
𝑥*𝐵𝑗 ≤ 𝑀 * (1 − 𝑌 ) ∀𝑗
Where M is a very large number. To explain the introduction of the binary decision variables and the set of constraints,
note that what we want to accomplish is the following logic:
“if 𝑗 𝑥𝐵𝑗 = 3 then 𝑥*𝐵𝑗 ≥ 0 else 𝑥*𝐵𝑗 = 0”
∑︀
𝑥 *𝐵𝑗 +𝑀 * 𝑌 ≥ 0 ∀𝑗
These constraints correspond to the left side of the ∨ operator.
Similarly, to account for the right hand side, we introduce the constraints:
∑︀
𝑗 𝑥𝐵𝑗 − 3 ≤ 𝑀 * (1 − 𝑌 )
𝑥*𝐵𝑗 ≤ 𝑀 * (1 − 𝑌 ) ∀𝑗
Note that, if Y = 0, the logical constraints become:
∑︀
𝑗 𝑥𝐵𝑗 ≤ 3
𝑗 𝑥𝐵𝑗 − 3 ≥ 0 (and as per the previous constraint, the sum can only be equal to 3).
∑︀
𝑥*𝐵𝑗 ≥ 0 ∀𝑗
𝑥*𝐵𝑗 ≤ 0 ∀𝑗 (and since they cannot be negative, they must be equal to zero)
Since the constraint 𝑗 𝑥𝐵𝑗 − 3 ≤ 𝑀 * (1 − 𝑌 ) is irrelevant when Y=0 and when Y=1, it is removed, and we get the
∑︀
set of constraints in the solution above.
Solution in Python
The following script solves the problem using Python. ### Requirements First, install the requirements:
[ ]: !pip install pulp
!pip install pandas
!pip install IPython
[ ]: import pulp
import pandas as pd
#And we will use numpy to perform array operations
import numpy as np
#We will use display and Markdown to format the output of code cells as Markdown
from [Link] import display, Markdown
# Instantiate model
model = [Link]("Transport Planning", [Link])
# Demand
demand = [5, 4, 3]
# Capacities
capacities = [8, 5, 3]
variables = [Link]("x",
[(i, j) for i in plants for j in warehouses],
lowBound=0,
cat= Integer )
model += (
[Link]([
transportation_costs[i][j] * variables[(plants[i], warehouses[j])]
for i in range(len(plants)) for j in range(len(warehouses))])
), "Transportation Cost"
# Capacity constraints
(continues on next page)
230 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
# Demand
for j in range(len(warehouses)):
model += [Link]([
variables[(plants[i], warehouses[j])]
for i in range(len(plants))]) >= demand[j], warehouses[j]
# Instantiate model
model = [Link]("Transport Planning", [Link])
# Demand
demand = [5, 4, 3]
# Capacities
capacities = [8, 5, 3]
variables = [Link]("x",
[(i, j) for i in plants for j in warehouses],
lowBound=0,
cat= Integer )
model += (
[Link]([
transportation_costs[i][j] * variables[(plants[i], warehouses[j])]
for i in range(len(plants)) for j in range(len(warehouses))])
), "Transportation Cost"
# Capacity constraints
for i in range(len(plants)):
model += [Link]([
variables[(plants[i], warehouses[j])]
for j in range(len(warehouses))]) <= capacities[i], plants[i]
# Demand
for j in range(len(warehouses)):
model += [Link]([
variables[(plants[i], warehouses[j])]
for i in range(len(plants))]) >= demand[j], warehouses[j]
# Solution
max_z = [Link]([Link])
print(max_z)
Optimal
460.0
[ ]:
Problem definition
Patrick “Eel” O’Brian’s (PEOB) Ltd. is a company that manufactures plastic components for the automotive sector. As an
intern at PEOB Ltd, your first assignment is to write an Integer Programming Model to calculate the optimal production
plan for the plastic injection machine. The injection machine heats plastic and injects it into a mould to get a specific
shape. Each mould can thus only be used to manufacture specific component types. Your first version will take into
account the storage costs and the delayed orders cost which are defined below.
Storage costs The storage or inventory costs represent the cost of storing the inventory levels of every component type
at every planning period and are modeled as a fixed cost per unit and planning period. The storage costs are different for
every component type.
Delayed orders costs At every planning period, you may delay part of the demand for the next planning period. Customers
will apply a fixed penalty for every delayed unit at every period. The delayed costs are also different for every component
type.
Your model needs to take into account the following additional data:
Initial Inventory Levels (units): There is an initial inventory level for every component type available at the first planning
period that needs to be taken into account.
Minimum and Maximum Inventory Levels (units): There is a maximum and a minimum inventory level for every
component type.
Machine capacity (units): The machine capacity represents the number of units of a given component type that the
machine can produce using a given mould. If a mould cannot be used to manufacture a component type, the machine
capacity is zero for that combination of component type and mould.
232 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Demand (Units): The company has several confirmed orders for the following periods and therefore, our model needs
to take into account the demand for every product at every planning period.
a. Write down the indexes and decision variables Indices
• t = periods to produce 𝑡 ∈ [0, .., 𝑇 ]
• m = moulds 𝑚 ∈ [0, .., 𝑀 ]
• p = products 𝑝 ∈ [0, .., 𝑃 ]
Decision Variables
• 𝑌𝑝𝑡 = units to store for product p on period t (Integer)
• 𝐷𝑝𝑡 = delayed production for product p on period t (Integer)
• 𝑋𝑝𝑡 = production for product p on period t (Integer)
• 𝑆𝑚𝑡 = (Binary) {1 if mould m is used on period t, 0 otherwise}
b. Write down the objective function The objective function is to minimise storage costs and delayed order costs (eur):
∑︀𝑇 ∑︀𝑃 ∑︀𝑇 ∑︀𝑃
min 𝑧 = 𝑡=0 𝑝=0 𝐶𝑑 ·𝐷𝑝𝑡 + 𝑡=0 𝑝=0 𝐶𝑠 ·𝑌𝑝𝑡 (eur)
Where:
• 𝐶𝑠 represents the storage costs per unit and period (eur)
• 𝐶𝑑 represents the delayed order costs per unit and period (eur)
c. Write down the constraints
Problem Data
• 𝑀𝑚𝑝 Machine Capacity using mould m to produce product p(units)
• 𝑅𝑝𝑡 Demand for product p in period t
• 𝑌𝑝0 Initial inventory level of product p
• 𝑌𝑝𝑚𝑎𝑥 Maximum inventory level of product p
• 𝑌𝑝𝑚𝑖𝑛 Minimum inventory level of product p
Machine Capacity Constraint The machine capacity constraint ensures that the model is consistent and that the machine
capacity is not exceeded.
∑︀𝑀
𝑋𝑝𝑡 = 𝑚=0 𝑀𝑚𝑝 ·𝑆𝑚𝑡 ∀𝑝, 𝑡
That is, the number of units produced in period t of product p is equal to the sum of the machine capacity of the machine
using the mould m multiplied by the binary decision variable that determines if the mould is used at period t.
Mould Constraint The second constraint ensures that the model is consistent and only one mould is used in one period:
∑︀𝑀
𝑚=0 𝑆𝑚𝑡 = 1∀𝑡
That is, since we do not have any inventory left nor delayed production from period -1 (the problem starts in t=0), we
need to modify slightly the demand constraint for t = 0.
Inventory levels
We need to ensure that the inventory levels are within the minimum and maximum levels:
𝑌𝑝𝑡 ≥ 𝑌𝑚𝑖𝑛𝑝 ∀𝑝, 𝑡
𝑌𝑝𝑡 ≤ 𝑌𝑚𝑎𝑥𝑝 ∀𝑝, 𝑡
You have successfully validated your model, and it is already providing valuable information for the company. Now the
company would like to extend the model to take into account as well the set-up costs:
Set up costs As explained above, the injection machine uses different moulds to manufacture different parts. Each time
that a mould is changed to make a different component, the operators need to set up the machine. The company estimates
that this setup cost only depends on the mould that is used and is only applied when a product is changed.
d. Modify the model to take into account the set-up costs.
We introduce a new decision variable to model the sequence of mould changes and simplify the model:
• 𝑆𝑢𝑚𝑡 Mould setup sequence (Binary) 1 if mould m is changed in period t, 0 otherwise.
• 𝐶𝑚 Setup costs of mould m (Eur).
Now, the objective function becomes:
∑︀𝑇 ∑︀𝑀 ∑︀𝑇 ∑︀𝑃 ∑︀𝑇 ∑︀𝑃
min 𝑧 = 𝑡=0 𝑚=0 𝐶𝑚 ·𝑆𝑢𝑚𝑡 + 𝑡=0 𝑝=0 𝐶𝑠 ·𝐷𝑝𝑡 + 𝑡=0 𝑝=0 𝐶𝑑 ·𝑌𝑝𝑡 (Eur)
We also need to introduce the following constraints for the new decision variable:
𝑆𝑢𝑚0 = 𝑆𝑚0 ∀𝑚
Meaning that we take into account the costs of the initial setup of the machine.
𝑆𝑢𝑚𝑡 ≥ 𝑆𝑚𝑡 − 𝑆𝑚𝑡−1
Meaning that we only take into account in the costs mould changes (that is, when the mould used is different for two
consecutive periods).
Try me
Problem Definition
A firm must transport machines from production plants A, B and C to warehouses X, Y and Z. Five machines are required
in X, four in Y and three in Z and there are eight machines available in A, five in B and three in C. a) Contemplate and
solve a Graph Theory model to determine the maximal flow of the machines that can be transported and the run of this
flow. b) By assuming a mean cost of €45 per transported machine, what would the total cost be of transporting the
machines obtained in the former section?
234 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Requirements
Run the following script to install the packages used in the exercise:
Solution
We are going to use [networkx] ([Link] to draw the network and find the maximal flow at a minimum
cost between two nodes. We are going to create a graph to model the transport process, the network will comprise the
Source node (node S), production plant nodes (nodes A, B, and C), warehouse nodes (nodes X, Y, and Z), and a sink
node (node T). Edges are going to have two attributes:
• 𝑏𝑖 : maximum capacity (number of machines) of each production plant or warehouse
• 𝑐𝑖 : cost, cost for the company to move one machine (€).
The flow of edges going from source node S to each production plant represent the available machines at each
production plant. These edges have a capacity equal to machines available at each production plant, and a cost of 0;
The flow of edges going from each production plant to each warehouse represents the machines transported by the
company from each production plant to each warehouse. The edges will have a maximum capacity equal to the
machines available at each production plan, and a cost of 45€. Finally, flow in edges from the warehouse nodes to the
sink node represent the total number of machines in each warehouse. These edges will have a maximum capacity equal
to the demand of each warehouse, a company cost of 0.
[3]: # Import the libraries that we are going to use, Network x to import the
import networkx as nx
import [Link] as plt
[Link](G, pos)
nx.draw_networkx_edges(G, pos, weight=2)
nx.draw_networkx_nodes(G, pos, node_size=600, node_color= #efefef )
nx.draw_networkx_labels(G, pos, font_weight= bold )
236 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
[ ]: import pandas as pd
from [Link] import display, Markdown
[ ]: optimal_flow = {}
for k,v in [Link]():
for k2 in [Link]():
optimal_flow[k,k2] = flow[k][k2]
[Link](G, pos)
nx.draw_networkx_edges(G, pos, weight=2)
nx.draw_networkx_nodes(G, pos, node_size=600, node_color= #efefef )
nx.draw_networkx_labels(G, pos, font_weight= bold )
nx.draw_networkx_edge_labels(G, pos, edge_labels=optimal_flow)
[ ]:
Problem Definition
A low-cost airline, ACP (Flying High), operates four daily flights from Valencia to London at 10:00, 12:00, 14:00 and
16:00 hours. The first two flights hold 100 passengers, and the last two can fly up to 150 passengers each. If overbooking
occurs, which implies having sold more seats than the plane actually has, the airline can place a passenger on a later flight.
Evidently each delayed traveller is compensated by being paid €200 plus €20 for each hour delayed. The firm places
delayed travellers on their own operating flights, or on one of the flights from other airlines departing at 20:00 hours, which
always have available seats (a capacity of 999 passengers is always considered) at no extra charge. Let us assume that at
the beginning of the day we know that ACP has sold 110, 160, 100 and 100 seats on its four daily flights, respectively.
Model this problem as a maximal flow model at a minimum cost in order to minimise the airline’s total overbooking cost.
Solution
We are going to use networkx to draw the network and find the maximal flow at a minimum cost between two nodes. We
are going to create a graph to model the selling process as a system with different states: source state (containing node S),
flights sold state (comprised of nodes 10s, 12s, 14s, 16s), flights used state (comprised of nodes 10u, 12u, 14u, 16u, and
20u), and a sink state (containing node T). Edges are going to have two attributes:
• 𝑎𝑖 : maximum capacity in number of flight tickets sold or used
• 𝑐𝑖 : cost, cost for the company to move a passenger from one adjacent node to the other
The flow of edges going from source node S to each flight sold state node flight represent the seats sold (edge S,10s
represents the flights sold for flight at 10:00h, edge S,12s for the flight at 12:00s, etc.). These flights have a capacity equal
to the number of tickets sold (110, 160, 100 and 140 respectively), and a cost of 0; The flow of edges going from each
flight sold state to each flight used state represents how the company arranges passengers in the different flights. The edges
will have a maximum capacity equal to the maximum number of passengers in each flight (100, 100, 150, 150 and 999)
respectively, and a cost equal to the overbooking cost for each delayed flight (that is, zero for no delay, 240 for two hours
late, 280 for hours late, and so on).
Finally, flow in edges from the flights used state nodes to the sink node represent the total number of seats used in each
plane. These edges will have a maximum capacity equal to the maximum capacity of each plane and a company cost of
0.
238 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
[Link](G, pos)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_nodes(G, pos, node_size=600, node_color= #efefef )
nx.draw_networkx_labels(G, pos, font_weight= bold )
c_label = nx.get_edge_attributes(G, cost )
nx.draw_networkx_edge_labels(G, pos, edge_labels=c_label)
240 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
[16]: optimal_flow = {}
for i in [Link]():
for j in flow[i].keys():
optimal_flow[i,j] = flow[i][j]
[Link](G, pos)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_nodes(G, pos, node_size=600, node_color= #efefef )
nx.draw_networkx_edge_labels(G, pos, edge_labels=optimal_flow)
print(flow)
{ S : { 10s : 110, 12s : 160, 14s : 100, 16s : 140}, 10s : { 10u : 100, 12u : 0,
˓→ 14u : 0, 16u : 0, 20u : 10}, 12s : { 12u : 100, 14u : 50, 16u : 10, 20u : 0},
˓→ 14s : { 14u : 100, 16u : 0, 20u : 0}, 16s : { 16u : 140, 20u : 0}, 10u : { T
˓→ : 100}, 12u : { T : 100}, 14u : { T : 150}, 16u : { T : 150}, 20u : { T : 10},
˓→ T : {}}
[ ]:
Problem Definition
PLACASA, a supplier of plastic injection parts for the automobile sector, foresees the demand of an article for the
following 4 months of 100, 140, 210 and 180 units, respectively. The firm can maintain only sufficient stock to meet the
demand of each month, or it can have excess stock to meet the demand of two successive months or more with a storage
cost of 1.2€ per month and unit of excessive stock. PLACASA calculates that the production cost for the following
months, is €15, €12, €10 and €14 per unit. A preparation cost of €200 is incurred every time a production order is
placed. The firm wishes to develop a production plan that minimises the total costs of production orders, of production
and of keeping an article in stock. Formulate and solve the shortest path model to find an optimum production plan.
242 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Solution
We are going to use [networkx] ([Link] to draw the network and find the shortest path between two
nodes. Each node in the graph is going to represent a production period (one month). Thus, there will be 5 nodes, for
month 0 (current month) and the four following months. Edges (i,j) represent the decision to produce in month i all the
demand up to month j. For instance, edge 01 means that we decide to manufacture in month 0 100 units, which is the
demand in month 1, and 04 means that we decide to manufacture in month 0 100+140+210+180=650 units, which is the
demand forecast for the forthcoming 4 months. To calculate the costs, we need to apply the production cost 𝑐𝑝𝑖 , storage
cost 𝑐𝑠, and preparation costs 𝑐𝑃 .
∑︀𝑗
𝑐𝑖𝑗 = 𝑐𝑃 + 𝑘=𝑖+1 𝑑𝑘 ·(𝑐𝑝𝑖 + (𝑘 − 1)·𝑐𝑠)
∑︀1
𝑐01 = 200 + 𝑘=1 𝑑𝑘 ·(𝑐𝑝0 + (𝑘 − 1)·𝑐𝑠) = 200 + 100·(15 + 0·1.2) = 1500
∑︀2
𝑐02 = 200 + 𝑘=1 𝑑𝑘 ·(𝑐𝑝0 + (𝑘 − 1)·𝑐𝑠) = 200 + 100·(15 + 0·1.2) + 140·(15 + 1·1.2) = 3968
…
∑︀4
𝑐24 = 200 + 𝑘=3 𝑑𝑘 ·(𝑐𝑝2 + (𝑘 − 1)·𝑐𝑠) = 200 + 210·(10 + 0·1.2) + 180·(10 + 1·1.2) = 4316
∑︀4
𝑐34 = 200 + 𝑘=4 𝑑𝑘 ·(𝑐𝑝2 + (𝑘 − 1)·𝑐𝑠) = 200 + 180·(14 + 0·1.2) = 2720
The following code shows the solution in Python.
#Calculate the shortest path from 0 to 4, using the attribute cost as edge weight
shortest_path = nx.shortest_path(G, 0, 4, weight="cost")
# Calculate the production per month, and the total cost using the shortest path␣
˓→solution and the cost attribute
total_cost = 0
production = {}
for i in range(len(shortest_path)-1):
total_cost+=G[shortest_path[i]][shortest_path[i+1]][ cost ]
production[i]={ production : G[shortest_path[i]][shortest_path[i+1]][ production
˓→ ]}
edges_df = nx.to_pandas_edgelist(G);
nx.draw_networkx_edges(G, pos)
nx.draw_networkx_nodes(G, pos, node_size=600, node_color= #efefef )
nx.draw_networkx_labels(G, pos, font_weight= bold )
c_label = nx.get_edge_attributes(G, production )
nx.draw_networkx_edge_labels(G, pos, edge_labels=c_label)
[Link]( equal )
[Link]( off )
[Link]()
244 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
[ ]:
Problem Definition
A manufacturer of the metal sector in Stafford manufactures four types of products in sequence on two machines. The
Table below provides the necessary technical production [Link] into account only the data on the production times
per product and the maximum daily production capacity of each machine, and taking a maximum daily production of
100 units of each product type, consider and solve a maximal flow model in a graph to determine the maximum number
of minutes during which machines 1 and 2 can operate on a production-in-sequence basis given the existing capacity
constraints.
Solution
This is an example of how graph theory can be used to solve production sequencing problems. In this case, the resource
that we want to optimise is machine time. The flow in our graph is going to represent machine time and the unit is going
to be minutes. We will have a source node, one node representing the first step of the sequence (machine 1), four nodes
representing the different products to be manufactured, another node for the second step of the process (machine 2), and a
sink node. The capacity of the edge between the source node and the Machine 1 node is equal to the machine production
capacity (500), since it is the total number of minutes that we can use in that machine. The capacities of edges between
the machine 1 node and the products nodes are the production times in that machine times the number of units (200, 300,
400, 200), since it is the maximum time that we can invest in each time of product in machine 1. Likewise, the edges
between the product nodes and the machine 2 node are 300, 200, 100, and 200, and the capacity of the edge between the
machine 2 node and the sink node is 380.
246 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
[Link](G, pos)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_nodes(G, pos, node_size=600, node_color= #efefef )
nx.draw_networkx_labels(G, pos, font_weight= bold )
c_label = nx.get_edge_attributes(G, capacity )
nx.draw_networkx_edge_labels(G, pos, edge_labels=c_label)
[ ]:
Problem definition
Planet Express deliveries wants to optimize their transportation network from a set of source warehouses to a set of
destinations. In particular, they want to minimize the transportation costs through a set of intermediate warehouses, so
that items are transported from the source warehouses, through the intermediate warehouses, to the destination regions.
Let us first consider that transportation costs per item from the source warehouse 𝑖 to intermediate warehouse 𝑗 as 𝑠𝑖𝑗
and that the transportation costs per item from intermediate warehouse 𝑗 to destination region 𝑘 is 𝑡𝑗𝑘 . Let us note the
capacity of source warehouses as 𝑎𝑖 items, the capacity of intermediate warehouses 𝑗 as 𝑏𝑗 items, and the demand for
region 𝑘 as 𝑑𝑘 items. Let us also consider that 𝑚 is the number of source warehouses, 𝑛 is the number of intermediate
warehouses and 𝑝 is the number of destination regions.
a Consider that m = p = 3 and n = 5 and draw a network to solve the transportation problem as a maximal flow at minimum
cost problem.
The network consists of a Source Node, 3 nodes that represent the source warehouses, 5 nodes that represent the inter-
mediate warehouses, and 3 nodes that represent the destination regions. The edges must be labeled with the capacities
and the costs. In the figure below, capacities and costs of every edge are labeled as “capacity, cost”, e.g. an edge with
capacity 𝑎11 and cost 𝑠11 is labeled as 𝑎11 , 𝑠11 . For the sake of clarity, only the first and last edges are labeled at every
stage:
248 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
b Model the problem as a Mixed Integer Programming (MIP), not taking into account the values of m,p, and n defined
in the previous section
Decision variables
• 𝑥𝑖𝑗 : (Integer) Number of units to transport from source warehouse i to intermediate warehouse j
• 𝑦𝑗𝑘 : (Integer) Number of units to transport from intermediate warehouse j to destination region k
The linear model is then:
min 𝑧 = 𝑖 𝑗 𝑠𝑖𝑗 * 𝑥𝑖𝑗 + 𝑗 𝑘 𝑡𝑗𝑘 * 𝑦𝑗𝑘
∑︀ ∑︀ ∑︀ ∑︀
𝑠.𝑡.
Source warehouse capacity constraints:
∑︀
𝑗 𝑥𝑖𝑗 ≤ 𝑎𝑖 ∀𝑖
Intermediate warehouse capacity constraints:
∑︀
𝑘 𝑦𝑗𝑘 ≤ 𝑏𝑗 ∀𝑗
Demand constraints:
∑︀
𝑗 𝑦𝑗𝑘 ≥ 𝑑𝑘 ∀𝑘
Flow constraints:
∑︀ ∑︀
𝑖 𝑥𝑖𝑗 = 𝑘 𝑦𝑗𝑘 ∀𝑗
c Planet Express is now considering the use of warehouses from an external provider. The provider of the service has
a total of 𝑛𝑒 external warehouses. They offer a fixed cost 𝐹𝑙 when an external warehouse 𝑙 is used, plus a cost per item
received and processed in warehouse 𝑙, 𝑟𝑙 . External warehouse 𝑙 has a capacity of 𝑐𝑙 items. Modify your model to
incorporate this offer into your distribution network.
The following decision variables are introduced in the model:
• 𝑌𝑙 : (Binary) Indicates if external warehouse 𝑙 is used
• 𝑥′𝑖𝑙 : (Integer) Number of units to transport from source warehouse i to external intermediate warehouse l
• 𝑦𝑙𝑘
′
: (Integer) Number of units to transport from external intermediate warehouse l to destination region k
The model is now:
min 𝑧 = 𝑖 𝑗 𝑠𝑖𝑗 * 𝑥𝑖𝑗 + 𝑗 𝑘 𝑡𝑗𝑘 * 𝑦𝑗𝑘 + 𝑙 𝑌𝑙 * 𝐹𝑙 + 𝑖 𝑙 𝑟𝑙 * 𝑥′𝑖𝑙
∑︀ ∑︀ ∑︀ ∑︀ ∑︀ ∑︀ ∑︀
𝑠.𝑡.
Source warehouse capacity constraints:
∑︀ ∑︀ ′
𝑗 𝑥𝑖𝑗 + 𝑙 𝑥𝑖𝑙 ≤ 𝑎𝑖 ∀𝑖
𝑥′𝑖𝑙 = ′
∑︀ ∑︀
𝑖 𝑘 𝑦𝑙𝑘 ∀𝑙
Logical constraint:
∑︀ ′ ∑︀
𝑖 𝑥𝑖𝑙 ≤ 𝑀 * 𝑙 𝑌𝑙
Problem Definition
You work for a company that manufactures high quality polymer parts for OrgoCorp, a galactic bioengineering company.
The quality requirements are so high that you need to use very sophisticated 3D printing machines. You need to develop
a mathematical programming model to organize monthly production considering:
• Fixed operational costs (euros): Each 3D printing machine 𝑚 has a different fixed operational costs 𝐹 𝑚 that
needs to be considered when a printing machine is used to print any units.
• Unitary production costs (euros): Each 3D printing machine 𝑚 produces parts of product type 𝑝 at a different
unitary costs 𝐶𝑚𝑝
• Capacity (minutes): Each 3D printing machine 𝑚 has a different capacity 𝑆𝑚 (minutes)
• Speed (minutes/part): Each 3D printing machine 𝑚 prints a unit of product type 𝑝 at a different unitary speed
• Demand (units): OrgoCorp has confirmed a demand for 𝑑𝑝 units of every product type 𝑝 Build a model that takes
into account these requirements, identifying indices, decision variables, objective function and constraints.
The CEO of OrgoCorp, The High Evolutionary, would like to set up a new contract allowing more flexibility in the
delivery of units, such that:
• Demand per period (units): Now you need to consider that the demand for every product type 𝑝 is not constant
and depends on the planning period 𝑡, 𝐷𝑝𝑡
• Delayed demand (units): You may delay the production for one period. For every unit of product type 𝑝 that is
delayed, OrgoCorp will charge an extra delayed demand cost of 𝐵𝑝𝑡 Modify the model to take into account this
new contract
Solution
Indices
250 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Decision Variables
Objective Function
Constraints
• Capacity constraint: The total time used by all the 3D printing machines cannot exceed the total capacity of the
machines
𝑃
∑︁
𝑥𝑚𝑝 ·𝑇𝑚𝑝 ≤ 𝑆𝑚 ·𝑌𝑚 ∀𝑚 ∈ [1, 2, ..., 𝑀 ]
𝑝=1
Where 𝑇𝑚𝑝 is the time needed (in minutes) to print a unit of product type 𝑝 in 3D printing machine 𝑚. Based on the
data provided, this time is calculated as the inverse of the speed of the machine for that product type, which we can note
as 𝑆𝑚𝑝 , that is 𝑇𝑚𝑝 = 𝑆𝑚𝑝1
Note that we are using the binary variable 𝑌𝑚 to ensure that the capacity constraint is only considered if the machine is
used.
• Demand constraint: The total number of units of product type 𝑝 printed by all the 3D printing machines must be
equal or greater than the demand for that product type
𝑀
∑︁
𝑥𝑚𝑝 = 𝑑𝑝 ∀𝑝 ∈ [1, 2, ..., 𝑃 ]
𝑚=1
That is, the total number of units of product type 𝑝 printed by all the 3D printing machines must be equal to the demand
for that product type. We could add some slack to this constraint, making the demand constraints of type greater or equal,
but we are assuming that the demand is always met exactly (being a precision parts company, we cannot afford to deliver
more or less units than the ones requested).
Model
s.t
𝑃
∑︁
𝑥𝑚𝑝 ·𝑇𝑚𝑝 ≤ 𝑆𝑚 ·𝑌𝑚 ∀𝑚 ∈ [1, 2, ..., 𝑀 ]
𝑝=1
𝑀
∑︁
𝑥𝑚𝑝 = 𝑑𝑝 ∀𝑝 ∈ [1, 2, ..., 𝑃 ]
𝑚=1
Based on the model proposed in part I, we need to introduce a new index 𝑡 to represent the planning period. We also need
to modify the decision variables to introduce the new index and allow our solution to adapt production in each period to
demand. Therefore, the decision variables 𝑥𝑚𝑝 now becomes 𝑥𝑚𝑝𝑡 , and 𝑌𝑚 becomes 𝑌𝑚𝑡 . We also need to introduce a
new set of decision variables to model delayed demand, 𝐷𝑚𝑝𝑡 , which represents the number of units of product type 𝑝
that are delayed in period 𝑡 and printed in period 𝑡 + 1 by 3D printing machine 𝑚, and modify the objective function and
constraints accordingly.
Indices
Decision Variables
• 𝑥𝑚𝑝𝑡 : (Integer) Number of units of product type 𝑝 printed by 3D printing machine 𝑚 in period 𝑡
• 𝑌𝑚𝑡 : (Binary) 1 if 3D printing machine 𝑚 is used in period 𝑡, 0 otherwise
• 𝐼𝑝𝑡 : (Integer) Number of units of product type 𝑝 delayed in period 𝑡 and printed in period 𝑡 + 1
Objective Function
∑︁ 𝑀
𝑇 ∑︁ ∑︁ 𝑀 ∑︁
𝑇 ∑︁ 𝑃 𝑇 ∑︁
∑︁ 𝑃
min 𝑧 = 𝐹𝑚 ·𝑌𝑚𝑡 + 𝐶𝑚𝑝 ·𝑥𝑚𝑝𝑡 + 𝐵𝑝𝑡 ·𝐼𝑝𝑡
𝑡=1 𝑚=1 𝑡=1 𝑚=1 𝑝=1 𝑡=1 𝑝=1
where the first term are the fixed operational costs, the second term are the unitary production costs and the third term
are the delayed demand costs.
Constraints
• Capacity constraint: The total time used by all the 3D printing machines cannot exceed the total capacity of the
machines. We need to consider the time period:
𝑃
∑︁
𝑥𝑚𝑝𝑡 ·𝑇𝑚𝑝 ≤ 𝑆𝑚 ·𝑌𝑚𝑡 ∀𝑚 ∈ [1, 2, ..., 𝑀 ], ∀𝑡 ∈ [1, 2, ..., 𝑇 ]
𝑝=1
• Demand constraint: The total number of units of product type 𝑝 printed by all the 3D printing machines must be
equal or greater than the demand for that product type. Now, we need to make sure that the units produced satisfy
the demand and the delayed demand:
𝑀
∑︁
𝑥𝑚𝑝𝑡 = 𝐼𝑝𝑡−1 + 𝐷𝑝𝑡 − 𝐼𝑝𝑡 ∀𝑝 ∈ [1, 2, ..., 𝑃 ], ∀𝑡 ∈ [1, 2, ..., 𝑇 ]
𝑚=1
252 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
That is, the number of units produced in period 𝑡 must be equal to the units delayed in the previous period 𝑡 − 1 plus the
demand in period 𝑡 minus the units delayed for the next period 𝑡 + 1. Note that we are considering that the units delayed
in period 𝑡 are printed in period 𝑡 + 1, so we need to consider the units delayed in period 𝑡 − 1 to calculate the units
produced in period 𝑡. Finally, we are considering that there are no units delayed in the previous period 𝑡 = 0.
Model
s.t
𝑃
∑︁
𝑥𝑚𝑝𝑡 ·𝑇𝑚𝑝 ≤ 𝑆𝑚 ·𝑌𝑚𝑡 ∀𝑚 ∈ [1, 2, ..., 𝑀 ], ∀𝑡 ∈ [1, 2, ..., 𝑇 ]
𝑝=1
𝑀
∑︁
𝑥𝑚𝑝𝑡 = 𝐼𝑝𝑡−1 + 𝐷𝑝𝑡 − 𝐼𝑝𝑡 ∀𝑝 ∈ [1, 2, ..., 𝑃 ], ∀𝑡 ∈ [1, 2, ..., 𝑇 ]
𝑚=1
Spellman’s would like Sabrina to focus on the optimization of their distribution network, to support the distribution of
the 2 types of drinks from 3 sourcing facilities to 4 destination warehouses, through 6 intermediate warehouses. Sabrina
needs to take into account the transportation costs (both from sourcing warehouses to intermediate warehouses and from
intermediate warehouses to final destinations). Additionally, Sabrina can decide how many of the 6 intermediate solutions
to use, given that they have a fixed operational cost that needs to be paid when the warehouse is used.
The following tables contain the transportation problem data:
From/To I1 I2 I3 I4 I5 I6
S1 2 4 5 7 3 6
S2 3 2 6 8 4 5
S3 1 3 4 6 5 7
From/To D1 D2 D3 D4
I1 5 2 3 4
I2 4 1 5 2
I3 3 4 2 5
I4 5 3 4 1
I5 2 5 3 4
I6 4 2 1 5
Note that the distribution costs are independent of the product type.
1. Help Sabrina write an Integer Programming Problem to model the transportation problem .
Index - 𝑖: Index of the sourcing warehouse - 𝑗: Index of the intermediate warehouse - 𝑘: Index of the destination
warehouse - 𝑙: Index of the product type
Decision variables - 𝑥𝑖𝑗𝑙 : Number of units of product 𝑙 transported from sourcing warehouse 𝑖 to intermediate warehouse
𝑗 (Integer) - 𝑦𝑗𝑘𝑙 : Number of units of product 𝑙 transported from intermediate warehouse 𝑗 to destination warehouse 𝑘
(Integer) - 𝑍𝑗 : Binary variable indicating if intermediate warehouse 𝑗 is used (Binary)
Objective function min 𝑧 = 𝑗 𝑍𝑗 * 𝐹𝑗 + 𝑖 𝑗 𝑙 𝑠𝑖𝑗𝑙 * 𝑥𝑖𝑗𝑙 + 𝑗 𝑘 𝑙 𝑡𝑗𝑘𝑙 * 𝑦𝑗𝑘𝑙
∑︀ ∑︀ ∑︀ ∑︀ ∑︀ ∑︀ ∑︀
Where 𝐶𝑖𝑙 is the capacity of sourcing warehouse 𝑖 for product 𝑙. The capacities are indicated in the table above.
• Destination demand constraints: 𝑗 𝑦𝑗𝑘𝑙 = 𝐷𝑘𝑙 ∀𝑘 ∀𝑙
∑︀
Where 𝐷𝑘𝑙 is the demand of destination warehouse 𝑘 for product 𝑙. The demands are indicated in the table above.
254 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Problem Definition
Professor Xavier’s School for Gifted Youngsters is organizing a special summer session focusing on enhancing the students’
unique abilities. Students from across the country have been invited, and the school needs to arrange their transportation.
The goal is to ensure that all students can arrive at the school in time for the session while minimizing transportation costs.
1. First, let us consider an abstract model where gifted students reside in 𝑛 different locations, can can be transported in
𝑚 different modes of transport. Each mode of transport from each location to the school has a different associated
cost. Additionally, each transportation mode has a different capacity, and each location has a different number
of gifted students that need transportation to the school. Write down an Integer Programming (IP) problem that
minimizes the overall transportation costs.
Index - 𝑖 ∈ {1, 2, ..., 𝑛}: Index for the locations - 𝑗 ∈ {1, 2, ..., 𝑚}: Index for the modes of transport
Decision Variables: - 𝑥𝑖𝑗 : Number of students transported from location 𝑖 to the school using mode of transport 𝑗. 𝑥𝑖𝑗
is an integer variable.
Objective Function: Minimize the total transportation cost:
∑︀𝑛 ∑︀𝑚
min 𝑧 = 𝑖=1 𝑗=1 𝑐𝑖𝑗 𝑥𝑖𝑗
Where 𝑐𝑖𝑗 is the cost of transporting a student from location 𝑖 to the school using mode of transport 𝑗.
Constraints:
1. Ensure that all students are transported to the school:
∑︀𝑚
𝑗=1 𝑥𝑖𝑗 = 𝑠𝑖 , ∀𝑖 ∈ {1, 2, ..., 𝑛}
And the following capacities and costs of transport per student from the different locations for three different modes of
transport:
Mode Capacity L1 L2 L3 L4 L5 L6
T1 50 10 8 12 11 9 7
T2 60 9 7 11 10 8 6
T3 40 8 9 10 12 7 11
Draw a graph that allows to model the transportation problem as a maximum flow at minimum cost transportation problem.
Try me
Introduction
This notebook provides an overview and tutorial of Networkx, a Python package to create, manipulate, and analyse graphs
with an extensive set of algorithms to solve common graph theory problems. Basically, we will use Networkx to build a
network model of the network, and present some of the most important algorithms to solve the problems covered in the
book, and finally we will see some nice add-ons and tools to draw networks and create networks from other data structures
such as open maps!
256 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Requirements
You need to install Networkx in your runtime, so make sure you run this script if not already installed.
Note that the installation line includes the extra option to install additional packages which are useful to work with Net-
workx.
Instalation
[ ]: import networkx as nx
The basics
Creating networks
We can create different types of graphs with the following constructor functions. Review the definitions in the Graph
theory tutorial:
• [Link]: Creates an object representing an undirected graph.
• [Link]: Creates an object representing a directed Graph
• [Link]: Creates an object representing a with multiple edges between any pair of nodes
• [Link]: Directed graph with multiple edges between any pair of nodes
By default, graphs are created without nodes or edges. The simplest way to add edges and nodes is to use the class methods
add_node and add_edge. The former adds the object that is passed as argument as a node of the graph. We can add
as a node a string variable, a numeric, or a tuple with several values which are relevant for our application. In fact, we
can add any hashable object, any object that will not change during the execution of the program. Functions and objects
of user-defined classes are also hashable by default. You can find the precise definition of hashable in the glossary, but
what is important is that Python can assign a unique identifier to each hashable object, and networkx uses these feature
to identify each node of the network. Normally, we will use simple types like strings or integers, with different values
for each node. The function add_edge creates and edge passing between two objects are arguments. If the objects are
already in the network, it will create an edge between the two, as long as the type of network allows it (if not, it will raise
an exception). If any of the objects passed as arguments are not in the network, the function will also add them as nodes.
For instance:
We can add attributes to the edges. We can define as many attributes as we want and pass them as named arguments to
the add_edge function, for instance:
Graph properties describe the structure of the graph, for instance, the list of nodes and edges. Some important properties
are:
• nodes: Provides a list containing the nodes of the graph. Each element of the list is the object used to add a node.
• edges: Provides the list of the edges of the graph. Each edge is represented as a tuple where the first element is
the object that represents the origin node and the second element is the object that represents the destination node.
• adjacency: The adjacency provides a dictionary containing the information in the adjacency matrix. Normally,
the adjacency matrix will be sparse (containing lots of zeroes) and, for the sake of efficiency, networkx represents
the adjacency as a dictionary where the node objects are keys and the values are dictionaries with the information
of the edges with origin at the key node. The information of the edges are also dictionaries, where each key is the
destination node object and the values are dictionaries with the attributes of the edge (see example below).
• degree: The degree of each node of the graph is represented as a tuple where the first element is the node object
and the second element an integer with the degree of the graph.
• size(): The size of the graph (integer)
• order(): The order of the graph (integer)
Let`s see these properties with the example above:
# The edges:
print(my_first_Graph.edges)
# The adjacency:
print(my_first_Graph.adj)
# Or the order:
print(my_first_Graph.order())
258 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Algorithms
Networkx has an extensive library of algorithms to solve graph theory problems, ranging from path algorithms to flow
algorithms. The next sections provide practical examples and guidelines to solve common graph theory problems using
Networkx.
Path algorithms
It packages several algorithms to compute paths, the shortest paths and path lengths between nodes in a graph. The
algorithms work both on directed and undirected graphs. Basically, they all take as arguments the graph, the source and
target nodes, and optionally the edge attribute that represents the distance, cost or weight of each edge. If not provided,
all edges have a weight equal to one.
shortest_path
Shortest_path computes the shortest paths in the graph. By default, it uses the Dijkstra algorithm, but it is possible to use
Bellman-Ford’s algorithm using the argument method = ‘bellman-ford’. If only the source node is specified,
shortest_path returns a dictionary keyed by targets with the shortest path between the source node and every other node in
the network. Conversely, if only the target is specified, it returns a dictionary keyed by sources with the shortest path from
every node to the specified target node. If neither the source nor target are specified, it returns a dictionary of dictionaries
with all shortest paths from every source and every target node.
[ ]: # Create a directed graph structure:
G = [Link]()
G.add_edge(0,1, cost=1700)
G.add_edge(0,2, cost=3968)
G.add_edge(0,3, cost=7622)
G.add_edge(0,4, cost=10970)
G.add_edge(1,2, cost=1880)
G.add_edge(1,3, cost=1880)
G.add_edge(1,4, cost=4652)
G.add_edge(2,3, cost=2300)
G.add_edge(2,4, cost=4316)
G.add_edge(3,4, cost=2720)
minimum_spanning_tree
minimum_spanning_tree returns the minimum spanning tree of an undirected graph. Recall that the minimum spanning
tree is a sub-graph that connects all the nodes in the graph with the minimum sum of edge weights. If the graph is not
connected, the function returns a collection of the minimum spanning trees of each connected sub-graph. This is referred
to as a spanning forest.
[ ]: G = [Link]()
G.add_node("a")
G.add_node("d")
G.add_edge("a", "b", weight=3)
G.add_edge("a", "c", weight=6)
(continues on next page)
Flow algorithms
maximum_flow
maximum_flow finds a maximum flow of a commodity in a directed graph where each node has a ‘capacity’ attribute that
specifies the maximum capacity that the flow can support. It returns the value of the flow and the path that provides the
maximum flow in a dictionary keyed with the source and destination nodes. See the example below:
[ ]: G = [Link]()
G.add_edge("x", "a", capacity=3.0)
G.add_edge("x", "b", capacity=1.0)
G.add_edge("a", "c", capacity=3.0)
G.add_edge("b", "c", capacity=5.0)
G.add_edge("b", "d", capacity=4.0)
G.add_edge("d", "e", capacity=2.0)
G.add_edge("c", "y", capacity=2.0)
G.add_edge("e", "y", capacity=3.0)
min_cost_flow
G is a directed graph with edge capacity and in which nodes have demand, maximum_flow_value finds a maximum flow
from a source node to a destination node, using the node s to node s, using edge attribute ‘capacity’ as edge capacity and
node attribute ‘demand’ as the demand. negative demand means that the node wants to send flow, a positive demand
means that the node want to receive flow. A flow on the digraph G satisfies all demand if the net flow into each node is
equal to the demand of that node.
[ ]: G = [Link]()
G.add_node("a", demand=-5)
G.add_node("d", demand=5)
G.add_edge("a", "b", weight=3, capacity=4)
G.add_edge("a", "c", weight=6, capacity=10)
G.add_edge("b", "d", weight=1, capacity=9)
G.add_edge("c", "d", weight=2, capacity=5)
flowDict = nx.min_cost_flow(G)
260 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
Displaying networks
You can draw the graph with the function draw(G, pos). The function takes a graph as the first argument. The second
argument is a tuple with the relative (x, y) coordinates of nodes in the graph.
Networkx provides convenient functions to customise the representation of the network:
• The function draw_networkx_labels is used to control the presentation of the node labels (reference here
• The function draw_networkx_nodesto control the presentation of the nodes (reference here)
• The function draw_networkx_edge_labels to control the edge labels (reference here).
See a practical example below:
Networkx provides convenient functions and methods to create networks from large data structures. This is necessary to
build networks in practical applications. This section covers functions to create graphs from iterables and Pandas data
frames.
Specifically, The method add_edges_from adds edges from an array where each element is a tuple (edge tuple) with
the following elements:
• origin node object
• destination node object
• (optional) dictionary with edge properties
[ ]: my_graph = [Link]()
my_edges = [(1, 2, {"weight": 3, "capacity": 5}), # adds an edge from node 1, to node␣
˓→2, with weight 3 and capacity 5
my_graph.add_edges_from(my_edges)
It is also possible to add paths to a graph using an array that contains the list of nodes in the path. If the nodes do not
exist in the graph, they are automatically added. It is possible to define properties for the edges added to the path. let us
see it in action:
[ ]: my_graph = [Link]()
path_1 = [1, 2, 3, 4]
# Add a path 1 -> 2 -> 3 4 with weight 3
nx.add_path(my_graph, path_1, weight = 3)
nx.draw_planar(my_graph)
The function add_cycle adds a cycle connecting the nodes provided in an array. It is similar to add_path, except
that the first and the last node are connected:
[ ]: my_graph = [Link]()
path_1 = [1, 2, 3, 4]
# Add a path 1 -> 2 -> 3 4 with weight 3
nx.add_cycle(my_graph, path_1, weight = 3)
nx.draw_planar(my_graph)
from_pandas_edgelist
Networkx has a good integration with Pandas. The function from_pandas_edgelist creates a graph from a Pandas
dataframe that contains the information of the edges. You only need to specify which column specifies the origin node,
the destination node and which columns contain information about the edges we want to map as attributes. The arguments
are:
• edgelist: The dataframe containing the edge information
• source: The column that contains the source nodes
• Target: The column that contains the target nodes
• edge_attr: An array with the names of the columns that contain edge attributes
[ ]: import pandas as pd
edge_df = [Link]({ u : [1, 2, 2, 3, 3, 4], v : [2, 3, 4, 1, 4, 1], weight :␣
˓→[2, 1, 3, 4, 2, 1]})
nx.draw_planar(graph)
262 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
from_pandas_adjacency_matrix
It is also possible to create a graph from a Pandas dataframe that contains the adjacency matrix. An entry i,j in the
dataframe corresponds to the weight of an edge from node i to j. For directed graphs, it is necessary to use the cre-
ate_using argument equal to [Link]:
print([Link])
print([Link])
The functions to_pandas_adjacency and to_pandas_edgelist export the information of the graph to
dataframes, either as the adjacency matrix or as an edge list (make sure you run the cell above):
[ ]: df = nx.to_pandas_edgelist(graph)
df
osmnx is a really nice package that allows to create a map from Open Street Map data, which is a really nice resource in
logistics applications.
Installation
Run the following script to install onsmnx if it is not installed in your system:
Creating a map
• graph_from_bbox: Creates a graph within four points of a bounding box, specifying the north northern
latitude of the bounding box, the south southern latitude of bounding box, the east eastern longitude of the
bounding box and the west western longitude of the bounding box.
[ ]: import networkx as nx
import osmnx as ox
# get two markers from Google Maps around EDEM
# Latitude, Longitude
#North-west marker
# 39.468370277652426, -0.33528989341188187
# South east marker
# 39.45963084307057, -0.3184406656568226
G_nx = ox.graph_from_bbox(north=39.468370277652426,
south=39.45963084307057,
east=-0.3184406656568226,
west=-0.33528989341188187)
The function plot_graph_folium uses Folium to render the map in an interactive map:
[ ]: m1 = ox.plot_graph_folium(G_nx)
m1
get_nearest_node
When you work on a graph, you can possibly click on a point in the map that is not necessarily an edge in the graph, so to be
able to process it, you first need to find the node in the graph that is closest to the point. You can use the get_nearest_point
function for this purpose, it returns the node that is closest to the point you pass as an argument so that you can later use
the algorithms:
Networkx algorithms
You can now run any algorithm on your graph. The following example shows the spanning tree in green. Since spanning
tree returns a graph, we can use again the function plot_graph_folium to render the result. Since we want to show it
over the previous generated graph, we pass the Folium map object m1 created below as the value of the named parameter
graph_map, and we use the edge_color red to represent the edges of the spanning tree in a different color.
[ ]: spanning_tree = nx.minimum_spanning_tree(G_nx.to_undirected())
ox.plot_graph_folium(spanning_tree, graph_map=m1, edge_color= #ff0000 )
264 Chapter 3. Combinatorial Optimization, Mixed Integer Programming and Network Theory
Notebooks for Operations Research, Release I
plot route
You can plot a route in a map using the function plot_route(). Optionally, you can pass as argument a previously generated
map so that the route is printed as an overlay:
[ ]:
FOUR
NON-LINEAR PROGRAMMING
This chapter provides an introduction to Non-Linear Programming (NLP), the branch of optimisation that deals with
problem models where the functions that define the relationship between the unknowns (either objective function or con-
straints) are not linear. The fact that the functions are not linear makes NLP a lot harder to deal with from a mathematical
point of view. The chapter will focus on specific cases that have many applications in real life problems, particularly
quadratic functions and their relationship to machine learning.
4.1 Tutorials
Try me
Introduction
A non-linear programming (NLP) problem is similar to a linear programming problem in the sense that it is also composed
of an objective function and constraints, but a NLP includes at least a non-linear function. In general, this chapter will
deal with continuous decision variables and problems where either the objective function, or any of the constraints are not
linear. NLP problems are in many cases more difficult to solve than linear programming problems. The mathematical
foundations of NLP optimisation date back to the enlightenment era and the work of Joseph Louis Lagrange, a great
mathematician and astronomer. He developed a method to take into account non-linear constraints into optimisation
problems, which is called Lagrange multipliers, and that will be used in constrained NLP. In this introduction, we will
use some Python code snippets to show why NLP are more difficult to solve.
267
Notebooks for Operations Research, Release I
In linear programming, methods like the simplex need only to know the value of the unknowns and the value of the
objective function to determine if the solution is optimal, because the maximum is always at a vertex of the feasibility
region. Non-linear functions have critical points (we will provide a more formal definition of a critical point later on in
the book), which can be either local or global maxima or minima:
• Local maximum: The value of the function at the critical point is higher than the values of the function around
the critical point.
• Global maximum: The value of the function at the critical point is the highest value of the function.
• Local minimum: The value of the function at the critical point is lower than the values of the function around the
critical point.
• Global minimum: The value of the function at the critical point is the lowest value of the function.
Let us look at one example in Python.
x = [Link](-3, 3, 100)
y = ([Link](x**3) - 5*[Link](x**2) + 4*[Link](x) + 12)**2 - 4
[Link](x,y)
# sets limits
[Link]((-3,3))
[Link](r $x$ )
[Link]((0,459))
[Link](r $f(x)$ )
global_min = [Link](y)
global_min_x = x[[Link](y)]
global_max = [Link](y)
global_max_x = x[[Link](y)]
As it can be noted in the graph, the function has many critical points. Any critical point can be a local maximum or a
global maximum depending on the range of values that x can take. For instance, if x could only take values in the range
𝑥 ∈ [−3, 0], then the local maximum would become a global maximum. This makes it somewhat more difficult to find
the optimal solution in an optimisation problem.
With non-linear functions, the optimal (maximum or minimum) value might no longer be at one of the vertices. For
instance, let us take us an example the function in the following Python script:
The example shows a non-linear function on two decision variables, x and y. The black lines represent some constraints
limiting the feasibility region. The contour graph shows that the maximum value of the objective function is within the
interior of the feasibility region and not in one of the vertices.
The following situations are examples where the optimal value might not be at one vertex of the feasibility region:
• Multimodal function: As in the example above, the function might be multimodal and depend on several decision
variables, increasing its complexity.
• Interior optima: As in the example above, the optimal value might be found in an interior point of the feasibility
region.
• Discontinuous: The objective function might be discontinuous and again, the optimal value might not be surely
located in one vertex.
Given that the objective functions and the constraints can be of any family of functions, potentially, there is a huge
body of mathematical theory that can be applied to NLP, since non-linear functions have a wide range of characteristics.
Definitively, this makes NLP somewhat more difficult. The theoretical framework is more sophisticated, and modeling is
also more difficult, since the researcher needs to define the types of function to use in the model.
Solver selection
Due to the complex mathematical theory behind, selecting the right solver to solve a specific problem can be complex.
In fact, different algorithms and solvers can provide different results. Normally, algorithms deal with local optimisation,
rather than global optimisation, and for that reason, the selection of the initial point used to start the algorithm might have
an impact in the solution. Hence, different algorithms might provide different solutions, but when a specific algorithm is
selected, its configuration (particularly the initial point) might yield different results.
Types of problems
In this chapter, NLP is divided into two different classes of problems with increasing complexity:
• Unconstrained NLP Problems This class of NLP problems have no constraints, we look for a maximum or
minimum of the objective function within some bounded decision variables, but not subject to any constraint.
• Constrained NLP Problems This class of problems have constraints, i.e. there are restrictions to the objective
function solution determined by a set of functions of the decision variables.
Additionally, to better present the mathematical framework behind NLP, we will consider One-Dimensional un-
constrained problems, where there is only one decision variable, and Multi-Dimensional or multi-modal, where there
are several decision variables
Let us first consider just one decision variable. The objective is to search a maximum or minimum of a non-linear function.
Without loss of generalisation, let us consider that the objective is to minimize the objective function:
min 𝑓 (𝑥) 𝑥 ∈ R
Any (local or global) minimum of 𝑓 (𝑥), 𝑥* will have the following properties:
1. First derivative test: The first derivative of a function at a point 𝑥* represents the slope of a line tangent to 𝑓 (𝑥)
at 𝑥* . In a minimum, the first derivative is equal to zero, 𝑑𝑓𝑑𝑥
(𝑥)
= 0, meaning that the tangent is horizontal.
2
2. Second derivative test: The second derivative is positive 𝑑 𝑑𝑥
𝑓 (𝑥)
2 , meaning that the slope of the tangent is increasing
and therefore, it must be less than zero for 𝑥 < 𝑥 , meaning that the function decreases before 𝑥* , and greater than
*
zero for 𝑥 > 𝑥* , meaning that the function increases after 𝑥* . Therefore 𝑓 (𝑥) takes its minimum value at 𝑥* , at
least in its proximity.
By definition, 𝑥* is a critical point. For a maximum, the second derivative is negative and using the same logic, 𝑓 (𝑥)
decreases in the proximity of 𝑥* .
Bi-section algorithm
Since the sign of the first derivative changes at a critical point, it is possible to search a critical point if we find two initial
points such that the sign of the first derivative is different. The simplest algorithm that uses this property is known as the
bi-section method, and it can be formulated as this:
Initialisation
1. Choose an acceptable error 𝜖
𝑑𝑓 (𝑥𝐿 )
2. Find an initial left point 𝑥𝐿 such that 𝑑𝑥 <0
𝑑𝑓 (𝑥𝑅 )
3. Find an initial right point 𝑥𝑅 such that 𝑑𝑥 >0
𝑑𝑓 (𝑥′ ) 𝑑𝑓 (𝑥′ )
Iteration 1. Bisect the range [𝑥𝐿 , 𝑥𝑅 ] 𝑥′ = 2 2. If 𝑑𝑥 < 0 then make = 𝑥′ , else if 𝑑𝑥 < 0 then make = 𝑥′
3. If ≤ 2𝜖 then the solution is 2 , else repeat
That is, we start with two initial values for which the first derivative has different sign. If the function is continuously
differentiable, then there must be a value somewhere in between these values where the first derivative is zero. Then,
we make a bi-section and continue looking in the part of the range for which there is a change in the sign of the first
derivative. The process stops either when we find exactly a critical point or when the distance between both points is less
than the acceptable error.
For multidimensional problems the logic applied is the same, except that in this case it is necessary to consider partial
derivatives in the different decision variables or dimensions of the problem. Thus, given an n-dimensional function:
𝑓 (𝑥) 𝑥 = [𝑥1 , 𝑥2 , ..., 𝑥𝑛 ]
The gradient vector is defined as a vector containing the first partial derivatives:
𝜕𝑓 (𝑥)
⎡ ⎤
⎢ 𝜕𝑥1 ⎥
⎢ 𝜕𝑓 (𝑥) ⎥
⎢ ⎥
𝜕𝑥2 ⎥
⎢ ⎥
∇𝑓 (𝑥) = ⎢
⎢ .. ⎥
.
⎢ ⎥
⎢ ⎥
⎣ 𝜕𝑓 (𝑥) ⎦
𝜕𝑥𝑛
The gradient represents the slopes of the tangent planes to 𝑓 (𝑥) in every dimension. For a minimum, the gradient must
be zero, as an extension of the first derivative test of one dimensional problems.
1. Gradient test The gradient must be zero at a critical point 𝑥* ∇𝑓 (𝑥* ) = [0, ..., 0]𝑇 .
Now, to know if the function decreases in every direction around 𝑥* , we need ot define the Hessian:
⎡ 𝑑2 𝑓 (𝑥) 𝑑2 𝑓 (𝑥) 𝑑2 𝑓 (𝑥)
⎤
𝑑𝑥21 𝑑𝑥1 𝑑𝑥2 ... 𝑑𝑥 1 𝑑𝑥𝑛
⎢ 𝑑2 𝑓 (𝑥) 𝑑2 𝑓 (𝑥) 𝑑2 𝑓 (𝑥) ⎥
⎢ 𝑑
⎢ 𝑑𝑥2 𝑥1 𝑑𝑥22
... 𝑑𝑥2𝑑𝑥 ⎥
Hess𝑓 (𝑥) = ⎢ . 𝑛⎥
⎢ .
⎥
⎣ .
⎥
⎦
2 2 2
𝑑 𝑓 (𝑥) 𝑑 𝑓 (𝑥) 𝑑 𝑓 (𝑥)
𝑑𝑥𝑑 𝑑𝑥𝑛 𝑑𝑥2 ... 𝑑𝑥𝑛 2
𝑛 𝑥1
⎡ ⎤
ℎ11 ℎ12 ... ℎ1𝑛
⎢ ℎ21 ℎ22 ... ℎ2𝑛 ⎥
Hess𝑓 (𝑥) = ⎢ .
⎢ ⎥
⎣ ..
⎥
⎦
ℎ𝑛1 ℎ𝑛2 ... ℎ𝑛𝑛
That is, the Hessian is a nxn matrix that contains the second order derivatives.
To determine how the function increases or decreases in any direction around a given point, we can check Sylvester’s
criterion. This criterion evaluates the leading principal minors of the Hessian matrix. A leading principal minor 𝑘 of
a Hessian matrix is the determinant of the square sub-matrix that includes columns and rows from 1 to 𝑘, that is, if note,
𝐻𝑘 as the leading minor of the Hessian matrix A, we can compute the leading principal minors as:
⃒ ⃒
𝐻1 = ⃒ℎ11 ⃒
⃒ ⃒
⃒ℎ ℎ12 ⃒⃒
𝐻2 = ⃒⃒ 11
ℎ21 ℎ22 ⃒
...
Note that an n-dimensional function has n Hessian leading minors. Now, the Hessian determinants can help us decide
whether a function is a local or global minimum, according to the following definitions:
• Definitive positive Hessian: all leading principal minors are greater than zero > 0∀𝑖 ∈ [1, .., ].
• Semi-definitive positive Hessian: all leading principal minors are greater or equal than zero ≥ 0∀𝑖 ∈ [1, .., ].
• Definitive negative Hessian: all leading principal minors are lower than zero < 0∀𝑖 ∈ [1, .., ].
• Semi-definitive negative Hessian: all leading principal minors are less or equal than zero ≤ 0∀𝑖 ∈ [1, .., ].
Now, the second derivative test becomes:
2. Second partial derivative test:
Introduction
Gradient Descent Methods constitute a large family of heuristic methods based on the gradient definitions presented in
the set-up of unconstrained NLP. Gradient descent methods are useful to find critical points and test whether they are
global minimum (for minimisation problems) or global maximum (for maximisation problems).
Basically, they consist of two types functions:
• search functions: to find points where the gradient is zero or close to zero, i.e. functions to find critical points.
• test functions: to verify whether the critical point is a global or local maximum or minimum.
The different implementations have different performance trade-offs depending on the characteristics of the optimisation
problem. In this notebook, we are going to cover two different methods, the simple gradient descent method and the
stochastic gradient descent, with applications in machine learning.
In the Simple gradient descent method, the algorithm starts at an initial point, calculates the gradient, and if It’s different
from zero, it looks for the next point to test in the direction opposite to the gradient. Recall that, at any given point 𝑥*
the gradient of the objective function ∇𝑓 (𝑥*) represents a vector tangent to 𝑓 (𝑥*). This tangent vector represents the
direction of the maximum change of x towards infinity in the n-dimensional space. Therefore, the algorithm continues
the search in the opposite direction to this vector, assuming that this will provide the maximum change of the function
towards its minimum value. With this, the Simple Gradient descent method can be defined as:
Start
• Choose an acceptable error 𝜖
• Choose a starting point 𝑥′
Iterate
• Calculate ∇𝑓 (𝑥′ )
• If |∇𝑓 (𝑥′ )| ≤ 𝜖 then exit with x′ as the solution, else
• Set 𝑥′′ = ′ − 𝑡·∇𝑓 (𝑥′ ) 𝑡 ≥ 0, 𝑡 ∈ R and iterate again.
Note that since t is a positive value and |∇𝑓 (𝑥′ )| is a vector, we are changing the value of x in the direction of the
vector. The change is proportional to t, which can be a fixed parameter or a calculated parameter depending on the
implementation. One implementation alternative is to use a one-dimensional search (e.g. using a bisection algorithm) to
find * such that 𝑓 (𝑥′′ ) is a local minimum. Note that since both 𝑥′ and |∇𝑓 (𝑥′ )| are vectors, the only unknown is 𝑡, and
this bisection is a reduction of the multidimensional minimisation problem to a one-dimensional minimisation problem.
The stochastic gradient descent method can be applied in problems where the gradient of the objective function can be
estimated from a subset of the parameters needed to compute the closed form of the gradient. The stochastic gradient
descent is one of the fundamental optimization methods used in machine learning and given its importance, we will
illustrate some outstanding applications of this method in the field of machine learning the of this method using in the
quadratic optimization examples. Let us consider the following objective function:
∑︀𝑛
min 𝑅𝑛 (𝜃) = 11 𝑡=1 𝐿𝑖 (𝜃)
The stochastic gradient descent method is defined as:
Start
• Choose an acceptable error 𝜖
• Choose a starting point 𝜃 (e.g 𝜃 = 0)
• Choose a learning factor for each iteration k 𝜁𝑘
Iterate
• select a random value 𝑡*
• Calculate the gradient of ∇𝐿𝑡* (𝜃𝑘 )
• Update 𝑡ℎ𝑒𝑡𝑎𝑘 in the direction contrary to the gradient at 𝑡*: 𝜃𝑘+1 = 𝜃𝑘 − 𝜁𝑘 ·∇𝐿𝑡* (𝜃𝑘 )
• Repeat until the difference between two consecutive estimations is sufficiently small, or until the maximum number
of iterations is reached.
Try me
Introduction
Gradient-Descent (GD) methods are in the backbone of many machine learning methods. in this tutorial, we will use a
practical example to illustrate how the simplest algorithm in the family (Simple Gradient Descent) works.
Import libraries
Before we dive into GD methods, let’s import the libraries that we will use in this tutorial:
[ ]: import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
Problem definition
Gradient-Descent methods allow us to find the maximum or minimum of a function that depends on an array of variables:
𝑥 = [𝑥1 , 𝑥2 , ..., 𝑥𝑛 ]
min 𝑧 = 𝑓 (𝑥)
And similarly, for maximization, we want to find the maximum value of the function in x:
max 𝑧 = 𝑓 (𝑥)
Tutorial Example
In this tutorial, as an example, let us find the maximum of the following function:
Note that it is a quadratic expression, probably the simplest form of non-linear function. We have chosen this function
because it is relatively easy to analyze, so we will use it to get insights on Gradient descent methods.
The following Python function returns this value, given that you pass 𝑥 as a list or array:
[ ]: def my_func(x):
# This is the function to optimize.
# x is an array containing the dependent variables to optimize (x = [x_1, x_2, ...,␣
˓→x_n])
Now, let’s plot it to get a general idea of how the function looks like. The following script represents a contour plot of the
function:
[ ]: x_1 = [Link](-20, 20, 0.01) # The horizontal axis of the contour plot, it will␣
˓→represent x_1
x_2 = [Link](-30, 30, 0.01) # The vertical axis of the contour plot, it will␣
˓→represent x_1
The yellow area shows the values that are greater. From calculus, we know that the maximum is found at 𝑥* such that:
∇𝑓 (𝑥* ) = [0, ..., 0]𝑇
In this example the gradient is a vector of length 2:
∇𝑓 (𝑥) = [8 − 2 * 𝑥1 , 16 − 2 * 𝑥2 ]𝑇
We can easily find the solution analytically with a linear system of equations, one equation for each component of the
gradient:
8 − 2 * 𝑥1 = 0
16 − 2 * 𝑥2 = 0
So, the maximum is found at:
𝑥1 = 4
𝑥2 = 8
However, in many applications, particularly in machine learning, it is computationally expensive (we would need a lot
of computational resources) to find the solution of ∇𝑓 (𝑥* ) = [0, ..., 0]𝑇 analytically. In those cases, gradient-descent
methods are a very efficient solution to find an approximate solution.
The strategy of GD methods is based on the following, it is expensive to find the value of x where the gradient is zero, but
it is easy (in computational terms) to compute the value of the gradient for any value of x (e.g. 𝑥′ ). Now, if the value of the
gradient at 𝑥′ is sufficiently small (for instance, smaller than an arbitrary error 𝜖 in absolute value, |∇𝑓 (𝑥′ )| ≤ [𝜖, ..., 𝜖]𝑇 ,
then we can consider that it is a good estimate of the maximum!
For instance, the steepest method starts at an initial 𝑥′ , and iteratively, updates this value as:
𝑥′′ = 𝑥′ + 𝑡 * ∇𝑓 (𝑥′ )
where t is a parameter known as the learning rate. The gradient is a vector that tells us the direction of maximum
change of the function, so the algorithm takes a step in this direction at every iteration (a step of size t). When the
gradient is “reasonably close to zero”, the algorithm has found an approximation, and if not, it tries updating the value
again, making x’ = x’’ and repeating the calculation above. Intuitively, think that you are in a mountain, and you want
to get to the top, but the mountain is really high, and there are trees around you, so you do not really know how to get
there. However, at every step, you can move in the direction where the slope is steepest. This is what the simple gradient
descent algorithm does. Note that since it is a maximization problem (and we want to get to the top of the mountain), we
update x with a positive increment in the direction of the gradient. For minimization, we would update with a negative
increment (𝑥′′ = 𝑥′ − 𝑡 * ∇𝑓 (𝑥′ )).
Ok, to make things simple and easy to update, let us define another Python function to calculate the gradient. This function
will take an array as (𝑥 = [𝑥1 , 𝑥2 , ..., 𝑥3 ] and return an array with the gradient of the function. By default, it will compute
∇(𝑥) = [ 𝛿𝑓𝛿𝑥(𝑥)
1
, 𝛿𝑓𝛿𝑥(𝑥)
2
] = [−2 * 𝑥1 + 8, −2 * 𝑥 + 16], but you can update it if you would like to test some other function.
[ ]: def gradient_func(x):
Ok, now, let us program another function in Python to run the Simple Gradient Descent algorithm. This function takes
the following parameters:
• start: The starting value of x’. This is where our hike to the top (or bottom) of the mountain starts.
• learn_rate: The learning rate t, or the size of the steps that we are going to take.
• max_iter: Maximum number of iterations, to control that we do not enter and endless loop (or an endless hike..)
• tol: This is the tolerance, or the maximum error in the approximation of the gradient 𝜖. In other words, how close
we want to get to the actual top of the mountain. This parameter is optional and by default takes the value 0.01
• sense: This is the sense or type of optimization problem. By default, the sense is “max” for maximization problem
(to hike uphill to the top of the mountain. You can use sense="min" for a minimization problem.
• gradient: This is a function that computes the gradient, by default is the function gradient_func we have
defined before.
The algorithm will return: - iterations: An array that contains the value of x and the error at every iteration.
tolerance = tol*[Link]([Link])
if [Link](error <= tol): #If we are below tolerance, exit the for loop
break
step = learn_rate*g
if sense == "max":
(continues on next page)
Ok, Let’s test the algorithm starting at 𝑥 = [𝑥1 , 𝑥2 ] = 0, and use 𝑡 = 0.147 and 𝑒𝑝𝑠𝑖𝑙𝑜𝑛 = 0.1. We will then show the
result iterations in a Pandas dataframe so that we can visualize the results in a table.
X error
0 [0.0, 0.0] [8.0, 16.0]
1 [2.0, 4.0] [4.0, 8.0]
2 [3.0, 6.0] [2.0, 4.0]
3 [3.5, 7.0] [1.0, 2.0]
4 [3.75, 7.5] [0.5, 1.0]
5 [3.875, 7.75] [0.25, 0.5]
6 [3.9375, 7.875] [0.125, 0.25]
7 [3.96875, 7.9375] [0.0625, 0.125]
8 [3.984375, 7.96875] [0.03125, 0.0625]
Ok, let us visualize the result in a contour graph. We are going to use red arrows to represent how the different iterations
converge to the maximum. Each red arrow starts at x’ and stops at x’’ (x’ ⇒ x’’).
[Link]()
4.1.5 Questions
1. Repeat the experimentation with lower tolerances values and note how the number of iterations increases. For
instance, try to modify the script to achieve a tolerance of 0.01. How many iterations did the algorithm need, and
what is the difference in the estimated x with respect to the previous experiment. What if you decrease it to 0.001?
2. What happens with the distances between iterations as we get closer to the maximum? Can you reason why this
happens?
3. Let us experiment now with the learning rate t. Let us set the tolerance back to 0.1 and test the script above with
a learning rate of 0.25. Is convergence faster (in less iterations)? Try it now with a value of 1. Did the algorithm
find an optimal solution? What about 0.5? What can we say about the sensitivity of the algorithm to changes in the
learning rate?
4. We know where the maximum solution is. Can we use the second partial derivative test generalization to know if
it is a local maximum or minimum?
5. Can you repeat the experiment for another function, for instance, minimize 𝑧 = 𝑓 (𝑥) = 2*𝑥21 +𝑥22 −10*(𝑥1 +𝑥2 )?
Introduction
Recall that in constrained NLP, the objective is to find the optimal value (maximum or minimum) of an objective function,
subject to a set of constraints, where at least one function is not linear. In this section, we will present the canonical form
for non-linear problems, and use this form to introduce the Kuhn-Tucker conditions, which are a set of conditions that
the optimal value must hold.
Canonical Form
The Kuhn-Tucker (KT) conditions provide a set of differential equations that can be used to find the optimal value of a
constrained NLP, based on the Lagrangian defined below:
Lagrangian
Given an optimisation problem with m constraints in the canonical form, let us define the Lagrangian function as:
∑︀𝑚
L(𝑥, 𝜆) = 𝑓 (𝑥) + 𝑖=1 𝜆𝑖 * 𝑔𝑖 (𝑥)
That is, to take into account the constraints in the objective function, we add the corresponding functions on the right
hand side multiplied by a set of coefficients noted as 𝜆𝑖 which are known as Lagrangian multipliers.
Gradient condition
Now, for any candidate solution to be an optimal solution, we know that, as for unconstrained NLP, it must be a critical
point and thus satisfy:
∇𝑥 L(𝑥, 𝜆) = 0
That is, since each component of the gradient is the first order derivative of the corresponding decision variable, the
Lagrangian must satisfy:
𝛿L
𝛿𝑥𝑗 =0 ∀𝑗 = [1, ..., 𝑛]
Feasibility condition
Additionally, we must ensure that the solution is feasible, i.e. that meets all the constraints. Therefore, the feasibility
condition yields:
𝑔𝑖 (𝑥) ≤ 0 ∀𝑖 = [1, ..., 𝑚]
Note that, given the expression of the Lagrangian, this is equivalent to:
𝛿L
𝛿𝜆𝑖 𝑔𝑖 (𝑥) ≤ 0 ∀𝑖 = [1, ..., 𝑚]
Orthogonality condition
Now, note that for the Lagrangian and the objective function to represent exactly the point of the function, at the optimal
value, the following conditions must be met:
𝜆𝑖 * 𝑔𝑖 (𝑥) = 0 ∀𝑖 = [1, ..., 𝑚]
That is, either the Lagrangian multiplier is equal to zero or the corresponding right hand side is equal to zero.
Once that the problem is in the canonical form, we also need to check that the Lagrangian multipliers have the correct
size, that is, that they are non-negative or non-positive depending on the type of optimisation function and the type of
constraint. The following table summarizes the conditions for minimization problems:
Introduction
Machine learning is a field of mathematics focused on developing software that solve problems by learning from expe-
rience. The main idea behind machine learning is to develop algorithms that mimic the reasoning capability of learning
through examples. As explained, in the introduction to operations research, artificial intelligence gathers a set of math-
ematical tools that allow to solve problems that intelligent beings are able to solve intuitively, but that are a priori complex
to solve computationally. One of the most relevant fields of artificial intelligence is machine learning, which focuses on
how to solve problems that cannot be precisely specified, or whose solution method cannot be described by symbolic
reasoning rules, by using available data.
As shown in this unit, machine learning provides tools to reduce problems for which there is no formal mathematical model
to an optimization problem through data. Note that this is an important change of paradigm to previous problem-solving
approaches, as the starting point is available data, not a mathematical model of the problem.
Let us look illustrate how we have been approaching problem-solving until now with the following figure:
Based on the knowledge of the problem at hand and based on a set of assumptions, so far we have developed a mathematical
model of a decision problem as an optimization problem subject to a set of constraints, and use data to set up the coefficients
of the model based on the environment framing the decision-making problem. The solution to the problem provided the
values of the objective variable and the decision variables.
However, the approach in machine learning is radically different:
Now, what we do is use a flexible mathematical model, or swiss-knife type of mathematical model, which is in a nutshell
any mathematical model which has enough degrees of freedom to model a wide set of problems. For now, we can just
assume that we will use models with coefficients that are not defined a priori, and that there are enough of such coefficients
to allow it to model many problems. Now, Training consists in finding the parameters of the model that provide the best
mapping between input data and output data, given a set of examples, or training data. With these parameters, the
machine learning model agrees with the experienced results described in the training data. Out of all possible values for
the parameters, the optimal parameters minimize an error function between the solutions obtained with the model and
the solutions available in the training data.
This way, learning is reduced to a minimization problem. There are many machine learning approaches, but in most
cases, learning is reduced to a minimization problem and gradient descent methods are behind most machine learning
algorithms.
This section describes the core learning tasks, which is how we refer to the types of problems that are normally solved
with machine learning. Before we go into the details of each individual learning task, bear in mind that the common
denominator is that these are tasks that humans and other type of intelligence beings perform naturally and intuitively,
but that do not have a closed mathematical form.
Prediction
Learn the behaviour of a variable with time, to make predictions about future trends or events. The variable can be
quantitative (e.g. predict the value of a market stock based on a historic dataset) or categorical (e.g. predict the time to
failure of a machine)
Learn to classify input data into known categories (classification) or unknown categories (clustering) based on the features
available in the training data. For instance, classify images of cells into tumorous or healthy (classification), or learn the
different types of customers from collected data.
Generation
Learn to generate data with the same characteristics of a set of examples. For instance, learn to translate text into a
language, or generate videos from images.
Optimization
Learn to solve complex optimization problems, either combinatorial optimization problems (e.g. play chess or Go) or
convex optimization (drone navigation control) which are very difficult to model and solve with other techniques.
Introduction
Experience will soon tell you that amid the wide range of solvers that support NLP, most provide support specifically
for quadratic functions. This is because there is a wide range of problems that deal specifically with quadratic functions,
rather than with generic non-linear functions. Recall that a quadratic function is a polynomial function of the decision
variables with terms of at most second order degree. For instance, an outstanding example of quadratic function is the
quadratic error function:
𝑧2
𝐿𝑜𝑠𝑠(𝑧) = 2
Any optimization problem that aims to minimize a given error can use this empirical error function as the objective
function. The next subsections present some examples of quadratic optimization problems that use exclusively this type
of functions.
The objective of a linear regression problem is to explain a response variable, or dependent variable, based on the values
of a set of explanatory variables, or independent variables, assuming that the relationship between the response variable
and the explanatory variables is linear.
That is, given:
• 𝑥(𝑡) : feature vector t. Sample vector t of explanatory variables (e.g. different characteristics of people like gender,
age, region, device, …). 𝑥(𝑡) is a d-dimensional vector (i.e. 𝑥(𝑡) ∈ R)
• 𝑦 (𝑡) : Label t. Response variable t that we want to explain (e.g. for instance the probability that a person is a
potential customer or not). Let us assume that every 𝑦 (𝑡) is a real value (i.e. 𝑦 (𝑡) ∈ R)
• 𝑆𝑛 : Training set containing all labeled feature vectors, i.e. 𝑆𝑛 = {𝑥(𝑡) , 𝑦 (𝑡) |𝑡 = 1, ..., 𝑛}
The objective is to learn the linear mapping between the feature vector space x and the response variable y:
∑︀𝑑
𝑦^ = 𝑓 (𝑥, 𝜃, 𝜃0 ) = 𝑖=1 𝑥 * 𝜃 + 𝜃0 = 𝑥·𝜃 + 𝜃0
So that the value of y can be estimated for any point in the vector space x based on the training data set. The parameters
to learn are:
• 𝜃: Linear regression function coefficients
• 𝜃0 : Linear regression independent term (Let us assume it is zero for now, without loss of generality)
In general, the objective is to minimise the empirical risk, noted as 𝑅𝑛 , which is the average of the estimation error at
every training point t. Let as for now note Loss the loss function that represents the error at every training point. Then,
the objective function is:
∑︀𝑛
min 𝑅𝑛 (𝜃) = 𝑛1 𝑡=1 Loss(𝑦 (𝑡) − 𝑥(𝑡) ·𝜃)
Now, if we consider the quadratic error function, the empirical risk becomes:
(𝑡) (𝑡) 2
min 𝑅𝑛 (𝜃) = 𝑛1 𝑡=1 (𝑦 −𝑥2 ·𝜃)
∑︀𝑛
This minimisation problem is a quadratic optimization problem where the decision variables are the components of 𝜃.
Thus, we can compute the closed form of the gradient as:
(𝑡) (𝑡) 2
∇𝜃 𝑅𝑛 (𝜃) = 𝑛1 𝑡=1 ∇𝜃 (𝑦 −𝑥2 ·𝜃)
∑︀𝑛 ∑︀𝑛 [︀ ∑︀𝑛
= 𝑛1 𝑡=1 (𝑦 (𝑡) − 𝑥(𝑡) ·𝜃) * (−𝑥(𝑡) ) − 𝑛1
]︀
= 𝑡=1 𝑦 (𝑡) * 𝑥(𝑡) −
∑︀𝑛
𝑡=1 (𝑥 ·𝜃) * −𝑥
1 (𝑡) (𝑡)
𝑛
Now, note that the first term is the sum-product of scalars (𝑦 (𝑡) ) and vectors of size d (𝑥(𝑡) ) and therefore, it is a vector.
Let us note this first term as b:
∑︀𝑛
𝑏 = 𝑛1 𝑡=1 𝑦 (𝑡) * 𝑥(𝑡)
As for the second term, note that is the sum of the scalar product of two vectors of size d (which is a scalar) times another
vector of size d. We can apply the following transformation:
∑︀𝑛 ∑︀𝑛
− 𝑛1 𝑡=1 (𝑥(𝑡) ·𝜃) * −𝑥(𝑡) = 𝑛1 𝑡=1 𝑥(𝑡) * (𝑥(𝑡) )𝑇 * 𝜃 = 𝐴 * 𝜃
That is, first we use the vector product properties to place together the two 𝑥(𝑡) and then we move 𝜃 outside the summation
since it does not depend on t.
With this transformation, the closed form of the optimisation problem now becomes:
∇𝜃 𝑅𝑛 (𝜃) = −𝑏 + 𝐴𝜃 = 0 → 𝐴𝜃 = 𝑏
Try me
Problem definition
In this notebook we are to provide a closed form to reduce a machine learning linear classification problem to a constrained
quadratic optimization problem.
In this example, let us imagine that we want to predict the status of an engine by reading sensor data. We do not know
what is the mathematical expression that models the status of the machine as a function of the sensor data reading, but
we have collected data in different conditions, so we have a dataset with the data readings that have been generated by
sensors measuring the engine in different states: normal operation, and failure state.
In linear classification problems, we find the following definitions:
• 𝑥(𝑡) : feature vector of length t of independent variables (e.g. in our example this is going to be the different sensor
data readings like temperature, rotation speed, torque) x is a vector of length d i.e. 𝑥(𝑡) ∈ R𝑑 , and each element
𝑥1 , 𝑥2 , ... is going to represent the readings of the different sensors.
• 𝑦 (𝑡) : Label t representation the variable that we want to explain from the feature vector (e.g. in our case, whether
the engine is in a failure state or not)
The objective is to learn the parameters of a maximum margin linear separator from a training dataset. A maximum
margin linear separator is a hyperplane in the vector space X. Think of a hyperplane as a plane that divides the vector space
into two regions. For instance, a line, which is a 1 dimensional plane, divides a 2-dimensional space into two regions, the
area above the line and the area below the line. Consider that a hyperplane in the vector space of size 𝑑 can be represented
by a vector of size 𝑑. Let us note as 𝜃^ ∈ R𝑑 the vector that represents our linear separator.
To clearly visualize the results, we are going to work with a linear separator of size 𝑑 = 2, so that we can visualize the
results in a coordinate system. Therefore, we are only going to have data from two sensors, and our data points are noted
as:
𝑥 = [𝑥1 , 𝑥2 ]
𝑥1 : temperature sensor data readings
𝑥2 : Encoder measuring the engine speed in rpms
Dataset generation
Now, since we do not really have a dataset, we are going to generate a synthetic one. The following script generates
random points and represents them in the bi-dimensional containing all data points.
[ ]: import numpy as np
from matplotlib import pyplot as plt
Problem representation
Now, let us plot our dataset, together with a hyper-plane which is not necessarily a separator, to illustrate how a line
(1-dimensional hyper-plane) divides the 2-dimensional space into two regions:
# Initial separator
thetahat_1 =-57
thetahat_0 = 4452
#
r = thetahat_1*t + thetahat_0
[Link](t,r)
[Link]( $x_1$ (temperature in celsius degrees) )
[Link]( $x_2$ (engine speed in rpms) )
The line represents a linear separator with parameters 𝜃^ = [57, 1], 𝜃^0 = 4452, that is, all points in the line satisfy the
following equation:
^ + 𝜃^0 = 0
𝜃·𝑥
conform a line (1 dimensional hyperplane) that classifies all points of the 2 dimensional space into two categories. The
objective is to configure the parameters of this line so that all data points corresponding to the failure state fall into one
category, and that all data points corresponding to the normal operation state fall into the other category. This way, we
^ + 𝜃^0 to explain the status of the engine from a reading x:
can use the expression 𝜃·𝑥
^ + 𝜃^0 ≥ 0 → the engine is in failure state
𝜃·𝑥
^ + 𝜃^0 ≤ 0 → the engine is in normal state
𝜃·𝑥
We can use the sign operator to provide a numeric value to the labels that represent both status:
ℎ(𝑥) = sign(𝜃^ · 𝑥 + 𝜃^0 )
If we read new sensor data and multiply it by the coefficients of our linear separator, we can predict the status of the
machine as a failure if the sign is positive (the result is greater than zero) and we can predict the status of the machine as
normal state if the result is negative. This type of classifiers are also known as Support Vector Machines.
Now, the objective is to learn the parameters of our separator from the dataset, a set of historic readings from which we
know the status of the machine. Let a sample t of our data set be noted as:
(𝑡) (𝑡)
• 𝑥(𝑡) = [𝑥1 , 𝑥2 ] temperature sensor and rpm readings at sample t
• 𝑦 (𝑡) status at sample t {-1 if machine is in normal state, +1 if machine is in failure state}
We are going to have many data readings, some of them in normal state, and some in failure state, and we are going to
use these data to find the parameters of a separator that divides the space into two regions based on the information that
we have in the database we have collected.
Let us note our training data set as:
Now, given that we are going to use the sign of the result to determine the status of the machine, every separator must
ensure that:
^ (𝑡) + 𝜃^0 ≥ 0 ∀𝑦 (𝑡) = 1
𝜃·𝑥
^ (𝑡) + 𝜃^0 ≤ 0 ∀𝑦 (𝑡) = −1
𝜃·𝑥
There might be many lines that satisfy these constraints, or there might be actually none, that is, the space might not be
separable by a line. If the space can be separated by a line, the objective is to find a hard margin separator. Note that it is
beneficial to maximise the margin of our separator, that is, the distance between the line and the closest points above and
below it. Given that there is uncertainty on the information we have collected (for instance, we might not have gathered
data in every possible situation), it is better to find a margin that maximises the distance between the distance between
the data clusters in the two regions. In fact, this is what a human will solve the problem. This is known as the maximum
margin SVM, i.e., to find the linear hyperplane with the maximum margin, such that all points are classified correctly.
Furthermore, the parameters 𝜃^ and 𝜃^0 of the maximum margin separator satisfy the following constraint:
^ (𝑡) + 𝜃^0 ) ≥ 1 ∀𝑡 ∈ [1, ..., 𝑛]
𝑦 (𝑡) * (𝜃·𝑥
For convenience, we have set up the minimum distance to the separator to 1. This yields that the margin of our hyperplane
is given by ⃦⃦2^⃦⃦ . For instance, in our example, imagine that point 𝑥𝐴 is the closest point above the line (𝑦 𝐴 = 1) and
⃦𝜃 ⃦
point 𝑥𝐵 is the closest point below the line(𝑦 𝐵 = 1). Let us now define a line that is parallel to the separator and passes
through 𝑥𝐴 :
^ 𝐴 + 𝜃^0 = 1
𝜃·𝑥
𝜃^0 ·𝑥𝐴 ^ 𝐴 ^
0 + 𝜃1 ·𝑥1 + 𝜃0 − 1 = 0
and another one that is also parallel to the separator and passes through 𝑥𝐵 = −1:
^ 𝐵 − 𝜃^0 = 1
−𝜃·𝑥
𝜃^1 ·𝑥𝐵 ^ 𝐵 ^
1 + 𝜃1 ·𝑥2 + 𝜃0 + 1 = 0
The distance between both parallel lines is noted as 𝜔 and is given by:
|(𝜃^0 +1)−(𝜃^0 −1)| ⃦2⃦
𝜔= √︁ = ⃦ ^⃦
𝜃^2 +𝜃^2
1 2
⃦𝜃 ⃦
⃦ ⃦
Therefore, our objective function is to maximise this expression, or equivalently, to minimise ⃦𝜃^⃦ /2, which is a function
⃦ ⃦
subject to:
^ (𝑡) + 𝜃^0 ) ≥ 1 ∀𝑡 ∈ [1, ..., 𝑛]
𝑦 (𝑡) * (𝜃·𝑥
Or equivalently
√︁
𝜃^12 +𝜃^22
min 2
subject to:
^ (𝑡) + 𝜃^0 ≥ 1 ∀𝑦 (𝑡) = 1
𝜃·𝑥
^ (𝑡) + 𝜃^0 ≤ −1
𝜃·𝑥 ∀𝑦 (𝑡) = −1
SVMs in Python
Now, we are going to use two different approaches in Python to find the maximum margin separator for our dataset, using
the package for data science Scipy.
In the first approach we are going to use the package optimize for optimization. More specifically, we are going to use
the LinearConstraint, the Bounds modules, and the minimize function. The script below imports the dependencies and
packs the features into a matrix.
[ ]: from [Link] import LinearConstraint, Bounds, minimize
Minimize
Constraints
Now, for the constraints, we can either introduce linear constraints or non-linear constraints. The linear constraints are
instances of [Link]. This function has the following parameters:
• A: Matrix defining the coefficients in the left-hand-sides of the constraints
• ub: A vector defining the upper bound of the constraints or a scalar defining the upper bound for all the constraints
• lb: A vector defining the lower bound of the constraints or a scalar defining the lower bound for all the constraints
Note that, playing with the values provided to ub and lb it is possible to defines constraints of type less or equal, greater
or equal, or equal. With this function, the following code snippet defines the set of constraints corresponding to the failure
state data set samples
[ ]: # The right hand sides are x_1^(t), x_2^(t), 1, so we append 1s to the failure␣
˓→features to obtain all right hand sides:
failure_rhs_coefs = [Link](failure_features,[Link]([Link]((no_samples,1))),1)
# For the label +1, we do not need to make any change to the RHS, the lower bound is␣
(continues on next page)
And the following code snippet to define the set of constraints for the normal state condition
[ ]: normal_rhs_coefs = [Link](normal_features, [Link]([Link]((no_samples,1))),1)
normal_rhs_coefs = normal_rhs_coefs
# For the label +1, we do not need to make any change to the RHS, the lower bound is␣
˓→1, i.e. -[Link] <= x_1(i)*theta_1 + x_2(i)*theta_2 + theta_0 <= -1
Example
Now, we have everything that we need to build our separator! let us use the initial separator at the beginning of the
function as the initial guess:
[ ]: theta_hat_0 = [Link]([57, 1, -4452])
linear_constraint = [failure_linear_constraints, normal_linear_constraints]
print(len(linear_constraint))
# x_0 = [ 1.13792022e+00, 5.42842896e-03, -4.83177976e+01]
res = minimize(objective_func, theta_hat_0, constraints=linear_constraint,
options={"maxiter":1000, "disp": True})
print(res)
theta = res.x
Note that the separator might not be the same as a human would have selected when solving this task. This is because the
algorithm is quite sensitive to the initial guess passed as argument, and it can converge to a local minimum. To make the
algorithm more resilient, we can modify slightly the objective function to factor in 𝜃0 :
[ ]: def objective_func(theta):
return 1/2*(theta[0]**2 + theta[1]**2 + theta[2]**2)**(1/2)
With this regularization, we assume by looking at the data that the separator we are looking for crosses the y-axis at a
high value, and therefore, we include it in the objective function. Now, if we try again with this objective function, we get
a support vector machine which is closer to the solution that a human would provide:
theta_prime = res.x
Using Scipy
SVM
Luckily for us, we do not need to worry about in practice because Scipy packs an SVM model
[ ]: from [Link] import YTick
from sklearn import svm
clf_svm = [Link](kernel="linear")
X = [Link](failure_features, normal_features, axis=0)
#y is a vector of ones
y = [Link]((2*no_samples,1))
# make the normal features negative:
y[no_samples:]=-1
clf_svm.fit(X,y)
[Link]()
/usr/local/lib/python3.7/dist-packages/sklearn/utils/[Link]:␣
˓→DataConversionWarning: A column-vector y was passed when a 1d array was expected.␣
y = column_or_1d(y, warn=True)
clf_sgd.fit(X, y)
[Link]()
/usr/local/lib/python3.7/dist-packages/sklearn/utils/[Link]:␣
˓→DataConversionWarning: A column-vector y was passed when a 1d array was expected.␣
y = column_or_1d(y, warn=True)
1. Looking at the shapes of the different separators, which one do you think performed best given the training data?
Why?
2. Note that the variable no_samples defined in the first cell defines the number of samples. Increase the value
of samples to 3000 and run all the script again to see what happens. What are your main conclusions of this
experiment?
Set again the number of samples to 30 to answer the rest of the questions. 3. Note that in the Using Linear Program-
ming Section, the variable theta has the parameters of the first linear separator, and the variable theta_prime the
^ 𝜃^0 −1)|
parameter of the second linear separator. Recall that the margin is defined as 𝜔 = |(𝜃0 +1)−(
√︁ = ⃦⃦2^⃦⃦ º. Calculate
2𝜃^1 +𝜃^2
2 ⃦𝜃 ⃦
the margin of the two linear separators. Which one has the largest margin? Why?
[ ]:
4. Now, imagine we want to predict the status of the machine for the following points, given as pairs of temperature,
rpms (temperature, rpm):
• (32, 2600)
• (34, 2600)
• (36, 2600)
Note that to get the results with the two NLP linear separators, you need to calculate if the point is over or below the
separators as, as:
• theta[0]*temp + theta[1]*rpm + theta[2] >= 1 → predict failure
• theta[0]*temp + theta[1]*rpm + theta[2] <= -1 → predict normal state$
Test both linear separators in these provided points. Looking at the data, which one do you think provides more reliable
results?
[ ]:
5. Now, to predict values with the Scipy separators, you need to use the method predict() of the predictor. For
instance, the following script uses the SVM predictor to predict the values at 24 degrees and 2200 rpms and 28
degrees and 3300 rpms:
Write down a script to predict the values at the same points as in exercise 4, but using the Scipy models you have trained.
What are the main conclusions?
4.2 Exercises
On a housing estate on the Alicante coastline, two types of homes are being built: apartments and penthouses, whose
prices are 𝑝1 and 𝑝2 M€ respectively. The curve of demand for apartments is 𝑑1 = 40–2𝑝1 and 𝑑2 = 150–3𝑝2 for
penthouses. The builder calculated that, owing to the orders that he has already sent to his raw materials suppliers, it is
worth building 15 times more apartments than penthouses. He has also calculated that building an apartment costs him
5M€, while a penthouse costs him 3M€. Knowing that the builder has a budget of 350 M€, work out the following:
a) Write an NLP to calculate the optimal prices for apartments and penthouses.
b) Write the Kuhn Tucker conditions of the NLP problem
The Operations Department of DINOCO automobile manufacturing and assembly firm must establish the daily production
quantities of two car models (SUV and Compact) which maximise profits according to the production capacity constraints.
The firm also wishes to respect the environment, and in the future to benefit its sales, given its commitment to increase
the FFM (Fleet Fuel Mileage) indicator; that is, the mileage efficiency per litre of fuel of produced fleet.
To simplify this study case, a linear relation between the sale price and the quantity to be produced is assumed, given by
the following function: 𝑞𝑖 = 𝑎𝑖 − 𝑏𝑖 ·𝑝𝑖 , where 𝑎𝑖 and 𝑏𝑖 are constants provided in the table below, and 𝑝𝑖 is the mean unit
price per family of cars in K€. Parameter 𝐶𝑖 is also provided, which represents the cost per unit for the cars of family i.
The only productive resource that restricts the system is the assembly line. It is estimated that the firm spends 1 h every
day on assembling SUV and Compact cars. The time required (𝑅𝑖 ) to produce one unit of each family of cars and the
remaining former data are shown in the table.
The FFM indicator, which must be at least 15 Kmpl, is calculated by using the harmonic mean:
𝑞1 +𝑞2
𝐹𝐹𝑀 = 𝑞1 𝑞2
𝑘𝑚𝑝𝑙1 + 𝑘𝑚𝑝𝑙2
a) Formulate a non-linear programming model to help the Operations Department establish an optimum production plan
which meets the existing constraints
b) Find the Kuhn-Tucker conditions
c) A solver provides the following solution: 𝑞1 = 31.14, 𝑞2 = 34.26, 𝜆1 = −0.034, 𝜆2 = 0, where 𝜆1 is the Lagrangian
multiplier corresponding to the capacity constraint and 𝜆2 is the Lagrangian multiplier of the FFM constraint. Interpret
the results.
Problem Definition
You work for Nova case, a start-up company that manufactures protective cases for mobile phones made of a novel
material. The marketing department of your company has estimated a formula for the optimal price elasticity of demand
for the two different models you are currently selling online. Recall that the price elasticity of demand represents the
relationship between the quantity and the price of a good or service. They have estimated that, for both products, the
price elasticity follows the following expression:
LQ = K + E·LP
Where LQ is the logarithm of the quantity, LP is the logarithm of the price, K is the demand constant and E the demand
elasticity. You are in charge of the production department and need to calculate the optimal production mix one planning
period (1 day), taking into account this relationship between price and quantity. You have local production, and the most
restrictive resource is the moulding machine which has different cycle time (in seconds) for each case. You also have a
limited supply of the novel material and each model uses a different quantity of this material. In summary, this is the data
of your first product:
K1 = 4 E1 = 2 cycle time = 30 seconds key material quantity = 45 grams
And for your second product: K2 = 8 E2 = 2 cycle time = 25 seconds key material quantity = 40 grams
The total operational time of the moulding machine in the planning period is 6.5 hours and the supplier can provide you
up to 40 kilograms per day of the novel material.
a. Write down a Non-Linear Programming problem to calculate the optimal production mix.
b. Write down the Kuhn Tucker conditions.
c. Assume that you need to take into account in your model the initial stock level of each product at the beginning of the
planning period. How does this affect your model? Motivate your response
d. What would it mean if, in a Kuh Tucker point, the Lagrangian multiplier of the material quantity constraint was equal
to zero?
Problem Definition
Your startup company has just raised 100M€ in a round of funding to reinvest in the company during the next period.
Using regression and historical data, your team has found the following formulas for the Return of Investments (ROI) in
different departments:
Research and Development:
(︀ √ )︀
10· 3 2𝑋 − 2
Advertisement:
10· (ln(𝑋) − 2)
Technical Equipment:
(︀ )︀
10· 𝑒𝑋/50 − 2
Human Resources:
𝑋
10·
50
According to the collective agreement, the minimum investment in human resources is 20M€. Additionally, analysing
the formulas obtained, it is clear that although significant investments in technical equipment yield a high ROI, for small
investments the ROI of R&D or advertisement is actually larger. However, due to the pressure imposed by competitors,
the company has decided that investments in technical equipment must be at least high enough to ensure that this concept
does not have a negative impact in the ROI of the next period investments.
a. Write a Non-Linear Programming Model to maximise the ROI
b. Write down the Kuhn-Tucker conditions
c. Solving the problem yields a value of -0.29 for the lagrangian multiplier of the minimum investment in human resources
constraint. Interpret this result. How should the company use this value in the negotiation of the next collective agreement?
A firm that packs refreshments employs the same syrup to produce its 1.5 l COLI and PEPSA products on its S1 production
line. Once processed, each hectolitre of syrup produces 40 units of the 1.5 l COLI product or 20 units of the 1.5 l PEPSA
product. If 𝑥1 units of the 1.5 l COLI product and 𝑥2 units of the 1.5 l PEPSA product are produced, the firm estimates
that the daily income obtained in dollars would be given by the following function:
𝑓 (𝑥) = 49000·𝑥1 − 𝑥21 + 30·𝑥2 − 2·𝑥22
It costs 150 dollars to buy and process each hectolitre of syrup. The S1 packaging line has a net capacity of producing
56,800 1.5 l product units every day. The firm is committed to produce at least half the amount of PEPSA than COLI.
Although priority orders tend to amend its production planning, the firm wishes to have a basic product planning that
optimises its daily profits.
a) Formulate a non-linear programming model that helps the firm create its basic daily product planning for its S1 pack-
aging line.
b) Write down the Kuhn Tucker conditions that would help the company determine the basic daily production plan.
c) The following critical point is found 𝑥1 = 13838.33; 𝑥2 = 6919.16; 𝜆1 = 0; 𝜆2 = 15323.34; 𝑧 = 287249204.2,
where 𝜆1 is the Lagrangian multiplier corresponding to the S1 packaging line capacity constraint. Can you conclude
whether it is a local/global maximum? With this solution, What is the maximum quantity that the firm would be willing
to pay for 1 h of overtime production? How much would the daily profit increase per additional COLI unit produced?
Problem definition
Cheston Pharmaceuticals manufactures two different products. The company has conducted different studies to estimate
the demand curve of their products, to learn the relationship between price and demand. The company has build a linear
model that has proven to be accurate enough in the price range of interest for the company. Let us note the linear model
as:
𝑑𝑗 = −𝜃𝑗 * 𝑝𝑗 + 𝜃^𝑗 𝑝𝑗 = [𝑚𝑗 , 𝑀𝑗 ], ∀𝑗 = [1, 2]
Where 𝑑𝑗 is the total units of product 𝑗 manufactured, 𝑝𝑗 is the price of product 𝑗 and 𝜃𝑗 and 𝜃^𝑗 are the parameters of
the linear models for the curve of demand of product 𝑗. The price of product 𝑗 must be in the range of interest, that is,
greater or equal than the minimum price 𝑚𝑗 and lower or equal than the maximum 𝑀𝑗 .
Both products incorporate a critical compound for which the company has limited resources to produce. The total pro-
duction capacity of the company for the compound in the planning period is C (milligrams). A unit of product 𝑗 contains
𝑟𝑗 milligrams of the critical compound.
Let us assume that the production costs of product 𝑗 can be neglected.
a. Write a Non-Linear Programming problem to calculate the optimal production mix (number of units to produce of
each product) that maximises the revenues in the planning period.
b Write down the Lagrangian
c Write down the Kuhn-Tucker conditions:
d. Write down the Hessian matrix and the Hessian determinants. In case that you find a critical point, can you determine
if it is a local or a global maximum? Motivate your response.
Problem definition
You work on the R&D department of Banshee Ltd., a company that manufactures headphones. Through a customer
survey you have determined that the level of satisfaction of your headphones is given by the following expression:
𝑧 = 5 + 𝑙𝑛(𝑥1 ) + 𝑥22 + 𝑥1 * 𝑥2
where 𝑥1 is the thickness of the diaphragm in microns and 𝑥2 is the radius of the diaphragm in millimeters. Due to
design constraints, the volume of the driver, which can be estimated as 0.2 * 𝜋 * 𝑥2 * 𝑥1 cannot be larger than 0.172 cubic
millimeters. The properties of the material you use makes it unfeasible to manufacture a diaphragm with a thickness
lower than 0.3 microns or higher than 0.9 microns.
a Write a Non-Linear Programming (NLP) problem to find the optimal design specifications (thickness and radius of
diaphragm) for Banshee Ltd.
b Write down the Lagrangian and the Kuhn Tucker conditions
c A solver gives you the following solution (𝑥1 = 0.9, 𝑥2 = 0.304). Determine if it is a local or global maximum
Problem Definition
Nathaniel Richards is a young, brilliant scientist that has developed the following Non-Linear Programming (NLP) prob-
lem to find the optimal balance between studying and meditating to maximize the overall satisfaction and achieve a state
of enlightenment (Mathematical Nirvana).
Decision Variables: Let:
𝑥1 Time spent studying (in hours)
𝑥2 = Time spent meditating (in hours)
𝑥 = [𝑥1 , 𝑥2 ] The set of decision variables
𝑥1 , 𝑥 2 ≥ 0
Objective Function: Maximize the overall satisfaction obtained from studying and meditating:
max 𝑧 = 𝑓 (𝑥) = 2 * 𝑥1 + 0.5 * ln(1 + 𝑥1 ) + 0.7 * 𝑥2 + 0.3 * (𝑥2 )
√︀
On a housing estate on the Alicante coastline, two types of homes are being built: apartments and penthouses, whose
prices are 𝑝1 and 𝑝2 M€ respectively. The curve of demand for apartments is 𝑑1 = 40–2𝑝1 and 𝑑2 = 150–3𝑝2 for
penthouses. The builder calculated that, owing to the orders that he has already sent to his raw materials suppliers, it is
worth building 15 times more apartments than penthouses. He has also calculated that building an apartment costs him
5M€, while a penthouse costs him 3M€. Knowing that the builder has a budget of 350 M€, work out the following:
a) Write an NLP to calculate the optimal prices for apartments and penthouses.
max 𝑧 = (𝑝1 − 5)(40 − 2𝑝1 ) + (𝑝2 − 3)(150 − 3𝑝2 ) = −2𝑝21 − 3𝑝22 + 50𝑝1 + 159𝑝2 − 650
s.t
def objective_func(p):
return 2*p[0]**2 + 3*p[1]**2 - 50*p[0] - 159*p[1]+650
p0 = [5, 40]
print(res.x)
Optimization terminated successfully (Exit mode 0)
Current function value: 2387450.0025050757
Iterations: 3
Function evaluations: 11
Gradient evaluations: 3
[1.10500000e+03 2.08014536e-08]
The Operations Department of DINOCO automobile manufacturing and assembly firm must establish the daily production
quantities of two car models (SUV and Compact) which maximise profits according to the production capacity constraints.
The firm also wishes to respect the environment, and in the future to benefit its sales, given its commitment to increase
the FFM (Fleet Fuel Mileage) indicator; that is, the mileage efficiency per litre of fuel of produced fleet.
To simplify this study case, a linear relation between the sale price and the quantity to be produced is assumed, given by
the following function: 𝑞𝑖 = 𝑎𝑖 − 𝑏𝑖 ·𝑝𝑖 , where 𝑎𝑖 and 𝑏𝑖 are constants provided in the table below, and 𝑝𝑖 is the mean unit
price per family of cars in K€. Parameter 𝐶𝑖 is also provided, which represents the cost per unit for the cars of family i.
The only productive resource that restricts the system is the assembly line. It is estimated that the firm spends 1 h every
day on assembling SUV and Compact cars. The time required (𝑅𝑖 ) to produce one unit of each family of cars and the
remaining former data are shown in the table.
The FFM indicator, which must at least be 15 Kmpl, is calculated by using the harmonic mean:
𝑞1 +𝑞2
𝐹𝐹𝑀 = 𝑞1 𝑞2
𝑘𝑚𝑝𝑙1 + 𝑘𝑚𝑝𝑙2
a) Formulate a non-linear programming model to help the Operations Department establish an optimum production plan
which meets the existing constraints
The decision variables are the quantities to produce (𝑞𝑖 )
The objective of the production plan is to maximise profits:
max 𝑧 = 𝑖 𝑞𝑖 ·(𝑝𝑖 − 𝐶𝑖 )
∑︀
(︂ )︂
∑︀ 𝑎𝑖 − 𝑞𝑖
= 𝑖 (𝑞𝑖 )· − 𝐶𝑖
𝑏𝑖
(︂ )︂ (︂ )︂
440 − 𝑞1 248 − 𝑞2
= 𝑞1 · − 17 + 𝑞2 · − 13
20 12
𝑧 = −0.05𝑞12 − 0.083𝑞22 + 5𝑞1 + 7.6𝑞2
We have two constraints,
The first constraint takes into account the bottleneck in the assembly line (seconds):
𝑖 𝑅𝑖 ·𝑞𝑖 ≤ 3600
∑︀
𝑞1 ·(1 − 15
𝑘𝑚𝑝𝑙1 ) + 𝑞2 ·(1 − 15
𝑘𝑚𝑝𝑙2 ) ≥0→
−𝑞1 · 12
3
+ 𝑞2 · 20
5
≥0→
𝑞1 · 12
3
− 𝑞2 · 20
5
≤0→
0.25·𝑞1 − 0.25·𝑞2 ≤ 0
Problem Definition
You work for Nova case, a start-up company that manufactures protective cases for mobile phones made of a novel
material. The marketing department of your company has estimated a formula for the optimal price elasticity of demand
for the two different models you are currently selling online. Recall that the price elasticity of demand represents the
relationship between the quantity and the price of a good or service. They have estimated that, for both products, the
price elasticity follows the following expression:
LQ = K + E·LP
Where LQ is the logarithm of the quantity, LP is the logarithm of the price, K is the demand constant and E the demand
elasticity. You are in charge of the production department and need to calculate the optimal production mix one planning
period (1 day), taking into account this relationship between price and quantity. You have local production, and the most
restrictive resource is the moulding machine which has different cycle time (in seconds) for each case. You also have a
limited supply of the novel material and each model uses a different quantity of this material. In summary, this is the data
of your first product:
• K1 = 4
• E1 = 2
• cycle time = 30 seconds
• key material quantity = 45 grams
And for your second product:
• K2 = 8
• E2 = 2
• cycle time = 25 seconds
• key material quantity = 40 grams
The total operational time of the moulding machine in the planning period is 6.5 hours and your supplier can provide you
up to 40 kilograms per day of the novel material.
a. Write down a Non-Linear Programming problem to calculate the optimal production mix. (1 point) This is a non-linear
production mix problem where the objective is to maximise profits. The objective function is of the type:
max 𝑧 = 𝑖 𝑄𝑖 ·𝑃𝑖
∑︀
We know that relationship between price and quantity is determined by the price elasticity expression:
LQ = K + E·LP
Now, we can transform this into a linear expression as:
𝑒ln(𝑄) = 𝑒𝑘+𝐸· ln(𝑃 ) = 𝑒𝑘 * 𝑒𝐸· ln(𝑃 )
𝑄 = 𝑒𝑘 ·𝑃 𝐸
or
𝑃 = 𝑒−𝑘/𝐸 ·𝑄1/𝐸
We can now substitute this expression in the objective function.
1/𝐸
max 𝑧 = 𝑖 𝑄𝑖 ·𝑒−𝑘𝑖 /𝐸𝑖 ·𝑄𝑖 𝑖
∑︀
𝐸 +1/𝐸𝑖
max 𝑧 = 𝑖 𝑒−𝑘𝑖 /𝐸𝑖 ·𝑄𝑖 𝑖
∑︀
3/2 3/2
max 𝑧 = 𝑒−2 ·𝑄1 + 𝑒−4 ·𝑄2
We have two constraints that depend on the decision variables, the operating time of the moulding machine and the
availability of materials:
30·𝑄1 + 25·𝑄2 ≤ 6.5·60·60
45·𝑄1 + 40·𝑄2 ≤ 40000
b. Write down the Kuhn Tucker conditions. (2 points)
Let us start by writing the problem in the canonical form:
3/2 3/2
max 𝑧 = 𝑒−2 ·𝑄1 + 𝑒−4 ·𝑄2
30·𝑄1 + 25·𝑄2 − 23400 ≤ 0
45·𝑄1 + 40·𝑄2 − 40000 ≤
Now, the Lagrangian:
3/2 3/2
𝐿 = 𝑒−2 ·𝑄1 + 𝑒−4 ·𝑄2 + 𝜆1 ·(30·𝑄1 + 25·𝑄2 − 23400) + 𝜆2 ·(45·𝑄1 + 40·𝑄2 − 40000)
We are ready to proceed with the Kuhn Tucker conditions.
• Gradient condition
√
𝑑𝐿
𝑑𝑄1 = 3/2·𝑒−2 · 𝑄1 + 30·𝜆1 + 45·𝜆2
√
𝑑𝐿
𝑑𝑄2 = 3/2·𝑒
−4
· 𝑄2 + 25·𝜆1 + 40·𝜆2
• Orthogonality condition
𝜆1 ·(30·𝑄1 + 25·𝑄2 − 23400) = 0
$:nbsphinx-math:lambda_2·(45·Q_1 + 40·Q_2 - 40000) = 0 $
• Feasibility condition
30·𝑄1 + 25·𝑄2 − 23400 ≤ 0
45·𝑄1 + 40·𝑄2 − 40000 ≤ 0
• Non negativity condition
𝑄1 , 𝑄2 ≥ 0
𝜆1 , 𝜆 2 ≤ 0
c. Assume that you need to take into account in your model the initial stock level of each product at the beginning of the
planning period. How does this affect your model? Motivate your response (1 point)
If we need to take into account the initial stock level, we need to define new decision variables representing the amounts to
stock for next periods, and a new index to represent the periods. The objective function would take into account the total
available quantity, that is, the sum of the produce quantity plus the quantity manufactured in previous periods that we can
use at one period. Similarly, in the constraint we could use the available resources to produce for the current period or
for future periods.
d. What would it mean if, in a Kuh Tucker point, the Lagrangian multiplier of the material quantity constraint was equal
to zero? (1 point)
If the Lagrangian multiplier of the material quantity constraint is equal to zero, then by the orthogonality condition the
right hand side of the constraint might be less than the daily quantity available, meaning that there might be some unused
quantity.
Problem definition
Your startup company has just raised 100M€ in a round of funding to reinvest in the company during the next period.
Using regression and historical data, your team has found the following formulas for the Return of Investments (ROI) in
different departments:
Research and Development:
(︀ √ )︀
10· 3 2𝑋 − 2
Advertisement:
10· (ln(𝑋) − 2)
Technical Equipment:
(︀ )︀
10· 𝑒𝑋/50 − 2
Human Resources:
𝑋
10·
50
According to the collective agreement, the minimum investment in human resources is 20M€. Additionally, analysing
the formulas obtained, it is clear that although significant investments in technical equipment yield a high ROI, for small
investments the ROI of R&D or advertisement is actually larger. However, due to the pressure imposed by competitors,
the company has decided that investments in technical equipment must be at least high enough to ensure that this concept
does not have a negative impact in the ROI of the next period investments.
a. Write a Non-Linear Programming Model to maximise the ROI (1.5 points)
Decision variables 𝑥𝑛 , 𝑛 = [1, 2, 3, 4]: (non-negative) Investment in M€ in 1: R&D, 2: Advertisement, 3: Technical
Equipment, 4: Human Resources
Maximise ROI.
(︀ √ 𝑥4
max 𝑧 = 10· 3 2𝑥1 − 2 + 10· (ln(𝑥2 ) − 2) + 10· 𝑒𝑥3 /50 − 2 + 10·
)︀ (︀ )︀
50
s.t.
𝑥1 + 𝑥2 + 𝑥3 + 𝑥4 ≤ 100
𝑥4 ≥ 20
(︀ )︀
10· 𝑒𝑥3 /50 − 2 ≥ 0
𝑥𝑛 ≥ 0 ∀𝑛
b. Write down the Kuhn-Tucker conditions (1.5 points)
First, we write down the problem in the canonical form:
(︀ √ 𝑥4
max 𝑧 = 10· 3 2𝑥1 − 2 + 10· (ln(𝑥2 ) − 2) + 10· 𝑒𝑥3 /50 − 2 + 10·
)︀ (︀ )︀
50
s.t.
𝑥1 + 𝑥2 + 𝑥3 + 𝑥4 − 100 ≤ 0
20 − 𝑥4 ≤ 0
(︀ )︀
−10· 𝑒𝑥3 /50 − 2 ≤ 0
𝑥𝑛 ≥ 0 ∀𝑛
From here, we can write down the Lagrangian:
(︀ √ )︀ (︀ )︀ 𝑥4
𝐿 = 10· 2𝑥1 − 2 + 10· (ln(𝑥2 ) − 2) + 10· 𝑒𝑥3 /50 − 2 + 10·
3
50
𝜆1 ·(𝑥1 + 𝑥2 + 𝑥3 + 𝑥4 − 100)
𝜆2 ·(20 − 𝑥4 )
𝜆3 ·(−10· 𝑒𝑥3 /50 − 2
(︀ )︀
And, once we have computed the lagrangian, we can obtain the Kuhn-Tucker conditions:
Gradient condition
∇𝐿 = 0
𝑑𝐿
= 20/3·(2·𝑥1 − 2)−2/3 + 𝜆1 = 0
𝑑𝑥1
𝑑𝐿
= 10·(1/𝑥2 ) + 𝜆1 = 0
𝑑𝑥2
𝑑𝐿
= 10/50·𝑒𝑥3 /50 + 𝜆1 − 𝜆3 ·10/50·𝑒𝑥3 /50 = 0
𝑑𝑥3
𝑑𝐿
= 10/50 + 𝜆1 − 𝜆2 = 0
𝑑𝑥4
Orthogonality condition
𝜆1 ·(𝑥1 + 𝑥2 + 𝑥3 + 𝑥4 − 100) = 0
𝜆2 ·(20 − 𝑥4 ) = 0
𝜆3 ·(−10· 𝑒𝑥3 /50 − 2 = 0
(︀ )︀
Feasibility condition
𝑥1 + 𝑥2 + 𝑥3 + 𝑥4 − 100 ≤ 0
20 − 𝑥4 ≤ 0
(︀ )︀
−10· 𝑒𝑥3 /50 − 2 ≤ 0
non-negative condition:
𝜆𝑛 ≤ 0∀𝑛
𝑥𝑛 ≥ 0 ∀𝑛
c. Solving the problem yields a value of -0.29 for the lagrangian multiplier of the minimum investment in human resources
constraint. Interpret this result. How should the company use this value in the negotiation of the next collective agreement?
(1 point)
The lagrangian multiplier represents the change in the objective function per unitary change in the right-hand side of the
corresponding constraint. Note that, in the canonical form, if we increase the right hand side 1 unit (from 0), then we
need to increase the left hand side also one unit for the equation to remain the same, for instance making the investments
in human resources raise to 21M€. This yields a decrease of the ROI of -0.29M€, so the impact of increasing the
investments in human resources is negative in the return for the company. In the next collective agreement negotiation,
the company could use this to argue against proposals or make a proposal to reduce the investment.
A firm that packs refreshments employs the same syrup to produce its 1.5 l COLI and PEPSA products on its S1 production
line. Once processed, each hectolitre of syrup produces 40 units of the 1.5 l COLI product or 20 units of the 1.5 l PEPSA
product. If 𝑥1 units of the 1.5 l COLI product and 𝑥2 units of the 1.5 l PEPSA product are produced, the firm estimates
that the daily income obtained in dollars would be given by the following function:
𝑓 (𝑥) = 49000·𝑥1 − 𝑥21 + 30·𝑥2 − 2·𝑥22
It costs 150 dollars to buy and process each hectolitre of syrup. The S1 packaging line has a net capacity of producing
56,800 1.5 l product units every day. The firm is committed to produce at least half the amount of PEPSA than COLI.
Although priority orders tend to amend its production planning, the firm wishes to have a basic product planning that
optimises its daily profits.
a) Formulate a non-linear programming model that helps the firm create its basic daily product planning for its S1 pack-
aging line. Our decision variables are:
• 𝑥1 : Units of COLI
• 𝑥2 : Units of PEPSA
The objective is to maximise the profits, so we need to calculate the difference between the revenues and the costs:
max 𝑧 = 𝑓 (𝑥) − 𝑐(𝑥)
Let us first consider the costs as a function of the number of hectolitres of syrup used (ℎ𝑙 ):
𝑐 = 150 * ℎ𝑙
ℎ𝑙 = 𝑥1 /40 + 𝑥2 /20
If we define the cost as a function of 𝑥 = [𝑥1 , 𝑥2 ], then:
𝑐(𝑥) = 150·(𝑥1 /40 + 𝑥2 /20)
Now, z becomes:
𝑧 = 49000·𝑥1 − 𝑥21 + 30·𝑥2 − 2·𝑥22 − 3.75·𝑥1 − 7.5·𝑥2
As for the constraints, the capacity cannot exceed the total capacity of the line:
𝑥1 + 𝑥2 ≤ 56800
And the
𝑧 = 48996.25𝑥1 − 𝑥21 + 22.5·𝑥2 − 2𝑥22
𝑠.𝑡
𝑥1 + 𝑥2 ≤ 56800
𝑥2 ≥ 𝑥1 /2
Or in canonical form:
𝑧 = 48996.25𝑥1 − 𝑥21 − 22.5·𝑥2 − 2𝑥22
𝑠.𝑡.
𝑥1 + 𝑥2 − 56800 ≤ 0
𝑥1 − 2𝑥2 ≤ 0
𝑥1 , 𝑥 2 ≥ 0
b) Write down the Kuhn Tucker conditions that would help the company determine the basic daily production plan.
The Lagrangian is:
Problem definition
Cheston Pharmaceuticals manufactures two different products. The company has conducted different studies to estimate
the demand curve of their products, to learn the relationship between price and demand. The company has build a linear
model that has proven to be accurate enough in the price range of interest for the company. Let us note the linear model
as:
𝑑𝑗 = −𝜃𝑗 * 𝑝𝑗 + 𝜃^𝑗 𝑝𝑗 = [𝑚𝑗 , 𝑀𝑗 ], ∀𝑗 = [1, 2]
Where 𝑑𝑗 is the total units of product 𝑗 manufactured, 𝑝𝑗 is the price of product 𝑗 and 𝜃𝑗 and 𝜃^𝑗 are the parameters of
the linear models for the curve of demand of product 𝑗. The price of product 𝑗 must be in the range of interest, that is,
greater or equal than the minimum price 𝑚𝑗 and lower or equal than the maximum 𝑀𝑗 .
Both products incorporate a critical compound for which the company has limited resources to produce. The total pro-
duction capacity of the company for the compound in the planning period is C (milligrams). A unit of product 𝑗 contains
𝑟𝑗 milligrams of the critical compound.
Let us assume that the production costs of product 𝑗 can be neglected.
a. Write a Non-Linear Programming problem to calculate the optimal production mix (number of units to produce of
each product) that maximises the revenues in the planning period.
The optimization problem can be defined as:
max 𝑧 = 𝑗 𝑑𝑗 * 𝑝𝑗
∑︀
s.t.
𝑝𝑗 ≥ 𝑚𝑗 ∀𝑗
𝑝𝑗 ≤ 𝑀𝑗 ∀𝑗
∑︀
𝑗 𝑑𝑗 * 𝑟𝑗 ≤ 𝐶
yields:
∑︀ (︁ 𝜃^𝑗
)︁
max 𝑧 = 𝑗 − 𝜃1𝑗 * 𝑑2𝑗 + 𝜃𝑗 * 𝑑𝑗
𝑠.𝑡.
1 𝜃^𝑗
𝜃𝑗 * 𝑑𝑗 − 𝜃𝑗 + 𝑚𝑗 ≤ 0 ∀𝑗
𝜃^
− 𝜃1𝑗 * 𝑑𝑗 + 𝜃𝑗𝑗 − 𝑀𝑗 ≤ 0 ∀𝑗
∑︀
𝑗 𝑑𝑗 * 𝑟𝑗 − 𝐶 ≤ 0
𝜃^1 𝜃^2
... + 𝜆3 * (− 𝜃11 * 𝑑1 + − 𝑀1 ) + 𝜆4 * (− 𝜃12 * 𝑑2 +
∑︀
𝜃1 𝜃2 − 𝑀2 ) + 𝜆5 ( 𝑗 𝑑𝑗 * 𝑟𝑗 − 𝐶)
Non-negativity condition
𝑝𝑗 ≥ 0 ∀𝑗 = [1, 2]
𝜆𝑖 ≤ 0∀𝑖 = [1, 5]
d. Write down the Hessian matrix and the Hessian determinants. In case that you find a critical point, can you determine
if it is a local or a global maximum? Motivate your response.
[︂ 2 ]︂
− 𝜃1 0
𝐻=
0 − 𝜃22
ℎ1 = − 𝜃11
1
ℎ2 = 𝜃1 *𝜃2
It is not possible to conclude that this is a critical point from the Hessian determinants, although it is possible to test the
equivalent minimization problem 𝑧* = −𝑧 for which the Hessian matrix is:
[︂ 1 ]︂
𝜃 0
𝐻= 1
0 𝜃12
And the Hessian determinants are:
1
ℎ1 = 𝜃1
1
ℎ2 = 𝜃1 *𝜃2
Meaning that the Hessian is definitive positive and therefore the critical point that has been found is a global maximum.
Problem definition
You work on the R&D department of Banshee Ltd., a company that manufactures headphones. Through a customer
survey you have determined that the level of satisfaction of your headphones is given by the following expression:
𝑧 = 5 + 𝑙𝑛(𝑥1 ) + 𝑥22 + 𝑥1 * 𝑥2
where 𝑥1 is the thickness of the diaphragm in microns and 𝑥2 is the radius of the diaphragm in millimeters. Due to
design constraints, the volume of the driver, which can be estimated as 0.2 * 𝜋 * 𝑥2 * 𝑥1 cannot be larger than 0.172 cubic
millimeters. The properties of the material you use makes it unfeasible to manufacture a diaphragm with a thickness
lower than 0.3 microns or higher than 0.9 microns.
a Write a Non-Linear Programming (NLP) problem to find the optimal design specifications (thickness and radius of
diaphragm) for Banshee Ltd.
The objective is to maximise the level of satisfaction given by the following expressions:
max 𝑧 = 5 + 𝑙𝑛(𝑥1 ) + 𝑥22 + 𝑥1 * 𝑥2
s.t.
2 * 𝜋 * 𝑥2 * 𝑥1 ≤ 1.72
𝑥1 ≥ 0.3
𝑥1 ≤ 0.9
b Write down the Lagrangian and the Kuhn Tucker conditions
The Lagrangian is:
L(𝑥1 , 𝑥2 , 𝜆1 , 𝜆2 , 𝜆3 ) = 5 + 𝑙𝑛(𝑥1 ) + 𝑥22 + 𝑥1 * 𝑥2 + 𝜆1 * (2 * 𝜋 * 𝑥2 * 𝑥1 − 1.72) + 𝜆2 * (0.3 − 𝑥1 ) + 𝜆3 * (𝑥1 − 0.9)
Gradient condition
∇(L(𝑥1 , 𝑥2 , 𝜆1 , 𝜆2 , 𝜆3 )) = 0
𝛿L 1
𝛿𝑥1 = 𝑥1 + 𝑥2 + 2 * 𝜋 * 𝜆1 * 𝑥2 − 𝜆2 + 𝜆3 = 0
𝛿L
𝛿𝑥2 = 2 * 𝑥2 + 𝑥1 + 2 * 𝜋 * 𝜆 1 * 𝑥1 = 0
Feasibility condition
2 * 𝜋 * 𝑥2 * 𝑥1 ≤ 1.72
𝑥1 ≥ 0.3
𝑥1 ≤ 0.9
Orthogonality condition
𝜆1 * (2 * 𝜋 * 𝑥2 * 𝑥1 − 1.72) = 0
𝜆2 * (0.3 − 𝑥1 ) = 0
𝜆3 * (𝑥1 − 0.9) = 0
Non-Negativity condition
Since we expressed the problem in the canonical form, we know that the multipliers must be non-negative: 𝑥1 , 𝑥2 ≥ 0
𝜆1 , 𝜆 2 , 𝜆 3 ≤ 0
c A solver gives you the following solution (𝑥1 = 0.9,𝑥2 = 0.304). Determine if it is a local or global maximum
First, we need to calculate the Lagrangian multipliers to make sure that the solution is feasible.
We plug in the numbers provided by the solver in the second gradient condition and obtain:
−2*𝑥2 −𝑥1
𝜆1 = 2*𝜋*𝑥1 = −0.267 ≤ 0
From the second orthogonality condition, we know that 𝜆2 must be zero:
𝜆2 * (0.3 − 𝑥1 ) = 𝜆2 * (−0.6) = 0
𝜆2 = 0
Now, we can plug in this value into the first gradient condition to compute 𝜆3 :
𝜆3 = −1/𝑥1 − 𝑥2 − 2 * 𝜋 * 𝜆1 * 𝑥2 = −0.906
Since all the multipliers are non-positive, the solution is feasible. The Hessian is given by:
[︂ −1 ]︂
𝑥 2 1
𝐻= 1
1 2
The determinants of the Hessian are:
−1
ℎ1 = 𝑥22
≤ 0 ∀𝑥2 > 0
−2
ℎ2 = 𝑥22
− 1 ≤ 0 ∀𝑥2 > 0
Since 𝑥2 is greater than zero, the solution is a global maximum.
Problem Definition
Nathaniel Richards is a young, brilliant scientist that has developed the following Non-Linear Programming (NLP) prob-
lem to find the optimal balance between studying and meditating to maximize the overall satisfaction and achieve a state
of enlightenment (Mathematical Nirvana).
Decision Variables: Let:
𝑥1 Time spent studying (in hours)
𝑥2 = Time spent meditating (in hours)
𝑥 = [𝑥1 , 𝑥2 ] The set of decision variables
𝑥1 , 𝑥 2 ≥ 0
Objective Function: Maximize the overall satisfaction obtained from studying and meditating:
max 𝑧 = 𝑓 (𝑥) = 2 * 𝑥1 + 0.5 * ln(1 + 𝑥1 ) + 0.7 * 𝑥2 + 0.3 * (𝑥2 )
√︀
Note that to obtain the expression above we have first express the problem in a canonical form where all the constraints
are inequalities of type ≤.
Now, we can obtain the Kuhn-Tucker conditions by taking the partial derivatives of the Lagrangian function with respect
to the decision variables and the Lagrangian multipliers:
• Gradient Conditions: ∇𝑥 𝐿(𝑥, 𝜆) = 0
𝜕𝐿 0.5
𝜕𝑥1 =2+ 1+𝑥1 + 𝜆1 − 𝜆2 = 0
𝜕𝐿 0.3
𝜕𝑥2 = 0.7 + √
2 𝑥2 + 𝜆1 = 0
𝜕 2 𝑓 (𝑥) 0.3
𝜕𝑥22
=− 3/2 ≤0
4*𝑥2
𝜕 2 𝑓 (𝑥)
𝜕𝑥1 𝜕𝑥2 =0
𝜕 2 𝑓 (𝑥)
𝜕𝑥2 𝜕𝑥1 =0
Now, we can obtain the Hessian matrix:
0.5
⎡ ⎤
−
⎢ (1+𝑥1 ) 2 0
𝐻(𝑥) = ⎣
⎥
0.3 ⎦
0 − 3/2
4*𝑥2
To determine if the solution is a global or local maximum, we need to check the definiteness of the Hessian matrix for
the values 𝑥1 = 3.9, 𝑥2 = 6.1:
0.5
⎡ ⎤ ⎡ ⎤
− 2 0 −0.02 0
𝐻(𝑥) = ⎣ (1+3.9) ⎦=⎣ ⎦
0.3 0 −0.005
0 − 4*6.1 3/2
The first determinant is negative (ℎ1 = −0.02), and the second determinant is positive (ℎ2 = −0.02 * −0.005 > 0),
so the Hessian matrix is indefinite. Therefore, the test is inconclusive. If we look at the Hessian matrix of the equivalent
minimization problem (min 𝑓 * (𝑥) = −𝑓 (𝑥)), since now the Hessian becomes:
[︂ ]︂
0.02 0
𝐻(𝑥) =
0 0.005
we can see that it is positive definite (ℎ1 = 0.02, ℎ2 = 0.02 * 0.005 > 0), so the solution is a global minimum, and
therefore the solution to the original maximization problem is a global maximum.
5. Use the Kuhn-Tucker conditions to calculate the Lagrangian multipliers for this solution, can you explain what they
mean? Discuss if this can be an optimal solution to the problem
Now, we can use the Kuhn-Tucker conditions to calculate the Lagrangian multipliers for this solution. From the gradient
conditions, we have:
𝜕𝐿 0.5
𝜕𝑥1 =2+ 1+3.9 + 𝜆1 − 𝜆2 = 0
𝜕𝐿 0.3
𝜕𝑥2 = 0.7 + √
2 6.1
+ 𝜆1 = 0
From the second gradient condition, we can obtain the value of 𝜆1 :
0.3
𝜆1 = −0.7 − √
2 6.1
= −0.8
From the first gradient condition, we can obtain the value of 𝜆2 :
0.5
𝜆2 = 2 + 1+3.9 + 𝜆1 = 1.35
The Lagrangian multipliers obtained do not satisfy the orthogonality conditions and non-negative conditions, so this so-
lution cannot be optimal.
FIVE
This chapter provides an introduction to decision theory, where we will focus on solving decision problems whre the de-
cision maker must select among various alternatives, which provide different performance. The chapter also covers game
theory, a field dedicated to modelling and solving decision problems involving several rational decision makers. Here,
we will focus on solving decision problems where the decision maker must select among various alternatives, focusing on
competition and collaboration.
5.1 Tutorials
Introduction
Decision theory spans a combination of problem-solving techniques to find the best decision in complex decision problems.
In this unit, we will use the following terminology:
• Alternatives: Decision variables which are controllable and depend on the decision maker’s decision.
• Uncertainty and states of nature: External variables, are uncontrollable and need to be estimated or assumed.
• Performances: Profit or Cost (utility) of the result of a decision
Hence, the objective is to find the alternative with the highest performance for the decision maker, possibly in situations
where the performance may depend on external variables which cannot be controlled.
So far, this set up is not that different from the definitions seen in previous units, however, we will be focusing on the
following aspects in this unit:
• Impacts over time All the important consequences of a problem do not occur at the same instant in time
• Uncertainty At the time the decision-maker must select an alternative, the consequences are not known with
certainty.
• Possibility of acquiring information Often we can acquire additional information to support decision-making
at a cost. For instance, to collect seismic information to decide whether to drill for oil. Decision theory provides
methods to evaluate if it is worth acquiring additional information or not.
• Dynamic aspects The problem might not end immediately after an alternative is chosen but might require further
analysis (e.g. further decisions)
317
Notebooks for Operations Research, Release I
The pay-off matrix is a tool to represent the performances of the different alternatives against the possible future outcomes
of an uncontrolled event, or states of nature. The different rows of the matrix represent the alternatives of the decision
maker, and the different columns of the matrix, the different possible states of nature. Finally, every cell in the matrix
contains the performance of each alternative given the occurrence of each state of nature. That is, let us note the decision
maker’s alternatives as 𝑎1 , 𝑎2 , ..., 𝑎𝑚 , and the different states of nature as 𝑠1 , 𝑠2 , ..., 𝑠𝑛 . Let us note the performance of
alternative 𝑎𝑖 when 𝑠𝑗 has occurred as 𝑢𝑖𝑗 , then the pay-off matrix is:
⎡ ⎤
𝑢11 𝑢12 ... 𝑢1𝑛
⎣ 𝑢21 𝑢22 ... 𝑢2𝑛 ⎦
𝑢𝑚1 𝑢𝑚2 ... 𝑢𝑚𝑛
Note that the pay-off matrix represents all possible outcomes of our decision under uncertainty, given that the states of
nature are exhaustive (together they describe all the possible outcomes of the uncontrolled variable) and mutually exclusive
(if one occurs, then the rest cannot occur). The pay-off matrix can also be represented in tabular form as:
Let us, at this point, set one example to be used in the next sections of this presentation. In the example, the decision
maker needs to select a financial product among a set of market alternatives: Gold, bonds, stock options, deposit, or hedge
fund. Each product provides different benefits or losses depending on the behaviour of the market. The behaviour of the
market is not controlled by the decision maker, therefore, it is characterised in this example as a set of states of natures:
• Accumulation Phase: The market is stable and characterised by a slow raise
• Mark-up Phase: The market has been stable for a while, investors feel secure and the market is characterised by a
fast raise.
• Distribution Phase: Most investors start selling to collect benefits, the market stabilises and there is little or no
change.
• Mark-down Phase: Some investors try to hold positions as there is a large fall of the market
The pay-off matrix shows the expected performance in euros of the investment of each product under each market cycle
phase:
Dominance
Dominance is a property of alternatives that provide a better performance than others for every state of nature. In the
example above, it can be seen that the bond provides a higher benefit than the option hedge in any market scenario,
therefore the bond option is dominant over the hedge fund option. Dominance allows us to simplify the decision-making
process, eliminating the dominated alternatives in favour of the dominant alternatives. Taking into account dominance,
the pay-off matrix above can be written as:
Any rational decision maker would select bonds before stock options under any market phase and therefore, the latter can
be ignored.
Decision Rules
Decision rules are criteria used by a rational decision maker to make systematic decisions, id est, to select the best alter-
native. This section describes some of the most important criteria in related literature:
MinMax
The MinMax criteria aims to minimise loss in the worst-case scenario. It is therefore a conservative, or pessimistic criteria.
Also known as Maximin (minimise the maximum loss), this criteria first finds the minimum value of the performance of
each decision variables in every scenario:
𝑚𝑖 = min(𝑢𝑖1 , 𝑢𝑖2 , ..., 𝑢𝑖𝑛 ) ∀𝑖 = [1, 2, ..., 𝑚]
These values represent the worst case scenario in every decision alternative, then the minmax criteria selects the maximum
of these values:
𝑑 = argmax(𝑚1 , 𝑚2 , ..., 𝑚𝑚 )
The function argmax above returns the index of the maximum value rather than the maximum value. Hence, it will return
the index of the alternative for which the maximum is value:
In the example above, the minmax criteria yields:
MaxMax
The MaxMax criteria on the other hand aims to maximise profit in the best-case scenario. It is therefore an aggressive,
and optimistic criteria. This criteria first finds the maximum value of the performance of each decision variables in every
scenario:
𝑜𝑖 = max(𝑢𝑖1 , 𝑢𝑖2 , ..., 𝑢𝑖𝑛 ) ∀𝑖 = [1, 2, ..., 𝑚]
These values represent the best case scenario in every decision alternative, then the MaxMax criteria selects the maximum
of these values:
𝑑 = (𝑚1 , 𝑚2 , ..., 𝑚𝑛 )
In the example above, the MaxMax criteria yields:
Bayesian
The Bayesian criteria takes into account additional information about the likelihood of each state of nature. It is therefore
the criteria applied by an informed decision maker which wants to factor in the decision the likelihood of each alternative.
The probabilities of each state or nature as defined as 𝑝(𝑠𝑗 ). The Expected Monetary Value (EMV) of each alternative is
defined as:
EMV𝑖 = 𝑖𝑗 * 𝑝(𝑠𝑗 )
∑︀
The EMV can be interpreted as the weighted average value of the alternative given the probabilities of occurrence of each
state of nature.
The Bayesian criteria selects the alternative with the maximum EMV:
𝑑 = argmax(𝑡𝑒𝑥𝑡𝐸𝑀 𝑉 1 , 𝑡𝑒𝑥𝑡𝐸𝑀 𝑉 2 , ..., 𝑡𝑒𝑥𝑡𝐸𝑀 𝑉 𝑚 )
Let us use again the example above to apply this decision criteria.
Introduction
Decision Trees are chronological representations of complex decision processes that can be used to find an optimal decision
based on a specific criteria, using a divide-and-conquer approach.
Decision trees have three main graphical components:
• Decision Nodes: Represent decisions under certainty. Each branch represents a decision alternative an and is
represented by a utility or cost as a measure of its performance.
• Random nodes: Represent possible outcomes under uncertainty. Each branch corresponds to a possible state and
is represented by a probability P
• Leafs: Possible outcomes of the decision process. They are represented by the performance, the utility or cost
value corresponding to the connected decision nodes and random nodes.
The image below shows these components and their relationships as a baseline example.
The example shows just a decision node, labeled as 1, with two different alternatives, noted as 𝑎1 and 𝑎2 . Each alternative
has a different utility value (𝑐𝑎1 for 𝑎1 and 𝑐𝑎2 for 𝑎2 ). There is some uncontrolled variable that can impact our decision,
and therefore, for each of the output branches of the decision node, there are two random nodes, labeled as 2 and 5, which
represent the uncontrolled variable. From each node, there are two different branches that represent the two possible states
of the decision variable. Each branch is labeled with the corresponding probability of the same state of nature, 𝑃 (𝑠1 )
and 𝑃 (𝑠2 ). Finally, the leave nodes, are labeled according to the utility values of each decision under each state of nature
(𝑢3 , 𝑢4 , 𝑢6 , 𝑢7 ). Note that the same information can be represented in a Pay-off matrix as:
However, the decision tree allows to represent more complex set-ups adding more nodes and uncontrolled variable, even
dealing with different combinations of uncontrolled variables and decision nodes at each branch. To define a decision
tree, it is necessary to apply the following steps
1. Structure the problem: define decision steps, states, objectives and their performance measures. In general, a
decision problem can have multiple objectives. Each objective has a performance measure to represent preferences
of the decision maker (e.g. An objective can be to minimize costs and the performance metric can be a monetary
unit like euros). If there are multiple objectives, it is necessary to take into account the trade-offs among different
objectives to obtain a single utility function to represent preferences. However, for the rest of the unit, we will
deal with single objective decision problems. Utility functions help us quantify the value of each decision. Each
alternative can have a positive impact or negative impact on the value.
2. Describe consequences: describe the probability of each possible state of nature. In situations of certainty, each
decision will have a positive or negative impact in the value of the decision. In situations of uncertainty or risk,
each possible state will have a different probability of occurrence. We need an estimation of these probabilities to
quantify the value of each decision.
3. Assign a value to each decision alternative: Define the utility of each decision. We need to estimate the utility
of each possible outcome of the decision problem.
4. Decide which of the proposed alternatives is preferred: To decide which of the proposed alternative is preferred,
it is necessary to solve the decision tree, as described in the next section.
Decision trees are solved from right to left, that is, from the leaves, back to the initial decision node. At every decision step,
it is necessary to quantify the value of each alternative, taking into account the probability of states of nature. Moreover,
the values of random nodes and decision nodes are calculated differently.
The value of a random node is calculated using a Bayesian approach, as the weighted expected value across the different
states:
∑︀𝑛
𝑉𝑟 = 𝑖=1 𝑃 (𝑠𝑖 ) * 𝑉𝑖
Where 𝑃 (𝑠𝑖 ) is the probability of state i and 𝑉𝑖 is the value at branch or leaf i.
The value of a decision node on the other hand is calculated as:
𝑉𝑛 = max{𝑉 𝑖 − 𝑐𝑎𝑘 , 𝑉 𝑗 − 𝑐𝑎𝑝 , ...}
That is, a rational decision would always select the alternative with the highest value across the different alternatives, taking
into account their costs.
With this two simple rules, the value of a tree can be calculated from its leaves, no matter how complex the set-up is and
regardless of the number of steps.
Imperfect Information
Sometimes we need to decide whether to incorporate into the decision imperfect information. Imperfect information
is information about uncontrolled variables that we can incorporate into the decision (possibly at a cost) to improve the
performance. For instance, coming back to the previous example, imagine that our decision problem is to decide a
financial product. To make a better decision, we may purchase a forecast report of the market trends for the following
year. The report forecasts a given market trend, but the state is not known with certainty. It is possible to evaluate the
usefulness of incorporating this information into the problem. Applying the Bayes Theorem, the probabilities of the
different states of random nodes now will be conditioned on the outcome of the imperfect information (in the example,
of the forecast report).
In these cases, it is necessary to review the different probabilities. After imperfect information, the probabilities of
occurrence of the different states become revised (posterior) probabilities. The revised probabilities are calculated by
applying the Bayes Theorem.
Let us assume that there are n different states and that, consequently, the imperfect information may provide additional
information about the occurrence of each of the states. The introduction of imperfect information can be modeled first
as a decision node that models the decision of whether to incorporate imperfect information or not, and then as a random
node in the branch of the imperfect information state i. For instance, let us consider a basic example with two alternatives
and two possible states.
Let us now introduce the acquisition of imperfect information about the states. First, the decision maker needs to decide
whether not to incorporate this information (make the decision without imperfect information) or to incorporate this
information (make the decision with additional information, possibly at a cost). The diagram below introduces this first
decision as an additional decision node. Then, since the result of the forecast is not controlled by the decision maker, its
two possible results - 𝑖1 when it forecasts 𝑠1 and 𝑖2 when it forecasts 𝑠2 - are modeled as a random node with two states.
Note that now the probability of state 𝑠𝑗 is conditioned to the event 𝑖𝑖 in every branch. We can apply the Bayes Theorem
to calculate the probability that event 𝑠𝑗 occurs given that the imperfect information forecasts 𝑖𝑖 :
((𝑗 )·(𝑖 𝑗 )) (( )·( ))
(𝑗 𝑖) = = ∑︀ 𝑗 𝑖 𝑗
(𝑖𝑖 ) 𝑘 (𝑘 )·(𝑖𝑖 𝑠𝑘 )
(2 )·(1 2 )
(2 1) = 𝑃 (𝑖1 )
(2 )·(2 2 )
(2 2) = 𝑃 (𝑖2 )
𝑃 (𝑠1 ) and 𝑃 (𝑠2 ) are the a priori probabilities, or the probabilities without further information. The conditional proba-
bilities: (1 1 ), (1 2 ) refer to the probability that information 𝑖1 occurs under states 𝑠1 and 𝑠2 , respectively. The same
applies to (2 1 ) and (2 2 ). This conditional probabilities can be estimated from a historical record of events.
For instance, connecting with our previous example, let us assume that 𝑠1 represents a market raise state and 𝑠2 a market
fall state, and 𝑎1 and 𝑎2 two financial products. We may purchase a financial report to guide our investment decision, at
a cost. The report has a previous record of predicting 95% of the times a market fall correctly, that is (1 1 ) = 0.95 and
consequently (1 2 ) = 0.05. The record also tells us that the forecast is right 90% of the time when the market falls,
therefore (2 2 ) = 0.9 and (2 1 ) = 0.1. With these values, we can calculate the revised probabilities and solve the tree
to determine whether to incorporate the report or not.
The previous section described how to calculate the value of a decision tree after incorporating additional information,
which may come at a cost. An obvious question that arises is, how much should the decision maker be willing to pay for
additional information? This quantity is known as the Value of Perfect Information. Perfect Information is an abstract
concept that represents information that would make the occurrence of a state of nature certain. For instance, a forecast
report which can tell us with total certainty which is going to be the trend of the market in the future. Obviously, this
type of forecast does not actually exist in reality, but we can model its effect in the decision tree and solve it to calculate
its final value. The Expected Value with Perfect Information (EVPI) is the expected final value of the tree given that
we had perfect information. It is also an abstract concept to assess the value of the decision-making problem with access
to perfect a priori information.
For instance in the example above, perfect information means that the forecast report is always right, and therefore we
can plug in (1 1 ) = 1 and (2 2 ) = 1 since we know that the information about the states of the report is always right,
and since it is always right, then also this means that (1 2 ) = 0 and (2 1 ) = 0. This simplifies the tree and the value of
the node with additional information becomes:
EVPI = 𝑃 (𝑠1 ) * max(𝑣1 , 𝑣3 ) + 𝑃 (𝑠2 ) * max(𝑣2 , 𝑣4 )
Since this is the maximum value of that node provided that we had perfect a priori information, we can compare the EMV
that we obtain solving the report to the EVPI to see how close we are to perfect information. This difference is known as
the **Value of Perfect Information (PVI)$:
VPI = 𝐸𝑉 𝑃 𝐼 − 𝐸𝑀 𝑉
Try me
Introduction
So far, we have seen how decision trees can be used as tools to support decision-making in complex decision problems.
However, decision trees provide the basis for a family of machine learning techniques. The idea behind these techniques is
to learn from training data a decision tree that can be used to solve a machine learning tasks. Normally, decision trees are
applied in classification problems (recall that these problems the objective is to classify input data into known categories
based on the features available in the training data).
The objective is to generate a decision tree which represents the decisions that the machine will take to classify a data
sample based on its features. For instance, Let’s generate some synthetic data representing sensor data from two sensors,
temperature and encoding speed, in two different operating states, normal operation and failure. The following script
generates some synthetic data that we can use to guide the example:
n_samples = 50000
centers = [(25, 25), (33, 32)]
X, y = make_blobs(n_samples=n_samples, centers=centers, shuffle=False, random_
˓→state=42)
[Link]()
y_unique = [Link](y)
colors = [ blue , red ]
classes = [ Normal operating state , Failure state ]
for this_y, color in zip(y_unique, colors):
this_X = X[y == this_y]
[Link](
this_X[:, 0],
this_X[:, 1],
c=color,
alpha=0.5,
edgecolor="k",
label=classes[this_y],
)
[Link](loc="best")
[Link]( rpms/1000 )
[Link]( Temperature in degrees )
[Link]("Sensor readings")
Text(0.5, 1.0, Sensor readings )
Analyzing the data, we can see that the machine is in normal operating state if the rpms are below 29000 rpms and the
temperature below 29 degrees Celsius. The decision tree below shows how these decisions perform the classification.
As you can see in the figure, we first check the temperature reading and compare it to a threshold value, and it will take one
decision branch or the other depending on whether the reading is greater or equal to the threshold. Then, in a subsequent
decision node, it will check the readings of the encoder and depending on the value, and the branch, determine if the
machine is in normal operating state or in failure state.
The script below represents the data and the resulting decision regions:
[ ]: [Link]()
[Link](
(continues on next page)
Now, the objective is to develop an algorithm that is able to learn this decision tree from training data, that is, use the
training data to decide which decision nodes are needed at each stage and what are the values of the thresholds that need
to be applied. The result is a decision tree that can be used to classify new data, with the following generic structure:
The following section describes the most common strategy used in decision trees algorithms to obtain these decision trees.
The most common strategy used to build decision trees from training data consists in applying a greedy approach to split
the dataset into subsets, step by step, choosing at every step the feature that best splits the data into two subsets, until each
subset contains only data samples from one class, or until the subsets are homogeneous or pure enough, or in other words,
the level of entropy of the data is low enough. Moreover, the strategy is to iteratively select one feature to split the data
until:
• All (or almost all) data samples in a leaf node belong to the same class (minimum impurity or minimum entropy).
• The tree has reached the maximum pre-defined number of splits (maximum depth).
• The tree has tried all features and found that none of them is useful to split the data anymore.
There are some concepts in the paragraph above that we need to unpack, mainly related to the concepts of data ho-
mogeneity and entropy.
Data Homogeneity
Data homogeneity is the condition that all data samples in a leaf node belong to the same class. The Gini impurity
measure is a measure of data homogeneity in a dataset 𝑆), expressed as:
∑︀𝑐
Gini(𝑆) = 1 − 𝑖=1 𝑝2𝑖
Where 𝐶 = 1, 2, ..., 𝑐 is the set of possible classes, and 𝑝𝑖 is the probability of class 𝑖, defined as the number of data
samples of class 𝑖 divided by the total number of data samples in the dataset. From the definition above, we can see that
the impurity is 0 if all the data samples in the dataset are of the same class.
Entropy
In information theory, the entropy is a measure of the level of uncertainty in a system. Formally, the entropy of a system
is the sum of the probability of each possible state of the system multiplied by the logarithm of the probability of each
possible state of the system:
∑︀𝑐
Entropy(𝑆) = 𝑖=1 𝑝𝑖 log2 𝑝𝑖
To understand this measure, consider tossing a coin. If the coin is fair, the probability of getting heads is equal to the
probability of getting tails, and the entropy of the system is 1, representing total disorder, or chaos, because the uncertainty
of the result of the toss is maximum. However, if the coin is completely biased, for instance, the probability of getting
heads is 1, then the entropy is 0, because the result is certain, and completely predictable.
We can see that the measure of entropy and the measure of impurity are equivalent, in the sense that we can use the
entropy to assess data homogeneity in a data subset.
Recursive partitioning
As mentioned above, the tree is built by partitioning the dataset into two subsets, selecting in each iteration the feature
and the threshold that maximizes data homogeneity (minimizes entropy or impurity). The partition is recursive because
it is applied to every node of the tree (that is, the first partition results into two subsets, and then the partition is applied
again to each subset, resulting in four subsets, and so forth).
At every iteration, the data at any node 𝑚 is partitioned into two datasets, and the data Homogeneity of the two datasets
is evaluated for every candidate split 𝜃, expressed as two decision variables, the feature 𝑗 and a threshold 𝑡𝑚 : 𝜃 = (𝑗, 𝑡𝑚 ).
Then, for instance, gradient descent methods can be used to find the optimal 𝜃 for the current node 𝑚 that minimizes the
data homogeneity.
Formally, let the data subset at node 𝑚 be 𝑆𝑚 , consisting of 𝑁𝑚 data samples, each containing a feature vector 𝑥 and a
label 𝑦. The candidate 𝜃 = (𝑗, 𝑡𝑚 ) partition the data into two subsets 𝑆𝑚
𝑙𝑒𝑓 𝑡
(𝜃) such that:
𝑙𝑒𝑓 𝑡
𝑆𝑚 (𝜃) = 𝑥 ∈ 𝑆𝑚 : 𝑥𝑗 ≤ 𝑡𝑚
And and 𝑆𝑚
𝑟𝑖𝑔ℎ𝑡
(𝜃) such that:
𝑟𝑖𝑔ℎ𝑡
𝑆𝑚 (𝜃) = 𝑥 ∈ 𝑆𝑚 : 𝑥𝑗 > 𝑡𝑚
Let us now define the loss function for the current node 𝑚:
𝑙𝑒𝑓 𝑡 𝑟𝑖𝑔ℎ𝑡
𝑁𝑚 𝑁𝑚
L(𝑆𝑚 , 𝜃) = 𝑁𝑚 H(𝑆𝑚 (𝜃))
𝑙𝑒𝑓 𝑡
+ 𝑁𝑚 H(𝑆𝑚
𝑟𝑖𝑔ℎ𝑡
(𝜃))
where 𝑁𝑚 𝑙𝑒𝑓 𝑡
and 𝑁𝑚
𝑟𝑖𝑔ℎ𝑡
are the number of data samples in the left and right subsets, respectively, and H(𝑆) is a measure
of the data entropy or impurity in the dataset 𝑆.
This way, the learning problem is reduced to a minimization of the loss function, which is equivalent to finding the 𝜃 that
minimizes the data Homogeneity.
Information gain
Another approach is to maximise the information gain, which is the difference between the data Homogeneity of the data
subset at node 𝑚 and the data homogeneity of the two resulting subsets.
𝑙𝑒𝑓 𝑡 𝑟𝑖𝑔ℎ𝑡
𝑁𝑚 𝑁𝑚
I(𝑆𝑚 ) = H(𝑆𝑚 ) − 𝑁𝑚 H(𝑆𝑚 )
𝑙𝑒𝑓 𝑡
− 𝑁𝑚 H(𝑆𝑚
𝑟𝑖𝑔ℎ𝑡
)
That is, the objective now is to find the 𝜃 that maximizes the difference between the data homogeneity before and after
the split.
Algorithms
There are different algorithms that use this approach to build decision trees, the most popular being Iterative Dichotomiser
3 (ID3), its successors C4.5 and C5.0., and finally the Classification and Regression Trees (CART) algorithm.
ID3 uses the greedy recursive partitioning algorithm finding for each node the feature and threshold that maximizes the
information gain, with the limitation that the features must be categorical or qualitative (that is, it can only take one of a
finite number of values). C4.5 and C5.0 on the other hand remove this restriction. CART is very similar to C4.5, but it
provides additional support to solve regression problems.
Pruning
All the algorithm above have a common drawback: They tend to overfitting the training data. To overcome this, they use
a pruning strategy that removes the nodes that do not improve the model performance. One common pruning strategy is
cost complexity pruning, where the nodes are removed (pruned) if they do not improve the model performance. Minimum
cost complexity pruning finds the best trade-off between the tree complexity (expressed as the number of terminal nodes)
and performance.
Try me
In this notebook we are going to train a decision tree to solve a classification problem in Python.
Problem definition
The goal is to train a model to get the category of a wine according to a set of physicochemical properties (e.g. alcohol
percentage, color intensity and hue, or flavonoids). Imagine that the categories have been assigned by our customers on a
given number of wines (e.g. they have determined which wines that are awesome, which wines are ok, or which ones are
only drinkable). Then, with such a model, given a new wine, we could predict its category based on the physicochemical
properties of the wine provided by a physicochemical test.
The objective is then to train a model to predict the category of the wine based on 13 different properties of wine.
Load data
We are going to use a dataset provided by SKlearn. The dataset contains 177 samples of physicochemical properties of
different types of wines, classified into three different classes, class 1, class 2, and class 3.
The dataset in SKLearn is loaded with the function load_wine. The object returned contains the following properties:
• data: A 2D Numpy array where each row is a different physicochemical test performed over a different wine (that
is, each row represents the properties of a wine) and each column contains the data of a specific property.
• target: A 1D Numpy (column vector) array where each row represents the category of the corresponding wine
• feature_names: The names of the columns in data
• target_names: The names of the wine categories
You can check the docs for further details.
Let’s load the data into a Pandas dataframe so that we can explore its properties:
od280/od315_of_diluted_wines proline
0 3.92 1065.0
1 3.40 1050.0
2 3.17 1185.0
3 3.45 1480.0
4 2.93 735.0
.. … …
173 1.74 740.0
174 1.56 750.0
175 1.56 835.0
176 1.62 840.0
177 1.60 560.0
Now, let us explore the data so that we understand the dataset better. First, we use the describe() method of the
pandas dataframe to show some statistics of each class:
[ ]: from [Link] import Markdown
target_classes = range(0, 3)
The statistical information is useful, but it is impossible or in most cases really hard to determine manually the rules to
separate the different classes in each of the 19 properties in the data set. Just to certify this, Let’s display some data using
Pyplot:
FIG_SIZE = (10, 7)
# Create figure
fig, axes = [Link](nrows=2, ncols=2, figsize=FIG_SIZE)
# Now, we define some styles and colors for the 3 target classes
target_classes = range(0, 3)
colors = ("blue", "red", "green")
markers = ("^", "s", "o")
In the plot, we see 4 different properties (proline, flavanoids, ash, malic acid) against the color intensity. We can see that
the data is not linearly separable in any of them, and this is only 4 out of 132 possible pairs of parameters, it is clear that is
unfeasible to come up with some simple rules to separate the datasets easily. But can we get the decision tree to separate
the data in the three classes automatically, using a decision tree? Let’s find out in the following section.
The first step is to divide the dataset into the training dataset and the validation dataset. With this step, we want to ensure
that we leave some portion of the dataset so that we can validate our model. In the code below, the size of the data left
out to validate the model is around 30% of the available data.
We use the function train_test_split to split the data between the training data set and the validation dataset.
(text_size=0.3).
• y_test: And these are the categories of the wines in the test dataset.
Here are the full details of the train_test_split function.
We are going to train our model, using the training data. We only need to create an instance of a DecisionTreeClas-
sifier class, and use the class method fit passing the trainining data:
Ok, once that we have trained our model, let us test its, accuracy. We are going to use some built-in functions provided
in SKLearn. The first one, accuracy_score computes the accuracy of a model, passing as parameters, the real
categories and the predicted categories. So Let’s predict the categories in the test data set and get teh accuracy score:
# Use the method predict to predict the category of the wines in the test dataset
y_predict = clf_model.predict(X_test)
# Calculate the accuracy with accurate_score, using the real categories in the test␣
˓→dataset
0.9629629629629629
SKLearn also allow us to display the confusion matrix given a set of real categories and a set of predicted categories, with
the function confusion_matrix (see docs here), and display the confusion matrix with ConfusionMatrixDis-
play (see docs here):
Finally, Let’s render the decision tree using Graphviz and the provided class method export_graph_viz. Read the
docs here.
graph
You are now ready to test the model! You only need to create an array with where the Physicochemical properties are
added in the right order:
The following code cell shows the class of a wine that has the physicochemical properties in the example:
[ ]: example = [[15.0, 1.7, 2.1, 15.0, 105, 2.3, 1.32, 0.5, 2.0, 3.9, 1.1, 3.0, 890]]
example_class = clf_model.predict(example)
print(example_class)
1. Now that you have trained the model, you can use the predict method to get the category of a new wine.
Use this method to get the category of the wonderful Casa Quemada (CQ) from Viña Elena´s winerie, given its
physicochemical properties:
Physicochemical properties CQ
alcohol 14.38
malic_acid 1.83
ash 2.36
alcalinity_of_ash 17.2
magnesium 104
total_phenols 2.42
flavanoids 1.39
nonflavanoid_phenols 0.42
proanthocyanins 1.97
color_intensity 3.84
hue 1.23
od280/od315_of_diluted_wines 2.87
proline 990
[ ]: # Enter the physicochemical properties of the wine you would like to test, in order␣
˓→and using commas to separate the values
cq = [[]]
cq_class = clf_model.predict(cq)
print(cq_class)
How good is the wine? Now look at the decision rules in the tree and solve the tree manually. Do you get the same result?
2. The confusion matrix shows the errors made by the model, whereas the accuracy is just a metric of the number of
errors. Imagine that you use the different categories to guide your marketing policies, and that you will invest more
money in the marketing of wines you expect will have better ratings (being class 2 the category of best rated wines)
more than in wines with lower expectations. Do you think that the confusion matrix provides valuable information
for analysis?
3. The accuracy is just one out of different metrics used to evaluate machine learning models. Another interesting
metric is called precision, and is also implemented in SKLearn. You can check the docs in this link. Based on your
response to the previous question, do you think that the precision is a relevant metric in this use case scenario?
4. Run the experiment again with different sizes of the test data (e.g. 20% and 40%). Recall the concepts of overfitting
and underfitting and note what happens with the accuracy. What are your conclusions?
5. Look now to the right hand of the decision tree. Looking to the left, it would be interesting to plot the proline
against the malic acid. Check the code cells used to render some properties against the color intensity to plot the
proline against the malic acid for a. all wines, b. only wines in classes 0 and 1 c. wines where the color intensity is
greater than 3.82 and flavanoids greater than 1.4.
6. SKLearn has other datasets you can use to step up your machine learning skills. Do you dare to train a model for
a different training dataset?
In this section you have a collection of decision tree problems sorted by difficulty:
• Easy problems: You can tackle these problems after the first lesson on decision trees.
• Normal problems: These problems require that you are familiar with concepts like decision trees and perfect
information value.
• Hard problems: This is the type of problems that definitively get you ready for the exam.
Problem Definition
You are the trainer of a basketball team playing an inter-university tournament over a weekend. You won the first game
of the tournament yesterday, and now you have to decide whether to play with the same starting 5 or make changes in
the team. You want to assess your decision considering the possibilities of winning (𝑝𝑤 ) or loosing(𝑝𝑙 ) the game and of
having any player injured (𝑝𝑖 ) or all healthy (𝑝ℎ ) after the game. Since it is a friendly tournament, your priority is that
none of your classmates ends up injured, so you establish the following priorities between the utility values of the possible
outcomes: v1 (victory – no injuries) > v2 (loose – no injuries) > v3 (win – any injured) > v4 (loose – any injured).
a. Draw a decision tree indicating the probabilities and utility values of the possible outcomes, considering that the
probability of winning or loosing and the probability of having any player injured or all healthy are independent and also
independent of your decision to make changes in the team.
b. How would the decision tree change if you consider that the probability of having any player injured is not independent
of your decision to make changes?.
Problem Definition
Ash Ketchum is a renowned Pokémon trainer. He thinks that his most beloved Pokémon, Pikachu, could have been
injured in the last battle of the Winners Trophy play-offs. Therefore, the question is:
should he use Pikachu in the next battle against Team Rocket?
The trainer thinks that there is a probability of 0.1 of victory. However, if Pikachu participates in the fight, his injury
could worsen. Ash thinks that there is a probability of 0.2 that Pikachu is actually injured from the last battle.
The utilities (in points) that the trainer employs are:
• if Pikachu fights, and Ash wins the battle, and Pikachu is not injured, +100;
• if Pikachu fights, and Ash wins the battle, and Pikachu is injured, +50;
• if Pikachu fights, and Ash loses the battle, and Pikachu is not injured, 0;
• if Pikachu fights, and Ash loses the battle, and Pikachu is injured, -50
• If Pikachu does not fight and Pikachu is injured, the utility is -10,
• If Pikachu does not fight and Pikachu is not injured, the utility is 0.
Ash wants to use decision theory to support his decision-making in the battle against Team Rocket.
a. Draw the decision tree for this problem considering that the probabilities of the result of the battle and the injury are
independent.
b. Determine which is the best decision for Ash.
c. Ash could acquire further information about the probabilities of the result of the battle. The additional information
determines the result of the battle (Win or lose), and based on previous results, it has a certain accuracy to successfully
predict the result of the battle. Draw again the decision tree to incorporate into the decision problem the acquisition of
this imperfect information about the result of the battle, indicating in the corresponding branches the revised probabilities
Problem Definition
Dinoco, a multinational firm in the automobile sector, is deciding on whether to build an assembly plant in Brazil or in
Mississipi (USA). The cost to build this plant in Brazil is 10 million euros and the cost of building the plant in Mississippi
is 20 million. However, if the firm builds the plant in Brazil and local demand drops over the following 5 years, the
project will be stopped and the firm will lose 10M€ (and it will still have to build a plant in Mississippi). A priori, Dinoco
believes that the probability of demand for cars dropping in Brazil over the following 5 years is 20%. For 1M€, Dinoco
can hire a market research firm to analyse demand for cars in Brazil, which will indicate whether demand for cars will
drop or not. The market research firm’s record indicates that his record shows that they are able to predict the occurrence
of a drop in demand with a 95% success rate, and 90% when the demand does not drop.
a. Draw the decision tree.
b. Solve the tree and find the best alternative for Dinoco.
c. Calculate the Imperfect Information Value and the Perfect Information Value associated to the market research (demand
in Brazil)
Problem Definition
Your company, Altered Silicon, manufactures solar energy panels, and it has received an urgent order for 40 panels from
a new German customer which is willing to pay 1,000€ per panel. Altered Silicon has committed its production capacity
to other orders, and the only alternative left to serve the new order is to subcontract the production involved.
Altered Silicon has located two possible suppliers: - Supplier A: based in Romania, placed an offer of 500€ per panel -
Supplier B: from Poland, which would sell each panel for 550€
The cost to transport one batch of 40 panels from either of the two suppliers to the German firm is 1,000€. Nonetheless,
the customer’s technical specifications are very demanding, so Altered Silicon estimates that Supplier A could supply one
correct batch with a probability of 70%, whereas Supplier B could do it with a probability of 80 %. If the batch were
incorrect, Altered Silicon could sell it to another customer at the price of 200€ per panel. Altered Silicon is considering
the possibility of asking for a test panel from each supplier to test it before placing an order. Altered Silicon’s testing
system guarantees that a faulty panel is always detected, while there is a 5% margin of error with correct panels. The
testing system is prepared to assess two test panels, and the overall cost (cost of the two panels + transport + cost of the
test) comes to 2,000€.
a Draw the corresponding decision tree and indicate with a letter per branch the associated probability or the associated
cost (depending on the case)
b Solve the decision tree
c Up to how much should SUN2 pay for the test?
Problem Definition
María and Alberto (names have been selected randomly, any resemblance with reality is pure coincidence) are two class-
mates that want to celebrate the end of the course with a game. They will go to their favourite bar and Alberto will
randomly select a bottle of wine from the wine list. María will do a blind testing of the wine, with no possibility to see
the wine selected by Alberto. If María guesses the type of wine (red or white) just by holding her glass, Alberto will
pay 20€. Otherwise, if she fails, María will pay Alberto 10€. She may also taste the wine for 5€ (that is, Alberto will
discount 5€ of the bet if she guesses the type of wine, or María will pay 5€ extra if she does not).
María thinks she can use decision theory to improve her chances of winning the bet. She knows that in the wine list of
their favourite bar, there are 15 bottles of red wine and 11 of white wine. She has also done some blind wine tasting
to prepare for the bet and found out that it is actually not that easy to guess the colour of the wine just by tasting it
blindfolded. She guessed correctly 3/4 of the times she tried a white wine and 2/4 of the times she tried a red wine.
a Draw the decision tree for María without taking into account that she may test the wine to get additional information.
b Modify the decision tree for María now taking into account that she may test the wine.
c What is the best alternative for María?
Problem Definition
Doctor Stephen Strange is the chief surgeon at the Metropolitan General Hospital in New York. Doctor Strange needs
to decide whether to perform surgery or not on a patient with a rare disease. If the patient dies, the hospital must pay a
3M€ compensation, and the cost of the surgery is estimated in 1.5M€. Based on available data, the medical department
estimates that the probability of the patient surviving without surgery is 20%, while the probability of the patient surviving
with surgery is 75%. Let us use operational research to determine if Doctor Strange should hold the knife:
a. Draw the decision tree to support doctor Strange with this decision problem
b. Solve the decision tree
c. Doctor Strange can use a procedure with a device known as the Eye of Agamoto to get additional information of the
result of the surgery, with a cost of 0.5M€. Draw the decision tree incorporating the use of the Eye of Agamoto in the
decision problem
In this section you have the solution to the decision theory exercises.
Problem Definition
You are the trainer of a basketball team playing an inter-university tournament over a weekend. You won the first game
of the tournament yesterday, and now you have to decide whether to play with the same starting 5 or make changes in
the team. You want to assess your decision considering the possibilities of winning (𝑝𝑤 ) or loosing(𝑝𝑙 ) the game and of
having any player injured (𝑝𝑖 ) or all healthy (𝑝ℎ ) after the game. Since it is a friendly tournament, your priority is that
none of your classmates ends up injured, so you establish the following priorities between the utility values of the possible
outcomes: v1 (victory – no injuries) > v2 (loose – no injuries) > v3 (win – any injured) > v4 (loose – any injured).
a. Draw a decision tree indicating the probabilities and utility values of the possible outcomes, considering that the
probability of winning or loosing and the probability of having any player injured or all healthy are independent and also
independent of your decision to make changes in the team.
The following decision tree represents the solution of the problem:
# Second branch
[Link]( 9 , shape= circle , style="filled", fillcolor= green )
din
b. How would the decision tree change if you consider that the probability of having any player injured is not independent
of your decision to make changes?
We need to take into account the conditional probabilities of: - p(i|s): Probability of having an injury given that we play
with the same (s) team. - p(h|s): Probability of not having any injury given that we play with the same team - p(i|c):
Probability of having an injury given that we make changes (c) - p(h|c): Probability of not having any injury given that
we play with a different starting team
With this posterior probabilities, we can redraw the decision tree as follows:
# Second branch
[Link]( 9 , shape= circle , style="filled", fillcolor= green )
din
Problem Definition
Ash Ketchum is a renowned Pokémon trainer. He thinks that his most beloved Pokémon, Pikachu, could have been
injured in the last battle of the Winners Trophy play-offs. Therefore, the question is:
should he use Pikachu in the next battle against Team Rocket?
The trainer thinks that there is a probability of 0.1 of victory. However, if Pikachu participates in the fight, his injury
could worsen. Ash thinks that there is a probability of 0.2 that Pikachu is actually injured from the last battle.
The utilities (in points) that the trainer employs are:
• if Pikachu fights, and Ash wins the battle, and Pikachu is not injured, +100;
• if Pikachu fights, and Ash wins the battle, and Pikachu is injured, +50;
• if Pikachu fights, and Ash loses the battle, and Pikachu is not injured, 0;
• if Pikachu fights, and Ash loses the battle, and Pikachu is injured, -50
• If Pikachu does not fight and Pikachu is injured, the utility is -10,
• If Pikachu does not fight and Pikachu is not injured, the utility is 0.
Ash wants to use decision theory to support his decision-making in the battle against Team Rocket.
a. Draw the decision tree for this problem considering that the probabilities of the result of the battle and the injury are
independent.
Ash has one decision to make, with two different alternatives:
• Pikachu fights: Pikachu fights in the next tournament
• Pikachu does not fight:
If Pikachu fights, the result of the game can be modeled as a random node with two possible outcomes:
• Win: Win the battle with probability P(W) = 0.1
• Lose: Lose the battle with a probability P(L) = 1 - P(W) = 0.9
Independent of the result of the battle, Pikachu might be injured from a previous battle. This can be modeled as a random
event:
• Pikachu injured: Pikachu is injured with probability P(I) = 0.2
• Pikachu is not injured: Pikachu is not injured with probability P(NI) = 0.8
This yields the following decision tree:
b. Determine which is the best decision for Ash. We need to determine the expected value of the intermediate random
nodes, applying the probabilities:
𝑉3 = 50·0.2 + 0.8·100 = 90
𝑉6 = −50·0.2 + 0.8·0 = −10
𝑉2 = 90·0.1 − 10·0.9 = 0
𝑉9 = −10·0.2 + 0.8·0 = −2
Finally, to solve the tree, the value of the decision node is calculated as the maximum value minus cost of the different
alternatives:
𝑉1 = max(𝑉2 , 𝑉9 ) = 0
and the decision is given by the argument of the maximum (argmax), which corresponds to alternative “Pikachu plays”.
c. Ash could acquire further information about the probabilities of the result of the battle. The additional information
determines the result of the battle (Win or lose), and based on previous results, it has a certain accuracy to successfully
predict the result of the battle. Draw again the decision tree to incorporate into the decision problem the acquisition of
this imperfect information about the result of the battle, indicating in the corresponding branches the revised probabilities
The addition information would make Ash review the probabilities of the result of the battle.
Now, we can model the acquisition of additional information as a decision node with two alternatives: - Do not acquire
additional information - Acquire additional information
The result of the additional information can be modeled as a random node with possible events:
• Predict a win: The additional information may predict a win with probability P(WP)
• Predict a Loss: The additional information may predict a loss, with probability P(LP)
Finally, it is required to modify the probabilities of the result of the game to take into account the additional information.
This yields the following decision tree
Problem Definition
Dinoco, a multinational firm in the automobile sector, is deciding on whether to build an assembly plant in Brazil or in
Mississipi (USA). The cost to build this plant in Brazil is 10 million euros and the cost of building the plant in Mississippi
is 20 million. However, if the firm builds the plant in Brazil and local demand drops over the following 5 years, the
project will be stopped and the firm will lose 10M€ (and it will still have to build a plant in Mississippi). A priori, Dinoco
believes that the probability of demand for cars dropping in Brazil over the following 5 years is 20%. For 1M€, Dinoco
can hire a market research firm to analyse demand for cars in Brazil, which will indicate whether demand for cars will
drop or not. The market research firm’s record indicates that his record shows that they are able to predict the occurrence
of a drop in demand with a 95% success rate, and 90% when the demand does not drop.
a. Draw the decision tree.
b. Solve the tree and find the best alternative for Dinoco.
c. Calculate the Imperfect Information Value and the Perfect Information Value associated to the market research (demand
in Brazil)
The following diagram shows the decision tree of the problem:
The image has been generated using Python, if you want to do it yourself, you can try the following code cell in a
Notebook!
[ ]: from graphviz import Digraph
# Create Digraph object
din = Digraph(format= png )
din.graph_attr[ rankdir ] = LR
# Second branch
(continues on next page)
# Third branch
[Link]( 13 , shape= square , style="filled", fillcolor= yellow )
din
Problem Definition
Your company, Altered Silicon, manufactures solar energy panels, and it has received an urgent order for 40 panels from
a new German customer which is willing to pay 1,000€ per panel. Altered Silicon has committed its production capacity
to other orders, and the only alternative left to serve the new order is to subcontract the production involved.
Altered Silicon has located two possible suppliers: - Supplier A: based in Romania, placed an offer of 500€ per panel -
Supplier B: from Poland, which would sell each panel for 550€
The cost to transport one batch of 40 panels from either of the two suppliers to the German firm is 1,000€. Nonetheless,
the customer’s technical specifications are very demanding, so Altered Silicon estimates that Supplier A could supply one
correct batch with a probability of 70%, whereas Supplier B could do it with a probability of 80 %. If the batch were
incorrect, Altered Silicon could sell it to another customer at the price of 200€ per panel. Altered Silicon is considering
the possibility of asking for a test panel from each supplier to test it before placing an order. Altered Silicon’s testing
system guarantees that a faulty panel is always detected, while there is a 5% margin of error with correct panels. The
testing system is prepared to assess two test panels, and the overall cost (cost of the two panels + transport + cost of the
test) comes to 2,000€.
a Draw the corresponding decision tree and indicate with a letter per branch the associated probability or the associated
cost (depending on the case)
The company needs to decide whether to conform the test panel or not. So the alternatives for the first decision node are:
• Not conform test panel: Cost 0
• Conform test panel: Cost CP= 2K€
The test panel will provide additional information on the possibility that the batches provided by each provider are bad.
The outcome of the test panel can be modeled as a random node with 4 possible outcomes:
• The test on the sample from supplier A is correct (PAC), with Probability P(PAC) and the test on the sample from
supplier B is correct (PBC), with probability P(PBC): P(PAC)*P(PBC)
• The test on the sample from supplier A is correct (PAC), with Probability P(PAC) and the test on the sample from
supplier B is incorrect (PBI), with probability P(PBI): P(PAC)*P(PBI)
• The test on the sample from supplier A is incorrect (PAI), with Probability P(PAI) and the test on the sample from
supplier B is correct (PBC), with probability P(PBC): P(PAI)*P(PBC)
• The test on the sample from supplier A is incorrect (PAI), with Probability P(PAI) and the test on the sample from
supplier B is incorrect (PBI), with probability P(PBI): P(PAI)*P(PBI)
In the probabilities above, we assumed that the results on the samples from different suppliers are independent events.
Let us assume that the 3 alternatives for the company are:
• Select supplier A (Supplier A): CA = -(0.5*40)-1=-21
• Select supplier B (Supplier B): CB = -(0.55*40)-1=-23
• Do not purchase from any supplier (No supplier): CN = 0
Now, if we select provider A, the batch may be correct or incorrect. This event can be modeled as a random node with
the following alternatives and corresponding initial probabilities:
• Batch is correct (AC), with probability P(AC)=0.7
• Batch is incorrect (AI), with probability P(AI) = 0.3
Similarly, for player B, the batch may also be correct or incorrect, with (a priori) probabilities:
• Batch is correct (BC), with probability P(BC)=0.8
• Batch is incorrect (BI), with probability P(BI) = 0.2
Now, the problem also gives some conditional probabilities on further information, related to the reliability of the test.
From historic results, the probability that a test gave an incorrect result given that the batch was correct is 0.05. Hence:
• P(PAC|AC) = 0.95
• P(PAI|AC) = 0.05
• P(PBC|BC) = 0.95
• P(PBI|BC) = 0.05
Likewise, in the past, the test has never given an incorrect result and therefore:
• P(PAC|AI) = 0
• P(PAI|AI) = 1
• P(PBC|BI) = 0
• P(PBI|BI) = 1
By applying the Bayes rule, the probabilities of occurrence of the test results are:
P(PAC) = P(PAC|AC)P(AC) + P(PAC|AI)P(AI) = 0.665 P(PAI) = 1-P(PAC) = 0.335 P(PBC) = P(PBC|BC)P(BC) +
P(PBC|BI)P(BI) = 0.76 P(PAI) = 1-P(PBC) = 0.24
Which yields:
P(PAC)P(PBC) = 0.5054 P(PAC)P(PBI) = 0.1596 P(PAI)P(PBC) = 0.254 P(PAI)P(PBI) = 0.0804
And applying Bayes yields
P(AC|PAC) = 1 P(AI|PAC) = 0 P(AC|PAI) = 0.1045 P(AI|PAI) = 0.8955
P(BC|PBC) = 1 P(BI|PBC) = 0 P(BC|PBI) = 0.1667 P(BI|PBI) = 0.8333
Finally, we have the following outcomes in the different leave nodes: - When the batch is correct GC=40K€ - When the
batch is incorrect GI=8K€ - No purchase = 0
b Solve the decision tree To solve, the decision tree, we need to calculate the expected value of random nodes, and select
the alternative that provides the maximum benefit (outcome minus cost) in decision nodes. The following figure shows
the solution of obtained in the decision tree:
Problem Definition
María and Alberto (names have been selected randomly, any resemblance with reality is pure coincidence) are two class-
mates that want to celebrate the end of the course with a game. They will go to their favourite bar and Alberto will
randomly select a bottle of wine from the wine list. María will do a blind testing of the wine, with no possibility to see
the wine selected by Alberto. If María guesses the type of wine (red or white) just by holding her glass, Alberto will
pay 20€. Otherwise, if she fails, María will pay Alberto 10€. She may also taste the wine for 5€ (that is, Alberto will
discount 5€ of the bet if she guesses the type of wine, or María will pay 5€ extra if she does not).
María thinks she can use decision theory to improve her chances of winning the bet. She knows that in the wine list of
their favourite bar, there are 15 bottles of red wine and 11 of white wine. She has also done some blind wine tasting
to prepare for the bet and found out that it is actually not that easy to guess the colour of the wine just by tasting it
blindfolded. She guessed correctly 3/4 of the times she tried a white wine and 2/4 of the times she tried a red wine.
a Draw the decision tree for María without taking into account that she may test the wine to get additional information.
In this option, we only consider the possibility that María guesses the type of wine just by holding the glass of wine. In
this scenario, there is only one decision node, with two alternatives, either white wine or red wine. For every alternative,
we can model the selection of Alberto as a random event, without any María’s control. Without further information, let
us consider that all wines have the same probability of being selected by Alberto. Under this assumption, each random
node has two possible states:
• White wine: Alberto selects a white wine with probability 𝑃 (𝑊 ) = 11/26
• Red wine: Alberto selects a red wine with probability 𝑃 (𝑅) = 15/26
Now, since María gets 20€ when she correctly guesses the type of wine and -10 otherwise, the decision tree is:
b Modify the decision tree for María now taking into account that she may test the wine. Now, to modify the decision
tree taking into account that she may test the wine, we need to introduce a new decision node to model the decision of
tasting the wine or not. Given that we have the record of attempts of María, we can assume that tasting the wine will
provide to María additional imperfect information about the type of wine, and model the result of the tasting through a
random node with two different alternatives:
• María tastes the wine, and she thinks it tastes like white wine: 𝑃 (𝑇 𝑊 )
• María tastes the wine, and she thinks it tastes like red wine: 𝑃 (𝑇 𝑊 )
Note that tasting the wine and choosing the wine are not the same think. María may test the wine and then trust her taste
or not, taking into account the reliability of previous tests, for which we have information.
With this, the decision tree becomes:
We can calculate the posterior probabilities from the record of tests conducted by María, applying Bayes. From her tests
we know that:
• Probability that María tasted a white wine given that the wine was actually white 𝑃 (𝑇 𝑊 |𝑊 ) : 3/4
• Probability that María tasted a white wine given that the wine was actually red 𝑃 (𝑇 𝑊 |𝑅) : 2/4
• Probability that María tasted a red wine given that the wine was actually red 𝑃 (𝑇 𝑅|𝑅) : 2/4
• Probability that María tasted a red wine given that the wine was actually white 𝑃 (𝑇 𝑅|𝑊 ) : 1/4
Now, using the law of total probability we can calculate the probabilities of tasting a white wine and a red wine:
Problem Definition
Doctor Stephen Strange is the chief surgeon at the Metropolitan General Hospital in New York. Doctor Strange needs
to decide whether to perform surgery or not on a patient with a rare disease. If the patient dies, the hospital must pay a
3M€ compensation, and the cost of the surgery is estimated in 1.5M€. Based on available data, the medical department
estimates that the probability of the patient surviving without surgery is 20%, while the probability of the patient surviving
with surgery is 75%. Let us use operational research to determine if Doctor Strange should hold the knife:
a. Draw the decision tree to support doctor Strange with this decision problem The following image represents the decision
tree for Doctor Strange:
The first node represents the decision of whether to perform surgery (at a cost of 1.M€) or not. In both branches, the
random nodes represent the event of the patient surviving the procedure. Note that the probabilities of surviving the
surgery are different in both branches, because they are conditioned on whether the operation is performed or not.
Also note that the value if the patient survives is 0 while the value if the patient passes away is -3M€ in both cases.
b. Solve the decision tree Let us solve the tree from right to left. If Strange performs the operation, the value of the
random node (in M€) is:
𝑉2 = 0.75 * 0 + 0.25 * −3 = −3/4
And, if he does not, the value of the random node is:
𝑉5 = 0.2 * 0 + 0.8 * −3 = −4 * 3/5
Now, the value of the decision node is going to be the maximum taking into account the cost:
𝑉1 = max(𝑉2 − 1.5, 𝑣5 ) = max(−3/4 − 3/2, −4 * 3/5) = max(−9/4, −12/5) = −9/4
So, the best alternative for Dr. Strange is to perform the operation.
c. Doctor Strange can use a procedure with a device known as the Eye of Agamoto to get additional information of the
result of the surgery, with a cost of 0.5M€. Draw the decision tree incorporating the use of the Eye of Agamoto in the
decision problem Now, the following diagram represents the decision with additional information provided by the Eye of
Agamoto:
If Dr. Strange decides not to use the Eye of Agamoto, the decision tree looks exactly the same as in the previous section,
because the decision process will be equivalent.
If Dr. Strange decides to use the Eye of Agamoto, we can model the result of the prediction provided by this tool as a
random node with two possible states:
• Survival predicted (sp): The eye of Agamoto will predict that the patient survives the operation with probability
𝑃 (𝑠𝑝)
• Death predicted (sp): The eye of Agamoto will predict that the patient does not survive the operation with proba-
bility 𝑃 (𝑠𝑝)
Since the Eye of Agamoto provides additional information about the result of the procedure, we need to plug in the revised
probabilities in the branches where Dr. Strange decides to perform the procedure, but the probabilities without surgery
remain the same.
In this section you have a collection of decision tree problems sorted by difficulty:
• Easy problems: You can tackle these problems after the first lesson on game theory.
• Normal problems: These problems require that you are familiar with concepts like game equilibrium.
• Hard problems: This is the type of problems that definitively get you ready for the exam.
Problem definition
There are two bars in the paradise beach resort, Awesome Sloth and Brave Flamingo. Each one of the two bars charges
its own price for a beer, either 2€, 4€, or 5€. The cost of obtaining and serving the beer can be neglected. It is expected
that 60% of the tourists are relaxed and casual and choose the bars randomly regardless of the price, while 40% are more
thoughtful and will go to the bar with the lowest price, and split evenly in case both bars offer the same price.
a) Consider a sample of 100 guests and represent the beer price decision-making as a game with two players where the
objective is to maximise revenues
b) Represent the beer price decision-making as a zero-sum game where the objective is to maximise the percentage of
revenues per beer sales in the resort
Problem definition
Two manufacturers, AdeFab1 and AdeFab2, compete for the sales of two different product lines which are equally prof-
itable. In both cases, AdeFab2’s sales volume triples that of AdeFab1. Due to some technological advances, both man-
ufacturers can make substantial improvements to the two products, but they are not sure as to which development and
commercialisation strategy they should adopt. If the improvements to the two products are done at the same time, neither
manufacturer can have them ready to sell under 12 months. One alternative is to carry out an ‘‘intensive programme’’ to
first develop one of the two products and to try to commercialise it before the competition does. If this were the case,
AdeFab2 can have one product ready to sell in 9 months, while AdeFab1 needs 10 months (due to previous commitments
in its production installations). Either manufacturer can have the second product ready after another 9-month period. For
either product line, if both manufacturers commercialised the improved models simultaneously, it is estimated that Ade-
Fab1 can increase the percentage of all the future sales of this product by 8 % of the total (from 25 % to 33 %). Likewise,
AdeFab1 can increase its total sales in 20, 30 and 40 % of the total if it commercialises the product 2, 6 and 8 months
before AdeFab2 does, respectively. Moreover, AdeFab1 can lose 4, 10, 12 and 14 % of the total if AdeFab2 manages to
commercialise it 1, 3, 7 and 10 month(s) before it, respectively. Formulate this problem as if it were a zero-sum game
with two players and then establish the strategy the manufacturers must adopt according to the MiniMax criterion.
Problem definition
In the 1970s, the OPEP countries adopted a price-linking strategy and oil prices went from €3/barrel to a level above
€30/barrel. Analysts foresaw that prices could rise to over €100/barrel by the end of the twentieth century. Unexpectedly
however, the cartel failed and prices went down again. Therefore, what are the conditions for these cartels to survive?
In other words, what determines the equilibrium between cooperation and competition? This problem is similar to the
prisoner’s dilemma.
To simplify matters, it is assumed that only two producers exist, Saudi Arabia and Iran, and that there are only three
possible production levels: 2, 4 and 6 million barrels/day. So, depending on the two players’ decisions, total world
production is 4, 6, 8, 10 and 12 million barrels/day. Accordingly, world prices are 35, 30, 25, 15 or only 10€/barrel. The
production costs of one barrel are considered to be €2 for Saudi Arabia and €4 for Iran.
a) The intention is to maximise the difference between the profit of a producer and that of its competitor. Consider and
solve the case as if it were a zero-sum game with two players.
b) If the idea is to seek OPEP’s prime objective by avoiding mutual competition and regulating oil production, sales and
prices, what is the best option for Saudi Arabia and for Iran if they cooperate with each other and try to simultaneously
obtain the best profit each?
Problem definition
BIOSENS and TECHSENS, two competing firms, are developing a new state-of-the-art biomedical sensor, whose total
sales will amount to 1,000 million dollars. Both must opt for using the most advanced ‘‘e1’’ or ‘‘e2’’ technology. Should
both firms decide on the same technology, BIOSENS would obtain 60% of sales, since they know how to sell their
products better than their competitor, which sells similar products. However, if both opt for different technologies, then
TECHSENS would obtain a 60 % market share because it exploits differentiation better.
a) Determine which strategy each firm should adopt
Problem Definition
An investor wishes to invest €12,000 over a 1-year period, although he/she must decide to invest in market shares and/or
gold. The profitability ratios estimated for each investment are based on the possible states of economy (see Table).
Consider a zero-sum Games Theory model with two players and answer the following:
a) How should the investor invest the €12,000 to carry out the optimal strategy?
b) What mean profitability value is obtained? What is the profit for the investor?
Problem definition
Two students of EDEM, Jaime and Lucas, are playing a game named Bluff, that goes as follows. Jaime writes a number
on a piece of paper. Without showing Lucas what he has written, he tells him what he wrote. Jaime might be lying or
telling the truth. Then Lucas must guess if Jaime is lying or telling the truth, or he can choose to pass and not to continue
playing. If Lucas discovers that Jaime lied, Jaime must pay Lucas €50. If Lucas wrongly accuses Jaime of lying, Lucas
pays him €25. If Jaime told the truth and Lucas guesses this, then Jaime pays Lucas €5. If Jaime lied and Lucas does not
guess that he lied, then Lucas pays Jaime €24. Should Lucas decide to pass, then neither player wins or loses anything.
a Consider this a 2-player’s zero-sum game in game theory and write down the tabular representation.
b How would you determine the game mean value and the mixed strategies of both players in this case?
c Using the method seen in class to calculate the mixed strategies, a solver provides the following solution for Lucas
(u1=0, u2=0, u3=0.02), where u1 is the decision variable associated to the alternative “Jaime lied”, u2 the decision
variable associated to the alternative “Jaime told the truth” and u3 the decision variable associated to “Pass”. Write down
the model and determine his optimal strategy.
Problem definition
You were out celebrating the end of the exams at EDEM and the next thing you know is you are trapped in an island
playing for your life to a game known as the Squid Game. There are two players in the Squid Game, the attacker and the
defender. The attacker must pass through the field, choosing one out of three possible paths, up, middle, and down. The
defender must guess which path the attacker has selected, and follow the same path to meet him in the middle of the field.
Both players have a limited endurance, measured in endurance points, and start with 10 endurance points. The winner is
the player that resists the longest time without loosing all endurance points.
The field is fraught with traps that cause injuries to the players. If the attacker crosses the ‘up’ or ‘down’ paths, the damage
caused to the attacker is assessed as -3 endurance points. If the attacker chooses the ‘middle’ path, the damage is assessed
as -1 endurance points. If the defender chooses the ‘up’ or ‘down’ paths,the damage is -1 endurance points. The damage
for the defender is -3 endurance points if he chooses the middle path.
Both players are blindfolded and choose the path they would like to follow at the same time. If the defender chooses the
same path as the attacker, the damage for the attacker is -5 endurance points. If on the other hand the defender chooses a
different path, the damage for the defender is -2 endurance points. The following image shows the Squid Game field and
the damage in storage points in each path.
Problem Definition
Suppose there are two political parties, The Avengers Party (a coalition of superheroes who have come together to fight
for the greater good. They believe in using their powers to protect the people and promote equality and justice) and the
BrotherHood party (This party represents a group of mutants who feel oppressed by society and seek to overthrow the
existing power structures). They are competing in an election. Each party has three possible strategies: they can focus
their campaign on young citizens (below 30), middle-aged citizens (30-50), or senior citizens (over 50). The parties use
national statistics to estimate the number of votes that can shift in each demographic group. Here are the estimated values
for each demographic group:
• Young voters: They represent 60% of the undecided voters.
• Middle-aged voters: They represent 25% of the undecided voters.
• Senior citizens: They represent 15% of the undecided voters.
From past elections, the Avengers party has collected the following estimation about undecided voters on each scenario:
• Young voters: If both parties focus on young voters, the Avengers party will get 40% of the young voters and the
Brotherhood party 60% of the young voters. If the Avengers party focuses on the young voters and the Brotherhood
party does not, the Avengers party will get 70% of the young voters. If the Brotherhood party focuses on the young
voters and the Avengers party does not, the Avengers party will get 10% of the young voters. If neither party
focuses on the young voters, the Avengers party will get 40% of the young voters.
• Middle-aged voters: If both parties focus on middle-aged voters, the Avengers party will get 60% of the
middle-aged voters and the Brotherhood party 40% of the middle-aged voters. If the Avengers party focuses
on the middle-aged voters and the Brotherhood party does not, the Avengers party will get 90% of the middle-aged
voters. If the Brotherhood party focuses on the middle-aged voters and the Avengers party does not, the Avengers
party will get 30% of the middle-aged voters. If neither party focuses on the middle-aged voters, the Avengers
party will get 60% of the middle-aged voters.
• Senior citizens: If both parties focus on senior citizens, the Avengers party will get 70% of the senior citizens
and the Brotherhood party 30% of the senior citizens. If the Avengers party focuses on the senior citizens and the
Brotherhood party does not, the Avengers party will get 90% of the senior citizens. If the Brotherhood party focuses
on the senior citizens and the Avengers party does not, the Avengers party will get 20% of the senior citizens. If
neither party focuses on the senior citizens, the Avengers party will get 70% of the senior citizens.
Let us use Game Theory to model the strategies of both political parties, following these steps:
1. Identify the alternatives for both players and draw a tabular representation of the game were Player A is the Avengers
Party
2. Complete the tabular representation of the game, estimating the total percentage of undecided voters that would
vote for each party
3. Calculate the strategy of each party using the MinMax criteria
Problem definition
There are two bars in the paradise beach resort, Awesome Sloth and Brave Flamingo. Each one of the two bars charges
its own price for a beer, either 2€, 4€, or 5€. The cost of obtaining and serving the beer can be neglected. It is expected
that 60% of the tourists are relaxed and casual and choose the bars randomly regardless of the price, while 40% are more
thoughtful and will go to the bar with the lowest price, and split evenly in case both bars offer the same price.
a) Consider a sample of 100 guests and represent the beer price decision-making as a game with two players where the
objective is to maximise revenues
The pay-off matrix in this case is:
BF AS 2€ 4€ 5€ min:
2€ 100/100 140/120 140/150 100
4€ 120/140 200/200 280/150 120
5€ 150/140 150/280 250/250 150
min: 100 120 150
AS/BF 2€ 4€ 5€
2€ 50/50 53.85/46.15 48.27/51.72
4€ 46.15/53.85 50/50 65.11/34.88
5€ 51.72/48.27 34.88/65.11 50/50
We need only to take into consideration the values of player 1 to represent it as a zero-sum game:
BF/AS 2€ 4€ 5€
2€ 50 53.85 48.27
4€ 46.15 50 65.11
5€ 51.72 34.88 50
Now, if we calculate the minimum of each column and the maximum of each row:
BF/AS 2€ 4€ 5€ min:
2€ 50 53.85 48.27 48.27
4€ 46.15 50 65.11 46.25
5€ 51.72 34.88 50 34.88
max: 51.72 53.85 65.11
With the MinMax criteria, the bar Awesome Sloth will select the maximum minimum loss, that is the maximum between
the minimum of each row and set a price of 2€. The bar Brave Flamingo will select the minimum maximum win, that
is, the minimum across the maximum values of each column, also setting a price of 2€.
[ ]:
Problem definition
Two manufacturers, AdeFab1 and AdeFab2, compete for the sales of two different product lines which are equally prof-
itable. In both cases, AdeFab2’s sales volume triples that of AdeFab1. Due to some technological advances, both man-
ufacturers can make substantial improvements to the two products, but they are not sure as to which development and
commercialisation strategy they should adopt. If the improvements to the two products are done at the same time, neither
manufacturer can have them ready to sell under 12 months. One alternative is to carry out an ‘‘intensive programme’’ to
first develop one of the two products and to try to commercialise it before the competition does. If this were the case,
AdeFab2 can have one product ready to sell in 9 months, while AdeFab1 needs 10 months (due to previous commitments
in its production installations). Either manufacturer can have the second product ready after another 9-month period. For
either product line, if both manufacturers commercialised the improved models simultaneously, it is estimated that Ade-
Fab1 can increase the percentage of all the future sales of this product by 8 % of the total (from 25 % to 33 %). Likewise,
AdeFab1 can increase its total sales in 20, 30 and 40 % of the total if it commercialises the product 2, 6 and 8 months
before AdeFab2 does, respectively. Moreover, AdeFab1 can lose 4, 10, 12 and 14 % of the total if AdeFab2 manages to
commercialise it 1, 3, 7 and 10 month(s) before it, respectively. Formulate this problem as if it were a zero-sum game
with two players and then establish the strategy the manufacturers must adopt according to the MiniMax criterion.
Solution
The table below contains the pay-off matrix for both companies, including the calculations needed to calculate the costs
and the MinMax criteria for each company.
Each cell contains the percentage of sales for adeFab1, adding the percentage of sales for both products. The percentage of
sales of each product depends on the difference in the time to market in each scenario. For instance, if both companies opt
for simultaneous improvement, the products reach the market at the same time, and the percentage of sales for adeFab1
is 33% for the first product and 33% for the first product, which yields a total percentage of 66%. However, if AdeFab1
opts for simultaneous improvement, and AdeFab2 chooses the intensive program for product 1, AdeFab1 will lose 10%
of the 25% market share of product 1, yielding 15%, whereas it will get a 30% extra for product 2, yielding 55%, and the
sum of both products yields 15% + 55% = 70%. We can compute in a similar way the market shares in each scenario.
In the 1970s, the OPEP countries adopted a price-linking strategy and oil prices went from €3/barrel to a level above
€30/barrel. Analysts foresaw that prices could rise to over €100/barrel by the end of the twentieth century. Unexpectedly
however, the cartel failed and prices went down again. Therefore, what are the conditions for these cartels to survive?
In other words, what determines the equilibrium between cooperation and competition? This problem is similar to the
prisoner’s dilemma.
To simplify matters, it is assumed that only two producers exist, Saudi Arabia and Iran, and that there are only three
possible production levels: 2, 4 and 6 million barrels/day. So, depending on the two players’ decisions, total world
production is 4, 6, 8, 10 and 12 million barrels/day. Accordingly, world prices are 35, 30, 25, 15 or only 10€/barrel. The
production costs of one barrel are considered to be €2 for Saudi Arabia and €4 for Iran.
a) The intention is to maximise the difference between the profit of a producer and that of its competitor. Consider and
solve the case as if it were a zero-sum game with two players.
b) If the idea is to seek OPEP’s prime objective by avoiding mutual competition and regulating oil production, sales and
prices, what is the best option for Saudi Arabia and for Iran if they cooperate with each other and try to simultaneously
obtain the best profit each?
Solution
a) Pay-off Matrix:
This is a Pure Strategy Game. Thus, even though the dominated strategies are eliminated and the MiniMax approach is
used, the production level of 6 million barrels/day will always be more profitable for Saudi Arabia. When both players
adopt a dominant strategy, which is a production of 6 million barrels/day in this case, the players gain 48 and 36 million
dollars, respectively.
b) OPEP’s Pay-off Matrix:
The best option is that which offers the best profit to them both at the same time; that is, production of 4 million barrels/day,
which implies profits of 92 and 84 million dollars for Saudi Arabia and Iran, respectively.
Problem definition
BIOSENS and TECHSENS, two competing firms, are developing a new state-of-the-art biomedical sensor, whose total
sales will amount to 1,000 million dollars. Both must opt for using the most advanced ‘‘e1’’ or ‘‘e2’’ technology. Should
both firms decide on the same technology, BIOSENS would obtain 60% of sales, since they know how to sell their
products better than their competitor, which sells similar products. However, if both opt for different technologies, then
TECHSENS would obtain a 60 % market share because it exploits differentiation better.
a) Determine which strategy each firm should adopt
Pay-off Matrix:
Techsens Biosens e1 e2
e1 60 40 p
e2 40 60 1-p
q 1-q
Problem definition
An investor wishes to invest €12,000 over a 1-year period, although he/she must decide to invest in market shares and/or
gold. The profitability ratios estimated for each investment are based on the possible states of economy (see Table).
Consider a zero-sum Games Theory model with two players and answer the following:
a) How should the investor invest the €12,000 to carry out the optimal strategy? The interpretation of this Games Theory
problem is that the investor is playing against the states of nature (the states of economy). Since there is no data available
regarding the probabilities of the states of nature, the optimal strategy may be based on a mixed strategy considering the
market as the other player. Let us add a constant k = 1 to make all the profitability ratios positive. Adding this constant
value to the table yields:
The optimal strategy for the investor is obtained through the following continuous linear programming problem:
𝑚𝑖𝑛𝑧 = 𝑥1 + 𝑥2
s.t.
6 * 𝑥1 + 3 * 𝑥2 ≥ 1
5 * 𝑥1 + 4 * 𝑥2 ≥ 1
4 * 𝑥1 + 5 * 𝑥2 ≥ 1
0 * 𝑥1 + 6 * 𝑥2 ≥ 1
where:
𝑥1
𝑝1 = (𝑥1 +𝑥2 )
Is the probability that the investor will invest in market shares if he/she chooses the optimal strategy, and:
𝑥2
𝑝2 = (𝑥1 +𝑥2 )
Is the probability that the investor will invest in gold if he/she chooses the optimal strategy.
Therefore, given 12K€ to invest, the investor should invest 12K€p_1 in marketing and 12K€p_2 in gold.
We would need a solver to find the actual values. The values provided by a solver are p_1 = 0.33 and p_2 = 0.67, therefore
the investor should invest 12K€0.33 = 4K€ in marketing and 12K€0.67 = 8K€ in gold.
b) What mean profitability value is obtained? Recall that the objective function is inversely proportional to the lower
bound of the profitability ratio, and that we added a constant k = 1 to make all the profitability ratios positive, so:
𝑝1 +𝑝2 1
𝑧 = 𝑥1 + 𝑥2 = 𝑣 = 𝑣
With this expression we can obtain the mean profitability value, recalling that we need to subtract k, since we added the
constant to make all the profitability ratios positive.
Problem definition
Two students of EDEM, Jaime and Lucas, are playing a game named Bluff, that goes as follows. Jaime writes a number
on a piece of paper. Without showing Lucas what he has written, he tells him what he wrote. Jaime might be lying or
telling the truth. Then Lucas must guess if Jaime is lying or telling the truth, or he can choose to pass and not to continue
playing. If Lucas discovers that Jaime lied, Jaime must pay Lucas €50. If Lucas wrongly accuses Jaime of lying, Lucas
pays him €25. If Jaime told the truth and Lucas guesses this, then Jaime pays Lucas €5. If Jaime lied and Lucas does not
guess that he lied, then Lucas pays Jaime €24. Should Lucas decide to pass, then neither player wins or loses anything.
a Consider this a 2-player’s zero-sum game in game theory and write down the tabular representation. Let us note Jaime
as player A and Lucas as player B. The game can be represented through the following matrix:
b How would you determine the game mean value and the mixed strategies of both players in this case?
Since this is a 2x3 game, let us formulate a Continuous Linear Programming problem to find the mixed strategies and the
game mean value with these strategies.
c Using the method seen in class to calculate the mixed strategies, a solver provides the following solution for Lucas
(u1=0, u2=0, u3=0.02), where u1 is the decision variable associated to the alternative “Jaime lied”, u2 the decision
variable associated to the alternative “Jaime told the truth” and u3 the decision variable associated to “Pass”. Write down
the model and determine his optimal strategy. First, let us add a constant K to the game such that game values are
non-negative:
K = -50 yields
The value of the objective value can also be computed from the decision variables of the dual as:
1
𝑧= 𝑢1 +𝑢2 +𝑢3 − 50
Now, plugin-in the values provided by the solver, we see that the optimal strategy for lucas is always to pass:
𝑢1 0
𝑞1 = 𝑢1 +𝑢2 +𝑢3 = 0+0+0.02 =0
𝑢2 0
𝑞2 = 𝑢1 +𝑢2 +𝑢3 = 0+0+0.02 =0
𝑢3 0.02
𝑞3 = 𝑢1 +𝑢2 +𝑢3 = 0+0+0.02 =1
Also, the game value obtained is 0:
𝑧 = 1/0.02 − 50 = 0
Problem definition
YYou were out celebrating the end of the exams at EDEM and the next thing you know is you are trapped in an island
playing for your life to a game known as the Squid Game. There are two players in the Squid Game, the attacker and the
defender. The attacker must pass through the field, choosing one out of three possible paths, up, middle, and down. The
defender must guess which path the attacker has selected, and follow the same path to meet him in the middle of the field.
Both players have a limited endurance, measured in endurance points, and start with 10 endurance points. The winner is
the player that resists the longest time without loosing all endurance points.
The field is fraught with traps that cause injuries to the players. If the attacker crosses the ‘up’ or ‘down’ paths, the damage
caused to the attacker is assessed as -3 endurance points. If the attacker chooses the ‘middle’ path, the damage is assessed
as -1 endurance points. If the defender chooses the ‘up’ or ‘down’ paths,the damage is -1 endurance points. The damage
for the defender is -3 endurance points if he chooses the middle path.
Both players are blindfolded and choose the path they would like to follow at the same time. If the defender chooses the
same path as the attacker, the damage for the attacker is -5 endurance points. If on the other hand the defender chooses a
different path, the damage for the defender is -2 endurance points. The following image shows the Squid Game field and
the damage in storage points in each path.
a) Write down the tabular representation of the game. Let us note the Attacker as Player A and the defender as Player B.
The tabular representation, noting the first value of the tuple is the gain for player A and the second value after the slash
is the value for player B is:
In short:
b) Find the move each player would choose following the minmax criteria. Discuss briefly if there is equilibrium. Applying
the min max criteria, we add a new column to note the worst case scenario for each alternative of player A, and a new
row to note the worst case alternative for each alternative of player B.
Player A would select the Middle as it provides the maximum value across the three worst case scenarios (-6). Player B
would select either up or down since they both provide the minimum value (-3). The problem does not have equilibrium,
since player B will probably would like to change strategy after few moves.
c) Now think of the game as a zero-sum game where the gain in each move is the difference in damage points between the
attacker and the defender for each combination of pairs of paths selected. Write down the linear programming problems
to calculate the optimal probabilities of the mixed strategies for both players.
Let us add a constant (𝑘 = 2) to create an equivalent problem where all the values are positive:
Now, the following CLP problem is used to calculate the probabilities of player A:
max 𝑧 = 𝑥1 + 𝑥2 + 𝑥3
9 * 𝑥1 + 0 * 𝑥2 + 2 * 𝑥3 ≤ 1
0 * 𝑥1 + 5 * 𝑥2 + 0 * 𝑥3 ≤ 1
2 * 𝑥1 + 0 * 𝑥2 + 9 * 𝑥3 ≤ 1
The strategy for Player B is obtained with the dual problem:
min 𝑧 = 𝑢1 + 𝑢2 + 𝑢3
9 * 𝑢1 + 0 * 𝑢2 + 2 * 𝑢2 ≥ 1
0 * 𝑢1 + 5 * 𝑢2 + 0 * 𝑢3 ≥ 1
2 * 𝑢1 + 0 * 𝑢2 + 9 * 𝑢3 ≥ 1
Problem Definition
Suppose there are two political parties, The Avengers Party (a coalition of superheroes who have come together to fight
for the greater good. They believe in using their powers to protect the people and promote equality and justice) and the
BrotherHood party (This party represents a group of mutants who feel oppressed by society and seek to overthrow the
existing power structures). They are competing in an election. Each party has three possible strategies: they can focus
their campaign on young citizens (below 30), middle-aged citizens (30-50), or senior citizens (over 50). The parties use
national statistics to estimate the number of votes that can shift in each demographic group. Here are the estimated values
for each demographic group:
• Young voters: They represent 60% of the undecided voters.
• Middle-aged voters: They represent 25% of the undecided voters.
• Senior citizens: They represent 15% of the undecided voters.
From past elections, the Avengers party has collected the following estimation about undecided voters on each scenario:
• Young voters: If both parties focus on young voters, the Avengers party will get 40% of the young voters and the
Brotherhood party 60% of the young voters. If the Avengers party focuses on the young voters and the Brotherhood
party does not, the Avengers party will get 70% of the young voters. If the Brotherhood party focuses on the young
voters and the Avengers party does not, the Avengers party will get 10% of the young voters. If neither party
focuses on the young voters, the Avengers party will get 40% of the young voters.
• Middle-aged voters: If both parties focus on middle-aged voters, the Avengers party will get 60% of the
middle-aged voters and the Brotherhood party 40% of the middle-aged voters. If the Avengers party focuses
on the middle-aged voters and the Brotherhood party does not, the Avengers party will get 90% of the middle-aged
voters. If the Brotherhood party focuses on the middle-aged voters and the Avengers party does not, the Avengers
party will get 30% of the middle-aged voters. If neither party focuses on the middle-aged voters, the Avengers
party will get 60% of the middle-aged voters.
• Senior citizens: If both parties focus on senior citizens, the Avengers party will get 70% of the senior citizens
and the Brotherhood party 30% of the senior citizens. If the Avengers party focuses on the senior citizens and the
Brotherhood party does not, the Avengers party will get 90% of the senior citizens. If the Brotherhood party focuses
on the senior citizens and the Avengers party does not, the Avengers party will get 20% of the senior citizens. If
neither party focuses on the senior citizens, the Avengers party will get 70% of the senior citizens.
Let us use Game Theory to model the strategies of both political parties, following these steps:
1. Identify the alternatives for both players and draw a tabular representation of the game were Player A is the Avengers
Party
Note that each political party can choose only one out of three possible strategies: Focusing on young, middle-aged, or
senior citizens. Therefore, the Avengers Party has three alternatives, noted as:
• Young: Focus on young citizens
• Middle-aged: Focus on middle-aged citizens
• Senior: Focus on senior citizens
The Brotherhood Party also has three possible strategies:
• Young: Focus on young citizens
• Middle-age: Focus on middle-aged citizens
• Senior: Focus on senior citizens.
For the sake of simplicity, The Avengers Party will be Player A and the Brotherhood Party will be Player B.
1. Complete the tabular representation of the game, estimating the total percentage of undecided voters that would
vote for each party
Now, since each player has three different strategies, this is 3x3 game, and therefore we have a total of 9 possible scenarios.
In each possible scenario, we need to assess the total percentage of undecided voters that would vote for each party. For
example, if both parties focus on young voters, the Avengers Party will get 40% of the young voters and the Brotherhood
party 60% of the young voters. Therefore, the Avengers Party will get 40% of 60% of the undecided voters in this
segment, which is 24% of the total undecided voters. Similarly, the Brotherhood Party will get 60% of 60% = 36% of
the total undecided voters. Additionally, since we know that both parties are focused on young voters, neither will focus
on middle-age voters. Therefore, the Avengers Party will get 60% of 25% = 15% of the total undecided voters in this
segment, and the Brotherhood Party will get 40% of 25% = 10% of the total undecided voters in this segment. Similarly,
the Avengers Party will get 70% of 15% = 10.5% of the total undecided voters in the senior segment, and the Brotherhood
Party will get 30% of 15% = 4,5% of the total undecided voters in the senior segment:
• Player A: Young, Player B: Young
– Player A: 0.60.4 + 0.60.25 + 0.7*0.15 = 0.24 +0.15 + 0.105 = 0.495 = 49.5%
– Player B: 0.60.6 + 0.60.25 + 0.3*0.15 = 0.36 + 0.15 + 0.045 = 0.555 = 55.5%
Note that the sum of the percentages for each player is 100%, since we are considering all the undecided voters, and
therefore we can also represent the game as a zero-sum game and do only have of the required calculations.
If we repeat this process for each of the 9 possible scenarios, we will get the following table:
• • Player B (Brother- • •
hood Party)
SIX
6.1 Tutorials
6.1.1 Simulation
Introduction
Simulation is a decision support tool that provides deep insights of the behaviour of a system, by representing it through
a mathematical model and using a computer to run the model and obtain a virtual representation of the system. Thus, the
main concepts are:
• Simulation Model: Set of mathematical rules (e.g. differential equations, state machines) that defines the be-
haviour of the system. Normally, the simulation model is formulated such that future system states are obtained
from the current state, to model the system behaviour over time.
• Simulation: We refer to the execution of the simulation model as simulation, that is, simulation consists of taking
the model through state changes over time to obtain a (virtual) representation of its behaviour
Simulation is used when there is no mathematical or analytical solution to a problem, or when the available methods are
just too complex. From a practical point of view, simulation is also used when we want to experiment with the system
behaviour before it is build, to get a better understanding of it, or just to visualize, demonstrate, or experiment with its
behaviour. In some applications, it is not possible to perform such experiments with the real system, due to economic
reasons (it is too expensive), security (it is too dangerous) or ethical reasons. Computers can run simulation models through
state changes at much higher rates than the actual system behaviour. For instance, a computer may run a simulation of a
model of the evolution of the earth climate through thousand of years in a matter of hours. Thus, simulation can also be
used to save time. Finally, by running simulations before the real system we may also gain control over system conditions.
System Dynamics
System dynamic models use differential equations to model the system behaviour of the model. System Dynamics models
are also known as Continuous Simulation models or Differential-Algebraic Equations (DAE) models. One of the main
characteristics of these models is that the lack of individuality of the inner components of the system. A set of differential
equations model the system behaviour as a hole, where its individual elements are not represented individually, but instead,
they are grouped into entities like Queues or Stocks. The model just defines the casual relationships and flows between
the stocks.
For instance, a system dynamics model can be used to model the adoption of a product. In this example, all potential cus-
tomers are modeled as a stock variable that depends on time 𝑝𝑠 (𝑡). The simulation is initialised with an initial population
of potential customers of 𝑝𝑠 (0). The actual customers on the other hand are modeled as another stock variable 𝑐𝑠 (𝑡). Let
us assume that there are no customers at the beginning of the simulation and that therefore 𝑐𝑠 (0) = 0. The adoption rate
379
Notebooks for Operations Research, Release I
𝑎 represents the flow of customers between these two stocks, that is 𝛿𝑐𝛿𝑡
𝑠 (𝑡)
= 𝑎 and 𝛿𝑐𝑠 (𝑡)
𝛿𝑡 = −𝑎. Thus, we can obtain
the number of potential customers or customers at any given time t as:
𝑐𝑠 (𝑡) = 𝑐𝑠 (0) + 𝑎 * 𝑡 = 𝑎 * 𝑡
𝑝𝑠 (𝑡) = 𝑝𝑠 (0) − 𝑎 * 𝑡
Note that in this model, individual customers are not represented.
Discrete Events
In discrete events’ simulation, the system is modeled as a flow chart that represents the system as a sequence of steps.
Therefore, the blocks in the flow chart represent different steps in the overall system. The flowchart blocks are modeled
as stochastic processes that drive the simulation model execution. These stochastic processes are computed at discrete
instant time events to represent the system state through the flow chart.
Agent based
Agent based models are decentralised models, where each agent has individual behavioural rules that define how they
interact with each other. This is a bottom-up approach where the system model is build from individual models of its
inner components.
Montecarlo Simulation
Montecarlo Simulation is probably the first simulation technique, and it basically consists on the computation of a math-
ematical model of the system which depends on random variables. The model is computed for a number of iterations
(simulations) and the output is computed as the average. By the central limit theorem, this average will converge to a
normal distribution, and therefore, it is possible to establish some confidence intervals to bound the simulation result.
Thus, the steps in a Montecarlo simulation are:
• Define the output expression: Define a mathematical model of the variable(s) that we want to simulate, the model
implements random variables.
• Generate random values: Generate values for the random input variables of the model. The generated values
must be defined in a valid input domain using a probability distribution (e.g. normal or uniform distribution)
• Compute output: Compute the value of the output expression for the random input values using the output
expression. The output expression is computed a given number of iterations and the results are collected to get
some statistics. The output of the simulation is the average value of the different iterations.
• Check confidence interval of solution: Finally, we check the confidence intervals for a given confidence level
and if the confidence interval is not satisfactory, the number of simulations should be increased.
Introduction
Markov chains are stochastic processes in which the state of the system alters between a given set of possible states (i.e.
a state machine), according to a set of transition probabilities between states. This concept is illustrated in the following
image:
Note that the transition probabilities do not depend on previous states. This memorylessness characteristic is known as a
Markov property and is the most outstanding characteristic of Markov Chains.
Markov chains allow to analyse the performance of a system and compare various alternatives to support decision making.
Set up
In this section you have an example of a simulation solved with the Montecarlo method:
Try me
Problem Definition
A company with 5 sales managers wants to provision budget to pay sales commissions to sales managers. The company
applies a commission rate based on the percentage of target sales obtained, given by the following table:
Each salesman will be compensanted with the commission rate times the total sales obtained. The following table shows
the target sales for the five sales managers:
a) Estimate the budget for sales commissions the company has to pay in the scenario where all sales managers get exactly
the 100% of the sales target (naive approach).
b) The company has a historic record of sales for the five sales managers and from this record, it can estimate that the
Percent to Plan (The ratio between the actual sales and the sales target) can be modelled by a normal distribution with
a mean of 100% and standard deviation of 10%. Use this insight to estimate the budget for sales commissions using a
MonteCarlo distribution.
Try me
The following metrics and indicators determine the expenditures and return of investments of marketing investments in
paid inclusion (including your company’s web page in search results) for your company:
• S (Total Search results in period): Total number of times the keywords are used in searches in the planning
period.
• CPM (Cost per 1000 impressions): Cost of the search engine per every 1000 impressions, every time your
website appears in a search result
• CPC (Cost per click): Cost per every click
• CTR (Click Through Rate): rate between the number of clicks and number of impressions
• CVR (Conversion Rate): rate between the number of visitors and the number of users
With this, the number of visitors (V) and the number of users (U) can be calculated as:
𝑈 = 𝑉 * 𝐶𝑉 𝑅 = 𝑆 * 𝐶𝑇 𝑅 * 𝐶𝑉 𝑅
The total costs (𝐶𝑡 ) of the search engine investmets are:
𝐶𝑡 = 𝐶𝑃 𝐶 * 𝑉 + 𝐶𝑃 𝑀 /1000 * 𝑆
The ARPU (Average revenue per user in planning period) is the average revenue per user, or the total revenue in the
planning period (R), divided by the number of users:
𝐴𝑅𝑃 𝑈 = 𝑅/𝑈
The Return of Investments for online marketing is calculated as:
𝑅−𝐶𝑡
𝑅𝑂𝐼 = 𝐶𝑡
After some research, you have found that the different metrics can be modeled as normal distributions with the following
parameters:
These are the search engine fees for your keywords: - CPM = 0,3€ - CPC = 0,75€
You estimate your ARPU in 5€
a. Calculate the total costs, the total Return of Investments and the average cost per acquisition using Montecarlo Sim-
ulation
b. Calculate the 95% confidence interval of the ROI
Try me
Problem Definition
A company with 5 sales managers wants to provision budget to pay sales commissions to sales managers. The company
applies a commission rate based on the percentage of target sales obtained, given by the following table:
Each salesman will be compensated with the commission rate times the total sales obtained. The following table shows
the target sales for the five sales managers:
a) Estimate the budget for sales commissions the company has to pay in the scenario where all sales managers get exactly
the 100% of the sales target (naive approach).
b) The company has a historical record of sales for the five sales managers and from this record, it can estimate that the
Percent to Plan (The ratio between the actual sales and the sales target) can be modelled by a normal distribution with
a mean of 100% and standard deviation of 10%. Use this insight to estimate the budget for sales commissions using a
MonteCarlo distribution.
Solution
a) In the requested scenario, the sales obtained by each sales manager are represented in the table below:
Sales Man- Sales Target Actual Sales Percent to Plan Commission Commission
ager (€) (€) (%) Rate (€) Amount (€)
1 100,000 100,000 100 4 4,000
2 200,000 200,000 100 4 8,000
3 75,000 75,000 100 4 3,000
4 400,000 400,000 100 4 16,000
5 500,000 500,000 100 4 20,000
The total budget for sales commission can be obtained with the summation of the last column (51,000€)
b) In order to estimate the budget using Montecarlo, we are going to use the Python numpy package to calculate the
probability distribution.
First we import the libraries we are going to use:
[45]:
import pandas as pd
import numpy as np
[46]:
avg = 1
std_dev = .1
num_simulations = 1000
# Define a function to calculate the commission rate depending on the rate to target
def calc_com_rate(x):
if x <= 0.9:
return 0.02
elif x <= 1:
return 0.03
else:
return 0.04
# Define a list to keep all the results from each simulation that we want to analyze
all_stats = [Link]((num_simulations, 3))
# Choose random inputs for the sales targets and percent to target
pct_to_target = [Link](avg, std_dev, len(sales_target_values))
# We want to track sales,commission amounts and sales targets over all the␣
˓→simulations
# Sum values among sales managers and calculate the mean commission rate
all_stats[i,:] = [[Link](sales),
[Link](commission),
[Link](commission_rate)]
The rowNum attribute was deprecated in Matplotlib 3.2 and will be removed two minor␣
˓→releases later. Use ax.get_subplotspec().[Link] instead.
The colNum attribute was deprecated in Matplotlib 3.2 and will be removed two minor␣
˓→releases later. Use ax.get_subplotspec().[Link] instead.
The rowNum attribute was deprecated in Matplotlib 3.2 and will be removed two minor␣
˓→releases later. Use ax.get_subplotspec().[Link] instead.
The colNum attribute was deprecated in Matplotlib 3.2 and will be removed two minor␣
˓→releases later. Use ax.get_subplotspec().[Link] instead.
avg = 1
std_dev = .1
num_reps = 500
num_simulations = 1000
# Choose random inputs for the sales targets and percent to target,
# this time create a matrix with as many rows as simulations
pct_to_target = [Link](avg, std_dev, (num_simulations, len(sales_target_
˓→values)))
# And commission
commission = sales*commission_rate
# Sum values among sales managers and calculate the mean commission rate
all_stats = [[Link](sales, axis=1), [Link](commission, axis=1), [Link](commission_
˓→rate, axis=1)]
results_df.describe()
Try me
The following metrics and indicators determine the expenditures and return of investments of marketing investments in
paid inclusion (including your company’s web page in search results) for your company:
• S (Total Search results in period): Total number of times the keywords are used in searches in the planning
period.
• CPM (Cost per 1000 impressions): Cost of the search engine per every 1000 impressions, every time your
website appears in a search result
• CPC (Cost per click): Cost per every click
• CTR (Click-Through Rate): rate between the number of clicks and number of impressions
• CVR (Conversion Rate): rate between the number of visitors and the number of users
With this, the number of visitors (V) and the number of users (U) can be calculated as:
𝑈 = 𝑉 * 𝐶𝑉 𝑅 = 𝑆 * 𝐶𝑇 𝑅 * 𝐶𝑉 𝑅
The total costs (𝐶𝑡 ) of the search engine investments are:
𝐶𝑡 = 𝐶𝑃 𝐶 * 𝑉 + 𝐶𝑃 𝑀 /1000 * 𝑆
The ARPU (Average revenue per user in planning period) is the average revenue per user, or the total revenue in the
planning period (R), divided by the number of users:
𝐴𝑅𝑃 𝑈 = 𝑅/𝑈
The Return of Investments for online marketing is calculated as:
𝑅−𝐶𝑡
𝑅𝑂𝐼 = 𝐶𝑡
After some research, you have found that the different metrics can be modeled as normal distributions with the following
parameters:
These are the search engine fees for your keywords: - CPM = 0,3€ - CPC = 0,75€
You estimate your ARPU in 5€
a. Calculate the total costs, the total Return of Investments and the average cost per acquisition using Montecarlo Sim-
ulation
Ok, Let’s first import the libraries we will need:
Ok, now we can start with the simulation. First, we will define the number of simulations we want to run. We will
use 100000 simulations, but you can change this number to see how the results change. Once, we define the number of
simulations, we will also define the properties of the random variables we want to simulate with Montecarlo (mean and
standard deviation). We will use the numpy library to generate the random variables. Finally, in this basic implementation,
we will define a for loop to run the simulation and store the results in a dataframe. We will also calculate the ROI for each
simulation and store it in the dataframe. Finally, We will use the describe function to get the statistics of the results.
[ ]: # Number of simulations
num_simulations = 100000
ctr_mean = 0.05
ctr_std = 0.01
cvr_mean = 0.5
cvr_std = 0.1
ARPU = 5
# We initialize a numpy array with the number of simulations and the number of␣
˓→variables we want to simulate
# Then we calculate the total number of visitors using the Click-Through Rate␣
˓→(CTR)
CTR = [Link](ctr_mean, ctr_std)
total_visitors = total_impacts * CTR
# Then we calculate the total number of customers using the Conversion Rate (CVR)
CVR = [Link](cvr_mean, cvr_std)
total_customers = total_visitors * CVR
# Finally, we calculate the total cost and the total revenues, using the costs␣
˓→and the ARPU
total_cost = CPC*total_visitors + CPM*total_impacts/1000
total_revenues = total_customers * ARPU
ROI = (total_revenues - total_cost)/total_cost
This code works and is easy to interpret, but it does not leverage one of the most outstanding features of Numpy, working
with vectors and matrices. Let’s see how we can improve the code using vectors and matrices, avoiding the for loop:
cvr_mean = 0.5
cvr_std = 0.1
ARPU = 5
# Conversion rate
CVR = [Link](cvr_mean, cvr_std, num_simulations)
Note that the only difference is that now we have used the numpy library to generate bi-dimensional matrices with the
random variables, and then just algebraic operations to calculate and store the results. This is much more efficient than
using a for loop.
Ok, now we can answer the questions just use the function hist() of the dataframe to plot the histogram:
hist = results_df.hist(bins=100)
Now, to calculate the confidence interval of the ROI, we can use the standard distribution, as we have a large number of
simulations. We can use the scipy library to get the confidence interval, using the function [Link]() to get the quantiles
of the standard distribution. We can also use the describe function to get the statistics of the results:
[5]: # Get the confidence interval of the ROI using the standard distribution
interval = ([Link](0.025, loc= [Link](ROI), scale=[Link](ROI)), [Link](0.
˓→975, loc= [Link](ROI), scale=[Link](ROI)))
print(interval)
(1.010423544564778, 3.593008469189609)
The 95% confidence interval of the ROI will be between these 2 values
Note that the function [Link] takes the quantile as the first argument, and the mean and standard deviation as the
second and third arguments. Since we want to get the 95% confidence interval, we use 0.025 and 0.975 as the quantiles.
To get the average and standard distribution of the ROI, we use the numpy functions mean and std, which will return
the empirical mean and standard deviation of the data generated during the simulation.
[6]: # We can also get the empirical 95% confidence interval of all metrics using describe
results_df.describe(percentiles=[0.025, 0.975])
[6]: impacts CTR Visitors CVR \
count 1.000000e+05 100000.000000 100000.000000 100000.000000
mean 5.999030e+05 0.050052 30031.266831 0.499396
std 1.001245e+05 0.010003 7901.093998 0.099647
min 1.627489e+05 0.006749 3111.804727 0.095343
2.5% 4.026289e+05 0.030309 15950.632852 0.304002
50% 5.997867e+05 0.050051 29532.234129 0.499373
97.5% 7.955853e+05 0.069589 46908.820897 0.693940
max 1.045158e+06 0.092695 73104.943275 0.958135
In this section you can find different Operations Research Problems modeled with Markov Chains:
Problem Definition
ABC Consulting is a consultancy firm in which employees move through three levels: Junior Consultant, Senior Consultant
and Manager. Changes of level are determined by the Human Resources (HR) Director based on an annual evaluation
done for each employee. Only one change of level can be done per evaluation and employees never go down one level.
After doing a statistical analysis, the HR Director has determined that the Junior Consultant has a 20 % probability of
moving up one level after the evaluation, whereas this probability lowers to 5 % for a Senior Consultant. He has also
established that there is a probability of 15, 10 and 5 % that a Junior Consultant, a Senior Consultant or a Manager,
respectively, leaves the firm (to work for another firm or to retire) after knowing the result of his or her annual evaluation.
For every employee who leaves the firm, a new Junior Consultant is contracted.
a) Model employee carriers as a Markov Chain
b) According to the model, calculate the stationary probabilities to determine What percentage of employees at leach level
will the company have in the long term
Problem Definition
Rick is a re-known scientist that is currently analysing the effects and mortality of an alien virus. Rick considers that,
under the effect of the virus, a cell can be in three different states s1=healthy, s2=infected, s3=dead.
a Rick thinks that the effect of the virus can be modelled as a Markov Process. Consider the transition probabilities as
unknowns, taking into account that infected cells may heal but dead cells cannot be alive again. Draw the Markov process
chain and the one-step transition probability matrix.
Rick makes a series of experiments by exposing a healthy cell culture to the virus and checking a sample every 10 hours.
After 10 hours, 40% of the cells are infected, but none are dead. After 20 hours, 24% of the cells are dead and 36% are
infected.
b Consider that the result of the 10 hours sample is the probability vector Vt (t=1) obtained from the one-step transition
probability matrix above and a vector Vt(t=0) representing the healthy cell culture population. Calculate the transition
probabilities from s1.
c Consider now the result of the 20 hours sample as the probability vector Vt(t=2). Can you determine the transition
probabilities from s2?
Tina Belcher, brand-new manager of the new Bob´s burger parlour downtown San Francisco, wants to analyse the impact
on the market and the loyalty of the customers of Bob’s Burger and Pesto´s, an Italian restaurant nearby. It is assumed that
one customer dines once a week at Bob’s or at Pesto´s, but not at both. Tina has collected information from 100 consumers
over a 10-week period. When checking the data, she discovered that of all the customers who consumed at Bob’s in a
given week, 90 % returned to the restaurant following week, while 10 % switched to Pesto’s. Of all the consumers who
consumed at Pesto’s in a given week, 80 % returned to the same place the following week, but 20 % switched to Bob´s.
Assuming that the transition probabilities are the same for every customer and that they not change over time, we can get
insights modelling customer fidelity with Markov chains.
Model customer fidelity as a Markov process and answer the following questions:
a) If at week 0, a customer dines at Bob’s, what is the probability of the same customer dining at Bob´s in week 1?
b) What is the probability of a customer going back to Bob´s two weeks running?
c) What is the probability of a customer changing to Pesto´s after dining at Bob´s and then going back to Bob´s
d) Consider the customer of section a) what is the probability that this customer comes back to Bob´s in two weeks time?
e) What is the expected market share of customers between the two restaurants?
Problem Definition
Rick & Morty Inc. is a small workshop that specialises in manufacturing special parts for the metallurgical industry. The
firms’ personnel comprises the Director Rick (an Industrial Organisation Engineer), the Designer Morty (an Industrial
Design Engineer) and three highly specialised Operators. The workshop has two very different areas (A and B) given the
type of machinery in them and the kind of works that can be done with it. The three Operators can move between the
two areas as they prefer because they can all work on any of the workshop machines. The Director has noticed that the
Operators tend to gather in the same area because their performance is enhanced if they help each other. Nevertheless,
leaving an area without Operators for several days is not a good option because the tasks in this area are considerably
delayed. By analysing last year’s manufacturing reports, the Director has calculated that the two areas were not occupied
by the Operators for 30 % of the days. However, the most worrying aspect is that one area can be void of Operators
for several days running. Therefore, the Director has decided to set up the following work plan: at the beginning of the
working day, the three Operators will enter a draw to see which of them changes area so no area will be empty for more
than 1 day running, or so the Director believes.
a) Consider the problem according to a Markov chain
b) For what percentage of time will one of the areas be void of Operators?
c) On average, how much time passes from there being no Operator in one zone to there being one Operator in it? And
the time from an area with no Operator until this same situation occurs again?
[ ]:
Problem definition
Problem definition
The IT department of your company has detected a threat in a software virus that affects the Operating System (OS) of
the PCs used in the company. When the virus infects a computer, it sends emails to a set of corporate emails. Once
the virus is installed in a computer, there is a procedure that can successfully remove the virus and restore the normal
operation of the computer. However, in some situations, IT might not be able to restore the OS and the computer might
become non-operative.
IT wants to use Markov Chains to model the status of a computer. After collecting data, they have determined that the
probability that a computer is infected by the virus given that it was operating normally the day before is 0.05. The
probability that the computer is non-operative for other reasons given that it was operating normally the day before is
0.1. Once a computer is infected, they always perform the virus removal procedure in the same day. They estimate that
the probability that the procedure is successful is 70%, while in 30% of the cases the procedure renders the computer
non-operative. When a computer is in non-operative state, the equipment supplier always replaces it the next business
day.
a Define the one-step probability matrix of the Markov chain
b The maintenance cost of a computer is 3€/day when it operates normally. The cost of the virus removal procedure is
30€ and the cost of replacing a computer is 1200€. Calculate the long term average costs in computer maintenance for
the IT department.
Problem Definition
ABC Consulting is a consultancy firm in which employees move through three levels: Junior Consultant, Senior Consultant
and Manager. Changes of level are determined by the Human Resources (HR) Director based on an annual evaluation
done for each employee. Only one change of level can be done per evaluation and employees never go down one level.
After doing a statistical analysis, the HR Director has determined that the Junior Consultant has a 20 % probability of
moving up one level after the evaluation, whereas this probability lowers to 5 % for a Senior Consultant. He has also
established that there is a probability of 15, 10 and 5 % that a Junior Consultant, a Senior Consultant or a Manager,
respectively, leaves the firm (to work for another firm or to retire) after knowing the result of his or her annual evaluation.
For every employee who leaves the firm, a new Junior Consultant is contracted.
a) Model employee carriers as a Markov Chain
We can define a Markov chain with one state per level:
• 𝑠1 : Employee at Junior consultant level
• 𝑠2 : Employee at Senior consultant level
• 𝑠3 : Employee at Manager level
• 𝑠4 : Employee leaves the firm
The time period between state changes is equal to the evaluation period (not specified).
Using the information collected by the HR Director, we can note the one-step probability matrix as:
⎡ ⎤
0.65 0.2 0.0 0.15
⎢0.00 0.85 0.05 0.10⎥
𝑃 (1) = ⎢
⎣ 0.0 0.0 .95 0.05⎦
⎥
0.2·𝜋1 = 0.15·𝜋2
0.04𝜋3 = 0.04·𝜋2
𝜋1 = 0.249
𝜋2 = 0.332
𝜋3 = 0.332
𝜋4 = 0.08715
Problem Definition
Rick is a re-known scientist that is currently analysing the effects and mortality of an alien virus. Rick considers that,
under the effect of the virus, a cell can be in three different states s1=healthy, s2=infected, s3=dead.
a Rick thinks that the effect of the virus can be modelled as a Markov Process. Consider the transition probabilities as
unknowns, taking into account that infected cells may heal but dead cells cannot be alive again. Draw the Markov process
chain and the one-step transition probability matrix.
The one-step probability matrix is given by:
⎡ ⎤
𝑝11 𝑝12 𝑝13
𝑃 (1) = ⎣𝑝21 𝑝22 𝑝23 ⎦
0 0 1
Since dead cells cannot be healthy or infected again, the probability of a dead cell remaining cell is 1, the rest of the
transition probabilities are unknowns.
Rick makes a series of experiments by exposing a healthy cell culture to the virus and checking a sample every 10 hours.
After 10 hours, 40% of the cells are infected, but none are dead. After 20 hours, 24% of the cells are dead and 36% are
infected.
b Consider that the result of the 10 hours sample is the probability vector Vt (t=1) obtained from the one-step transition
probability matrix above and a vector Vt(t=0) representing the healthy cell culture population. Calculate the transition
probabilities from s1. After 10 ours, our vector is:
𝑉 1 = [0.6 0.4 0] = [1 0 0] * 𝑃 (1) = [𝑝11 𝑝12 𝑝13 ]
𝑝11 = 0.6
𝑝12 = 0.4
𝑝13 = 0
c Consider now the result of the 20 hours sample as the probability vector Vt(t=2). Can you determine the transition
probabilities from s2?
We can obtain the missing values using the same procedure:
𝑉 2 = [0.4 0.36 0.24] = [0.6 0.4 0] * 𝑃 (1)
0.4−0.36
0.4 = 0.6 * 𝑝11 + 0.4 * 𝑝21 → 𝑝21 = 0.4 = 0.1
0.36−0.24
0.36 = 0.6 * 𝑝12 + 0.4 * 𝑝22 → 𝑝22 = 0.4 = 0.3
0.24
0.24 = 0.6 * 𝑝13 + 0.4 * 𝑝23 → 𝑝23 = 0.4 = 0.6
Tina Belcher, brand-new manager of the new Bob´s burger parlour downtown San Francisco, wants to analyse the impact
on the market and the loyalty of the customers of Bob’s Burger and Pesto´s, an Italian restaurant nearby. It is assumed that
one customer dines once a week at Bob’s or at Pesto´s, but not at both. Tina has collected information from 100 consumers
over a 10-week period. When checking the data, she discovered that of all the customers who consumed at Bob’s in a
given week, 90 % returned to the restaurant following week, while 10 % switched to Pesto’s. Of all the consumers who
consumed at Pesto’s in a given week, 80 % returned to the same place the following week, but 20 % switched to Bob´s.
Assuming that the transition probabilities are the same for every customer and that they not change over time, we can get
insights modelling customer fidelity with Markov chains.
Model
We model the decision of customers as a Markov chain, assuming two possible states every week (which is the discrete
event period of our model). The states are:
• 𝑠1 : represents the customers decision to go to Bob´s Burger.
• 𝑠2 : represents the customers decision to go to Pestos.
Now, with the data collected by Tina, we can estimate the transition probability Matrix.
• 𝑝11 : It is the probability that a customer goes back to Bob´s Burger after they have been to Bob´s Burger. Tina
discovered that this probability is 0.9 or 90%.
• 𝑝12 : It is the probability that a customer goes to Pesto´s after going to Bob´s Burger. Tina estimates that this
probability is 10%. Clearly, it has to be (1 − 𝑝11 = 0.1) since we only consider two possible states and at any given
time, the system has to be in one particular state, so the transition probabilities need to add up to 1.
• 𝑝11 : It is the probability that a customer goes back to Bob´s Burger after they have been to Bob´s Burger. Tina
discovered that this probability is 0.9 or 90%.
• 𝑝21 : It is the probability that a customer goes to Bob´s Burger after going to Pesto´s. Tina estimates this probability
to be 0.2.
• 𝑝22 : It is the probability that a customer goes to Pesto´s for two consecutive week, 0.8 according to Tina´s data.
With this, the transition probability matrix is:
[︂ ]︂
0.9 0.1
𝑃 (1) =
0.2 0.8
We can use Graphviz to represent the Markov chain:
# Add edges
[Link]( s1 , s1 , 0.9 )
[Link]( s1 , s2 , 0.1 )
[Link]( s2 , s1 , 0.2 )
[Link]( s2 , s2 , 0.8 )
(continues on next page)
din
Problem Definition
Rick & Morty Inc. is a small workshop that specialises in manufacturing special parts for the metallurgical industry. The
firms’ personnel comprises the Director Rick (an Industrial Organisation Engineer), the Designer Morty (an Industrial
Design Engineer) and three highly specialised Operators. The workshop has two very different areas (A and B) given the
type of machinery in them and the kind of works that can be done with it. The three Operators can move between the
two areas as they prefer because they can all work on any of the workshop machines. The Director has noticed that the
Operators tend to gather in the same area because their performance is enhanced if they help each other. Nevertheless,
leaving an area without Operators for several days is not a good option because the tasks in this area are considerably
delayed. By analysing last year’s manufacturing reports, the Director has calculated that the two areas were not occupied
by the Operators for 30 % of the days. However, the most worrying aspect is that one area can be void of Operators
for several days running. Therefore, the Director has decided to set up the following work plan: at the beginning of the
working day, the three Operators will enter a draw to see which of them changes area so no area will be empty for more
than 1 day running, or so the Director believes.
a) Consider the problem according to a Markov chain We can model the problem as a Markov chain with the following
states:
• 𝑠1 : 0 operators in cell A and 3 operators in cell B
• 𝑠2 : 1 operator in cell A and 2 operators in cell B
• 𝑠3 : 2 operators in cell A and 1 operator in cell B
• 𝑠4 : 3 operators in cell A and 0 operators in cell B
The period between states is one day.
Now, at the beginning of each day, the operators will enter a draw to see who must change area. Assuming that each
one has a probability of 𝑃 𝑐 = 1/3 to be selected in the draw and change cell, we can calculate the transition probability
matrix. For instance, the probability of going from state 𝑠1 to state 𝑠2 is 1, since there are 3 operators in cell B and one
of them must change area. The probability of going from state 𝑠2 to state 𝑠1 is 1/3, since one of the operators in cell A
must change area:
3 * 𝑃𝑐 = 1
The probability of going from state 𝑠2 to state 𝑠3 is 2/3, since the probability of the two operators in cell B to change area
is 2 * 𝑃 𝑐 = 2/3, and the probability of going from state 𝑠2 to state 𝑠1 is 1/3, since the probability of the operator in cell
A to change area is 𝑃 𝑐 = 1/3.
Following this reasoning yields a transition probability matrix equal to:
⎡ ⎤
0 1 0 0
⎢1/3 0 2/3 0 ⎥
𝑃 (1) = ⎢
⎣ 0
⎥
2/3 0 1/3⎦
0 0 1 0
The following diagram shows the Markov chain:
b) For what percentage of time will one of the areas be void of Operators?
We can calculate the stationary probabilities since they will tell us which is the probability that the system is at any given
state.
𝜋1 = 1/3·𝜋2
𝜋2 = 𝜋1 + 2/3·𝜋3
𝜋3 = 2/3·𝜋2 + 𝜋4
𝜋4 = 1/3·𝜋3
𝜋1 + 𝜋2 + 𝜋3 + 𝜋4 = 1
This yields:
𝜋1 = 1/3·𝜋2
2/3·𝜋2 = 2/3·𝜋3
𝜋4 = 1/3·𝑝𝑖3
𝜋1 + 3·𝜋1 + 3𝜋1 + 𝜋1 = 1
𝜋1 = 1/8 = 0.125
𝜋2 = 3/8 = 0.375
𝜋3 = 3/8 = 0.375
𝜋4 = 1/8 = 0.125
A will be voi 12.5% of the time and B 12.5% of the time, so one of the areas is going to be void 25% of the time. Rick
is not a genius after all.
c) On average, how much time passes from there being no Operator in one zone to there being one Operator in it? And
the time from an area with no Operator until this same situation occurs again?
This is left for future work!
Problem definition
Solution
We can model the status of the car at the beginning of the next year as a Markov system, with three possible states:
• 𝑠1 : represents the car being in good state.
• 𝑠2 : represents the car being in regular state.
• 𝑠2 : represents the car being in bad state.
With this model, we have to evaluate two possible scenarios. If we let the car transition to the regular state, the one-step
transition probability matrix is:
⎡ ⎤
0.9 0.05 0.05
𝑃 (1) = ⎣ 0 0.7 0.3 ⎦
0.9 0.05 0.05
Since a bad car needs to be replaced immediately, even if the event occurs in the last day of the year, a car in a bad status
is always replaced by a new one before the beginning of the next year, and therefore the transition probabilities are the
same as for a new car.
Now, if we replace the car immediately as soon as it is in a regular state, the one-step probability matrix becomes:
⎡ ⎤
0.9 0.05 0.05
𝑃 (1) = ⎣0.9 0.05 0.05⎦
0.9 0.05 0.05
That is, as soon as the car is in a regular state, it is replaced by a new one. We have thus two different scenarios, and each
step has different associated in each scenario.
We can calculate the stationary probabilities and corresponding long term average costs. In scenario 1, the long term
probabilities are:
𝜋1 = 0.771429
𝜋2 = 0.142857
𝜋3 = 0.0857143
In this scenario the costs are:
• 𝐶1 : 1000€ maintenance cost of a good car.
• 𝐶2 : 2000€ maintenance cost of a regular car.
• 𝐶2 : 13000€ cost of purchasing a new car plus year maintenance costs.
The long term average cost is:
𝐶 = 𝑖 𝐶𝑖 ·𝜋𝑖 = 2, 171
∑︀
So, under these conditions, the second scenario provides a lower long term average cost
Problem definition
The control system of a certain machine comprises two independent controls, A and B. This system is activated every
hour the machine operates to check that the machine works according to suitable parameters. The controls have a limited
life span. Indeed, control A has been replaced 52 times in the last 1,300 h of operation, whereas control B has been
substituted 39 times in the same time. Every time the system is activated, apart from controlling the machine, it warns
that one (or both) of the controls has failed. The faulty control is replaced before the system is next activated. When one
of the two controls is replaced, its reliability is lower because it has not been verified. Specifically, it is considered that
when the system is next activated, the reliability of the substituted control is half its normal value. Replacing control A
entails a cost of €70 and of €50 for replacing control B.
a) Consider the problem according to a Markov chain. Calculate the failure probability of each control according to its
historic of failures. Calculate the reliability
b) What is the hourly cost of the control system?
states s1 s2 s3 s4
s1 0.9312 0.0288 0.0388 0.0012
s2 0.4656 0.4944 0.0194 0.0206
s3 0.4656 0.0144 0.5044 0.0156
s4 0.2328 0.2472 0.2522 0.2678
Since control A has been replaced 52 times in 1300h, if we consider a sampling period of 1 hour, the fault probability is
0.04. For control B, fault probability is 0.03. The reliability is then 0.96 for control A and 0.97 for control B.
The probability that none of the controls is replaced is 0.96·0.97 = 0.9312, so this is the probability that we remain in
state 1. The probability that only control A is replaced is 0.04·0.97 (control A is faulty and control B is still operating
normally). The probability that only control B is replaced is 0.96·0.03, and the probability that both remain operational
is 0.03·0.04. This is how we obtain the first row.
The problem states that if one control is replaced, the reliability of the replaced component is half the normal value.
Therefore, if control B is replaced, the reliability goes down from 0.97 to 0.485. Now, the probability that both controls
remain operational is 0.485·0.96 = 0.4656. The probability that only control B is replaced is 0.515·0.96 = 0.4944. The
probability that only control A is replaced is 0.485·0.04 = 0,0194. And finally, the probability that both controls are
replaced is 0.515·0.04. This is how we obtain the transition probabilities from state two.
We can obtain the transition probabilities from state 3 in a similar manner. In this case, the reliability of control A goes
down from 0.96 to 0.48, and therefore the fault probability goes up to 0.52. The reliability of control B in this case is the
same as in state 1. Taking this into account we can derive the probabilities of the four possible state transitions. In state
four, the reliability of both controllers is down to half their nominal values (0.48 and 0.485) and using these values we
can obtain the transition probabilities and the final row.
Once we have obtained the one step transition matrix, we can calculate the stationary probability vector and the average
cost.
Problem definition
The IT department of your company has detected a threat in a software virus that affects the Operating System (OS) of
the PCs used in the company. When the virus infects a computer, it sends emails to a set of corporate emails. Once
the virus is installed in a computer, there is a procedure that can successfully remove the virus and restore the normal
operation of the computer. However, in some situations, IT might not be able to restore the OS and the computer might
become non-operative.
IT wants to use Markov Chains to model the status of a computer. After collecting data, they have determined that the
probability that a computer is infected by the virus given that it was operating normally the day before is 0.05. The
probability that the computer is non-operative for other reasons given that it was operating normally the day before is
0.1. Once a computer is infected, they always perform the virus removal procedure in the same day. They estimate that
the probability that the procedure is successful is 70%, while in 30% of the cases the procedure renders the computer
non-operative. When a computer is in non-operative state, the equipment supplier always replaces it the next business
day.
a Define the one-step probability matrix of the Markov chain Let us identify the following states of a computer:
𝑠1 : The computer is in normal operation
𝑠2 : The computer is infected by the virus
𝑠3 : The computer is non-operative for any other reason
Given this states, the one-step transition probability matrix can be expressed as:
⎡ ⎤
0.85 0.05 0.1
𝑃 (1) = ⎣ 0.7 0 0.3⎦
1 0 0
Note that in the matrix the value of 𝑝𝑖𝑗 is the probability that a computer is in state 𝑗 in the next day given that it is in
state 𝑖. Since the provider always replaces the computer the next day, 𝑝31 = 1.
b The maintenance cost of a computer is 3€/day when it operates normally. The cost of the virus removal procedure is
30€ and the cost of replacing a computer is 1200€. Calculate the long term average costs in computer maintenance for
the IT department.
Let us first define the system of equations to obtain the long term probabilities of the Markov system:
𝜋1 = 0.85 * 𝜋1 + 0.7 * 𝜋2 + 𝜋3
𝜋2 = 0.05 * 𝜋1
𝜋3 = 0.1 * 𝜋1 + 0.3 * 𝜋2
𝜋1 + 𝜋2 + 𝜋3 = 1
With this, we can calculate:
1
𝜋1 = 1+0.05+0.115 = 0, 858
𝜋2 = 0.05 * 𝜋1 = 0, 0429
𝜋3 = 0.015 * 𝜋1 = 0, 0987
And once that the values of the long term probabilities are obtained, long term costs are calculated as:
𝐶 = 3 * 𝜋1 + 30 * 𝜋2 + 1200 * 𝜋3
𝐶 = 122.3€
SEVEN
BIBLIOGRAPHY
The following references have been used throughout this interactive book:
• European Union. (n.d.). Artificial intelligence. Retrieved from [Link]
• Hagberg, A., Schult, D., & Swart, P. (2008). Networkx: A Python package for the creation, manipulation, and
study of the structure, dynamics, and functions of complex networks. Retrieved from [Link]
• Harris, C. R., Millman, K. J., van der Walt, S. J., Gommers, R., Virtanen, P., Cournapeau, D., Wieser, E., & others.
(2020). Array programming with NumPy. Nature, 585(7825), 357-362. Retrieved from [Link]
• Hunter, J. D. (2007). Matplotlib: A 2D graphics environment. Computing in Science & Engineering, 9(3), 90-95.
Retrieved from [Link]
• Keen, B. A. (2018). Introduction to Operations Research with Python. Retrieved from [Link]
keen/Introduction-to-linear-programming>
• Jones, E., Oliphant, T., & Peterson, P. (2001). SciPy: Open source scientific tools for Python. Retrieved from
[Link]
• Mitchell, L. (2011). PuLP: A Linear Programming Toolkit for Python. Retrieved from [Link]
pulp/
• Pedregosa, F., Varoquaux, G., Gramfort, A., Michel, V., Thirion, B., Grisel, O., Blondel, M., & others. (2011).
Scikit-learn: Machine learning in Python. Journal of Machine Learning Research, 12, 2825-2830. Retrieved from
[Link]
• Poler, R., Mula, J., & Díaz-Madroñero, M. (2014). Operations Research Problems Statements and Solutions.
Springer.
• Python Software Foundation. (n.d.). Python. Retrieved from [Link]
• The Pandas Development Team. (2020). Pandas: Powerful data structures for data analysis in Python. Retrieved
from [Link]
407
CHAPTER
EIGHT
If you are a teacher and would like to contribute to this online book, please do not hesitate to contact me and I will be
glad to discuss how to integrate your valuable input. We are always eager to:
• Add new exercises: There are just not enough exercises to master the field, so if you think you can contribute
with exercises to any of the sections, please reach out! We will gladly see how to incorporate them into the book.
• Add new tutorials: Interactive tutorials and dynamics are at the heart of this book, if you have any activity in
mind that uses Python to illustrate key concepts we will be very happy to go through them with you.
• Add new chapters: Operations research is a vast field of applied mathematics and many techniques and methods
are not covered in this book, yet. Let us work together to prepare new chapters and extend the scope of the book.
409
NumPy enhances numerical computations by providing support for multidimensional arrays and various derived objects such as masked arrays and matrices. It supplies a large library of high-level mathematical functions to operate on these arrays, enabling vectorized operations that improve efficiency over traditional loops. Functions like minimum() and maximum() perform element-wise operations efficiently, contributing to robust data analysis capabilities .
To determine if a solution is a global or local maximum in non-linear programming, the Hessian matrix of the objective function at the point is evaluated. If the Hessian is positive definite, the point is a local minimum. Conversely, if it's negative definite, the point is a local maximum. In cases where Hessian definiteness changes, further analysis or inspection might be needed to ensure correct classification of the maximum .
Indentation in Python is crucial as it defines the body of statements under control constructs like 'if' and 'else'. Without proper indentation, Python will not execute the clauses correctly, as indentation indicates which code block belongs to each clause. For instance, in 'if-else' statements, the lines under the 'if' and 'else' need to be indented consistently to be associated with the specific control structure, thereby influencing the flow of execution .
Formulating a linear model in operations research aids decision-making by structuring the optimization problem using decision variables, constraints, and an objective function. This framework helps in analyzing various resource allocations and forecasting outcomes based on changes to constraints, supporting data-driven decision making to maximize production efficiency and profit .
A 3D printing production plan must incorporate fixed operational costs, unitary production costs, machine capacities, and production speed. Flexibility can be introduced by considering demand variations over periods and allowing for delayed production meeting costs. This integration ensures demand variations are met by adapting production scheduling to optimize resource allocation, reducing waste, and increasing responsiveness to fluctuating market demands .
Shadow prices in linear programming represent the change in the objective function per unit increase in a constraint's right-hand side. For Spellman’s Ltd, the shadow price provides insight into how sensitive the profit is to changes in available resources like ingredient D. In their model, shadow prices inform decisions on whether increasing a resource constraint or investing in additional resources will benefit the production plan by indicating the marginal value of resources .
List comprehensions in Python provide a more concise way to construct lists as compared to traditional loops. They allow iteration over sequences and conditional logic in a single readable line, resulting in more efficient and less verbose code. For example, where a traditional loop might require several lines to instantiate and populate a list, list comprehensions achieve the same in one line, improving code clarity and performance .
NP-completeness affects computational feasibility as it classifies problems for which no polynomial time solution is known but which can be verified quickly. Problems like arranging elements factorially grow factorially with the number of elements, resulting in a dramatic increase in computational requirements. An NP-complete label implies that a practical solution may involve heuristics or approximations rather than exact algorithms, impacting solution time and resource allocation .
Incorporating external warehouses into Planet Express's transportation model adds layers of decision-making costs and constraints. The model must consider fixed and variable costs associated with these warehouses, alongside capacity constraints, which can increase operational flexibility. However, it also adds complexity to the cost optimization strategy, requiring the managing of these additional cost elements within the overall transportation cost structure .
Matplotlib, particularly the Pyplot module, is preferable when there is a need for a high level of customization in static and interactive plots. It is especially useful in notebook environments where interactive mode can enable zooming and panning. For presentations requiring non-interactive representations, the 'inline' mode generates static plots, making it versatile for different stages of data visualization tasks .