├── LICENSE
├── Machine Learning + Decision Optimization
├── CPLEX_Python
│ └── Promoting financial products to bank customers.ipynb
└── README.md
├── Production_Planning
├── CPLEX_OPL
│ └── production.mod
├── CPLEX_Python
│ ├── Production planning docplex.ipynb
│ ├── production_df.py
│ └── production_lists.py
└── README.md
├── Project Scheduling
├── OPL
│ ├── Assign workers
│ │ ├── Model.ops
│ │ ├── README.md
│ │ ├── Scheduling-workers.xlsx
│ │ ├── Workers.mod
│ │ └── model data.dat
│ ├── Calendars
│ │ ├── Calendar.mod
│ │ ├── Model data.dat
│ │ ├── Model.ops
│ │ ├── README.md
│ │ └── Scheduling-calendar.xlsx
│ └── README.md
├── README.md
└── Watson
│ ├── Assign workers - watson code.ipynb
│ ├── Assign workers - watson instructions.ipynb
│ ├── Calendar(scheduled breaks) - watson code.ipynb
│ └── README.md
├── README.md
├── TSP
├── CPLEX_OPL
│ └── inicial.mod
├── CPLEX_Python
│ └── TSP.ipynb
└── README.md
├── Tips_CPLEX
├── OPL
│ ├── changeTuplesWithLoop.mod
│ ├── database connection
│ │ ├── product_data.db
│ │ ├── production_for_db.mod
│ │ └── production_with_db.dat
│ └── incrementalChanges.mod
└── README.md
└── VRPTW
├── CPLEX_OPL
├── README.md
└── VRPTW.mod
├── CPLEX_Python
├── VRPTW.html
└── VRPTW.ipynb
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Machine Learning + Decision Optimization/README.md:
--------------------------------------------------------------------------------
1 | # Machine Learning + Decision Optimization
2 |
3 | While machine learning can take into account all available data and past history to predict the likelihood of failure for a given machine, decision optimization (DO) can take it a step further and generate a schedule that is optimal for a set of machines, subject to limited resources (e.g. maintenance crew availability), other constraints and dependencies (production plan and repair costs), and optimization metrics (minimizing total cost, maximizing customer satisfaction/meeting planned production, minimizing late maintenance).
4 |
5 | As is the case with any business solution, it is not enough to create a model. Our ultimate goal should be a solution delivered in the hands of business users and decision makers. This is true no matter what technology is being used, and the methodology will be similar (Yana Ageeva, 2018).
6 |
7 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
8 |
9 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
10 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
11 |
12 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
13 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
14 |
15 | #### For more information about SmartBP
16 | - [Website](http://www.smart-bp.com)
17 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
18 | - [Follow Us](https://twitter.com/Smart_BP)
19 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
--------------------------------------------------------------------------------
/Production_Planning/CPLEX_OPL/production.mod:
--------------------------------------------------------------------------------
1 |
2 | //Define sets
3 | {string} products = {"A","B","C","D"};
4 |
5 | //Define parameters
6 | //demand
7 | int demand[products] = [50,70,100,20];
8 | //profit
9 | int profit[products] = [40,20,10,70];
10 | //processing time
11 | int pro_time[products] = [15,15,5,25];
12 | //total capacity
13 | int capacity = 2000;
14 |
15 | //Define decision variables
16 | dvar int production[products];
17 |
18 | //Define linear expressions
19 | dexpr int profit_prod = sum(p in products)(production[p]*profit[p]);
20 | //Define objective function
21 | maximize profit_prod;
22 |
23 | //Define constraints
24 | subject to{
25 | //The company has limited time capacity to produce all the products
26 | forall(p in products)
27 | production[p] <= demand[p];
28 | //The company cannot sale products over the known demand
29 | sum(p in products)(production[p]*pro_time[p]) <= capacity;
30 | }
31 |
32 | execute{
33 | writeln("The maximum profit would be: "+profit_prod);
34 | for(var p in products){
35 | writeln("The company needs to produce "+production[p]+" unit of product "+p);
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/Production_Planning/CPLEX_Python/Production planning docplex.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Production Planning Problem\n",
8 | "\n",
9 | "## Problem description\n",
10 | "\n",
11 | "\n",
12 | "A company needs to decide their production plan for the next month. They produce four products: A, B, C and D. Each product has a known demand, the production cannot exceed this demand as it would be lost. Moreover, the company has a limited time of 2000 minutes to produce all the products. What should be the production level for each product so that they can maximize their profit.\n",
13 | "\n",
14 | "| Product | Demand | Profit | Processing time |\n",
15 | "|---------|--------|--------|-----------------|\n",
16 | "| A | 50 | 40 | 15 |\n",
17 | "| B | 70 | 20 | 15 |\n",
18 | "| C | 100 | 10 | 5 |\n",
19 | "| D | 20 | 70 | 25 |"
20 | ]
21 | },
22 | {
23 | "cell_type": "markdown",
24 | "metadata": {},
25 | "source": [
26 | "## Model formulation\n",
27 | "\n",
28 | "We would use a Mathematical programming approach to formulate our optimization model. As our production should be determine by units, the decision must be a integer number. In this case, we are working with an Integer Programming problem.\n",
29 | "\n",
30 | "### Sets\n",
31 | "\n",
32 | "$Products$: set of products\n",
33 | "\n",
34 | "### Parameters\n",
35 | "$demand_p$: demand of product $p \\in Products$\n",
36 | "\n",
37 | "$profit_p$: profit per unit of product $p \\in Products$\n",
38 | "\n",
39 | "$proTime_p$: processing time per unit of product $p \\in Products$\n",
40 | "\n",
41 | "$capacity$: total time capacity available for production\n",
42 | "\n",
43 | "### Decision variables\n",
44 | "\n",
45 | "$production_p \\in \\mathbb{Z}^+$: production level of product $p \\in Products$\n",
46 | "\n",
47 | "### Objective function\n",
48 | "\n",
49 | "$$\\max totalProfit=\\sum_{p \\in Products} production_p * profit_p$$\n",
50 | "\n",
51 | "### Constraints\n",
52 | "\n",
53 | "$$production_p \\leq demand_p \\forall p \\in Products$$\n",
54 | "\n",
55 | "$$\\sum_{p \\in Products} production_p * proTime_p \\leq capacity$$\n"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | "## Python implementation\n",
63 | "\n",
64 | "We will follow the next steps by using the IBM® Decision Optimization CPLEX® Modeling for Python:\n",
65 | "1. Import docplex library\n",
66 | "2. Create a Model instance\n",
67 | "3. Define sets and parameters\n",
68 | "4. Define decision variables\n",
69 | "5. Define constraints\n",
70 | "6. Define linear expressions\n",
71 | "7. Define objective function\n",
72 | "8. Define de solving command"
73 | ]
74 | },
75 | {
76 | "cell_type": "markdown",
77 | "metadata": {},
78 | "source": [
79 | "#### 1. Import docplex library\n",
80 | "First of all, we will import the docplex library, and specifically the model module. If you need to use other library, for example, for data processing or data visualization, you should import it in this step as well. For this problem, we are no using any additional library."
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "execution_count": 2,
86 | "metadata": {},
87 | "outputs": [],
88 | "source": [
89 | "import docplex\n",
90 | "from docplex.mp.model import Model"
91 | ]
92 | },
93 | {
94 | "cell_type": "markdown",
95 | "metadata": {},
96 | "source": [
97 | "#### 2. Create a Model instance\n",
98 | "You need a Model instance to define all the elements needed to create the production problem"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "execution_count": 19,
104 | "metadata": {},
105 | "outputs": [],
106 | "source": [
107 | "model = Model(name=\"production_problem\")"
108 | ]
109 | },
110 | {
111 | "cell_type": "markdown",
112 | "metadata": {},
113 | "source": [
114 | "#### 3. Define sets and parameters\n",
115 | "**Sets:** The first you need to do is define your sets as they are going to be the indexes for your parameters and variable decisions. \n",
116 | "\n",
117 | "**Parameters:** These are the known data from your problem that allows to make decisions."
118 | ]
119 | },
120 | {
121 | "cell_type": "code",
122 | "execution_count": 20,
123 | "metadata": {},
124 | "outputs": [],
125 | "source": [
126 | "# Define sets\n",
127 | "products = {\"A\",\"B\",\"C\",\"D\"}\n",
128 | "\n",
129 | "# Define parameters\n",
130 | "#demand\n",
131 | "demand = {\"A\":50,\"B\":70,\"C\":100,\"D\":20}\n",
132 | "#profit\n",
133 | "profit = {\"A\":40,\"B\":20,\"C\":10,\"D\":70}\n",
134 | "#processing time\n",
135 | "pro_time = {\"A\":15,\"B\":15,\"C\":5,\"D\":25}\n",
136 | "#total capacity\n",
137 | "capacity = 2000"
138 | ]
139 | },
140 | {
141 | "cell_type": "markdown",
142 | "metadata": {},
143 | "source": [
144 | "#### 4. Define decision variables"
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": 21,
150 | "metadata": {},
151 | "outputs": [],
152 | "source": [
153 | "production = model.integer_var_dict(products,name=\"prod\")"
154 | ]
155 | },
156 | {
157 | "cell_type": "markdown",
158 | "metadata": {},
159 | "source": [
160 | "#### 5. Define constraints\n",
161 | "For this problem we have two constraints:\n",
162 | "1. The company cannot sale products over the known demand\n",
163 | "2. The company has limited time capacity to produce all the products."
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": 22,
169 | "metadata": {},
170 | "outputs": [
171 | {
172 | "data": {
173 | "text/plain": [
174 | "docplex.mp.LinearConstraint[](15prod_A+15prod_B+5prod_C+25prod_D,LE,2000)"
175 | ]
176 | },
177 | "execution_count": 22,
178 | "metadata": {},
179 | "output_type": "execute_result"
180 | }
181 | ],
182 | "source": [
183 | "#1. The company cannot sale products over the known demand\n",
184 | "for p in products:\n",
185 | " model.add_constraint(production[p]<=demand[p])\n",
186 | "#2. The company has limited time capacity to produce all the products.\n",
187 | "model.add_constraint(model.sum(production[p]*pro_time[p] for p in products)<=capacity)"
188 | ]
189 | },
190 | {
191 | "cell_type": "markdown",
192 | "metadata": {},
193 | "source": [
194 | "#### 6. Define linear expression\n",
195 | "Defining linear expression is a good practice when using complex or long objective functions. Dividing an expression let you keep track of the values each expression is getting and, in some cases, find formulation problems.\n",
196 | "\n",
197 | "For this example, the objective function is simple, btu we are using linear expressions to show how to build them and use them."
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "execution_count": 23,
203 | "metadata": {},
204 | "outputs": [],
205 | "source": [
206 | "profit_prod = model.sum(production[p]*profit[p] for p in products)"
207 | ]
208 | },
209 | {
210 | "cell_type": "markdown",
211 | "metadata": {},
212 | "source": [
213 | "#### 7. Define the objective function\n",
214 | "The objective function is an important step in your formulation as it is the one that would guide your problem solution. Results might change as the objective function is changed, so be careful when defining it. \n",
215 | "\n",
216 | "For this example, we are try to get the highest profit possible, so we choose the maximization as our objective."
217 | ]
218 | },
219 | {
220 | "cell_type": "code",
221 | "execution_count": 24,
222 | "metadata": {},
223 | "outputs": [],
224 | "source": [
225 | "model.maximize(profit_prod)"
226 | ]
227 | },
228 | {
229 | "cell_type": "markdown",
230 | "metadata": {},
231 | "source": [
232 | "#### 8. Solve your model\n",
233 | "By using the solve() method from the model instance, the optimiaztion motor is called"
234 | ]
235 | },
236 | {
237 | "cell_type": "code",
238 | "execution_count": 25,
239 | "metadata": {},
240 | "outputs": [],
241 | "source": [
242 | "solution=model.solve()"
243 | ]
244 | },
245 | {
246 | "cell_type": "markdown",
247 | "metadata": {},
248 | "source": [
249 | "### Post processing\n",
250 | "Once the optimization model is solved, you can retrieve the results to pritn them."
251 | ]
252 | },
253 | {
254 | "cell_type": "code",
255 | "execution_count": 27,
256 | "metadata": {},
257 | "outputs": [
258 | {
259 | "name": "stdout",
260 | "output_type": "stream",
261 | "text": [
262 | "The maximum profit would be: 4730\n",
263 | "The company needs to produce 50.0 units of product A\n",
264 | "The company needs to produce 17.0 units of product B\n",
265 | "The company needs to produce 99.0 units of product C\n",
266 | "The company needs to produce 20.0 units of product D\n"
267 | ]
268 | }
269 | ],
270 | "source": [
271 | "print('The maximum profit would be: %a' %solution.get_objective_value())\n",
272 | "for p in sorted(products):\n",
273 | " print('The company needs to produce %a units of product %s' %(production[p].solution_value,p))"
274 | ]
275 | }
276 | ],
277 | "metadata": {
278 | "kernelspec": {
279 | "display_name": "Python 3",
280 | "language": "python",
281 | "name": "python3"
282 | },
283 | "language_info": {
284 | "codemirror_mode": {
285 | "name": "ipython",
286 | "version": 3
287 | },
288 | "file_extension": ".py",
289 | "mimetype": "text/x-python",
290 | "name": "python",
291 | "nbconvert_exporter": "python",
292 | "pygments_lexer": "ipython3",
293 | "version": "3.6.8"
294 | }
295 | },
296 | "nbformat": 4,
297 | "nbformat_minor": 2
298 | }
299 |
--------------------------------------------------------------------------------
/Production_Planning/CPLEX_Python/production_df.py:
--------------------------------------------------------------------------------
1 | # --------------------------------------------------------------------------
2 | # Source file provided under Apache License, Version 2.0, January 2004,
3 | # http://www.apache.org/licenses/
4 | # (c) Copyright IBM Corp. 2015, 2018
5 | # --------------------------------------------------------------------------
6 |
7 | """The model aims at minimizing the production cost for a number of products
8 | while satisfying customer demand. Each product can be produced either inside
9 | the company or outside, at a higher cost.
10 |
11 | The inside production is constrained by the company's resources, while outside
12 | production is considered unlimited.
13 |
14 | The model first declares the products and the resources.
15 | The data consists of the description of the products (the demand, the inside
16 | and outside costs, and the resource consumption) and the capacity of the
17 | various resources.
18 |
19 | The variables for this problem are the inside and outside production for each
20 | product.
21 | """
22 |
23 | from docplex.mp.model import Model
24 | from docplex.util.environment import get_environment
25 | import pandas
26 | import pdb
27 | # ----------------------------------------------------------------------------
28 | # Initialize the problem data
29 | # ----------------------------------------------------------------------------
30 | PRODUCTS = [("kluski", 100, 0.6, 0.8),
31 | ("capellini", 200, 0.8, 0.9),
32 | ("fettucine", 300, 0.3, 0.4)]
33 | product_df = pandas.DataFrame(data = PRODUCTS, columns = ['producto', 'demanda', 'costo_interno','costo_externo'])
34 | # resources are a list of simple tuples (name, capacity)
35 | RESOURCES = [("flour", 20),
36 | ("eggs", 40)]
37 | resource_df = pandas.DataFrame(data = RESOURCES, columns = ['recurso','cantidad'])
38 | CONSUMPTIONS = {("kluski", "flour"): 0.5,
39 | ("kluski", "eggs"): 0.2,
40 | ("capellini", "flour"): 0.4,
41 | ("capellini", "eggs"): 0.4,
42 | ("fettucine", "flour"): 0.3,
43 | ("fettucine", "eggs"): 0.6}
44 | consumption_rows = [(key[0],key[1],CONSUMPTIONS[key]) for key in CONSUMPTIONS.keys()]
45 | consumption_df = pandas.DataFrame(data = consumption_rows, columns = ['producto','recurso','consumo'])
46 |
47 | # ----------------------------------------------------------------------------
48 | # Build the model
49 | # ----------------------------------------------------------------------------
50 | def build_production_problem(product_df, resource_df, conumption_df, **kwargs):
51 | """ Takes as input:
52 | - a list of product tuples (name, demand, inside, outside)
53 | - a list of resource tuples (name, capacity)
54 | - a list of consumption tuples (product_name, resource_named, consumed)
55 | """
56 | mdl = Model(name='production', log_output = False, **kwargs)
57 | # --- decision variables ---
58 | product_df['inside'] = mdl.continuous_var_list(
59 | [row.producto for row in product_df.itertuples()],
60 | lb = [0]*len(product_df),
61 | name = 'inside'
62 | )
63 | product_df['outside'] = mdl.continuous_var_list(
64 | [row.producto for row in product_df.itertuples()],
65 | lb = [0]*len(product_df),
66 | name = 'outside'
67 | )
68 | # --- constraints ---
69 | # demand satisfaction
70 | #mdl.add_constraints((mdl.inside_vars[prod] + mdl.outside_vars[prod] >= prod[1], 'ct_demand_%s' % prod[0]) for prod in products)
71 | mdl.add_constraints((row.inside + row.outside >= row.demanda, 'ct_demand_{}'.format(row.producto)) for row in product_df.itertuples())
72 |
73 | # --- resource capacity ---
74 | #mdl.add_constraints((mdl.sum(mdl.inside_vars[p] * consumptions[p[0], res[0]] for p in products) <= res[1],
75 | # 'ct_res_%s' % res[0]) for res in resources)
76 | merge_df = product_df.merge(consumption_df, on = 'producto')
77 | merge_df = merge_df.merge(resource_df, on = 'recurso')
78 | merge_df['consumo_expr'] = merge_df.inside * merge_df.consumo
79 | gb = merge_df.groupby(by = 'recurso').agg({'consumo_expr': mdl.sum, 'cantidad': min}).reset_index()
80 | mdl.add_constraints((row.consumo_expr <= row.cantidad, 'ct_res_{}'.format(row.recurso)) for row in gb.itertuples())
81 | # --- objective ---
82 | mdl.total_inside_cost = mdl.sum(row.inside * row.costo_interno for row in product_df.itertuples())
83 | mdl.add_kpi(mdl.total_inside_cost, "inside cost")
84 | mdl.total_outside_cost = mdl.sum(row.outside * row.costo_externo for row in product_df.itertuples())
85 | mdl.add_kpi(mdl.total_outside_cost, "outside cost")
86 | mdl.minimize(mdl.total_inside_cost + mdl.total_outside_cost)
87 | return mdl
88 |
89 |
90 | def print_production_solution(mdl, product_df):
91 | obj = mdl.objective_value
92 | print("* Production model solved with objective: {:g}".format(obj))
93 | print("* Total inside cost=%g" % mdl.total_inside_cost.solution_value)
94 | for row in product_df.itertuples():
95 | print("Inside production of {product}: {ins_var}".format
96 | (product=row.producto, ins_var=row.inside.solution_value))
97 | print("* Total outside cost=%g" % mdl.total_outside_cost.solution_value)
98 | for row in product_df.itertuples():
99 | print("Outside production of {product}: {out_var}".format
100 | (product=row.producto, out_var=row.outside.solution_value))
101 |
102 |
103 | def build_default_production_problem(**kwargs):
104 | return build_production_problem(PRODUCTS, RESOURCES, CONSUMPTIONS, **kwargs)
105 |
106 | # ----------------------------------------------------------------------------
107 | # Solve the model and display the result
108 | # ----------------------------------------------------------------------------
109 | if __name__ == '__main__':
110 | # Build the model
111 | model = build_production_problem(product_df, resource_df, consumption_df)
112 | model.print_information()
113 | # Solve the model.
114 | if model.solve():
115 | print_production_solution(model, product_df)
116 | # Save the CPLEX solution as "solution.json" program output
117 | with get_environment().get_output_stream("solution.json") as fp:
118 | model.solution.export(fp, "json")
119 | else:
120 | print("Problem has no solution")
--------------------------------------------------------------------------------
/Production_Planning/CPLEX_Python/production_lists.py:
--------------------------------------------------------------------------------
1 | # --------------------------------------------------------------------------
2 | # Source file provided under Apache License, Version 2.0, January 2004,
3 | # http://www.apache.org/licenses/
4 | # (c) Copyright IBM Corp. 2015, 2018
5 | # --------------------------------------------------------------------------
6 |
7 | """The model aims at minimizing the production cost for a number of products
8 | while satisfying customer demand. Each product can be produced either inside
9 | the company or outside, at a higher cost.
10 |
11 | The inside production is constrained by the company's resources, while outside
12 | production is considered unlimited.
13 |
14 | The model first declares the products and the resources.
15 | The data consists of the description of the products (the demand, the inside
16 | and outside costs, and the resource consumption) and the capacity of the
17 | various resources.
18 |
19 | The variables for this problem are the inside and outside production for each
20 | product.
21 | """
22 |
23 | from docplex.mp.model import Model
24 | from docplex.util.environment import get_environment
25 |
26 |
27 | # ----------------------------------------------------------------------------
28 | # Initialize the problem data
29 | # ----------------------------------------------------------------------------
30 | PRODUCTS = [("kluski", 100, 0.6, 0.8),
31 | ("capellini", 200, 0.8, 0.9),
32 | ("fettucine", 300, 0.3, 0.4)]
33 |
34 | # resources are a list of simple tuples (name, capacity)
35 | RESOURCES = [("flour", 20),
36 | ("eggs", 40)]
37 |
38 | CONSUMPTIONS = {("kluski", "flour"): 0.5,
39 | ("kluski", "eggs"): 0.2,
40 | ("capellini", "flour"): 0.4,
41 | ("capellini", "eggs"): 0.4,
42 | ("fettucine", "flour"): 0.3,
43 | ("fettucine", "eggs"): 0.6}
44 |
45 |
46 | # ----------------------------------------------------------------------------
47 | # Build the model
48 | # ----------------------------------------------------------------------------
49 | def build_production_problem(products, resources, consumptions, **kwargs):
50 | """ Takes as input:
51 | - a list of product tuples (name, demand, inside, outside)
52 | - a list of resource tuples (name, capacity)
53 | - a list of consumption tuples (product_name, resource_named, consumed)
54 | """
55 | mdl = Model(name='production', **kwargs)
56 | # --- decision variables ---
57 | mdl.inside_vars = mdl.continuous_var_dict(products, name=lambda p: 'inside_%s' % p[0])
58 | mdl.outside_vars = mdl.continuous_var_dict(products, name=lambda p: 'outside_%s' % p[0])
59 |
60 | # --- constraints ---
61 | # demand satisfaction
62 | mdl.add_constraints((mdl.inside_vars[prod] + mdl.outside_vars[prod] >= prod[1], 'ct_demand_%s' % prod[0]) for prod in products)
63 |
64 | # --- resource capacity ---
65 | mdl.add_constraints((mdl.sum(mdl.inside_vars[p] * consumptions[p[0], res[0]] for p in products) <= res[1],
66 | 'ct_res_%s' % res[0]) for res in resources)
67 |
68 | # --- objective ---
69 | mdl.total_inside_cost = mdl.sum(mdl.inside_vars[p] * p[2] for p in products)
70 | mdl.add_kpi(mdl.total_inside_cost, "inside cost")
71 | mdl.total_outside_cost = mdl.sum(mdl.outside_vars[p] * p[3] for p in products)
72 | mdl.add_kpi(mdl.total_outside_cost, "outside cost")
73 | mdl.minimize(mdl.total_inside_cost + mdl.total_outside_cost)
74 | return mdl
75 |
76 |
77 | def print_production_solution(mdl, products):
78 | obj = mdl.objective_value
79 | print("* Production model solved with objective: {:g}".format(obj))
80 | print("* Total inside cost=%g" % mdl.total_inside_cost.solution_value)
81 | for p in products:
82 | print("Inside production of {product}: {ins_var}".format
83 | (product=p[0], ins_var=mdl.inside_vars[p].solution_value))
84 | print("* Total outside cost=%g" % mdl.total_outside_cost.solution_value)
85 | for p in products:
86 | print("Outside production of {product}: {out_var}".format
87 | (product=p[0], out_var=mdl.outside_vars[p].solution_value))
88 |
89 |
90 | def build_default_production_problem(**kwargs):
91 | return build_production_problem(PRODUCTS, RESOURCES, CONSUMPTIONS, **kwargs)
92 |
93 | # ----------------------------------------------------------------------------
94 | # Solve the model and display the result
95 | # ----------------------------------------------------------------------------
96 | if __name__ == '__main__':
97 | # Build the model
98 | model = build_production_problem(PRODUCTS, RESOURCES, CONSUMPTIONS)
99 | model.print_information()
100 | # Solve the model.
101 | if model.solve():
102 | print_production_solution(model, PRODUCTS)
103 | # Save the CPLEX solution as "solution.json" program output
104 | with get_environment().get_output_stream("solution.json") as fp:
105 | model.solution.export(fp, "json")
106 | else:
107 | print("Problem has no solution")
--------------------------------------------------------------------------------
/Production_Planning/README.md:
--------------------------------------------------------------------------------
1 | # Production Planning Problem
2 |
3 | ## Problem description
4 |
5 |
6 | A company needs to decide their production plan for the next month. They produce four products: A, B, C and D. Each product has a known demand, the production cannot exceed this demand as it would be lost. Moreover, the company has a limited time of 2000 minutes to produce all the products. What should be the production level for each product so that they can maximize their profit.
7 |
8 | | Product | Demand | Profit | Processing time |
9 | |---------|--------|--------|-----------------|
10 | | A | 50 | 40 | 15 |
11 | | B | 70 | 20 | 15 |
12 | | C | 100 | 10 | 5 |
13 | | D | 20 | 70 | 25 |
14 |
15 | ## Video tutorial
16 |
17 | Follow [this link](https://www.youtube.com/watch?v=__4AfV37XVI&list=PL_xEQLGJPHhLxR3GHYxLJSmvLCUyCs3ME) for watching the full tutorial to create a production planning problem using Python and CPLEX.
18 |
19 |
20 |
21 |
22 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
23 |
24 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
25 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
26 |
27 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
28 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
29 |
30 | #### For more information about SmartBP
31 | - [Website](http://www.smart-bp.com)
32 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
33 | - [Follow Us](https://twitter.com/Smart_BP)
34 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
35 | - [YouTube](https://www.youtube.com/c/SmartBP)
36 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Assign workers/Model.ops:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Assign workers/README.md:
--------------------------------------------------------------------------------
1 | # Workers assignment
2 |
3 | For this example, we are going to create a basic project scheduling model. We will take into account worker assignments and costs.
4 |
5 | We consider the following instance:
6 | - We have a project with a list of tasks that need to be performed
7 | - Each task has requirements to be fulfilled by the available workers
8 | - Each worker has different skills and an expertise level needed to fulfill the requirements
9 | - Each worker has a fixed and a variable cost for performing a requirement
10 | - Tasks have precedence behavior; some tasks cannot start before another one starts or ends
11 | - Parent tasks are defined, a parent tasks define the span of a group of tasks
12 |
13 | Download this folder and create a new OPL project in IBM® ILOG CPLEX Optimization Studio
14 |
15 | #### For more information about SmartBP
16 | - [Website](http://www.smart-bp.com)
17 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
18 | - [Follow Us](https://twitter.com/Smart_BP)
19 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
20 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Assign workers/Scheduling-workers.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartBP/Modeling_Training/247c58ef287b26d9d6166e96f2c40f66e4565c44/Project Scheduling/OPL/Assign workers/Scheduling-workers.xlsx
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Assign workers/Workers.mod:
--------------------------------------------------------------------------------
1 | /****************************************************
2 | * ILOG CP Optimizer Training
3 | *
4 | * Project scheduling SOL 2 - Worker assignment
5 | ****************************************************/
6 |
7 | using CP;
8 |
9 | /********
10 | * Data *
11 | ********/
12 |
13 | tuple Task {
14 | key int id;
15 | string name;
16 | int ptMin; // minimum duration
17 | };
18 |
19 | { Task } Tasks = ...;
20 |
21 | tuple hierarchy_data { // hierarchy data
22 | int taskId;
23 | int parentId;
24 | };
25 |
26 | { hierarchy_data } Hierarchy = ...;
27 | { int } Parents = { p.parentId | p in Hierarchy };
28 |
29 | tuple Precedence {
30 | int beforeId;
31 | int afterId;
32 | string type;
33 | int delay;
34 | };
35 |
36 | { Precedence } Precedences = ...;
37 |
38 | tuple Worker {
39 | key int id;
40 | string name;
41 | float fixedCost;
42 | float varCost;
43 | };
44 |
45 | { Worker } Workers = ...;
46 |
47 | tuple Skill {
48 | key int id;
49 | string name;
50 | };
51 |
52 | { Skill } Skills = ...;
53 |
54 | tuple Proficiency {
55 | int workerId;
56 | int skillId;
57 | int level;
58 | };
59 |
60 | { Proficiency } Proficiencies = ...;
61 |
62 | tuple Requirement {
63 | key int id;
64 | int taskId;
65 | };
66 |
67 | { Requirement } Requirements = ...;
68 |
69 | tuple RequiredSkill {
70 | int reqId;
71 | int skillId;
72 | int levelMin;
73 | int levelMax;
74 | };
75 |
76 | { RequiredSkill } RequiredSkills = ...;
77 |
78 | { int } PossibleWorkers[r in Requirements] =
79 | { p.workerId | p in Proficiencies, n in RequiredSkills :
80 | (n.reqId==r.id) &&
81 | (p.skillId==n.skillId) &&
82 | (n.levelMin <= p.level) &&
83 | (p.level <= n.levelMax) };
84 |
85 | tuple Alloc {
86 | int reqId;
87 | int workerId;
88 | int pt;
89 | };
90 |
91 | { Alloc } Allocations = { | r in Requirements, t in Tasks, i in PossibleWorkers[r] : t.id==r.taskId };
92 |
93 | // KPIs
94 | float MakespanWeight = ...;
95 | float FixedWeight = ...;
96 | float VariableWeight = ...;
97 |
98 | int MaxInterval = 10000001;
99 |
100 | /**********************
101 | * Decision variables *
102 | **********************/
103 |
104 | dvar interval task[t in Tasks] size t.ptMin..MaxInterval;
105 | dvar interval alts[a in Allocations] optional;
106 | dvar interval workerSpan[w in Workers] optional;
107 |
108 | /************************
109 | * Decision expressions *
110 | ************************/
111 |
112 | dexpr int makespan = max(t in Tasks) endOf(task[t]);
113 | dexpr int workerTimeSpent[w in Workers] = sum(a in Allocations: a.workerId==w.id) sizeOf(alts[a],0);
114 | dexpr float workersFixedCost = sum(w in Workers) w.fixedCost * presenceOf(workerSpan[w]);
115 | dexpr float workersVariableCost = sum(w in Workers) w.varCost*workerTimeSpent[w];
116 |
117 | /*************
118 | * Objective *
119 | *************/
120 |
121 | minimize MakespanWeight * makespan
122 | + FixedWeight * workersFixedCost
123 | + VariableWeight * workersVariableCost;
124 |
125 | /***************
126 | * Constraints *
127 | ***************/
128 |
129 | subject to {
130 | // Hierarchy structure
131 | forall (t in Tasks : t.id in Parents)
132 | span(task[t], all(i in Hierarchy: i.parentId == t.id) task[]);
133 |
134 | // Precedence constraints
135 | forall (p in Precedences : p.type == "StartsAfterStart")
136 | startBeforeStart(task[], task[], p.delay);
137 | forall (p in Precedences : p.type == "StartsAfterEnd")
138 | endBeforeStart(task[], task[], p.delay);
139 |
140 | // Alternatives of (each requirement must be perfomed by one worker)
141 | forall(r in Requirements)
142 | alternative(task[], all(a in Allocations: a.reqId==r.id) alts[a]);
143 |
144 | // A worker can perform only one task requirement at any point in time
145 | forall(w in Workers)
146 | noOverlap(all(a in Allocations: a.workerId==w.id) alts[a]);
147 |
148 | // Calculate whether each worker is used in the project
149 | forall(w in Workers)
150 | span(workerSpan[w], all(a in Allocations: a.workerId==w.id) alts[a]);
151 |
152 | };
153 |
154 | tuple result{
155 | int taskId;
156 | int start;
157 | int end;
158 | }
159 |
160 | {result} results = { | t in Tasks};
161 |
162 | execute{results};
163 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Assign workers/model data.dat:
--------------------------------------------------------------------------------
1 | SheetConnection file ( "Scheduling-workers.xlsx" );
2 | // Workers data
3 | Workers from SheetRead (file, "Workers!A2:D16");
4 | Skills from SheetRead (file, "Skills!A2:B8");
5 | Proficiencies from SheetRead (file, "Proficiencies!A2:C18");
6 | // Tasks data
7 | Tasks from SheetRead (file, "Tasks!A2:C130");
8 | Hierarchy from SheetRead (file, "Hierarchy!A2:B129");
9 | Precedences from SheetRead (file, "Precedences!A2:D243");
10 | Requirements from SheetRead (file, "Requirements!A2:B182");
11 | RequiredSkills from SheetRead (file, "RequiredSkills!A2:D182");
12 | // KPIs
13 | MakespanWeight from SheetRead (file, "KPIs!B2");
14 | FixedWeight from SheetRead (file, "KPIs!B3");
15 | VariableWeight from SheetRead (file, "KPIs!B4");
16 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Calendars/Calendar.mod:
--------------------------------------------------------------------------------
1 |
2 | using CP;
3 |
4 | /********
5 | * Data *
6 | ********/
7 |
8 | tuple Task {
9 | key int id;
10 | string name;
11 | int ptMin;
12 | };
13 |
14 | { Task } Tasks = ...;
15 |
16 | tuple hierarchy_data { // hierarchy data
17 | int taskId;
18 | int parentId;
19 | };
20 |
21 | { hierarchy_data } Hierarchy = ...;
22 | { int } Parents = { p.parentId | p in Hierarchy };
23 |
24 |
25 | tuple Precedence {
26 | int beforeId;
27 | int afterId;
28 | string type;
29 | int delay;
30 | };
31 |
32 | { Precedence } Precedences = ...;
33 |
34 | tuple Worker {
35 | key int id;
36 | string name;
37 | float fixedCost;
38 | float varCost;
39 | };
40 |
41 | { Worker } Workers = ...;
42 |
43 | tuple Skill {
44 | key int id;
45 | string name;
46 | };
47 |
48 | { Skill } Skills = ...;
49 |
50 | tuple Proficiency {
51 | int workerId;
52 | int skillId;
53 | int level;
54 | };
55 |
56 | { Proficiency } Proficiencies = ...;
57 |
58 | tuple Requirement {
59 | key int id;
60 | int taskId;
61 | };
62 |
63 | { Requirement } Requirements = ...;
64 |
65 | tuple RequiredSkill {
66 | int reqId;
67 | int skillId;
68 | int levelMin;
69 | int levelMax;
70 | };
71 |
72 | { RequiredSkill } RequiredSkills = ...;
73 |
74 | { int } PossibleWorkers[r in Requirements] =
75 | { p.workerId | p in Proficiencies, n in RequiredSkills :
76 | (n.reqId==r.id) &&
77 | (p.skillId==n.skillId) &&
78 | (n.levelMin <= p.level) &&
79 | (p.level <= n.levelMax) };
80 |
81 | tuple Alloc {
82 | int reqId;
83 | int workerId;
84 | int pt;
85 | };
86 |
87 | { Alloc } Allocations = { | r in Requirements, t in Tasks, i in PossibleWorkers[r] : t.id==r.taskId };
88 |
89 | tuple WorkerBreak {
90 | int workerId;
91 | int start;
92 | int end;
93 | };
94 |
95 | { WorkerBreak } WorkerBreaks = ...;
96 |
97 | // KPIs
98 | float MakespanWeight = ...;
99 | float FixedWeight = ...;
100 | float VariableWeight = ...;
101 |
102 | int MaxInterval = 10000001;
103 |
104 | tuple Step {
105 | int value;
106 | key int time;
107 | };
108 | sorted {Step} Steps[w in Workers] =
109 | { <100, b.start> | b in WorkerBreaks : b.workerId==w.id } union
110 | { <0, b.end> | b in WorkerBreaks : b.workerId==w.id };
111 |
112 | stepFunction breaks[w in Workers] = stepwise (s in Steps[w]) { s.value -> s.time; 100 };
113 |
114 | /**********************
115 | * Decision variables *
116 | **********************/
117 |
118 | dvar interval task[t in Tasks] size t.ptMin..MaxInterval;
119 | dvar interval alts[a in Allocations] optional size a.pt..MaxInterval intensity breaks[];
120 | dvar interval workerSpan[w in Workers] optional;
121 |
122 | /************************
123 | * Decision expressions *
124 | ************************/
125 |
126 | dexpr int makespan = max(t in Tasks) endOf(task[t]);
127 | dexpr int workerTimeSpent[w in Workers] = sum(a in Allocations: a.workerId==w.id) sizeOf(alts[a],0);
128 | dexpr float workersFixedCost = sum(w in Workers) w.fixedCost * presenceOf(workerSpan[w]);
129 | dexpr float workersVariableCost = sum(w in Workers) w.varCost*workerTimeSpent[w];
130 |
131 | /*************
132 | * Objective *
133 | *************/
134 |
135 | minimize MakespanWeight * makespan
136 | + FixedWeight * workersFixedCost
137 | + VariableWeight * workersVariableCost;
138 |
139 | /***************
140 | * Constraints *
141 | ***************/
142 |
143 | subject to {
144 | // Work breakdown structure
145 | forall (t in Tasks : t.id in Parents)
146 | span(task[t], all(i in Hierarchy: i.parentId == t.id) task[]);
147 |
148 | // Precedence constraints
149 | forall (p in Precedences : p.type == "StartsAfterStart")
150 | startBeforeStart(task[], task[], p.delay);
151 | forall (p in Precedences : p.type == "StartsAfterEnd")
152 | endBeforeStart(task[], task[], p.delay);
153 |
154 | // Alternatives of workers who can fulfil task requirement (each requirement must be filled by one worker)
155 | forall(r in Requirements)
156 | alternative(task[], all(a in Allocations: a.reqId==r.id) alts[a]);
157 |
158 | // Calculate whether each worker is used in the project using span constraint
159 | forall(w in Workers)
160 | span(workerSpan[w], all(a in Allocations: a.workerId==w.id) alts[a]);
161 |
162 | // A worker can fill only one task requirement at any point in time
163 | forall(w in Workers)
164 | noOverlap(all(a in Allocations: a.workerId==w.id) alts[a]);
165 |
166 | };
167 |
168 | tuple result_task{
169 | int taskId;
170 | int start;
171 | int end;
172 | }
173 |
174 | {result_task} results_tasks = { | t in Tasks};
175 |
176 | tuple result_alloc{
177 | int reqId;
178 | int taskId;
179 | int workerId;
180 | int start;
181 | int end;
182 | }
183 |
184 | {result_alloc} results_allocs = { | r in Requirements, a in Allocations: r.id == a.reqId};
185 |
186 | tuple result_worker{
187 | int workerId;
188 | string workerName;
189 | int start;
190 | int end;
191 | }
192 |
193 | {result_worker} results_workers = { | w in Workers};
194 |
195 | tuple result_task_date{
196 | int taskId;
197 | string start;
198 | string end;
199 | }
200 | {result_task_date} result_task_dates = {};
201 |
202 | tuple result_alloc_date{
203 | int reqId;
204 | int taskId;
205 | int workerId;
206 | string start;
207 | string end;
208 | }
209 | {result_alloc_date} result_alloc_dates = {};
210 |
211 | tuple result_worker_date{
212 | int workerId;
213 | string workerName;
214 | string start;
215 | string end;
216 | }
217 | {result_worker_date} result_worker_dates = {};
218 |
219 | tuple workerTime{
220 | int workerId;
221 | string workerName;
222 | int duration;
223 | }
224 |
225 | {workerTime} workerTimes = {|w in Workers};
226 |
227 | execute{
228 | workerTimes;
229 | for(var t in results_tasks){
230 | var start = t.start;
231 | var end = t.end;
232 | var start_date = new Date(2021, 1, 5, 0, start, 0);
233 | var end_date = new Date(2021, 1, 5, 0, end, 0);
234 | result_task_dates.add(t.taskId, String(start_date), String(end_date));
235 | }
236 |
237 | for(var t in results_allocs){
238 | var start = t.start;
239 | var end = t.end;
240 | var start_date = new Date(2021, 1, 5, 0, start, 0);
241 | var end_date = new Date(2021, 1, 5, 0, end, 0);
242 | result_alloc_dates.add(t.reqId, t.taskId, t.workerId, String(start_date), String(end_date));
243 | }
244 |
245 | for(var t in results_workers){
246 | var start = t.start;
247 | var end = t.end;
248 | var start_date = new Date(2021, 1, 5, 0, start, 0);
249 | var end_date = new Date(2021, 1, 5, 0, end, 0);
250 | result_worker_dates.add(t.workerId, t.workerName, String(start_date), String(end_date));
251 | }
252 | };
253 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Calendars/Model data.dat:
--------------------------------------------------------------------------------
1 | SheetConnection file ( "Scheduling-calendar.xlsx" );
2 | // Workers data
3 | Workers from SheetRead (file, "Workers!A2:D16");
4 | WorkerBreaks from SheetRead (file, "WorkerBreaks!A2:C8");
5 | Skills from SheetRead (file, "Skills!A2:B8");
6 | Proficiencies from SheetRead (file, "Proficiencies!A2:C18");
7 | // Tasks data
8 | Tasks from SheetRead (file, "Tasks!A2:C130");
9 | Hierarchy from SheetRead (file, "Hierarchy!A2:B129");
10 | Precedences from SheetRead (file, "Precedences!A2:D243");
11 | Requirements from SheetRead (file, "Requirements!A2:B182");
12 | RequiredSkills from SheetRead (file, "RequiredSkills!A2:D182");
13 | // KPIs
14 | MakespanWeight from SheetRead (file, "KPIs!B2");
15 | FixedWeight from SheetRead (file, "KPIs!B3");
16 | VariableWeight from SheetRead (file, "KPIs!B4");
17 |
18 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Calendars/Model.ops:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Calendars/README.md:
--------------------------------------------------------------------------------
1 | # Workers assignment
2 |
3 | For this example, we are going to create a basic project scheduling model. We will take into account worker assignments and costs.
4 |
5 | We consider the following instance:
6 | - We have a project with a list of tasks that need to be performed
7 | - Each task has requirements to be fulfilled by the available workers
8 | - Each worker has different skills and an expertise level needed to fulfill the requirements
9 | - Each worker has a fixed and a variable cost for performing a requirement
10 | - Tasks have precedence behavior; some tasks cannot start before another one starts or ends
11 | - Parent tasks are defined, a parent tasks define the span of a group of tasks
12 | -Some workers have scheduled breaks that must be respected
13 |
14 | Download this folder and create a new OPL project in IBM® ILOG CPLEX Optimization Studio
15 |
16 | #### For more information about SmartBP
17 | - [Website](http://www.smart-bp.com)
18 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
19 | - [Follow Us](https://twitter.com/Smart_BP)
20 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
21 |
--------------------------------------------------------------------------------
/Project Scheduling/OPL/Calendars/Scheduling-calendar.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartBP/Modeling_Training/247c58ef287b26d9d6166e96f2c40f66e4565c44/Project Scheduling/OPL/Calendars/Scheduling-calendar.xlsx
--------------------------------------------------------------------------------
/Project Scheduling/OPL/README.md:
--------------------------------------------------------------------------------
1 | # Project Scheduling - OPL
2 |
3 | Projects found in this folder are all applied to Project Scheduling examples. They were developed in IBM® ILOG CPLEX Optimization Studio using OPL language.
4 |
5 |
6 |
7 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
8 |
9 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
10 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
11 |
12 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
13 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
14 |
15 | #### For more information about SmartBP
16 | - [Website](http://www.smart-bp.com)
17 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
18 | - [Follow Us](https://twitter.com/Smart_BP)
19 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
20 |
--------------------------------------------------------------------------------
/Project Scheduling/README.md:
--------------------------------------------------------------------------------
1 | # Project Scheduling
2 |
3 | Project Scheduling problems are problems that require the optimal use of time and resources to a minimal cost.
4 |
5 | The basic model defines what activity needs to be done, which resource will do the work and the timeframe in which that work must be done.
6 |
7 | For this kind of problem, we usually have:
8 | - List of tasks (activities)
9 | - List of resources
10 | - Timeframes
11 |
12 | For more detailed decision making we have:
13 | - Precedences
14 | - Skills needed to perform an activity
15 | - Skilled workers
16 | - Due dates
17 | - ...
18 |
19 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
20 |
21 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
22 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
23 |
24 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
25 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
26 |
27 | ## IBM Watson Studio
28 |
29 | [IBM Watson Studio](https://www.ibm.com/cloud/watson-studio) is a platform software for data science. The advantage of using Watson is having a workspace that includes multiple collaboration and open-source tools such as RStudio, Spark and Python, all in an integrated environment.
30 |
31 | As you create a new project, you can add multiple collaborators, all having access to various predictive and prescriptive analytics models. Data can be accessed through Watson Data Platform, on-premise or on the cloud.
32 |
33 |
34 | #### For more information about SmartBP
35 | - [Website](http://www.smart-bp.com)
36 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
37 | - [Follow Us](https://twitter.com/Smart_BP)
38 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
39 |
--------------------------------------------------------------------------------
/Project Scheduling/Watson/Assign workers - watson code.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Project Scheduling\n",
8 | "## Workers assignment\n",
9 | "\n",
10 | "For this example, we are going to create a basic project scheduling model. We will take into account worker assignments and costs.\n",
11 | "\n",
12 | "We consider the following instance:\n",
13 | "- We have a project with a list of tasks that need to be performed \n",
14 | "- Each task has requirements to be fulfilled by the available workers\n",
15 | "- Each worker has different skills and an expertise level needed to fulfill the requirements\n",
16 | "- Each worker has a fixed and a variable cost for performing a requirement\n",
17 | "- Tasks have precedence behavior; some tasks cannot start before another one starts or ends\n",
18 | "- Parent tasks are defined, a parent tasks define the span of a group of tasks\n",
19 | "\n",
20 | "## IBM Watson Studio\n",
21 | "\n",
22 | "IBM Watson Studio is a platform software for data science. The advantage of using Watson is having a workspace that includes multiple collaboration and open-source tools such as RStudio, Spark and Python, all in an integrated environment. \n",
23 | "\n",
24 | "As you create a new project, you can add multiple collaborators, all having access to various predictive and prescriptive analytics models. Data can be accessed through Watson Data Platform, on-premise or on the cloud.\n",
25 | "\n",
26 | "For this example, we are creating a new project, loading data files and creating a Decision Optimization (DO) Experiment.\n",
27 | "\n",
28 | "## Source code\n",
29 | "\n",
30 | "In [Assign workers](https://github.com/SmartBP/Modeling_Training/blob/master/Project%20Scheduling/Watson/Assign%20workers%20-%20watson%20instructions.ipynb) you can find step-to-step instructions to create a project and a DO experiment to solve the workers assignment problem. In this notebook you will find the OPL code for the optimization model and the JSON file script to create the gantt diagram.\n",
31 | "\n",
32 | "### OPL code \n",
33 | "\n",
34 | "Here you can find the source code for the workers assignment problem.\n"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": null,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": [
43 | "using CP;\n",
44 | " \n",
45 | "/********\n",
46 | " * Data *\n",
47 | " ********/\n",
48 | "\n",
49 | "tuple Task {\n",
50 | " key int id;\n",
51 | " string name;\n",
52 | " int ptMin; // minimum duration\n",
53 | "};\n",
54 | "\n",
55 | "{ Task } Tasks = ...;\n",
56 | "\n",
57 | "tuple hierarchy_data { // hierarchy data\n",
58 | " int taskId;\n",
59 | " int parentId;\n",
60 | "};\n",
61 | "\n",
62 | "{ hierarchy_data } Hierarchy = ...;\n",
63 | "{ int } Parents = { p.parentId | p in Hierarchy };\n",
64 | "\n",
65 | "tuple Precedence {\n",
66 | " int beforeId;\n",
67 | " int afterId;\n",
68 | " string type;\n",
69 | " int delay;\n",
70 | "};\n",
71 | "\n",
72 | "{ Precedence } Precedences = ...;\n",
73 | "\n",
74 | "tuple Worker {\n",
75 | " key int id;\n",
76 | " string name;\n",
77 | " float fixedCost;\n",
78 | " float varCost;\n",
79 | "};\n",
80 | "\n",
81 | "{ Worker } Workers = ...;\n",
82 | "\n",
83 | "tuple Skill {\n",
84 | " key int id;\n",
85 | " string name;\n",
86 | "};\n",
87 | "\n",
88 | "{ Skill } Skills = ...;\n",
89 | "\n",
90 | "tuple Proficiency {\n",
91 | " int workerId;\n",
92 | " int skillId;\n",
93 | " int level;\n",
94 | "};\n",
95 | " \n",
96 | "{ Proficiency } Proficiencies = ...;\n",
97 | "\n",
98 | "tuple Requirement {\n",
99 | " key int id;\n",
100 | " int taskId;\n",
101 | "};\n",
102 | "\n",
103 | "{ Requirement } Requirements = ...;\n",
104 | "\n",
105 | "tuple RequiredSkill {\n",
106 | " int reqId;\n",
107 | " int skillId;\n",
108 | " int levelMin;\n",
109 | " int levelMax;\n",
110 | "};\n",
111 | "\n",
112 | "{ RequiredSkill } RequiredSkills = ...;\n",
113 | "\n",
114 | "{ int } PossibleWorkers[r in Requirements] = \n",
115 | " { p.workerId | p in Proficiencies, n in RequiredSkills : \n",
116 | " (n.reqId==r.id) && \n",
117 | " (p.skillId==n.skillId) && \n",
118 | " (n.levelMin <= p.level) && \n",
119 | " (p.level <= n.levelMax) };\n",
120 | "\n",
121 | "tuple Alloc {\n",
122 | " int reqId;\n",
123 | " int workerId;\n",
124 | " int pt;\n",
125 | "};\n",
126 | "\n",
127 | "{ Alloc } Allocations = { | r in Requirements, t in Tasks, i in PossibleWorkers[r] : t.id==r.taskId };\n",
128 | "\n",
129 | "// KPIs\n",
130 | "tuple kpi{\n",
131 | " string kpi;\n",
132 | " float value; \n",
133 | "}\n",
134 | "\n",
135 | "{kpi} KPIs = ...;\n",
136 | "{string} kpi_name = {p |
in KPIs};\n",
137 | "float kpi_value[kpi_name] = [p:v |
in KPIs];\n",
138 | "float MakespanWeight = kpi_value[\"Makespan\"];\n",
139 | "float FixedWeight = kpi_value[\"WorkersFixed\"];\n",
140 | "float VariableWeight = kpi_value[\"WorkersProportional\"];\n",
141 | "\n",
142 | "int MaxInterval = 10000001;\n",
143 | "\n",
144 | "execute CPX_PARAMS{\n",
145 | " cp.param.timeLimit = 60;\n",
146 | " cp.param.TemporalRelaxation = \"Off\";\n",
147 | "};\n",
148 | "\n",
149 | "\n",
150 | "/**********************\n",
151 | " * Decision variables *\n",
152 | " **********************/\n",
153 | " \n",
154 | "dvar interval task[t in Tasks] size t.ptMin..MaxInterval;\n",
155 | "dvar interval alts[a in Allocations] optional;\n",
156 | "dvar interval workerSpan[w in Workers] optional;\n",
157 | "\n",
158 | "/************************\n",
159 | " * Decision expressions *\n",
160 | " ************************/\n",
161 | " \n",
162 | "dexpr int makespan = max(t in Tasks) endOf(task[t]);\n",
163 | "dexpr int workerTimeSpent[w in Workers] = sum(a in Allocations: a.workerId==w.id) sizeOf(alts[a],0);\n",
164 | "dexpr float workersFixedCost = sum(w in Workers) w.fixedCost * presenceOf(workerSpan[w]); \n",
165 | "dexpr float workersVariableCost = sum(w in Workers) w.varCost*workerTimeSpent[w];\n",
166 | "\n",
167 | "/*************\n",
168 | " * Objective *\n",
169 | " *************/\n",
170 | " \n",
171 | "minimize MakespanWeight * makespan \n",
172 | " + FixedWeight * workersFixedCost \n",
173 | " + VariableWeight * workersVariableCost;\n",
174 | "\n",
175 | "/***************\n",
176 | " * Constraints *\n",
177 | " ***************/\n",
178 | " \n",
179 | "subject to { \n",
180 | " // Hierarchy structure\n",
181 | " forall (t in Tasks : t.id in Parents)\n",
182 | " span(task[t], all(i in Hierarchy: i.parentId == t.id) task[]); \n",
183 | " \n",
184 | " // Precedence constraints\n",
185 | " forall (p in Precedences : p.type == \"StartsAfterStart\") \n",
186 | " startBeforeStart(task[], task[], p.delay);\n",
187 | " forall (p in Precedences : p.type == \"StartsAfterEnd\") \n",
188 | " endBeforeStart(task[], task[], p.delay);\n",
189 | " \n",
190 | " // Alternatives of (each requirement must be perfomed by one worker)\n",
191 | " forall(r in Requirements)\n",
192 | " alternative(task[], all(a in Allocations: a.reqId==r.id) alts[a]);\n",
193 | "\n",
194 | " // A worker can perform only one task requirement at any point in time\n",
195 | " forall(w in Workers)\n",
196 | " noOverlap(all(a in Allocations: a.workerId==w.id) alts[a]);\n",
197 | " \n",
198 | " // Calculate whether each worker is used in the project\n",
199 | " forall(w in Workers)\n",
200 | " span(workerSpan[w], all(a in Allocations: a.workerId==w.id) alts[a]);\n",
201 | " \n",
202 | "};\n",
203 | "\n",
204 | "\n",
205 | "tuple result_task{\n",
206 | " int taskId;\n",
207 | " int start;\n",
208 | " int end; \n",
209 | "} \n",
210 | "\n",
211 | "{result_task} results_tasks = { | t in Tasks};\n",
212 | "\n",
213 | "tuple result_alloc{\n",
214 | " int reqId;\n",
215 | " int taskId;\n",
216 | " int workerId;\n",
217 | " int start;\n",
218 | " int end; \n",
219 | "} \n",
220 | "\n",
221 | "{result_alloc} results_allocs = { | r in Requirements, a in Allocations: r.id == a.reqId};\n",
222 | "\n",
223 | "tuple result_worker{\n",
224 | " int workerId;\n",
225 | " string workerName;\n",
226 | " int start;\n",
227 | " int end; \n",
228 | "} \n",
229 | "\n",
230 | "{result_worker} results_workers = { | w in Workers};\n",
231 | "\n",
232 | "tuple result_task_date{\n",
233 | " int taskId;\n",
234 | " string start;\n",
235 | " string end; \n",
236 | "} \n",
237 | "{result_task_date} result_task_dates = {};\n",
238 | "\n",
239 | "tuple result_alloc_date{\n",
240 | " int reqId;\n",
241 | " int taskId;\n",
242 | " int workerId;\n",
243 | " string start;\n",
244 | " string end; \n",
245 | "}\n",
246 | "{result_alloc_date} result_alloc_dates = {};\n",
247 | "\n",
248 | "tuple result_worker_date{\n",
249 | " int workerId;\n",
250 | " string workerName;\n",
251 | " string start;\n",
252 | " string end; \n",
253 | "}\n",
254 | "{result_worker_date} result_worker_dates = {};\n",
255 | "\n",
256 | "execute{\n",
257 | " for(var t in results_tasks){\n",
258 | " var start = t.start;\n",
259 | " var end = t.end;\n",
260 | " var start_date = new Date(2021, 0, 1, 0, start, 0, 0);\n",
261 | " var end_date = new Date(2021, 0, 1, 0, end, 0, 0);\n",
262 | " result_task_dates.add(t.taskId, start_date.toString(), end_date.toString());\n",
263 | " }\n",
264 | " \n",
265 | " for(var t in results_allocs){\n",
266 | " var start = t.start;\n",
267 | " var end = t.end;\n",
268 | " if(start+end > 0){\n",
269 | " var start_date = new Date(2021, 0, 1, 0, start, 0, 0);\n",
270 | " var end_date = new Date(2021, 0, 1, 0, end, 0, 0);\n",
271 | " result_alloc_dates.add(t.reqId, t.taskId, t.workerId, start_date.toString(), end_date.toString());\n",
272 | " }\n",
273 | " } \n",
274 | "\n",
275 | " for(var t in results_workers){\n",
276 | " var start = t.start;\n",
277 | " var end = t.end;\n",
278 | " if(start+end > 0){\n",
279 | " var start_date = new Date(2021, 0, 1, 0, start, 0, 0);\n",
280 | " var end_date = new Date(2021, 0, 1, 0, end, 0, 0);\n",
281 | " result_worker_dates.add(t.workerId, t.workerName, start_date.toString(), end_date.toString());\n",
282 | " }\n",
283 | " } \n",
284 | "};\n"
285 | ]
286 | },
287 | {
288 | "cell_type": "markdown",
289 | "metadata": {},
290 | "source": [
291 | "### JSON file\n",
292 | "Here you can find the JSON file to create the gantt diagram in watson"
293 | ]
294 | },
295 | {
296 | "cell_type": "code",
297 | "execution_count": null,
298 | "metadata": {},
299 | "outputs": [],
300 | "source": [
301 | "{\n",
302 | " \"name\": \"\",\n",
303 | " \"type\": \"Gantt\",\n",
304 | " \"props\": {\n",
305 | " \"container\": \"\",\n",
306 | " \"data\": [\n",
307 | " \"Workers\",\n",
308 | " \"result_alloc_dates\"\n",
309 | " ],\n",
310 | " \"spec\": {\n",
311 | " \"resources\": {\n",
312 | " \"data\": \"Workers\",\n",
313 | " \"id\": \"id\",\n",
314 | " \"name\": \"name\"\n",
315 | " },\n",
316 | " \"activities\": {\n",
317 | " \"data\": \"result_alloc_dates\",\n",
318 | " \"id\": \"reqId\",\n",
319 | " \"name\": \"taskId\",\n",
320 | " \"start\": \"start\",\n",
321 | " \"end\": \"end\"\n",
322 | " },\n",
323 | " \"reservations\": {\n",
324 | " \"data\": \"result_alloc_dates\",\n",
325 | " \"activity\": \"reqId\",\n",
326 | " \"resource\": \"workerId\"\n",
327 | " },\n",
328 | " \"constraints\": {},\n",
329 | " \"dateFormat\": \"MM/dd/yyyy HH:mm:ss SSS\"\n",
330 | " },\n",
331 | " \"search\": \"\"\n",
332 | " }\n",
333 | "}"
334 | ]
335 | }
336 | ],
337 | "metadata": {
338 | "kernelspec": {
339 | "display_name": "Python 3",
340 | "language": "python",
341 | "name": "python3"
342 | },
343 | "language_info": {
344 | "codemirror_mode": {
345 | "name": "ipython",
346 | "version": 3
347 | },
348 | "file_extension": ".py",
349 | "mimetype": "text/x-python",
350 | "name": "python",
351 | "nbconvert_exporter": "python",
352 | "pygments_lexer": "ipython3",
353 | "version": "3.7.7"
354 | }
355 | },
356 | "nbformat": 4,
357 | "nbformat_minor": 4
358 | }
359 |
--------------------------------------------------------------------------------
/Project Scheduling/Watson/Calendar(scheduled breaks) - watson code.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Project Scheduling\n",
8 | "## Calendar problem - scheduled breaks\n",
9 | "\n",
10 | "For this example, we are going to create a basic project scheduling model. We will take into account worker assignments and costs.\n",
11 | "\n",
12 | "We consider the following instance:\n",
13 | "- We have a project with a list of tasks that need to be performed \n",
14 | "- Each task has requirements to be fulfilled by the available workers\n",
15 | "- Each worker has different skills and an expertise level needed to fulfill the requirements\n",
16 | "- Each worker has a fixed and a variable cost for performing a requirement\n",
17 | "- Tasks have precedence behavior; some tasks cannot start before another one starts or ends\n",
18 | "- Parent tasks are defined, a parent tasks define the span of a group of tasks\n",
19 | "- Some workers have scheduled breaks that must be respected\n",
20 | "\n",
21 | "## IBM Watson Studio\n",
22 | "\n",
23 | "IBM Watson Studio is a platform software for data science. The advantage of using Watson is having a workspace that includes multiple collaboration and open-source tools such as RStudio, Spark and Python, all in an integrated environment. \n",
24 | "\n",
25 | "As you create a new project, you can add multiple collaborators, all having access to various predictive and prescriptive analytics models. Data can be accessed through Watson Data Platform, on-premise or on the cloud.\n",
26 | "\n",
27 | "For this example, we are creating a new project, loading data files and creating a Decision Optimization (DO) Experiment.\n",
28 | "\n",
29 | "## Source code\n",
30 | "\n",
31 | "In [Assign workers - watson instructions](https://github.com/SmartBP/Modeling_Training/blob/master/Project%20Scheduling/Watson/Assign%20workers%20-%20watson%20instructions.ipynb) you can find step-to-step instructions to create a project and a DO experiment to solve the project scheduling problems. In this notebook you will find the OPL code for the optimization model and the JSON file script to create the gantt diagram.\n",
32 | "\n",
33 | "### OPL code \n",
34 | "\n",
35 | "Here you can find the source code for the calendar problem - it takes into account scheduled breaks for the workers.\n"
36 | ]
37 | },
38 | {
39 | "cell_type": "code",
40 | "execution_count": null,
41 | "metadata": {},
42 | "outputs": [],
43 | "source": [
44 | "\n",
45 | "using CP;\n",
46 | " \n",
47 | "/********\n",
48 | " * Data *\n",
49 | " ********/\n",
50 | "\n",
51 | "tuple Task {\n",
52 | " key int id;\n",
53 | " string name;\n",
54 | " int ptMin; // minimum duration\n",
55 | "};\n",
56 | "\n",
57 | "{ Task } Tasks = ...;\n",
58 | "\n",
59 | "tuple hierarchy_data { // hierarchy data\n",
60 | " int taskId;\n",
61 | " int parentId;\n",
62 | "};\n",
63 | "\n",
64 | "{ hierarchy_data } Hierarchy = ...;\n",
65 | "{ int } Parents = { p.parentId | p in Hierarchy };\n",
66 | "\n",
67 | "tuple Precedence {\n",
68 | " int beforeId;\n",
69 | " int afterId;\n",
70 | " string type;\n",
71 | " int delay;\n",
72 | "};\n",
73 | "\n",
74 | "{ Precedence } Precedences = ...;\n",
75 | "\n",
76 | "tuple Worker {\n",
77 | " key int id;\n",
78 | " string name;\n",
79 | " float fixedCost;\n",
80 | " float varCost;\n",
81 | "};\n",
82 | "\n",
83 | "{ Worker } Workers = ...;\n",
84 | "\n",
85 | "tuple Skill {\n",
86 | " key int id;\n",
87 | " string name;\n",
88 | "};\n",
89 | "\n",
90 | "{ Skill } Skills = ...;\n",
91 | "\n",
92 | "tuple Proficiency {\n",
93 | " int workerId;\n",
94 | " int skillId;\n",
95 | " int level;\n",
96 | "};\n",
97 | " \n",
98 | "{ Proficiency } Proficiencies = ...;\n",
99 | "\n",
100 | "tuple Requirement {\n",
101 | " key int id;\n",
102 | " int taskId;\n",
103 | "};\n",
104 | "\n",
105 | "{ Requirement } Requirements = ...;\n",
106 | "\n",
107 | "tuple RequiredSkill {\n",
108 | " int reqId;\n",
109 | " int skillId;\n",
110 | " int levelMin;\n",
111 | " int levelMax;\n",
112 | "};\n",
113 | "\n",
114 | "{ RequiredSkill } RequiredSkills = ...;\n",
115 | "\n",
116 | "{ int } PossibleWorkers[r in Requirements] = \n",
117 | " { p.workerId | p in Proficiencies, n in RequiredSkills : \n",
118 | " (n.reqId==r.id) && \n",
119 | " (p.skillId==n.skillId) && \n",
120 | " (n.levelMin <= p.level) && \n",
121 | " (p.level <= n.levelMax) };\n",
122 | "\n",
123 | "tuple Alloc {\n",
124 | " int reqId;\n",
125 | " int workerId;\n",
126 | " int pt;\n",
127 | "};\n",
128 | "\n",
129 | "{ Alloc } Allocations = { | r in Requirements, t in Tasks, i in PossibleWorkers[r] : t.id==r.taskId };\n",
130 | "\n",
131 | "// KPIs\n",
132 | "tuple kpi{\n",
133 | " string kpi;\n",
134 | " float value; \n",
135 | "}\n",
136 | "\n",
137 | "{kpi} KPIs = ...;\n",
138 | "{string} kpi_name = {p |
in KPIs};\n",
139 | "float kpi_value[kpi_name] = [p:v |
in KPIs];\n",
140 | "float MakespanWeight = kpi_value[\"Makespan\"];\n",
141 | "float FixedWeight = kpi_value[\"WorkersFixed\"];\n",
142 | "float VariableWeight = kpi_value[\"WorkersProportional\"];\n",
143 | "\n",
144 | "int MaxInterval = 10000001;\n",
145 | "\n",
146 | "execute CPX_PARAMS{\n",
147 | " cp.param.timeLimit = 60;\n",
148 | " cp.param.TemporalRelaxation = \"Off\";\n",
149 | "};\n",
150 | "\n",
151 | "/**********************\n",
152 | " * Decision variables *\n",
153 | " **********************/\n",
154 | " \n",
155 | "dvar interval task[t in Tasks] size t.ptMin..MaxInterval;\n",
156 | "dvar interval alts[a in Allocations] optional;\n",
157 | "dvar interval workerSpan[w in Workers] optional;\n",
158 | "\n",
159 | "/************************\n",
160 | " * Decision expressions *\n",
161 | " ************************/\n",
162 | " \n",
163 | "dexpr int makespan = max(t in Tasks) endOf(task[t]);\n",
164 | "dexpr int workerTimeSpent[w in Workers] = sum(a in Allocations: a.workerId==w.id) sizeOf(alts[a],0);\n",
165 | "dexpr float workersFixedCost = sum(w in Workers) w.fixedCost * presenceOf(workerSpan[w]); \n",
166 | "dexpr float workersVariableCost = sum(w in Workers) w.varCost*workerTimeSpent[w];\n",
167 | "\n",
168 | "/*************\n",
169 | " * Objective *\n",
170 | " *************/\n",
171 | " \n",
172 | "minimize MakespanWeight * makespan \n",
173 | " + FixedWeight * workersFixedCost \n",
174 | " + VariableWeight * workersVariableCost;\n",
175 | "\n",
176 | "/***************\n",
177 | " * Constraints *\n",
178 | " ***************/\n",
179 | " \n",
180 | "subject to { \n",
181 | " // Hierarchy structure\n",
182 | " forall (t in Tasks : t.id in Parents)\n",
183 | " span(task[t], all(i in Hierarchy: i.parentId == t.id) task[]); \n",
184 | " \n",
185 | " // Precedence constraints\n",
186 | " forall (p in Precedences : p.type == \"StartsAfterStart\") \n",
187 | " startBeforeStart(task[], task[], p.delay);\n",
188 | " forall (p in Precedences : p.type == \"StartsAfterEnd\") \n",
189 | " endBeforeStart(task[], task[], p.delay);\n",
190 | " \n",
191 | " // Alternatives of (each requirement must be perfomed by one worker)\n",
192 | " forall(r in Requirements)\n",
193 | " alternative(task[], all(a in Allocations: a.reqId==r.id) alts[a]);\n",
194 | "\n",
195 | " // A worker can perform only one task requirement at any point in time\n",
196 | " forall(w in Workers)\n",
197 | " noOverlap(all(a in Allocations: a.workerId==w.id) alts[a]);\n",
198 | " \n",
199 | " // Calculate whether each worker is used in the project\n",
200 | " forall(w in Workers)\n",
201 | " span(workerSpan[w], all(a in Allocations: a.workerId==w.id) alts[a]);\n",
202 | " \t\n",
203 | "};\n",
204 | "\n",
205 | "tuple result_task{\n",
206 | " int taskId;\n",
207 | " int start;\n",
208 | " int end; \n",
209 | "} \n",
210 | "\n",
211 | "{result_task} results_tasks = { | t in Tasks};\n",
212 | "\n",
213 | "tuple result_alloc{\n",
214 | " int reqId;\n",
215 | " int taskId;\n",
216 | " int workerId;\n",
217 | " int start;\n",
218 | " int end; \n",
219 | "} \n",
220 | "\n",
221 | "{result_alloc} results_allocs = { | r in Requirements, a in Allocations: r.id == a.reqId};\n",
222 | "\n",
223 | "tuple result_worker{\n",
224 | " int workerId;\n",
225 | " string workerName;\n",
226 | " int start;\n",
227 | " int end; \n",
228 | "} \n",
229 | "\n",
230 | "{result_worker} results_workers = { | w in Workers};\n",
231 | "\n",
232 | "tuple result_task_date{\n",
233 | " int taskId;\n",
234 | " string start;\n",
235 | " string end; \n",
236 | "} \n",
237 | "{result_task_date} result_task_dates = {};\n",
238 | "\n",
239 | "tuple result_alloc_date{\n",
240 | " int reqId;\n",
241 | " int taskId;\n",
242 | " int workerId;\n",
243 | " string start;\n",
244 | " string end; \n",
245 | "}\n",
246 | "{result_alloc_date} result_alloc_dates = {};\n",
247 | "\n",
248 | "tuple result_worker_date{\n",
249 | " int workerId;\n",
250 | " string workerName;\n",
251 | " string start;\n",
252 | " string end; \n",
253 | "}\n",
254 | "{result_worker_date} result_worker_dates = {};\n",
255 | "\n",
256 | "tuple workerTime{\n",
257 | " int workerId;\n",
258 | " string workerName;\n",
259 | " int duration;\n",
260 | "}\n",
261 | "\n",
262 | "{workerTime} workerTimes = {|w in Workers};\n",
263 | "\n",
264 | "execute{\n",
265 | " for(var t in results_tasks){\n",
266 | " var start = t.start;\n",
267 | " var end = t.end;\n",
268 | " var start_date = new Date(2021, 0, 1, 0, start, 0, 0);\n",
269 | " var end_date = new Date(2021, 0, 1, 0, end, 0, 0);\n",
270 | " result_task_dates.add(t.taskId, start_date.toString(), end_date.toString());\n",
271 | " }\n",
272 | "\n",
273 | " for(var t in results_allocs){\n",
274 | " var start = t.start;\n",
275 | " var end = t.end;\n",
276 | " if(start+end > 0){\n",
277 | " var start_date = new Date(2021, 0, 1, 0, start, 0, 0);\n",
278 | " var end_date = new Date(2021, 0, 1, 0, end, 0, 0);\n",
279 | " result_alloc_dates.add(t.reqId, t.taskId, t.workerId, start_date.toString(), end_date.toString());\n",
280 | " }\n",
281 | " } \n",
282 | "\n",
283 | " for(var t in results_workers){\n",
284 | " var start = t.start;\n",
285 | " var end = t.end;\n",
286 | " if(start+end > 0){\n",
287 | " var start_date = new Date(2021, 0, 1, 0, start, 0, 0);\n",
288 | " var end_date = new Date(2021, 0, 1, 0, end, 0, 0);\n",
289 | " result_worker_dates.add(t.workerId, t.workerName, start_date.toString(), end_date.toString());\n",
290 | " }\n",
291 | " } \n",
292 | "};\n"
293 | ]
294 | },
295 | {
296 | "cell_type": "markdown",
297 | "metadata": {},
298 | "source": [
299 | "### JSON file\n",
300 | "Here you can find the JSON file to create the gantt diagram in watson"
301 | ]
302 | },
303 | {
304 | "cell_type": "code",
305 | "execution_count": null,
306 | "metadata": {},
307 | "outputs": [],
308 | "source": [
309 | "{\n",
310 | " \"name\": \"\",\n",
311 | " \"type\": \"Gantt\",\n",
312 | " \"props\": {\n",
313 | " \"container\": \"\",\n",
314 | " \"data\": [\n",
315 | " \"Workers\",\n",
316 | " \"result_alloc_dates\"\n",
317 | " ],\n",
318 | " \"spec\": {\n",
319 | " \"resources\": {\n",
320 | " \"data\": \"Workers\",\n",
321 | " \"id\": \"id\",\n",
322 | " \"name\": \"name\"\n",
323 | " },\n",
324 | " \"activities\": {\n",
325 | " \"data\": \"result_alloc_dates\",\n",
326 | " \"id\": \"reqId\",\n",
327 | " \"name\": \"taskId\",\n",
328 | " \"start\": \"start\",\n",
329 | " \"end\": \"end\"\n",
330 | " },\n",
331 | " \"reservations\": {\n",
332 | " \"data\": \"result_alloc_dates\",\n",
333 | " \"activity\": \"reqId\",\n",
334 | " \"resource\": \"workerId\"\n",
335 | " },\n",
336 | " \"constraints\": {},\n",
337 | " \"dateFormat\": \"MM/dd/yyyy HH:mm:ss SSS\"\n",
338 | " },\n",
339 | " \"search\": \"\"\n",
340 | " }\n",
341 | "}"
342 | ]
343 | }
344 | ],
345 | "metadata": {
346 | "kernelspec": {
347 | "display_name": "Python 3",
348 | "language": "python",
349 | "name": "python3"
350 | },
351 | "language_info": {
352 | "codemirror_mode": {
353 | "name": "ipython",
354 | "version": 3
355 | },
356 | "file_extension": ".py",
357 | "mimetype": "text/x-python",
358 | "name": "python",
359 | "nbconvert_exporter": "python",
360 | "pygments_lexer": "ipython3",
361 | "version": "3.7.7"
362 | }
363 | },
364 | "nbformat": 4,
365 | "nbformat_minor": 4
366 | }
367 |
--------------------------------------------------------------------------------
/Project Scheduling/Watson/README.md:
--------------------------------------------------------------------------------
1 | # Project Scheduling - Watson
2 |
3 | Notebooks found in this folder are all applied to Project Scheduling examples. They have a step-by-step procedure to create a project using IBM Watson Studio platform.
4 |
5 |
6 |
7 | ## IBM Watson Studio
8 |
9 | [IBM Watson Studio](https://www.ibm.com/cloud/watson-studio) is a platform software for data science. The advantage of using Watson is having a workspace that includes multiple collaboration and open-source tools such as RStudio, Spark and Python, all in an integrated environment.
10 |
11 | As you create a new project, you can add multiple collaborators, all having access to various predictive and prescriptive analytics models. Data can be accessed through Watson Data Platform, on-premise or on the cloud.
12 |
13 | #### For more information about SmartBP
14 | - [Website](http://www.smart-bp.com)
15 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
16 | - [Follow Us](https://twitter.com/Smart_BP)
17 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SmartBP® Modeling Training
2 |
3 |
4 | ## Index of Modeling Problems
5 | - [Production Planning](https://github.com/SmartBP/Modeling_Training/tree/master/Production_Planning)
6 | - [TSP](https://github.com/SmartBP/Modeling_Training/tree/master/TSP)
7 | - [VRPTW](https://github.com/SmartBP/Modeling_Training/tree/master/VRPTW)
8 | - [Machine Learning + Decision Optimization](https://github.com/SmartBP/Modeling_Training/tree/master/Machine%20Learning%20%2B%20Decision%20Optimization)
9 |
10 |
11 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
12 |
13 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
14 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
15 |
16 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
17 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
18 |
19 | #### For more information about SmartBP
20 | - [Website](http://www.smart-bp.com)
21 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
22 | - [Follow Us](https://twitter.com/Smart_BP)
23 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
24 | - [YouTube](https://www.youtube.com/c/SmartBP)
25 |
--------------------------------------------------------------------------------
/TSP/CPLEX_OPL/inicial.mod:
--------------------------------------------------------------------------------
1 | #archivo inicial
2 |
--------------------------------------------------------------------------------
/TSP/CPLEX_Python/TSP.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Travelling Salesman Problem"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "#### Importación de libraría necesarias para la creación del problema"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": 12,
20 | "metadata": {},
21 | "outputs": [],
22 | "source": [
23 | "#Import libraries\n",
24 | "import pandas\n",
25 | "import itertools \n",
26 | "import numpy\n",
27 | "import random\n",
28 | "import networkx\n",
29 | "\n",
30 | "#Import graphing libraries\n",
31 | "%matplotlib inline\n",
32 | "\n",
33 | "import matplotlib as mpl\n",
34 | "import matplotlib.pyplot as plt"
35 | ]
36 | },
37 | {
38 | "attachments": {},
39 | "cell_type": "markdown",
40 | "metadata": {},
41 | "source": [
42 | "#### Creación del modelo con DOcplex\n",
43 | "Parámetros\n",
44 | "\\begin{equation}\n",
45 | "c_ij = \\text{distance from i to j}\n",
46 | "\\end{equation}\n",
47 | "Variables de decisión\n",
48 | "\\begin{equation}\n",
49 | "x_{ij} = \\begin{cases} 0, & \\text{if the path from i to j is selected} \\\\1, & \\text{otherwise}\\end{cases} \\text{ }\\forall i = 1,..,n \\text{ , } j = 1,..,n\\end{equation}\n",
50 | "\n",
51 | "Función Objetivo\n",
52 | "\\begin{equation}\n",
53 | "\\text{Min} \\sum\\limits_{i=1}^n \\sum\\limits_{i\\neq j,j=1}^n c_{ij}x_{ij}\n",
54 | "\n",
55 | "\\end{equation}\n",
56 | "\n",
57 | "Restricciones\n",
58 | "\\begin{equation}\n",
59 | "\\sum\\limits_{i=1,i\\neq j}^n x_{ij} = 1,\\forall j = 1..n\n",
60 | "\\end{equation}\n",
61 | "\\begin{equation}\n",
62 | "\\sum\\limits_{j=1,j\\neq i}^n x_{ij} = 1,\\forall i = 1..n\n",
63 | "\\end{equation}\n",
64 | "\\begin{equation}\n",
65 | "\\sum\\limits_{i\\in S,j\\neq i,j\\in S} x_{ij} \\leq \\lvert S \\rvert - 1,\\text{ } \\forall S\\subset {1,..,n},2\\leq \\lvert S \\rvert \\leq n-2\n",
66 | "\\end{equation}\n"
67 | ]
68 | },
69 | {
70 | "cell_type": "code",
71 | "execution_count": null,
72 | "metadata": {},
73 | "outputs": [],
74 | "source": [
75 | "from docplex.mp.model import Model\n",
76 | "\n",
77 | "#create the base model\n",
78 | "def tsp(data, max_length):\n",
79 | " m = Model(name='tsp',log_output=False)\n",
80 | " m.parameters.threads.set(1)\n",
81 | " \n",
82 | " all_locations = set(data.point_from.unique()).union(set(data.point_to.unique()))\n",
83 | " \n",
84 | " ####VARIABLES####\n",
85 | " data['travel_on'] = m.binary_var_list([(row.point_from, row.point_to) for row in data.itertuples()], name = 'travel_on')\n",
86 | " \n",
87 | " ####OBJECTIVE####\n",
88 | " distance_traveled = m.sum([row.travel_on * row.distance for row in data.itertuples()]) \n",
89 | " m.add_kpi(distance_traveled, \"distance\")\n",
90 | " \n",
91 | " m.minimize(distance_traveled)\n",
92 | " ####CONSTRAINTS####\n",
93 | " #force each location to only have one outgoing edge\n",
94 | " for start_point in all_locations:\n",
95 | " m.add_constraint(m.sum([row.travel_on for row in data[data.point_from == start_point].itertuples()]) == 1, \\\n",
96 | " 'outgoing_edge_%s' % start_point)\n",
97 | "\n",
98 | " #force each location to only have one incoming edge\n",
99 | " for end_point in all_locations:\n",
100 | " m.add_constraint(m.sum([row.travel_on for row in data[data.point_to == end_point].itertuples()]) == 1, \\\n",
101 | " 'incoming_edge_%s' % end_point)\n",
102 | "\n",
103 | " return m\n",
104 | "\n",
105 | "#update the parameters, solve the model, and return the results\n",
106 | "def update_and_solve(m, data, mipgap = 0.0001):\n",
107 | " m.parameters.mip.tolerances.mipgap.set(mipgap)\n",
108 | " m.parameters.timelimit = 600\n",
109 | " m.solve()\n",
110 | " data['travel_on_val'] = [var.solution_value for var in data.travel_on.values]\n",
111 | "\n",
112 | "def add_cycle_breaking_constraints(m,subtour_id, data):\n",
113 | " g = networkx.DiGraph()\n",
114 | " g.add_edges_from([(row.point_from,row.point_to) for row in data[data.travel_on_val > 0.5].itertuples()])\n",
115 | " num_cycles = 0\n",
116 | " longest_cycle = None\n",
117 | " subtours = {}\n",
118 | " for cycle in networkx.simple_cycles(g):\n",
119 | " cycleLength = len(cycle)\n",
120 | " num_cycles += 1\n",
121 | " subtours[subtour_id] = cycle\n",
122 | " subtour_id += 1\n",
123 | " if num_cycles == 1: #finished\n",
124 | " return m.kpis_as_dict()['distance'], cycle, subtour_id\n",
125 | " else:\n",
126 | " for new_subtour in subtours.keys():\n",
127 | " cycle = subtours[new_subtour]\n",
128 | " idxs = data[(data.point_from.isin(cycle)) & (data.point_to.isin(cycle)) & (data.travel_on_val > 0.5)].index.values\n",
129 | " m.add_constraint(m.sum(data.loc[idxs,'travel_on'].values) <= len(cycle) - 1,\\\n",
130 | " 'subtour_elimintaion_%d' % subtour_id)\n",
131 | " return m.kpis_as_dict()['distance'], [], subtour_id\n",
132 | " \n",
133 | "def distance_tsp(data, max_length):\n",
134 | " m = tsp(data, max_length)\n",
135 | " mipgap = 0.1\n",
136 | " subtour_id = 0\n",
137 | " iteracion = 0\n",
138 | " max_iter = 500\n",
139 | " estado_iter = ''\n",
140 | " update_and_solve(m, data, mipgap = mipgap)\n",
141 | " distance, tour, subtour_id = add_cycle_breaking_constraints(m,subtour_id, data)\n",
142 | " if len(tour) == max_length:\n",
143 | " mipgap = mipgap - 0.01\n",
144 | " while (len(tour) < max_length or mipgap > 0.009) and iteracion < max_iter:\n",
145 | " update_and_solve(m, data, mipgap = mipgap)\n",
146 | " distance, tour, subtour_id = add_cycle_breaking_constraints(m,subtour_id, data)\n",
147 | " if len(tour) == max_length:\n",
148 | " mipgap = 0\n",
149 | " iteracion = iteracion + 1\n",
150 | " if iteracion == max_iter:\n",
151 | " estado_iter = 'SIN SOLUCION'\n",
152 | " else:\n",
153 | " estado_iter='OPTIMO'\n",
154 | " return distance, tour, estado_iter"
155 | ]
156 | },
157 | {
158 | "cell_type": "markdown",
159 | "metadata": {},
160 | "source": [
161 | "#### Creación de coordenadas aleatorias\n",
162 | "Se definen p puntos con coordenadas aleatorias. Estos puntos serán los lugares a visitar"
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": 13,
168 | "metadata": {},
169 | "outputs": [],
170 | "source": [
171 | "p = 20\n",
172 | "df = pandas.DataFrame({'X':[random.randrange(100) for i in range(p)],'Y':[random.randrange(100) for i in range(p)]})"
173 | ]
174 | },
175 | {
176 | "cell_type": "code",
177 | "execution_count": 14,
178 | "metadata": {},
179 | "outputs": [
180 | {
181 | "data": {
182 | "text/plain": [
183 | ""
184 | ]
185 | },
186 | "execution_count": 14,
187 | "metadata": {},
188 | "output_type": "execute_result"
189 | },
190 | {
191 | "data": {
192 | "image/png": "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\n",
193 | "text/plain": [
194 | "
"
295 | ],
296 | "text/plain": [
297 | " point_from point_to distance\n",
298 | "0 0.0 1.0 49.20\n",
299 | "1 0.0 2.0 14.42\n",
300 | "2 0.0 3.0 35.34\n",
301 | "3 0.0 4.0 26.68\n",
302 | "4 0.0 5.0 3.16"
303 | ]
304 | },
305 | "execution_count": 16,
306 | "metadata": {},
307 | "output_type": "execute_result"
308 | }
309 | ],
310 | "source": [
311 | "data = pandas.DataFrame(columns=['point_from','point_to','distance'])\n",
312 | "\n",
313 | "for i in range(len(perm)):\n",
314 | " p1 = perm[i][0]\n",
315 | " p2 = perm[i][1]\n",
316 | " data.loc[i] = p1 , p2 , \\\n",
317 | " round(numpy.lib.scimath.sqrt((df.loc[p1,'X'] - df.loc[p2,'X'])**2+(df.loc[p1,'Y'] - df.loc[p2,'Y'])**2),2)\n",
318 | "\n",
319 | "data.head(5)"
320 | ]
321 | },
322 | {
323 | "cell_type": "markdown",
324 | "metadata": {},
325 | "source": [
326 | "#### Ejecución de modelo - DOcplex\n",
327 | "Por medio del modelo definido en tsp_model, se obtiene la ruta óptima para los puntos definidos"
328 | ]
329 | },
330 | {
331 | "cell_type": "code",
332 | "execution_count": 17,
333 | "metadata": {},
334 | "outputs": [],
335 | "source": [
336 | "max_length = len(set(data.point_from.unique()).union(set(data.point_to.unique())))\n",
337 | "distance, tour, estado = distance_tsp(data, max_length)"
338 | ]
339 | },
340 | {
341 | "cell_type": "markdown",
342 | "metadata": {},
343 | "source": [
344 | "#### Solución de modelo - DOcplex\n",
345 | "La solución del modelo nos retornará la distancia recorrida, el orden de recorrido de los puntos y el estado del modelo (óptimo o sin solución óptima)"
346 | ]
347 | },
348 | {
349 | "cell_type": "code",
350 | "execution_count": 18,
351 | "metadata": {},
352 | "outputs": [
353 | {
354 | "data": {
355 | "text/plain": [
356 | "362.94999999999993"
357 | ]
358 | },
359 | "execution_count": 18,
360 | "metadata": {},
361 | "output_type": "execute_result"
362 | }
363 | ],
364 | "source": [
365 | "distance"
366 | ]
367 | },
368 | {
369 | "cell_type": "code",
370 | "execution_count": 19,
371 | "metadata": {},
372 | "outputs": [
373 | {
374 | "data": {
375 | "text/plain": [
376 | "[0.0,\n",
377 | " 4.0,\n",
378 | " 12.0,\n",
379 | " 3.0,\n",
380 | " 1.0,\n",
381 | " 7.0,\n",
382 | " 16.0,\n",
383 | " 6.0,\n",
384 | " 10.0,\n",
385 | " 9.0,\n",
386 | " 15.0,\n",
387 | " 13.0,\n",
388 | " 17.0,\n",
389 | " 8.0,\n",
390 | " 14.0,\n",
391 | " 19.0,\n",
392 | " 11.0,\n",
393 | " 18.0,\n",
394 | " 2.0,\n",
395 | " 5.0]"
396 | ]
397 | },
398 | "execution_count": 19,
399 | "metadata": {},
400 | "output_type": "execute_result"
401 | }
402 | ],
403 | "source": [
404 | "tour"
405 | ]
406 | },
407 | {
408 | "cell_type": "code",
409 | "execution_count": 20,
410 | "metadata": {},
411 | "outputs": [
412 | {
413 | "data": {
414 | "text/plain": [
415 | "'OPTIMO'"
416 | ]
417 | },
418 | "execution_count": 20,
419 | "metadata": {},
420 | "output_type": "execute_result"
421 | }
422 | ],
423 | "source": [
424 | "estado"
425 | ]
426 | },
427 | {
428 | "cell_type": "markdown",
429 | "metadata": {},
430 | "source": [
431 | "#### Solución gráfica \n",
432 | "Para evaluar la solución, graficamos las rutas definidas por la soluci´´on del modelo"
433 | ]
434 | },
435 | {
436 | "cell_type": "code",
437 | "execution_count": 21,
438 | "metadata": {},
439 | "outputs": [],
440 | "source": [
441 | "def plot_tsp(df,points, style='bo-'):\n",
442 | " \"Plot lines to connect a series of points.\"\n",
443 | " plt.plot([df.loc[p,'X'] for p in points], [df.loc[p,'Y'] for p in points], style)\n",
444 | " plt.axis('scaled'); plt.axis('off')"
445 | ]
446 | },
447 | {
448 | "cell_type": "code",
449 | "execution_count": 22,
450 | "metadata": {},
451 | "outputs": [
452 | {
453 | "data": {
454 | "image/png": "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\n",
455 | "text/plain": [
456 | ""
457 | ]
458 | },
459 | "metadata": {
460 | "needs_background": "light"
461 | },
462 | "output_type": "display_data"
463 | }
464 | ],
465 | "source": [
466 | "first_point= tour[0]\n",
467 | "tour.append(first_point)\n",
468 | "plot_tsp(df,tour)"
469 | ]
470 | }
471 | ],
472 | "metadata": {
473 | "kernelspec": {
474 | "display_name": "Python 3",
475 | "language": "python",
476 | "name": "python3"
477 | },
478 | "language_info": {
479 | "codemirror_mode": {
480 | "name": "ipython",
481 | "version": 3
482 | },
483 | "file_extension": ".py",
484 | "mimetype": "text/x-python",
485 | "name": "python",
486 | "nbconvert_exporter": "python",
487 | "pygments_lexer": "ipython3",
488 | "version": "3.6.8"
489 | }
490 | },
491 | "nbformat": 4,
492 | "nbformat_minor": 2
493 | }
--------------------------------------------------------------------------------
/TSP/README.md:
--------------------------------------------------------------------------------
1 | # Travelling Salesman Problem (TSP)
2 |
3 | The travelling salesman problem (also called the travelling salesperson problem or TSP) asks the following question: "Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city and returns to the origin city?"
4 |
5 | It is an NP-hard problem in combinatorial optimization, important in theoretical computer science and operations research. The travelling purchaser problem and the vehicle routing problem are both generalizations of TSP.
6 |
7 | ## TSP applications
8 |
9 | - Vehicle routing
10 | - Order-picking in Warehouse
11 | - Computer wiring
12 | - Drilling of printed circuit boards
13 | - Mask plotting in PCB production
14 | - Overhauling gas turbine engines
15 | - X-Ray crystallography
16 | - Scheduling problems
17 | - Mission planning
18 | - Navigation satellite system surveying networks
19 |
20 | This modeling example is at the advanced level, where we assume that you know Python and the CPLEX Python API and you have advanced knowledge of building mathematical optimization models.
21 |
22 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
23 |
24 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
25 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
26 |
27 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
28 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
29 |
30 | #### For more information about SmartBP
31 | - [Website](http://www.smart-bp.com)
32 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
33 | - [Follow Us](https://twitter.com/Smart_BP)
34 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
35 |
--------------------------------------------------------------------------------
/Tips_CPLEX/OPL/changeTuplesWithLoop.mod:
--------------------------------------------------------------------------------
1 | /*
2 | Let's take as example a production model
3 | with four products, each one with a known demand,
4 | also with a processing time and a profit
5 |
6 | we would like to maximize the profit taking into account
7 | the maximum production time avialable
8 | */
9 |
10 | //Define parameters
11 | tuple produdct_tuple
12 | {
13 | key int id;
14 | float demand;
15 | float profit;
16 | float prod_time;
17 | }
18 |
19 | {produdct_tuple} products={<1,50,40,15>,<2,70,20,15>,<3,100,10,5>,<4,20,70,25>};
20 |
21 | //Now suppose we need to reduce demand 20%
22 |
23 | range rangeProducts=0..card(products)-1;
24 |
25 | execute
26 | {
27 | for(var indexProd in rangeProducts)
28 | {
29 | var p=Opl.item(products,indexProd);
30 | p.demand=0.8*p.demand;
31 | }
32 | writeln(products);
33 | }
34 |
35 | float capacity = 2000;
36 |
37 | //Define decision variables
38 | dvar int production[products];
39 |
40 | //Define linear expressions
41 | dexpr float profit_prod = sum(p in products)(production[p]*p.profit);
42 |
43 | maximize profit_prod;
44 |
45 | //Define constraints
46 | subject to{
47 | //For each product the produced quantity must be less than or equal to the demand
48 | forall(p in products)
49 | production[p] <= p.demand;
50 | //The total production time must be less than or equal to the available production time
51 | ctCapacity: sum(p in products)(production[p]*p.prod_time) <= capacity;
52 | }
53 |
54 | execute{
55 | writeln("The maximum profit would be: "+profit_prod);
56 | for(var p in products){
57 | writeln("The company needs to produce "+production[p]+" unit of product "+p.id);
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/Tips_CPLEX/OPL/database connection/product_data.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartBP/Modeling_Training/247c58ef287b26d9d6166e96f2c40f66e4565c44/Tips_CPLEX/OPL/database connection/product_data.db
--------------------------------------------------------------------------------
/Tips_CPLEX/OPL/database connection/production_for_db.mod:
--------------------------------------------------------------------------------
1 | tuple productData {
2 | string name;
3 | float demand;
4 | float insideCost;
5 | float outsideCost;
6 | float consumptionFlour;
7 | float consumptionEggs;
8 | }
9 | {productData} Products = ...;
10 | float CapacityFlour = 20;
11 | float CapacityEggs = 40;
12 |
13 | dvar int+ Inside[Products];
14 | dvar int+ Outside[Products];
15 |
16 | execute CPX_PARAM {
17 | cplex.preind = 0;
18 | cplex.simdisplay = 2;
19 | }
20 |
21 |
22 | minimize
23 | sum( p in Products )
24 | (p.insideCost * Inside[p] +
25 | p.outsideCost * Outside[p] );
26 | subject to {
27 | ctInsideFlour:
28 | sum( p in Products )
29 | p.consumptionFlour * Inside[p] <= CapacityFlour;
30 | ctInsideEggs:
31 | sum( p in Products )
32 | p.consumptionEggs * Inside[p] <= CapacityEggs;
33 | forall( p in Products )
34 | ctDemand:
35 | Inside[p] + Outside[p] >= p.demand;
36 | }
37 |
38 | tuple R {
39 | string productName;
40 | float inside;
41 | float outside;
42 | };
43 | {R} Results = { | p in Products };
44 |
45 |
--------------------------------------------------------------------------------
/Tips_CPLEX/OPL/database connection/production_with_db.dat:
--------------------------------------------------------------------------------
1 | JDBCConnection conn("jdbc:sqlite:product_data.db",
2 | "DROP TABLE IF EXISTS results; CREATE TABLE results (Product VARCHAR, Inside INTEGER, Outside INTEGER)");
3 |
4 | Products from JDBCRead(conn, "SELECT name, demand, insideCost, outsideCost, consumptionFlour, consumptionEggs" FROM products");
5 | Results to JDBCPublish(conn, "INSERT INTO results VALUES(?, ?, ?)");
--------------------------------------------------------------------------------
/Tips_CPLEX/OPL/incrementalChanges.mod:
--------------------------------------------------------------------------------
1 | /*
2 | Let's take as example a production model
3 | with four products, each one with a known demand,
4 | also with a processing time and a profit
5 |
6 | we would like to maximize the profit taking into account
7 | the maximum production time avialable
8 | */
9 |
10 | //Define parameters
11 | tuple produdct_tuple
12 | {
13 | key int id;
14 | float demand;
15 | float profit;
16 | float prod_time;
17 | }
18 |
19 | {produdct_tuple} products={<1,50,40,15>,<2,70,20,15>,<3,100,10,5>,<4,20,70,25>};
20 |
21 | float capacity = 2000;
22 |
23 | //Define decision variables
24 | dvar int production[products];
25 |
26 | //Define linear expressions
27 | dexpr float profit_prod = sum(p in products)(production[p]*p.profit);
28 |
29 | maximize profit_prod;
30 |
31 | //Define constraints
32 | subject to{
33 | //For each product the produced quantity must be less than or equal to the demand
34 | forall(p in products)
35 | production[p] <= p.demand;
36 | //The total production time must be less than or equal to the available production time
37 | ctCapacity: sum(p in products)(production[p]*p.prod_time) <= capacity;
38 | }
39 |
40 | execute{
41 | writeln("The maximum profit would be: "+profit_prod);
42 | for(var p in products){
43 | writeln("The company needs to produce "+production[p]+" unit of product "+p.id);
44 | }
45 |
46 | }
47 |
48 | /*
49 | Now we would like to see what happens if the available time is doubled
50 | to do so, use flow control and a buffer variable
51 | */
52 |
53 | main{
54 | thisOplModel.generate();
55 |
56 | cplex.solve();
57 | thisOplModel.postProcess();
58 |
59 | writeln("now 4000 of capacity instead of 2000");
60 |
61 | var buffer=2*thisOplModel.capacity;
62 |
63 | thisOplModel.ctCapacity.UB=buffer;
64 |
65 | cplex.solve();
66 | thisOplModel.postProcess();
67 | }
--------------------------------------------------------------------------------
/Tips_CPLEX/README.md:
--------------------------------------------------------------------------------
1 | # Tips and Tricks CPLEX (OPL and Python)
2 |
3 |
4 | ## OPL Tips
5 |
6 | - [Modify a tuple set in a scripting loop](https://github.com/SmartBP/Modeling_Training/blob/master/Tips_CPLEX/OPL/changeTuplesWithLoop.mod): Modify every element of an existing tuple with a loop.
7 | - [Several incremental changes](https://github.com/SmartBP/Modeling_Training/blob/master/Tips_CPLEX/OPL/incrementalChanges.mod): Use flow control to solve an instance of a model, then modify a restriction and solve the model again.
8 | - [Database connection](https://github.com/SmartBP/Modeling_Training/tree/master/Tips_CPLEX/OPL/database%20connection): Use a JDBC connection to retrieve the data from a database to a dat file.
9 |
10 | ## Python Tips (docplex)
11 |
12 | - Modify a tuple set in a scripting loop
13 | - Several incremental changes
14 |
15 |
16 |
17 |
18 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
19 |
20 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
21 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
22 |
23 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
24 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
25 |
26 | #### For more information about SmartBP
27 | - [Website](http://www.smart-bp.com)
28 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
29 | - [Follow Us](https://twitter.com/Smart_BP)
30 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
31 | - [YouTube](https://www.youtube.com/c/SmartBP)
32 |
--------------------------------------------------------------------------------
/VRPTW/CPLEX_OPL/README.md:
--------------------------------------------------------------------------------
1 | # Vehicle Routing Problem with Time Windows
2 |
3 |
4 | ## Problem Description
5 | The VRPTW can be described as follows. Given a set of customers, a set of vehicles, and a depot, the VRPTW is to find a set of routes of minimal total length, starting and ending at the depot, such that each customer is visited by exactly one vehicle to satisfy a specific demand. Customer visit has to respect a requested time window. A vehicle can wait in case of early arrival, but late arrival is not allowed. In connection with customer demands, a capacity constraint restricts the load that can be carried by a vehicle.
6 |
7 | ### CPLEX license
8 |
9 | In order to run this `.mod` properly, you must have a IBM® ILOG CPLEX license.
10 |
11 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
12 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
13 |
14 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
15 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
16 |
17 |
18 | ## VRPTW Model Formulation
19 | ### Sets and Indices
20 |
25 |
26 |
31 |
32 |
37 |
38 | ### Parameters
39 |
40 |
45 |
46 |
51 |
52 |
57 |
58 |
63 |
64 |
69 |
70 |
75 |
76 |
81 |
82 | #### Assumptions
83 | In the following, we make these additional common assumptions: the cost and the travel time matrices are supposed to be equal, nonnegative and to satisfy the triangle inequality. For the sake of simplicity, we also define and .
84 |
85 | ### Decision Variables
86 |
91 |
92 |
97 |
98 | ### Objective Function
99 | - **Minimum cost routes**. Minimize the total cost of the routes.
100 |
101 |
107 |
108 | ### Constraints
109 | - **Customer satisfaction**. Enforces the visit of every customer. Notice that is is allowed to visit a customer more than once, this relaxation is valid since is not optimal to visit a customer more than once.
110 |
111 |
116 |
117 | - **Route structure**. The following constraints define the route structure for the vehicles.
118 |
119 |
124 |
125 |
130 |
131 | - **Capacity**. The total demand satisfied by a vehicle with a route cant be greater than teh vehicle capacity.
132 |
133 |
138 |
139 | - **Time windows**. The following constraints concern time windows satisfaction.
140 |
141 |
146 |
147 |
152 |
153 |
158 |
--------------------------------------------------------------------------------
/VRPTW/CPLEX_OPL/VRPTW.mod:
--------------------------------------------------------------------------------
1 | // Vehicles
2 | int v = 2;
3 | range Vehicles = 1..v;
4 |
5 | // Customers
6 | int CustomersNumber = 4;
7 | range Customers = 1..CustomersNumber;
8 | range CustomersAndRefinery = 0..(CustomersNumber+1); // includes the starting depot and the returning depot
9 |
10 | // Capacity
11 | int Capacity = 100;
12 |
13 | // Demand
14 | int Demand[Customers] = [35, 25, 35, 45];
15 |
16 | // Time windows
17 | int LBTW[CustomersAndRefinery] = [0, 15, 23, 12, 24, 0]; // Lower Bound of the Time Window
18 | int UBTW[CustomersAndRefinery] = [120, 24, 42, 38, 48, 120]; // Upper Bound of the Time Window
19 |
20 | int ServiceTime[CustomersAndRefinery] = [0, 5, 6, 5, 6, 0];
21 | float Cost[CustomersAndRefinery][CustomersAndRefinery] = [[0, 7, 7, 15, 5, 0],
22 | [7, 0, 12, 8, 5, 7],
23 | [7, 12, 0, 9, 3, 7],
24 | [15, 8, 9, 0, 2, 15],
25 | [5, 5, 3, 2, 0, 5],
26 | [0, 7, 7, 15, 5, 0]]; // Cost between i and j
27 | float Time[CustomersAndRefinery][CustomersAndRefinery] = [[0, 7, 7, 15, 5, 0],
28 | [7, 0, 12, 8, 5, 7],
29 | [7, 12, 0, 9, 3, 7],
30 | [15, 8, 9, 0, 2, 15],
31 | [5, 5, 3, 2, 0, 5],
32 | [0, 7, 7, 15, 5, 0]]; // Distance between i and j
33 |
34 | // Decision variables
35 | dvar boolean x[Vehicles][CustomersAndRefinery][CustomersAndRefinery]; // 1 if a vehicle drives directly from vertex i to vertex j
36 | dvar int s[Vehicles][CustomersAndRefinery]; // the time a vehicle starts to service a customer
37 | dexpr float maxTimeSpentBetweenTwoCustomers = max(a,b in CustomersAndRefinery)(UBTW[a] + Time[a][b] - LBTW[b]);
38 |
39 | minimize sum(k in Vehicles, i,j in CustomersAndRefinery) (Cost[i][j]*x[k][i][j]);
40 |
41 | subject to {
42 | forall(i in CustomersAndRefinery, k in Vehicles)
43 | x[k][i][i] == 0;
44 |
45 | // Each customer is visited exactly once
46 | forall (i in Customers)
47 | sum(k in Vehicles, j in CustomersAndRefinery) x[k][i][j] == 1;
48 |
49 | // A vehicle can only be loaded up to it's capacity
50 | forall(k in Vehicles)
51 | sum(i in Customers, j in CustomersAndRefinery)(Demand[i] * x[k][i][j]) <= Capacity;
52 | // Each vehicle must leave the depot 0
53 | forall(k in Vehicles)
54 | sum (j in CustomersAndRefinery)x[k][0][j] == 1;
55 | // After a vehicle arrives at a customer it has to leave for another destination
56 | forall(h in Customers, k in Vehicles)
57 | sum(i in CustomersAndRefinery)x[k][i][h] - sum(j in CustomersAndRefinery)x[k][h][j] == 0;
58 | // All vehicles must arrive at the depot n + 1
59 | forall(k in Vehicles)
60 | sum (i in CustomersAndRefinery) x[k][i][CustomersNumber+1] == 1;
61 | // The time windows are observed
62 | forall(i in CustomersAndRefinery, k in Vehicles)
63 | LBTW[i] <= s[k][i] <= UBTW[i];
64 | // From depot departs a number of vehicles equal to or smaller than v
65 | forall(k in Vehicles, j in CustomersAndRefinery)
66 | sum (k in Vehicles, j in CustomersAndRefinery) x[k][0][j] <= v;
67 | // Vehicle departure time from a customer and its immediate successor
68 | forall(i,j in CustomersAndRefinery, k in Vehicles)
69 | s[k][i] + Time[i][j] + ServiceTime[i] - maxTimeSpentBetweenTwoCustomers*(1 - x[k][i][j]) <= s[k][j];
70 | };
71 |
72 | execute DISPLAY {
73 | writeln("Solutions: ");
74 | for(var k in Vehicles){
75 | for(var i in CustomersAndRefinery){
76 | for (var j in CustomersAndRefinery){
77 | if(x[k][i][j] == 1){
78 | writeln("vehicle ", k, " from ", i, " to ", j,", starts trip at: ", (s[k][j]-Time[i][j]),", starting service at: ", s[k][j], " and ending at: ",(s[k][j] + ServiceTime[j]));
79 | }
80 | }
81 | }
82 | }
83 | }
--------------------------------------------------------------------------------
/VRPTW/README.md:
--------------------------------------------------------------------------------
1 | # Vehicle Routing Problem with Time Windows (VRPTW)
2 |
3 | The VRPTW can be described as follows. Given a set of customers, a set of vehicles, and a depot, the VRPTW is to find a set of routes of minimal total length, starting and ending at the depot, such that each customer is visited by exactly one vehicle to satisfy a specific demand. Customer visit has to respect a requested time window. A vehicle can wait in case of early arrival, but late arrival is not allowed. In connection with customer demands, a capacity constraint restricts the load that can be carried by a vehicle.
4 |
5 | More formally, the VRPTW is defined on a complete directed graph G = (V, A), where V = {v0, . . . , vn} is the set of nodes and A is the set of arcs. Vertex v0 is a special node called the depot, vertices v1 to vn represent customers. A cost ci j and a travel time ti j are defined for every arc (vi, vj ) ∈ A. Every customer vi ∈ V\{v0} has a positive demand di , a time window [ai , bi ] and a positive service time servi . A fleet of U vehicles of capacity Q is available for serving the customers. Vehicles must begin and end their routes at the depot within a time horizon [a0, b0]. The cumulative demand of the customers visited by a route is limited by Q. The service of a customer has to start within its time window, but a vehicle is allowed to arrive earlier and to wait. The VRPTW consists in finding a minimum cost set of at most U routes visiting exactly once each customer with respect to the previous constraints.
6 |
7 | ## VRPTW applications
8 |
9 | - Product deliveries
10 | - Solid waste collection
11 | - Street cleaning
12 | - School bus routing
13 | - Dial-a-ride systems
14 | - Transportation of handicapped persons
15 | - Routing of salespeople
16 | - Maintenance of units
17 |
18 | This modeling example is at the advanced level, where we assume that you know Python and the CPLEX Python API and you have advanced knowledge of building mathematical optimization models.
19 |
20 | ## Actual example
21 |
22 | In order to present the VRPTW problem, the problem is defined on a complete directed graph G = (V, A), a set of customers and depots is created where V = {v0, v1, v2, v3, v4 , v5} is the set of nodes and A is the set of arcs.
23 | - Vertex v0 and v5 are special nodes called origin and destination depots, vertices v1 to v4 represent customers
24 | - A cost c(i,j) and a travel time t(i,j) are defined for every arc (vi, vj ) ∈ A
25 | - Every customer vi ∈ V\{v0, v5} has a positive demand di , a time window [ai , bi ] and a positive service time servi
26 | - A fleet of 2 vehicles of capacity 100 is available for serving the customers
27 | - Vehicles must begin and end their routes at the depot within a time horizon [a0, b0]
28 | - The cumulative demand of the customers visited by a route is limited by 100
29 | - The service of a customer has to start within its time window, but a vehicle is allowed to arrive earlier and to wait.
30 |
31 | ## Video Tutorials
32 | You can find a complete playlist with the tutorials and the walkthrough of the VRPTW by clicking [here](https://www.youtube.com/watch?v=gNeTPxgZ5RE&list=PL_xEQLGJPHhL_Pi7bchXaXI5YBJhhGp17).
33 | ## Get your IBM® ILOG CPLEX Optimization Studio edition
34 |
35 | - You can get a free [Community Edition](http://www-01.ibm.com/software/websphere/products/optimization/cplex-studio-community-edition)
36 | of CPLEX Optimization Studio, with limited solving capabilities in term of problem size.
37 |
38 | - Faculty members, research professionals at accredited institutions can get access to an unlimited version of CPLEX through the
39 | [IBM® Academic Initiative](https://www.ibm.com/academic/technology/data-science).
40 |
41 | #### For more information about SmartBP
42 | - [Website](http://www.smart-bp.com)
43 | - [Like Us](https://www.facebook.com/Smartbp-122794631689852/?ref=bookmarks)
44 | - [Follow Us](https://twitter.com/Smart_BP)
45 | - [Connect with Us](https://www.linkedin.com/company/smartbp/?viewAsMember=true)
--------------------------------------------------------------------------------