├── 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 | "
" 195 | ] 196 | }, 197 | "metadata": { 198 | "needs_background": "light" 199 | }, 200 | "output_type": "display_data" 201 | } 202 | ], 203 | "source": [ 204 | "df.plot(kind='scatter', x='X', y='Y', figsize=(6, 6), color='darkblue')" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": {}, 210 | "source": [ 211 | "Se definen todas las posibles combinaciones entre dos puntos" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 15, 217 | "metadata": {}, 218 | "outputs": [], 219 | "source": [ 220 | "perm = [x for x in itertools.permutations(range(p), 2)]" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "Se definen las distancias para cada par de puntos" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 16, 233 | "metadata": {}, 234 | "outputs": [ 235 | { 236 | "data": { 237 | "text/html": [ 238 | "
\n", 239 | "\n", 252 | "\n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | "
point_frompoint_todistance
00.01.049.20
10.02.014.42
20.03.035.34
30.04.026.68
40.05.03.16
\n", 294 | "
" 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 | \begin{align*}
 23 | \text{Vertex}= {(v_{0},...,v_{n})} \text{: is the set of nodes with a special node} v_{0} \text{called the depot}
 24 | \end{align*} 25 | 26 | \begin{align*}
 29 | \text{Arcs}= \{(v_{i},v_{j}) \in \text{Vertex} \times \text{Vertex \}: Set of arcs between nodes.}
 30 | \end{align*} 31 | 32 | \begin{align*}
 35 | G = (V, A) \text{: A complete directed graph.}
 36 | \end{align*} 37 | 38 | ### Parameters 39 | 40 | \begin{align*}
 43 | c_{i,j} \text{: Cost of going from vertex } \: i \: \text{to vertex } j \text{, for all} (v_{i},v_{j}) \in \text{A.}
 44 | \end{align*} 45 | 46 | \begin{align*}
 49 | t_{i,j} \text{: Travel time going from vertex } \: i \: \text{to vertex}  \: j \: \text{, for all }(v_{i},v_{j}) \in \text{A.}
 50 | \end{align*} 51 | 52 | \begin{align*}
 55 | d_{i} \in \mathbb{R}^+ \text{: Demand of the customer }v_{i} \in \text{V}-v_{0} \text{.} 
 56 | \end{align*} 57 | 58 | \begin{align*}
 61 | serv_{i} \in \mathbb{R}^+ \text{: Service time for the customer} v_{i} \in \text{V}-v_{0} \text{.}  
 62 | \end{align*} 63 | 64 | \begin{align*}
 67 | [a_{i},b_{i}] \text{: Time window for the vertex} v_{i} \in \text{V.} 
 68 | \end{align*} 69 | 70 | \begin{align*}
 73 | U \text{: Size of the fleet of vehicles }
 74 | \end{align*} 75 | 76 | \begin{align*}
 79 | Q \text{: Capacity for a vehicle}
 80 | \end{align*} 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 | \begin{align*}
 89 | x_{i, j}^u \in \{0, 1\ \text{: This variable is equal to 1, if the arc} (v_{i},v_{j}) \in A \text{is used by vehicle} \: u \: \text{. Otherwise, the decision variable is equal to zero.}
 90 | \end{align*} 91 | 92 | \begin{align*}
 95 | s_{i}^u \in \mathbb{R}^+ \text{: The time when the vehicle} \: u \: \text{starts serving vertex }v_{i} \in V\text{ . For the depot, } \: s_{0}^u  \: \text{is the departure time of vehicle} \: u \text{.}  
 96 | \end{align*} 97 | 98 | ### Objective Function 99 | - **Minimum cost routes**. Minimize the total cost of the routes. 100 | 101 | \begin{equation}
104 |     \text{Min} \quad Z = \sum_{1 \leq u \leq U}\sum_{(v_{i},v_{j}) \in \text{A}}c_{i,j} \cdot x_{i,j}^u
105 |     \end{equation}
106 |     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 | \begin{equation}
114 |     \sum_{1 \leq u \leq U} \sum_{v_{j} \in V |(v_{i},v_{j}) \in \text{A}} x_{i, j}^u \geq 1 \quad \forall \quad v_{i} \in \text{V}-v_{0}
115 |     \end{equation} 116 | 117 | - **Route structure**. The following constraints define the route structure for the vehicles. 118 | 119 | \begin{equation}
122 |     \sum_{v_{j} \in V |(v_{i},v_{j}) \in \text{A}} x_{i,j}^u - \sum_{v_{j} \in V |(v_{i},v_{j}) \in \text{A}} x_{j,i}^u  = 0 \quad \forall \quad  v_{i} \in V, 1 \leq u \leq U
123 |     \end{equation} 124 | 125 | \begin{equation}
128 |     \sum_{v_{j} \in V |(v_{i},v_{j}) \in \text{A}} x_{0,i}^u \leq 1 \quad \forall \quad 1 \leq u \leq U
129 |     \end{equation} 130 | 131 | - **Capacity**. The total demand satisfied by a vehicle with a route cant be greater than teh vehicle capacity. 132 | 133 | \begin{equation}
136 |     \sum_{(v_{i},v_{j}) \in \text{A}} d_{i} \cdot x_{i,j}^u \leq Q \quad \forall \quad 1 \leq u \leq U
137 |     \end{equation} 138 | 139 | - **Time windows**. The following constraints concern time windows satisfaction. 140 | 141 | \begin{equation}
144 |     s_{i}^u + serv_{i} + t_{i,j} - s_{j}^u + M \cdot x_{i,j}^u \leq M \quad \forall \quad (v_{i},v_{j})\in A, v_{i}\neq v_{0},1 \leq u \leq U
145 |     \end{equation} 146 | 147 | \begin{equation}
150 |     s_{i}^u + serv_{i} + t_{i,0} - b_{0} + M \cdot x_{i,0}^u \leq M \quad \forall \quad (v_{i},v_{j})\in A,1 \leq u \leq U
151 |     \end{equation} 152 | 153 | \begin{equation}
156 |     a_{i} \leq s_{i}^u \leq b_{i} \quad \forall \quad v_{i} \in V,1 \leq u \leq U
157 |     \end{equation} 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) --------------------------------------------------------------------------------