Mathematical optimization that can be used for free work with Python + PuLP

Postscript (2020/05/25)

The mathematical optimization solver (COIN-CBC for 1 thread), which is included in PuLP and is used by default, does not support multithreading (at least for Windows), so it takes time to solve integer optimization problems. May take. There was an article that wrote how to install the multi-threaded version of COIN-CBC, so I will post the link. Of course, it is available for commercial use free of charge.

--Windows: make the calculation engine of Python mathematical optimization package PuLP faster (Windows version easy edition) & specify the calculation time --Mac: Use your own CBC solver with PuLP

Postscript (2020/05/11)

Another free solver called "MIPCL" seems to solve the problem faster than PuLP (the one-threaded version of COIN-CBC that comes with it).

(Reference entry) Finally a free mathematical optimization solver that can be used? MIPCL

However, MIPCL seems to have a little peculiarity in installation and grammar, so at the moment, I think that you can use MIPCL if you want speed and PuLP if you want ease. If it takes time to write and solve with PuLP, it is one way to rewrite it to MIPCL ~ ~, and considering the time and effort, it is also one way to introduce MIPCL from the beginning and get used to it ~ ~ I think.

Introduction

Such a mathematical problem called mathematical optimization or mathematical planning

Problem (1): Linear optimization problem (Linear programming problem)
\begin{alignat}{2}
 &\mbox{Maximize} 
 &\qquad x + y & \\
 &\mbox{Constraint} 
 & 2x + y &\leq 2 \\
 &
 & x + 2y &\leq 2 \\
 &
 & x &\geq 0 \\
 &
 & y &\geq 0 \\
\end{alignat}

a - コピー.png

And such a math problem

Problem (2): Integer optimization problem (integer programming problem)
\begin{alignat}{3}
 &\mbox{Minimize} 
 &\qquad \sum_{i \in I} \sum_{j \in J} c_{ij} x_{ij} & 
 &\qquad & \\
 &\mbox{subject to} 
 & \sum_{j \in J} x_{ij} &\leq 1 
 & &\forall i \in I \\
 &
 &\sum_{i \in I} x_{ij} &= 1
 & &\forall j \in J \\
 &
 & x_{ij} &\in \{0,1\}
 & &\forall i \in I, \quad \forall j \in J
\end{alignat}

Introducing Python's PuLP package that solves.

It is a target, but it is assumed that the objective function and the constraint expression can be described in linear form (linear expression), and the variable can be described as continuous value or discrete value or a mixture of them.

As an aside, problem (2) is sometimes called an integer linear optimization problem (integer linear programming problem). Also, problems with a mixture of continuous and discrete variables are called mixed integer optimization problems (mixed integer programming problems, mixed integer linear optimization problems, mixed integer linear programming problems).

What is PuLP

You should think of PuLP itself as a ** modeling API **, ** modeling language ** that makes it easy to code mathematical optimization problems on Python. It is different from the ** solver ** that actually solves the formula, but since the solver called COIN is included, you can solve the problem just by installing PuLP. PuLP itself supports several solvers other than COIN, so if those solvers are installed separately, you can (easily) switch the solver to call from PuLP.

reference

Qiita entry of ancestors

-Python in optimization -Introduction to solving linear programming problems with PuLP

Head family site

Why Python + PuLP

It's just a ** personal opinion **, but ...

Price

Gurobi Optimizer, IBM ILOG CPLEX Optimization Studio, FICO Xpress Optimization Suite, Numerical Optimizer are expensive ... ** → PuLP is free! The same solver COIN is also free! !! ** **

Speed

GLPK and lp_solve are slow ... Microsoft Excel is slow and can handle a small number of variables and constraint expressions ... ** → The COIN included in PuLP is not bad for a free solver! You can call a commercial solver just by changing the code! !! ** **

Commercial use

It says that if you want to use SCIP for commercial purposes, please email me ... ** → PuLP & COIN is OK for commercial use! There is no obligation to publish the source code of the incorporated product! !! ** **

Model description language

AMPL, a modeling language that Mr. K of K & R, who is famous for C language, was involved in the development, and original modeling languages such as IBM ILOG CPLEX Optimization Studio, FICO Xpress Optimization Suite, and Numerical Optimizer. It's easy to understand because you can describe it. But it can't be used anywhere else, and if you want to do something complicated, you have to look at the manual, and even if you google, there is little information ... ** → PuLP can also write models like mathematical formulas! Since it is Python, it is easy to link with other algorithms, and if you don't understand it, you can get a lot of information by google! !! Since the description of the model part can be changed as it is and only the solver to be called can be changed, PuLP can actually become a common language! !! !! ** **

Development environment

The integrated development environment that comes with IBM ILOG CPLEX Optimization Studio and FICO Xpress Optimization Suite can display various information, and it's convenient to be able to click with the mouse. But I can't use it anywhere else ... ** → Because it is Python, it can be used on Visual Studio Code, Visual Studio (even for free Community edition and Express edition), Jupyter Notebook and Spyder! Works on various machines and environments! !! Anyone can co-develop and test anywhere! !! !! ** **


To researchers and students

Researchers and students may get a commercial solver cheaply or for free for research and learning purposes.

If the research content seems to be for commercial use in the future, researchers should consider using Python + PuLP from now on, considering the cost involved. As I've written many times, the solver you call from PuLP can be easily switched, so if you don't need to touch the depths of commercial solvers (such as tuning integer optimization parameters), PuLP is a good modeling API. think. Also, the amount of coding required is not so large for porting and compatibility from commercial solvers that have APIs for Python.

Students should consider using Python + PuLP (COIN) from now on, considering the use of mathematical optimization at their current part-time job or future employment or their customers. Of course, it depends on the scale of the project, but it is quite a hurdle to explain the cost-effectiveness of raising the cost of purchasing and maintaining a commercial solver. The same applies even if you are conducting research commissioned by a company or joint research. Think of options that corporate people can use.


That was my personal opinion.

Assumed environment

The following is written assuming the case of ** Anaconda ** that supports ** Python 3.7 ** on ** Windows ** (supported). Replace it appropriately on Mac or Linux.

Installation

In advance!

If you have installed Gurobi Optimizer or simulation software in the past in addition to the Python you installed yourself, there is a possibility that the Python processing system is stuck. In that case, start the command prompt (Windows start button → Windows system tools → command prompt) and type where python or where pip to check which processing system is prioritized. ..

If the ʻAnaconda3` folder is displayed first, as shown below, it means that Anaconda has priority, as expected in this article.

C:\Users\(username)>where python
C:\Users\(username)\Anaconda3\python.exe
C:\Users\(username)\AppData\Local\Microsoft\WindowsApps\python.exe

C:\Users\(username)>where pip
C:\Users\(username)\Anaconda3\Scripts\pip.exe

C:\Users\(username)>

If something that is not the ʻAnaconda3` folder is displayed first, it means that the processing system that is not Anaconda is prioritized. Please decide for yourself whether it is okay to keep it as it is, and change the order of the items listed in "Path" of "Environment Variables" if necessary.

If the following is displayed, or if other processing systems are displayed but the ʻAnaconda3` folder is not displayed,

C:\Users\(username)>where python
information:The file with the given pattern was not found.

C:\Users\(username)>

This is the so-called Anaconda "pass does not pass" state. Probably because I didn't check "Add Anaconda to my PATH environment variable" when I installed Anaconda. (Reference) https://weblabo.oscasierra.net/python-anaconda-install-windows/ In that case, pass the path (either by yourself or by uninstalling and reinstalling Anaconda), or do the following work with Anaconda Prompt (Windows start button → Anaconda3 (64bit) → Anaconda Prompt) instead of the command prompt. Please give me.

Was good. Actual work from

Just in case, close the command prompt and reopen it (because it is necessary when the environment variables are rearranged). If Python is installed in a folder that requires writing with administrator privileges (for example, if you select "All users (requires admin privileges)" in the installation of Anaconda), select "Run as administrator". start up.

If you try to install from ** inside the company ** and get in the way of ** proxy **, you should temporarily set the proxy in the command prompt as follows (IP address and port number). Please replace with the value in your environment).

set HTTP_PROXY=111.222.111.222:3333
set HTTPS_PROXY=111.222.111.222:3333

Reference: http://d.hatena.ne.jp/showhey810/20140905/1409892787

Type pip install pulp to download and install the pulp. If ** security software ** asks for communication permission, please do so. If all goes well, you should see something like this:

C:\Users\(username)>pip install pulp
Collecting pulp
  Downloading PuLP-2.1-py3-none-any.whl (40.6 MB)
    |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■| 40.6 MB 6.4 MB/s
Requirement already satisfied: pyparsing>=2.0.1 in c:\users\(username)\anaconda3\lib\site-packages (from pulp) (2.4.6)
Installing collected packages: pulp
Successfully installed pulp-2.1
C:\Users\(username)>

If it is already installed, you should see something like this: It's already installed, so there's no problem.

C:\Users\(username)>pip install pulp
Requirement already satisfied: pulp in c:\users\(username)\anaconda3\lib\site-packages (2.1)
Requirement already satisfied: pyparsing>=2.0.1 in c:\users\(username)\anaconda3\lib\site-packages (from pulp) (2.4.6)
C:\Users\(username)>

(Memo)

--You can also install with python -m pip install pulp. --You can update pip with pip install -U pulp or python -m pip install -U pulp.

Example 1)

Solve the opening problem (1).

\begin{alignat}{2}
 &\mbox{Maximize} 
 &\qquad x + y & \\
 &\mbox{Constraint} 
 & 2x + y &\leq 2 \\
 &
 & x + 2y &\leq 2 \\
 &
 & x &\geq 0 \\
 &
 & y &\geq 0. \\
\end{alignat}

code

pulp_problem_1.py


# coding: UTF-8

#linear/Import PuLP to solve integer linear optimization problems
import pulp
# sys.Import to get the maximum integer (int) that python can handle with maxsize
import sys

#Declare a mathematical optimization problem (maximization)
problem = pulp.LpProblem("Problem-1", pulp.LpMaximize)

#Declare variables (continuous)
#   *The variable object itself (x,y) and
#A string representation of a variable ("xx", "yy") To distinguish
#I dare to use the character string expression"xx", "yy"Is written
x = pulp.LpVariable("xx", 0, sys.maxsize, pulp.LpContinuous)
y = pulp.LpVariable("yy", 0, sys.maxsize, pulp.LpContinuous)

#Declare the objective function
#   *Parentheses are not required, but are listed for clarity
problem += ( x + y, "Objective" )

#Declare constraints
problem += ( 2 * x + y <= 2 , "Constraint_1" )
problem += ( x + 2 * y <= 2 , "Constraint_2" )

#Show all problem expressions
#   *The string representation of the variable is used when the problem is printed in a print statement.
print("Problem formula")
print("-" * 8)
print(problem)
print("-" * 8)

#Calculation
result_status = problem.solve()

#Display objective function value and solution (if solution is available)
print("")
print("Calculation result")
print("*" * 8)
print(f"Optimality= {pulp.LpStatus[result_status]}")
print(f"Objective function value= {pulp.value(problem.objective)}")
print(f"Solution x= {pulp.value(x)}")
print(f"  y = {pulp.value(y)}")
print("*" * 8)

output

Problem formula
--------
Problem-1:
MAXIMIZE
1*xx + 1*yy + 0
SUBJECT TO
Constraint_1: 2 xx + yy <= 2

Constraint_2: xx + 2 yy <= 2

VARIABLES
xx <= 9.22337203685e+18 Continuous
yy <= 9.22337203685e+18 Continuous

--------

Calculation result
********
Optimality= Optimal
Objective function value= 1.33333334
Solution x= 0.66666667
  y = 0.66666667
********

Digression (1)

Languages that can use operator overloading can easily write mathematical optimization expressions. Languages that aren't ... Java ...


Example (2)

Solve the opening problem (2).

\begin{alignat}{3}
 &\mbox{Minimize} 
 &\qquad \sum_{i \in I} \sum_{j \in J} c_{ij} x_{ij} & 
 &\qquad & \\
 &\mbox{subject to} 
 & \sum_{j \in J} x_{ij} &\leq 1 
 & &\forall i \in I \\
 &
 &\sum_{i \in I} x_{ij} &= 1
 & &\forall j \in J \\
 &
 & x_{ij} &\in \{0,1\}
 & &\forall i \in I, \quad \forall j \in J.
\end{alignat}

Digression (2)

You often use $ \ sum $ in mathematical optimization formulas, don't you? Mathematical optimization modeling languages are based on how you can write $ \ sum $. In that respect, PuLP is safe. By the way, in the introductory text of mathematical optimization, the set $ I $ and $ J $ in this problem is $ I: = \ {1, \ ldots, m \} $ and $ J: = \ Numbering from 1 by force, such as {1, \ ldots, n \} $, for example, constraint conditions

\sum_{j = 1}^{n} x_{ij} \leq 1 \quad \mbox{for} \;\; i = 1, \ldots, m

There is something that says, but I am confused as to what the elements of $ I $ and $ J $ represent, and which element of the number $ 2 $ is $ I $ or $ J $. It is recommended that you do not replace the set with a column of positive integers, and use the original names of the elements of the set as well. PuLP allows you to model naturally by using language specifications such as Python dictionaries and tuples.

Also, like the formula written with the $ \ LaTeX $ command in this problem, it would be nice to align the height of each formula to make it easier to see.

Also, this problem is mitigated by changing the 0-1 variable $ x_ {ij} \ in \ {0,1 \} $ to the continuous variable $ 0 \ leq x_ {ij} \ leq 1 $ (changed to a looser condition). It is well known that even if you solve a problem, there is an optimal solution for integers because of the total unimodularity of the problem, and you can get it. However, when you actually model it at work, the constraints are increasing steadily, and in most cases all unimodularity does not hold.


code

pulp_problem_2.py


# coding: UTF-8

#linear/Import PuLP to solve integer linear optimization problems
import pulp
#Import time to measure calculation time
import time



#Set of workers (use a list for convenience)
I = ["Mr. A", "Mr. B", "Mr. C"]

print(f"Assembly of workers I= {I}")


#Set of tasks (use a list for convenience)
J = ["Work i", "Work b", "Work c"]

print(f"Set of tasks J= {J}")


#Set of costs (temporary list) when worker i is assigned to task j
cc = [
      [ 1,  2,  3],
      [ 4,  6,  8],
      [10, 13, 16],
     ]

#Because cc is a list and the subscript is a number
#Define dictionary c, for example cc[0][0]Is c["Mr. A","Work i"]Make it accessible with
c = {} #Empty dictionary
for i in I:
    for j in J:
        c[i,j] = cc[I.index(i)][J.index(j)]

print("Cost c[i,j]: ")
for i in I:
    for j in J:
        print(f"c[{i},{j}] = {c[i,j]:2d},  ", end = "")
    print("")
print("")



#Declare a mathematical optimization problem (minimization)
problem = pulp.LpProblem("Problem-2", pulp.LpMinimize)
# pulp.LpMinimize :Minimize
# pulp.LpMaximize :Maximize


#Dictionary representing variable set
x = {} #Empty dictionary
       # x[i,j]Or x[(i,j)]so,(i,j)Read and write values using the tuple as a key

# 0-Declare one variable
for i in I:
    for j in J:
        x[i,j] = pulp.LpVariable(f"x({i},{j})", 0, 1, pulp.LpInteger)
        #On the variable label'['Or']'Or'-'For some reason'_'It changes to ...?
# lowBound,If you do not specify upBound, each-Infinity, +Infinity になる

#Inclusive notation can also be used
# x_suffixes = [(i,j) for i in I for j in J]
# x = pulp.LpVariable.dicts("x", x_suffixes, cat = pulp.LpBinary) 

# pulp.LpContinuous :Continuous variable
# pulp.LpInteger    :Integer variable
# pulp.LpBinary     : 0-1 variable


#Declare the objective function
problem += pulp.lpSum(c[i,j] * x[i,j] for i in I for j in J), "TotalCost"
# problem += sum(c[i,j] * x[i,j] for i in I for j in J)
#OK


#Declare constraints
#For each worker i, no more than one task can be assigned
for i in I:
    problem += sum(x[i,j] for j in J) <= 1, f"Constraint_leq_{i}"
    #On the constraint label'['Or']'Or'-'For some reason'_'It changes to ...?

#Exactly one worker is assigned for each task j
for j in J:
    problem += sum(x[i,j] for i in I) == 1, f"Constraint_eq_{j}"


#Show all problem expressions
print("Problem formula")
print(f"-" * 8)
print(problem)
print(f"-" * 8)
print("")



#Calculation
#Solver designation
solver = pulp.PULP_CBC_CMD()
# pulp.PULP_CBC_CMD() :Coin attached to PuLP-CBC
# pulp.GUROBI_CMD()   :Launch Gurobi from the command line(.Temporarily generate lp file)
# pulp.GUROBI()       :Launch Gurobi from the library(Library location required)
#Supports several other solvers
# (Example of use)
# if pulp.GUROBI_CMD().available():
#     solver = pulp.GUROBI_CMD()

#Start time measurement
time_start = time.perf_counter()

result_status = problem.solve(solver)
# solve()of()You can specify the solver within
#Pulp if nothing is specified.PULP_CBC_CMD()

#Time measurement finished
time_stop = time.perf_counter()



#Display objective function value and solution (if solution is available)
print("Calculation result")
print(f"*" * 8)
print(f"Optimality= {pulp.LpStatus[result_status]}, ", end="")
print(f"Objective function value= {pulp.value(problem.objective)}, ", end="")
print(f"Calculation time= {time_stop - time_start:.3f} (Seconds)")
print("Solution x[i,j]: ")
for i in I:
    for j in J:
        print(f"{x[i,j].name} = {x[i,j].value()},  ", end="")
    print("")
print(f"*" * 8)

output

Assembly of workers I= ['Mr. A', 'Mr. B', 'Mr. C']
Set of tasks J= ['Work i', 'Work b', 'Work c']
Cost c[i,j]:
c[Mr. A,Work i] =  1,  c[Mr. A,Work b] =  2,  c[Mr. A,Work c] =  3,  
c[Mr. B,Work i] =  4,  c[Mr. B,Work b] =  6,  c[Mr. B,Work c] =  8,  
c[Mr. C,Work i] = 10,  c[Mr. C,Work b] = 13,  c[Mr. C,Work c] = 16,  

Problem formula
--------
Problem-2:
MINIMIZE
1*x(Mr. A,Work i) + 3*x(Mr. A,Work c) + 2*x(Mr. A,Work b) + 4*x(Mr. B,Work i) + 8*x(Mr. B,Work c) + 6*x(Mr. B,Work b) + 10*x(Mr. C,Work i) + 16*x(Mr. C,Work c) + 13*x(Mr. C,Work b) + 0
SUBJECT TO
Constraint_leq_Mr. A: x(Mr. A,Work i) + x(Mr. A,Work c) + x(Mr. A,Work b) <= 1

Constraint_leq_Mr. B: x(Mr. B,Work i) + x(Mr. B,Work c) + x(Mr. B,Work b) <= 1

Constraint_leq_Mr. C: x(Mr. C,Work i) + x(Mr. C,Work c) + x(Mr. C,Work b) <= 1

Constraint_eq_Work i: x(Mr. A,Work i) + x(Mr. B,Work i) + x(Mr. C,Work i) = 1

Constraint_eq_Work b: x(Mr. A,Work b) + x(Mr. B,Work b) + x(Mr. C,Work b) = 1

Constraint_eq_Work c: x(Mr. A,Work c) + x(Mr. B,Work c) + x(Mr. C,Work c) = 1

VARIABLES
0 <= x(Mr. A,Work i) <= 1 Integer
0 <= x(Mr. A,Work c) <= 1 Integer
0 <= x(Mr. A,Work b) <= 1 Integer
0 <= x(Mr. B,Work c) <= 1 Integer
0 <= x(Mr. B,Work b) <= 1 Integer
0 <= x(Mr. C,Work i) <= 1 Integer
0 <= x(Mr. C,Work c) <= 1 Integer
0 <= x(Mr. C,Work b) <= 1 Integer

--------

Calculation result
********
Optimality= Optimal,Objective function value= 19.0,Calculation time= 0.040 (Seconds)
Solution x[i,j]:
x(Mr. A,Work i) = 0.0,  x(Mr. A,Work b) = 0.0,  x(Mr. A,Work c) = 1.0,
x(Mr. B,Work i) = 0.0,  x(Mr. B,Work b) = 1.0,  x(Mr. B,Work c) = 0.0,
x(Mr. C,Work i) = 1.0,  x(Mr. C,Work b) = 0.0,  x(Mr. C,Work c) = 0.0,
********

in conclusion

I think it's easier than Bob's painting class, so please try Python + PuLP. If the problem you want to solve ** takes a long time to calculate, see the multithreaded solver article ** with the link at the top and give it a try.

Recommended Posts

Mathematical optimization that can be used for free work with Python + PuLP
Python knowledge notes that can be used with AtCoder
File sharing server made with Raspberry Pi that can be used for remote work
I created a template for a Python project that can be used universally
File types that can be used with Go
Functions that can be used in for statements
Understand the probabilities and statistics that can be used for progress management with a python program
I made a familiar function that can be used in statistics with Python
Japanese can be used with Python in Docker environment
[Python] Building an environment for competitive programming with Atom (input () can be used!) [Mac]
[Python] Introduction to web scraping | Summary of methods that can be used with webdriver
SSD 1306 OLED can be used with Raspberry Pi + python (Note)
Scripts that can be used when using bottle in Python
Can be used with AtCoder! A collection of techniques for drawing short code in Python!
[Python] Make a graph that can be moved around with Plotly
I made a shuffle that can be reset (reverted) with Python
Python standard input summary that can be used in competition pro
Python standard module that can be used on the command line
Mathematical Optimization Modeler (PuLP) Cheat Sheet (Python)
About the matter that the re.compiled object can be used for the re.match pattern
Acoustic signal processing module that can be used with Python-Sounddevice ASIO [Application]
"Manim" that can draw animation of mathematical formulas and graphs with Python
Acoustic signal processing module that can be used with Python-Sounddevice ASIO [Basic]
I wrote a tri-tree that can be used for high-speed dictionary implementation in D language and Python.
A memo for making a figure that can be posted to a journal with matplotlib
++ and-cannot be used for increment / decrement in python
Until youtube-dl can be used with Synology (DS120j)
A class for PYTHON that can be operated without being aware of LDAP
When writing tests with python unittests, use doCleanups for setUps that can fail
Introduction to Python Mathematical Optimization Solving junior high school math problems with pulp
Moved Raspberry Pi remotely so that it can be LED attached with Python
How to install a Python library that can be used by pharmaceutical companies
List packages that can be updated with pip
[Python] f strings should be used for embedding strings
List of tools that can be used to easily try sentiment analysis of Japanese sentences in Python (try with google colab)
Overview and useful features of scikit-learn that can also be used for deep learning
Workaround for the problem that UTF-8 Japanese mail cannot be sent with Flask-Mail (Python3)
Convert images from FlyCapture SDK to a form that can be used with openCV
Summary of statistical data analysis methods using Python that can be used in business
The story that sendmail that can be executed in the terminal did not work with cron
Basic algorithms that can be used in competition pros
ANTs image registration that can be used in 5 minutes
Can be used in competition pros! Python standard library
[Django] About users that can be used on template
Limits that can be analyzed at once with MeCab
Python optimization library Pulp
Install Mecab and CaboCha on ubuntu16.04LTS so that it can be used from python3 series
[Python3] Code that can be used when you want to resize images in folder units
How to set variables that can be used throughout the Django app-useful for templates, etc.-
Format summary of formats that can be serialized with gensim
It seems that Skeleton Tracking can be done with RealSense
pd.tseries.offsets.DateOffset can be quite slow if not used with caution
[Python] Variadic arguments can be used when unpacking iterable elements
Goroutine (parallel control) that can be used in the field
Goroutine that can be used in the field (errgroup.Group edition)
I investigated the pretreatment that can be done with PyCaret
Let's make a diagram that can be clicked with IPython
This and that for using Step Functions with CDK + Python
[Python] Draw elevation data on a sphere with Plotly and draw a globe that can be rotated round and round
I tried to expand the database so that it can be used with PES analysis software
I bought and analyzed the year-end jumbo lottery with Python that can be executed in Colaboratory