diff --git a/examples/cp/basic/facility.py b/examples/cp/basic/facility.py index ec2623b..d6896c2 100644 --- a/examples/cp/basic/facility.py +++ b/examples/cp/basic/facility.py @@ -35,10 +35,10 @@ # Initialize the problem data #----------------------------------------------------------------------------- -Warehouse = namedtuple('Wharehouse', ('city', # Name of the city - 'capacity', # Capacity of the warehouse - 'cost', # Warehouse building cost - )) +Warehouse = namedtuple('Warehouse', ('city', # Name of the city + 'capacity', # Capacity of the warehouse + 'cost', # Warehouse building cost + )) # List of warehouses WAREHOUSES = (Warehouse("Bonn", 3, 480), diff --git a/examples/cp/zeppelin/SteelMill.json b/examples/cp/zeppelin/SteelMill.json deleted file mode 100644 index cecb94f..0000000 --- a/examples/cp/zeppelin/SteelMill.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/SteelMill", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Building steel coils\n\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires a valid subscription to **Decision Optimization on the Cloud** or a **local installation of CPLEX Optimizers**. \nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the Data\n * Step 4: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization solve service\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "
This tutorial includes everything you need to set up decision optimization engines, build constraint programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n* Step 4: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization solve service\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n* A coil order can be built from only one slab.\n
\n* Each coil order requires a specific process to build it from a slab. This process is encoded by a color.\n
\n* Several coil orders can be built from the same slab. But a slab can be used to produce at most two different \"colors\" of coils.\n
\n* The sum of the sizes of each coil order built from a slab must not exceed the slab size.\n
\n\n\n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.\n\n__Set your DOcplexcloud credentials:__\n0. A first option is to set the DOcplexcloud url and key directly in the model source file *(see below)*\n1. For a persistent setting, create a Python file __docloud_config.py__ somewhere that is visible from the __PYTHONPATH__", "apps": [], "results": {"msg": [{"data": "Set your DOcplexcloud credentials:
\nSet model parameter
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom collections import namedtuple\n\n##############################################################################\n# Model configuration\n##############################################################################\n\n# The number of coils to produce\nTUPLE_ORDER = namedtuple(\"TUPLE_ORDER\", [\"index\", \"weight\", \"color\"])\norders = [ TUPLE_ORDER(1, 22, 5),\n TUPLE_ORDER(2, 9, 3),\n TUPLE_ORDER(3, 9, 4),\n TUPLE_ORDER(4, 8, 5),\n TUPLE_ORDER(5, 8, 7),\n TUPLE_ORDER(6, 6, 3),\n TUPLE_ORDER(7, 5, 6),\n TUPLE_ORDER(8, 3, 0),\n TUPLE_ORDER(9, 3, 2),\n TUPLE_ORDER(10, 3, 3),\n TUPLE_ORDER(11, 2, 1),\n TUPLE_ORDER(12, 2, 5)\n ]\n\nNB_SLABS = 12\nMAX_COLOR_PER_SLAB = 2\n\n# The total number of slabs available. In theory this can be unlimited,\n# but we impose a reasonable upper bound in order to produce a practical\n# optimization model.\n\n# The different slab weights available.\nslab_weights = [ 0, 11, 13, 16, 17, 19, 20, 23, 24, 25,\n 26, 27, 28, 29, 30, 33, 34, 40, 43, 45 ]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnb_orders = len(orders)\nslabs = range(NB_SLABS)\nallcolors = set([ o.color for o in orders ])\n\n# CPO needs lists for pack constraint\norder_weights = [ o.weight for o in orders ]\n\n# The heaviest slab\nmax_slab_weight = max(slab_weights)\n\n# The amount of loss incurred for different amounts of slab use\n# The loss will depend on how much less steel is used than the slab\n# just large enough to produce the coils.\nloss = [ min([sw-use for sw in slab_weights if sw >= use]) for use in range(max_slab_weight+1)]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "Create CPO model
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl = CpoModel(name=\"trucks\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/cp/zeppelin/golomb_ruler.json b/examples/cp/zeppelin/golomb_ruler.json deleted file mode 100644 index b45b04a..0000000 --- a/examples/cp/zeppelin/golomb_ruler.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/golomb_ruler", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Golomb Ruler\n\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires a valid subscription to **Decision Optimization on the Cloud** or a **local installation of CPLEX Optimizers**. \n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the Data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization solve service\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build constraint programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization solve service\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n\nThis problem is not only an intellectual problem. It has a lot of practical applications:\n
Following is an example of Golomb ruler of order 4 and length 6.
\n\n\nThis problem is not only an intellectual problem. It has a lot of practical applications:
\n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\nConstraint Programming is a programming paradigm that allows to express a problem using:\n
\nAll this information, plus some configuration parameters, is aggregated into a single object called model. \n
\nThe remainder of this notebook describes in details how to build and solve this problem with IBM CP Optimizer, using its DOcplex Python modeling API.", "apps": [], "results": {"msg": [{"data": "
Constraint Programming is a programming paradigm that allows to express a problem using:
\nAll this information, plus some configuration parameters, is aggregated into a single object called model.
\n\nThe remainder of this notebook describes in details how to build and solve this problem with IBM CP Optimizer, using its DOcplex Python modeling API.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.", "apps": [], "results": {"msg": [{"data": "Now, we need to import all required modeling functions that are provided by the docplex.cp package:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Import Constraint Programming modelization functions\nfrom docplex.cp.model import CpoModel", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Model the data\n\nThe first thing to define is the model input data.\nIn the case of the Golomb Ruler problem, there is only one input which is the order of the ruler, that is the number of marks:", "apps": [], "results": {"msg": [{"data": "
The first thing to define is the model input data.
\nIn the case of the Golomb Ruler problem, there is only one input which is the order of the ruler, that is the number of marks:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Define required number of marks on the ruler\nORDER = 7", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "\nThe model is represented by a Python object that is filled with the different model elements (variables, constraints, objective function, etc). The first thing to do is then to create such an object:", "apps": [], "results": {"msg": [{"data": "
The model is represented by a Python object that is filled with the different model elements (variables, constraints, objective function, etc). The first thing to do is then to create such an object:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Create model object\nmdl = CpoModel(name=\"GolombRuler\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables\n\n* Now, we need to define the variables of the problem. As the expected problem result is the list of mark positions, the simplest choice is to create one integer variable to represent the position of each mark on the ruler.\n\n* Each variable has a a set of possible values called his domain. To reduce the search space, it is important to reduce this domain as far as possible.\n\n* In our case, we can naively estimate that the maximum distance between two adjacent marks is the order of the ruler minus one. Then the maximal position of a mark is (ORDER - 1)\u00b2. Each variable domain is then limited to an interval [0..(ORDER - 1)\u00b2].\n\n* A list of integer variables can be defined using method integer_var_list(). In our case, defining one variable for each mark can be created as follows:", "apps": [], "results": {"msg": [{"data": "\nTo force all these distances to be different, we use the special all_diff() constraint as follows:", "apps": [], "results": {"msg": [{"data": "
We have used here the operator '-' to express the difference between variables. It may appear strange as the variables are not instanciated at that time, but the Python operator has been overloaded to construct a CP expression instead of attempting to compute the arithmetic difference. All other standard Python operators can be used to make operations between CP objects (<, >, <=, >=, ==, !=, +, -, /, , &, |, //, *, ...). Have a look to documentation for details.
\n\nTo force all these distances to be different, we use the special all_diff() constraint as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Force all distances to be different\nmdl.add(mdl.all_diff(dist))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe call mdl.add(...) is necessary to express that the constraint must be added to the model.", "apps": [], "results": {"msg": [{"data": "The call mdl.add(...) is necessary to express that the constraint must be added to the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\nThe constraint we have expressed above is theoritically enough, and the model can be solved as it is.\n
\nHowever, it does not differentiate between all possible permutations of the different mark positions that are solutions to the problem, for example, 0-1-4-6, 4-6-1-0, 6-0-1-4, etc. As there are ORDER! (factorial of ORDER) such permutations, the search space would be drastically reduced by removing them.\n
\nWe can do that by forcing an order between marks, for example the order of their index:", "apps": [], "results": {"msg": [{"data": "
The constraint we have expressed above is theoritically enough, and the model can be solved as it is.
\n\nHowever, it does not differentiate between all possible permutations of the different mark positions that are solutions to the problem, for example, 0-1-4-6, 4-6-1-0, 6-0-1-4, etc. As there are ORDER! (factorial of ORDER) such permutations, the search space would be drastically reduced by removing them.
\n\nWe can do that by forcing an order between marks, for example the order of their index:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Avoid symmetric solutions by ordering marks\nfor i in range(1, ORDER):\n mdl.add(marks[i] > marks[i - 1])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe also know that first mark is at the beginning of the ruler:", "apps": [], "results": {"msg": [{"data": "We also know that first mark is at the beginning of the ruler:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Force first mark position to zero\nmdl.add(marks[0] == 0)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\nEach optimal solution has a mirror, with all mark distances in the reverse order, for example, 0-1-4-6 and 0-2-5-6. \nThe following constraint can be added to avoid this: ", "apps": [], "results": {"msg": [{"data": "
Each optimal solution has a mirror, with all mark distances in the reverse order, for example, 0-1-4-6 and 0-2-5-6.
\nThe following constraint can be added to avoid this:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Avoid mirror solution\nmdl.add((marks[1] - marks[0]) < (marks[ORDER - 1] - marks[ORDER - 2]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective\n\n* Finally, we want to get the shortest Golomb Ruler. This can be expressed by minimizing the position of the last mark.\nAs we have ordered the marks, we can do this using:", "apps": [], "results": {"msg": [{"data": "As we have ordered the marks, we can do this using:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Minimize ruler size\nmdl.add(mdl.minimize(marks[ORDER - 1]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf the marks were not ordered, we should have use instead: mdl.add(mdl.minimize(mdl.max(marks)))
If the marks were not ordered, we should have use instead:
mdl.add(mdl.minimize(mdl.max(marks)))
If url and key are None, the Modeling layer will look for a local runtime, otherwise will use the credentials.
\nLook at the documentation for a good understanding of the various solving/generation modes.
\n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe model can be solved by calling:", "apps": [], "results": {"msg": [{"data": "The model can be solved by calling:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Solve the model\nprint(\"Solving model....\")\nmsol = mdl.solve(url=SVC_URL, key=SVC_KEY, TimeLimit=10)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 6: Investigate the solution and then run an example analysis\n\nThe shortest way to output the solution that has been found by the solver is to call the method print_solution() as follows:", "apps": [], "results": {"msg": [{"data": "The shortest way to output the solution that has been found by the solver is to call the method print_solution() as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Print solution\nprint(\"Solution: \")\nmsol.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThis output is totally generic and simply prints the value of all model variables, the objective value, and some other solving information.\n\nA more specific output can be generated by writing more code. The following example illustrates how to access specific elements of the solution. ", "apps": [], "results": {"msg": [{"data": "
This output is totally generic and simply prints the value of all model variables, the objective value, and some other solving information.
\n\nA more specific output can be generated by writing more code. The following example illustrates how to access specific elements of the solution.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Print solution\nfrom sys import stdout\nif msol:\n # Print found solution\n stdout.write(\"Solution: \" + msol.get_solve_status() + \"\\n\")\n stdout.write(\"Position of ruler marks: \")\n for v in marks:\n stdout.write(\" \" + str(msol[v]))\n stdout.write(\"\\n\")\n stdout.write(\"Solve time: \" + str(round(msol.get_solve_time(), 2)) + \"s\\n\")\nelse:\n # No solution found\n stdout.write(\"No solution found. Search status: \" + msol.get_solve_status() + \"\\n\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAnother possibility is for example to simulate real ruler using characters, as follows:", "apps": [], "results": {"msg": [{"data": "Another possibility is for example to simulate real ruler using characters, as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Print solution as a ruler\nif msol:\n stdout.write(\"Ruler: +\")\n for i in range(1, ORDER):\n stdout.write('-' * (msol[marks[i]] - msol[marks[i - 1]] - 1) + '+')\n stdout.write(\"\\n\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe last available installable package is available on Pypi here: https://pypi.python.org/pypi/docplex
\n\nA complete set of modeling examples can be downloaded here: https://github.com/IBMDecisionOptimization/docplex-examples
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/cp/zeppelin/house_building.json b/examples/cp/zeppelin/house_building.json deleted file mode 100644 index 981f902..0000000 --- a/examples/cp/zeppelin/house_building.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/house_building", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n\n# House Building with worker skills\n\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires a valid subscription to **Decision Optimization on the Cloud** or a **local installation of CPLEX Optimizers**. \nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the Data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization solve service\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization solve service\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\n
\n
Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.", "apps": [], "results": {"msg": [{"data": "And for display of the solution, ensure last version of matplotlib is available:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import matplotlib\n if matplotlib.__version__ < \"1.4.3\":\n pip.main(['install --upgrade', matplotlib])\nexcept:\n pip.main(['install --user', matplotlib])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow, we need to import all required modeling functions that are provided by the docplex.cp package:", "apps": [], "results": {"msg": [{"data": "Now, we need to import all required modeling functions that are provided by the docplex.cp package:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.cp.model import CpoModel\nfrom sys import stdout\nfrom collections import namedtuple", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Model the data", "apps": [], "results": {"msg": [{"data": "Planning contains the number of houses and the max amount of periods (days) for our schedule
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nNB_HOUSES = 5\nMAX_AMOUNT_OF_PERIODS = 318\nHOUSES = range(1, NB_HOUSES + 1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAll tasks must start and end between 0 and the max amount of periods", "apps": [], "results": {"msg": [{"data": "All tasks must start and end between 0 and the max amount of periods
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nperiod_domain = (0, MAX_AMOUNT_OF_PERIODS)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFor each task type in the house building project, the following table shows the duration of the task in days along with the tasks that must be finished before the task can start. A worker can only work on one task at a time; each task, once started, may not be interrupted.\n\n\n| *Task* | *Duration* | *Preceding tasks* |\n|---|---|---|\n| masonry \t| 35 |\t|\n| carpentry | 15 | masonry |\n| plumbing \t| 40 | masonry |\n| ceiling \t| 15 | masonry |\n| roofing \t| 5 | carpentry |\n| painting \t| 10 | ceiling |\n| windows \t| 5 | roofing |\n| facade \t| 10 | roofing, plumbing |\n| garden \t| 5 | roofing, plumbing |\n| moving \t| 5 | windows, facade, garden, painting | ", "apps": [], "results": {"msg": [{"data": "
For each task type in the house building project, the following table shows the duration of the task in days along with the tasks that must be finished before the task can start. A worker can only work on one task at a time; each task, once started, may not be interrupted.
\n\n\n| Task | Duration | Preceding tasks |
\n|---|---|---|
\n| masonry | 35 | |
\n| carpentry | 15 | masonry |
\n| plumbing | 40 | masonry |
\n| ceiling | 15 | masonry |
\n| roofing | 5 | carpentry |
\n| painting | 10 | ceiling |
\n| windows | 5 | roofing |
\n| facade | 10 | roofing, plumbing |
\n| garden | 5 | roofing, plumbing |
\n| moving | 5 | windows, facade, garden, painting |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Tasks' durations", "apps": [], "results": {"msg": [{"data": "\n\n| *Task* | *Joe* | *Jack* | *Jim* |\n|---|---|---|---|\n|masonry |9 |\t5 |\t0|\n|carpentry |7 |\t0 |\t5|\n|plumbing |0 |\t7 |\t0|\n|ceiling |5 |\t8 |\t0|\n|roofing |6 |\t7 |\t0|\n|painting |0 |\t9 |\t6|\n|windows |8 |\t0 |\t5|\n|fa\u00e7ade |5 |\t5 |\t0|\n|garden |5 |\t5 |\t9|\n|moving |6 |\t0 |\t8|", "apps": [], "results": {"msg": [{"data": "
There are three workers with varying skill levels in regard to the ten tasks. If a worker has a skill level of zero for a task, he may not be assigned to the task.
\n\n\n| Task | Joe | Jack | Jim |
\n|---|---|---|---|
\n|masonry |9 | 5 | 0|
\n|carpentry |7 | 0 | 5|
\n|plumbing |0 | 7 | 0|
\n|ceiling |5 | 8 | 0|
\n|roofing |6 | 7 | 0|
\n|painting |0 | 9 | 6|
\n|windows |8 | 0 | 5|
\n|fa\u00e7ade |5 | 5 | 0|
\n|garden |5 | 5 | 9|
\n|moving |6 | 0 | 8|
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Workers Names", "apps": [], "results": {"msg": [{"data": "find_tasks: returns the task it refers to in the TASKS vector
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef find_tasks(name):\n return next(t for t in TASKS if t.name == name)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nfind_skills: returns the skill it refers to in the SKILLS vector", "apps": [], "results": {"msg": [{"data": "find_skills: returns the skill it refers to in the SKILLS vector
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef find_skills(worker, task):\n return next(s for s in SKILLS if (s.worker == worker) and (s.task == task))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nfind_max_level_skill: returns the tuple \"skill\" where the level is themaximum for a given task", "apps": [], "results": {"msg": [{"data": "findmaxlevel_skill: returns the tuple \"skill\" where the level is themaximum for a given task
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef find_max_level_skill(task):\n st = [s for s in SKILLS if s.task == task]\n return next(sk for sk in st if sk.level == max([s.level for s in st]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "\nThe model is represented by a Python object that is filled with the different model elements (variables, constraints, objective function, etc). The first thing to do is then to create such an object:", "apps": [], "results": {"msg": [{"data": "
The model is represented by a Python object that is filled with the different model elements (variables, constraints, objective function, etc). The first thing to do is then to create such an object:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl = CpoModel(name=\"HouseBuilding\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "\n
Modeling an interval of time during which a particular property holds\n
\n(an activity executes, a resource is idle, a tank must be non-empty, \u2026)
interval_var(start=(0,1000), end=(0,1000), size=(10,20))
\n
\n\n\nModeling an interval of time during which a particular property holds\n
\n(an activity executes, a resource is idle, a tank must be non-empty, \u2026)
interval_var(start=(0,1000), end=(0,1000), size=(10,20))
\n
\n\n\n
For each house, an interval variable is created for each task.
This interval must start and end inside the period_domain and its duration is set as the value stated in TASKS definition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntasks = {} # dict of interval variable for each house and task\nfor house in HOUSES:\n for task in TASKS:\n tasks[(house, task)] = mdl.interval_var(start=period_domain,\n end=period_domain,\n size=task.duration,\n name=\"house {} task {}\".format(house, task))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\n
Modeling optional activities, alternative execution modes for activities, and \u2026 most of the discrete decisions in a schedule\n
interval_var(optional=True, start=(0,1000), end=(0,1000), size=(10,20))
\n
\nModeling optional activities, alternative execution modes for activities, and \u2026 most of the discrete decisions in a schedule\n
interval_var(optional=True, start=(0,1000), end=(0,1000), size=(10,20))
\n
\n\nThe \"**set_optional()**\" specifier allows a choice between different variables, thus between different couples house-skill.\nThis means that the engine decides if the interval will be present or absent in the solution.", "apps": [], "results": {"msg": [{"data": "
For each house, an optional interval variable is created for each skill.
Skill being a tuple (worker, task, level), this means that for each house, an optional interval variable is created for each couple worker-task such that the skill level of this worker for this task is > 0.
\nThe \"set_optional()\" specifier allows a choice between different variables, thus between different couples house-skill.
\nThis means that the engine decides if the interval will be present or absent in the solution.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nwtasks = {} # dict of interval variable for each house and skill\nfor house in HOUSES:\n for skill in SKILLS:\n iv = mdl.interval_var(name='H' + str(house) + '-' + skill.task + '(' + skill.worker + ')')\n iv.set_optional()\n wtasks[(house, skill)] = iv", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the business constraints", "apps": [], "results": {"msg": [{"data": "\n
Semantic of the constraints handles optionality (as for all constraints in CP Optimizer).\n
\nExample of endBeforeStart:
\nend_before_start(a,b,z)
\npresent(a) AND present(b) ⇒ end(a)+z ⩽ start(b) \n
Semantic of the constraints handles optionality (as for all constraints in CP Optimizer).\n
\nExample of endBeforeStart:
\n\n
endbeforestart(a,b,z)
present(a) AND present(b) ⇒ end(a)+z ⩽ start(b)
\n
The tasks in the model have precedence constraints that are added to the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in HOUSES:\n for p in TASK_PRECEDENCES:\n mdl.add(mdl.end_before_start(tasks[(h, find_tasks(p.beforeTask))], tasks[(h, find_tasks(p.afterTask))]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\n
alternative(a,[b1,...,bn])
\n
\n\n\nalternative(a,[b1,...,bn])
\n
\n\n\n
To constrain the solution so that exactly one of the interval variables wtasks associated with a given task of a given house is to be present in the solution, an \"alternative\" constraint is used.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in HOUSES:\n for t in TASKS:\n mdl.add(mdl.alternative(tasks[(h, t)], [wtasks[(h, s)] for s in SKILLS if (s.task == t.name)], 1))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nTo add the constraints that a given worker can be assigned only one task at a given moment in time, a **noOverlap** constraint is used.", "apps": [], "results": {"msg": [{"data": "
To add the constraints that a given worker can be assigned only one task at a given moment in time, a noOverlap constraint is used.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor w in WORKERS:\n mdl.add(mdl.no_overlap([wtasks[(h, s)] for h in HOUSES for s in SKILLS if s.worker == w]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective", "apps": [], "results": {"msg": [{"data": "\nThe objective of this problem is to maximize the skill level used for all the tasks.", "apps": [], "results": {"msg": [{"data": "
The presence of an interval variable in wtasks in the solution must be accounted for in the objective. Thus for each of these possible tasks, the cost is incremented by the product of the skill level and the expression representing the presence of the interval variable in the solution.
\nThe objective of this problem is to maximize the skill level used for all the tasks.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nobj = mdl.sum([s.level * mdl.presence_of(wtasks[(h, s)]) for s in SKILLS for h in HOUSES])\nmdl.add(mdl.maximize(obj))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe model is now completely defined. It is time to solve it !\n\nTo use the CP Optimizer solver available on the IBM Decision Optimization on Cloud service:\n
", "apps": [], "results": {"msg": [{"data": "
The model is now completely defined. It is time to solve it !
\n\nTo use the CP Optimizer solver available on the IBM Decision Optimization on Cloud service:
\nYou can set POP_UP_GRAPHIC=True if you prefer a pop up graphic window instead of an inline one.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nPOP_UP_GRAPHIC=False", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport docplex.cp.utils_visu as visu\nimport matplotlib.pyplot as plt\nif not POP_UP_GRAPHIC:\n %matplotlib inline\n#Change the plot size\nfrom pylab import rcParams\nrcParams['figure.figsize'] = 15, 3", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Draw solution", "apps": [], "results": {"msg": [{"data": "With the aim to facilitate the display of tasks names, we keep only the n first characters.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef compact_name(name,n): return name[:n]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol and visu.is_visu_enabled():\n workers_colors = {}\n workers_colors[\"Joe\"] = 'lightblue'\n workers_colors[\"Jack\"] = 'violet'\n workers_colors[\"Jim\"] = 'lightgreen'\n visu.timeline('Solution per houses', 0, MAX_AMOUNT_OF_PERIODS)\n for h in HOUSES:\n visu.sequence(name=\"house \" + str(h))\n for s in SKILLS:\n wt = msol.get_var_solution(wtasks[(h,s)])\n if wt.is_present():\n color = workers_colors[s.worker]\n wtname = compact_name(s.task,2)\n visu.interval(wt, color, wtname)\n visu.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe purpose of this function is to compact the names of the different tasks with the aim of making the graphical display readable. \nFor example \"H3-garden\" becomes \"G3\"", "apps": [], "results": {"msg": [{"data": "The purpose of this function is to compact the names of the different tasks with the aim of making the graphical display readable.
\nFor example \"H3-garden\" becomes \"G3\"
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef compact_house_task(name):\n loc, task = name[1:].split('-', 1)\n return task[0].upper() + loc", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nGreen-like color when task is using the most skilled worker\nRed-like color when task does not use the most skilled worker", "apps": [], "results": {"msg": [{"data": "Green-like color when task is using the most skilled worker
\nRed-like color when task does not use the most skilled worker
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol and visu.is_visu_enabled():\n visu.timeline('Solution per workers', 0, MAX_AMOUNT_OF_PERIODS)\n for w in WORKERS:\n visu.sequence(name=w)\n for h in HOUSES:\n for s in SKILLS:\n if s.worker == w:\n wt = msol.get_var_solution(wtasks[(h,s)])\n if wt.is_present():\n ml = find_max_level_skill(s.task).level\n if s.level == ml:\n color = 'lightgreen'\n else:\n color = 'salmon'\n wtname = compact_house_task(wt.get_name())\n visu.interval(wt, color, wtname)\n visu.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe last available installable package is available on Pypi here: https://pypi.python.org/pypi/docplex
\n\nA complete set of modeling examples can be downloaded here: https://github.com/IBMDecisionOptimization/docplex-examples
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/cp/zeppelin/n_queen.json b/examples/cp/zeppelin/n_queen.json deleted file mode 100644 index 93e6047..0000000 --- a/examples/cp/zeppelin/n_queen.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/n_queen", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# The eight queens puzzle\n\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires a valid subscription to **Decision Optimization on the Cloud** or a **local installation of CPLEX Optimizers**. \nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the Data\n * Step 4: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Solve with Decision Optimization solve service\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build constraint programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n* Step 4: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Solve with Decision Optimization solve service\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nchessboard so that no two queens threaten each other. Thus, a solution requires
\nthat no two queens share the same row, column, or diagonal.
\n\nplacing n queens on an nxn chessboard, where solutions exist for all natural
\nnumbers n with the exception of n=2 and n=3.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* https://en.wikipedia.org/wiki/Eight_queens_puzzle", "apps": [], "results": {"msg": [{"data": "+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.\n\n__Set your DOcplexcloud credentials:__\n0. A first option is to set the DOcplexcloud url and key directly in the model source file *(see below)*\n1. For a persistent setting, create a Python file __docloud_config.py__ somewhere that is visible from the __PYTHONPATH__", "apps": [], "results": {"msg": [{"data": "Set your DOcplexcloud credentials:
\nSet model parameter
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nNB_QUEEN = 8", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "Create CPO model
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl = CpoModel(name=\"NQueen\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "Import required external libraries (numpy and matplotlib)
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import numpy as np\n import matplotlib.pyplot as plt\n VISU_ENABLED = True\nexcept ImportError:\n VISU_ENABLED = False", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef display(sol):\n \n chess_board = np.zeros((NB_QUEEN, NB_QUEEN, 3))\n black = 0.5\n white = 1\n for l in range(NB_QUEEN):\n for c in range(NB_QUEEN):\n if (l%2 == c%2):\n col = white\n else:\n col = black\n chess_board[l,c,::]=col\n\n fig, ax = plt.subplots(figsize=(NB_QUEEN / 2, NB_QUEEN / 2))\n ax.imshow(chess_board, interpolation='none')\n # wq_im_file = \"./n_queen_utils/WQueen.png\"\n # bq_im_file = \"./n_queen_utils/BQueen.png\"\n wq_im_file = \"https://github.com/IBMDecisionOptimization/docplex-examples/blob/master/examples/cp/jupyter/n_queen_utils/WQueen.png?raw=true\"\n bq_im_file = \"https://github.com/IBMDecisionOptimization/docplex-examples/blob/master/examples/cp/jupyter/n_queen_utils/BQueen.png?raw=true\"\n wq = plt.imread(wq_im_file)\n bq = plt.imread(bq_im_file)\n for y, x in enumerate(sol):\n if (x%2 == y%2):\n queen = bq\n else:\n queen = wq \n ax.imshow(queen, extent=[x-0.4, x + 0.4, y - 0.4, y + 0.4])\n ax.set(xticks=[], yticks=[])\n ax.axis('image')\n plt.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol: \n stdout.write(\"Solution:\")\n sol = [msol[v] for v in x]\n for v in range(NB_QUEEN):\n stdout.write(\" \" + str(sol[v]))\n stdout.write(\"\\n\")\n stdout.write(\"Solve time: \" + str(msol.get_solve_time()) + \"\\n\")\n if VISU_ENABLED:\n display(sol)\nelse:\n stdout.write(\"No solution found\\n\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/cp/zeppelin/sched_square.json b/examples/cp/zeppelin/sched_square.json deleted file mode 100644 index a7436c0..0000000 --- a/examples/cp/zeppelin/sched_square.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/sched_square", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Sched Square\n\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires a valid subscription to **Decision Optimization on the Cloud** or a **local installation of CPLEX Optimizers**. \nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the Data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the search phase\n * Solve with Decision Optimization solve service\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build constraint programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the search phase\n
\n * Solve with Decision Optimization solve service\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.\n\n#### Set your DOcplexcloud credentials:\n0. A first option is to set the DOcplexcloud url and key directly in the model source file *(see below)*\n1. For a persistent setting, create a Python file __docloud_config.py__ somewhere that is visible from the __PYTHONPATH__", "apps": [], "results": {"msg": [{"data": "Size of the englobing square
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nSIZE_SQUARE = 112", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSizes of the sub-squares", "apps": [], "results": {"msg": [{"data": "Sizes of the sub-squares
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nSIZE_SUBSQUARE = [50, 42, 37, 35, 33, 29, 27, 25, 24, 19, 18, 17, 16, 15, 11, 9, 8, 7, 6, 4, 2]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "You can set POP_UP_GRAPHIC=True if you prefer a pop up graphic window instead of an inline one.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nPOP_UP_GRAPHIC=False", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol and visu.is_visu_enabled():\n import matplotlib.cm as cm\n from matplotlib.patches import Polygon\n \n \n # Plot external square\n print(\"Plotting squares....\")\n fig, ax = plt.subplots()\n plt.plot((0, 0), (0, SIZE_SQUARE), (SIZE_SQUARE, SIZE_SQUARE), (SIZE_SQUARE, 0))\n for i in range(len(SIZE_SUBSQUARE)):\n # Display square i\n (sx, sy) = (msol.get_var_solution(x[i]), msol.get_var_solution(y[i]))\n (sx1, sx2, sy1, sy2) = (sx.get_start(), sx.get_end(), sy.get_start(), sy.get_end())\n poly = Polygon([(sx1, sy1), (sx1, sy2), (sx2, sy2), (sx2, sy1)], fc=cm.Set2(float(i) / len(SIZE_SUBSQUARE)))\n ax.add_patch(poly)\n # Display identifier of square i at its center\n ax.text(float(sx1 + sx2) / 2, float(sy1 + sy2) / 2, str(SIZE_SUBSQUARE[i]), ha='center', va='center')\n plt.margins(0)\n plt.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/cp/zeppelin/scheduling_tuto.json b/examples/cp/zeppelin/scheduling_tuto.json deleted file mode 100644 index 20b5577..0000000 --- a/examples/cp/zeppelin/scheduling_tuto.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/scheduling_tuto", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Tutorial: Getting started with *Scheduling* in CPLEX for Python", "apps": [], "results": {"msg": [{"data": "This notebook introduces the basic building blocks of a scheduling model that can be solved using Constraint Programming Optimizer (named CP Optimizer in the following) that is included in CPLEX for Python.
\n\nIt is part of Prescriptive Analytics for Python and requires a valid subscription to Decision Optimization on Cloud or a local installation of CPLEX Optimizers.
\nDiscover us here.
\n\nTo follow the examples in this section, some knowledge about optimization (math programming or constraint programming) and about modeling optimization problems is necessary.
\nFor beginners in optimization, following the online free Decision Optimization tutorials (here and here) might help to get a better understanding of Mathematical Optimization.
\n\n\nEach chapter of this notebook is a self-contained separate lesson.
\n\nThis chapter describes the basic characteristics of a scheduling program.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Set up the model solving\n\nSolving capabilities are required to solve example models that are given in the following. \nThere are several ways to solve a model:\n\n* Subscribe to the private cloud offer or Decision Optimization on Cloud solve service [here](https://developer.ibm.com/docloud).\n* Use DSX Desktop or Local version that contain a pre-installed version of CPLEX Community Edition\n* Use a local solver, a licensed installation of [CPLEX Optimization Studio](https://www.ibm.com/bs-en/marketplace/ibm-ilog-cplex) to run the notebook locally.\n\nWhen using a cloud solving solution, the following attributes must be set with appropriate values: ", "apps": [], "results": {"msg": [{"data": "Solving capabilities are required to solve example models that are given in the following.
\nThere are several ways to solve a model:
\n\nWhen using a cloud solving solution, the following attributes must be set with appropriate values:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nurl = None\nkey = None", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Scheduling building blocks\n\nScheduling is the act of creating a schedule, which is a timetable for planned occurrences. \nScheduling may also involve allocating resources to activities over time. \n\nA scheduling problem can be viewed as a constraint satisfaction problem or as a constrained optimization problem. Regardless of how it is viewed, a scheduling problem is defined by:\n* A set of *time intervals*, to define activities, operations, or tasks to be completed\n* A set of *temporal constraints*, to define possible relationships between the start and end times of the intervals\n* A set of *specialized constraints*, to specify of the complex relationships on a set of intervals due to the state and finite capacity of resources.", "apps": [], "results": {"msg": [{"data": "Scheduling is the act of creating a schedule, which is a timetable for planned occurrences.
\nScheduling may also involve allocating resources to activities over time.
\n\nA scheduling problem can be viewed as a constraint satisfaction problem or as a constrained optimization problem. Regardless of how it is viewed, a scheduling problem is defined by:
\nA scheduling model starts with the creation of the model container, as follows
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nfrom docplex.cp.model import *", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl0 = CpoModel()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThis code creates a CP model container that allows the use of constraints that are specific to constraint programming or to\nscheduling.", "apps": [], "results": {"msg": [{"data": "This code creates a CP model container that allows the use of constraints that are specific to constraint programming or to
\nscheduling.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Declarations of decision variables\n\nVariable declarations define the type of each variable in the model. For example, to create a variable that equals the amount of material shipped from location *i* to location *j*, a variable named *ship* can be created as follows:\n\n ship = [[integer_var(min=0) for j in range(N)] for i in range(N)]\n
", "apps": [], "results": {"msg": [{"data": "Variable declarations define the type of each variable in the model. For example, to create a variable that equals the amount of material shipped from location i to location j, a variable named ship can be created as follows:
\nship = [[integer_var(min=0) for j in range(N)] for i in range(N)]
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThis code declares an *array* (list of lists in Python) of non-negative integer decision variables;ship[i][j]
is the decision variable handling the amount of material shipped from location *i* to location *j*.\n\nFor scheduling there are specific additional decision variables, namely:\n * *interval* variables\n * *sequence* variables.\n\n*Activities*, *operations* and*tasks* are represented as interval decision variables.\n\nAn interval has a *start*, a *end*, a *length*, and a *size*. An interval variable allows for these values to be variable within the model. \nThe start is the lower endpoint of the interval and the end is the upper endpoint of the interval. \nBy default, the size is equal to the length, which is the difference between the end and the start of the interval. \nIn general, the size is a lower bound on the length.\n\nAn interval variable may also be optional, and its presence in the solution is represented by a decision variable. \nIf an interval is not present in the solution, this means that any constraints on this interval acts like the interval is \u201cnot there\u201d.\nThe exact semantics will depend on the specific constraint.\n\nThe following example contains a dictionary of interval decision variables where the sizes of the interval variables are fixed and the keys are 2 dimensional:\n\n itvs = {(h,t) : mdl.interval_var(size = Duration[t]) for h in Houses for t in TaskNames}\n
", "apps": [], "results": {"msg": [{"data": "This code declares an array (list of lists in Python) of non-negative integer decision variables; ship[i][j]
is the decision variable handling the amount of material shipped from location i to location j.
For scheduling there are specific additional decision variables, namely:
\nActivities, operations andtasks are represented as interval decision variables.
\n\nAn interval has a start, a end, a length, and a size. An interval variable allows for these values to be variable within the model.
\nThe start is the lower endpoint of the interval and the end is the upper endpoint of the interval.
\nBy default, the size is equal to the length, which is the difference between the end and the start of the interval.
\nIn general, the size is a lower bound on the length.
\n\nAn interval variable may also be optional, and its presence in the solution is represented by a decision variable.
\nIf an interval is not present in the solution, this means that any constraints on this interval acts like the interval is \u201cnot there\u201d.
\nThe exact semantics will depend on the specific constraint.
\n\nThe following example contains a dictionary of interval decision variables where the sizes of the interval variables are fixed and the keys are 2 dimensional:
\nitvs = {(h,t) : mdl.interval_var(size = Duration[t]) for h in Houses for t in TaskNames}
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Objective function\n\nThe objective function is an expression that has to be optimized. This function consists of variables and data that have been declared earlier in the model.\nThe objective function is introduced by either the *minimize* or the *maximize* function. \n\nFor example:\n\n mdl.minimize(mdl.endOf(tasks[\"moving\"]))\n
\nindicates that the end of the interval variable tasks[\"moving\"]
needs to be minimized.", "apps": [], "results": {"msg": [{"data": "The objective function is an expression that has to be optimized. This function consists of variables and data that have been declared earlier in the model.
\nThe objective function is introduced by either the minimize or the maximize function.
\n\nFor example:
\nmdl.minimize(mdl.endOf(tasks[\"moving\"]))
\n\nindicates that the end of the interval variable tasks[\"moving\"]
needs to be minimized.
The constraints indicate the conditions that are necessary for a feasible solution to the model.
\n\nSeveral types of constraints can be placed on interval variables:
\nThis section provides a completed example model that can be tested.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe problem is a house building problem. There are ten tasks of fixed size, and each of them needs to be assigned a starting time. \n\nThe statements for creating the interval variables that represent the tasks are:", "apps": [], "results": {"msg": [{"data": "The problem is a house building problem. There are ten tasks of fixed size, and each of them needs to be assigned a starting time.
\n\nThe statements for creating the interval variables that represent the tasks are:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmasonry = mdl0.interval_var(size=35)\ncarpentry = mdl0.interval_var(size=15)\nplumbing = mdl0.interval_var(size=40)\nceiling = mdl0.interval_var(size=15)\nroofing = mdl0.interval_var(size=5)\npainting = mdl0.interval_var(size=10)\nwindows = mdl0.interval_var(size=5)\nfacade = mdl0.interval_var(size=10)\ngarden = mdl0.interval_var(size=5)\nmoving = mdl0.interval_var(size=5)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Adding the constraints\n\nThe constraints in this problem are precedence constraints; some tasks cannot start until other tasks have ended. \nFor example, the *ceilings* must be completed before *painting* can begin. \n\nThe set of precedence constraints for this problem can be added to the model with the block:", "apps": [], "results": {"msg": [{"data": "The constraints in this problem are precedence constraints; some tasks cannot start until other tasks have ended.
\nFor example, the ceilings must be completed before painting can begin.
\n\nThe set of precedence constraints for this problem can be added to the model with the block:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl0.add( mdl0.end_before_start(masonry, carpentry) )\nmdl0.add( mdl0.end_before_start(masonry, plumbing) )\nmdl0.add( mdl0.end_before_start(masonry, ceiling) )\nmdl0.add( mdl0.end_before_start(carpentry, roofing) )\nmdl0.add( mdl0.end_before_start(ceiling, painting) )\nmdl0.add( mdl0.end_before_start(roofing, windows) )\nmdl0.add( mdl0.end_before_start(roofing, facade) )\nmdl0.add( mdl0.end_before_start(plumbing, facade) )\nmdl0.add( mdl0.end_before_start(roofing, garden) )\nmdl0.add( mdl0.end_before_start(plumbing, garden) )\nmdl0.add( mdl0.end_before_start(windows, moving) )\nmdl0.add( mdl0.end_before_start(facade, moving) )\nmdl0.add( mdl0.end_before_start(garden, moving) )\nmdl0.add( mdl0.end_before_start(painting, moving) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHere, the special constraint *end_before_start()* ensures that one interval variable ends before the other starts. \nIf one of the interval variables is not present, the constraint is automatically satisfied.", "apps": [], "results": {"msg": [{"data": "Here, the special constraint end_before_start() ensures that one interval variable ends before the other starts.
\nIf one of the interval variables is not present, the constraint is automatically satisfied.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Calling the solve", "apps": [], "results": {"msg": [{"data": "The interval variables and precedence constraints completely describe this simple problem.
\n\nPrint statements display the solution, after values have been assigned to the start and end of each of the interval variables in the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol0:\n var_sol = msol0.get_var_solution(masonry)\n print(\"Masonry : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(carpentry)\n print(\"Carpentry : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(plumbing)\n print(\"Plumbing : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(ceiling)\n print(\"Ceiling : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(roofing)\n print(\"Roofing : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(painting)\n print(\"Painting : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(windows)\n print(\"Windows : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(facade)\n print(\"Facade : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\n var_sol = msol0.get_var_solution(moving)\n print(\"Moving : {}..{}\".format(var_sol.get_start(), var_sol.get_end()))\nelse:\n print(\"No solution found\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nTo understand the solution found by *CP Optimizer* to this satisfiability scheduling problem, consider the line:\nMasonry : 0..35
\n\nThe interval variable representing the masonry task, which has size 35, has been assigned the interval [0,35). \nMasonry starts at time 0 and ends at the time point 35.", "apps": [], "results": {"msg": [{"data": "To understand the solution found by CP Optimizer to this satisfiability scheduling problem, consider the line:
\nMasonry : 0..35
The interval variable representing the masonry task, which has size 35, has been assigned the interval [0,35).
\nMasonry starts at time 0 and ends at the time point 35.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nGraphical view of these tasks can be obtained with following additional code: ", "apps": [], "results": {"msg": [{"data": "Graphical view of these tasks can be obtained with following additional code:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport docplex.cp.utils_visu as visu\nimport matplotlib.pyplot as plt\n#Change the plot size\nfrom pylab import rcParams\nrcParams['figure.figsize'] = 15, 3", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol0:\n wt = msol0.get_var_solution(masonry) \n visu.interval(wt, 'lightblue', 'masonry') \n wt = msol0.get_var_solution(carpentry) \n visu.interval(wt, 'lightblue', 'carpentry')\n wt = msol0.get_var_solution(plumbing) \n visu.interval(wt, 'lightblue', 'plumbing')\n wt = msol0.get_var_solution(ceiling) \n visu.interval(wt, 'lightblue', 'ceiling')\n wt = msol0.get_var_solution(roofing) \n visu.interval(wt, 'lightblue', 'roofing')\n wt = msol0.get_var_solution(painting) \n visu.interval(wt, 'lightblue', 'painting')\n wt = msol0.get_var_solution(windows) \n visu.interval(wt, 'lightblue', 'windows')\n wt = msol0.get_var_solution(facade) \n visu.interval(wt, 'lightblue', 'facade')\n wt = msol0.get_var_solution(moving) \n visu.interval(wt, 'lightblue', 'moving')\n visu.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Note on interval variables\n\nAfter a time interval has been assigned a start value (say s) and an end value (say e), the interval is written as [s,e). \nThe time interval does not include the endpoint e. \nIf another interval variable is constrained to be placed after this interval, it can start at the time e.", "apps": [], "results": {"msg": [{"data": "After a time interval has been assigned a start value (say s) and an end value (say e), the interval is written as [s,e).
\nThe time interval does not include the endpoint e.
\nIf another interval variable is constrained to be placed after this interval, it can start at the time e.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Chapter 2. Modeling and solving house building with an objective", "apps": [], "results": {"msg": [{"data": "This chapter presents the same house building example in such a manner that minimizes an objective.
\n\nIt intends to present how to:
\nThe objective to minimize is here the cost associated with performing specific tasks before a preferred earliest start date or after a preferred latest end date.
\nSome tasks must necessarily take place before other tasks, and each task has a given duration.
\n\nTo find a solution to this problem, a three-stage method is used: describe, model, and solve.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Problem to be solved\n\nThe problem consists of assigning start dates to tasks in such a way that the resulting schedule satisfies precedence constraints and minimizes a criterion. \nThe criterion for this problem is to minimize the earliness costs associated with starting certain tasks earlier than a given date, and tardiness costs associated with completing certain tasks later than a given date.\n\nFor each task in the house building project, the following table shows the duration (measured in days) of the task along with the tasks that must finish before the task can start.\n\n**Note:**\nThe unit of time represented by an interval variable is not defined. As a result, the size of the masonry task in this problem could be 35 hours or 35 weeks or 35 months.", "apps": [], "results": {"msg": [{"data": "The problem consists of assigning start dates to tasks in such a way that the resulting schedule satisfies precedence constraints and minimizes a criterion.
\nThe criterion for this problem is to minimize the earliness costs associated with starting certain tasks earlier than a given date, and tardiness costs associated with completing certain tasks later than a given date.
\n\nFor each task in the house building project, the following table shows the duration (measured in days) of the task along with the tasks that must finish before the task can start.
\n\nNote:
\nThe unit of time represented by an interval variable is not defined. As a result, the size of the masonry task in this problem could be 35 hours or 35 weeks or 35 months.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHouse construction tasks:\n\n| Task | Duration | Preceding tasks |\n|-----------|----------|-----------------------------------|\n| masonry | 35 | |\n| carpentry | 15 | masonry |\n| plumbing | 40 | masonry |\n| ceiling | 15 | masonry |\n| roofing | 5 | carpentry |\n| painting | 10 | ceiling |\n| windows | 5 | roofing |\n| facade | 10 | roofing, plumbing |\n| garden | 5 | roofing, plumbing |\n| moving | 5 | windows, facade, garden, painting |", "apps": [], "results": {"msg": [{"data": "House construction tasks:
\n\n| Task | Duration | Preceding tasks |
\n|-----------|----------|-----------------------------------|
\n| masonry | 35 | |
\n| carpentry | 15 | masonry |
\n| plumbing | 40 | masonry |
\n| ceiling | 15 | masonry |
\n| roofing | 5 | carpentry |
\n| painting | 10 | ceiling |
\n| windows | 5 | roofing |
\n| facade | 10 | roofing, plumbing |
\n| garden | 5 | roofing, plumbing |
\n| moving | 5 | windows, facade, garden, painting |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe other information for the problem includes the earliness and tardiness costs associated with some tasks.", "apps": [], "results": {"msg": [{"data": "The other information for the problem includes the earliness and tardiness costs associated with some tasks.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHouse construction task earliness costs:\n \n| Task | Preferred earliest start date | Cost per day for starting early |\n|-----------|-------------------------------|---------------------------------|\n| masonry | 25 | 200.0 |\n| carpentry | 75 | 300.0 |\n| ceiling |75 | 100.0 |", "apps": [], "results": {"msg": [{"data": "House construction task earliness costs:
\n\n| Task | Preferred earliest start date | Cost per day for starting early |
\n|-----------|-------------------------------|---------------------------------|
\n| masonry | 25 | 200.0 |
\n| carpentry | 75 | 300.0 |
\n| ceiling |75 | 100.0 |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHouse construction task tardiness costs:\n \n| Task | Preferred latest end date | Cost per day for ending late |\n|--------|---------------------------|------------------------------|\n| moving | 100 | 400.0 |", "apps": [], "results": {"msg": [{"data": "House construction task tardiness costs:
\n\n| Task | Preferred latest end date | Cost per day for ending late |
\n|--------|---------------------------|------------------------------|
\n| moving | 100 | 400.0 |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSolving the problem consists of identifying starting dates for the tasks such that the total cost, determined by the earliness and lateness costs, is minimized.", "apps": [], "results": {"msg": [{"data": "Solving the problem consists of identifying starting dates for the tasks such that the total cost, determined by the earliness and lateness costs, is minimized.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 1: Describe the problem\n\nThe first step in modeling the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.\n\nWriting a natural language description of this problem requires to answer these questions:\n* What is the known information in this problem ?\n* What are the decision variables or unknowns in this problem ?\n* What are the constraints on these variables ?\n* What is the objective ?", "apps": [], "results": {"msg": [{"data": "The first step in modeling the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.
\n\nWriting a natural language description of this problem requires to answer these questions:
\nThere are ten house building tasks, each with a given duration. For each task,
\nthere is a list of tasks that must be completed before the task can start. Some
\ntasks also have costs associated with an early start date or late end date.
\n\n\nThe unknowns are the date that each task will start. The cost is determined by the assigned start dates.
\n\n\nIn this case, each constraint specifies that a particular task may not begin until one or more given tasks have been completed.
\n\n\nThe objective is to minimize the cost incurred through earliness and tardiness costs.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 2: Declare the interval variables", "apps": [], "results": {"msg": [{"data": "In the model, each task is represented by an interval variables.
\nEach variable represents the unknown information, the scheduled interval for each activity.
\nAfter the model is executed, the values assigned to these interval variables will represent the solution to the problem.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Declaration of engine\nA scheduling model starts with the declaration of the engine as follows:", "apps": [], "results": {"msg": [{"data": "A scheduling model starts with the declaration of the engine as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nfrom docplex.cp.model import *\n\nmdl1 = CpoModel()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe declaration of necessary interval variables is done as follows:", "apps": [], "results": {"msg": [{"data": "The declaration of necessary interval variables is done as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmasonry = mdl1.interval_var(size=35)\ncarpentry = mdl1.interval_var(size=15)\nplumbing = mdl1.interval_var(size=40)\nceiling = mdl1.interval_var(size=15)\nroofing = mdl1.interval_var(size=5)\npainting = mdl1.interval_var(size=10)\nwindows = mdl1.interval_var(size=5)\nfacade = mdl1.interval_var(size=10)\ngarden = mdl1.interval_var(size=5)\nmoving = mdl1.interval_var(size=5)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 3: Add the precedence constraints", "apps": [], "results": {"msg": [{"data": "In this example, certain tasks can start only after other tasks have been completed.
\nCP Optimizer allows to express constraints involving temporal relationships between pairs of interval variables using precedence constraints.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nPrecedence constraints are used to specify when an interval variable must start or end with respect to the start or end time of another interval variable. \n\nThe following types of precedence constraints are available; if *a* and *b* denote interval variables, both interval variables are present, and *delay* is a number or integer expression (0 by default), then:\n* *end_before_end(a, b, delay)* constrains at least the given delay to elapse between the end of a and the end of b. It imposes the inequality endTime(a) + delay <= endTime(b).\n* *end_before_start(a, b, delay)* constrains at least the given delay to elapse between the end of a and the start of b. It imposes the inequality endTime(a) + delay <= startTime(b).\n* *end_at_end(a, b, delay)* constrains the given delay to separate the end of a and the end of ab. It imposes the equality endTime(a) + delay == endTime(b).\n* *end_at_start(a, b, delay)* constrains the given delay to separate the end of a and the start of b. It imposes the equality endTime(a) + delay == startTime(b).\n* *start_before_end(a, b, delay)* constrains at least the given delay to elapse between the start of a and the end of b. It imposes the inequality startTime(a) + delay <= endTime(b).\n* *start_before_start(a, b, delay)* constrains at least the given delay to elapse between the start of act1 and the start of act2. It imposes the inequality startTime(a) + delay <= startTime(b).\n* *start_at_end(a, b, delay)* constrains the given delay to separate the start of a and the end of b. It imposes the equality startTime(a) + delay == endTime(b).\n* *start_at_start(a, b, delay)* constrains the given delay to separate the start of a and the start of b. It imposes the equality startTime(a) + delay == startTime(b).\n\nIf either interval *a* or *b* is not present in the solution, the constraint is automatically satisfied, and it is as if the constraint was never imposed.", "apps": [], "results": {"msg": [{"data": "Precedence constraints are used to specify when an interval variable must start or end with respect to the start or end time of another interval variable.
\n\nThe following types of precedence constraints are available; if a and b denote interval variables, both interval variables are present, and delay is a number or integer expression (0 by default), then:
\nIf either interval a or b is not present in the solution, the constraint is automatically satisfied, and it is as if the constraint was never imposed.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFor our model, precedence constraints can be added with the following code:", "apps": [], "results": {"msg": [{"data": "For our model, precedence constraints can be added with the following code:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl1.add( mdl1.end_before_start(masonry, carpentry) )\nmdl1.add( mdl1.end_before_start(masonry, plumbing) )\nmdl1.add( mdl1.end_before_start(masonry, ceiling) )\nmdl1.add( mdl1.end_before_start(carpentry, roofing) )\nmdl1.add( mdl1.end_before_start(ceiling, painting) )\nmdl1.add( mdl1.end_before_start(roofing, windows) )\nmdl1.add( mdl1.end_before_start(roofing, facade) )\nmdl1.add( mdl1.end_before_start(plumbing, facade) )\nmdl1.add( mdl1.end_before_start(roofing, garden) )\nmdl1.add( mdl1.end_before_start(plumbing, garden) )\nmdl1.add( mdl1.end_before_start(windows, moving) )\nmdl1.add( mdl1.end_before_start(facade, moving) )\nmdl1.add( mdl1.end_before_start(garden, moving) )\nmdl1.add( mdl1.end_before_start(painting, moving) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nTo model the cost for starting a task earlier than the preferred starting date, the expression *start_of()* can be used. \nIt represents the start of an interval variable as an integer expression.", "apps": [], "results": {"msg": [{"data": "To model the cost for starting a task earlier than the preferred starting date, the expression start_of() can be used.
\nIt represents the start of an interval variable as an integer expression.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFor each task that has an earliest preferred start date, the number of days before the preferred date it is scheduled to start can be determined using the expression *start_of()*.\nThis expression can be negative if the task starts after the preferred date. \nTaking the maximum of this value and 0 using *max()* allows to determine how many days early the task is scheduled to start. \nWeighting this value with the cost per day of starting early determines the cost associated with the task.\n\nThe cost for ending a task later than the preferred date is modeled in a similar manner using the expression *endOf()*. \nThe earliness and lateness costs can be summed to determine the total cost.", "apps": [], "results": {"msg": [{"data": "For each task that has an earliest preferred start date, the number of days before the preferred date it is scheduled to start can be determined using the expression start_of().
\nThis expression can be negative if the task starts after the preferred date.
\nTaking the maximum of this value and 0 using max() allows to determine how many days early the task is scheduled to start.
\nWeighting this value with the cost per day of starting early determines the cost associated with the task.
\n\nThe cost for ending a task later than the preferred date is modeled in a similar manner using the expression endOf().
\nThe earliness and lateness costs can be summed to determine the total cost.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 4: Add the objective\nThe objective function to be minimized can be written as follows:", "apps": [], "results": {"msg": [{"data": "The objective function to be minimized can be written as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nobj = mdl1.minimize( 400 * mdl1.max([mdl1.end_of(moving) - 100, 0]) \n + 200 * mdl1.max([25 - mdl1.start_of(masonry), 0]) \n + 300 * mdl1.max([75 - mdl1.start_of(carpentry), 0]) \n + 100 * mdl1.max([75 - mdl1.start_of(ceiling), 0]) )\nmdl1.add(obj)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSolving a problem consists of finding a value for each decision variable so that all constraints are satisfied. \nIt is not always know beforehand whether there is a solution that satisfies all the constraints of the problem. \nIn some cases, there may be no solution. In other cases, there may be many solutions to a problem.", "apps": [], "results": {"msg": [{"data": "Solving a problem consists of finding a value for each decision variable so that all constraints are satisfied.
\nIt is not always know beforehand whether there is a solution that satisfies all the constraints of the problem.
\nIn some cases, there may be no solution. In other cases, there may be many solutions to a problem.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 5: Solve the model and display the solution", "apps": [], "results": {"msg": [{"data": "Graphical display of the same result is available with:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport docplex.cp.utils_visu as visu\nimport matplotlib.pyplot as plt\n#Change the plot size\nfrom pylab import rcParams\nrcParams['figure.figsize'] = 15, 3", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol1:\n wt = msol1.get_var_solution(masonry) \n visu.interval(wt, 'lightblue', 'masonry') \n wt = msol1.get_var_solution(carpentry) \n visu.interval(wt, 'lightblue', 'carpentry')\n wt = msol1.get_var_solution(plumbing) \n visu.interval(wt, 'lightblue', 'plumbing')\n wt = msol1.get_var_solution(ceiling) \n visu.interval(wt, 'lightblue', 'ceiling')\n wt = msol1.get_var_solution(roofing) \n visu.interval(wt, 'lightblue', 'roofing')\n wt = msol1.get_var_solution(painting) \n visu.interval(wt, 'lightblue', 'painting')\n wt = msol1.get_var_solution(windows) \n visu.interval(wt, 'lightblue', 'windows')\n wt = msol1.get_var_solution(facade) \n visu.interval(wt, 'lightblue', 'facade')\n wt = msol1.get_var_solution(moving) \n visu.interval(wt, 'lightblue', 'moving')\n visu.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe overall cost is 5000 and moving will be completed by day 110.", "apps": [], "results": {"msg": [{"data": "The overall cost is 5000 and moving will be completed by day 110.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Chapter 3. Adding workers and transition times to the house building problem", "apps": [], "results": {"msg": [{"data": "This chapter introduces workers and transition times to the house building problem described in the previous chapters. It allows to learn the following concepts:
\nThe problem to be solved is the scheduling of tasks involved in building multiple houses in a manner that minimizes the costs associated with completing each house after a given due date and with the length of time it takes to build each house.
\nSome tasks must necessarily take place before other tasks, and each task has a predefined duration.
\nEach house has an earliest starting date.
\nMoreover, there are two workers, each of whom must perform a given subset of the necessary tasks, and there is a transition time associated with a worker transferring from one house to another house.
\nA task, once started, cannot be interrupted.
\n\nThe objective is to minimize the cost, which is composed of tardiness costs for certain tasks as well as a cost associated with the length of time it takes to complete each house.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Problem to be solved", "apps": [], "results": {"msg": [{"data": "The problem consists of assigning start dates to a set of tasks in such a way that the schedule satisfies temporal constraints and minimizes a criterion.
\nThe criterion for this problem is to minimize the tardiness costs associated with completing each house later than its specified due date and the cost associated with the length of time it takes to complete each house.
\n\nFor each type of task, the following table shows the duration of the task in days along with the tasks that must be finished before the task can start.
\nIn addition, each type of task must be performed by a specific worker, Jim or Joe.
\nA worker can only work on one task at a time.
\nA task, once started, may not be interrupted.
\nThe time required to transfer from one house to another house is determined by a function based on the location of the two houses.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe following table indicates these details for each task:\n\n| Task | Duration | Worker | Preceding tasks |\n|-----------|----------|--------|-------------------|\n| masonry | 35 | Joe | |\n| carpentry | 15 | Joe | masonry |\n| plumbing | 40 | Jim | masonry |\n| ceiling | 15 | Jim | masonry |\n| roofing | 5 | Joe | carpentry |\n| painting | 10 | Jim | ceiling |\n| windows | 5 | Jim | roofing |\n| facade | 10 | Joe | roofing, plumbing |\n| garden | 5 | Joe | roofing, plumbing |\n| moving | 5 | Jim | windows, facade,garden, painting|", "apps": [], "results": {"msg": [{"data": "The following table indicates these details for each task:
\n\n| Task | Duration | Worker | Preceding tasks |
\n|-----------|----------|--------|-------------------|
\n| masonry | 35 | Joe | |
\n| carpentry | 15 | Joe | masonry |
\n| plumbing | 40 | Jim | masonry |
\n| ceiling | 15 | Jim | masonry |
\n| roofing | 5 | Joe | carpentry |
\n| painting | 10 | Jim | ceiling |
\n| windows | 5 | Jim | roofing |
\n| facade | 10 | Joe | roofing, plumbing |
\n| garden | 5 | Joe | roofing, plumbing |
\n| moving | 5 | Jim | windows, facade,garden, painting|
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFor each of the five houses that must be built, there is an earliest starting date, a due date and a cost per day of completing the house later than the preferred due date.", "apps": [], "results": {"msg": [{"data": "For each of the five houses that must be built, there is an earliest starting date, a due date and a cost per day of completing the house later than the preferred due date.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe house construction tardiness costs is indicated in the following table:\n\n| House | Earliest start date | Preferred latest end date | Cost per day for ending late |\n|-------|---------------------|---------------------------|------------------------------|\n| 0 | 0 | 120 | 100.0 |\n| 1 | 0 | 212 | 100.0 |\n| 2 | 151 | 304 | 100.0 |\n| 3 | 59 | 181 | 200.0 |\n| 4 | 243 | 425 | 100.0 |", "apps": [], "results": {"msg": [{"data": "The house construction tardiness costs is indicated in the following table:
\n\n| House | Earliest start date | Preferred latest end date | Cost per day for ending late |
\n|-------|---------------------|---------------------------|------------------------------|
\n| 0 | 0 | 120 | 100.0 |
\n| 1 | 0 | 212 | 100.0 |
\n| 2 | 151 | 304 | 100.0 |
\n| 3 | 59 | 181 | 200.0 |
\n| 4 | 243 | 425 | 100.0 |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSolving the problem consists of determining starting dates for the tasks such that the cost, where the cost is determined by the lateness costs and length costs, is minimized.", "apps": [], "results": {"msg": [{"data": "Solving the problem consists of determining starting dates for the tasks such that the cost, where the cost is determined by the lateness costs and length costs, is minimized.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 1: Describe the problem\n\n* What is the known information in this problem ?\n\n There are five houses to be built by two workers. For each house, there are ten house building tasks, each with a given duration, or size. Each house also has a given earliest starting date. For each task, there is a list of tasks that must be completed before the task can start. Each task must be performed by a given worker, and there is a transition time associated with a worker transferring from one house to another house. There are costs associated with completing eachhouse after its preferred due date and with the length of time it takes to complete each house.\n \n \n* What are the decision variables or unknowns in this problem ?\n\n The unknowns are the start and end dates of the interval variables associated with the tasks. Once fixed, these interval variables also determine the cost of the solution. For some of the interval variables, there is a fixed minimum start date.\n\n\n* What are the constraints on these variables ?\n\n There are constraints that specify a particular task may not begin until one or more given tasks have been completed. In addition, there are constraints that specify that a worker can be assigned to only one task at a time and that it takes time for a worker to travel from one house to the other.\n\n\n* What is the objective ?\n\n The objective is to minimize the cost incurred through tardiness and length costs.", "apps": [], "results": {"msg": [{"data": "There are five houses to be built by two workers. For each house, there are ten house building tasks, each with a given duration, or size. Each house also has a given earliest starting date. For each task, there is a list of tasks that must be completed before the task can start. Each task must be performed by a given worker, and there is a transition time associated with a worker transferring from one house to another house. There are costs associated with completing eachhouse after its preferred due date and with the length of time it takes to complete each house.\n
\n\n\nThe unknowns are the start and end dates of the interval variables associated with the tasks. Once fixed, these interval variables also determine the cost of the solution. For some of the interval variables, there is a fixed minimum start date.
\n\n\nThere are constraints that specify a particular task may not begin until one or more given tasks have been completed. In addition, there are constraints that specify that a worker can be assigned to only one task at a time and that it takes time for a worker to travel from one house to the other.
\n\n\nThe objective is to minimize the cost incurred through tardiness and length costs.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step2: Prepare data\nFirst coding step is to prepare model data:", "apps": [], "results": {"msg": [{"data": "First coding step is to prepare model data:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nNbHouses = 5\n\nWorkerNames = [\"Joe\", \"Jim\"]\n\nTaskNames = [\"masonry\", \"carpentry\", \"plumbing\", \n \"ceiling\", \"roofing\", \"painting\", \n \"windows\", \"facade\", \"garden\", \"moving\"]\n\nDuration = [35, 15, 40, 15, 5, 10, 5, 10, 5, 5]\n\nWorker = {\"masonry\" : \"Joe\" , \n \"carpentry\": \"Joe\" , \n \"plumbing\" : \"Jim\" , \n \"ceiling\" : \"Jim\" , \n \"roofing\" : \"Joe\" , \n \"painting\" : \"Jim\" , \n \"windows\" : \"Jim\" , \n \"facade\" : \"Joe\" , \n \"garden\" : \"Joe\" , \n \"moving\" : \"Jim\"}\n\nReleaseDate = [ 0, 0, 151, 59, 243]\nDueDate = [120, 212, 304, 181, 425]\nWeight = [100.0, 100.0, 100.0, 200.0, 100.0]\n\nPrecedences = [(\"masonry\", \"carpentry\"),(\"masonry\", \"plumbing\"),\n (\"masonry\", \"ceiling\"), (\"carpentry\", \"roofing\"),\n (\"ceiling\", \"painting\"), (\"roofing\", \"windows\"), \n (\"roofing\", \"facade\"), (\"plumbing\", \"facade\"),\n (\"roofing\", \"garden\"), (\"plumbing\", \"garden\"),\n (\"windows\", \"moving\"), (\"facade\", \"moving\"), \n (\"garden\", \"moving\"), (\"painting\", \"moving\")]\n\nHouses = range(NbHouses)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nOne part of the objective is based on the time it takes to build a house.\nTo model this, one interval variable is used for each house, and is later constrained to span the tasks associated with the given house. \nAs each house has an earliest starting date, and each house interval variable is declared to have a start date no earlier than that release date. \nThe ending date of the task is not constrained, so the upper value of the range for the variable is maxint.", "apps": [], "results": {"msg": [{"data": "One part of the objective is based on the time it takes to build a house.
\nTo model this, one interval variable is used for each house, and is later constrained to span the tasks associated with the given house.
\nAs each house has an earliest starting date, and each house interval variable is declared to have a start date no earlier than that release date.
\nThe ending date of the task is not constrained, so the upper value of the range for the variable is maxint.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 3: Create the house interval variables", "apps": [], "results": {"msg": [{"data": "Each house has a list of tasks that must be scheduled.
\nThe duration, or size, of each task t is Duration[t].
\nThis information allows to build the matrix itvs of interval variables.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nTaskNames_ids = {}\nitvs = {}\nfor h in Houses:\n for i,t in enumerate(TaskNames):\n _name = str(h)+\"_\"+str(t)\n itvs[(h,t)] = mdl2.interval_var(size=Duration[i], name=_name)\n TaskNames_ids[_name] = i", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 5: Add the precedence constraints", "apps": [], "results": {"msg": [{"data": "The tasks of the house building project have precedence constraints that are added to the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n for p in Precedences:\n mdl2.add(mdl2.end_before_start(itvs[(h,p[0])], itvs[(h,p[1])]) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nTo model the cost associated with the length of time it takes to build a single house, the interval variable associated with the house is constrained to start at the start of the first task of the house and end at the end of the last task. \nThis interval variable must span the tasks.\n", "apps": [], "results": {"msg": [{"data": "To model the cost associated with the length of time it takes to build a single house, the interval variable associated with the house is constrained to start at the start of the first task of the house and end at the end of the last task.
\nThis interval variable must span the tasks.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 6: Add the span constraints", "apps": [], "results": {"msg": [{"data": "The constraint span allows to specify that one interval variable must exactly cover a set of interval variables.
\nIn other words, the spanning interval is present in the solution if and only if at least one of the spanned interval variables is present and, in this case, the spanning interval variable starts at the start of the interval variable scheduled earliest in the set and ends at the end of the interval variable scheduled latest in the set.
\n\nFor house h, the interval variable houses[h] is constrained to cover the interval variables in itvs that are associated with the tasks of the given house.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n mdl2.add( mdl2.span(houses[h], [itvs[(h,t)] for t in TaskNames] ) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 7: Create the transition times", "apps": [], "results": {"msg": [{"data": "Transition times can be modeled using tuples with three elements.
\nThe first element is the interval variable type of one task, the second is the interval variable type of the other task and the third element of the tuple is the transition time from the first to the second.
\nAn integer interval variable type can be associated with each interval variable.
\n\nGiven an interval variable a1 that precedes (not necessarily directly) an interval variable a2 in a sequence of non-overlapping interval variables, the transition time between a1 and a2 is an amount of time that must elapse between the end of a1 and the beginning of a2.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntransitionTimes = transition_matrix([[int(abs(i - j)) for j in Houses] for i in Houses])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nEach of the tasks requires a particular worker. \nAs a worker can perform only one task at a time, it is necessary to know all of the tasks that a worker must perform and then constrain that these intervals not overlap and respect the transition times.\nA sequence variable represents the order in which the workers perform the tasks.\n\nNote that the sequence variable does not force the tasks to not overlap or the order of tasks. In a later step, a constraint is created that enforces these relations on the sequence of interval variables.", "apps": [], "results": {"msg": [{"data": "Each of the tasks requires a particular worker.
\nAs a worker can perform only one task at a time, it is necessary to know all of the tasks that a worker must perform and then constrain that these intervals not overlap and respect the transition times.
\nA sequence variable represents the order in which the workers perform the tasks.
\n\nNote that the sequence variable does not force the tasks to not overlap or the order of tasks. In a later step, a constraint is created that enforces these relations on the sequence of interval variables.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 8: Create the sequence variables", "apps": [], "results": {"msg": [{"data": "Using the decision variable type sequence, variable can be created to represent a sequence of interval variables. The sequence can contain a subset of the variables or be empty.
\nIn a solution, the sequence will represent a total order over all the intervals in the set that are present in the solution.
\nThe assigned order of interval variables in the sequence does not necessarily determine their relative positions in time in the schedule.
\nThe sequence variable takes an array of interval variables as well as the transition types for each of those variables.
\nInterval sequence variables are created for Jim and Joe, using the arrays of their tasks and the task locations.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nworkers = {w : mdl2.sequence_var([ itvs[(h,t)] for h in Houses for t in TaskNames if Worker[t]==w ], \n types=[h for h in Houses for t in TaskNames if Worker[t]==w ], name=\"workers_\"+w) \n for w in WorkerNames}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 9: Add the no overlap constraint", "apps": [], "results": {"msg": [{"data": "Now that the sequence variables have been created, each sequence must be constrained such that the interval variables do not overlap in the solution, that the transition times are respected, and that the sequence represents the relations of the interval variables in time.
\n\nThe constraint no_overlap allows to constrain an interval sequence variable to define a chain of non-overlapping intervals that are present in the solution.
\nIf a set of transition tuples is specified, it defines the minimal time that must elapse between two intervals in the chain.
\nNote that intervals which are not present in the solution are automatically removed from the sequence.
\nOne no overlap constraint is created for the sequence interval variable for each worker.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor w in WorkerNames:\n mdl2.add( mdl2.no_overlap(workers[w], transitionTimes) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe cost for building a house is the sum of the tardiness cost and the number of days it takes from start to finish building the house. \nTo model the cost associated with a task being completed later than its preferred latest end date, the expression *endOf()* can be used to determine the end date of the house interval variable. \nTo model the cost of the length of time it takes to build the house, the expression *lengthOf()* can be used, which returns an expression representing the length of an interval variable. ", "apps": [], "results": {"msg": [{"data": "The cost for building a house is the sum of the tardiness cost and the number of days it takes from start to finish building the house.
\nTo model the cost associated with a task being completed later than its preferred latest end date, the expression endOf() can be used to determine the end date of the house interval variable.
\nTo model the cost of the length of time it takes to build the house, the expression lengthOf() can be used, which returns an expression representing the length of an interval variable.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 10: Add the objective", "apps": [], "results": {"msg": [{"data": "The objective of this problem is to minimize the cost as represented by the cost expression.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# create the obj and add it.\nmdl2.add( \n mdl2.minimize( \n mdl2.sum(Weight[h] * mdl2.max([0, mdl2.end_of(houses[h])-DueDate[h]]) + mdl2.length_of(houses[h]) for h in Houses) \n ) \n)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 11: Solve the model", "apps": [], "results": {"msg": [{"data": "The search for an optimal solution in this problem can potentiality take a long time. A fail limit can be placed on the solve process to limit the search process.
\nThe search stops when the fail limit is reached, even if optimality of the current best solution is not guaranteed.
\nThe code for limiting the solve process is provided below:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Solve the model\nprint(\"\\nSolving model....\")\nmsol2 = mdl2.solve(url=url, key=key, FailLimit=30000)\nprint(\"done\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol2:\n print(\"Cost will be \" + str(msol2.get_objective_values()[0]))\nelse:\n print(\"No solution found\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Viewing the results of sequencing problems in a Gantt chart\n# (double click on the gantt to see details)\nimport docplex.cp.utils_visu as visu\nimport matplotlib.pyplot as plt\n#Change the plot size\nfrom pylab import rcParams\nrcParams['figure.figsize'] = 15, 3\n\ndef showsequence(msol, s, setup, tp):\n seq = msol.get_var_solution(s)\n visu.sequence(name=s.get_name())\n vs = seq.get_value()\n for v in vs:\n nm = v.get_name()\n visu.interval(v, tp[TaskNames_ids[nm]], nm)\n for i in range(len(vs) - 1):\n end = vs[i].get_end()\n tp1 = tp[TaskNames_ids[vs[i].get_name()]]\n tp2 = tp[TaskNames_ids[vs[i + 1].get_name()]]\n visu.transition(end, end + setup.get_value(tp1, tp2))\nif msol2:\n visu.timeline(\"Solution for SchedSetup\")\n for w in WorkerNames:\n types=[h for h in Houses for t in TaskNames if Worker[t]==w]\n showsequence(msol2, workers[w], transitionTimes, types)\n visu.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Chapter 4. Adding calendars to the house building problem\n\nThis chapter introduces calendars into the house building problem, a problem of scheduling the tasks involved in building multiple houses in such a manner that minimizes the overall completion date of the houses.\n\nThere are two workers, each of whom must perform a given subset of the necessary tasks. \nEach worker has a calendar detailing on which days he does not work, such as weekends and holidays. \nOn a worker\u2019s day off, he does no work on his tasks, and his tasks may not be scheduled to start or end on these days. \nTasks that are in process by the worker are suspended during his days off.\n\nFollowing concepts are demonstrated:\n* use of the *step functions*,\n* use an alternative version of the constraint *no_overlap*,\n* use *intensity* expression,\n* use the constraints *forbid_start* and *forbid_end*,\n* use the *length* and *size* of an interval variable.", "apps": [], "results": {"msg": [{"data": "This chapter introduces calendars into the house building problem, a problem of scheduling the tasks involved in building multiple houses in such a manner that minimizes the overall completion date of the houses.
\n\nThere are two workers, each of whom must perform a given subset of the necessary tasks.
\nEach worker has a calendar detailing on which days he does not work, such as weekends and holidays.
\nOn a worker\u2019s day off, he does no work on his tasks, and his tasks may not be scheduled to start or end on these days.
\nTasks that are in process by the worker are suspended during his days off.
\n\nFollowing concepts are demonstrated:
\nThe problem consists of assigning start dates to a set of tasks in such a way that the schedule satisfies temporal constraints and minimizes a criterion.
\nThe criterion for this problem is to minimize the overall completion date.
\nFor each task type in the house building project, the following table shows the size of the task in days along with the tasks that must be finished before the task can start.
\nIn addition, each type of task can be performed by a given one of the two workers, Jim and Joe.
\nA worker can only work on one task at a time.
\nOnce started, Problem to be solveda task may be suspended during a worker\u2019s days off, but may not be interrupted by another task.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHouse construction tasks are detailed in the folowing table:\n\n| Task | Duration | Worker | Preceding tasks |\n|-----------|----------|--------|-----------------------------------|\n| masonry | 35 | Joe | |\n| carpentry | 15 | Joe | masonry |\n| plumbing | 40 | Jim | masonry |\n| ceiling | 15 | Jim | masonry |\n| roofing | 5 | Joe | carpentry |\n| painting | 10 | Jim | ceiling |\n| windows | 5 | Jim | roofing |\n| facade | 10 | Joe | roofing, plumbing |\n| garden | 5 | Joe | roofing, plumbing |\n| moving | 5 | Jim | windows, facade, garden, painting |", "apps": [], "results": {"msg": [{"data": "House construction tasks are detailed in the folowing table:
\n\n| Task | Duration | Worker | Preceding tasks |
\n|-----------|----------|--------|-----------------------------------|
\n| masonry | 35 | Joe | |
\n| carpentry | 15 | Joe | masonry |
\n| plumbing | 40 | Jim | masonry |
\n| ceiling | 15 | Jim | masonry |
\n| roofing | 5 | Joe | carpentry |
\n| painting | 10 | Jim | ceiling |
\n| windows | 5 | Jim | roofing |
\n| facade | 10 | Joe | roofing, plumbing |
\n| garden | 5 | Joe | roofing, plumbing |
\n| moving | 5 | Jim | windows, facade, garden, painting |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSolving the problem consists of determining starting dates for the tasks such that\nthe overall completion date is minimized.", "apps": [], "results": {"msg": [{"data": "Solving the problem consists of determining starting dates for the tasks such that
\nthe overall completion date is minimized.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 1: Describe the problem\n\nThe first step in modeling the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.\n\n* What is the known information in this problem ?\n\n There are five houses to be built by two workers. For each house, there are ten house building tasks, each with a given size. For each task, there is a list of tasks that must be completed before the task can start. Each task must be performed by a given worker, and each worker has a calendar listing his days off.\n\n\n* What are the decision variables or unknowns in this problem ?\n\n The unknowns are the start and end times of tasks which also determine the overall completion time. The actual length of a task depends on its position in time and on the calendar of the associated worker.\n \n \n* What are the constraints on these variables ?\n\n There are constraints that specify that a particular task may not begin until one or more given tasks have been completed. In addition, there are constraints that specify that a worker can be assigned to only one task at a time. A task cannot start or end during the associated worker\u2019s days off.\n\n\n* What is the objective ?\n\n The objective is to minimize the overall completion date.", "apps": [], "results": {"msg": [{"data": "The first step in modeling the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.
\n\nThere are five houses to be built by two workers. For each house, there are ten house building tasks, each with a given size. For each task, there is a list of tasks that must be completed before the task can start. Each task must be performed by a given worker, and each worker has a calendar listing his days off.
\n\n\nThe unknowns are the start and end times of tasks which also determine the overall completion time. The actual length of a task depends on its position in time and on the calendar of the associated worker.
\n\n\nThere are constraints that specify that a particular task may not begin until one or more given tasks have been completed. In addition, there are constraints that specify that a worker can be assigned to only one task at a time. A task cannot start or end during the associated worker\u2019s days off.
\n\n\nThe objective is to minimize the overall completion date.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 2: Prepare data\nA scheduling model starts with the declaration of the engine as follows:", "apps": [], "results": {"msg": [{"data": "A scheduling model starts with the declaration of the engine as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nfrom docplex.cp.model import *\n\nmdl3 = CpoModel()\n\nNbHouses = 5;\n\nWorkerNames = [\"Joe\", \"Jim\" ]\n\nTaskNames = [\"masonry\",\"carpentry\",\"plumbing\",\"ceiling\",\"roofing\",\"painting\",\"windows\",\"facade\",\"garden\",\"moving\"]\n\nDuration = [35,15,40,15,5,10,5,10,5,5]\n\nWorker = {\"masonry\":\"Joe\",\"carpentry\":\"Joe\",\"plumbing\":\"Jim\",\"ceiling\":\"Jim\",\n \"roofing\":\"Joe\",\"painting\":\"Jim\",\"windows\":\"Jim\",\"facade\":\"Joe\",\n \"garden\":\"Joe\",\"moving\":\"Jim\"}\n\n\nPrecedences = { (\"masonry\",\"carpentry\"),(\"masonry\",\"plumbing\"),\n (\"masonry\",\"ceiling\"),(\"carpentry\",\"roofing\"),\n (\"ceiling\",\"painting\"),(\"roofing\",\"windows\"),\n (\"roofing\",\"facade\"),(\"plumbing\",\"facade\"),\n (\"roofing\",\"garden\"),(\"plumbing\",\"garden\"),\n (\"windows\",\"moving\"),(\"facade\",\"moving\"), \n (\"garden\",\"moving\"),(\"painting\",\"moving\") }", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 3: Add the intensity step functions", "apps": [], "results": {"msg": [{"data": "To model the availability of a worker with respect to his days off, a step function is created to represents his intensity over time.
\nThis function has a range of [0..100], where the value 0 represents that the worker is not available and the value 100 represents that the worker is available with regard to his calendar.
\n\nStep functions are created by the method step_function().
\nEach interval [x1, x2) on which the function has the same value is called a step.
\nWhen two consecutive steps of the function have the same value, these steps are merged so that the function is always represented with the minimal number of steps.
\n\nFor each worker, a sorted tupleset is created. At each point in time where the worker\u2019s availability changes, a tuple is created.
\nThe tuple has two elements; the first element is an integer value that represents the worker\u2019s availability (0 for on a break, 100 for fully available to work, 50 for a half-day), and the other element represents the date at which the availability changes to this value.
\nThis tupleset, sorted by date, is then used to create a step function to represent the worker\u2019s intensity over time.
\nThe value of the function after the final step is set to 100.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nBreaks ={\n \"Joe\" : [\n (5,14),(19,21),(26,28),(33,35),(40,42),(47,49),(54,56),(61,63),\n (68,70),(75,77),(82,84),(89,91),(96,98),(103,105),(110,112),(117,119),\n (124,133),(138,140),(145,147),(152,154),(159,161),(166,168),(173,175),\n (180,182),(187,189),(194,196),(201,203),(208,210),(215,238),(243,245),(250,252),\n (257,259),(264,266),(271,273),(278,280),(285,287),(292,294),(299,301),\n (306,308),(313,315),(320,322),(327,329),(334,336),(341,343),(348,350),\n (355,357),(362,364),(369,378),(383,385),(390,392),(397,399),(404,406),(411,413),\n (418,420),(425,427),(432,434),(439,441),(446,448),(453,455),(460,462),(467,469),\n (474,476),(481,483),(488,490),(495,504),(509,511),(516,518),(523,525),(530,532),\n (537,539),(544,546),(551,553),(558,560),(565,567),(572,574),(579,602),(607,609),\n (614,616),(621,623),(628,630),(635,637),(642,644),(649,651),(656,658),(663,665),\n (670,672),(677,679),(684,686),(691,693),(698,700),(705,707),(712,714),\n (719,721),(726,728)\n ],\n \"Jim\" : [\n (5,7),(12,14),(19,21),(26,42),(47,49),(54,56),(61,63),(68,70),(75,77),\n (82,84),(89,91),(96,98),(103,105),(110,112),(117,119),(124,126),(131,133),\n (138,140),(145,147),(152,154),(159,161),(166,168),(173,175),(180,182),(187,189),\n (194,196),(201,225),(229,231),(236,238),(243,245),(250,252),(257,259),\n (264,266),(271,273),(278,280),(285,287),(292,294),(299,301),(306,315),\n (320,322),(327,329),(334,336),(341,343),(348,350),(355,357),(362,364),(369,371),\n (376,378),(383,385),(390,392),(397,413),(418,420),(425,427),(432,434),(439,441),\n (446,448),(453,455),(460,462),(467,469),(474,476),(481,483),(488,490),(495,497),\n (502,504),(509,511),(516,518),(523,525),(530,532),(537,539),(544,546),\n (551,553),(558,560),(565,581),(586,588),(593,595),(600,602),(607,609),\n (614,616),(621,623),(628,630),(635,637),(642,644),(649,651),(656,658),\n (663,665),(670,672),(677,679),(684,686),(691,693),(698,700),(705,707),\n (712,714),(719,721),(726,728)]\n }", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom collections import namedtuple\nBreak = namedtuple('Break', ['start', 'end'])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCalendar = {}\nmymax = max(max(v for k,v in Breaks[w]) for w in WorkerNames)\nfor w in WorkerNames:\n step = CpoStepFunction()\n step.set_value(0, mymax, 100)\n for b in Breaks[w]:\n t = Break(*b)\n step.set_value(t.start, t.end, 0)\n Calendar[w] = step", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThis intensity function is used in creating the task variables for the workers. \nThe intensity step function of the appropriate worker is passed to the creation of each interval variable. \nThe size of the interval variable is the time spent at the house to process the task, not including the worker\u2019s day off. \nThe length is the difference between the start and the end of the interval.", "apps": [], "results": {"msg": [{"data": "This intensity function is used in creating the task variables for the workers.
\nThe intensity step function of the appropriate worker is passed to the creation of each interval variable.
\nThe size of the interval variable is the time spent at the house to process the task, not including the worker\u2019s day off.
\nThe length is the difference between the start and the end of the interval.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 4: Create the interval variables", "apps": [], "results": {"msg": [{"data": "The tasks of the house building project have precedence constraints that are added to the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 5: Add the precedence constraints", "apps": [], "results": {"msg": [{"data": "To add the constraints that a worker can perform only one task at a time, the interval variables associated with that worker are constrained to not overlap in the solution.
\nTo do this, the specialized constraint no_overlap() is used, but with a slightly different form than was used in the section Chapter 3, \u201cAdding workers and transition times to the house building problem,\u201d.
\n\nThis form is a shortcut that avoids the need to explicitly define the interval sequence variable when no additional constraints are required on the sequence variable. A single no_overlap() constraint is added on the array of interval variables for each worker.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor w in WorkerNames:\n mdl3.add( mdl3.no_overlap( [itvs[h,t] for h in Houses for t in TaskNames if Worker[t]==w] ) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 7: Create the forbidden start and end constraints", "apps": [], "results": {"msg": [{"data": "When an intensity function is set on an interval variable, the tasks which overlap weekends and/or holidays will be automatically prolonged.
\nA task could still be scheduled to start or end in a weekend, but, in this problem, a worker\u2019s tasks cannot start or end during the worker\u2019s days off.
\nCP Optimizer provides the constraints forbid_start and forbid_end to model these types of constraints.
\n\nWith the constraint forbid_start, a constraint is created to specifies that an interval variable must not be scheduled to start at certain times.
\nThe constraint takes as parameters an interval variable and a step function.
\nIf the interval variable is present in the solution, then it is constrained to not start at a time when the value of the step function is zero.
\n\nCP Optimizer also provides forbid_end and forbid_extent, which respectively constrain an interval variable to not end and not overlap where the associated step function is valued zero.
\nThe first argument of the constraint forbid_start is the interval variable on which the constraint is placed.
\nThe second argument is the step function that defines a set of forbidden values for the start of the interval variable: the interval variable cannot start at a point where the step function is 0.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n for t in TaskNames:\n mdl3.add(mdl3.forbid_start(itvs[h,t], Calendar[Worker[t]]))\n mdl3.add(mdl3.forbid_end (itvs[h,t], Calendar[Worker[t]]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 8: Create the objective", "apps": [], "results": {"msg": [{"data": "The objective of this problem is to minimize the overall completion date (the completion date of the house that is completed last).
\nThe maximum completion date among the individual house projects is determined using the expression end_of() on the last task in building each house (here, it is the moving task) and minimize the maximum of these expressions.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl3.add( mdl3.minimize(mdl3.max(mdl3.end_of(itvs[h,\"moving\"]) for h in Houses)))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 9: Solve the model", "apps": [], "results": {"msg": [{"data": "The search for an optimal solution in this problem could potentiality take a long time, so a fail limit has been placed on the solve process.
\nThe search will stop when the fail limit is reached, even if optimality of the current best solution is not guaranteed.
\nThe code for limiting the solve process is provided below:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Solve the model\nprint(\"\\nSolving model....\")\nmsol3 = mdl3.solve(url=url, key=key, FailLimit=30000)\nprint(\"done\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol3:\n print(\"Cost will be \" + str( msol3.get_objective_values()[0] )) # Allocate tasks to workers\n tasks = {w : [] for w in WorkerNames}\n for k,v in Worker.items():\n tasks[v].append(k)\n\n types = {t : i for i,t in enumerate(TaskNames)}\n\n import docplex.cp.utils_visu as visu\n import matplotlib.pyplot as plt\n #Change the plot size\n from pylab import rcParams\n rcParams['figure.figsize'] = 15, 3\n\n visu.timeline('Solution SchedCalendar')\n for w in WorkerNames:\n visu.panel()\n visu.pause(Calendar[w])\n visu.sequence(name=w,\n intervals=[(msol3.get_var_solution(itvs[h,t]), types[t], t) for t in tasks[w] for h in Houses])\n visu.show()\nelse:\n print(\"No solution found\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Chapter 5. Using cumulative functions in the house building problem\n\nSome tasks must necessarily take place before other tasks, and each task has a predefined duration. \nMoreover, there are three workers, and each task requires any one of the three workers. \nA worker can be assigned to at most one task at a time. \nIn addition, there is a cash budget with a starting balance. \nEach task consumes a certain amount of the budget at the start of the task, and the cash balance is increased every 60 days. \n\nThis chapter introduces:\n* use the modeling function *cumul_function*,\n* use the functions *pulse*, *step*, *step_at_start* and *step_at_end*.\n\n", "apps": [], "results": {"msg": [{"data": "Some tasks must necessarily take place before other tasks, and each task has a predefined duration.
\nMoreover, there are three workers, and each task requires any one of the three workers.
\nA worker can be assigned to at most one task at a time.
\nIn addition, there is a cash budget with a starting balance.
\nEach task consumes a certain amount of the budget at the start of the task, and the cash balance is increased every 60 days.
\n\nThis chapter introduces:
\nThe problem consists of assigning start dates to a set of tasks in such a way that the schedule satisfies temporal constraints and minimizes a criterion. The criterion
\nfor this problem is to minimize the overall completion date. Each task requires 200 dollars per day of the task, payable at the start of the task. Every 60 days, starting
\nat day 0, the amount of 30,000 dollars is added to the cash balance.
\n\nFor each task type in the house building project, the following table shows the duration of the task in days along with the tasks that must be finished before the task can start. Each task requires any one of the three workers. A worker can only work on one task at a time; each task, once started, may not be interrupted.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHouse construction tasks:\n\n| Task | Duration | Preceding tasks |\n|-----------|----------|----------------------|\n| masonry | 35 | | \n| carpentry | 15 | masonry | \n| plumbing | 40 | masonry | \n| ceiling | 15 | masonry | \n| roofingv | 5 | carpentry | \n| painting | 10 | ceiling | \n| windows | 5 | roofing | \n| facade | 10 | roofing, plumbing | \n| garden | 5 | roofing, plumbing | \n| moving | 5 | windows, facade, garden,painting | ", "apps": [], "results": {"msg": [{"data": "House construction tasks:
\n\n| Task | Duration | Preceding tasks |
\n|-----------|----------|----------------------|
\n| masonry | 35 | |
\n| carpentry | 15 | masonry |
\n| plumbing | 40 | masonry |
\n| ceiling | 15 | masonry |
\n| roofingv | 5 | carpentry |
\n| painting | 10 | ceiling |
\n| windows | 5 | roofing |
\n| facade | 10 | roofing, plumbing |
\n| garden | 5 | roofing, plumbing |
\n| moving | 5 | windows, facade, garden,painting |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThere is an earliest starting date for each of the five houses that must be built.\n\n| House | Earliest starting date |\n|---|----|\n| 0 | 31 |\n| 1 | 0 |\n| 2 | 90 |\n| 3 | 120|\n| 4 | 90 |\nSolving the problem consists of determining starting dates for the tasks such that\nthe overall completion date is minimized.", "apps": [], "results": {"msg": [{"data": "There is an earliest starting date for each of the five houses that must be built.
\n\n| House | Earliest starting date |
\n|---|----|
\n| 0 | 31 |
\n| 1 | 0 |
\n| 2 | 90 |
\n| 3 | 120|
\n| 4 | 90 |
\nSolving the problem consists of determining starting dates for the tasks such that
\nthe overall completion date is minimized.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 1: Describe the problem\n\nThe first step in modeling and solving the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.\n\n* What is the known information in this problem ?\n\n There are five houses to be built by three workers. For each house, there are ten house building tasks, each with a given size and cost. For each task, there is a list of tasks that must be completed before the task can start. There is a starting cash balance of a given amount, and, each sixty days, the cash balance is increased by a given amount.\n\n\n* What are the decision variables or unknowns in this problem ?\n\n The unknown is the point in time that each task will start. Once starting dates have been fixed, the overall completion date will also be fixed.\n\n\n* What are the constraints on these variables ?\n\n There are constraints that specify that a particular task may not begin until one or more given tasks have been completed. Each task requires any one of the three workers. In addition, there are constraints that specify that a worker can be assigned to only one task at a time. Before a task can start, the cash balance must be large enough to pay the cost of the task.\n\n\n* What is the objective ?\n\n The objective is to minimize the overall completion date.", "apps": [], "results": {"msg": [{"data": "The first step in modeling and solving the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.
\n\nThere are five houses to be built by three workers. For each house, there are ten house building tasks, each with a given size and cost. For each task, there is a list of tasks that must be completed before the task can start. There is a starting cash balance of a given amount, and, each sixty days, the cash balance is increased by a given amount.
\n\n\nThe unknown is the point in time that each task will start. Once starting dates have been fixed, the overall completion date will also be fixed.
\n\n\nThere are constraints that specify that a particular task may not begin until one or more given tasks have been completed. Each task requires any one of the three workers. In addition, there are constraints that specify that a worker can be assigned to only one task at a time. Before a task can start, the cash balance must be large enough to pay the cost of the task.
\n\n\nThe objective is to minimize the overall completion date.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 2: Prepare data\nIn the related data file, the data provided includes the number of houses (NbHouses), the number of workers (NbWorkers), the names of the tasks (TaskNames), the sizes of the tasks (Duration), the precedence relations (Precedences), and the earliest start dates of the houses (ReleaseDate).\n\nAs each house has an earliest starting date, the task interval variables are declared to have a start date no earlier than that release date of the associated house. The ending dates of the tasks are not constrained, so the upper value of the range for the variables is maxint.", "apps": [], "results": {"msg": [{"data": "In the related data file, the data provided includes the number of houses (NbHouses), the number of workers (NbWorkers), the names of the tasks (TaskNames), the sizes of the tasks (Duration), the precedence relations (Precedences), and the earliest start dates of the houses (ReleaseDate).
\n\nAs each house has an earliest starting date, the task interval variables are declared to have a start date no earlier than that release date of the associated house. The ending dates of the tasks are not constrained, so the upper value of the range for the variables is maxint.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nNbWorkers = 3\nNbHouses = 5\n\nTaskNames = {\"masonry\",\"carpentry\",\"plumbing\",\n \"ceiling\",\"roofing\",\"painting\",\n \"windows\",\"facade\",\"garden\",\"moving\"}\n\nDuration = [35, 15, 40, 15, 5, 10, 5, 10, 5, 5]\n\nReleaseDate = [31, 0, 90, 120, 90]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nPrecedences = [(\"masonry\", \"carpentry\"), (\"masonry\", \"plumbing\"), (\"masonry\", \"ceiling\"),\n (\"carpentry\", \"roofing\"), (\"ceiling\", \"painting\"), (\"roofing\", \"windows\"),\n (\"roofing\", \"facade\"), (\"plumbing\", \"facade\"), (\"roofing\", \"garden\"),\n (\"plumbing\", \"garden\"), (\"windows\", \"moving\"), (\"facade\", \"moving\"),\n (\"garden\", \"moving\"), (\"painting\", \"moving\")]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 3: Create the interval variables", "apps": [], "results": {"msg": [{"data": "As the workers are equivalent in this problem, it is better to represent them as one pool of workers instead of as individual workers with no overlap constraints as was done in the earlier examples.
\nThe expression representing usage of this pool of workers can be modified by the interval variables that require a worker.
\n\nTo model both the limited number of workers and the limited budget, we need to represent the sum of the individual contributions associated with the interval variables.
\nIn the case of the cash budget, some tasks consume some of the budget at the start.
\nIn the case of the workers, a task requires the worker only for the duration of the task.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 4: Declare the worker usage function", "apps": [], "results": {"msg": [{"data": "A cumulative function expression, can be used to model a resource usage function over time.
\nThis function can be computed as a sum of interval variable demands on a resource over time.
\nAn interval usually increases the cumulated resource usage function at its start time and decreases it when it releases the resource at its end time (pulse function).
\nFor resources that can be produced and consumed by activities (for instance the contents of an inventory or a tank), the resource level can also be described as a function of time.
\nA production activity will increase the resource level at the start or end time of the activity whereas a consuming activity will decrease it.
\nThe cumulated contribution of activities on the resource can be represented by a function of time, and constraints can be modeled on this function (for instance, a maximal or a safety level).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe value of the expression at any given moment in time is constrained to be non-negative. A cumulative function expression can be modified with the atomic demand functions:\n* *step()*, which increases or decreases the level of the function by a given amount at a given time,\n* *pulse()*, which increases or decreases the level of the function by a given amount for the length of a given interval variable or fixed interval,\n* *step_at_start()*, which increases or decreases the level of the function by a given amount at the start of a given interval variable,\n* *step_at_end()*, which increases or decreases the level of the function by a given amount at the end of a given interval variable.\n\nA cumulative function expression can be constrained to model limited resource capacity by constraining that the function be \u2264 the capacity.\n\nTwo cumulative functions are required, one to represent the usage of the workers and the other to represent the cash balance.\nEach task requires one worker from the start to the end of the task interval. \n\nA cumulative function expression, *workerUsage* is used to represent the fact that a worker is required for the task.\nThis function is constrained to not exceed the number of workers at any point in time. \nThe function *pulse()* adjusts the expression by a given amount on the interval. \nSumming these pulse atoms over all the interval variables results in an expression that represents worker usage over the entire time frame for building the houses.", "apps": [], "results": {"msg": [{"data": "The value of the expression at any given moment in time is constrained to be non-negative. A cumulative function expression can be modified with the atomic demand functions:
\nA cumulative function expression can be constrained to model limited resource capacity by constraining that the function be \u2264 the capacity.
\n\nTwo cumulative functions are required, one to represent the usage of the workers and the other to represent the cash balance.
\nEach task requires one worker from the start to the end of the task interval.
\n\nA cumulative function expression, workerUsage is used to represent the fact that a worker is required for the task.
\nThis function is constrained to not exceed the number of workers at any point in time.
\nThe function pulse() adjusts the expression by a given amount on the interval.
\nSumming these pulse atoms over all the interval variables results in an expression that represents worker usage over the entire time frame for building the houses.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nworkers_usage = step_at(0, 0)\nfor h in Houses:\n for t in TaskNames:\n workers_usage += mdl4.pulse(itvs[h,t],1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 5: Declare the cash budget function", "apps": [], "results": {"msg": [{"data": "A cumulative function cach is also used to model the cash budget.
\nTo set the initial cash balance of 30,000 dollars and increase the balance by 30,000 every sixty days, the function step_at() is used to increment or decrement the cumulative function expression by a fixed amount on a given date.
\n\nEach task requires a cash payment equal to 200 dollars a day for the length of the task, payable at the start of the task.
\nThe function step_at_start() is used to adjust the cash balance cumulative function expression the appropriate amount for every task.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ncash = step_at(0, 0)\nfor p in Houses:\n cash += mdl4.step_at(60*p, 30000)\n\nfor h in Houses:\n for i,t in enumerate(TaskNames):\n cash -= mdl4.step_at_start(itvs[h,t], 200*Duration[i])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 6: Add the temporal constraints", "apps": [], "results": {"msg": [{"data": "The tasks have precedence constraints that are added to the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n for p in Precedences:\n mdl4.add( mdl4.end_before_start(itvs[h,p[0]], itvs[h,p[1]]) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 7: Add the worker usage constraint", "apps": [], "results": {"msg": [{"data": "There is a limited number of workers, and the cumulative function expression representing worker usage must be constrained to not be greater than the number of workers..
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl4.add( workers_usage <= NbWorkers )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 8: Add the cash budget constraint", "apps": [], "results": {"msg": [{"data": "The budget must always be nonnegative, and the cumulative function expression representing the cash budget must be greater than 0.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl4.add( cash >= 0 )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 9: Add the objective", "apps": [], "results": {"msg": [{"data": "The objective of this problem is to minimize the overall completion date (the completion date of the house that is completed last).
\nThe maximum completion date among the individual house projects is determined using the expression end_of() on the last task in building each house (here, it is the moving task) and minimize the maximum of these expressions.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl4.add(\n mdl4.minimize( \n mdl4.max( mdl4.end_of(itvs[h,\"moving\"]) for h in Houses)\n )\n)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 10: Solve the model", "apps": [], "results": {"msg": [{"data": "The search for an optimal solution in this problem could potentiality take a long time, so a fail limit has been placed on the solve process.
\nThe search will stop when the fail limit is reached, even if optimality of the current best solution is not guaranteed.
\nThe code for limiting the solve process is:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Solve the model\nprint(\"\\nSolving model....\")\nmsol4 = mdl4.solve(url=url, key=key, FailLimit=30000)\nprint(\"done\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol4:\n print(\"Cost will be \" + str( msol4.get_objective_values()[0] ))\n\n import docplex.cp.utils_visu as visu\n import matplotlib.pyplot as plt\n #Change the plot size\n from pylab import rcParams\n rcParams['figure.figsize'] = 15, 3\n\n workersF = CpoStepFunction()\n cashF = CpoStepFunction()\n for p in range(5):\n cashF.add_value(60 * p, INT_MAX, 30000)\n for h in Houses:\n for i,t in enumerate(TaskNames):\n itv = msol4.get_var_solution(itvs[h,t])\n workersF.add_value(itv.get_start(), itv.get_end(), 1)\n cashF.add_value(itv.start, INT_MAX, -200 * Duration[i])\n\n visu.timeline('Solution SchedCumul')\n visu.panel(name=\"Schedule\")\n for h in Houses:\n for i,t in enumerate(TaskNames):\n visu.interval(msol4.get_var_solution(itvs[h,t]), h, t)\n visu.panel(name=\"Workers\")\n visu.function(segments=workersF, style='area')\n visu.panel(name=\"Cash\")\n visu.function(segments=cashF, style='area', color='gold')\n visu.show()\nelse:\n print(\"No solution found\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Chapter 6. Using alternative resources in the house building problem\n\nThis chapter presents how to use alternative resources in the house building problem. The following concepts are presented:\n* use the constraints *alternative* and *presence_of*,\n* use the function *optional*.\n\nEach house has a maximal completion date. \nMoreover, there are three workers, and one of the three is required for each task. \nThe three workers have varying levels of skills with regard to the various tasks; if a worker has no skill for a particular task, he may not be assigned to the task. \nFor some pairs of tasks, if a particular worker performs one of the pair on a house, then the same worker must be assigned to the other of the pair for that house. \nThe objective is to find a solution that maximizes the task associated skill levels of the workers assigned to the tasks. ", "apps": [], "results": {"msg": [{"data": "This chapter presents how to use alternative resources in the house building problem. The following concepts are presented:
\nEach house has a maximal completion date.
\nMoreover, there are three workers, and one of the three is required for each task.
\nThe three workers have varying levels of skills with regard to the various tasks; if a worker has no skill for a particular task, he may not be assigned to the task.
\nFor some pairs of tasks, if a particular worker performs one of the pair on a house, then the same worker must be assigned to the other of the pair for that house.
\nThe objective is to find a solution that maximizes the task associated skill levels of the workers assigned to the tasks.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Problem to be solved\n\nThe problem consists of assigning start dates to a set of tasks in such a way that the schedule satisfies temporal constraints and maximizes a criterion. The criterion for this problem is to maximize the task associated skill levels of the workers assigned to the tasks.\n\nFor each task type in the house building project, the following table shows the duration of the task in days along with the tasks that must be finished before the task can start. A worker can only work on one task at a time; each task, once started, may not be interrupted.", "apps": [], "results": {"msg": [{"data": "The problem consists of assigning start dates to a set of tasks in such a way that the schedule satisfies temporal constraints and maximizes a criterion. The criterion for this problem is to maximize the task associated skill levels of the workers assigned to the tasks.
\n\nFor each task type in the house building project, the following table shows the duration of the task in days along with the tasks that must be finished before the task can start. A worker can only work on one task at a time; each task, once started, may not be interrupted.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHouse construction tasks:\n\n| Task | Duration | Preceding tasks |\n|-----------|----------|-----------------|\n| masonry | 35 | |\n| carpentry | 15 | masonry |\n| plumbing | 40 | masonry |\n| ceiling | 15 | masonry |\n| roofing | 5 | carpentry |\n| painting | 10 | ceiling |\n| windows | 5 | roofing |\n| facade | 10 | roofing, plumbing |\n| garden | 5 | roofing, plumbing |\n| moving | 5 | windows, facade, garden,painting |", "apps": [], "results": {"msg": [{"data": "House construction tasks:
\n\n| Task | Duration | Preceding tasks |
\n|-----------|----------|-----------------|
\n| masonry | 35 | |
\n| carpentry | 15 | masonry |
\n| plumbing | 40 | masonry |
\n| ceiling | 15 | masonry |
\n| roofing | 5 | carpentry |
\n| painting | 10 | ceiling |
\n| windows | 5 | roofing |
\n| facade | 10 | roofing, plumbing |
\n| garden | 5 | roofing, plumbing |
\n| moving | 5 | windows, facade, garden,painting |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nEvery house must be completed within 300 days. There are three workers with varying skill levels in regard to the ten tasks. If a worker has a skill level of zero for a task, he may not be assigned to the task.", "apps": [], "results": {"msg": [{"data": "Every house must be completed within 300 days. There are three workers with varying skill levels in regard to the ten tasks. If a worker has a skill level of zero for a task, he may not be assigned to the task.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWorker-task skill levels:\n \n| Task | Joe | Jack | Jim |\n|-----------|-----|------|-----|\n| masonry | 9 | 5 | 0 | \n| carpentry | 7 | 0 | 5 | \n| plumbing | 0 | 7 | 0 | \n| ceiling | 5 | 8 | 0 | \n| roofing | 6 | 7 | 0 | \n| painting | 0 | 9 | 6 | \n| windows | 8 | 0 | 5 | \n| fa\u00e7ade | 5 | 5 | 0 | \n| garden | 5 | 5 | 9 | \n| moving | 6 | 0 | 8 | ", "apps": [], "results": {"msg": [{"data": "Worker-task skill levels:
\n\n| Task | Joe | Jack | Jim |
\n|-----------|-----|------|-----|
\n| masonry | 9 | 5 | 0 |
\n| carpentry | 7 | 0 | 5 |
\n| plumbing | 0 | 7 | 0 |
\n| ceiling | 5 | 8 | 0 |
\n| roofing | 6 | 7 | 0 |
\n| painting | 0 | 9 | 6 |
\n| windows | 8 | 0 | 5 |
\n| fa\u00e7ade | 5 | 5 | 0 |
\n| garden | 5 | 5 | 9 |
\n| moving | 6 | 0 | 8 |
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFor Jack, if he performs the roofing task or facade task on a house, then he must perform the other task on that house. For Jim, if he performs the garden task or moving task on a house, then he must perform the other task on that house. For\n\nJoe, if he performs the masonry task or carpentry task on a house, then he must perform the other task on that house. Also, if Joe performs the carpentry task or roofing task on a house, then he must perform the other task on that house.", "apps": [], "results": {"msg": [{"data": "For Jack, if he performs the roofing task or facade task on a house, then he must perform the other task on that house. For Jim, if he performs the garden task or moving task on a house, then he must perform the other task on that house. For
\n\nJoe, if he performs the masonry task or carpentry task on a house, then he must perform the other task on that house. Also, if Joe performs the carpentry task or roofing task on a house, then he must perform the other task on that house.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 1: Describe the problem\nThe first step in modeling and solving the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.\n\n* What is the known information in this problem ?\n\n There are five houses to be built by three workers. For each house, there are ten house building tasks, each with a given size. For each task, there is a list of tasks that must be completed before the task can start. Each worker has a skill level associated with each task. There is an overall deadline for the work to be completed on the five houses.\n\n\n* What are the decision variables or unknowns in this problem ?\n\n The unknown is the point in time that each task will start. Also, unknown is which worker will be assigned to each task.\n\n\n* What are the constraints on these variables ?\n\n There are constraints that specify that a particular task may not begin until one or more given tasks have been completed. In addition, there are constraints that specify that each task must have one worker assigned to it, that a worker can be assigned to only one task at a time and that a worker can be assigned only to tasks for which he has some level of skill. There are pairs of tasks that if one task for a house is done by a particular worker, then the other task for that house must be done by the same worker.\n\n\n* What is the objective ?\n\n The objective is to maximize the skill levels used.", "apps": [], "results": {"msg": [{"data": "The first step in modeling and solving the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.
\n\nThere are five houses to be built by three workers. For each house, there are ten house building tasks, each with a given size. For each task, there is a list of tasks that must be completed before the task can start. Each worker has a skill level associated with each task. There is an overall deadline for the work to be completed on the five houses.
\n\n\nThe unknown is the point in time that each task will start. Also, unknown is which worker will be assigned to each task.
\n\n\nThere are constraints that specify that a particular task may not begin until one or more given tasks have been completed. In addition, there are constraints that specify that each task must have one worker assigned to it, that a worker can be assigned to only one task at a time and that a worker can be assigned only to tasks for which he has some level of skill. There are pairs of tasks that if one task for a house is done by a particular worker, then the other task for that house must be done by the same worker.
\n\n\nThe objective is to maximize the skill levels used.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 2: Prepare data\nIn the related data file, the data provided includes the number of houses (NbHouses), the names of the workers (Workers), the names of the tasks (Tasks), the sizes of the tasks (Durations), the precedence relations (Precedences), and the overall deadline for the construction of the houses (Deadline).\n\nThe data also includes a tupleset, Skills. Each tuple in the set consists of a worker, a task, and the skill level that the worker has for the task. In addition, there is a tupleset, Continuities, which is a set of triples (a pair of tasks and a worker). If one of the two tasks in a pair is performed by the worker for a given house, then the other task in the pair must be performed by the same worker for that house.\n\nTwo matrices of interval variables are created in this model. \nThe first, tasks, is indexed on the houses and tasks and must be scheduled in the interval [0..Deadline]. \nThe other matrix of interval variables is indexed on the houses and the Skills tupleset. \nThese interval variables are optional and may or may not be present in the solution. \nThe intervals that are performed will represent which worker performs which task.", "apps": [], "results": {"msg": [{"data": "In the related data file, the data provided includes the number of houses (NbHouses), the names of the workers (Workers), the names of the tasks (Tasks), the sizes of the tasks (Durations), the precedence relations (Precedences), and the overall deadline for the construction of the houses (Deadline).
\n\nThe data also includes a tupleset, Skills. Each tuple in the set consists of a worker, a task, and the skill level that the worker has for the task. In addition, there is a tupleset, Continuities, which is a set of triples (a pair of tasks and a worker). If one of the two tasks in a pair is performed by the worker for a given house, then the other task in the pair must be performed by the same worker for that house.
\n\nTwo matrices of interval variables are created in this model.
\nThe first, tasks, is indexed on the houses and tasks and must be scheduled in the interval [0..Deadline].
\nThe other matrix of interval variables is indexed on the houses and the Skills tupleset.
\nThese interval variables are optional and may or may not be present in the solution.
\nThe intervals that are performed will represent which worker performs which task.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nNbHouses = 5\nDeadline = 318\n\nWorkers = [\"Joe\", \"Jack\", \"Jim\"]\n\nTasks = [\"masonry\", \"carpentry\", \"plumbing\", \"ceiling\",\"roofing\", \"painting\", \"windows\", \"facade\",\"garden\", \"moving\"]\n\nDurations = [35, 15, 40, 15, 5, 10, 5, 10, 5, 5]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nSkills = [(\"Joe\",\"masonry\",9),(\"Joe\",\"carpentry\",7),(\"Joe\",\"ceiling\",5),(\"Joe\",\"roofing\",6), \n (\"Joe\",\"windows\",8),(\"Joe\",\"facade\",5),(\"Joe\",\"garden\",5),(\"Joe\",\"moving\",6),\n (\"Jack\",\"masonry\",5),(\"Jack\",\"plumbing\",7),(\"Jack\",\"ceiling\",8),(\"Jack\",\"roofing\",7),\n (\"Jack\",\"painting\",9),(\"Jack\",\"facade\",5),(\"Jack\",\"garden\",5),(\"Jim\",\"carpentry\",5),\n (\"Jim\",\"painting\",6),(\"Jim\",\"windows\",5),(\"Jim\",\"garden\",9),(\"Jim\",\"moving\",8)]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nPrecedences = [(\"masonry\",\"carpentry\"),(\"masonry\",\"plumbing\"),(\"masonry\",\"ceiling\"),\n (\"carpentry\",\"roofing\"),(\"ceiling\",\"painting\"),(\"roofing\",\"windows\"),\n (\"roofing\",\"facade\"),(\"plumbing\",\"facade\"),(\"roofing\",\"garden\"),\n (\"plumbing\",\"garden\"),(\"windows\",\"moving\"),(\"facade\",\"moving\"),\n (\"garden\",\"moving\"),(\"painting\",\"moving\")\n ]\n \nContinuities = [(\"Joe\",\"masonry\",\"carpentry\"),(\"Jack\",\"roofing\",\"facade\"), \n (\"Joe\",\"carpentry\", \"roofing\"),(\"Jim\",\"garden\",\"moving\")]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnbWorkers = len(Workers)\nHouses = range(NbHouses)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 3: Create the interval variables", "apps": [], "results": {"msg": [{"data": "The tasks in the model have precedence constraints that are added to the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n for p in Precedences:\n mdl5.add( mdl5.end_before_start(tasks[h,p[0]], tasks[h,p[1]]) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 5: Add the alternative constraints", "apps": [], "results": {"msg": [{"data": "the specialized constraint alternative() is used to constrain the solution so that exactly one of the interval variables tasks associated with a given task of a given house is to be present in the solution,
\n\nThe constraint alternative() creates a constraint between an interval and a set of intervals that specifies that if the given interval is present in the solution, then exactly one interval variable of the set is present in the solution.
\n\nIn other words, consider an alternative constraint created with an interval variable a and an array of interval variables bs. If a is present in the solution, then exactly one of the interval variables in bs will be present, and a starts and ends together with this chosen interval.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n for t in Tasks:\n mdl5.add( mdl5.alternative(tasks[h,t], [wtasks[h,s] for s in Skills if s[1]==t]) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe expression *presence_of()* is used to represent whether a task is performed by a worker. \nThe constraint *presence_of()* is true if the interval variable is present in and is false if the interval variable is absent from the solution.\n\nFor each house and each given pair of tasks and worker that must have continuity, a constraint states that if the interval variable for one of the two tasks for the worker is present, the interval variable associated with that worker and the other task must also be present.", "apps": [], "results": {"msg": [{"data": "The expression presence_of() is used to represent whether a task is performed by a worker.
\nThe constraint presence_of() is true if the interval variable is present in and is false if the interval variable is absent from the solution.
\n\nFor each house and each given pair of tasks and worker that must have continuity, a constraint states that if the interval variable for one of the two tasks for the worker is present, the interval variable associated with that worker and the other task must also be present.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n for c in Continuities:\n for (worker1, task1, l1) in Skills:\n if worker1 == c[0] and task1 == c[1]:\n for (worker2, task2, l2) in Skills:\n if worker2 == c[0] and task2 == c[2]:\n mdl5.add(\n mdl5.presence_of(wtasks[h,(c[0], task1, l1)]) \n == \n mdl5.presence_of(wtasks[h,(c[0], task2, l2)])\n )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 7: Add the no overlap constraints", "apps": [], "results": {"msg": [{"data": "The constraint no_overlap() allows to specify that a given worker can be assigned only one task at a given moment in time.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor w in Workers:\n mdl5.add( mdl5.no_overlap([wtasks[h,s] for h in Houses for s in Skills if s[0]==w]) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 8: Add the objective", "apps": [], "results": {"msg": [{"data": "The presence of an interval variable in the solution must be accounted in the objective. Thus for each of these possible tasks, the cost is incremented by the product of the skill level and the expression representing the presence of the interval variable in the solution.
\nThe objective of this problem is to maximize the skill levels used for all the tasks, then to maximize the expression.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl5.add(\n mdl5.maximize(\n mdl5.sum( s[2] * mdl5.presence_of(wtasks[h,s]) for h in Houses for s in Skills)\n )\n)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 9: Solve the model", "apps": [], "results": {"msg": [{"data": "The search for an optimal solution in this problem could potentiality take a long time, so a fail limit has been placed on the solve process. The search will stop when the fail limit is reached, even if optimality of the current best solution is not guaranteed.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Solve the model\nprint(\"\\nSolving model....\")\nmsol5 = mdl5.solve(url=url, key=key, FailLimit=30000)\nprint(\"done\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol5:\n print(\"Cost will be \"+str( msol5.get_objective_values()[0] ))\n\n worker_idx = {w : i for i,w in enumerate(Workers)}\n worker_tasks = [[] for w in range(nbWorkers)] # Tasks assigned to a given worker\n for h in Houses:\n for s in Skills:\n worker = s[0]\n wt = wtasks[(h,s)]\n worker_tasks[worker_idx[worker]].append(wt)\n\n import docplex.cp.utils_visu as visu\n import matplotlib.pyplot as plt\n #Change the plot size\n from pylab import rcParams\n rcParams['figure.figsize'] = 15, 3\n\n visu.timeline('Solution SchedOptional', 0, Deadline)\n for i,w in enumerate(Workers):\n visu.sequence(name=w)\n for t in worker_tasks[worker_idx[w]]:\n wt = msol5.get_var_solution(t)\n if wt.is_present():\n #if desc[t].skills[w] == max(desc[t].skills):\n # Green-like color when task is using the most skilled worker\n # color = 'lightgreen'\n #else:\n # Red-like color when task does not use the most skilled worker\n # color = 'salmon'\n color = 'salmon'\n visu.interval(wt, color, wt.get_name())\n visu.show()\nelse:\n print(\"No solution found\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Chapter 7. Using state functions: house building with state incompatibilities\n\nThis chapter describes how to use state functions to take into account incompatible states as tasks finish. Following concepts are presented:\n* use the *stateFunction*,\n* use the constraint *alwaysEqual*.\n\nThere are two workers, and each task requires either one of the two workers. \nA subset of the tasks require that the house be clean, whereas other tasks make the house dirty. \nA transition time is needed to change the state of the house from dirty to clean. ", "apps": [], "results": {"msg": [{"data": "This chapter describes how to use state functions to take into account incompatible states as tasks finish. Following concepts are presented:
\nThere are two workers, and each task requires either one of the two workers.
\nA subset of the tasks require that the house be clean, whereas other tasks make the house dirty.
\nA transition time is needed to change the state of the house from dirty to clean.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Problem to be solved\n\nThe problem consists of assigning start dates to a set of tasks in such a way that the schedule satisfies temporal constraints and minimizes an expression. The objective for this problem is to minimize the overall completion date.\n\nFor each task type in the house building project, the following table shows the duration of the task in days along with state of the house during the task. A worker can only work on one task at a time; each task, once started, may not be interrupted.", "apps": [], "results": {"msg": [{"data": "The problem consists of assigning start dates to a set of tasks in such a way that the schedule satisfies temporal constraints and minimizes an expression. The objective for this problem is to minimize the overall completion date.
\n\nFor each task type in the house building project, the following table shows the duration of the task in days along with state of the house during the task. A worker can only work on one task at a time; each task, once started, may not be interrupted.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nHouse construction tasks:\n \n| Task | Duration | State | Preceding tasks |\n|-----------|----------|-------|-----------------|\n| masonry | 35 | dirty | | \n| carpentry | 15 | dirty | masonry | \n| plumbing | 40 | clean | masonry | \n| ceiling | 15 | clean | masonry | \n| roofing | 5 | dirty | carpentry | \n| painting | 10 | clean | ceiling |\n| windows | 5 | dirty | roofing | \n| facade | 10 | | roofing, plumbing| \n| garden | 5 | | roofing, plumbing| \n| moving | 5 | | windows, facade,garden, painting| \n\nSolving the problem consists of determining starting dates for the tasks such that\nthe overall completion date is minimized.", "apps": [], "results": {"msg": [{"data": "House construction tasks:
\n\n| Task | Duration | State | Preceding tasks |
\n|-----------|----------|-------|-----------------|
\n| masonry | 35 | dirty | |
\n| carpentry | 15 | dirty | masonry |
\n| plumbing | 40 | clean | masonry |
\n| ceiling | 15 | clean | masonry |
\n| roofing | 5 | dirty | carpentry |
\n| painting | 10 | clean | ceiling |
\n| windows | 5 | dirty | roofing |
\n| facade | 10 | | roofing, plumbing|
\n| garden | 5 | | roofing, plumbing|
\n| moving | 5 | | windows, facade,garden, painting|
\n\nSolving the problem consists of determining starting dates for the tasks such that
\nthe overall completion date is minimized.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 1: Describe the problem\n\nThe first step in modeling and solving the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.\n\n* What is the known information in this problem ?\n\n There are five houses to be built by two workers. For each house, there are ten house building tasks, each with a given size. For each task, there is a list of tasks that must be completed before the task can start. There are two workers. There is a transition time associated with changing the state of a house from dirty to clean.\n\n\n* What are the decision variables or unknowns in this problem ?\n\n The unknowns are the date that each task will start. The cost is determined by the assigned start dates.\n\n\n* What are the constraints on these variables ?\n\n There are constraints that specify that a particular task may not begin until one or more given tasks have been completed. Each task requires either one of the two workers. Some tasks have a specified house cleanliness state.\n\n\n* What is the objective ?\n\n The objective is to minimize the overall completion date.", "apps": [], "results": {"msg": [{"data": "The first step in modeling and solving the problem is to write a natural language description of the problem, identifying the decision variables and the constraints on these variables.
\n\nThere are five houses to be built by two workers. For each house, there are ten house building tasks, each with a given size. For each task, there is a list of tasks that must be completed before the task can start. There are two workers. There is a transition time associated with changing the state of a house from dirty to clean.
\n\n\nThe unknowns are the date that each task will start. The cost is determined by the assigned start dates.
\n\n\nThere are constraints that specify that a particular task may not begin until one or more given tasks have been completed. Each task requires either one of the two workers. Some tasks have a specified house cleanliness state.
\n\n\nThe objective is to minimize the overall completion date.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 2: Prepare data\nIn the related data, the data provided includes the number of houses (NbHouses), the number of workers (NbWorkers), the names of the tasks (TaskNames), the sizes of the tasks (Duration), the precedence relations (Precedences), and the cleanliness state of each task (AllStates).\n\nEach house has a list of tasks that must be scheduled. The duration, or size, of each task *t* is *Duration[t]*. Using this information, a matrix task of interval variables can be built.", "apps": [], "results": {"msg": [{"data": "In the related data, the data provided includes the number of houses (NbHouses), the number of workers (NbWorkers), the names of the tasks (TaskNames), the sizes of the tasks (Duration), the precedence relations (Precedences), and the cleanliness state of each task (AllStates).
\n\nEach house has a list of tasks that must be scheduled. The duration, or size, of each task t is Duration[t]. Using this information, a matrix task of interval variables can be built.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nNbHouses = 5\nNbWorkers = 2\nAllStates = [\"clean\", \"dirty\"]\n\nTaskNames = [\"masonry\",\"carpentry\", \"plumbing\", \"ceiling\",\"roofing\",\"painting\",\"windows\",\"facade\",\"garden\",\"moving\"]\n\nDuration = [35,15,40,15,5,10,5,10,5,5]\n\nStates = [(\"masonry\",\"dirty\"),(\"carpentry\",\"dirty\"),(\"plumbing\",\"clean\"),\n (\"ceiling\",\"clean\"),(\"roofing\",\"dirty\"),(\"painting\",\"clean\"),\n (\"windows\",\"dirty\")]\n\nPrecedences = [(\"masonry\",\"carpentry\"),(\"masonry\",\"plumbing\"),(\"masonry\",\"ceiling\"),\n (\"carpentry\",\"roofing\"),(\"ceiling\",\"painting\"),(\"roofing\",\"windows\"),\n (\"roofing\",\"facade\"),(\"plumbing\",\"facade\"),(\"roofing\",\"garden\"),\n (\"plumbing\",\"garden\"),(\"windows\",\"moving\"),(\"facade\",\"moving\"),\n (\"garden\",\"moving\"),(\"painting\",\"moving\")]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nHouses = range(NbHouses)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 3: Create the interval variables", "apps": [], "results": {"msg": [{"data": "As in the example Chapter 5, \u201cUsing cumulative functions in the house building problem\u201d, each task requires one worker from the start to the end of the task interval. To represent the fact that a worker is required for the task, a cumulative function expression workers is created.
\nThis function is constrained to not exceed the number of workers at any point in time.
\nhe function pulse adjusts the expression by a given amount on the interval.
\nSumming these pulse atoms over all the interval variables results in an expression that represents worker usage over the entire time frame for building the houses.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nworkers = step_at(0, 0)\nfor h in Houses:\n for t in TaskNames:\n workers += mdl6.pulse(task[h,t], 1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 5: Create the transition times", "apps": [], "results": {"msg": [{"data": "The transition time from a dirty state to a clean state is the same for all houses.
\nAs in the example Chapter 3, \u201cAdding workers and transition times to the house building problem\u201d, a tupleset ttime is created to represent the transition time between cleanliness states.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nIndex = {s : i for i,s in enumerate(AllStates)}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nttvalues = [[0, 0], [0, 0]]\nttvalues[Index[\"dirty\"]][Index[\"clean\"]] = 1\nttime = transition_matrix(ttvalues, name='TTime')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 6: Declare the state function", "apps": [], "results": {"msg": [{"data": "Certain tasks require the house to be clean, and other tasks cause the house to be dirty.
\nTo model the possible states of the house, the state function function is used to represent the disjoint states through time.
\n\nA state function is a function describing the evolution of a given feature of the environment.
\nThe possible evolution of this feature is constrained by interval variables of the problem.
\nFor example, a scheduling problem may contain a resource whose state changes over time.
\nThe resource state can change because of scheduled activities or because of exogenous events; some activities in the schedule may need a particular resource state in order to execute.
\nInterval variables have an absolute effect on a state function, requiring the function value to be equal to a particular state or in a set of possible states.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nstate = { h : state_function(ttime, name=\"house\"+str(h)) for h in Houses}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 7: Add the constraints", "apps": [], "results": {"msg": [{"data": "To model the state required or imposed by a task, a constraint is created to specifies the state of the house throughout the interval variable representing that task.
\n\nThe constraint always_equal(), specifies the value of a state function over the interval variable.
\nThe constraint takes as parameters a state function, an interval variable, and a state value.
\nWhenever the interval variable is present, the state function is defined everywhere between the start and the end of the interval variable and remains equal to the specified state value over this interval.
\nThe state function is constrained to take the appropriate values during the tasks that require the house to be in a specific state.
\nTo add the constraint that there can be only two workers working at a given time, the cumulative function expression representing worker usage is constrained to not be greater than the value NbWorkers.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor h in Houses:\n for p in Precedences:\n mdl6.add( mdl6.end_before_start(task[h,p[0]], task[h,p[1]]) )\n\n for s in States:\n mdl6.add( mdl6.always_equal(state[h], task[h,s[0]], Index[s[1]]) )\n\nmdl6.add( workers <= NbWorkers )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 8: Add the objective", "apps": [], "results": {"msg": [{"data": "The objective of this problem is to minimize the overall completion date (the completion date of the house that is completed last).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl6.add(mdl6.minimize( mdl6.max( mdl6.end_of(task[h,\"moving\"]) for h in Houses )))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Step 9: Solve the model", "apps": [], "results": {"msg": [{"data": "The search for an optimal solution in this problem could potentiality take a long time, so a fail limit has been placed on the solve process. The search will stop when the fail limit is reached, even if optimality of the current best solution is not guaranteed.
\nThe code for limiting the solve process is given below:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Solve the model\nprint(\"\\nSolving model....\")\nmsol6 = mdl6.solve(url=url, key=key, FailLimit=30000)\nprint(\"done\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol6:\n print(\"Cost will be \" + str( msol6.get_objective_values()[0] ))\n\n import docplex.cp.utils_visu as visu\n import matplotlib.pyplot as plt\n #Change the plot size\n from pylab import rcParams\n rcParams['figure.figsize'] = 15, 3\n\n workers_function = CpoStepFunction()\n for h in Houses:\n for t in TaskNames:\n itv = msol6.get_var_solution(task[h,t])\n workers_function.add_value(itv.get_start(), itv.get_end(), 1)\n\n visu.timeline('Solution SchedState')\n visu.panel(name=\"Schedule\")\n for h in Houses:\n for t in TaskNames:\n visu.interval(msol6.get_var_solution(task[h,t]), h, t)\n\n\n visu.panel(name=\"Houses state\")\n for h in Houses:\n f = state[h]\n visu.sequence(name=f.get_name(), segments=msol6.get_var_solution(f))\n visu.panel(name=\"Nb of workers\")\n visu.function(segments=workers_function, style='line')\n visu.show()\nelse:\n print(\"No solution found\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Summary\n\nHaving completed this notebook, the reader should be able to:\n- Describe the characteristics of a Scheduling problem in terms of the objective, decision variables and constraints\n- Formulate a simple Scheduling model on paper\n- Conceptually explain the buidling blocks of a scheduling model\n- Write a simple model with docplex\n", "apps": [], "results": {"msg": [{"data": "Having completed this notebook, the reader should be able to:
\nThis tutorial includes everything you need to set up decision optimization engines, build mathematical programming models, and arrive at a good working schedule for a sports league's games.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n* Step 4: Prepare the data\n
\n- Step 5: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization solve service\n
\n* Step 6: Investigate the solution and run an example analysis\n
\n* To model this preference, there is an incentive for intradivisional games that increases each week as a square of the week.\n
\n* An opponent must be assigned to each team each week to maximize the total of the incentives..\n
\n\n\n\nThis is a type of discrete optimization problem that can be solved by using either Integer Programming (IP) or Constraint Programming (CP).
\n\n\n\n\nInteger Programming is the class of problems defined as the optimization of a linear function, subject to linear constraints over integer variables.
\n
\n\n\nConstraint Programming problems generally have discrete decision variables, but the constraints can be logical, and the arithmetic expressions are not restricted to being linear.
\n
For the purposes of this tutorial, we will illustrate a solution with constraint programming (CP).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\n* Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It takes into account specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \nWith prescriptive analytics, you can:
\n\nRun the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.", "apps": [], "results": {"msg": [{"data": "In this scenario, the data is simple. There are eight teams in each division, and the teams must play each team in the division once and each team outside the division once.
\n\nUse a Python module, Collections, which implements some data structures that will help solve some problems. Named tuples helps to define meaning of each position in a tuple. This helps the code be more readable and self-documenting. You can use named tuples in any place where you use tuples.
\n\nIn this example, you create a namedtuple to contain information for points. You are also defining some of the parameters.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Teams in 1st division\nTEAM_DIV1 = [\"Baltimore Ravens\",\"Cincinnati Bengals\", \"Cleveland Browns\",\"Pittsburgh Steelers\",\"Houston Texans\",\n \"Indianapolis Colts\",\"Jacksonville Jaguars\",\"Tennessee Titans\",\"Buffalo Bills\",\"Miami Dolphins\",\n \"New England Patriots\",\"New York Jets\",\"Denver Broncos\",\"Kansas City Chiefs\",\"Oakland Raiders\",\n \"San Diego Chargers\"]\n\n# Teams in 2nd division\nTEAM_DIV2 = [\"Chicago Bears\",\"Detroit Lions\",\"Green Bay Packers\",\"Minnesota Vikings\",\"Atlanta Falcons\",\n \"Carolina Panthers\",\"New Orleans Saints\",\"Tampa Bay Buccaneers\",\"Dallas Cowboys\",\"New York Giants\",\n \"Philadelphia Eagles\",\"Washington Redskins\",\"Arizona Cardinals\",\"San Francisco 49ers\",\n \"Seattle Seahawks\",\"St. Louis Rams\"]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom collections import namedtuple\nNUMBER_OF_MATCHES_TO_PLAY = 2 # Number of match to play between two teams on the league\n\nT_SCHEDULE_PARAMS = (namedtuple(\"TScheduleParams\",\n [\"nbTeamsInDivision\",\n \"maxTeamsInDivision\",\n \"numberOfMatchesToPlayInsideDivision\",\n \"numberOfMatchesToPlayOutsideDivision\"\n ]))\n# Schedule parameters: depending on their values, you may overreach the Community Edition of CPLEX\nSCHEDULE_PARAMS = T_SCHEDULE_PARAMS(5, # nbTeamsInDivision\n 10, # maxTeamsInDivision\n NUMBER_OF_MATCHES_TO_PLAY, # numberOfMatchesToPlayInsideDivision\n NUMBER_OF_MATCHES_TO_PLAY # numberOfMatchesToPlayOutsideDivision\n )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nUse basic HTML and a stylesheet to format the data.", "apps": [], "results": {"msg": [{"data": "Use basic HTML and a stylesheet to format the data.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCSS = \"\"\"\nbody {\n margin: 0;\n font-family: Helvetica;\n}\ntable.dataframe {\n border-collapse: collapse;\n border: none;\n}\ntable.dataframe tr {\n border: none;\n}\ntable.dataframe td, table.dataframe th {\n margin: 0;\n border: 1px solid white;\n padding-left: 0.25em;\n padding-right: 0.25em;\n}\ntable.dataframe th:not(:empty) {\n background-color: #fec;\n text-align: left;\n font-weight: normal;\n}\ntable.dataframe tr:nth-child(2) th:empty {\n border-left: none;\n border-right: 1px dashed #888;\n}\ntable.dataframe td {\n border: 2px solid #ccf;\n background-color: #f4f4ff;\n}\n table.dataframe thead th:first-child {\n display: none;\n }\n table.dataframe tbody th {\n display: none;\n }\n\"\"\"\n\nfrom IPython.core.display import HTML\nHTML(''.format(CSS))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow you will import the *pandas* library. Pandas is an open source Python library for data analysis. It uses two data structures, *Series* and *DataFrame*, which are built on top of *NumPy*.\n\nA **Series** is a one-dimensional object similar to an array, list, or column in a table. It will assign a labeled index to each item in the series. By default, each item receives an index label from 0 to N, where N is the length of the series minus one.\n\nA **DataFrame** is a tabular data structure comprised of rows and columns, similar to a spreadsheet, database table, or R's data.frame object. Think of a DataFrame as a group of Series objects that share an index (the column names).\n\nIn the example, each division (the AFC and the NFC) is part of a DataFrame.", "apps": [], "results": {"msg": [{"data": "Now you will import the pandas library. Pandas is an open source Python library for data analysis. It uses two data structures, Series and DataFrame, which are built on top of NumPy.
\n\nA Series is a one-dimensional object similar to an array, list, or column in a table. It will assign a labeled index to each item in the series. By default, each item receives an index label from 0 to N, where N is the length of the series minus one.
\n\nA DataFrame is a tabular data structure comprised of rows and columns, similar to a spreadsheet, database table, or R's data.frame object. Think of a DataFrame as a group of Series objects that share an index (the column names).
\n\nIn the example, each division (the AFC and the NFC) is part of a DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pandas as pd\n\nteam1 = pd.DataFrame(TEAM_DIV1)\nteam2 = pd.DataFrame(TEAM_DIV2)\nteam1.columns = [\"AFC\"]\nteam2.columns = [\"NFC\"]\n\nteams = pd.concat([team1,team2], axis=1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe following *display* function is a tool to show different representations of objects. When you issue the *display(teams)* command, you are sending the output to the notebook so that the result is stored in the document.", "apps": [], "results": {"msg": [{"data": "The following display function is a tool to show different representations of objects. When you issue the display(teams) command, you are sending the output to the notebook so that the result is stored in the document.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom IPython.display import display\n\ndisplay(teams)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Prepare the data\n\nGiven the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week. \n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.", "apps": [], "results": {"msg": [{"data": "Given the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week.
\n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport numpy as np\nNB_TEAMS = 2 * SCHEDULE_PARAMS.nbTeamsInDivision\nTEAMS = range(NB_TEAMS)\n\n# Calculate the number of weeks necessary\nNB_WEEKS = (SCHEDULE_PARAMS.nbTeamsInDivision - 1) * SCHEDULE_PARAMS.numberOfMatchesToPlayInsideDivision \\\n + SCHEDULE_PARAMS.nbTeamsInDivision * SCHEDULE_PARAMS.numberOfMatchesToPlayOutsideDivision\n\n\n# Weeks to schedule\nWEEKS = tuple(range(NB_WEEKS))\n\n# Season is split into two halves\nFIRST_HALF_WEEKS = tuple(range(NB_WEEKS // 2))\nNB_FIRST_HALS_WEEKS = NB_WEEKS // 3\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Set up the prescriptive model\n\n#### Define the decision variables\nYou can model a solution to the problem by assigning an opponent to each team for each week. \n\nTherefore, the main decision variables in this model are indexed on the **teams** and **weeks** and take a value in *1..nbTeams*. \n\nThe value at the solution of the decision variable ( __plays[t][w]__ ) indicates that *team t* plays in *week w*.", "apps": [], "results": {"msg": [{"data": "You can model a solution to the problem by assigning an opponent to each team for each week.
\n\nTherefore, the main decision variables in this model are indexed on the teams and weeks and take a value in 1..nbTeams.
\n\nThe value at the solution of the decision variable ( plays[t][w] ) indicates that team t plays in week w.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl = CpoModel(name=\"SportsScheduling\")\n\n# Variables of the model\nplays = {}\nfor i in range(NUMBER_OF_MATCHES_TO_PLAY):\n for t1 in TEAMS:\n for t2 in TEAMS:\n if t1 != t2:\n plays[(t1, t2, i)] = integer_var(1, NB_WEEKS, name=\"team1_{}_team2_{}_match_{}\".format(t1, t2, i))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the business constraints\n\n* For each week and each team, there is a constraint that the team cannot play itself. Also, the variables must be constrained to be symmetric. \n\n> If *team t* plays *team t2* in *week w*, then *team t2* must play *team t* in *week w*. \n\nIn constraint programming, you can use a decision variable to index an array by using an element expression.", "apps": [], "results": {"msg": [{"data": "\n\n\nIf team t plays team t2 in week w, then team t2 must play team t in week w.
\n
In constraint programming, you can use a decision variable to index an array by using an element expression.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Constraints of the model\nfor t1 in TEAMS:\n for t2 in TEAMS:\n if t2 != t1:\n for i in range(NUMBER_OF_MATCHES_TO_PLAY):\n mdl.add(plays[(t1, t2, i)] == plays[(t2, t1, i)]) ### symmetrical match t1->t2 = t2->t1 at the ieme match", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n* Each week, every team must be assigned to at most one game. To model this, you use the specialized *alldifferent* constraint. \n\n> for a given *week w*, the values of __play[t][w]__ must be unique for all *teams t*.", "apps": [], "results": {"msg": [{"data": "\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor t1 in TEAMS:\n mdl.add(all_diff([plays[(t1, t2, i)] for t2 in TEAMS if t2 != t1 for i in\n range(NUMBER_OF_MATCHES_TO_PLAY)])) ### team t1 must play one match per week", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n* One set of constraints is used to ensure that the solution satisfies the number of intradivisional and interdivisional games that each team must play. \n * A pair of teams cannot play each other on consecutive weeks.\n * Each team must play at least a certain number of intradivisional games, *nbFirstHalfGames*, in the first half of the season. ", "apps": [], "results": {"msg": [{"data": "for a given week w, the values of play[t][w] must be unique for all teams t.
\n
* A pair of teams cannot play each other on consecutive weeks.\n
\n* Each team must play at least a certain number of intradivisional games, *nbFirstHalfGames*, in the first half of the season.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Function that returns 1 if the two teams are in same division, 0 if not\ndef intra_divisional_pair(t1, t2):\n return int((t1 <= SCHEDULE_PARAMS.nbTeamsInDivision and t2 <= SCHEDULE_PARAMS.nbTeamsInDivision) or\n (t1 > SCHEDULE_PARAMS.nbTeamsInDivision and t2 > SCHEDULE_PARAMS.nbTeamsInDivision))\n\n# Some intradivisional games should be in the first half\nmdl.add(sum([intra_divisional_pair(t1, t2) * allowed_assignments(plays[(t1, t2, i)], FIRST_HALF_WEEKS) \n for t1 in TEAMS for t2 in [a for a in TEAMS if a != t1] \n for i in range(NUMBER_OF_MATCHES_TO_PLAY)]) >= NB_FIRST_HALS_WEEKS)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective\nThe objective function for this example is designed to force intradivisional games to occur as late in the season as possible. The incentive for intradivisional games increases by week. There is no incentive for interdivisional games. \n\nUse an indicator matrix, *intraDivisionalPair*, to specify whether a pair of teams is in the same division or not. For each pair which is intradivisional, the incentive, or gain, is a power function of the week.\n\nThese cost functions are used to create an expression that models the overall cost. The cost here is halved as the incentive for each game gets counted twice.", "apps": [], "results": {"msg": [{"data": "The objective function for this example is designed to force intradivisional games to occur as late in the season as possible. The incentive for intradivisional games increases by week. There is no incentive for interdivisional games.
\n\nUse an indicator matrix, intraDivisionalPair, to specify whether a pair of teams is in the same division or not. For each pair which is intradivisional, the incentive, or gain, is a power function of the week.
\n\nThese cost functions are used to create an expression that models the overall cost. The cost here is halved as the incentive for each game gets counted twice.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Objective of the model is to schedule intradivisional games to be played late in the schedule\nsm = []\nfor t1 in TEAMS:\n for t2 in TEAMS:\n if t1 != t2:\n if not intra_divisional_pair(t1, t2):\n for i in range(NUMBER_OF_MATCHES_TO_PLAY):\n sm.append(plays[(t1, t2, i)])\nmdl.add(maximize(sum(sm)))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization solve service \n\nIf url and key are None, the Modeling layer will look for a local runtime, otherwise will use the credentials.\nLook at the documentation for a good understanding of the various solving/generation modes.\n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.\n\nYou will get the best solution found after ***n*** seconds, thanks to a time limit parameter.", "apps": [], "results": {"msg": [{"data": "If url and key are None, the Modeling layer will look for a local runtime, otherwise will use the credentials.
\nLook at the documentation for a good understanding of the various solving/generation modes.
\n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n\nYou will get the best solution found after n seconds, thanks to a time limit parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nn = 25\nmdl.print_information()\nmsol = mdl.solve(url=SVC_URL, key=SVC_KEY, TimeLimit=n)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 6: Investigate the solution and then run an example analysis", "apps": [], "results": {"msg": [{"data": "\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nif msol:\n months = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"]\n report = []\n for t in nfl_finals:\n for m in matches:\n if t[1] in m[1] and t[2] in m[2]:\n report.append((m[0], months[m[0]//4], m[1], m[2], m[3]))\n if t[2] in m[1] and t[1] in m[2]: \n report.append((m[0], months[m[0]//4], m[1], m[2], m[3]))\n\n matches_bd = pd.DataFrame(report)\n matches_bd.columns = [\"week\", \"Month\", \"Team1\", \"Team2\", \"location\"]\n try: #pandas >= 0.17\n display(matches_bd[matches_bd['location'] != \"Home\"].sort_values(by='week').drop(labels=['week', 'location'], axis=1))\n except:\n display(matches_bd[matches_bd['location'] != \"Home\"].sort('week').drop(labels=['week', 'location'], axis=1))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the Cloud.", "apps": [], "results": {"msg": [{"data": "Determine when the last 10 final replay games will occur:
\n
You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com\"\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/cp/zeppelin/sudoku.json b/examples/cp/zeppelin/sudoku.json deleted file mode 100644 index 32d1fcd..0000000 --- a/examples/cp/zeppelin/sudoku.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/sudoku", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Sudoku\n\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires a valid subscription to **Decision Optimization on the Cloud** or a **local installation of CPLEX Optimizers**. \nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the Data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization solve service\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build constraint programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization solve service\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nand each of the nine 3x3 sub-grids that compose the grid contains all of the digits from 1 to 9.
\n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.cp.model import *\nfrom sys import stdout", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.\n\n__Set your DOcplexcloud credentials:__\n0. A first option is to set the DOcplexcloud url and key directly in the model source file *(see below)*\n1. For a persistent setting, create a Python file __docloud_config.py__ somewhere that is visible from the __PYTHONPATH__", "apps": [], "results": {"msg": [{"data": "Set your DOcplexcloud credentials:
\nzero means cell to be filled with appropriate value
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nSUDOKU_PROBLEM_1 = ( (0, 0, 0, 0, 9, 0, 1, 0, 0),\n (2, 8, 0, 0, 0, 5, 0, 0, 0),\n (7, 0, 0, 0, 0, 6, 4, 0, 0),\n (8, 0, 5, 0, 0, 3, 0, 0, 6),\n (0, 0, 1, 0, 0, 4, 0, 0, 0),\n (0, 7, 0, 2, 0, 0, 0, 0, 0),\n (3, 0, 0, 0, 0, 1, 0, 8, 0),\n (0, 0, 0, 0, 0, 0, 0, 5, 0),\n (0, 9, 0, 0, 0, 0, 0, 7, 0),\n )\n\nSUDOKU_PROBLEM_2 = ( (0, 7, 0, 0, 0, 0, 0, 4, 9),\n (0, 0, 0, 4, 0, 0, 0, 0, 0),\n (4, 0, 3, 5, 0, 7, 0, 0, 8),\n (0, 0, 7, 2, 5, 0, 4, 0, 0),\n (0, 0, 0, 0, 0, 0, 8, 0, 0),\n (0, 0, 4, 0, 3, 0, 5, 9, 2),\n (6, 1, 8, 0, 0, 0, 0, 0, 5),\n (0, 9, 0, 1, 0, 0, 0, 3, 0),\n (0, 0, 5, 0, 0, 0, 0, 0, 7),\n )\n\nSUDOKU_PROBLEM_3 = ( (0, 0, 0, 0, 0, 6, 0, 0, 0),\n (0, 5, 9, 0, 0, 0, 0, 0, 8),\n (2, 0, 0, 0, 0, 8, 0, 0, 0),\n (0, 4, 5, 0, 0, 0, 0, 0, 0),\n (0, 0, 3, 0, 0, 0, 0, 0, 0),\n (0, 0, 6, 0, 0, 3, 0, 5, 4),\n (0, 0, 0, 3, 2, 5, 0, 0, 6),\n (0, 0, 0, 0, 0, 0, 0, 0, 0),\n (0, 0, 0, 0, 0, 0, 0, 0, 0)\n )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import numpy as np\n import matplotlib.pyplot as plt\n VISU_ENABLED = True\nexcept ImportError:\n VISU_ENABLED = False", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef print_grid(grid):\n \"\"\" Print Sudoku grid \"\"\"\n for l in GRNG:\n if (l > 0) and (l % 3 == 0):\n stdout.write('\\n')\n for c in GRNG:\n v = grid[l][c]\n stdout.write(' ' if (c % 3 == 0) else ' ')\n stdout.write(str(v) if v > 0 else '.')\n stdout.write('\\n')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef draw_grid(values):\n fig, ax = plt.subplots(figsize =(4,4))\n min_val, max_val = 0, 9\n R = range(0,9)\n for l in R:\n for c in R:\n v = values[c][l]\n s = \" \"\n if v > 0:\n s = str(v)\n ax.text(l+0.5,8.5-c, s, va='center', ha='center')\n ax.set_xlim(min_val, max_val)\n ax.set_ylim(min_val, max_val)\n ax.set_xticks(np.arange(max_val))\n ax.set_yticks(np.arange(max_val))\n ax.grid()\n plt.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef display_grid(grid, name):\n stdout.write(name)\n stdout.write(\":\\n\")\n if VISU_ENABLED:\n draw_grid(grid)\n else:\n print_grid(grid)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndisplay_grid(SUDOKU_PROBLEM_1, \"PROBLEM 1\")\ndisplay_grid(SUDOKU_PROBLEM_2, \"PROBLEM 2\")\ndisplay_grid(SUDOKU_PROBLEM_3, \"PROBLEM 3\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Choose your preferred problem (SUDOKU_PROBLEM_1 or SUDOKU_PROBLEM_2 or SUDOKU_PROBLEM_3)\nIf you change the problem, ensure to re-run all cells below this one.", "apps": [], "results": {"msg": [{"data": "If you change the problem, ensure to re-run all cells below this one.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nproblem = SUDOKU_PROBLEM_3", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "Add alldiff constraints for lines
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor l in GRNG:\n mdl.add(all_diff([grid[l][c] for c in GRNG]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAdd alldiff constraints for columns", "apps": [], "results": {"msg": [{"data": "Add alldiff constraints for columns
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor c in GRNG:\n mdl.add(all_diff([grid[l][c] for l in GRNG]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAdd alldiff constraints for sub-squares", "apps": [], "results": {"msg": [{"data": "Add alldiff constraints for sub-squares
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nssrng = range(0, 9, 3)\nfor sl in ssrng:\n for sc in ssrng:\n mdl.add(all_diff([grid[l][c] for l in range(sl, sl + 3) for c in range(sc, sc + 3)]))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nInitialize known cells", "apps": [], "results": {"msg": [{"data": "Initialize known cells
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor l in GRNG:\n for c in GRNG:\n v = problem[l][c]\n if v > 0:\n grid[l][c].set_domain((v, v))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization solve service", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/cp/zeppelin/truck_fleet.json b/examples/cp/zeppelin/truck_fleet.json deleted file mode 100644 index c30774d..0000000 --- a/examples/cp/zeppelin/truck_fleet.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "cp/jupyter/truck_fleet", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# The Truck Fleet puzzle\n\nThis tutorial includes everything you need to set up decision optimization engines, build constraint programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires a valid subscription to **Decision Optimization on the Cloud** or a **local installation of CPLEX Optimizers**. \nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the Data\n * Step 4: Prepare the data\n - Step 4: Set up the prescriptive model\n * Prepare data for modeling\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization solve service\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build constraint programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\nIt requires a valid subscription to Decision Optimization on the Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the Data\n
\n* Step 4: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Prepare data for modeling\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization solve service\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nPlease refer to documentation for appropriate setup of solving configuration.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n*****\n## How decision optimization can help\n* Prescriptive analytics technology recommends actions based on desired outcomes, taking into account specific scenarios, resources, and knowledge of past and current events. This insight can help your organization make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom sys import stdout\nimport pip\ntry:\n import docplex.cp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to the [Decision Optimization on Cloud solve service](https://developer.ibm.com/docloud).\n* Get the service URL and your personal API key.\n\n__Set your DOcplexcloud credentials:__\n0. A first option is to set the DOcplexcloud url and key directly in the model source file *(see below)*\n1. For a persistent setting, create a Python file __docloud_config.py__ somewhere that is visible from the __PYTHONPATH__", "apps": [], "results": {"msg": [{"data": "Set your DOcplexcloud credentials:
\nNext section defines the data of the problem.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# List of possible truck configurations. Each tuple is (load, cost) with:\n# load: max truck load for this configuration,\n# cost: cost for loading the truck in this configuration\nTRUCK_CONFIGURATIONS = ((11, 2), (11, 2), (11, 2), (11, 3), (10, 3), (10, 3), (10, 4))\n\n# List of customer orders.\n# Each tuple is (customer index, volume, product type)\nCUSTOMER_ORDERS = ((0, 3, 1), (0, 4, 2), (0, 3, 0), (0, 2, 1), (0, 5, 1), (0, 4, 1), (0, 11, 0),\n (1, 4, 0), (1, 5, 0), (1, 2, 0), (1, 4, 2), (1, 7, 2), (1, 3, 2), (1, 5, 0), (1, 2, 2),\n (2, 5, 1), (2, 6, 0), (2, 11, 2), (2, 1, 0), (2, 6, 0), (2, 3, 0))\n\n# Transition costs between configurations.\n# Tuple (A, B, TCost) means that the cost of modifying the truck from configuration A to configuration B is TCost\nCONFIGURATION_TRANSITION_COST = tuple_set(((0, 0, 0), (0, 1, 0), (0, 2, 0), (0, 3, 10), (0, 4, 10),\n (0, 5, 10), (0, 6, 15), (1, 0, 0), (1, 1, 0), (1, 2, 0),\n (1, 3, 10), (1, 4, 10), (1, 5, 10), (1, 6, 15), (2, 0, 0),\n (2, 1, 0), (2, 2, 0), (2, 3, 10), (2, 4, 10), (2, 5, 10),\n (2, 6, 15), (3, 0, 3), (3, 1, 3), (3, 2, 3), (3, 3, 0),\n (3, 4, 10), (3, 5, 10), (3, 6, 15), (4, 0, 3), (4, 1, 3),\n (4, 2, 3), (4, 3, 10), (4, 4, 0), (4, 5, 10), (4, 6, 15),\n (5, 0, 3), (5, 1, 3), (5, 2, 3), (5, 3, 10), (5, 4, 10),\n (5, 5, 0), (5, 6, 15), (6, 0, 3), (6, 1, 3), (6, 2, 3),\n (6, 3, 10), (6, 4, 10), (6, 5, 10), (6, 6, 0)\n ))\n\n# Compatibility between the product types and the configuration of the truck\n# allowedContainerConfigs[i] = the array of all the configurations that accept products of type i\nALLOWED_CONTAINER_CONFIGS = ((0, 3, 4, 6),\n (1, 3, 5, 6),\n (2, 4, 5, 6))\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "Next section extracts from problem data the parts that are frequently used in the modeling section.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnbTruckConfigs = len(TRUCK_CONFIGURATIONS)\nmaxTruckConfigLoad = [tc[0] for tc in TRUCK_CONFIGURATIONS]\ntruckCost = [tc[1] for tc in TRUCK_CONFIGURATIONS]\nmaxLoad = max(maxTruckConfigLoad)\n\nnbOrders = len(CUSTOMER_ORDERS)\nnbCustomers = 1 + max(co[0] for co in CUSTOMER_ORDERS)\nvolumes = [co[1] for co in CUSTOMER_ORDERS]\nproductType = [co[2] for co in CUSTOMER_ORDERS]\n\n# Max number of truck deliveries (estimated upper bound, to be increased if no solution)\nmaxDeliveries = 15", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Create CPO model", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/callbacks/branch_callback.py b/examples/mp/callbacks/branch_callback.py new file mode 100644 index 0000000..aea51ef --- /dev/null +++ b/examples/mp/callbacks/branch_callback.py @@ -0,0 +1,207 @@ +# -------------------------------------------------------------------------- +# Source file provided under Apache License, Version 2.0, January 2004, +# http://www.apache.org/licenses/ +# (c) Copyright IBM Corp. 2015, 2018 +# -------------------------------------------------------------------------- + + +# This file shows how to connect CPLEX branch callbacks to a DOcplex model. +import math +import cplex +import cplex.callbacks as cpx_cb + +from docplex.mp.callbacks.cb_mixin import * +from docplex.mp.model import Model +from collections import defaultdict, namedtuple + + +class MyBranch(ModelCallbackMixin, cpx_cb.BranchCallback): + + brtype_map = {'0': 'var', '1': 'sos1', '2': 'sos2', 'X': 'user'} + def __init__(self, env): + # non public... + cpx_cb.BranchCallback.__init__(self, env) + ModelCallbackMixin.__init__(self) + self.nb_called = 0 + self.stats = defaultdict(int) + + def __call__(self): + self.nb_called += 1 + br_type = self.get_branch_type() + if (br_type == self.branch_type.SOS1 or + br_type == self.branch_type.SOS2): + return + + x = self.get_values() + + objval = self.get_objective_value() + obj = self.get_objective_coefficients() + feas = self.get_feasibilities() + + maxobj = -cplex.infinity + maxinf = -cplex.infinity + bestj = -1 + infeas = self.feasibility_status.infeasible + + for j in range(len(x)): + if feas[j] == infeas: + xj_inf = x[j] - math.floor(x[j]) + if xj_inf > 0.5: + xj_inf = 1.0 - xj_inf + + if (xj_inf >= maxinf and + (xj_inf > maxinf or abs(obj[j]) >= maxobj)): + bestj = j + maxinf = xj_inf + maxobj = abs(obj[j]) + + if bestj < 0: + return + + xj_lo = math.floor(x[bestj]) + # the (bestj, xj_lo, direction) triple can be any python object to + # associate with a node + dv = self.index_to_var(bestj) + self.stats[dv] += 1 + # note that we convert the variable index to its docplex name + print('---> BRANCH[{0}]--- custom branch callback, branch type is {1}, var={2!s}' + .format(self.nb_called, self.brtype_map.get(br_type, '??'), dv)) + self.make_branch(objval, variables=[(bestj, "L", xj_lo + 1)], + node_data=(bestj, xj_lo, "UP")) + self.make_branch(objval, variables=[(bestj, "U", xj_lo)], + node_data=(bestj, xj_lo, "DOWN")) + + def report(self, n=5): + sorted_stats = sorted(self.stats.items(), key=lambda p: p[1], reverse=True) + for k, (dv, occ) in enumerate(sorted_stats[:n], start=1): + print('#{0} most branched: {1}, branched: {2}'.format(k, dv, occ)) + + +def add_branch_callback(docplex_model, logged=False): + # register a class callback once!!! + bcb = docplex_model.register_callback(MyBranch) + + docplex_model.parameters.mip.interval = 1 + docplex_model.parameters.preprocessing.linear = 0 + + solution = docplex_model.solve(log_output=logged) + assert solution is not None + docplex_model.report() + + bcb.report(n=3) + + +Tdv = namedtuple('Tdv', ['dx', 'dy']) + +neighbors = [Tdv(i, j) for i in (-1, 0, 1) for j in (-1, 0, 1) if i or j] + +assert len(neighbors) == 8 + +def build_lifegame_model(n, **kwargs): + """ build a MIP model for a stable game of life configuration + + chessboard is (n+1) x (n+1) + + :param n: + :return: + """ + assert n >= 2 + + assert Model.supports_logical_constraints(), "This model requires logical constraints cplex.version must be 12.80 or higher" + lm = Model(name='game_of_life_{0}'.format(n), **kwargs) + border = range(0, n + 2) + inside = range(1, n + 1) + + # one binary var per cell + life = lm.binary_var_matrix(border, border, name=lambda rc: 'life_%d_%d' % rc) + + # store sum of alive neighbors for interior cells + sum_of_neighbors = {(i, j): lm.sum(life[i + n.dx, j + n.dy] for n in neighbors) for i in inside for j in inside} + + # all borderline cells are dead + for j in border: + life[0, j].ub = 0 + life[j, 0].ub = 0 + life[j, n + 1].ub = 0 + life[n + 1, j].ub = 0 + + # ct1: the sum of alive neighbors for an alive cell is greater than 2 + for i in inside: + for j in inside: + lm.add(2 * life[i, j] <= sum_of_neighbors[i, j]) + + # ct2: the sum of alive neighbors for an alive cell is less than 3 + for i in inside: + for j in inside: + lm.add(5 * life[i, j] + sum_of_neighbors[i, j] <= 8) + + # ct3: for a dead cell, the sum of alive neighbors cannot be 3 + for i in inside: + for j in inside: + ct3 = sum_of_neighbors[i, j] == 3 + lm.add(ct3 <= life[i, j]) # use logical cts here + + # satisfy the 'no 3 alive neighbors for extreme rows, columns + for i in border: + if i < n: + for d in [1, n]: + lm.add(life[i, d] + life[i + 1, d] + life[i + 2, d] <= 2) + lm.add(life[d, i] + life[d, i + 1] + life[d, i + 2] <= 2) + + # symmetry breaking + n2 = int(math.ceil(n/2)) + half1 = range(1, n2 + 1) + half2 = range(n2 + 1, n) + + # there are more alive cells in left side + lm.add(lm.sum(life[i1, j1] for i1 in half1 for j1 in inside) >= lm.sum( + life[i2, j2] for i2 in half2 for j2 in inside)) + + # there are more alive cells in upper side + lm.add(lm.sum(life[i1, j1] for i1 in inside for j1 in half1) >= lm.sum( + life[i2, j2] for i2 in inside for j2 in half2)) + + # find maximum number of alive cells + lm.maximize(lm.sum(life)) + + # add a dummy kpi + nlines = lm.sum( (lm.sum(life[i, j] for j in inside) >= 1) for i in inside) + lm.add_kpi(nlines, 'nlines') + + # parameters: branch up, use heusristics, emphasis on opt, threads free + lm.parameters.mip.strategy.branch = 1 + lm.parameters.mip.strategy.heuristicfreq = 10 + lm.parameters.emphasis.mip = 2 + lm.parameters.threads = 0 + + # store data items as fields + lm.size = n + lm.life = life + + ini_s = lifegame_make_initial_solution(lm) + if not ini_s.is_valid_solution(): + print('error in initial solution') + else: + lm.add_mip_start(ini_s) + + + return lm + + +def lifegame_make_initial_solution(mdl): + border3 = range(1, mdl.size-1, 3) + life_vars = mdl.life + vvmap = {} + for i in border3: + for j in border3: + vvmap[life_vars[i, j]] = 1 + vvmap[life_vars[i+1, j]] = 1 + vvmap[life_vars[i, j+1]] = 1 + vvmap[life_vars[i+1, j+1]] = 1 + return mdl.new_solution(var_value_dict=vvmap) + +if __name__ == "__main__": + life_m = build_lifegame_model(n=6) + add_branch_callback(life_m, logged=False) + + diff --git a/examples/mp/callbacks/cut_callback.py b/examples/mp/callbacks/cut_callback.py new file mode 100644 index 0000000..648f8c4 --- /dev/null +++ b/examples/mp/callbacks/cut_callback.py @@ -0,0 +1,190 @@ +# -------------------------------------------------------------------------- +# Source file provided under Apache License, Version 2.0, January 2004, +# http://www.apache.org/licenses/ +# (c) Copyright IBM Corp. 2015, 2018 +# -------------------------------------------------------------------------- + +# Given a set of locations J and a set of clients C +# Minimize +# sum(j in J) fixedCost[j]*used[j] + +# sum(j in J)sum(c in C)cost[c][j]*supply[c][j] +# Subject to +# sum(j in J) supply[c][j] == 1 for all c in C +# sum(c in C) supply[c][j] <= (|C| - 1) * used[j] for all j in J +# supply[c][j] in { 0, 1 } for all c in C, j in J +# used[j] in { 0, 1 } for all j in J + + +import sys + +from cplex.callbacks import UserCutCallback + +from docplex.mp.callbacks.cb_mixin import * +from docplex.mp.model import Model + +# Separate the disaggregated capacity constraints. +# In the model we have for each location j the constraint +# sum(c in clients) supply[c][j] <= (nbClients-1) * used[j] +# Clearly, a client can only be serviced from a location that is used, +# so we also have a constraint +# supply[c][j] <= used[j] +# that must be satisfied by every feasible solution. These constraints tend +# to be violated in LP relaxation. In this callback we separate them in cuts +# constraints added via a callback. + + +class CustomCutCallback(ConstraintCallbackMixin, UserCutCallback): + # Callback constructor. Model object is set after registration. + def __init__(self, env): + UserCutCallback.__init__(self, env) + ConstraintCallbackMixin.__init__(self) + self.eps = 1e-6 + self.nb_cuts = 0 + + def add_cut_constraint(self, ct): + self.register_constraint(ct) + + @print_called("--> custom cut callback called: #{0}") + def __call__(self): + # fetch variable solution values at this point. + sol = self.make_complete_solution() + # fetch those constraints which are not satisfied. + unsats = self.get_cpx_unsatisfied_cts(self.cts, sol, self.eps) + for ct, cut, sense, rhs in unsats: + # Method add() here is CPLEX's CutCallback.add() + self.add(cut, sense, rhs) + self.nb_cuts += 1 + print('-- add new cut[{0}]: [{1!s}]'.format(self.nb_cuts, ct)) + + +def build_supply_model(fixed_costs, supply_costs, use_cuts=False, **kwargs): + m = Model(name='suppy', **kwargs) + + nb_locations = len(fixed_costs) + nb_clients = len(supply_costs) + range_locations = range(nb_locations) + range_clients = range(nb_clients) + + # --- Create variables. --- + # - used[l] If location l is used. + # - supply[l][c] Amount shipped from location j to client c. This is a real + # number in [0,1] and specifies the percentage of c's + # demand that is served from location l. + used = m.binary_var_list(range_locations, name='used') + supply = m.continuous_var_matrix(range_clients, range_locations, lb=0, ub=1, name='supply') + m.used = used + m.supply = supply + # --- add constraints --- + # The supply for each client must sum to 1, i.e., the demand of each + # client must be met. + m.add_constraints(m.sum(supply[c, l] for l in range_locations) == 1 for c in range_clients) + # Capacity constraint for each location. We just require that a single + # location cannot serve all clients, that is, the capacity of each + # location is nbClients-1. This makes the model a little harder to + # solve and allows us to separate more cuts. + m.add_constraints( + m.sum(supply[c, l] for c in range_clients) <= (nb_clients - 1) * used[l] for l in range_locations) + + # Tweak some CPLEX parameters so that CPLEX has a harder time to + # solve the model and our cut separators can actually kick in. + # params = m.parameters + # params.threads = 1 + # # params.mip.strategy.heuristicfreq = -1 + # params.mip.cuts.mircut = -1 + # params.mip.cuts.implied = -1 + # params.mip.cuts.gomory = -1 + # params.mip.cuts.flowcovers = -1 + # params.mip.cuts.pathcut = -1 + # params.mip.cuts.liftproj = -1 + # params.mip.cuts.zerohalfcut = -1 + # params.mip.cuts.cliques = -1 + # params.mip.cuts.covers = -1 + + # --- set objective --- + # objective is to minimize total cost, i.e. sum of location fixed cost and supply costs + total_fixed_cost = m.dot(used, fixed_costs) + m.add_kpi(total_fixed_cost, 'Total fixed cost') + total_supply_cost = m.sum(supply[c, l] * supply_costs[c][l] for c in range_clients for l in range_locations) + m.add_kpi(total_supply_cost, 'Total supply cost') + m.minimize(total_fixed_cost + total_supply_cost) + + if use_cuts: + # register a cut constraint callback + # this links the model to the callback + cut_cb = m.register_callback(CustomCutCallback) + + # store cut constraints inside the callback, as DOcplex objects + # here we add the folwing cuts: + # supply[c,l] <= use[l] for c in clients, l in locations. + # These constraints are implied by the capacity constraints, but might be violated in LP solutions. + for l in range_locations: + location_used = used[l] + for c in range_clients: + cut_cb.add_cut_constraint(supply[c, l] <= location_used) + print('* add cut constraints callback with {0} cuts'.format(len(cut_cb.cts))) + + m.cut_callback = cut_cb + return m + + +def print_solution(m, tol=1e-6): + used = m.used + supply = m.supply + n_locations = len(used) + n_clients = (int)(len(supply) / n_locations) + for l in range(n_locations): + if used[l].solution_value >= 1 - tol: + print('Facility %d is used, it serves clients %s' % + (l, ', '.join((str(c) for c in range(n_clients) if supply[c, l].solution_value >= 1 - tol)))) + + +# default data +DEFAULT_FIXED_COSTS = [480, 200, 320, 340, 300] +DEFAULT_SUPPLY_COSTS = [[24, 74, 31, 51, 84], + [57, 54, 86, 61, 68], + [57, 67, 29, 91, 71], + [54, 54, 65, 82, 94], + [98, 81, 16, 61, 27], + [13, 92, 34, 94, 87], + [54, 72, 41, 12, 78], + [54, 64, 65, 89, 89]] + + +def build_test_supply_model(use_cuts, **kwargs): + return build_supply_model(DEFAULT_FIXED_COSTS, DEFAULT_SUPPLY_COSTS, use_cuts=use_cuts, **kwargs) + + +if __name__ == "__main__": + # parse args + args = sys.argv + use_cuts = True + for arg in args[1:]: + if arg == '-cuts': + use_cuts = False + elif arg == '-nocuts': + use_cuts = False + else: + print('Unknown argument %s' % arg) + random = False + if random: + import numpy as np + # trigger this to investigate higher volumes + nl = 20 + nc = 100 + fixed = np.random.randint(100, high=500, size=nl) + supply = np.random.randint(1, high=100, size=(nc, nl)) + else: + fixed = DEFAULT_FIXED_COSTS + supply = DEFAULT_SUPPLY_COSTS + + m = build_supply_model(fixed, supply, use_cuts=use_cuts) + m.parameters.preprocessing.presolve = 0 + m.print_information() + + s = m.solve(log_output=False) + assert s + m.report() + print_solution(m) + # expected value is 843, regardless of cuts + if not random: + assert abs(m.objective_value - 843) <= 1e-4 diff --git a/examples/mp/callbacks/data/location.lp b/examples/mp/callbacks/data/location.lp new file mode 100644 index 0000000..b5f8f0d --- /dev/null +++ b/examples/mp/callbacks/data/location.lp @@ -0,0 +1,75 @@ +Minimize +obj: cost +Subject To +c1: - cost + fixed + transport = 0 +c2: - fixed + 130 x1 + 150 x2 + 170 x3 + 180 x4 = 0 +c3: - transport ++ 10 y11 + 30 y12 + 25 y13 + 55 y14 ++ 10 y21 + 25 y22 + 25 y23 + 45 y24 ++ 20 y31 + 23 y32 + 30 y33 + 40 y34 ++ 25 y41 + 10 y42 + 26 y43 + 40 y44 ++ 28 y51 + 12 y52 + 20 y53 + 29 y54 ++ 36 y61 + 19 y62 + 16 y63 + 22 y64 ++ 40 y71 + 39 y72 + 22 y73 + 27 y74 ++ 75 y81 + 65 y82 + 55 y83 + 35 y84 ++ 34 y91 + 43 y92 + 41 y93 + 62 y94 = 0 +c4: 10 y11 + 10 y21 + 12 y31 + 15 y41 + 15 y51 + 15 y61 + 20 y71 + 25 y81 + +30 y91 - 90 x1 <= 0 +c5: 10 y12 + 10 y22 + 12 y32 + 15 y42 + 15 y52 + 15 y62 + 20 y72 + 25 y82 + +30 y92 - 110 x2 <= 0 +c6: 10 y13 + 10 y23 + 12 y33 + 15 y43 + 15 y53 + 15 y63 + 20 y73 + 25 y83 + +30 y93 - 130 x3 <= 0 +c7: 10 y14 + 10 y24 + 12 y34 + 15 y44 + 15 y54 + 15 y64 + 20 y74 + 25 y84 + +30 y94 - 150 x4 <= 0 +c8: y11 + y12 + y13 + y14 = 1 +c9: y21 + y22 + y23 + y24 = 1 +c10: y31 + y32 + y33 + y34 = 1 +c11: y41 + y42 + y43 + y44 = 1 +c12: y51 + y52 + y53 + y54 = 1 +c13: y61 + y62 + y63 + y64 = 1 +c14: y71 + y72 + y73 + y74 = 1 +c15: y81 + y82 + y83 + y84 = 1 +c16: y91 + y92 + y93 + y94 = 1 +c17: x1 - y11 >= 0 +c18: x1 - y21 >= 0 +c19: x1 - y31 >= 0 +c20: x1 - y41 >= 0 +c21: x1 - y51 >= 0 +c22: x1 - y61 >= 0 +c23: x1 - y71 >= 0 +c24: x1 - y81 >= 0 +c25: x1 - y91 >= 0 +c26: x2 - y12 >= 0 +c27: x2 - y22 >= 0 +c28: x2 - y32 >= 0 +c29: x2 - y42 >= 0 +c30: x2 - y52 >= 0 +c31: x2 - y62 >= 0 +c32: x2 - y72 >= 0 +c33: x2 - y82 >= 0 +c34: x2 - y92 >= 0 +c35: x3 - y13 >= 0 +c36: x3 - y23 >= 0 +c37: x3 - y33 >= 0 +c38: x3 - y43 >= 0 +c39: x3 - y53 >= 0 +c40: x3 - y63 >= 0 +c41: x3 - y73 >= 0 +c42: x3 - y83 >= 0 +c43: x3 - y93 >= 0 +c44: x4 - y14 >= 0 +c45: x4 - y24 >= 0 +c46: x4 - y34 >= 0 +c47: x4 - y44 >= 0 +c48: x4 - y54 >= 0 +c49: x4 - y64 >= 0 +c50: x4 - y74 >= 0 +c51: x4 - y84 >= 0 +c52: x4 - y94 >= 0 +Binaries +x1 x2 x3 x4 +y11 y12 y13 y14 y21 y22 y23 y24 y31 y32 y33 y34 +y41 y42 y43 y44 y51 y52 y53 y54 y61 y62 y63 y64 +y71 y72 y73 y74 y81 y82 y83 y84 y91 y92 y93 y94 +End + diff --git a/examples/mp/callbacks/heuristic_callback.py b/examples/mp/callbacks/heuristic_callback.py new file mode 100644 index 0000000..f891284 --- /dev/null +++ b/examples/mp/callbacks/heuristic_callback.py @@ -0,0 +1,76 @@ +# -------------------------------------------------------------------------- +# Source file provided under Apache License, Version 2.0, January 2004, +# http://www.apache.org/licenses/ +# (c) Copyright IBM Corp. 2015, 2018 +# -------------------------------------------------------------------------- + +# heuristic_callback.py - Use the heuristic callback +# for optimizing a MIP problem +# +# To run this example, the user must specify a problem file. +# +# You can run this example at the command line by +# +# python heuristic_callback.pyThis tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, then use the benders decomposition on it.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n* Step 2: Set up the prescriptive model\n
\n* Step 3: Solve the problem with default CPLEX algorithm\n
\n* Step 4: Apply a Benders strategy\n
\n* Step 5: Use the CPLEX annotations to guide CPLEX in your Benders decomposition\n
\nBenders decomposition is an approach to solve mathematical programming problems with a decomposable structure.
\n\nStarting with 12.7, CPLEX can decompose the model into a single master and (possibly multiple) subproblems.
\n\nTo do so, CPLEX can use of annotations that you supply for your model or can automatically do the decomposition.
\nThis approach can be applied to mixed-integer linear programs (MILP). For certain types of problems, this approach can offer significant performance improvements.
\n\nNote:
\nIf your problem does not match such decomposition, CPLEX will raise an error at solve time.
\n\nCPLEX will produce an error CPXERRBADDECOMPOSITION if the annotated decomposition does not yield disjoint subproblems
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Learn more bout Benders decomposition", "apps": [], "results": {"msg": [{"data": "Directs a reader to more sources about Benders algorithm.
\n\nThe popular acceptance of the original paper suggesting a decomposition or partitioning of a model to support solution of mixed integer programs gave rise to \"Benders algorithm\" as the name.
\n\nOther researchers developed the theory of cut-generating linear programs (CGLP) to further this practice.
\nStill others applied the practice to practical operations research. This technical report describes Benders algorithm in \"modern\" terms and offers implementation hints.
\nWith prescriptive analytics, you can:
\n\nRun the following code to import Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nA restart of the kernel might be needed.", "apps": [], "results": {"msg": [{"data": "A restart of the kernel might be needed.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "We will write a toy model just in order to show how to use the annotation api.
\n\nThis model is not important: it just matche a benders decomposition, that is CPLEX can apply its new algorithm without any error.
\n\nThe aim of this notebook is to discover and learn how to successfully apply Benders, not to see huge performance differences between a standard solve and a Benders based solve.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nd1 = 25\nd2 = 35\n\nCosts = [[20, 15, 22, 27, 13, 4, 15, 6, 15, 22, 25, 13, 7, 28, 14, 5, 8, 1, 17, 3, 19, 17, 22, 12, 14],\n [2, 15, 16, 16, 10, 13, 4, 2, 6, 29, 10, 8, 20, 11, 8, 11, 28, 17, 10, 29, 3, 24, 12, 11, 11],\n [13, 14, 6, 17, 14, 13, 8, 29, 19, 26, 22, 0, 8, 29, 15, 20, 5, 20, 26, 17, 24, 10, 24, 9, 1],\n [7, 27, 24, 3, 4, 23, 11, 9, 18, 1, 29, 24, 16, 9, 8, 3, 18, 24, 10, 12, 1, 3, 15, 29, 3],\n [25, 26, 29, 6, 24, 8, 2, 10, 17, 0, 4, 7, 2, 17, 2, 27, 24, 20, 18, 5, 5, 2, 21, 26, 20],\n [29, 5, 15, 5, 4, 26, 18, 8, 2, 14, 13, 6, 14, 28, 16, 28, 23, 8, 5, 8, 10, 28, 17, 0, 23],\n [12, 16, 10, 16, 17, 10, 29, 11, 28, 22, 25, 8, 27, 12, 10, 28, 7, 5, 3, 9, 18, 10, 15, 16, 2],\n [12, 9, 14, 23, 26, 4, 3, 3, 22, 12, 11, 9, 19, 5, 6, 16, 1, 1, 9, 20, 23, 23, 27, 4, 11],\n [18, 13, 28, 29, 3, 28, 16, 11, 9, 2, 7, 20, 13, 23, 6, 10, 3, 16, 14, 2, 15, 17, 1, 19, 27],\n [29, 17, 17, 14, 21, 18, 8, 21, 9, 20, 14, 6, 29, 24, 24, 4, 18, 16, 21, 24, 26, 0, 26, 9, 5],\n [27, 24, 21, 28, 17, 18, 10, 10, 26, 25, 13, 18, 2, 9, 16, 26, 10, 22, 5, 17, 15, 0, 9, 0, 16],\n [13, 15, 17, 21, 25, 9, 22, 13, 20, 15, 1, 17, 18, 10, 2, 27, 19, 21, 14, 26, 29, 13, 28, 28, 15],\n [16, 12, 2, 2, 9, 27, 11, 14, 12, 2, 14, 29, 3, 12, 18, 6, 7, 9, 1, 5, 19, 14, 11, 29, 4],\n [1, 15, 27, 29, 16, 17, 10, 10, 17, 19, 6, 10, 20, 20, 19, 10, 19, 26, 15, 7, 20, 19, 13, 3, 22],\n [22, 14, 12, 3, 22, 6, 15, 3, 6, 10, 9, 13, 11, 21, 6, 19, 29, 4, 5, 21, 7, 12, 13, 11, 22],\n [9, 27, 22, 29, 11, 14, 1, 19, 21, 2, 4, 13, 17, 9, 10, 17, 13, 8, 24, 13, 26, 27, 23, 4, 21],\n [3, 14, 26, 18, 17, 3, 1, 11, 13, 8, 22, 3, 18, 26, 17, 15, 22, 10, 19, 23, 13, 14, 17, 18, 27],\n [21, 14, 1, 28, 28, 0, 0, 29, 12, 23, 22, 17, 19, 2, 10, 19, 4, 18, 28, 13, 27, 12, 9, 29, 22],\n [29, 3, 20, 5, 5, 23, 28, 16, 1, 8, 26, 23, 11, 11, 21, 17, 13, 21, 3, 8, 6, 15, 18, 6, 24],\n [14, 20, 26, 10, 17, 20, 5, 9, 25, 20, 14, 22, 5, 12, 0, 18, 7, 0, 8, 15, 21, 12, 26, 7, 21],\n [7, 7, 1, 9, 24, 29, 0, 3, 29, 24, 1, 6, 14, 0, 11, 5, 21, 12, 15, 1, 25, 4, 7, 17, 16],\n [8, 18, 15, 6, 1, 22, 26, 13, 19, 20, 12, 15, 19, 27, 13, 3, 22, 22, 22, 20, 0, 4, 24, 13, 25],\n [14, 6, 29, 23, 8, 5, 4, 18, 21, 29, 18, 2, 2, 3, 7, 13, 12, 9, 2, 18, 26, 3, 18, 7, 7],\n [5, 8, 4, 8, 25, 4, 6, 20, 14, 21, 18, 16, 15, 11, 7, 8, 20, 27, 22, 7, 5, 8, 24, 11, 8],\n [0, 8, 29, 25, 29, 0, 12, 25, 19, 9, 19, 25, 27, 21, 2, 23, 2, 25, 17, 6, 0, 6, 15, 2, 15],\n [23, 24, 10, 26, 7, 5, 5, 26, 1, 16, 22, 8, 24, 9, 16, 17, 1, 26, 20, 23, 18, 20, 23, 2, 19],\n [16, 3, 9, 21, 15, 29, 8, 26, 20, 12, 18, 27, 29, 15, 24, 9, 17, 24, 3, 5, 21, 28, 7, 1, 12],\n [1, 11, 21, 1, 13, 14, 16, 14, 17, 25, 18, 9, 19, 26, 1, 13, 15, 6, 14, 10, 12, 19, 0, 15, 7],\n [20, 14, 7, 5, 8, 16, 12, 0, 5, 14, 18, 16, 24, 27, 20, 7, 11, 3, 16, 8, 2, 2, 4, 0, 3],\n [26, 19, 27, 29, 8, 9, 8, 10, 18, 4, 6, 0, 5, 17, 12, 18, 17, 17, 13, 0, 16, 12, 18, 19, 16],\n [3, 12, 11, 28, 3, 2, 14, 14, 17, 29, 18, 14, 19, 24, 9, 27, 4, 19, 6, 24, 19, 3, 28, 20, 4],\n [2, 0, 21, 14, 21, 12, 27, 6, 20, 29, 13, 21, 23, 0, 20, 4, 11, 27, 3, 11, 21, 11, 21, 4, 17],\n [20, 26, 5, 8, 18, 14, 12, 12, 24, 3, 8, 0, 25, 16, 19, 21, 7, 4, 23, 21, 20, 28, 6, 21, 19],\n [16, 18, 9, 1, 9, 7, 14, 6, 28, 26, 3, 14, 27, 4, 9, 9, 1, 9, 24, 3, 14, 13, 18, 3, 27],\n [1, 19, 7, 20, 26, 27, 0, 7, 4, 0, 13, 8, 10, 17, 14, 19, 21, 21, 14, 15, 22, 14, 5, 27, 0]];", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nR1 = range(1,d1)\nR2 = range(1,d2);\n\ndim = range(1,d1*d2+1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nCreate one model instance, with a name. We set the log output to true such that we can see when CPLEX enables the Benders algorithm.", "apps": [], "results": {"msg": [{"data": "Create one model instance, with a name. We set the log output to true such that we can see when CPLEX enables the Benders algorithm.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# first import the Model class from docplex.mp\nfrom docplex.mp.model import Model\n\nm = Model(name='benders', log_output=True)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nX = m.continuous_var_dict([(i,j) for i in R2 for j in R1])\nY = m.integer_var_dict(R1, 0, 1)\n\n\nbendersPartition = {(i,j) : i for i in R2 for j in R1}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.minimize( m.sum( Costs[i][j]*X[i,j] for i in R2 for j in R1) + sum(Y[i] for i in R1) )\n\n\nm.add_constraints( m.sum( X[i,j] for j in R1) ==1 for i in R2)\n \nm.add_constraints( X[i,j] - Y[j] <= 0 for i in R2 for j in R1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization \n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.\n\nYou will get the best solution found after ***n*** seconds, thanks to a time limit parameter.", "apps": [], "results": {"msg": [{"data": "If you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n\nYou will get the best solution found after n seconds, thanks to a time limit parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Solve the problem with default CPLEX algorithm", "apps": [], "results": {"msg": [{"data": "If you inspect the CPLEX, you will see that it is a very standard log.
\nCPLEX needed 63 iterations to solve it.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nobj1 = m.objective_value", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Apply a Benders strategy", "apps": [], "results": {"msg": [{"data": "CPLEX implements a default Benders decomposition in certain situations.
\n\nIf you want CPLEX to apply a Benders strategy as it solves your problem, but you do not specify cpxBendersPartition annotations yourself, CPLEX puts all integer variables in master and continuous variables into subproblems.
\nIf there are no integer variables in your model, or if there are no continuous variables in your model, CPLEX raises an error stating that it cannot automatically decompose the model to apply a Benders strategy.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nYou just need to set the Benders strategy parameter.", "apps": [], "results": {"msg": [{"data": "You just need to set the Benders strategy parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nCPLEX supports 4 values for this parameter, from -1 to 3:\n* OFF (default value) will ignore Benders.\n* AUTO, USER, WORKERS, FULL will enable Benders.\n\nRefer to the CPLEX documentation to understand the differences between the 4 values that trigger it.", "apps": [], "results": {"msg": [{"data": "CPLEX supports 4 values for this parameter, from -1 to 3:
\nRefer to the CPLEX documentation to understand the differences between the 4 values that trigger it.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.parameters.benders.strategy = 3", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe call cplex solve, but with the clean_before_solve flag because we want it to forget everything about previous solve and solution.", "apps": [], "results": {"msg": [{"data": "We call cplex solve, but with the cleanbeforesolve flag because we want it to forget everything about previous solve and solution.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmsol = m.solve(clean_before_solve=True)\nassert msol is not None, \"model can't solve\"\nm.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Inspect the CPLEX Log.", "apps": [], "results": {"msg": [{"data": "\nBenders cuts applied: 3\n
\nwhich proves CPLEX applied successfully\n\nYou can see that CPLEX needed only 61 cumulative iterations, while it needed 63 previously.", "apps": [], "results": {"msg": [{"data": "Inspect the CPLEX log: you can now see that the log are different and you can see the message
\nBenders cuts applied: 3
\n\nwhich proves CPLEX applied successfully
\n\nYou can see that CPLEX needed only 61 cumulative iterations, while it needed 63 previously.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nobj2 = m.objective_value", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Use the CPLEX annotations to guide CPLEX in your Benders decomposition", "apps": [], "results": {"msg": [{"data": "Settings benders annotation in docplex is very simple.
\nYou just need to use the benders_annotation property available on variables and constraints to state which worker they belong to.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor i in R2:\n for j in R1:\n X[i,j].benders_annotation = i%2", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmsol = m.solve(clean_before_solve=True)\nassert msol is not None, \"model can't solve\"\nm.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Inspect the CPLEX Log.", "apps": [], "results": {"msg": [{"data": "Inspect the CPLEX log: you can see that you now need only 57 cumulative iterations instead of 61 with default Benders and 63 with no Benders.
\nIf you look at the Best Bound column, you will also see that the listed sub problems are not the same as CPLEX applied the decomposition provided by the annotations.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nobj3 = m.objective_value", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nassert (obj1 == obj2) and (obj2 == obj3)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and apply a Benders decomposition.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and apply a Benders decomposition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com\"\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/Progress_callbacks.json b/examples/mp/zeppelin/Progress_callbacks.json deleted file mode 100644 index 1f04096..0000000 --- a/examples/mp/zeppelin/Progress_callbacks.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\Progress_callbacks", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Using the Progress Callbacks with CPLEX Optimizer\n\nThis tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, then use the progress callbacks to follow the progress, capture the intermediate solutions and stop the solve on your own criteria.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n * Step 2: Set up the prescriptive model\n * Step 3: Track the CPLEX progress\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, then use the progress callbacks to follow the progress, capture the intermediate solutions and stop the solve on your own criteria.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n* Step 2: Set up the prescriptive model\n
\n* Step 3: Track the CPLEX progress\n
\nWith prescriptive analytics, you can:
\n\nRun the following code to import Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "We will write a scalable model just in order to show how to use the progress callback API.
\n\nThis model is not important: it is a model that can take very long to solve and will find multiple intermediate solutions
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\ndef build_hearts(r, **kwargs):\n # initialize the model\n mdl = Model('love_hearts_%d' % r, **kwargs)\n\n # the dictionary of decision variables, one variable\n # for each circle with i in (1 .. r) as the row and\n # j in (1 .. i) as the position within the row \n idx = [(i, j) for i in range(1, r + 1) for j in range(1, i + 1)]\n a = mdl.binary_var_dict(idx, name=lambda idx_tuple: \"a_%d_%d\" % (idx_tuple[0], idx_tuple[1]))\n\n # the constraints - enumerate all equilateral triangles\n # and prevent any such triangles being formed by keeping\n # the number of included circles at its vertexes below 3\n\n # for each row except the last\n for i in range(1, r):\n # for each position in this row\n for j in range(1, i + 1):\n # for each triangle of side length (k) with its upper vertex at\n # (i, j) and its sides parallel to those of the overall shape\n for k in range(1, r - i + 1):\n # the sets of 3 points at the same distances clockwise along the\n # sides of these triangles form k equilateral triangles\n for m in range(k):\n u, v, w = (i + m, j), (i + k, j + m), (i + k - m, j + k - m)\n mdl.add_constraint(a[u] + a[v] + a[w] <= 2)\n\n mdl.maximize(mdl.sum(a))\n return mdl", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIt is perfect to demonstrate how to listen to CPLEX during its progress as it contains multiple intermediate solutions.", "apps": [], "results": {"msg": [{"data": "It is perfect to demonstrate how to listen to CPLEX during its progress as it contains multiple intermediate solutions.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Track the CPLEX progress", "apps": [], "results": {"msg": [{"data": "We will use a TextProgressListener to follow the CPLEX search. It will print on the standard output each time an intermediate solution is found.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm5 = build_hearts(5)\n\nfrom docplex.mp.progress import TextProgressListener\nunfiltered_texter = TextProgressListener(filtering=False)\nm5.add_progress_listener(unfiltered_texter)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization\n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.\n\nYou will get the best solution found after ***n*** seconds, thanks to a time limit parameter.", "apps": [], "results": {"msg": [{"data": "If you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n\nYou will get the best solution found after n seconds, thanks to a time limit parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm5.solve(clean_before_solve=True)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's remove the listener.", "apps": [], "results": {"msg": [{"data": "Let's remove the listener.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm5.remove_progress_listener(unfiltered_texter)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Track and store all intermediate solutions", "apps": [], "results": {"msg": [{"data": "You just need to subclass the SolutionListener object and specialize the notify_* methods if needed.
\nHere we will store all solutions all along the way.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.progress import SolutionListener\nclass MyProgressListener(SolutionListener):\n def __init__(self, model):\n SolutionListener.__init__(self, model)\n self.solutions = []\n \n def notify_solution(self, s):\n SolutionListener.notify_solution(self, s)\n self.solutions.append(self.current_solution)\n \n def get_solutions(self):\n return self.solutions\n \nkeeper = MyProgressListener(m5)\nm5.add_progress_listener(keeper)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm5.solve(clean_before_solve=True)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe have stored docplex.mp.solution.SolveSolution objects.\nWe can iterate on them to query the objective values, the values of each variables...", "apps": [], "results": {"msg": [{"data": "We have stored docplex.mp.solution.SolveSolution objects.
\nWe can iterate on them to query the objective values, the values of each variables...
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor s in keeper.get_solutions():\n print(s.objective_value)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Implement our own aborter\nIt may be nice to be able to abort the CPLEX on your own criteria.\nFor example, when the gap is converging very slowly, it may be a good idea to stop and use the last solution instead of waiting forever.\n\nYou just need to subclass the ProgressListener and specialize the notify_* methods.", "apps": [], "results": {"msg": [{"data": "It may be nice to be able to abort the CPLEX on your own criteria.
\nFor example, when the gap is converging very slowly, it may be a good idea to stop and use the last solution instead of waiting forever.
\n\nYou just need to subclass the ProgressListener and specialize the notify_* methods.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.progress import ProgressListener\nclass AutomaticAborter(ProgressListener):\n def __init__(self, max_no_solutions=10):\n self.last_incumbent_obj = -999999999\n self.nb_solutions = 0\n self.nb_non_improving = 0\n self.max_non_improving = max_no_solutions\n\n def notify_progress(self, progress_data):\n super(AutomaticAborter, self).notify_progress(progress_data)\n last_obj = self.last_incumbent_obj\n if progress_data.has_incumbent:\n if last_obj is None or progress_data.current_objective >= last_obj + 1e-5:\n self.nb_solutions += 1\n self.nb_non_improving = 0\n print('----> #solutions={}'.format(self.nb_solutions))\n else:\n\n # non improving move\n self.nb_non_improving += 1\n print('----> #non improving solutions={}'.format(self.nb_non_improving))\n self.last_incumbent_obj = progress_data.current_objective\n else:\n self.nb_non_improving += 1\n if self.nb_non_improving >= self.max_non_improving:\n if not self.has_aborted():\n print('!! aborting cplex, #solutions={0}, #non-improving: {1}'.format(self.nb_solutions,\n self.nb_non_improving))\n self.abort()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's build a bigger problem with more solutions.", "apps": [], "results": {"msg": [{"data": "Let's build a bigger problem with more solutions.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nlove14 = build_hearts(11)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nauto_abort = AutomaticAborter(max_no_solutions=50)\nlove14.add_progress_listener(auto_abort)\n\nlove14.solve()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and track its progress.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and track its progress.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com\"\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/boxes.json b/examples/mp/zeppelin/boxes.json deleted file mode 100644 index 1bc5dd7..0000000 --- a/examples/mp/zeppelin/boxes.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\boxes", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Objects in boxes\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>Running the sample requires the installation of\n [CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n (Commercial or free \n [CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n This sample automatically installs *CPLEX CE* if needed.\n\n\nTable of contents:\n\n* Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n * Step 2: Model the data\n * Step 3: Prepare the data\n * Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\nRunning the sample requires the installation of
\n
[CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n
\n(Commercial or free\n
\n[CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n
\nThis sample automatically installs *CPLEX CE* if needed.\n
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n* Step 2: Model the data\n
\n* Step 3: Prepare the data\n
\n* Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n* each box contains exactly one object,\n
\n* each object is stored in one box,\n
\n* the total distance from object $j$ to its storage box is minimal.\n
\n\n\n* From the first solution, we impose that object #1 is assigned to the box immediately to the left of object #2.\n
\n* Then we impose that object #5 is assigned to a box next to the box of object #6.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\n* Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It takes into account specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \nWith prescriptive analytics, you can:
\n\nRun the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/') ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf *CPLEX* is not installed, install CPLEX Community edition.", "apps": [], "results": {"msg": [{"data": "If CPLEX is not installed, install CPLEX Community edition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import cplex\nexcept:\n raise Exception('Please install CPLEX. See https://pypi.org/project/cplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\n\nThe input data is the number of objects (and boxes) _N_, and their positions in the (x,y) plane.\n\n### Step 3: Prepare the data\n\nWe use Euclidean distance to compute the distance between an object and its assigned box.\n\n", "apps": [], "results": {"msg": [{"data": "The input data is the number of objects (and boxes) N, and their positions in the (x,y) plane.
\n\nWe use Euclidean distance to compute the distance between an object and its assigned box.
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom math import sqrt\n\nN = 15\nbox_range = range(1, N+1)\nobj_range = range(1, N+1)\n\nimport random\n\no_xmax = N*10\no_ymax = 2*N\nbox_coords = {b: (10*b, 1) for b in box_range}\n\nobj_coords= {1: (140, 6), 2: (146, 8), 3: (132, 14), 4: (53, 28), \n 5: (146, 4), 6: (137, 13), 7: (95, 12), 8: (68, 9), 9: (102, 18), \n 10: (116, 8), 11: (19, 29), 12: (89, 15), 13: (141, 4), 14: (29, 4), 15: (4, 28)}\n\n# the distance matrix from box i to object j\n# actually we compute the square of distance to keep integer\n# this does not change the essence of the problem\ndistances = {}\nfor o in obj_range:\n for b in box_range:\n dx = obj_coords[o][0]-box_coords[b][0]\n dy = obj_coords[o][1]-box_coords[b][1]\n d2 = dx*dx + dy*dy\n distances[b, o] = d2", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmdl = Model(\"boxes\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables\n\n* For each box $i$ ($i$ in $1..N$) and object $j$ ($j$ in $1..N$), we define a binary variable $X_{i,j}$ equal to $1$ if and only if object $j$ is stored in box $i$.", "apps": [], "results": {"msg": [{"data": "As an additional constraint, we want to impose that object #1 is stored immediately to the left of object #2.
\nAs a consequence, object #2 cannot be stored in box #1, so we add:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.add_constraint(x[1,2] == 0)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow, we must state that for $k \\geq 2$ if $x[k,2] == 1$ then $x[k-1,1] == 1$; this is a logical implication that we express by a relational operator:", "apps": [], "results": {"msg": [{"data": "Now, we must state that for $k \\geq 2$ if $x[k,2] == 1$ then $x[k-1,1] == 1$; this is a logical implication that we express by a relational operator:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.add_constraints(x[k-1,1] >= x[k,2]\n for k in range(2,N+1))\nmdl.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow let's solve again and check that our new constraint is satisfied, that is, object #1 is immediately left to object #2", "apps": [], "results": {"msg": [{"data": "Now let's solve again and check that our new constraint is satisfied, that is, object #1 is immediately left to object #2
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nok2 = mdl.solve()\nassert ok2, \"solve failed\"\nmdl.report()\nd2 = mdl.objective_value\nsol2 = make_solution_vector(x)\nprint(\" solution #2 ={0!s}\".format(sol2))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe constraint is indeed satisfied, with a higher objective, as expected.", "apps": [], "results": {"msg": [{"data": "The constraint is indeed satisfied, with a higher objective, as expected.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Additional constraint #2\n\nNow, we want to add a second constraint to state that object #5 is stored in a box that is next to the box of object #6, either to the left or right.\n\nIn other words, when $x[k,6]$ is equal to $1$, then one of $x[k-1,5]$ and $x[k+1,5]$ is equal to $1$;\nthis is again a logical implication, with an OR in the right side.\n\nWe have to handle the case of extremities with care.", "apps": [], "results": {"msg": [{"data": "Now, we want to add a second constraint to state that object #5 is stored in a box that is next to the box of object #6, either to the left or right.
\n\nIn other words, when $x[k,6]$ is equal to $1$, then one of $x[k-1,5]$ and $x[k+1,5]$ is equal to $1$;
\nthis is again a logical implication, with an OR in the right side.
\n\nWe have to handle the case of extremities with care.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# forall k in 2..N-1 then we can use the sum on the right hand side\nmdl.add_constraints(x[k,6] <= x[k-1,5] + x[k+1,5]\n for k in range(2,N))\n \n# if 6 is in box 1 then 5 must be in 2\nmdl.add_constraint(x[1,6] <= x[2,5])\n\n# if 6 is last, then 5 must be before last\nmdl.add_constraint(x[N,6] <= x[N-1,5])\n\n# we solve again\nok3 = mdl.solve()\nassert ok3, \"solve failed\"\nmdl.report()\nd3 = mdl.objective_value\n\nsol3 = make_solution_vector(x)\nprint(\" solution #3 ={0!s}\".format(sol3)) ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAs expected, the constraint is satisfied; objects #5 and #6 are next to each other.\nPredictably, the objective is higher.\n\n### Step 5: Investigate the solution and then run an example analysis\n\nPresent the solution as a vector of object indices, sorted by box indices.\nWe use maptplotlib to display the assignment of objects to boxes.\n", "apps": [], "results": {"msg": [{"data": "As expected, the constraint is satisfied; objects #5 and #6 are next to each other.
\nPredictably, the objective is higher.
\n\nPresent the solution as a vector of object indices, sorted by box indices.
\nWe use maptplotlib to display the assignment of objects to boxes.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport matplotlib.pyplot as plt\nfrom pylab import rcParams\nrcParams['figure.figsize'] = 12, 6\n\ndef display_solution(sol):\n obj_boxes = make_obj_box_dir(sol)\n xs = []\n ys = []\n for o in obj_range:\n b = obj_boxes[o]\n box_x = box_coords[b][0]\n box_y = box_coords[b][1]\n obj_x = obj_coords[o][0]\n obj_y = obj_coords[o][1]\n plt.text(obj_x, obj_y, str(o), bbox=dict(facecolor='red', alpha=0.5))\n plt.plot([obj_x, box_x], [obj_y, box_y])\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe first solution shows no segments crossing, which is to be expected.", "apps": [], "results": {"msg": [{"data": "The first solution shows no segments crossing, which is to be expected.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndisplay_solution(sol1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe second solution, by enforcing that object #1 must be to the left of object #2, introduces crossings.", "apps": [], "results": {"msg": [{"data": "The second solution, by enforcing that object #1 must be to the left of object #2, introduces crossings.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndisplay_solution(sol2)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndisplay_solution(sol3)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n\ndef display(myDict, title):\n if True: #env.has_matplotlib:\n N = len(myDict)\n labels = myDict.keys()\n values= myDict.values()\n try: # Python 2\n ind = xrange(N) # the x locations for the groups\n except: # Python 3\n ind = range(N)\n width = 0.2 # the width of the bars\n fig, ax = plt.subplots()\n rects1 = ax.bar(ind, values, width, color='g')\t\n ax.set_title(title)\n ax.set_xticks([ind[i]+width/2 for i in ind])\n ax.set_xticklabels( labels )\t\n #ax.legend( (rects1[0]), (title) )\n plt.show()\n else:\n print(\"warning: no display\")\n\nfrom collections import OrderedDict\ndists = OrderedDict()\ndists[\"d1\"]= d1 -8000\ndists[\"d2\"] = d2 - 8000\ndists[\"d3\"] = d3 - 8000\nprint(dists)\n\ndisplay(dists, \"evolution of distance objective\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/chicago_coffee_shops.json b/examples/mp/zeppelin/chicago_coffee_shops.json deleted file mode 100644 index d1bcdfe..0000000 --- a/examples/mp/zeppelin/chicago_coffee_shops.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\chicago_coffee_shops", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Finding optimal locations of new stores\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n* Most of the customers of this coffee brewer enjoy reading and borrowing books, so the goal is to locate those shops in such a way that all the city public libraries are within minimal walking distance.\n
\nWith prescriptive analytics, you can:
\n\nRun the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/') ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNote that the more global package docplex contains another subpackage docplex.cp that is dedicated to Constraint Programming, another branch of optimization.", "apps": [], "results": {"msg": [{"data": "Note that the more global package docplex contains another subpackage docplex.cp that is dedicated to Constraint Programming, another branch of optimization.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\n\n- The data for this problem is quite simple: it is composed of the list of public libraries and their geographical locations.\n- The data is acquired from [Chicago open data](https://data.cityofchicago.org) as a JSON file, which is in the following format:\n\ndata\" : [ [ 1, \"13BFA4C7-78CE-4D83-B53D-B57C60B701CF\", 1, 1441918880, \"885709\", 1441918880, \"885709\", null, \"Albany Park\", \"M, W: 10AM-6PM; TU, TH: 12PM-8PM; F, SA: 9AM-5PM; SU: Closed\", \"Yes\", \"Yes \", \"3401 W. Foster Avenue\", \"CHICAGO\", \"IL\", \"60625\", \"(773) 539-5450\", [ \"http://www.chipublib.org/locations/1/\", null ], [ null, \"41.975456\", \"-87.71409\", null, false ] ]\n
\nThis code snippet represents library \"**3401 W. Foster Avenue**\" located at **41.975456, -87.71409**\n", "apps": [], "results": {"msg": [{"data": "data\" : [ [ 1, \"13BFA4C7-78CE-4D83-B53D-B57C60B701CF\", 1, 1441918880, \"885709\", 1441918880, \"885709\", null, \"Albany Park\", \"M, W: 10AM-6PM; TU, TH: 12PM-8PM; F, SA: 9AM-5PM; SU: Closed\", \"Yes\", \"Yes \", \"3401 W. Foster Avenue\", \"CHICAGO\", \"IL\", \"60625\", \"(773) 539-5450\", [ \"http://www.chipublib.org/locations/1/\", null ], [ null, \"41.975456\", \"-87.71409\", null, false ] ]
\n\nThis code snippet represents library \"3401 W. Foster Avenue\" located at 41.975456, -87.71409
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nDisclaimer:\nThis site provides applications using data that has been modified for use from its original source, www.cityofchicago.org, the official website of the City of Chicago. The City of Chicago makes no claims as to the content, accuracy, timeliness, or completeness of any of the data provided at this site. The data provided at this site is subject to change at any time. It is understood that the data provided at this site is being used at one\u2019s own risk.", "apps": [], "results": {"msg": [{"data": "Disclaimer:
\nThis site provides applications using data that has been modified for use from its original source, www.cityofchicago.org, the official website of the City of Chicago. The City of Chicago makes no claims as to the content, accuracy, timeliness, or completeness of any of the data provided at this site. The data provided at this site is subject to change at any time. It is understood that the data provided at this site is being used at one\u2019s own risk.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data\nWe need to collect the list of public libraries locations and keep their names, latitudes, and longitudes.", "apps": [], "results": {"msg": [{"data": "We need to collect the list of public libraries locations and keep their names, latitudes, and longitudes.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Store longitude, latitude and street crossing name of each public library location.\nclass XPoint(object):\n def __init__(self, x, y):\n self.x = x\n self.y = y\n def __str__(self):\n return \"P(%g_%g)\" % (self.x, self.y)\n\nclass NamedPoint(XPoint):\n def __init__(self, name, x, y):\n XPoint.__init__(self, x, y)\n self.name = name\n def __str__(self):\n return self.name", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define how to compute the earth distance between 2 points\nTo easily compute distance between 2 points, we use the Python package [geopy](https://pypi.python.org/pypi/geopy)", "apps": [], "results": {"msg": [{"data": "To easily compute distance between 2 points, we use the Python package geopy
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pip._internal\ntry:\n import geopy.distance\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip._internal.main(['install', 'geopy'])\n else:\n pip._internal.main(['install', '--user', 'geopy']) ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Simple distance computation between 2 locations.\nfrom geopy.distance import great_circle\n \ndef get_distance(p1, p2):\n return great_circle((p1.y, p1.x), (p2.y, p2.x)).miles", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Declare the list of libraries\nParse the JSON file to get the list of libraries and store them as Python elements.", "apps": [], "results": {"msg": [{"data": "Parse the JSON file to get the list of libraries and store them as Python elements.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef build_libraries_from_url(url, name_pos, lat_long_pos):\n import requests\n import json\n r = requests.get(url)\n myjson = json.loads(r.text, parse_constant='utf-8')\n myjson = myjson['data']\n libraries = []\n k = 1\n for location in myjson:\n uname = location[name_pos]\n try:\n latitude = float(location[lat_long_pos][1])\n longitude = float(location[lat_long_pos][2])\n except TypeError:\n latitude = longitude = None\n try:\n name = str(uname)\n except:\n name = \"???\"\n name = \"P_%s_%d\" % (name, k)\n if latitude and longitude:\n cp = NamedPoint(name, longitude, latitude)\n libraries.append(cp)\n k += 1\n return libraries", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nlibraries = build_libraries_from_url('https://data.cityofchicago.org/api/views/x8fc-8rcq/rows.json?accessType=DOWNLOAD',\n name_pos=12,\n lat_long_pos=18)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nprint(\"There are %d public libraries in Chicago\" % (len(libraries)))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define number of shops to open\nCreate a constant that indicates how many coffee shops we would like to open.", "apps": [], "results": {"msg": [{"data": "Create a constant that indicates how many coffee shops we would like to open.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnb_shops = 5\nprint(\"We would like to open %d coffee shops\" % nb_shops)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Validate the data by displaying them\nWe will use the [folium](https://folium.readthedocs.org/en/latest/quickstart.html#getting-started) library to display a map with markers.", "apps": [], "results": {"msg": [{"data": "We will use the folium library to display a map with markers.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pip._internal\ntry:\n import folium\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip._internal.main(['install', 'folium'])\n else:\n pip._internal.main(['install', '--user', 'folium'])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport folium\nmap_osm = folium.Map(location=[41.878, -87.629], zoom_start=11)\nfor library in libraries:\n lt = library.y\n lg = library.x\n folium.Marker([lt, lg]).add_to(map_osm)\nmap_osm", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAfter running the above code, the data is displayed but it is impossible to determine where to ideally open the coffee shops by just looking at the map.\n\nLet's set up DOcplex to write and solve an optimization model that will help us determine where to locate the coffee shops in an optimal way.", "apps": [], "results": {"msg": [{"data": "After running the above code, the data is displayed but it is impossible to determine where to ideally open the coffee shops by just looking at the map.
\n\nLet's set up DOcplex to write and solve an optimization model that will help us determine where to locate the coffee shops in an optimal way.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmdl = Model(\"coffee shops\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "First constraint: if the distance is suspect, it needs to be excluded from the problem.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor c_loc in coffeeshop_locations:\n for b in libraries:\n if get_distance(c_loc, b) >= BIGNUM:\n mdl.add_constraint(link_vars[c_loc, b] == 0, \"ct_forbid_{0!s}_{1!s}\".format(c_loc, b))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSecond constraint: each library must be linked to a coffee shop that is open.", "apps": [], "results": {"msg": [{"data": "Second constraint: each library must be linked to a coffee shop that is open.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.add_constraints(link_vars[c_loc, b] <= coffeeshop_vars[c_loc]\n for b in libraries\n for c_loc in coffeeshop_locations)\nmdl.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThird constraint: each library is linked to exactly one coffee shop.", "apps": [], "results": {"msg": [{"data": "Third constraint: each library is linked to exactly one coffee shop.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.add_constraints(mdl.sum(link_vars[c_loc, b] for c_loc in coffeeshop_locations) == 1\n for b in libraries)\nmdl.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFourth constraint: there is a fixed number of coffee shops to open.", "apps": [], "results": {"msg": [{"data": "Fourth constraint: there is a fixed number of coffee shops to open.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Total nb of open coffee shops\nmdl.add_constraint(mdl.sum(coffeeshop_vars[c_loc] for c_loc in coffeeshop_locations) == nb_shops)\n\n# Print model information\nmdl.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective\n\nThe objective is to minimize the total distance from libraries to coffee shops so that a book reader always gets to our coffee shop easily.\n", "apps": [], "results": {"msg": [{"data": "The objective is to minimize the total distance from libraries to coffee shops so that a book reader always gets to our coffee shop easily.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Minimize total distance from points to hubs\ntotal_distance = mdl.sum(link_vars[c_loc, b] * get_distance(c_loc, b) for c_loc in coffeeshop_locations for b in libraries)\nmdl.minimize(total_distance)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization\n\nSolve the model on the cloud. ", "apps": [], "results": {"msg": [{"data": "Solve the model on the cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nprint(\"# coffee shops locations = %d\" % len(coffeeshop_locations))\nprint(\"# coffee shops = %d\" % nb_shops)\n\nassert mdl.solve(), \"!!! Solve of the model fails\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 6: Investigate the solution and then run an example analysis\n\nThe solution can be analyzed by displaying the location of the coffee shops on a map.", "apps": [], "results": {"msg": [{"data": "The solution can be analyzed by displaying the location of the coffee shops on a map.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntotal_distance = mdl.objective_value\nopen_coffeeshops = [c_loc for c_loc in coffeeshop_locations if coffeeshop_vars[c_loc].solution_value == 1]\nnot_coffeeshops = [c_loc for c_loc in coffeeshop_locations if c_loc not in open_coffeeshops]\nedges = [(c_loc, b) for b in libraries for c_loc in coffeeshop_locations if int(link_vars[c_loc, b]) == 1]\n\nprint(\"Total distance = %g\" % total_distance)\nprint(\"# coffee shops = {0}\".format(len(open_coffeeshops)))\nfor c in open_coffeeshops:\n print(\"new coffee shop: {0!s}\".format(c))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Displaying the solution\nCoffee shops are highlighted in red.", "apps": [], "results": {"msg": [{"data": "Coffee shops are highlighted in red.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport folium\nmap_osm = folium.Map(location=[41.878, -87.629], zoom_start=11)\nfor coffeeshop in open_coffeeshops:\n lt = coffeeshop.y\n lg = coffeeshop.x\n folium.Marker([lt, lg], icon=folium.Icon(color='red',icon='info-sign')).add_to(map_osm)\n \nfor b in libraries:\n if b not in open_coffeeshops:\n lt = b.y\n lg = b.x\n folium.Marker([lt, lg]).add_to(map_osm)\n \n\nfor (c, b) in edges:\n coordinates = [[c.y, c.x], [b.y, b.x]]\n map_osm.add_child(folium.PolyLine(coordinates, color='#FF0000', weight=5))\n\nmap_osm", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/efficient.json b/examples/mp/zeppelin/efficient.json deleted file mode 100644 index a831f24..0000000 --- a/examples/mp/zeppelin/efficient.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\efficient", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Writing efficient DOcplex code\n\nIn this notebook, we show how to improve efficiency of DOcplex models using five simple rules.", "apps": [], "results": {"msg": [{"data": "In this notebook, we show how to improve efficiency of DOcplex models using five simple rules.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## A simple timing tool\n\nTo measure performance we need a simple timing tool. For this purpose, we chose to implement a Python context manager object (see https://docs.python.org/3/reference/datamodel.html#context-managers) for details.\n\nThis object stores the start time when entering a block and reports time spent when exiting the block. Python's `with` statement avoids cluttering code with intrusive prints.", "apps": [], "results": {"msg": [{"data": "To measure performance we need a simple timing tool. For this purpose, we chose to implement a Python context manager object (see https://docs.python.org/3/reference/datamodel.html#context-managers) for details.
\n\nThis object stores the start time when entering a block and reports time spent when exiting the block. Python's with
statement avoids cluttering code with intrusive prints.
To compare various implementations, we need a simple, scalable benchmark model. The model has no real business meaning, but is simple to grasp
\nand can be scaled by changing one size
parameter.
Note that we'll be comparing only the build time of the model, not the solve time.
\n\nNote that the model has n constraints, all with expressions of size N, so we expect the underlying matrix size to grow as $O(N^2)$.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Description\n\nLet $N$ be an integer (the size of the problem).\n\n$$\nminimize \\sum_{k=0}^{k=N-1} (k+1) * y_{k}\\\\\ns.t.\\\\\n\\forall\\ \\ m\\ in \\{0..N-1\\}\\ \\ \\sum_{l=0}^{l=N-1} (y_{l} * (l+ (l+m) \\%3) \\ge l\\\\\ny_{k} = 0, 1\n$$", "apps": [], "results": {"msg": [{"data": "Let $N$ be an integer (the size of the problem).
\n\n$$
\nminimize \\sum{k=0}^{k=N-1} (k+1) * y{k}\\
\ns.t.\\
\n\\forall\\ \\ m\\ in {0..N-1}\\ \\ \\sum{l=0}^{l=N-1} (y{l} * (l+ (l+m) \\%3) \\ge l\\
\ny_{k} = 0, 1
\n$$
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## A beginners's implementation of the model\n\nIn this section we show a Python/Docplex beginner's implementation of this model.\n", "apps": [], "results": {"msg": [{"data": "In this section we show a Python/Docplex beginner's implementation of this model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\ndef build_bench_model1(size=10):\n m = Model(name=\"bench1\")\n rsize = range(size)\n # create variables as a dictionary indexed by the range\n ys = m.binary_var_dict(rsize, name=\"y\")\n # create constraints\n k = {(i,j) : (i + (i+j) %3) for i in rsize for j in rsize}\n for i in rsize:\n m.add(m.sum(ys[i] * k[i,j] for j in rsize) >= i, \"ct_%d\" %i)\n # for minimize, create a list of coefficients\n rsize1 = [i+1 for i in rsize]\n m.minimize(m.sum(ys[k] * rsize[k] for k in rsize))\n return m", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLets run our context timer with N=1000; we expect a model with 1000 variables and 1000 constraints:", "apps": [], "results": {"msg": [{"data": "Lets run our context timer with N=1000; we expect a model with 1000 variables and 1000 constraints:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nwith ContextTimer(\"bench1_size_1000\"):\n m11k = build_bench_model1(1000)\n m11k.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAs expected the model has 1000 variables and 1000 constraints and the build time is significant.\nFor N=3000, we can expect an increase in buid time by a factor of 9:", "apps": [], "results": {"msg": [{"data": "As expected the model has 1000 variables and 1000 constraints and the build time is significant.
\nFor N=3000, we can expect an increase in buid time by a factor of 9:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nN=3000\nwith ContextTimer(\"bench1 size={0}\".format(N)):\n build_bench_model1(N)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n# Seven tips to improve DOcplex code efficiency", "apps": [], "results": {"msg": [{"data": "When building large expressions, scalar product (Model.scal_prod()
) is
an efficient way to combine a sequence of variables (or expressions)
\nand a sequence of coefficients.
\nTry using scalar_prod
instead of using for
loops in expressions.
In the previous examples, we had to create an auxiliary sequence from the variable dictionary to pass to scal_prod
. Actually, a variable list would be much simpler to use than the dictionary, so we replace the var_dict
by a var_list
Adding constraints to the model by batches using Model.add_constraints()
is usually more efficient.
\nTry grouping consttraints in lists or comprehensions (both work).
\n\nIf the constraints are named, pass a second argument with the collection of constraint names.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef build_bench_model3(size=10):\n m = Model(name=\"bench3\")\n rsize = range(size)\n # create variables as a dictionary indexed by the range\n ys = m.binary_var_list(rsize, name=\"y\")\n # create constraints\n k = {(i,j) : (i + (i+j) %3) for i in rsize for j in rsize}\n m.add_constraints((m.scal_prod(ys, [k[i,j] for j in rsize]) >= i for i in rsize),\n [\"ct_%d\" % i for i in rsize])\n # for minimize, create a list of coefficients\n rsize1 = [i+1 for i in rsize]\n m.minimize(m.scal_prod(ys, rsize1))\n return m\n\nwith ContextTimer(\"bench3 size={0}\".format(N)):\n build_bench_model3(N)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Avoid creating unnecessary containers\n\nThe previous version allocated one dictionary `k` for coefficients and an auxiliary list for the objective. We can simplify the code bys using comprehensions instead.", "apps": [], "results": {"msg": [{"data": "The previous version allocated one dictionary k
for coefficients and an auxiliary list for the objective. We can simplify the code bys using comprehensions instead.
Naming variables and/or constraints is useful to generate readable LP files. However, generating lare numbers of strings may have a significant cost in Python, sepcially for large models.
\n\nDOcplex provides a keyword ignore_names
at model creation time, which may disable all names (variables and constraint names alike) that are set in the model.
By default, this flag is False
, and names are enabled. By setting this flag to True
, all names mentioned in the model are discarded (in particular, names are not used in LP generation).
In the next version we simply add the ignore_names=True
keyword argument to the model constructor
DOcplex does a minimal checking on arguments. As this can be useful when writing the model to avoid errors, this checking has a runtime cost. When running a deployed model that has been thoroughly tested and tuned, you can remove all checks by adding the checker=\"off\"
keyword argument to the model constructor.
Again, the next version is identical to the previous one , except that type-checking has been disabled.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef build_bench_model6(size=10):\n m = Model(name=\"bench6\", ignore_names=True, checker=\"off\")\n rsize = range(size)\n # create variables as a dictionary indexed by the range\n ys = m.binary_var_list(rsize, name=\"y\")\n # create constraints\n m.add_constraints((m.scal_prod(ys, [(i+ (i+j)%3) for j in rsize]) >= i for i in rsize),\n (\"ct_%d\" % i for i in rsize))\n # for minimize, create a list of coefficients\n m.minimize(m.scal_prod(ys, (i+1 for i in rsize)))\n return m\n\nwith ContextTimer(\"bench6 size={0}\".format(N)):\n build_bench_model6(N)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use the \"advanced model\" class\n\nDOcplex contains and `AdvModel` class, which is a subclass of `Model`.\nThis class contains highly efficient methods for special cases, for examples, scalar prodicts with all different variables. \nBy default, `AdvModel` methods do not perform any checking on their arguments. For example, the `cal_prod_vars_all_different` method does not check that the variables are indeed all different. If this is not true, then errors or incorrect results may occur.\n\nStill, you can enable type-checking on AdvModel by specifying `checker=\"on\"` at construction time, and remove it later.\n\nThe benchmark model is a good fit for the `scal_prod_vars_all_different` method as all our scalar products involve the `ys` variables.\n\nAdvModel provides other specialized fast method, among them:\n\n - `sum_vars_all_different` to compute the sum of a sequence of all different variables.\n - `quad_matrix_sum` to compute a quadratic expression from a matrix $Q$ and a vector of variables $X$ as $X^{t}QX$\n - `vector_compare` to compute a sequence of linear constraint from two sequences of expressions\n", "apps": [], "results": {"msg": [{"data": "DOcplex contains and AdvModel
class, which is a subclass of Model
.
This class contains highly efficient methods for special cases, for examples, scalar prodicts with all different variables.
\nBy default, AdvModel
methods do not perform any checking on their arguments. For example, the cal_prod_vars_all_different
method does not check that the variables are indeed all different. If this is not true, then errors or incorrect results may occur.
Still, you can enable type-checking on AdvModel by specifying checker=\"on\"
at construction time, and remove it later.
The benchmark model is a good fit for the scal_prod_vars_all_different
method as all our scalar products involve the ys
variables.
AdvModel provides other specialized fast method, among them:
\n\nsum_vars_all_different
to compute the sum of a sequence of all different variables.quad_matrix_sum
to compute a quadratic expression from a matrix $Q$ and a vector of variables $X$ as $X^{t}QX$vector_compare
to compute a sequence of linear constraint from two sequences of expressionsFrom version 1 to version 7 , model build time has decreased from 35s to 4s (on our platform). Result smay well differ on other platforms, but still, this demonstrates that the way the model is built can greatly influence the performance.
\n\nHere is a list of tricks to try to improve model building time:
\n\nAdvModel
class.In this section we compute the times to build different model versions on various sizes, and
\nplot the result on a graph.
\nThis code requires the matplotlib
library to run.
Note: the next cell might take a significant time to run, as it
\nruns a lot of (size, modelbuildfunction) combinations...
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# various sizes to sample performance\nsizes = [100, 300, 600, 1000, 3000, 5000]\n\n# a lits of tuples (fn, label) to build model and an explanatory label\nbuilders = [(build_bench_model1, \"initial\"), \n (build_bench_model2, \"scal_prod\"),\n (build_bench_model4, \"batch_cts\"),\n (build_bench_model5, \"ignore_names\"),\n (build_bench_model6, \"checker_off\"),\n (build_bench_model7, \"advmodel\")]\nprint(\"* start computing performance data\")\nres = {}\nprint(\"* start computing results...\")\nnb_runs = len(sizes) * len(builders)\nr = 0\nfor s in sizes:\n for b, (bf, _) in enumerate(builders):\n r +=1 \n with ContextTimer(\"[{2}/{3}] use {0} with size={1}\"\n .format(bf.__name__, s, r, nb_runs)) as tt:\n m = bf(s)\n m.end()\n elapsed = tt.msecs\n res[b, s] = tt.msecs\n\n\nprint(\"* end computing results\")\n# now we have a dict of (#builder, size) -> time", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import matplotlib.pyplot as plt\n except ImportError:\n print(\"try install matplotlib: pip install matplotlib\")\n raise\n\n\nlabels = [ bl for (_, bl) in builders]\nplt.figure(figsize=(16,7))\nfor b in range(len(builders)):\n bts = [res[b,s]/1000 for s in sizes]\n plt.plot(sizes, bts, label=labels[b])\n plt.legend()\n\nplt.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Average improvement\n\nIn the next cell, we compute the geometric mean of improvment between the first and last versions. Of course, results may differ depending on platform (and the model, too) but the idea is, applying the above rules may yield a significant improvement", "apps": [], "results": {"msg": [{"data": "In the next cell, we compute the geometric mean of improvment between the first and last versions. Of course, results may differ depending on platform (and the model, too) but the idea is, applying the above rules may yield a significant improvement
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# compute geomerical mean for all sizes\nnb_builders = len(builders)\nratios = {}\nfor s in sizes:\n initial = res[0, s]\n final = res[nb_builders-1, s]\n r = (initial/final)\n ratios[s] = r\n\nimport math\nrgm = math.exp(sum(math.log(r) for r in ratios.values()) / float(nb_builders))\nprint(\"* geometric mean of time improvement is {0:.1f}\".format(rgm))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/green_truck.json b/examples/mp/zeppelin/green_truck.json deleted file mode 100644 index 1681121..0000000 --- a/examples/mp/zeppelin/green_truck.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\green_truck", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Use decision optimization to help a trucking company manage its shipments.\n\nThis tutorial includes everything you need to set up decision optimization engines, build mathematical programming models, and arrive at managing a truck fleet.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- The business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the Data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build mathematical programming models, and arrive at managing a truck fleet.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the Data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nWith prescriptive analytics, you can:
\n\nRun the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf *CPLEX* is not installed, install CPLEX Community edition.", "apps": [], "results": {"msg": [{"data": "If CPLEX is not installed, install CPLEX Community edition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import cplex\nexcept:\n raise Exception('Please install CPLEX. See https://pypi.org/project/cplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\nIn this scenario, the data is simple and is delivered in the json format under the Optimization github.", "apps": [], "results": {"msg": [{"data": "In this scenario, the data is simple and is delivered in the json format under the Optimization github.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom collections import namedtuple", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n_parameters = namedtuple('parameters', ['maxTrucks', 'maxVolume'])\n_location = namedtuple('location', ['name'])\n_spoke = namedtuple('spoke', ['name', 'minDepTime', 'maxArrTime'])\n_truckType = namedtuple('truckType', ['truckType', 'capacity', 'costPerMile', 'milesPerHour'])\n_loadTimeInfo = namedtuple('loadTimeInfo', ['hub', 'truckType', 'loadTime'])\n_routeInfo = namedtuple('routeInfo', ['spoke', 'hub', 'distance'])\n_triple = namedtuple('triple', ['origin', 'hub', 'destination'])\n_shipment = namedtuple('shipment', ['origin', 'destination', 'totalVolume'])\n\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport requests\nimport json\nimport decimal \nr = requests.get(\"https://github.com/vberaudi/utwt/blob/master/trucking.json?raw=true\")\njson_data = json.loads(r.text, parse_float=decimal.Decimal ) ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndef read_json_tuples(name, my_namedtuple):\n json_fragment = json_data[name]\n length = len(my_namedtuple._fields)\n ret = []\n for t in json_fragment:\n #print t\n ret2 = [0 for i in range(length)]\n for i in range(length):\n field = my_namedtuple._fields[i]\n ret2[i] = t[field]\n ret.append(my_namedtuple(*tuple(ret2)))\n return ret\n\ndef read_json_tuple(name, my_namedtuple):\n json_fragment = json_data[name]\n length = len(my_namedtuple._fields)\n ret = [0 for i in range(length)]\n for i in range(length):\n field = my_namedtuple._fields[i]\n ret[i] = json_fragment[field]\n return my_namedtuple(*tuple(ret))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nUse basic HTML and a stylesheet to format the data.", "apps": [], "results": {"msg": [{"data": "Use basic HTML and a stylesheet to format the data.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCSS = \"\"\"\nbody {\n margin: 0;\n font-family: Helvetica;\n}\ntable.dataframe {\n border-collapse: collapse;\n border: none;\n}\ntable.dataframe tr {\n border: none;\n}\ntable.dataframe td, table.dataframe th {\n margin: 0;\n border: 1px solid white;\n padding-left: 0.25em;\n padding-right: 0.25em;\n}\ntable.dataframe th:not(:empty) {\n background-color: #fec;\n text-align: left;\n font-weight: normal;\n}\ntable.dataframe tr:nth-child(2) th:empty {\n border-left: none;\n border-right: 1px dashed #888;\n}\ntable.dataframe td {\n border: 2px solid #ccf;\n background-color: #f4f4ff;\n}\n table.dataframe thead th:first-child {\n display: none;\n }\n table.dataframe tbody th {\n display: none;\n }\n\"\"\"\n\nfrom IPython.core.display import HTML\nHTML(''.format(CSS))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nparameters = read_json_tuple(name='Parameters', my_namedtuple=_parameters)\nhubs = read_json_tuples(name='Hubs', my_namedtuple=_location)\ntruckTypes = read_json_tuples(name='TruckTypes', my_namedtuple=_truckType)\nspokes = read_json_tuples(name='Spokes', my_namedtuple=_spoke)\nloadTimes = read_json_tuples(name='LoadTimes', my_namedtuple=_loadTimeInfo)\nroutes = read_json_tuples(name='Routes', my_namedtuple=_routeInfo)\nshipments = read_json_tuples(name='Shipments', my_namedtuple=_shipment)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data\n\nGiven the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week. \n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.", "apps": [], "results": {"msg": [{"data": "Given the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week.
\n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmaxTrucks = parameters.maxTrucks;\nmaxVolume = parameters.maxVolume;\n\nhubIds = {h.name for h in hubs}\n\nspokeIds = {s.name for s in spokes}\nspoke = {s.name : s for s in spokes}\n\ntruckTypeIds = {ttis.truckType for ttis in truckTypes}\ntruckTypeInfos = {tti.truckType : tti for tti in truckTypes}\n\nloadTime = {(lt.hub , lt.truckType) : lt.loadTime for lt in loadTimes}\n\n# feasible pathes from spokes to spokes via one hub\ntriples = {_triple(r1.spoke, r1.hub, r2.spoke) for r1 in routes for r2 in routes if (r1 != r2 and r1.hub == r2.hub)}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSome asserts to check the data follows the guidelines.", "apps": [], "results": {"msg": [{"data": "Some asserts to check the data follows the guidelines.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Make sure the data is consistent: latest arrive time >= earliest departure time\nfor s in spokeIds:\n assert spoke[s].maxArrTime > spoke[s].minDepTime, \"inconsistent data\"\n\n# The following assertion is to make sure that the spoke\n# in each route is indeed in the set of Spokes.\nfor r in routes:\n assert r.spoke in spokeIds, \"some route is not in the spokes\"\n\n# The following assertion is to make sure that the hub\n# in each route are indeed in the set of Hubs.\nfor r in routes:\n assert r.hub in hubIds, \"some route is not in the hubs\"\n\n# The following assertion is to make sure that the origin\n# of each shipment is indeed in the set of Spokes.\nfor s in shipments:\n assert s.origin in spokeIds, \"origin is not in the set of Spokes\"\n\n# The following assertion is to make sure that the destination\n# of each shipment is indeed in the set of Spokes.\nfor s in shipments:\n assert s.destination in spokeIds, \"shipment is not in the set of Spokes\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom math import ceil, floor\n# the earliest unloading time at a hub for each type of trucks\nearliestUnloadingTime = {(r, t) : int(ceil(loadTime[r.hub, t] + spoke[r.spoke].minDepTime + 60 * r.distance / truckTypeInfos[t].milesPerHour)) for t in truckTypeIds for r in routes}\n# the latest loading time at a hub for each type of trucks\nlatestLoadingTime = {(r, t) : int(floor(spoke[r.spoke].maxArrTime - loadTime[r.hub, t] - 60 * r.distance / truckTypeInfos[t].milesPerHour)) for t in truckTypeIds for r in routes}\n\n# Compute possible truck types that can be assigned on a route\n# A type of truck can be assigned on a route only if it can make it to the hub and back\n# before the max arrival time at the spoke.\npossibleTruckOnRoute = {(r, t) : 1 if earliestUnloadingTime[r, t] < latestLoadingTime[r, t] else 0 for t in truckTypeIds for r in routes}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmodel = Model(\"truck\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "In another words, the shipments for a truck must arrive at the hub from all spokes before the truck leaves.
\nThe constraint can be expressed as the following: For each route s-h and leaving truck of type t: Cumulated inbound volume arrived before the loading time of the truck >= Cumulated outbound volume upto the loading time of the truck(including the shipments being loaded).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor (s,h,dist) in routes:\n for t in truckTypeIds:\n model.add_constraint(\n # The expression below defines the indices of the trucks unloaded before truck t starts loading.\n model.sum(inVolumeThroughHubOnTruck[(o, h, s), t1]\n for (o,h0,s0) in triples if h0 == h and s0 == s\n for t1 in truckTypeIds\n for (o2,h2,dist1) in routes if h2 == h0 and o2 == o\n if earliestUnloadingTime[(o, h, dist1), t1] <= latestLoadingTime[(s, h, dist), t])\n >=\n # The expression below defines the indices of the trucks left before truck t starts loading.\n model.sum(outVolumeThroughHubOnTruck[(o, h, s), t2]\n for (o,h0,s0) in triples if h0 == h and s0 == s\n for t2 in truckTypeIds\n for (o2,h2,dist2) in routes if h2 == h0 and o2 == o\n if latestLoadingTime[(o, h, dist2), t2] <= latestLoadingTime[(s, h, dist), t])\n )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective", "apps": [], "results": {"msg": [{"data": "You will get the best solution found after n seconds, due to a time limit parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmodel.print_information()\n\nassert model.solve(), \"!!! Solve of the model fails\"\nmodel.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Investigate the solution and then run an example analysis", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/incremental_modeling.json b/examples/mp/zeppelin/incremental_modeling.json deleted file mode 100644 index 9368f6f..0000000 --- a/examples/mp/zeppelin/incremental_modeling.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\incremental_modeling", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Incremental modeling with decision optimization\n\nThis tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, then incrementally modify it.\nYou will learn how to:\n- change coefficients in an expression\n- add terms in an expression\n- modify constraints and variables bounds\n- remove/add constraints\n- play with relaxations\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n * Step 2: Set up the prescriptive model\n * Step 3: Modify the model\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, then incrementally modify it.
\nYou will learn how to:
\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n* Step 2: Set up the prescriptive model\n
\n* Step 3: Modify the model\n
\nA possible descriptive model of the telephone production problem is as follows:
\nObjective: Maximize profit
\nThis is a type of discrete optimization problem that can be solved by using either Integer Programming (IP) or Constraint Programming (CP).
\n\n\n\n\nInteger Programming is the class of problems defined as the optimization of a linear function, subject to linear constraints over integer variables.
\n
\n\n\nConstraint Programming problems generally have discrete decision variables, but the constraints can be logical, and the arithmetic expressions are not restricted to being linear.
\n
For the purposes of this tutorial, we will illustrate a solution with mathematical programming (MP).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\n* Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It takes into account specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \nWith prescriptive analytics, you can:
\n\nRun the following code to import Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nA restart of the kernel might be needed.", "apps": [], "results": {"msg": [{"data": "A restart of the kernel might be needed.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "maximize: 12 desk_production+20 cell_production\n\nsubject to: \n desk_production>=100 \n cell_production>=100 \n 0.2 desk_production+0.4 cell_production<=400 \n 0.5 desk_production+0.4 cell_production<=490\n
", "apps": [], "results": {"msg": [{"data": "Convert the descriptive model into a mathematical model:
\nTo express the last two constraints, we model assembly time and painting time as linear combinations of the two productions, resulting in the following mathematical model:
\n\nmaximize: 12 deskproduction+20 cellproduction
subject to:
\ndesk_production>=100
\ncell_production>=100
\n0.2 deskproduction+0.4 cellproduction<=400
\n0.5 deskproduction+0.4 cellproduction<=490
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# first import the Model class from docplex.mp\nfrom docplex.mp.model import Model\n\n# create one model instance, with a name\nm = Model(name='telephone_production')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe continuous variable desk represents the production of desk telephones.\nThe continuous variable cell represents the production of cell phones.", "apps": [], "results": {"msg": [{"data": "The continuous variable desk represents the production of desk telephones.
\nThe continuous variable cell represents the production of cell phones.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# by default, all variables in Docplex have a lower bound of 0 and infinite upper bound\ndesk = m.integer_var(name='desk')\ncell = m.integer_var(name='cell')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.maximize(12 * desk + 20 * cell)\n\n# write constraints\n# constraint #1: desk production is greater than 100\nm.add_constraint(desk >= 100, \"desk\")\n\n# constraint #2: cell production is greater than 100\nm.add_constraint(cell >= 100, \"cell\")\n\n# constraint #3: assembly time limit\nct_assembly = m.add_constraint( 0.2 * desk + 0.4 * cell <= 400, \"assembly_limit\")\n\n# constraint #4: paiting time limit\nct_painting = m.add_constraint( 0.5 * desk + 0.4 * cell <= 490, \"painting_limit\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization \n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.\n\nYou will get the best solution found after ***n*** seconds, thanks to a time limit parameter.", "apps": [], "results": {"msg": [{"data": "If you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n\nYou will get the best solution found after n seconds, thanks to a time limit parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.print_information()\nmsol = m.solve()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nassert msol is not None, \"model can't solve\"\nm.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Modify the model", "apps": [], "results": {"msg": [{"data": "The model object provides getters to retrieve variables and constraints by name:
\nThe variable and constraint objects both provide properties to access the right hand side (rhs) and left hand side (lhs).
\nWhen you modify a rhs or lhs of a variable, you of course need to give a number.
\nWhen you modify a rhs or lhs of a constraint, you can give a number or an expression based on variables.
\n\nLet's say we want to build 2000 cells and 1000 desks maximum.
\n\nAnd let's say we want to increase the production of both of them from 100 to 350
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Access by name\nm.get_var_by_name(\"desk\").ub = 2000\n# acess via the object\ncell.ub = 1000\n\n\nm.get_constraint_by_name(\"desk\").rhs = 350\nm.get_constraint_by_name(\"cell\").rhs = 350", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmsol = m.solve()\nassert msol is not None, \"model can't solve\"\nm.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe production plan has been updated accordingly to our small changes.", "apps": [], "results": {"msg": [{"data": "The production plan has been updated accordingly to our small changes.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Modify expressions", "apps": [], "results": {"msg": [{"data": "We now want to introduce a new type of product: the \"hybrid\" telephone.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nhybrid = m.integer_var(name='hybrid')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe need to:\n- introduce it in the objective\n- introduce it in the existing painting and assembly time constraints \n- add a new constraint for its production to produce at least 350 of them.", "apps": [], "results": {"msg": [{"data": "We need to:
\n\nmaximize: 12 desk_production+20 cell_production\n
\nto\n\nmaximize: 12 desk_production+20 cell_production + 10 hybrid_prodction\n
", "apps": [], "results": {"msg": [{"data": "The objective will move from
\nmaximize: 12 deskproduction+20 cellproduction
\n\nto
\nmaximize: 12 deskproduction+20 cellproduction + 10 hybrid_prodction
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.get_objective_expr().add_term(hybrid, 10);", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe time constraints will be updated from \n\n0.2 desk_production+0.4 cell_production<=400\n0.5 desk_production+0.4 cell_production<=490\n
\nto\n\n0.2 desk_production+0.4 cell_production + 0.2 hybrid_production<=400\n0.5 desk_production+0.4 cell_production + 0.2 hybrid_production<=490\n
", "apps": [], "results": {"msg": [{"data": "The time constraints will be updated from
\n0.2 deskproduction+0.4 cellproduction<=400
\n0.5 deskproduction+0.4 cellproduction<=490
\n\nto
\n0.2 deskproduction+0.4 cellproduction + 0.2 hybrid_production<=400
\n0.5 deskproduction+0.4 cellproduction + 0.2 hybrid_production<=490
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWhen you add a constraint to a model, its object is returned to you by the method add_constraint.\nIf you don't have it, you can access it via its name", "apps": [], "results": {"msg": [{"data": "When you add a constraint to a model, its object is returned to you by the method add_constraint.
\nIf you don't have it, you can access it via its name
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.get_constraint_by_name(\"assembly_limit\").lhs.add_term(hybrid, 0.2)\nct_painting.lhs.add_term(hybrid, 0.2);", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe can now compute the new production plan for our 3 products", "apps": [], "results": {"msg": [{"data": "We can now compute the new production plan for our 3 products
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmsol = m.solve()\nassert msol is not None, \"model can't solve\"\nm.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's now say we improved our painting process, the distribution of the coefficients in the painting limits is not [0.5, 0.4, 0.2] anymore but [0.1, 0.1, 0.1]\nWhen you have the hand on an expression, you can modify the coefficient variable by variable with set_coefficient or via a list of (variable, coeff) with set_coefficients", "apps": [], "results": {"msg": [{"data": "Let's now say we improved our painting process, the distribution of the coefficients in the painting limits is not [0.5, 0.4, 0.2] anymore but [0.1, 0.1, 0.1]
\nWhen you have the hand on an expression, you can modify the coefficient variable by variable with setcoefficient or via a list of (variable, coeff) with setcoefficients
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nct_painting.lhs.set_coefficients([(desk, 0.1), (cell, 0.1), (hybrid, 0.1)])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmsol = m.solve()\nassert msol is not None, \"model can't solve\"\nm.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Relaxations", "apps": [], "results": {"msg": [{"data": "Let's now introduce a new constraint: polishing time limit.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# constraint: polishing time limit\nct_polishing = m.add_constraint( 0.6 * desk + 0.6 * cell + 0.3 * hybrid <= 290, \"polishing_limit\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmsol = m.solve()\nif msol is None:\n print(\"model can't solve\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe model is now infeasible. We need to handle it and dig into the infeasibilities.", "apps": [], "results": {"msg": [{"data": "The model is now infeasible. We need to handle it and dig into the infeasibilities.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nYou can now use the Relaxer object. You can control the way it will relax the constraints or you can use 1 of the various automatic modes:\n- 'all' relaxes all constraints using a MEDIUM priority; this is the default.\n- 'named' relaxes all constraints with a user name but not the others.\n- 'match' looks for priority names within constraint names; unnamed constraints are not relaxed.\n\nWe will use the 'match' mode.\nPolishing constraint is mandatory.\nPainting constraint is a nice to have.\nAssembly constraint has low priority.", "apps": [], "results": {"msg": [{"data": "You can now use the Relaxer object. You can control the way it will relax the constraints or you can use 1 of the various automatic modes:
\nWe will use the 'match' mode.
\nPolishing constraint is mandatory.
\nPainting constraint is a nice to have.
\nAssembly constraint has low priority.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nct_polishing.name = \"high_\"+ct_polishing.name\nct_assembly.name = \"low_\"+ct_assembly.name\nct_painting.name = \"medium_\"+ct_painting.name", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# if a name contains \"low\", it has priority LOW\n# if a ct name contains \"medium\" it has priority MEDIUM\n# same for HIGH\n# if a constraint has no name or does not match any, it is not relaxable.\nfrom docplex.mp.relaxer import Relaxer\nrelaxer = Relaxer(prioritizer='match', verbose=True)\n\nrelaxed_sol = relaxer.relax(m)\nrelaxed_ok = relaxed_sol is not None\nassert relaxed_ok, \"relaxation failed\"\nrelaxer.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nct_polishing_relax = relaxer.get_relaxation(ct_polishing)\nprint(\"* found slack of {0} for polish ct\".format(ct_polishing_relax))\nct_polishing.rhs+= ct_polishing_relax\nm.solve()\nm.report()\nm.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and modify it in various ways.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and modify it in various ways.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com\"\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/lagrangian_relaxation.json b/examples/mp/zeppelin/lagrangian_relaxation.json deleted file mode 100644 index 1b601ca..0000000 --- a/examples/mp/zeppelin/lagrangian_relaxation.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\lagrangian_relaxation", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Solve a Generalized Assignment Problem using Lagrangian relaxation\n\nThis tutorial includes data and information that you need to set up decision optimization engines and build mathematical programming models to solve a Generalized Assignment Problem using Lagrangian relaxation.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\nSome familiarity with Python is recommended. This notebook runs on Python 2.", "apps": [], "results": {"msg": [{"data": "This tutorial includes data and information that you need to set up decision optimization engines and build mathematical programming models to solve a Generalized Assignment Problem using Lagrangian relaxation.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\nSome familiarity with Python is recommended. This notebook runs on Python 2.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Table of contents\n* Describe the business problem\n* How Decision Optimization can help\n* Use Decision Optimization to create and solve the model\n* Summary\n", "apps": [], "results": {"msg": [{"data": "This notebook illustrates how to solve an optimization model using Lagrangian relaxation technics.
\nIt solves a generalized assignment problem (GAP), as defined by Wolsey, using this relaxation technic.
\n\nThe main aim is to show multiple optimization through modifications of different models existing in a single environment, not to show how to solve a GAP problem.
\n\nIn the field of Mathematical Programming, this technic consists in the approximation of a difficult constrained problem by a simpler problem: you remove difficult constraints by integrating them in the objective function, penalizing it if the constraint is not respected.
\n\nThe method penalizes violations of inequality constraints using a Lagrange multiplier, which imposes a cost on violations. These added costs are used instead of the strict inequality constraints in the optimization. In practice, this relaxed problem can often be solved more easily than the original problem.
\n\nFor more information, see the following Wikipedia articles: Generalized assignment problem and Lagrangian relaxation.
\n\nThis notebook first solves the standard problem (which is not important here), then shows how to reformulate it to meet the Lagrangian Relaxation features.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\nPrescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It considers specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control over business outcomes.\n\nPrescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle a future situation. Organizations that act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage.\n\nWith prescriptive analytics, you can:\n\n* Automate the complex decisions and trade-offs to better manage your limited resources.\n \n* Take advantage of a future opportunity or mitigate a future risk.\n \n* Proactively update recommendations based on changing events.\n \n* Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n\n\n\n", "apps": [], "results": {"msg": [{"data": "Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It considers specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control over business outcomes.
\n\nPrescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle a future situation. Organizations that act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage.
\n\nWith prescriptive analytics, you can:
\n\nPerform the following steps to create and solve the model.
\n\n 3.1 Define the decision variables\n
\n 3.2 Express the business constraints\n
\n 3.3 Express the objective\n
\n 3.4 Solve the model\n
\n 3.5 Solve the model with Lagrangian Relaxation\n
\nRun the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains two modeling packages, mathematical programming (docplex.mp) package and constraint programming (docplex.cp) package.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf *CPLEX* is not installed, install CPLEX Community edition.", "apps": [], "results": {"msg": [{"data": "If CPLEX is not installed, install CPLEX Community edition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import cplex\nexcept:\n raise Exception('Please install CPLEX. See https://pypi.org/project/cplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### 2. Model the data\nIn this scenario, the data is simple. It is delivered as 3 input arrays: A, B, and C. The data does not need changing or refactoring.", "apps": [], "results": {"msg": [{"data": "In this scenario, the data is simple. It is delivered as 3 input arrays: A, B, and C. The data does not need changing or refactoring.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nB = [15, 15, 15]\nC = [\n [ 6, 10, 1],\n [12, 12, 5],\n [15, 4, 3],\n [10, 3, 9],\n [8, 9, 5]\n]\nA = [\n [ 5, 7, 2],\n [14, 8, 7],\n [10, 6, 12],\n [ 8, 4, 15],\n [ 6, 12, 5]\n]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### 3. Set up the prescriptive model\n\nStart with viewing the environment information. This information should be updated when you run the notebook.\n ", "apps": [], "results": {"msg": [{"data": "Start with viewing the environment information. This information should be updated when you run the notebook.
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.environment import Environment\nenv = Environment()\nenv.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe will firt create an optimization problem, composed of 2 basic constraints blocks, then we will resolve it using Lagrangian Relaxation on 1 of the constraints block.", "apps": [], "results": {"msg": [{"data": "We will firt create an optimization problem, composed of 2 basic constraints blocks, then we will resolve it using Lagrangian Relaxation on 1 of the constraints block.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### 3.1 Create the DOcplex model\nThe model contains the business constraints and the objective.\n", "apps": [], "results": {"msg": [{"data": "The model contains the business constraints and the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmdl = Model(\"GAP per Wolsey\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### 3.2 Define the decision variables", "apps": [], "results": {"msg": [{"data": "Use the Decision Optimization to solve the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ns = mdl.solve()\nassert s is not None\nobj = s.objective_value\nprint(\"* GAP with no relaxation run OK, best objective is: {:g}\".format(obj))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### 3.5. Solve the model with Lagrangian Relaxation method\n\nLet's consider for the demonstration of the Lagrangian Relaxation that this model was hard to solve for CPLEX.\nWe will approximate this problem by doing an iterative model, where the objective is modified at each iteration. \n\n(Wait a few seconds for the solution, due to a time limit parameter.)", "apps": [], "results": {"msg": [{"data": "Let's consider for the demonstration of the Lagrangian Relaxation that this model was hard to solve for CPLEX.
\nWe will approximate this problem by doing an iterative model, where the objective is modified at each iteration.
\n\n(Wait a few seconds for the solution, due to a time limit parameter.)
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe first remove the culprit constraints from the model", "apps": [], "results": {"msg": [{"data": "We first remove the culprit constraints from the model
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor ct in cts:\n mdl.remove_constraint(ct)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n#p_vars are the penalties attached to violating the constraints\np_vars = mdl.continuous_var_list(C, name='p') # new for relaxation", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# new version of the approximated constraint where we apply the penalties\nmdl.add_constraints(mdl.sum(xv) == 1 - pv for xv, pv in zip(x_vars, p_vars));", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n#Define the maximum number of iterations\nmax_iters = 10", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnumber_of_cs = len(C)\nc_range = range(number_of_cs)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Langrangian relaxation loop \neps = 1e-6\nloop_count = 0\nbest = 0\ninitial_multiplier = 1\nmultipliers = [initial_multiplier] * len(C)\n\n# Objective function\n# I'd write the key perfromance indicator (kpi) as\n# total_profit = mdl.sum(mdl.sum(x_vars[task][worker] * C[task][worker]) for task, worker in zip(tasks, workers))\ntotal_profit = mdl.sum(mdl.scal_prod(x_i, c_i) for c_i, x_i in zip(C, x_vars))\nmdl.add_kpi(total_profit, \"Total profit\")\nprint(\"starting the loop\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nwhile loop_count <= max_iters:\n loop_count += 1\n # Rebuilt at each loop iteration\n total_penalty = mdl.scal_prod(p_vars, multipliers)\n mdl.maximize(total_profit + total_penalty)\n s = mdl.solve()\n if not s:\n print(\"*** solve fails, stopping at iteration: %d\" % loop_count)\n break\n best = s.objective_value\n penalties = [pv.solution_value for pv in p_vars]\n print('%d> new lagrangian iteration:\\n\\t obj=%g, m=%s, p=%s' % (loop_count, best, str(multipliers), str(penalties)))\n do_stop = True\n justifier = 0\n for k in c_range:\n penalized_violation = penalties[k] * multipliers[k]\n if penalized_violation >= eps:\n do_stop = False\n justifier = penalized_violation\n break\n if do_stop:\n print(\"* Lagrangian relaxation succeeds, best={:g}, penalty={:g}, #iterations={}\"\n .format(best, total_penalty.solution_value, loop_count))\n break\n else:\n # Update multipliers and start the loop again.\n scale_factor = 1.0 / float(loop_count)\n multipliers = [max(multipliers[i] - scale_factor * penalties[i], 0.) for i in c_range]\n print('{0}> -- loop continues, m={1!s}, justifier={2:g}'.format(loop_count, multipliers, justifier))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nprint(best)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### 4. Investigate the solution and run an example analysis", "apps": [], "results": {"msg": [{"data": "You can see that with this relaxation method applied to this simple model, we find the same solution to the problem.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on Cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* [Decision Optimization documentation](https://datascience.ibm.com/docs/content/DO/DOinDSX.html)\n* For help with DOcplex, or to report a defect, go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com\n", "apps": [], "results": {"msg": [{"data": "Copyright © IBM Corp. 2017-2018. Released as licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/lifegame.json b/examples/mp/zeppelin/lifegame.json deleted file mode 100644 index 47dd4b8..0000000 --- a/examples/mp/zeppelin/lifegame.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\lifegame", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Using logical constraints: Conway's Game of Life\n\nThis tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, leveraging logical constraints.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\nThis model is greater than the size allowed in trial mode of CPLEX.\n>It requires a **local installation of CPLEX Optimizers**. \n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n * Step 2: Set up the prescriptive model\n * Step 3: Solve the problem with default CPLEX algorithm\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, leveraging logical constraints.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
This model is greater than the size allowed in trial mode of CPLEX.
\n\n\n\nIt requires a local installation of CPLEX Optimizers.
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n* Step 2: Set up the prescriptive model\n
\n* Step 3: Solve the problem with default CPLEX algorithm\n
\nThis example is demonstrating Life Game from Robert Bosch and Michael Trick, CP 2001, CPAIOR 2002. using CPLEX
\n\nThe original paper can be found here
\nIt is based on Conway's Game of Life and is a basic integer program with birth constraints.
\n\nTo begin the game, the player places checkers on some of the cells of the board, creating an initial pattern.
\nA cell with a checker in it is living and those without are dead.
\nThe pattern is then modified by applying the following rules over ad over abain.
\nWith prescriptive analytics, you can:
\n\nRun the following code to import Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\niimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nA restart of the kernel might be needed if you updated docplex.", "apps": [], "results": {"msg": [{"data": "A restart of the kernel might be needed if you updated docplex.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The sum of alive neighbors for an alive cell is greater than 2
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor i in inside:\n for j in inside:\n lm.add(2 * life[i, j] <= sum_of_neighbors[i, j])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe sum of alive neighbors for an alive cell is less than 3", "apps": [], "results": {"msg": [{"data": "The sum of alive neighbors for an alive cell is less than 3
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor i in inside:\n for j in inside:\n lm.add(5 * life[i, j] + sum_of_neighbors[i, j] <= 8)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFor a dead cell, the sum of alive neighbors cannot be 3", "apps": [], "results": {"msg": [{"data": "For a dead cell, the sum of alive neighbors cannot be 3
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor i in inside:\n for j in inside:\n ct3 = sum_of_neighbors[i, j] == 3\n lm.add(ct3 <= life[i, j]) # use logical cts here", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSatisfy the 'no 3 alive neighbors for extreme rows, columns", "apps": [], "results": {"msg": [{"data": "Satisfy the 'no 3 alive neighbors for extreme rows, columns
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor i in border:\n if i < n:\n for d in [1, n]:\n lm.add(life[i, d] + life[i + 1, d] + life[i + 2, d] <= 2)\n lm.add(life[d, i] + life[d, i + 1] + life[d, i + 2] <= 2)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSymmetry breaking", "apps": [], "results": {"msg": [{"data": "Symmetry breaking
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nn2 = int(math.ceil(n/2))\nhalf1 = range(1, n2 + 1)\nhalf2 = range(n2 + 1, n)\n\n# there are more alive cells in left side\nlm.add(lm.sum(life[i1, j1] for i1 in half1 for j1 in inside) >= lm.sum(life[i2, j2] for i2 in half2 for j2 in inside))\n\n# there are more alive cells in upper side\nlm.add(lm.sum(life[i1, j1] for i1 in inside for j1 in half1) >= lm.sum(life[i2, j2] for i2 in inside for j2 in half2))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nSetting up the objective: find maximum number of alive cells", "apps": [], "results": {"msg": [{"data": "Setting up the objective: find maximum number of alive cells
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nlm.maximize(lm.sum(life))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# add a dummy kpi\nnlines = lm.sum( (lm.sum(life[i,j] for j in inside) >= 1) for i in inside)\nlm.add_kpi(nlines, 'nlines')\n\n# parameters: branch up, use heusristics, emphasis on opt, threads free\nlm.parameters.mip.strategy.branch = 1\nlm.parameters.mip.strategy.heuristicfreq = 10\nlm.parameters.emphasis.mip = 2\nlm.parameters.threads = 0", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# store data items as fields\nlm.size = n\nlm.life = life\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nborder3 = range(1, lm.size-1, 3)\nlife_vars = lm.life\nvvmap = {}\nfor i in border3:\n for j in border3:\n vvmap[life_vars[i, j]] = 1\n vvmap[life_vars[i+1, j]] = 1\n vvmap[life_vars[i, j+1]] = 1\n vvmap[life_vars[i+1, j+1]] = 1\n\nini_s = lm.new_solution(var_value_dict=vvmap)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nassert ini_s.check(), 'error in initial solution'", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nlm.add_mip_start(ini_s)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Solve the problem with default CPLEX algorithm", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model with logical constraints.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com\"\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/load_balancing.json b/examples/mp/zeppelin/load_balancing.json deleted file mode 100644 index 3726683..0000000 --- a/examples/mp/zeppelin/load_balancing.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\load_balancing", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Use decision optimization to determine Cloud balancing.\n\nThis tutorial includes everything you need to set up decision optimization engines, build mathematical programming models, and a solve a capacitated facility location problem to do server load balancing.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- The business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the Data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build mathematical programming models, and a solve a capacitated facility location problem to do server load balancing.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the Data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nWith prescriptive analytics, you can:
\n\nRun the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\nIn this scenario, the data is simple and is delivered in the json format under the Optimization github.", "apps": [], "results": {"msg": [{"data": "In this scenario, the data is simple and is delivered in the json format under the Optimization github.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom collections import namedtuple", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nclass TUser(namedtuple(\"TUser\", [\"id\", \"running\", \"sleeping\", \"current_server\"])):\n def __str__(self):\n return self.id", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n from StringIO import StringIO\nexcept ImportError:\n from io import StringIO", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n from urllib2 import urlopen\nexcept ImportError:\n from urllib.request import urlopen", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport csv\n\ndata_url = \"https://github.com/vberaudi/utwt/blob/master/users.csv?raw=true\"\nxld = urlopen(data_url).read()\nxlds = StringIO(xld.decode('utf-8'))\nreader = csv.reader(xlds)\n\nusers = [(row[0], int(row[1]), int(row[2]), row[3]) for row in reader]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data\n\nGiven the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week. \n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.", "apps": [], "results": {"msg": [{"data": "Given the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week.
\n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmax_processes_per_server = 50\n\nusers = [TUser(*user_row) for user_row in users]\n\n\nservers = list({t.current_server for t in users})", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmdl = Model(\"truck\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "You will get the best solution found after n seconds, due to a time limit parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# build an ordered sequence of goals\nordered_kpi_keywords = [\"servers\", \"migrations\", \"sleeping\"]\nordered_goals = [mdl.kpi_by_name(k) for k in ordered_kpi_keywords]\n\nmdl.solve_lexicographic(ordered_goals)\nmdl.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Investigate the solution and then run an example analysis", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/logical_cts.json b/examples/mp/zeppelin/logical_cts.json deleted file mode 100644 index 92b3237..0000000 --- a/examples/mp/zeppelin/logical_cts.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\logical_cts", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Use logical constraints with decision optimization\n\nThis tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, leveraging logical constraints.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the **[Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)**\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n * Step 2: Learn about constraint truth values\n * Step 3: Learn about equivalence constraints\n* Summary\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build a mathematical programming model, leveraging logical constraints.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n* Step 2: Learn about constraint truth values\n
\n* Step 3: Learn about equivalence constraints\n
\nLogical constraints let you use the truth value of constraints inside the model. The truth value of a constraint
\nis true when it is satisfied and false when not. Adding a constraint to a model ensures that it is always satisfied.
\nHowever, with logical constraints, one can use the truth value of a constraint inside the model, allowing to choose dynamically whether a constraint is to be satisfied (or not).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\n* Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It takes into account specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \nWith prescriptive analytics, you can:
\n\nRun the following code to import Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nA restart of the kernel might be needed.", "apps": [], "results": {"msg": [{"data": "A restart of the kernel might be needed.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Learn about constraint truth values\n\nAny discrete linear constraint can be associated to a binary variable that holds the truth value of the constraint. \nBut first, let's explain what a discrete constraint is", "apps": [], "results": {"msg": [{"data": "Any discrete linear constraint can be associated to a binary variable that holds the truth value of the constraint.
\nBut first, let's explain what a discrete constraint is
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Discrete linear constraint\n\nA discrete linear constraint is built from discrete coefficients and discrete variables, taht is variables with type `integer` or `binary`. For example, assuming x and y are integer variables:\n\n - `2x+3y == 1` is discrete\n - `x+y = 3.14` is not (because of 3.14)\n - `1.1 x + 2.2 y <= 3` is not because of the non-integer coefficients 1.1 and 2.2", "apps": [], "results": {"msg": [{"data": "A discrete linear constraint is built from discrete coefficients and discrete variables, taht is variables with type integer
or binary
. For example, assuming x and y are integer variables:
2x+3y == 1
is discretex+y = 3.14
is not (because of 3.14)1.1 x + 2.2 y <= 3
is not because of the non-integer coefficients 1.1 and 2.2The truth value of a constraint is accessed by the status_var
property. This varianle is aplain Docplex decision variable that can be used anywhere a variable can. However, the value of the truth value variable and the constraint are linked, both ways:
In this toy model,we show that the truth value of a constraint which has been added to a model is always equal to 1.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nm1 = Model()\nx = m1.integer_var(name='ix')\ny = m1.integer_var(name='iy')\nct = m1.add(x + y <= 3)\nct_truth = ct.status_var\nm1.maximize(x+y)\nassert m1.solve()\nprint('the truth value of [{0!s}] is {1}'.format(ct, ct_truth.solution_value))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### The truth value of a constraint not added to a model is undefined\n\nA constraint that is not added to a model, has no effect. Its truth value is undefined: it can be either 1 or 0.\n\nIn the following example, both `x` and `y` are set to their upper bound, so that the constraint is not satisfied; hence the truth value is 0.", "apps": [], "results": {"msg": [{"data": "A constraint that is not added to a model, has no effect. Its truth value is undefined: it can be either 1 or 0.
\n\nIn the following example, both x
and y
are set to their upper bound, so that the constraint is not satisfied; hence the truth value is 0.
A constraint's truth value is actually a plain DOcplex decision variable, and as such, can be used with comparison operators and arithmetic operators.
\nLet's experiment again with a toy model: in this model,
\nwe state that the truth value of y == 4
is less than the truth value of x ==3
.
As we maximize y, y has value 4 in the optimal solution (it is the upper bound), and consequently the constraint ct_y4
is satisfied. From the inequality between truth values,
it follows that the truth value of ct_x2
equals 1 and x is equal to 2.
Using the constraints in the inequality has silently converted each constraint into its truth value.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm3 = Model()\nx = m3.integer_var(name='ix', ub=4)\ny = m3.integer_var(name='iy', ub=4)\nct_x2 = (x == 2)\nct_y4 = (y == 4)\nm3.add( ct_y4 <= ct_x2 )\nm3.maximize(y)\nassert m3.solve()\nm3.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nConstraint truth values can be used with arithmetic operators, just as variables can. In th enext model, we express a more complex constraint:\n- either x is equal to 3, _or_ both y and z are equal to 5\n\nLet's see how we can express this easilty with truth values:", "apps": [], "results": {"msg": [{"data": "Constraint truth values can be used with arithmetic operators, just as variables can. In th enext model, we express a more complex constraint:
\nLet's see how we can express this easilty with truth values:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm31 = Model(name='m31')\nx = m31.integer_var(name='ix', ub=4)\ny = m31.integer_var(name='iy', ub=10)\nz = m31.integer_var(name='iz', ub=10)\nct_x2 = (x == 3)\nct_y5 = (y == 5)\nct_z5 = (z == 5)\n#either ct-x2 is true or -both- ct_y5 and ct_z5 mus be true\nm31.add( 2 * ct_x2 + (ct_y5 + ct_z5) == 2)\n# force x to be less than 2: it cannot be equal to 3!\nm31.add(x <= 2)\n# maximize sum of x,y,z\nm31.maximize(x+y+z)\nassert m31.solve()\n# the expected solution is: x=2, y=5, z=5\nassert m31.objective_value == 12\nm31.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAs we have seen, constraints can be used in expressions. This includes the `Model.sum()` and `Model.dot()` aggregation methods.\n\nIn the next model, we define ten variables, one of which must be equal to 3 (we dpn't care which one, for now). As we maximize the sum of all `xs` variables, all will end up equal to their upper bound, except for one.", "apps": [], "results": {"msg": [{"data": "As we have seen, constraints can be used in expressions. This includes the Model.sum()
and Model.dot()
aggregation methods.
In the next model, we define ten variables, one of which must be equal to 3 (we dpn't care which one, for now). As we maximize the sum of all xs
variables, all will end up equal to their upper bound, except for one.
As we can see, all variables but one are set to their upper bound of 100. We cannot predict which variable will be set to 3.
\nHowever, let's imagine that we prefer variable with a lower index to be set to 3, how can we express this preference?
\n\nThe answer is to use an additional expression to the objective, using a scalar product of constraint truth value
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\npreference = m4.dot(cts, (k+1 for k in range(len(xs))))\n# we prefer lower indices for satisfying the x==3 constraint\n# so the final objective is a maximize of sum of xs -minus- the preference\nm4.maximize(m4.sum(xs) - preference)\nassert m4.solve()\nm4.print_solution()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAs expected, the `x` variable set to 3 now is the first one.", "apps": [], "results": {"msg": [{"data": "As expected, the x
variable set to 3 now is the first one.
Truth values can be used to express elegantly 'not equal' constraints, by forcing the truth value of an equality constraint to 0.
\n\nIn the next model, we illustrate how an equality constraint can be negated by forcing its truth value to zero. This negation forbids y to be equal to 4, as it would be without this negation.
\nFinally, the objective is 7 instead of 8.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nm5 = Model()\nx = m5.integer_var(name='ix', ub=4)\ny = m5.integer_var(name='iy', ub=4)\n# this is the equality constraint we want to negate\nct_y4 = (y == 4)\n# forcing truth value to zero means the constraint is not satisfied.\nnegation = m5.add( ct_y4 == 0)\n# maximize x+y should yield both variables to 4, but y cannot be equal to 4\n# as such we expect y to be equal to 3\nm5.maximize(x + y)\nassert m5.solve()\nm5.print_solution()\n# expecting 7 as objective, not 8\nassert m5.objective_value == 7\n\n# now remove the negation\nm5.remove_constraint(negation)\n# and solve again\nassert m5.solve()\n# the objective is 8 as expected: both x and y are equal to 4\nassert m5.objective_value == 8", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Summary\n\nWe have seen that linear constraints have an associated binary variable, its _truth value_, whose value is linked to whether or not the constraint is satisfied. \nMoreover, this llink enables to express 'not equals' constraints.# now remove netation", "apps": [], "results": {"msg": [{"data": "We have seen that linear constraints have an associated binary variable, its truth value, whose value is linked to whether or not the constraint is satisfied.
\nMoreover, this llink enables to express 'not equals' constraints.# now remove netation
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Learn about equivalence constraints\n\nAs we have seen, using a constraint in expressions automtically generates a truth value variable, whose value is linked to the status of the constraint. \n\nHowever, in some cases, it can be useful to relate the status of a constraint to an _existing_ binary variable. This is the purpose of equivalence constraints.\n\nAn equiavelnec constraints relates an existing binary variable to the status of a discrete linear constraints. The syntax is:\n\n `Model.add_equivalence(bvar, linear_ct, active_value, name)`\n \n - `bvar` is the existing binary variable\n - `linear-ct` is a discrete linear constraint\n - `active_value` can take values 1 or 0 (the default is 1)\n - `name` is an optional string to name the equivalence.", "apps": [], "results": {"msg": [{"data": "As we have seen, using a constraint in expressions automtically generates a truth value variable, whose value is linked to the status of the constraint.
\n\nHowever, in some cases, it can be useful to relate the status of a constraint to an existing binary variable. This is the purpose of equivalence constraints.
\n\nAn equiavelnec constraints relates an existing binary variable to the status of a discrete linear constraints. The syntax is:
\n\n`Model.add_equivalence(bvar, linear_ct, active_value, name)`\n
\n\nbvar
is the existing binary variablelinear-ct
is a discrete linear constraintactive_value
can take values 1 or 0 (the default is 1)name
is an optional string to name the equivalence.You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model with logical constraints.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud)\n* Contact us at dofeedback@wwpdl.vnet.ibm.com\"\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/marketing_campaign.json b/examples/mp/zeppelin/marketing_campaign.json deleted file mode 100644 index 35c2cb1..0000000 --- a/examples/mp/zeppelin/marketing_campaign.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\marketing_campaign", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# How to make targeted offers to customers?\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>Running the sample requires the installation of\n [CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n (Commercial or free \n [CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n This sample automatically installs *CPLEX CE* if needed.\n\nDiscover us [here](https://developer.ibm.com/docloud).\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Prepare the data\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Set up the prescriptive model\n * Define the decision variables\n * Set up the constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 3: Analyze the solution and run an example analysis\n", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python.
\n
\n\nRunning the sample requires the installation of
\n
[CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n
\n(Commercial or free\n
\n[CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n
\nThis sample automatically installs *CPLEX CE* if needed.\n
\n\nDiscover us here.
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Set up the constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 3: Analyze the solution and run an example analysis\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Describe the business problem\n* The Self-Learning Response Model (SLRM) node enables you to build a model that you can continually update. Such updates are useful in building a model that assists with predicting which offers are most appropriate for customers and the probability of the offers being accepted. These sorts of models are most beneficial in customer relationship management, such as marketing applications or call centers.\n* This example is based on a fictional banking company. \n* The marketing department wants to achieve more profitable results in future campaigns by matching the right offer of financial services to each customer. \n* Specifically, the datascience department identified the characteristics of customers who are most likely to respond favorably based on previous offers and responses and to promote the best current offer based on the results and now need to compute the best offerig plan.\nA set of business constraints have to be respected:
\n\n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Prepare the data\n\nThe predictions show which offers a customer is most likely to accept, and the confidence that they will accept, depending on each customer\u2019s details.\n\nFor example:\n(139987, \"Pension\", 0.13221, \"Mortgage\", 0.10675) indicates that customer Id=139987 will certainly not buy a _Pension_ as the level is only 13.2%, \nwhereas\n(140030, \"Savings\", 0.95678, \"Pension\", 0.84446) is more than likely to buy _Savings_ and a _Pension_ as the rates are 95.7% and 84.4%.\n\nThis data is taken from a SPSS example, except that the names of the customers were modified.\n\nA Python data analysis library, [pandas](http://pandas.pydata.org), is used to store the data. Let's set up and declare the data.", "apps": [], "results": {"msg": [{"data": "The predictions show which offers a customer is most likely to accept, and the confidence that they will accept, depending on each customer\u2019s details.
\n\nFor example:
\n(139987, \"Pension\", 0.13221, \"Mortgage\", 0.10675) indicates that customer Id=139987 will certainly not buy a Pension as the level is only 13.2%,
\nwhereas
\n(140030, \"Savings\", 0.95678, \"Pension\", 0.84446) is more than likely to buy Savings and a Pension as the rates are 95.7% and 84.4%.
\n\nThis data is taken from a SPSS example, except that the names of the customers were modified.
\n\nA Python data analysis library, pandas, is used to store the data. Let's set up and declare the data.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pandas as pd\n\nnames = {\n 139987 : \"Guadalupe J. Martinez\", 140030 : \"Michelle M. Lopez\", 140089 : \"Terry L. Ridgley\", \n 140097 : \"Miranda B. Roush\", 139068 : \"Sandra J. Wynkoop\", 139154 : \"Roland Gu\u00e9rette\", 139158 : \"Fabien Mailhot\", \n 139169 : \"Christian Austerlitz\", 139220 : \"Steffen Meister\", 139261 : \"Wolfgang Sanger\",\n 139416 : \"Lee Tsou\", 139422 : \"Sanaa' Hikmah Hakimi\", 139532 : \"Miroslav \u0160karoupka\", \n 139549 : \"George Blomqvist\", 139560 : \"Will Henderson\", 139577 : \"Yuina Ohira\", 139580 : \"Vlad Alekseeva\", \n 139636 : \"Cassio Lombardo\", 139647 : \"Trinity Zelaya Miramontes\", 139649 : \"Eldar Muravyov\", 139665 : \"Shu T'an\", \n 139667 : \"Jameel Abdul-Ghani Gerges\", 139696 : \"Zeeb Longoria Marrero\", 139752 : \"Matheus Azevedo Melo\", \n 139832 : \"Earl B. Wood\", 139859 : \"Gabrielly Sousa Martins\", 139881 : \"Franca Palermo\"}\n\n\ndata = [(139987, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (140030, \"Savings\", 0.95678, \"Pension\", 0.84446), (140089, \"Savings\", 0.95678, \"Pension\", 0.80233), \n (140097, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (139068, \"Pension\", 0.80506, \"Savings\", 0.28391), (139154, \"Pension\", 0.13221, \"Mortgage\", 0.10675), \n (139158, \"Pension\", 0.13221, \"Mortgage\", 0.10675),(139169, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (139220, \"Pension\", 0.13221, \"Mortgage\", 0.10675), \n (139261, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (139416, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (139422, \"Pension\", 0.13221, \"Mortgage\", 0.10675), \n (139532, \"Savings\", 0.95676, \"Mortgage\", 0.82269), (139549, \"Savings\", 0.16428, \"Pension\", 0.13221), (139560, \"Savings\", 0.95678, \"Pension\", 0.86779), \n (139577, \"Pension\", 0.13225, \"Mortgage\", 0.10675), (139580, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (139636, \"Pension\", 0.13221, \"Mortgage\", 0.10675), \n (139647, \"Savings\", 0.28934, \"Pension\", 0.13221), (139649, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (139665, \"Savings\", 0.95675, \"Pension\", 0.27248), \n (139667, \"Pension\", 0.13221, \"Mortgage\", 0.10675), (139696, \"Savings\", 0.16188, \"Pension\", 0.13221), (139752, \"Pension\", 0.13221, \"Mortgage\", 0.10675), \n (139832, \"Savings\", 0.95678, \"Pension\", 0.83426), (139859, \"Savings\", 0.95678, \"Pension\", 0.75925), (139881, \"Pension\", 0.13221, \"Mortgage\", 0.10675)]\n\nproducts = [\"Car loan\", \"Savings\", \"Mortgage\", \"Pension\"]\nproductValue = [100, 200, 300, 400]\nbudgetShare = [0.6, 0.1, 0.2, 0.1]\n\navailableBudget = 500\nchannels = pd.DataFrame(data=[(\"gift\", 20.0, 0.20), (\"newsletter\", 15.0, 0.05), (\"seminar\", 23.0, 0.30)], columns=[\"name\", \"cost\", \"factor\"])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nOffers are stored in a [pandas DataFrame](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html).", "apps": [], "results": {"msg": [{"data": "Offers are stored in a pandas DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry: # Python 2\n offers = pd.DataFrame(data=data, index=xrange(0, len(data)), columns=[\"customerid\", \"Product1\", \"Confidence1\", \"Product2\", \"Confidence2\"])\nexcept: # Python 3\n offers = pd.DataFrame(data=data, index=range(0, len(data)), columns=[\"customerid\", \"Product1\", \"Confidence1\", \"Product2\", \"Confidence2\"])\n\noffers.insert(0,'name',pd.Series(names[i[0]] for i in data))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's customize the display of this data and show the confidence forecast for each customer.", "apps": [], "results": {"msg": [{"data": "Let's customize the display of this data and show the confidence forecast for each customer.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCSS = \"\"\"\nbody {\n margin: 0;\n font-family: Helvetica;\n}\ntable.dataframe {\n border-collapse: collapse;\n border: none;\n}\ntable.dataframe tr {\n border: none;\n}\ntable.dataframe td, table.dataframe th {\n margin: 0;\n border: 1px solid white;\n padding-left: 0.25em;\n padding-right: 0.25em;\n}\ntable.dataframe th:not(:empty) {\n background-color: #fec;\n text-align: left;\n font-weight: normal;\n}\ntable.dataframe tr:nth-child(2) th:empty {\n border-left: none;\n border-right: 1px dashed #888;\n}\ntable.dataframe td {\n border: 2px solid #ccf;\n background-color: #f4f4ff;\n}\n table.dataframe thead th:first-child {\n display: none;\n }\n table.dataframe tbody th {\n display: none;\n }\n\"\"\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom IPython.core.display import HTML\nHTML(''.format(CSS))\n\nfrom IPython.display import display\ntry: \n display(offers.drop('customerid',1).sort_values(by='name')) #Pandas >= 0.17\nexcept:\n display(offers.drop('customerid',1).sort('name')) #Pandas < 0.17", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use IBM Decision Optimization CPLEX Modeling for Python\n\nLet's create the optimization model to select the best ways to contact customers and stay within the limited budget.", "apps": [], "results": {"msg": [{"data": "Let's create the optimization model to select the best ways to contact customers and stay within the limited budget.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 1: Import the library\n\nRun the following code to import the Decision Optimization CPLEX Modeling library. The *DOcplex* library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).", "apps": [], "results": {"msg": [{"data": "Run the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf *cplex* is not installed, install CPLEX Community edition.", "apps": [], "results": {"msg": [{"data": "If cplex is not installed, install CPLEX Community edition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import cplex\nexcept:\n raise Exception('Please install CPLEX. See https://pypi.org/project/cplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive model\n#### Create the model", "apps": [], "results": {"msg": [{"data": "channelVars
, represent whether or not a customer will be made an offer for a particular product via a particular channel.totaloffers
represents the total number of offers made.budgetSpent
represents the total cost of the offers made.We want to maximize the expected revenue.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.maximize(\n mdl.sum( channelVars[idx,p,idx2] * c.factor * productValue[p]* o.Confidence1 \n for p in productsR \n for idx,o in offers[offers['Product1'] == products[p]].iterrows() \n for idx2, c in channels.iterrows())\n +\n mdl.sum( channelVars[idx,p,idx2] * c.factor * productValue[p]* o.Confidence2 \n for p in productsR \n for idx,o in offers[offers['Product2'] == products[p]].iterrows() \n for idx2, c in channels.iterrows())\n )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve the model\n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.", "apps": [], "results": {"msg": [{"data": "If you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ns = mdl.solve()\nassert s, \"No Solution !!!\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Analyze the solution\n\nFirst, let's display the **Optimal Marketing Channel per customer**.", "apps": [], "results": {"msg": [{"data": "First, let's display the Optimal Marketing Channel per customer.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nreport = [(channels.get_value(index=c, col=\"name\"), products[p], names[offers.get_value(o, \"customerid\")]) \n for c in channelsR \n for p in productsR \n for o in offersR if channelVars[o,p,c].solution_value==1]\n\nassert len(report) == totaloffers.solution_value\n\nprint(\"Marketing plan has {0} offers costing {1}\".format(totaloffers.solution_value, budgetSpent.solution_value))\n\nreport_bd = pd.DataFrame(report, columns=['channel', 'product', 'customer'])\ndisplay(report_bd)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\nThen let's **focus on seminar**.", "apps": [], "results": {"msg": [{"data": "\nThen let's focus on seminar.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndisplay(report_bd[report_bd['channel'] == \"seminar\"].drop('channel',1))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n\n## Summary\n\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.\n", "apps": [], "results": {"msg": [{"data": "\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/mining_pandas.json b/examples/mp/zeppelin/mining_pandas.json deleted file mode 100644 index b797753..0000000 --- a/examples/mp/zeppelin/mining_pandas.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\mining_pandas", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Optimizing mining operations\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on Cloud with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>Running the sample requires the installation of\n [CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n (Commercial or free \n [CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n This sample automatically installs *CPLEX CE* if needed.\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on Cloud with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\nRunning the sample requires the installation of
\n
[CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n
\n(Commercial or free\n
\n[CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n
\nThis sample automatically installs *CPLEX CE* if needed.\n
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nThis mining operations optimization problem is an implementation of Problem 7 from \"Model Building in Mathematical Programming\" by
\nH.P. Williams.
\nThe operational decisions that need to be made are which mines should be operated each year and
\nhow much each mine should produce.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Business constraints\n\n * A mine that is closed cannot be worked.\n * Once closed, a mine stays closed until the end of the horizon.\n * Each year, a maximum number of mines can be worked.\n * For each mine and year, the quantity extracted is limited by the mine's maximum extracted quantity.\n * The average blend quality must be greater than or equal to the requirement of the year.\n \n### Objective and KPIs\n\n#### Total actualized revenue\n\nEach year, the total revenue is equal to the total quantity extracted multiplied by the blend price. The time series of revenues is aggregated in one expected revenue by applying the discount rate; in other terms, a revenue of \\$1000 next year is counted as \\$900 actualized, \\$810 if the revenue is expected in two years, etc.\n\n#### Total expected royalties\n\nA mine that stays open must pay royalties (see the column **royalties** in the DataFrame). Again, royalties from different years are actualized using the discount rate.\n\n#### Business objective\n\nThe business objective is to maximize the net actualized profit, that is the difference between the total actualized revenue and total actualized royalties.", "apps": [], "results": {"msg": [{"data": "Each year, the total revenue is equal to the total quantity extracted multiplied by the blend price. The time series of revenues is aggregated in one expected revenue by applying the discount rate; in other terms, a revenue of \\$1000 next year is counted as \\$900 actualized, \\$810 if the revenue is expected in two years, etc.
\n\nA mine that stays open must pay royalties (see the column royalties in the DataFrame). Again, royalties from different years are actualized using the discount rate.
\n\nThe business objective is to maximize the net actualized profit, that is the difference between the total actualized revenue and total actualized royalties.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\n* Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It takes into account specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \nWith prescriptive analytics, you can:
\n\nThis notebook uses some features of pandas that are available in version 0.17.1 or above.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pip\nREQUIRED_MINIMUM_PANDAS_VERSION = '0.17.1'\ntry:\n import pandas as pd\n assert pd.__version__ >= REQUIRED_MINIMUM_PANDAS_VERSION\nexcept:\n raise Exception(\"Version %s or above of Pandas is required to run this notebook\" % REQUIRED_MINIMUM_PANDAS_VERSION)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf *CPLEX* is not installed, install CPLEX Community edition.", "apps": [], "results": {"msg": [{"data": "If CPLEX is not installed, install CPLEX Community edition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import cplex\nexcept:\n raise Exception('Please install CPLEX. See https://pypi.org/project/cplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\n#### Mining Data\n\nThe mine data is provided as a *pandas* DataFrame. For each mine, we are given the amount of royalty to pay when operating the mine, its ore quality, and the maximum quantity that we can extract from the mine.\n", "apps": [], "results": {"msg": [{"data": "The mine data is provided as a pandas DataFrame. For each mine, we are given the amount of royalty to pay when operating the mine, its ore quality, and the maximum quantity that we can extract from the mine.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# If needed, install the module pandas prior to executing this cell\nimport pandas as pd\nfrom pandas import DataFrame, Series", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_mines = DataFrame({\"royalties\": [ 5 , 4, 4, 5 ],\n \"ore_quality\": [ 1.0, 0.7, 1.5, 0.5],\n \"max_extract\": [ 2 , 2.5, 1.3, 3 ]})\nnb_mines = len(df_mines)\ndf_mines.index.name='range_mines'\ndf_mines", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Blend quality data\n\nEach year, the average blend quality of all ore extracted from the mines\nmust be greater than a minimum quality. This data is provided as a *pandas* Series, the length of which is the plan horizon in years.", "apps": [], "results": {"msg": [{"data": "Each year, the average blend quality of all ore extracted from the mines
\nmust be greater than a minimum quality. This data is provided as a pandas Series, the length of which is the plan horizon in years.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nblend_qualities = Series([0.9, 0.8, 1.2, 0.6, 1.0])\nnb_years = len(blend_qualities)\nprint(\"* Planning mining operations for: {} years\".format(nb_years))\nblend_qualities.describe()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Additional (global) data\n\nWe need extra global data to run our planning model:\n\n * a blend price (supposedly flat),\n * a maximum number of worked mines for any given years (typically 3), and\n * a discount rate to compute the actualized revenue over the horizon.\n ", "apps": [], "results": {"msg": [{"data": "We need extra global data to run our planning model:
\n\nThe data is clean and does not need any cleansing.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmm = Model(\"mining_pandas\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWhat are the decisions we need to make?\n\n * What mines do we work each year? (a yes/no decision)\n * What mine do we keep open each year? (again a yes/no decision)\n * What quantity is extracted from each mine, each year? (a positive number)\n \n We need to define some decision variables and add constraints to our model related to these decisions.\n ", "apps": [], "results": {"msg": [{"data": "What are the decisions we need to make?
\n\nWe need to define some decision variables and add constraints to our model related to these decisions.
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "In order to take advantage of the pandas operations to create the optimization model, decision variables are organized in a DataFrame which is automatically indexed by 'range_mines' and 'range_years' (that is, the same keys as the dictionary created by the binary_var_matrix() method).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Organize all decision variables in a DataFrame indexed by 'range_mines' and 'range_years'\ndf_decision_vars = DataFrame({'work': work_vars, 'open': open_vars, 'ore': ore_vars})\n# Set index names\ndf_decision_vars.index.names=['range_mines', 'range_years']\n\n# Display rows of 'df_decision_vars' DataFrame for first mine\ndf_decision_vars[:nb_years]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow, let's iterate over rows of the DataFrame *\"df_decision_vars\"* and enforce the desired constraints.\n\nThe *pandas* method *itertuples()* returns a named tuple for each row of a DataFrame. This method is efficient and convenient for iterating over all rows.", "apps": [], "results": {"msg": [{"data": "Now, let's iterate over rows of the DataFrame \"df_decision_vars\" and enforce the desired constraints.
\n\nThe pandas method itertuples() returns a named tuple for each row of a DataFrame. This method is efficient and convenient for iterating over all rows.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmm.add_constraints(t.work <= t.open for t in df_decision_vars.itertuples())\nmm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Constraint 2: Once closed, a mine stays closed.\n\nThese constraints are a little more complex: we state that the series of *open_vars[m,y]* for a given mine *_m_* is decreasing. In other terms, once some *open_vars[m,y]* is zero, all subsequent values for future years are also zero.\n\nLet's use the *pandas* *groupby* operation to collect all *\"open\"* decision variables for each mine in separate *pandas* Series.These constraints are a little more complex: we state that the series of open_vars[m,y] for a given mine _m_ is decreasing. In other terms, once some open_vars[m,y] is zero, all subsequent values for future years are also zero.
\n\nLet's use the pandas groupby operation to collect all \"open\" decision variables for each mine in separate pandas Series.
Then, we iterate over the mines and invoke the aggregate() method, passing the postOpenCloseConstraint() function as the argument.
The pandas aggregate() method invokes postOpenCloseConstraint() for each mine, passing the associated Series of \"open\" decision variables as argument.
\nThe postOpenCloseConstraint() function posts a set of constraints on the sequence of \"open\" decision variables to enforce that a mine cannot re-open.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Once closed, a mine stays closed\ndef postOpenCloseConstraint(open_vars):\n mm.add_constraints(open_next <= open_curr\n for (open_next, open_curr) in zip(open_vars[1:], open_vars))\n # Optionally: return a string to display information regarding the aggregate operation in the Output cell\n return \"posted {0} open/close constraints\".format(len(open_vars) - 1)\n\n# Constraints on sequences of decision variables are posted for each mine, \n# using pandas' \"groupby\" operation.\ndf_decision_vars.open.groupby(level='range_mines').aggregate(postOpenCloseConstraint)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Constraint 3: The number of worked mines each year is limited.", "apps": [], "results": {"msg": [{"data": "This time, we use the pandas groupby operation to collect all \"work\" decision variables for each year in separate pandas Series. Each Series contains the \"work\" decision variables for all mines.
\nThen, the maximum number of worked mines constraint is enforced by making sure that the sum of all the terms of each Series is smaller or equal to the maximum number of worked mines.
The aggregate() method is used to post this constraint for each year.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Maximum number of worked mines each year\n# Note that Model.sum() accepts a pandas Series of variables.\ndf_decision_vars.work.groupby(level='range_years').aggregate(\n lambda works: mm.add_constraint(mm.sum(works) <= max_worked_mines))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Constraint 4: The quantity extracted is limited.\n\nThis constraint expresses two things:\n * Only a worked mine can give ore. (Note that there is no minimum on the quantity extracted, this model is very simplified).\n * The quantity extracted is less than the mine's maximum extracted quantity.", "apps": [], "results": {"msg": [{"data": "This constraint expresses two things:
\nTo illustrate the pandas join operation, let's build a DataFrame that joins the \"df_decision_vars\" DataFrame and the \"df_mines.max_extract\" Series such that each row contains the information to enforce the quantity extracted limit constraint.
The default behaviour of the pandas join operation is to look at the index of left DataFrame and to append columns of the right Series or DataFrame which have same index.
Here is the result of this operation in our case:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Display rows of 'df_decision_vars' joined with 'df_mines.max_extract' Series for first two mines\ndf_decision_vars.join(df_mines.max_extract)[:(nb_years * 2)]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow, the constraint to limit quantity extracted is easily created by iterating over all rows of the joined DataFrames:", "apps": [], "results": {"msg": [{"data": "Now, the constraint to limit quantity extracted is easily created by iterating over all rows of the joined DataFrames:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# quantity extracted is limited\nmm.add_constraints(t.ore <= t.max_extract * t.work\n for t in df_decision_vars.join(df_mines.max_extract).itertuples())\nmm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Blend constraints\n\nWe need to compute the total production of each year, stored in auxiliary variables.", "apps": [], "results": {"msg": [{"data": "We need to compute the total production of each year, stored in auxiliary variables.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAgain, we use the *pandas* *groupby* operation, this time to collect all *\"ore\"* decision variables for each **year** in separate *pandas* Series.Again, we use the pandas groupby operation, this time to collect all \"ore\" decision variables for each year in separate pandas Series.
The \"blend\" variable for a given year is the sum of \"ore\" decision variables for the corresponding Series.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# blend variables\nblend_vars = mm.continuous_var_list(nb_years, name='blend')\n\n# define blend variables as sum of extracted quantities\nmm.add_constraints(mm.sum(ores.values) == blend_vars[year]\n for year, ores in df_decision_vars.ore.groupby(level='range_years'))\nmm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Minimum average blend quality constraint\n\nThe average quality of the blend is the weighted sum of extracted quantities, divided by the total extracted quantity. Because we cannot use division here, we transform the inequality:", "apps": [], "results": {"msg": [{"data": "The average quality of the blend is the weighted sum of extracted quantities, divided by the total extracted quantity. Because we cannot use division here, we transform the inequality:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Quality requirement on blended ore\nmm.add_constraints(mm.sum(ores.values * df_mines.ore_quality) >= blend_qualities[year] * blend_vars[year]\n for year, ores in df_decision_vars.ore.groupby(level='range_years'))\nmm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### KPIs and objective\n\nSince both revenues and royalties are actualized using the same rate, we compute an auxiliary discount rate array.\n\n##### The discount rate array", "apps": [], "results": {"msg": [{"data": "Since both revenues and royalties are actualized using the same rate, we compute an auxiliary discount rate array.
\n\nTotal expected revenue is the sum of actualized yearly revenues, computed as total extracted quantities multiplied by the blend price (assumed to be constant over the years in this simplified model).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nexpected_revenue = blend_price * mm.dot(blend_vars, s_discounts)\nmm.add_kpi(expected_revenue, \"Total Actualized Revenue\");", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Total actualized royalty cost\n\nThe total actualized royalty cost is computed for all open mines, also actualized using the discounts array.", "apps": [], "results": {"msg": [{"data": "The total actualized royalty cost is computed for all open mines, also actualized using the discounts array.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThis time, we use the *pandas* *join* operation twice to build a DataFrame that joins the *\"df_decision_vars\"* DataFrame with the *\"df_mines.royalties\"* and *\"s_discounts\"* Series such that each row contains the relevant information to calculate its contribution to the total actualized royalty cost.This time, we use the pandas join operation twice to build a DataFrame that joins the \"df_decision_vars\" DataFrame with the \"df_mines.royalties\" and \"s_discounts\" Series such that each row contains the relevant information to calculate its contribution to the total actualized royalty cost.
The join with the \"df_mines.royalties\" Series is performed by looking at the common \"range_mines\" index, while the join with the \"s_discounts\" Series is performed by looking at the common \"range_years\" index.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_royalties_data = df_decision_vars.join(df_mines.royalties).join(s_discounts)\n# add a new column to compute discounted roylaties using pandas multiplication on columns\ndf_royalties_data['disc_royalties'] = df_royalties_data['royalties'] * df_royalties_data['discounts']\ndf_royalties_data[:nb_years]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe total royalty is now calculated by multiplying the columns *\"open\"*, *\"royalties\"* and *\"discounts\"*, and to sum over all rows.The total royalty is now calculated by multiplying the columns \"open\", \"royalties\" and \"discounts\", and to sum over all rows.
Using pandas constructs, this can be written in a very compact way as follows:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntotal_royalties = mm.dot(df_royalties_data.open, df_royalties_data.disc_royalties)\n\nmm.add_kpi(total_royalties, \"Total Actualized Royalties\");", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective\n\nThe business objective is to maximize the expected net profit, which is the difference between revenue and royalties.", "apps": [], "results": {"msg": [{"data": "The business objective is to maximize the expected net profit, which is the difference between revenue and royalties.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmm.maximize(expected_revenue - total_royalties)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization\n", "apps": [], "results": {"msg": [{"data": "To analyze the results, we again leverage pandas, by storing the solution value of the ore variables in a new DataFrame.
\nNote that we use the float function of Python to convert the variable to its solution value. Of course, this requires that the model be successfully solved.
For convenience, we want to organize the ore solution values in a pivot table with years as row index and mines as columns. The pandas unstack operation does this for us.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmine_labels = [(\"mine%d\" % (m+1)) for m in range_mines]\nylabels = [(\"y%d\" % (y+1)) for y in range_years]\n\n# Add a column to DataFrame containing 'ore' decision variables value\n# Note that we extract the solution values of ore variables in one operation with get_values().\ndf_decision_vars['ore_values'] = s1.get_values(df_decision_vars.ore)\n\n# Create a pivot table by (years, mines), using pandas' \"unstack\" method to transform the 'range_mines' row index\n# into columns\ndf_res = df_decision_vars.ore_values.unstack(level='range_mines')\n\n# Set user-friendly labels for column and row indices\ndf_res.columns = mine_labels\ndf_res.index = ylabels\n\ndf_res", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Visualize results\n\nIn this section you'll need the *matplotlib* module to visualize the results of the solve.", "apps": [], "results": {"msg": [{"data": "In this section you'll need the matplotlib module to visualize the results of the solve.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# import matplotlib library for visualization\nimport matplotlib.pyplot as plt\n# matplotlib graphics are printed -inside- the notebook\n\ndf_res.plot(kind=\"bar\", figsize=(10,4.5))\nplt.xlabel(\"year\")\nplt.ylabel(\"ore\")\nplt.title('ore values per year');", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Adding operational constraints.\n\nWhat if we wish to add operational constraints? For example, let us forbid work on certain pairs of (mines, years). Let's see how this impacts profit.\n\nFirst, we add extra constraints to forbid work on those tuples.", "apps": [], "results": {"msg": [{"data": "What if we wish to add operational constraints? For example, let us forbid work on certain pairs of (mines, years). Let's see how this impacts profit.
\n\nFirst, we add extra constraints to forbid work on those tuples.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# a list of (mine, year) tuples on which work is not possible.\nforced_stops = [(1, 2), (0, 1), (1, 0), (3, 2), (2, 3), (3, 4)]\n\nmm.add_constraints(work_vars[stop_m, stop_y] == 0 \n for stop_m, stop_y in forced_stops)\nmm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe previous solution does not satisfy these constraints; for example (0, 1) means mine 1 should not be worked on year 2, but it was in fact worked in the above solution.\n\nTo help CPLEX find a feasible solution, we will build a heuristic feasible solution and pass it to CPLEX.", "apps": [], "results": {"msg": [{"data": "The previous solution does not satisfy these constraints; for example (0, 1) means mine 1 should not be worked on year 2, but it was in fact worked in the above solution.
\n\nTo help CPLEX find a feasible solution, we will build a heuristic feasible solution and pass it to CPLEX.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Using an heuristic start solution\n\nIn this section, we show how one can provide a start solution to CPLEX, based on heuristics.\n\nFirst, we build a solution in which mines are worked whenever possible, that is for all couples *(m,y)* except for those in *forced_stops*.", "apps": [], "results": {"msg": [{"data": "In this section, we show how one can provide a start solution to CPLEX, based on heuristics.
\n\nFirst, we build a solution in which mines are worked whenever possible, that is for all couples (m,y) except for those in forced_stops.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# build a new, empty solution\nfull_mining = mm.new_solution()\n\n# define the worked \nfor m in range_mines:\n for y in range_years:\n if (m,y) not in forced_stops:\n full_mining.add_var_value(work_vars[m,y], 1)\n#full_mining.display()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThen we pass this solution to the model as a MIP start solution and re-solve,\nthis time with CPLEX logging turned on.", "apps": [], "results": {"msg": [{"data": "Then we pass this solution to the model as a MIP start solution and re-solve,
\nthis time with CPLEX logging turned on.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmm.add_mip_start(full_mining)\ns2 = mm.solve(log_output=True) # turns on CPLEX logging\nassert s2, \"solve failed\"\nmm.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nYou can see in the CPLEX log above, that our MIP start solution provided a good start for CPLEX, defining an initial solution with objective 157.9355\n\nNow we can again visualize the results with *pandas* and *matplotlib*.", "apps": [], "results": {"msg": [{"data": "You can see in the CPLEX log above, that our MIP start solution provided a good start for CPLEX, defining an initial solution with objective 157.9355
\n\nNow we can again visualize the results with pandas and matplotlib.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Add a column to DataFrame containing 'ore' decision variables value and create a pivot table by (years, mines)\ndf_decision_vars['ore_values2'] = s2.get_values(df_decision_vars.ore)\ndf_res2 = df_decision_vars.ore_values2.unstack(level='range_mines')\ndf_res2.columns = mine_labels\ndf_res2.index = ylabels\n\ndf_res2.plot(kind=\"bar\", figsize=(10,4.5))\nplt.xlabel(\"year\")\nplt.ylabel(\"ore\")\nplt.title('ore values per year - what-if scenario');", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAs expected, mine1 is not worked in year 2: there is no blue bar at y2.", "apps": [], "results": {"msg": [{"data": "As expected, mine1 is not worked in year 2: there is no blue bar at y2.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/nurses_pandas.json b/examples/mp/zeppelin/nurses_pandas.json deleted file mode 100644 index c329d89..0000000 --- a/examples/mp/zeppelin/nurses_pandas.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "nurses_pandas", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# The Nurse Assignment Problem\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>It requires a valid subscription to **Decision Optimization on Cloud** or a **local installation of CPLEX Optimizers**. \nDiscover us [here](https://developer.ibm.com/docloud).\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Download the library\n * Step 2: Set up the engines\n - Step 3: Model the data\n * Step 4: Prepare the data\n - Step 5: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with the Decision Optimization solve service\n * Step 6: Investigate the solution and run an example analysis\n* Summary\n\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\nIt requires a valid subscription to Decision Optimization on Cloud or a local installation of CPLEX Optimizers.
\n
Discover us here.
\n\n\nTable of contents:
\n\n* Step 1: Download the library\n
\n* Step 2: Set up the engines\n
\n- Step 3: Model the data\n
\n* Step 4: Prepare the data\n
\n- Step 5: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with the Decision Optimization solve service\n
\n* Step 6: Investigate the solution and run an example analysis\n
\nThis notebook describes how to use CPLEX Modeling for Python together with pandas to
\nmanage the assignment of nurses to shifts in a hospital.
\n\nNurses must be assigned to hospital shifts in accordance with various skill and staffing constraints.
\n\nThe goal of the model is to find an efficient balance between the different objectives:
\n\nWith prescriptive analytics, you can:
\n\nThis notebook uses some features of pandas that are available in version 0.17.1 or above.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pip\nREQUIRED_MINIMUM_PANDAS_VERSION = '0.17.1'\ntry:\n import pandas as pd\n assert pd.__version__ >= REQUIRED_MINIMUM_PANDAS_VERSION\nexcept:\n raise Exception(\"Version %s or above of Pandas is required to run this notebook\" % REQUIRED_MINIMUM_PANDAS_VERSION)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to install the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\nimport pip\ntry:\n import docplex.mp\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', docplex]) \n else:\n pip.main(['install --user', docplex]) ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Set up the prescriptive engine\n\n* Subscribe to our private cloud offer or Decision Optimization on Cloud solve service [here](https://developer.ibm.com/docloud) if you do not want to use a local solver.\n* Get the service URL and your personal API key and enter your credentials here if accurate:", "apps": [], "results": {"msg": [{"data": "The input data consists of several tables:
\n\nWe load the data from an Excel file using pandas.
\nEach sheet is read into a separate pandas DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCSS = \"\"\"\nbody {\n margin: 0;\n font-family: Helvetica;\n}\ntable.dataframe {\n border-collapse: collapse;\n border: none;\n}\ntable.dataframe tr {\n border: none;\n}\ntable.dataframe td, table.dataframe th {\n margin: 0;\n border: 1px solid white;\n padding-left: 0.25em;\n padding-right: 0.25em;\n}\ntable.dataframe th:not(:empty) {\n background-color: #fec;\n text-align: left;\n font-weight: normal;\n}\ntable.dataframe tr:nth-child(2) th:empty {\n border-left: none;\n border-right: 1px dashed #888;\n}\ntable.dataframe td {\n border: 2px solid #ccf;\n background-color: #f4f4ff;\n}\n table.dataframe thead th:first-child {\n display: none;\n }\n table.dataframe tbody th {\n display: none;\n }\n\"\"\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom IPython.core.display import HTML\nHTML(''.format(CSS))\n\nfrom IPython.display import display", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n from StringIO import StringIO\nexcept ImportError:\n from io import StringIO", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n from urllib2 import urlopen\nexcept ImportError:\n from urllib.request import urlopen", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# This notebook requires pandas to work\nimport pandas as pd\nfrom pandas import DataFrame\n\n# Make sure that xlrd package, which is a pandas optional dependency, is installed\n# This package is required for Excel I/O\ntry:\n import xlrd\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip.main(['install', xlrd]) \n else:\n pip.main(['install --user', xlrd]) \n\n# Use pandas to read the file, one tab for each table.\ndata_url = \"https://github.com/IBMDecisionOptimization/docplex-examples/blob/master/examples/mp/jupyter/nurses_data.xls?raw=true\"\nnurse_xls_file = pd.ExcelFile(urlopen(data_url))\n\ndf_skills = nurse_xls_file.parse('Skills')\ndf_depts = nurse_xls_file.parse('Departments')\ndf_shifts = nurse_xls_file.parse('Shifts')\n# Rename df_shifts index\ndf_shifts.index.name = 'shiftId'\n\n# Index is column 0: name\ndf_nurses = nurse_xls_file.parse('Nurses', header=0, index_col=0)\ndf_nurse_skilles = nurse_xls_file.parse('NurseSkills')\ndf_vacations = nurse_xls_file.parse('NurseVacations')\ndf_associations = nurse_xls_file.parse('NurseAssociations')\ndf_incompatibilities = nurse_xls_file.parse('NurseIncompatibilities')\n\n# Display the nurses dataframe\nprint(\"#nurses = {}\".format(len(df_nurses)))\nprint(\"#shifts = {}\".format(len(df_shifts)))\nprint(\"#vacations = {}\".format(len(df_vacations)))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIn addition, we introduce some extra global data:\n\n* The maximum work time for each nurse.\n* The maximum and minimum number of shifts worked by a nurse in a week.", "apps": [], "results": {"msg": [{"data": "In addition, we introduce some extra global data:
\n\nShifts are stored in a separate DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_shifts", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Prepare the data\n\nWe need to precompute additional data for shifts. \nFor each shift, we need the start time and end time expressed in hours, counting from the beginning of the week: Monday 8am is converted to 8, Tuesday 8am is converted to 24+8 = 32, and so on.\n\n#### Sub-step #1\nWe start by adding an extra column `dow` (day of week) which converts the string \"day\" into an integer in 0..6 (Monday is 0, Sunday is 6).", "apps": [], "results": {"msg": [{"data": "We need to precompute additional data for shifts.
\nFor each shift, we need the start time and end time expressed in hours, counting from the beginning of the week: Monday 8am is converted to 8, Tuesday 8am is converted to 24+8 = 32, and so on.
\n\nWe start by adding an extra column dow
(day of week) which converts the string \"day\" into an integer in 0..6 (Monday is 0, Sunday is 6).
Computing the start time in the week is easy: just add 24*dow
to column start_time
. The result is stored in a new column wstart
.
Computing the absolute end time is a little more complicated as certain shifts span across midnight. For example, Shift #3 starts on Monday at 18:00 and ends Tuesday at 2:00 AM. The absolute end time of Shift #3 is 26, not 2.
\nThe general rule for computing absolute end time is:
\n\nabs_end_time = end_time + 24 * dow + (start_time>= end_time ? 24 : 0)
Again, we use pandas to add a new calculated column wend
. This is done by using the pandas apply
method with an anonymous lambda
function over rows. The raw=True
parameter prevents the creation of a pandas Series for each row, which improves the performance significantly on large data sets.
Computing the duration of each shift is now a straightforward difference of columns. The result is stored in column duration
.
Minimum demand is the product of duration (in hours) by the minimum required number of nurses. Thus, in number of
\nnurse-hours, this demand is stored in another new column min_demand
.
Finally, we display the updated shifts DataFrame with all calculated columns.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# also compute minimum demand in nurse-hours\ndf_shifts[\"min_demand\"] = df_shifts.min_req * df_shifts.duration\n\n# finally check the modified shifts dataframe\ndf_shifts", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n\nWe now use CPLEX Modeling for Python to build a Mixed Integer Programming (MIP) model for this problem.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\nmdl = Model(name=\"nurses\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables\n\nFor each (nurse, shift) pair, we create one binary variable that is equal to 1 when the nurse is assigned to the shift.\n\nWe use the `binary_var_matrix` method of class `Model`, as each binary variable is indexed by _two_ objects: one nurse and one shift.", "apps": [], "results": {"msg": [{"data": "For each (nurse, shift) pair, we create one binary variable that is equal to 1 when the nurse is assigned to the shift.
\n\nWe use the binary_var_matrix
method of class Model
, as each binary variable is indexed by two objects: one nurse and one shift.
Some shifts overlap in time, and thus cannot be assigned to the same nurse.
\nTo check whether two shifts overlap in time, we start by ordering all shifts with respect to their wstart and duration properties. Then, for each shift, we iterate over the subsequent shifts in this ordered list to easily compute the subset of overlapping shifts.
\n\nWe use pandas operations to implement this algorithm. But first, we organize all decision variables in a DataFrame.
\n\nFor convenience, we also organize the decision variables in a pivot table with nurses as row index and shifts as columns. The pandas unstack operation does this.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Organize decision variables in a DataFrame\ndf_assigned = DataFrame({'assigned': assigned})\ndf_assigned.index.names=['all_nurses', 'all_shifts']\n\n# Re-organize the Data Frame as a pivot table with nurses as row index and shifts as columns:\ndf_assigned_pivot = df_assigned.unstack(level='all_shifts')\n\n# Create a pivot using nurses and shifts index as dimensions\n#df_assigned_pivot = df_assigned.reset_index().pivot(index='all_nurses', columns='all_shifts', values='assigned')\n\n# Display first rows of the pivot table\ndf_assigned_pivot.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe create a DataFrame representing a list of shifts sorted by *\"wstart\"* and *\"duration\"*.\nThis sorted list will be used to easily detect overlapping shifts.\n\nNote that indices are reset after sorting so that the DataFrame can be indexed with respect to\nthe index in the sorted list and not the original unsorted list. This is the purpose of the *reset_index()*\noperation which also adds a new column named *\"shiftId\"* with the original index.", "apps": [], "results": {"msg": [{"data": "We create a DataFrame representing a list of shifts sorted by \"wstart\" and \"duration\".
\nThis sorted list will be used to easily detect overlapping shifts.
\n\nNote that indices are reset after sorting so that the DataFrame can be indexed with respect to
\nthe index in the sorted list and not the original unsorted list. This is the purpose of the reset_index()
\noperation which also adds a new column named \"shiftId\" with the original index.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Create a Data Frame representing a list of shifts sorted by wstart and duration.\n# One keeps only the three relevant columns: 'shiftId', 'wstart' and 'wend' in the resulting Data Frame \ndf_sorted_shifts = df_shifts.sort_values(['wstart','duration']).reset_index()[['shiftId', 'wstart', 'wend']]\n\n# Display the first rows of the newly created Data Frame\ndf_sorted_shifts.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNext, we state that for any pair of shifts that overlap in time, a nurse can be assigned to only one of the two.", "apps": [], "results": {"msg": [{"data": "Next, we state that for any pair of shifts that overlap in time, a nurse can be assigned to only one of the two.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnumber_of_incompatible_shift_constraints = 0\nfor shift in df_sorted_shifts.itertuples():\n # Iterate over following shifts\n # 'shift[0]' contains the index of the current shift in the df_sorted_shifts Data Frame\n for shift_2 in df_sorted_shifts.iloc[shift[0] + 1:].itertuples():\n if (shift_2.wstart < shift.wend):\n # Iterate over all nurses to force incompatible assignment for the current pair of overlapping shifts\n for nurse_assignments in df_assigned_pivot[[shift.shiftId, shift_2.shiftId]].itertuples():\n # this is actually a logical OR\n mdl.add_constraint(nurse_assignments[1] + nurse_assignments[2] <= 1)\n number_of_incompatible_shift_constraints += 1\n else:\n # No need to test overlap with following shifts\n break\nprint(\"#incompatible shift constraints: {}\".format(number_of_incompatible_shift_constraints))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Vacations\n\nWhen the nurse is on vacation, he cannot be assigned to any shift starting that day.\n\nWe use the *pandas* *merge* operation to create a join between the *\"df_vacations\"*, *\"df_shifts\"*, and *\"df_assigned\"* DataFrames. Each row of the resulting DataFrame contains the assignment decision variable corresponding to the matching (nurse, shift) pair.", "apps": [], "results": {"msg": [{"data": "When the nurse is on vacation, he cannot be assigned to any shift starting that day.
\n\nWe use the pandas merge operation to create a join between the \"df_vacations\", \"df_shifts\", and \"df_assigned\" DataFrames. Each row of the resulting DataFrame contains the assignment decision variable corresponding to the matching (nurse, shift) pair.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Add 'day of week' column to vacations Data Frame\ndf_vacations['dow'] = df_vacations.day.apply(day_to_day_of_week)\n\n# Join 'df_vacations', 'df_shifts' and 'df_assigned' Data Frames to create the list of 'forbidden' assigments.\n# The 'reset_index()' function is invoked to move 'shiftId' index as a column in 'df_shifts' Data Frame, and\n# to move the index pair ('all_nurses', 'all_shifts') as columns in 'df_assigned' Data Frame.\n# 'reset_index()' is invoked so that a join can be performed between Data Frame, based on column names.\ndf_assigned_reindexed = df_assigned.reset_index()\ndf_vacation_forbidden_assignments = df_vacations.merge(df_shifts.reset_index()[['dow', 'shiftId']]).merge(\n df_assigned_reindexed, left_on=['nurse', 'shiftId'], right_on=['all_nurses', 'all_shifts'])\n\n# Here are the first few rows of the resulting Data Frames joins\ndf_vacation_forbidden_assignments.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor forbidden_assignment in df_vacation_forbidden_assignments.itertuples():\n # to forbid an assignment just set the variable to zero.\n mdl.add_constraint(forbidden_assignment.assigned == 0)\nprint(\"# vacation forbids: {} assignments\".format(len(df_vacation_forbidden_assignments)))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Associations\n\nSome pairs of nurses get along particularly well, so we wish to assign them together as a team. In other words, for every such couple and for each shift, both assignment variables should always be equal.\nEither both nurses work the shift, or both do not.\n\nIn the same way we modeled *vacations*, we use the *pandas* merge operation to create a DataFrame for which each row contains the pair of nurse-shift assignment decision variables matching each association.", "apps": [], "results": {"msg": [{"data": "Some pairs of nurses get along particularly well, so we wish to assign them together as a team. In other words, for every such couple and for each shift, both assignment variables should always be equal.
\nEither both nurses work the shift, or both do not.
\n\nIn the same way we modeled vacations, we use the pandas merge operation to create a DataFrame for which each row contains the pair of nurse-shift assignment decision variables matching each association.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Join 'df_assignment' Data Frame twice, based on associations to get corresponding decision variables pairs for all shifts\n# The 'suffixes' parameter in the second merge indicates our preference for updating the name of columns that occur both\n# in the first and second argument Data Frames (in our case, these columns are 'all_nurses' and 'assigned').\ndf_preferred_assign = df_associations.merge(\n df_assigned_reindexed, left_on='nurse1', right_on='all_nurses').merge(\n df_assigned_reindexed, left_on=['nurse2', 'all_shifts'], right_on=['all_nurses', 'all_shifts'], suffixes=('_1','_2'))\n\n# Here are the first few rows of the resulting Data Frames joins\ndf_preferred_assign.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe associations constraint can now easily be formulated by iterating on the rows of the *\"df_preferred_assign\"* DataFrame.", "apps": [], "results": {"msg": [{"data": "The associations constraint can now easily be formulated by iterating on the rows of the \"df_preferred_assign\" DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor preferred_assign in df_preferred_assign.itertuples():\n mdl.add_constraint(preferred_assign.assigned_1 == preferred_assign.assigned_2)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Incompatibilities\n\nSimilarly, certain pairs of nurses do not get along well, and we want to avoid having them together on a shift.\nIn other terms, for each shift, both nurses of an incompatible pair cannot be assigned together to the sift. Again, we state a logical OR between the two assignments: at most one nurse from the pair can work the shift.\n\nWe first create a DataFrame whose rows contain pairs of invalid assignment decision variables, using the same *pandas* `merge` operations as in the previous step.", "apps": [], "results": {"msg": [{"data": "Similarly, certain pairs of nurses do not get along well, and we want to avoid having them together on a shift.
\nIn other terms, for each shift, both nurses of an incompatible pair cannot be assigned together to the sift. Again, we state a logical OR between the two assignments: at most one nurse from the pair can work the shift.
\n\nWe first create a DataFrame whose rows contain pairs of invalid assignment decision variables, using the same pandas merge
operations as in the previous step.
The incompatibilities constraint can now easily be formulated, by iterating on the rows of the \"df_incompatible_assign\" DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor incompatible_assign in df_incompatible_assign.itertuples():\n mdl.add_constraint(incompatible_assign.assigned_1 + incompatible_assign.assigned_2 <= 1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Constraints on work time\n\nRegulations force constraints on the total work time over a week;\nand we compute this total work time in a new variable. We store the variable in an extra column in the nurse DataFrame.\n\nThe variable is declared as _continuous_ though it contains only integer values. This is done to avoid adding unnecessary integer variables for the _branch and bound_ algorithm. \nThese variables are not true decision variables; they are used to express work constraints.\n\nFrom a *pandas* perspective, we apply a function over the rows of the nurse DataFrame to create this variable and store it into a new column of the DataFrame.", "apps": [], "results": {"msg": [{"data": "Regulations force constraints on the total work time over a week;
\nand we compute this total work time in a new variable. We store the variable in an extra column in the nurse DataFrame.
\n\nThe variable is declared as continuous though it contains only integer values. This is done to avoid adding unnecessary integer variables for the branch and bound algorithm.
\nThese variables are not true decision variables; they are used to express work constraints.
\n\nFrom a pandas perspective, we apply a function over the rows of the nurse DataFrame to create this variable and store it into a new column of the DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# auxiliary function to create worktime variable from a row\ndef make_var(row, varname_fmt):\n return mdl.continuous_var(name=varname_fmt % row.name, lb=0)\n\n# apply the function over nurse rows and store result in a new column\ndf_nurses[\"worktime\"] = df_nurses.apply(lambda r: make_var(r, \"worktime_%s\"), axis=1)\n\n# display nurse dataframe\ndf_nurses", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n###### Define total work time\n\nWork time variables must be constrained to be equal to the sum of hours actually worked.\n\nWe use the *pandas* *groupby* operation to collect all assignment decision variables for each nurse in a separate series. Then, we iterate over nurses to post a constraint calculating the actual worktime for each nurse as the dot product of the series of nurse-shift assignments with the series of shift durations.", "apps": [], "results": {"msg": [{"data": "Work time variables must be constrained to be equal to the sum of hours actually worked.
\n\nWe use the pandas groupby operation to collect all assignment decision variables for each nurse in a separate series. Then, we iterate over nurses to post a constraint calculating the actual worktime for each nurse as the dot product of the series of nurse-shift assignments with the series of shift durations.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Use pandas' groupby operation to enforce constraint calculating worktime for each nurse as the sum of all assigned\n# shifts times the duration of each shift\nfor nurse, nurse_assignments in df_assigned.groupby(level='all_nurses'):\n mdl.add_constraint(df_nurses.worktime[nurse] == mdl.dot(nurse_assignments.assigned, df_shifts.duration))\n \n# print model information and check we now have 32 extra continuous variables\nmdl.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n###### Maximum work time\n\nFor each nurse, we add a constraint to enforce the maximum work time for a week.\nAgain we use the `apply` method, this time with an anonymous lambda function.", "apps": [], "results": {"msg": [{"data": "For each nurse, we add a constraint to enforce the maximum work time for a week.
\nAgain we use the apply
method, this time with an anonymous lambda function.
Each shift requires a minimum number of nurses.
\nFor each shift, the sum over all nurses of assignments to this shift
\nmust be greater than the minimum requirement.
\n\nThe pandas groupby operation is invoked to collect all assignment decision variables for each shift in a separate series. Then, we iterate over shifts to post the constraint enforcing the minimum number of nurse assignments for each shift.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Use pandas' groupby operation to enforce minimum requirement constraint for each shift\nfor shift, shift_nurses in df_assigned.groupby(level='all_shifts'):\n mdl.add_constraint(mdl.sum(shift_nurses.assigned) >= df_shifts.min_req[shift])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective\n\nThe objective mixes different (and contradictory) KPIs. \n\nThe first KPI is the total salary cost, computed as the sum of work times over all nurses, weighted by pay rate.\n\nWe compute this KPI as an expression from the variables we previously defined by using the panda summation over the DOcplex objects.", "apps": [], "results": {"msg": [{"data": "The objective mixes different (and contradictory) KPIs.
\n\nThe first KPI is the total salary cost, computed as the sum of work times over all nurses, weighted by pay rate.
\n\nWe compute this KPI as an expression from the variables we previously defined by using the panda summation over the DOcplex objects.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# again leverage pandas to create a series of expressions: costs of each nurse\ntotal_salary_series = df_nurses.worktime * df_nurses.pay_rate\n\n# compute global salary cost using pandas sum()\n# Note that the result is a DOcplex expression: DOcplex if fully compatible with pandas\ntotal_salary_cost = total_salary_series.sum()\nmdl.add_kpi(total_salary_cost, \"Total salary cost\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Minimizing salary cost\n\nIn a preliminary version of the model, we minimize the total salary cost. This is accomplished\nusing the `Model.minimize()` method.", "apps": [], "results": {"msg": [{"data": "In a preliminary version of the model, we minimize the total salary cost. This is accomplished
\nusing the Model.minimize()
method.
Now we have everything we need to solve the model, using Model.solve()
. The following cell solves using your local CPLEX (if any, and provided you have added it to your PYTHONPATH
variable).
If you do not have CPLEX installed, please enter your DOcplexcloud credentials below in the key
and url
fields in order to solve on DOcplexcloud.
We take advantage of pandas to analyze the results. First we store the solution values of the assignment variables into a new pandas Series.
\n\nCalling solution_value
on a DOcplex variable returns its value in the solution (provided the model has been successfully solved).
Let's analyze how worktime is distributed among nurses.
\n\nFirst, we compute the global average work time as the total minimum requirement in hours, divided by number of nurses.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ns_demand = df_shifts.min_req * df_shifts.duration\ntotal_demand = s_demand.sum()\navg_worktime = total_demand / float(len(all_nurses))\nprint(\"* theoretical average work time is {0:g} h\".format(avg_worktime))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's analyze the series of deviations to the average, stored in a *pandas* Series.", "apps": [], "results": {"msg": [{"data": "Let's analyze the series of deviations to the average, stored in a pandas Series.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# a pandas series of worktimes solution values\ns_worktime = df_nurses.worktime.apply(lambda v: v.solution_value)\n\n# returns a new series computed as deviation from average\ns_to_mean = s_worktime - avg_worktime\n\n# take the absolute value\ns_abs_to_mean = s_to_mean.apply(abs)\n\n\ntotal_to_mean = s_abs_to_mean.sum()\nprint(\"* the sum of absolute deviations from mean is {}\".format(total_to_mean))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nTo see how work time is distributed among nurses, print a histogram of work time values.\nNote that, as all time data are integers, work times in the solution can take only integer values.", "apps": [], "results": {"msg": [{"data": "To see how work time is distributed among nurses, print a histogram of work time values.
\nNote that, as all time data are integers, work times in the solution can take only integer values.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport matplotlib.pyplot as plt\n# we can also plot as a histogram the distribution of worktimes\ns_worktime.plot.hist(color='LightBlue')\nplt.xlabel(\"worktime\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### How shifts are distributed\n\nLet's now analyze the solution from the _number of shifts_ perspective.\nHow many shifts does each nurse work? Are these shifts fairly distributed amongst nurses?\n\nWe compute a new column in our result DataFrame for the number of shifts worked,\nby summing rows (the *\"axis=1\"* argument in the *sum()* call indicates to *pandas* that each sum is performed by row instead of column):", "apps": [], "results": {"msg": [{"data": "Let's now analyze the solution from the number of shifts perspective.
\nHow many shifts does each nurse work? Are these shifts fairly distributed amongst nurses?
\n\nWe compute a new column in our result DataFrame for the number of shifts worked,
\nby summing rows (the \"axis=1\" argument in the sum() call indicates to pandas that each sum is performed by row instead of column):
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# a pandas series of #shifts worked\ndf_worked = df_res[all_shifts].sum(axis=1)\ndf_res[\"worked\"] = df_worked\n\ndf_worked.plot.hist(color=\"gold\", xlim=(0,10))\nplt.ylabel(\"#shifts worked\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe see that one nurse works significantly fewer shifts than others do. What is the average number of shifts worked by a nurse? This is equal to the total demand divided by the number of nurses.\n\nOf course, this yields a fractional number of shifts that is not practical, but nonetheless will help us quantify\nthe _fairness_ in shift distribution.", "apps": [], "results": {"msg": [{"data": "We see that one nurse works significantly fewer shifts than others do. What is the average number of shifts worked by a nurse? This is equal to the total demand divided by the number of nurses.
\n\nOf course, this yields a fractional number of shifts that is not practical, but nonetheless will help us quantify
\nthe fairness in shift distribution.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\navg_worked = df_shifts[\"min_req\"].sum() / float(len(all_nurses))\nprint(\"-- expected avg #shifts worked is {}\".format(avg_worked))\n\nworked_to_avg = df_res[\"worked\"] - avg_worked\ntotal_to_mean = worked_to_avg.apply(abs).sum()\nprint(\"-- total absolute deviation to mean #shifts is {}\".format(total_to_mean))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Introducing a fairness goal\n\nAs the above diagram suggests, the distribution of shifts could be improved.\nWe implement this by adding one extra objective, _fairness_, which balances\nthe shifts assigned over nurses.\n\nNote that we can edit the model, that is add (or remove) constraints, even after it has been solved. \n\n### Step #1 : Introduce three new variables per nurse to model the \nnumber of shifts worked and positive and negative deviations to the average.", "apps": [], "results": {"msg": [{"data": "As the above diagram suggests, the distribution of shifts could be improved.
\nWe implement this by adding one extra objective, fairness, which balances
\nthe shifts assigned over nurses.
\n\nNote that we can edit the model, that is add (or remove) constraints, even after it has been solved.
\n\nnumber of shifts worked and positive and negative deviations to the average.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# add two extra variables per nurse: deviations above and below average\ndf_nurses[\"worked\"] = df_nurses.apply(lambda r: make_var(r, \"worked%s\"), axis=1)\ndf_nurses[\"overworked\"] = df_nurses.apply(lambda r: make_var(r, \"overw_%s\"), axis=1)\ndf_nurses[\"underworked\"] = df_nurses.apply(lambda r: make_var(r, \"underw_%s\"), axis=1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step #2 : Post the constraint that links these variables together.", "apps": [], "results": {"msg": [{"data": "Finally, let's modify the objective by adding the sum of over_worked and under_worked
to the previous objective.
Note: The definitions of over_worked
and under_worked
as described above are not sufficient to give them an unambiguous value. However, as all these variables are minimized, CPLEX ensures that these variables take the minimum possible values in the solution.
Our modified model is ready to solve. Again, enter your DOcplexcloud url
and api_key
in the appropriate fields below to solve on DOcplexcloud if you do not have a local CPLEX installation.
The log_output=True
parameter tells CPLEX to print the log on the standard output.
Let's recompute the new total deviation from average on this new solution.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Create a pandas Series containing actual shift assignment decision variables value\ns_assigned2 = df_assigned.assigned.apply(lambda v: v.solution_value)\n\n# Create a pivot table by (nurses, shifts), using pandas' \"unstack\" method to transform the 'all_shifts' row index\n# into columns\ndf_res2 = s_assigned2.unstack(level='all_shifts')\n\n# Add a new column to the pivot table containing the #shifts worked by summing over each row\ndf_res2[\"worked\"] = df_res2[all_shifts].sum(axis=1)\n\n# total absolute deviation from average is directly read on expressions\nnew_total_to_mean = total_overw.solution_value + total_underw.solution_value\nprint(\"-- total absolute deviation to mean #shifts is now {0} down from {1}\".format(new_total_to_mean, total_to_mean))\n\n# Display the first few rows of the result Data Frame\ndf_res2.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's print the new histogram of shifts worked.", "apps": [], "results": {"msg": [{"data": "Let's print the new histogram of shifts worked.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_res2[\"worked\"].plot(kind=\"hist\", color=\"gold\", xlim=(3,8))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### The breakdown of shifts over nurses is much closer to the average than it was in the previous version.", "apps": [], "results": {"msg": [{"data": "But what is the absolute minimum for the deviation to the ideal average number of shifts?
\nCPLEX can tell us: simply minimize only the the total deviation from average, ignoring the salary cost.
\nOf course this is unrealistic, but it will help us quantify how far our fairness result is to the
\nabsolute optimal fairness.
\n\nWe modify the objective and solve for the third time (using the usual necessary update for DOcplexcloud credentials).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.minimize(total_overw + total_underw)\nassert mdl.solve(url=url, key=key), \"solve failed\"\nmdl.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIn the fairness-optimal solution, we have zero under-average shifts and 4 over-average.\nSalary cost is now higher than the previous value of 28884 but this was expected as salary cost was not part of the objective.\n\nTo summarize, the absolute minimum for this measure of fairness is 4, and we have found a balance with fairness=7.\n\nFinally, we display the histogram for this optimal-fairness solution.", "apps": [], "results": {"msg": [{"data": "In the fairness-optimal solution, we have zero under-average shifts and 4 over-average.
\nSalary cost is now higher than the previous value of 28884 but this was expected as salary cost was not part of the objective.
\n\nTo summarize, the absolute minimum for this measure of fairness is 4, and we have found a balance with fairness=7.
\n\nFinally, we display the histogram for this optimal-fairness solution.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Create a pandas Series containing actual shift assignment decision variables value\ns_assigned_fair = df_assigned.assigned.apply(lambda v: v.solution_value)\n\n# Create a pivot table by (nurses, shifts), using pandas' \"unstack\" method to transform the 'all_shifts' row index\n# into columns\ndf_res_fair = s_assigned_fair.unstack(level='all_shifts')\n\n# Add a new column to the pivot table containing the #shifts worked by summing over each row\ndf_res_fair[\"solution_value_fair\"] = df_res_fair[all_shifts].sum(axis=1)\ndf_res_fair[\"worked\"] = df_res_fair[all_shifts].sum(axis=1)\ndf_res_fair[\"worked\"].plot.hist(color=\"plum\", xlim=(3,8))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIn the above figure, all nurses but one are assigned the average of 7 shifts, which is what we expected.\n\n## Summary\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.", "apps": [], "results": {"msg": [{"data": "In the above figure, all nurses but one are assigned the average of 7 shifts, which is what we expected.
\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/nurses_scheduling.json b/examples/mp/zeppelin/nurses_scheduling.json deleted file mode 100644 index ee2aa2a..0000000 --- a/examples/mp/zeppelin/nurses_scheduling.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\nurses_scheduling", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# The Nurses Model\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nThis model deals with nurse scheduling. Nurses must be assigned to hospital shifts in accordance with various skill and staffing constraints.
\n\nThe goal of the model is to find an efficient balance between the different objectives:
\n\nWith prescriptive analytics, you can:
\n\nRun the following code to import Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\n\nInput data consists of several tables:\n\n* The Departments table lists all departments in the scope of the assignment.\n* The Skills table list all skills.\n* The Shifts table lists all shifts to be staffed. A shift contains a department, a day in the week, plus the start and end times.\n* The Nurses table lists all nurses, identified by their names.\n* The NurseSkills table gives the skills of each nurse.\n* The SkillRequirements table lists the minimum number of persons required for a given department and skill.\n* The NurseVacations table lists days off for each nurse.\n* The NurseAssociations table lists pairs of nurses who wish to work together.\n* The NurseIncompatibilities table lists pairs of nurses who do not want to work together\n.\nIn addition, the plan has to satisfy a maximum worktime for all nurses, for example 40 hours a week.", "apps": [], "results": {"msg": [{"data": "Input data consists of several tables:
\n\n.
\nIn addition, the plan has to satisfy a maximum worktime for all nurses, for example 40 hours a week.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data\n\nNow we need some basic data structures to store information.", "apps": [], "results": {"msg": [{"data": "Now we need some basic data structures to store information.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom enum import Enum\nfrom collections import namedtuple\n\n# utility to conevrt a weekday string to an index in 0..6\n_all_days = [\"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\", \"sunday\"]\n\n\ndef day_to_day_week(day):\n day_map = {day: d for d, day in enumerate(_all_days)}\n return day_map[day.lower()]\n\nTWorkRules = namedtuple(\"TWorkRules\", [\"work_time_max\"])\nTVacation = namedtuple(\"TVacation\", [\"nurse\", \"day\"])\nTNursePair = namedtuple(\"TNursePair\", [\"firstNurse\", \"secondNurse\"])\nTNurseSkill = namedtuple(\"TNurseSkill\", [\"nurse\", \"skill\"])\nTSkillRequirement = namedtuple(\"TSkillRequirement\", [\"department\", \"skill\", \"required\"])\n\n\n# subclass the namedtuple to refine the str() method as the nurse's name\nclass TNurse(namedtuple(\"TNurse1\", [\"name\", \"pay_rate\"])):\n \"\"\" A subclass to redefine the default str() of namedtuple.\n This class is used in variable naming, so we need to redefine the str() method\n used by variable naming.\n \"\"\"\n\n def __str__(self):\n return self.name\n\n\nclass TShift(\n namedtuple(\"TShift1\", [\"department\", \"day\", \"start_time\", \"end_time\", \"min_requirement\", \"max_requirement\"])):\n \"\"\" specialize namedtuple to redefine its str() method\n \"\"\"\n\n def __str__(self):\n # keep first two characters in departement, uppercased\n dept2 = self.department[0:4].upper()\n # keep 3 days of weekday\n dayname = self.day[0:3]\n return '%s_%s_%02d' % (dept2, dayname, self.start_time)\n \n\nclass ShiftActivity(object):\n @staticmethod\n def to_abstime(day_index, time_of_day):\n \"\"\" Convert a pair (day_index, time) into a number of hours since Monday 00:00\n\n :param day_index: The index of the day from 1 to 7 (Monday is 1).\n :param time_of_day: An integer number of hours.\n\n :return:\n \"\"\"\n time = 24 * (day_index - 1)\n time += time_of_day\n return time\n\n def __init__(self, weekday, start_time_of_day, end_time_of_day):\n assert (start_time_of_day >= 0)\n assert (start_time_of_day <= 24)\n assert (end_time_of_day >= 0)\n assert (end_time_of_day <= 24)\n\n self._weekday = weekday\n self._start_time_of_day = start_time_of_day\n self._end_time_of_day = end_time_of_day\n # conversion to absolute time.\n start_day_index = day_to_day_week(self._weekday)\n self.start_time = self.to_abstime(start_day_index, start_time_of_day)\n self.day_start_time = self.to_abstime(start_day_index, 0)\n end_day_index = start_day_index if end_time_of_day > start_time_of_day else start_day_index + 1\n self.end_time = self.to_abstime(end_day_index, end_time_of_day)\n assert self.end_time > self.start_time\n\n @property\n def duration(self):\n return self.end_time - self.start_time\n\n def overlaps(self, other_shift):\n if not isinstance(other_shift, ShiftActivity):\n return False\n else:\n return other_shift.end_time > self.start_time and other_shift.start_time < self.end_time\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Loading data from Excel with pandas\n\nWe load the data from an Excel file using *pandas*.\nEach sheet is read into a separate *pandas* DataFrame.", "apps": [], "results": {"msg": [{"data": "We load the data from an Excel file using pandas.
\nEach sheet is read into a separate pandas DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCSS = \"\"\"\nbody {\n margin: 0;\n font-family: Helvetica;\n}\ntable.dataframe {\n border-collapse: collapse;\n border: none;\n}\ntable.dataframe tr {\n border: none;\n}\ntable.dataframe td, table.dataframe th {\n margin: 0;\n border: 1px solid white;\n padding-left: 0.25em;\n padding-right: 0.25em;\n}\ntable.dataframe th:not(:empty) {\n background-color: #fec;\n text-align: left;\n font-weight: normal;\n}\ntable.dataframe tr:nth-child(2) th:empty {\n border-left: none;\n border-right: 1px dashed #888;\n}\ntable.dataframe td {\n border: 2px solid #ccf;\n background-color: #f4f4ff;\n}\n table.dataframe thead th:first-child {\n display: none;\n }\n table.dataframe tbody th {\n display: none;\n }\n\"\"\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom IPython.core.display import HTML\nHTML(''.format(CSS))\n\nfrom IPython.display import display", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n from StringIO import StringIO\nexcept ImportError:\n from io import StringIO", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# This notebook requires pandas to work\nimport pandas as pd\n\n# Make sure that xlrd package, which is a pandas optional dependency, is installed\n# This package is required for Excel I/O\ntry:\n import xlrd\nimport pip._internal\nexcept:\n if hasattr(sys, 'real_prefix'):\n #we are in a virtual env.\n pip._internal.main(['install', 'xlrd'])\n else:\n pip._internal.main(['install', '--user', 'xlrd']) \n \ntry:\n from urllib2 import urlopen\nexcept ImportError:\n from urllib.request import urlopen\n\ndata_url = \"https://github.com/IBMDecisionOptimization/docplex-examples/blob/master/examples/mp/jupyter/nurses_data.xls?raw=true\"\nnurse_xls_file = pd.ExcelFile(urlopen(data_url))\n\nSkillTable = nurse_xls_file.parse('Skills')\nDeptTable = nurse_xls_file.parse('Departments')\nShiftTable = nurse_xls_file.parse('Shifts')\nSkillRequirementTable = nurse_xls_file.parse('SkillRequirements')\nNurseTable = nurse_xls_file.parse('Nurses')\nNurseSkillTable = nurse_xls_file.parse('NurseSkills')\nNurseVacationTable = nurse_xls_file.parse('NurseVacations')\nNurseAssociationTable = nurse_xls_file.parse('NurseAssociations')\nNurseIncompatibilityTable = nurse_xls_file.parse('NurseIncompatibilities')\n\ndisplay(NurseTable)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow, we create some additional data structures to be used for building the prescriptive model.Now, we create some additional data structures to be used for building the prescriptive model.
The goal is to not depend on pandas when defining decision variables and constraints.
\nThe 'nurses_pandas' notebook illustrates how to benefit from pandas to build the prescriptive model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nskills = [SkillTable[\"name\"][i] for i in range(len(SkillTable))]\ndepts = [DeptTable[\"name\"][i] for i in range(len(DeptTable))]\nnurses =[TNurse(NurseTable[\"name\"][i], NurseTable[\"pay_rate\"][i]) for i in range(len(NurseTable))]\n\nnurses = [nurse for nurse in nurses if nurse.pay_rate <25 and nurse.pay_rate >15]\n# Build {nurse: [skills]} dictionary\nnurse_skills = {}\nfor nsk in NurseSkillTable.itertuples(index=False):\n nskt= TNurseSkill(*nsk)\n nurse_skills.setdefault(nskt.nurse, []).append(nskt.skill)\n\nshifts = [TShift(*shift_row) for shift_row in ShiftTable.itertuples(index=False)]\nskill_requirements = [TSkillRequirement(*skill_requirement_row) for skill_requirement_row in\n SkillRequirementTable.itertuples(index=False)]\nvacations = [TVacation(*vacation_row) for vacation_row in NurseVacationTable.itertuples(index=False)]\nnurse_associations = [TNursePair(*na) for na in NurseAssociationTable.itertuples(index=False)]\nnurse_incompatibilities = [TNursePair(*na) for na in NurseIncompatibilityTable.itertuples(index=False)]\n\n# compute shift activities (start, end, duration) and store them in a dict indexed by shifts\nshift_activities = {s: ShiftActivity(s.day, s.start_time, s.end_time) for s in shifts}\n\n# map from nurse names to nurse tuples.\nnurses_by_id = {n.name: n for n in nurses}\n\n# Work rules: max work time\nwork_rules = TWorkRules(40)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "This model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmdl = Model(\"nurses\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables\n\nThe basic decisions are \"which nurse works which shift\", which is modeled by binary variables for each (nurse, shift) pair.\n\nThe output of the model is, for each shift, the list of nurses that work the shift.\n\n", "apps": [], "results": {"msg": [{"data": "The basic decisions are \"which nurse works which shift\", which is modeled by binary variables for each (nurse, shift) pair.
\n\nThe output of the model is, for each shift, the list of nurses that work the shift.
\n\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# One binary variable for each pair (nurse, shift) equal to 1 if nurse n is assigned to shift s\nnurse_assignment_vars = mdl.binary_var_matrix(nurses, shifts, 'NurseAssigned')\n\n# For each nurse, allocate one variable for worktime\nnurse_work_time_vars = mdl.continuous_var_dict(nurses, lb=0, name='NurseWorkTime')\n\n# And two variables for over_average and under-average work time\nnurse_over_average_time_vars = mdl.continuous_var_dict(nurses, lb=0, name='NurseOverAverageWorkTime')\nnurse_under_average_time_vars = mdl.continuous_var_dict(nurses, lb=0, name='NurseUnderAverageWorkTime')\n\n# Finally the global average work time\naverage_nurse_work_time = mdl.continuous_var(lb=0, name='AverageWorkTime')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the business constraints\n##### First constraint: define average work time\nThe average work time over all nurses will be used in particular to calculate the over/under average work time for each nurse, and to formulate a _fairness_ rule.", "apps": [], "results": {"msg": [{"data": "The average work time over all nurses will be used in particular to calculate the over/under average work time for each nurse, and to formulate a fairness rule.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.add_constraint(len(nurses) * average_nurse_work_time ==\n mdl.sum(nurse_work_time_vars[n] for n in nurses), \"average\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Second constraint: compute nurse work time, average and under/over time", "apps": [], "results": {"msg": [{"data": "When a nurse is on vacation, he or she cannot be assigned to any shift starting that day.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor vac_nurse_id, vac_day in vacations:\n vac_n = nurses_by_id.get(vac_nurse_id, -1)\n if vac_n != -1:\n for shift in (s for s in shifts if s.day == vac_day):\n mdl.add_constraint(nurse_assignment_vars[vac_n, shift] == 0,\n \"medium_vacations_{0!s}_{1!s}_{2!s}\".format(vac_n, vac_day, shift))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Fourth constraint: a nurse cannot be assigned overlapping shifts\nSome shifts overlap in time and thus cannot be assigned to the same nurse.", "apps": [], "results": {"msg": [{"data": "Some shifts overlap in time and thus cannot be assigned to the same nurse.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Post only one constraint per couple(s1, s2)\nnumber_of_overlaps = 0\nnb_shifts = len(shifts)\nfor i1 in range(nb_shifts):\n for i2 in range(i1 + 1, nb_shifts):\n s1 = shifts[i1]\n s2 = shifts[i2]\n if shift_activities[s1].overlaps(shift_activities[s2]):\n number_of_overlaps += 1\n for n in nurses:\n mdl.add_constraint(nurse_assignment_vars[n, s1] + nurse_assignment_vars[n, s2] <= 1,\n \"high_overlapping_{0!s}_{1!s}_{2!s}\".format(s1, s2, n))\nprint(\"# overlapping shifts: {}\".format(number_of_overlaps))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Fifth constraint: enforce minimum and maximum requirements for shifts\nEach shift requires a minimum and a maximum number of nurses. \nFor each shift, the sum over all nurses of assignments to this shift\nmust be greater than or equal to the minimum requirement and lesser than or equal to the maximum requirement.", "apps": [], "results": {"msg": [{"data": "Each shift requires a minimum and a maximum number of nurses.
\nFor each shift, the sum over all nurses of assignments to this shift
\nmust be greater than or equal to the minimum requirement and lesser than or equal to the maximum requirement.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor s in shifts:\n demand_min = s.min_requirement\n demand_max = s.max_requirement\n total_assigned = mdl.sum(nurse_assignment_vars[n, s] for n in nurses)\n mdl.add_constraint(total_assigned >= demand_min,\n \"high_req_min_{0!s}_{1}\".format(s, demand_min))\n mdl.add_constraint(total_assigned <= demand_max,\n \"medium_req_max_{0!s}_{1}\".format(s, demand_max))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Sixth constraint: enforce skill requirements for selected shifts\nSome shifts require at least _x_ nurses with a specified skill.", "apps": [], "results": {"msg": [{"data": "Some shifts require at least x nurses with a specified skill.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfor (dept, skill, required) in skill_requirements:\n if required > 0:\n for dsh in (s for s in shifts if dept == s.department):\n mdl.add_constraint(mdl.sum(nurse_assignment_vars[skilled_nurse, dsh] for skilled_nurse in\n (n for n in nurses if n.name in nurse_skills.keys() and \n skill in nurse_skills[n.name])) >= required,\n \"high_required_{0!s}_{1!s}_{2!s}_{3!s}\".format(dept, skill, required, dsh))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Seventh constraint: associations\nSome pairs of nurses get along particularly well, so we wish to assign them together as a team. In other words, for every such pair and for each shift, both assignment variables should always be equal.\nEither both nurses work the shift, or both do not.", "apps": [], "results": {"msg": [{"data": "Some pairs of nurses get along particularly well, so we wish to assign them together as a team. In other words, for every such pair and for each shift, both assignment variables should always be equal.
\nEither both nurses work the shift, or both do not.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# for each pair of associted nurses, their assignement variables are equal over all shifts.\nc = 0\nfor (nurse_id1, nurse_id2) in nurse_associations:\n if nurse_id1 in nurses_by_id and nurse_id2 in nurses_by_id:\n nurse1 = nurses_by_id[nurse_id1]\n nurse2 = nurses_by_id[nurse_id2]\n for s in shifts:\n c += 1\n ctname = 'medium_ct_nurse_assoc_{0!s}_{1!s}_{2:d}'.format(nurse_id1, nurse_id2, c)\n mdl.add_constraint(nurse_assignment_vars[nurse1, s] == nurse_assignment_vars[nurse2, s], ctname)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Eighth constraint: incompatibilities\nSimilarly, certain pairs of nurses do not get along well, and we want to avoid having them together on a shift.Similarly, certain pairs of nurses do not get along well, and we want to avoid having them together on a shift.
In other words, for each shift, both nurses of an incompatible pair cannot be assigned together to the shift.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# For each pair of incompatible nurses, the sum of assigned variables is less than one\nc = 0\nfor (nurse_id1, nurse_id2) in nurse_incompatibilities:\n if nurse_id1 in nurses_by_id and nurse_id2 in nurses_by_id:\n nurse1 = nurses_by_id[nurse_id1]\n nurse2 = nurses_by_id[nurse_id2]\n for s in shifts:\n c += 1\n ctname = 'medium_ct_nurse_incompat_{0!s}_{1!s}_{2:d}'.format(nurse_id1, nurse_id2, c)\n mdl.add_constraint(nurse_assignment_vars[nurse1, s] + nurse_assignment_vars[nurse2, s] <= 1, ctname)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective\nThe objective mixes different (and contradictory) KPIs. \n\nThe first KPI is the total salary cost, computed as the sum of work times over all nurses, weighted by pay rate.The objective mixes different (and contradictory) KPIs.
\n\nThe first KPI is the total salary cost, computed as the sum of work times over all nurses, weighted by pay rate.
The second KPI is the total number of assignments (nurse, shift).
The third KPI is the average total work time over all nurses.
The fourth KPI represents the total number of hours that is above the average work time (summed over all nurses), while the fifth KPI represents the total number of hours that is below this average.
\nFinally, the last KPI is a measure of fairness, which is evaluated as the total deviation from the average work time.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntotal_number_of_assignments = mdl.sum(nurse_assignment_vars[n,s] for n in nurses for s in shifts)\nnurse_costs = [nurse_assignment_vars[n, s] * n.pay_rate * shift_activities[s].duration for n in nurses for s in shifts]\ntotal_salary_cost = mdl.sum(nurse_costs)\nmdl.add_kpi(total_salary_cost, \"Total salary cost\")\nmdl.add_kpi(total_number_of_assignments, \"Total number of assignments\")\nmdl.add_kpi(average_nurse_work_time)\n\ntotal_over_average_worktime = mdl.sum(nurse_over_average_time_vars[n] for n in nurses)\ntotal_under_average_worktime = mdl.sum(nurse_under_average_time_vars[n] for n in nurses)\nmdl.add_kpi(total_over_average_worktime, \"Total over-average worktime\")\nmdl.add_kpi(total_under_average_worktime, \"Total under-average worktime\")\n\ntotal_fairness = total_over_average_worktime + total_under_average_worktime\nmdl.add_kpi(total_fairness, \"Total fairness\")\n\nmdl.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Minimizing objective\nThe goal is to minimize the non-weighted sum of the _total salary cost_, _fairness_ and _total number of assignment_.The goal is to minimize the non-weighted sum of the total salary cost, fairness and total number of assignment.
This is accomplished using the Model.minimize()
method.
This definition is arbitrary and could be revised. For instance, one could emphasize minimizing salary cost by adding a weight on this term in the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.minimize(total_salary_cost + total_fairness + total_number_of_assignments)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization\nNow we have everything we need to solve the model, using `Model.solve()`. The following cell solves using your local CPLEX (if any, and provided you have added it to your `PYTHONPATH` variable). \n", "apps": [], "results": {"msg": [{"data": "Now we have everything we need to solve the model, using Model.solve()
. The following cell solves using your local CPLEX (if any, and provided you have added it to your PYTHONPATH
variable).
Let's display some charts to visualize the results: a Gantt chart displaying the assignment of nurses to shifts in a Gantt chart, and another chart showing the number of assigned nurses to each department over time.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmin(shift_activities, key=lambda i: shift_activities[i].day_start_time)\nmin(s.day_start_time for s in shift_activities.values())", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport matplotlib.pyplot as plt\nimport matplotlib.gridspec as gridspec\n\n# Build set of all departments and assign a color to each of them to be used in figures\ndepartments = {s.department for s in shifts}\ncolorByDepartment = {}\nfor d, c in zip(departments, ['r', 'm', 'b', 'g', 'y', 'c', 'k']):\n colorByDepartment[d] = c\n\n# Build dictionary with number of assigned nurses for each shift\nnbAssignmentsByShift={}\nfor n in nurses:\n for s in shifts:\n if nurse_assignment_vars[n,s].solution_value > 0:\n nbAssignmentsByShift[s] = nbAssignmentsByShift.get(s,0) + 1\n\n# Build a dictionary with the list of each shift corresponding to each department\nshiftsByDepartment = {}\nfor s in shifts:\n shiftsByDepartment.setdefault(s.department, []).append(s)\n\n\n# Shared code\ndef createLabels(ax, title, xlabel, ylabel):\n shiftInfoByDay = {s1.day : s1 for s1 in shifts}\n try: # Python 2\n plt.xticks([shift_activities[s].day_start_time + w * 7 * 24 for w in [0,1] for (d, s) in shiftInfoByDay.iteritems()],\n [\"{}\".format(s.day) for w in [0,1] for (d, s) in shiftInfoByDay.iteritems()])\n except:\n plt.xticks([shift_activities[s].day_start_time + w * 7 * 24 for w in [0,1] for (d, s) in shiftInfoByDay.items()],\n [\"{}\".format(s.day) for w in [0,1] for (d, s) in shiftInfoByDay.items()])\n\n plt.xlim([min(s.day_start_time for s in shift_activities.values()) - 6,\n max(s.day_start_time for s in shift_activities.values()) + 30])\n ax.set_xlabel(xlabel)\n ax.set_ylabel(ylabel)\n ax.grid()\n ax.set_title(title)\n\n# Plot shift assignments for each nurse\ndef displayNursesAssignmentsGantt(ax):\n ylabels, tickloc = [], []\n for i, n in enumerate(nurses):\n for s in shifts:\n if nurse_assignment_vars[n,s].solution_value > 0:\n shift_activity = shift_activities[s]\n ax.bar(shift_activity.start_time, 0.8,\n width=shift_activity.end_time - shift_activity.start_time, bottom=i + 0.1,\n color=colorByDepartment[s.department])\n\n ylabels.append(\"{} (worked: {} hours)\".format(str(n), nurse_work_time_vars[n].solution_value))\n tickloc.append(i + 0.5)\n\n plt.ylim(0, len(nurses))\n plt.yticks(tickloc, ylabels)\n\n # Create labels on x/y axis\n createLabels(ax, 'SHIFTS ASSIGNMENTS', 'DAY OF WEEK', 'NURSES')\n\n# Plot number of assigned nurses for each shift, by department\ndef displayDepartmentsAssignments(ax):\n ylabels, tickloc = [], []\n maxNbAssignements = max(nbAssignmentsByShift.values())\n for i, d in enumerate(departments):\n for s in shiftsByDepartment[d]:\n shift_activity = shift_activities[s]\n ax.bar(shift_activity.start_time, nbAssignmentsByShift.get(s, 0) / float(maxNbAssignements + 1),\n width=shift_activity.end_time - shift_activity.start_time, bottom=i + 0.5,\n color=colorByDepartment[s.department])\n ylabels.append(\"{}\".format(d))\n tickloc.append(i + 0.5)\n\n plt.ylim(0, len(departments) + 0.5)\n plt.yticks(tickloc, ylabels)\n\n # Create labels on x/y axis\n createLabels(ax, 'NUMBER OF ASSIGNED NURSES', 'DAY OF WEEK', 'DEPARTMENTS')\n\n# Display figures as two sub-plots so that they are vertically aligned\nfig = plt.figure(figsize=[14,12])\ngs = gridspec.GridSpec(2, 1, height_ratios=[3,1])\n\nax = plt.subplot(gs[0])\ndisplayNursesAssignmentsGantt(ax)\n\nax = plt.subplot(gs[1])\ndisplayDepartmentsAssignments(ax)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/oil_blending.json b/examples/mp/zeppelin/oil_blending.json deleted file mode 100644 index fca04bb..0000000 --- a/examples/mp/zeppelin/oil_blending.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\oil_blending", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Maximizing the profit of an oil company\n\nThis tutorial includes everything you need to set up the decision optimization engines and build mathematical programming models.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>Running the sample requires the installation of\n [CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n (Commercial or free \n [CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n This sample automatically installs *CPLEX CE* if needed. \n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up the decision optimization engines and build mathematical programming models.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\nRunning the sample requires the installation of
\n
[CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n
\n(Commercial or free\n
\n[CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n
\nThis sample automatically installs *CPLEX CE* if needed.\n
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n+ Automate complex decisions and trade-offs to better manage limited resources.\n
\n+ Take advantage of a future opportunity or mitigate a future risk.\n
\n+ Proactively update recommendations based on changing events.\n
\n+ Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf *CPLEX* is not installed, install CPLEX Community edition.", "apps": [], "results": {"msg": [{"data": "If CPLEX is not installed, install CPLEX Community edition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import cplex\nexcept:\n raise Exception('Please install CPLEX. See https://pypi.org/project/cplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\n\n* For each type of crude oil, there are capacities of what can be bought, the buying price, the octane level, and the lead level. \n* For each type of gasoline or diesel, there is customer demand, selling prices, and octane and lead levels.\n* There is a maximum level of production imposed by the factory's limit as well as a fixed production cost. \n* There are inventory costs for each type of final product and blending proportions. All of these have actual values in the model.\n\n* The maginal production cost and maximum production are assumed to be identical for all oil types.\n\n\nInput data comes as *NumPy* arrays with two dimensions. [NumPy](http://www.numpy.org/) is the fundamental package for scientific computing with Python.", "apps": [], "results": {"msg": [{"data": "Input data comes as NumPy arrays with two dimensions. NumPy is the fundamental package for scientific computing with Python.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe first dimension of the *NumPy* array is the number of gasoline types; \nand for each gasoline type, we have a *NumPy* array containing capacity, price, octane and lead level, in that order.", "apps": [], "results": {"msg": [{"data": "The first dimension of the NumPy array is the number of gasoline types;
\nand for each gasoline type, we have a NumPy array containing capacity, price, octane and lead level, in that order.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport numpy as np\n\ngas_names = [\"super\", \"regular\", \"diesel\"]\n\ngas_data = np.array([[3000, 70, 10, 1], [2000, 60, 8, 2], [1000, 50, 6, 1]])\n\noil_names = [\"crude1\", \"crude2\", \"crude3\"]\n\noil_data = np.array([[5000, 45, 12, 0.5], [5000, 35, 6, 2], [5000, 25, 8, 3]])\n\nnb_gas = len(gas_names)\nnb_oils = len(oil_names)\nrange_gas = range(nb_gas)\nrange_oil = range(nb_oils)\nprint(\"Number of gasoline types = {0}\".format(nb_gas))\nprint(\"Number of crude types = {0}\".format(nb_oils))\n\n# global data\nproduction_cost = 4\nproduction_max = 14000\n# each $1 spent on advertising increases demand by 10.\nadvert_return = 10", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data", "apps": [], "results": {"msg": [{"data": "Pandas is another Python library that we use to store data. pandas contains data structures and data analysis tools for the Python programming language.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pandas as pd\ngaspd = pd.DataFrame([(gas_names[i],int(gas_data[i][0]),int(gas_data[i][1]),int(gas_data[i][2]),int(gas_data[i][3])) \n for i in range_gas])\noilpd = pd.DataFrame([(oil_names[i],int(oil_data[i][0]),int(oil_data[i][1]),int(oil_data[i][2]),oil_data[i][3]) \n for i in range_oil])\ngaspd.columns = ['name','demand','price','octane','lead']\noilpd.columns= ['name','capacity','price','octane','lead']", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nUse basic HTML and a stylesheet to format the data.", "apps": [], "results": {"msg": [{"data": "Use basic HTML and a stylesheet to format the data.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCSS = \"\"\"\nbody {\n margin: 0;\n font-family: Helvetica;\n}\ntable.dataframe {\n border-collapse: collapse;\n border: none;\n}\ntable.dataframe tr {\n border: none;\n}\ntable.dataframe td, table.dataframe th {\n margin: 0;\n border: 1px solid white;\n padding-left: 0.25em;\n padding-right: 0.25em;\n}\ntable.dataframe th:not(:empty) {\n background-color: #fec;\n text-align: left;\n font-weight: normal;\n}\ntable.dataframe tr:nth-child(2) th:empty {\n border-left: none;\n border-right: 1px dashed #888;\n}\ntable.dataframe td {\n border: 2px solid #ccf;\n background-color: #f4f4ff;\n}\n table.dataframe thead th:first-child {\n display: none;\n }\n table.dataframe tbody th {\n display: none;\n }\n\"\"\"\n\nfrom IPython.core.display import HTML\nHTML(''.format(CSS))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's display the data we just prepared.", "apps": [], "results": {"msg": [{"data": "Let's display the data we just prepared.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom IPython.display import display\nprint(\"Gas data:\")\ndisplay(gaspd)\nprint(\"Oil data:\")\ndisplay(oilpd)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model\n\n#### Create the DOcplex model\nA model is needed to store all the variables and constraints needed to formulate the business problem and submit the problem to the solve service.", "apps": [], "results": {"msg": [{"data": "A model is needed to store all the variables and constraints needed to formulate the business problem and submit the problem to the solve service.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmdl = Model(name=\"oil_blending\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables\n\nFor each combination of oil and gas, we have to decide the quantity of oil to use to produce a gasoline. A decision variable will be needed to represent that amount. \nA matrix of continuous variables, indexed by the set of oils and the set of gasolines needs to be created.\n", "apps": [], "results": {"msg": [{"data": "For each combination of oil and gas, we have to decide the quantity of oil to use to produce a gasoline. A decision variable will be needed to represent that amount.
\nA matrix of continuous variables, indexed by the set of oils and the set of gasolines needs to be created.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nblends = mdl.continuous_var_matrix(keys1=nb_oils, keys2=nb_gas, lb=0)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe also have to decide how much should be spent in advertising for each time of gasoline. To do so, we will create a list of continuous variables, indexed by the gasolines.", "apps": [], "results": {"msg": [{"data": "We also have to decide how much should be spent in advertising for each time of gasoline. To do so, we will create a list of continuous variables, indexed by the gasolines.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nadverts = mdl.continuous_var_list(nb_gas, lb=0)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the business constraints\n\nThe business constraints are the following:\n\n* The demand for each gasoline type must be satisfied. The total demand includes the initial demand as stored in the data,plus a variable demand caused by the advertising. This increase is assumed to be proportional to the advertising cost.\n- The capacity constraint on each oil type must also be satisfied.\n- For each gasoline type, the octane level must be above a minimum level, and the lead level must be below a maximum level.", "apps": [], "results": {"msg": [{"data": "The business constraints are the following:
\n\n* Total advertising cost\n
\n- Total Oil cost\n
\n- Total production cost\n
\n- Total revenue\n
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# KPIs\ntotal_advert_cost = mdl.sum(adverts)\nmdl.add_kpi(total_advert_cost, \"Total advertising cost\")\ntotal_oil_cost = mdl.sum(blends[o,g] * oil_data[o][1] for o in range_oil for g in range_gas)\nmdl.add_kpi(total_oil_cost, \"Total Oil cost\")\ntotal_production_cost = production_cost * mdl.sum(blends)\nmdl.add_kpi(total_production_cost, \"Total production cost\")\ntotal_revenue = mdl.sum(blends[o,g] * gas_data[g][1] for g in range(nb_gas) for o in range(nb_oils))\nmdl.add_kpi(total_revenue, \"Total revenue\")\n\n# finally the objective\nmdl.maximize(total_revenue - total_oil_cost - total_production_cost - total_advert_cost)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization\n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.\n\nWe display the objective and KPI values after the solve by calling the method report() on the model.", "apps": [], "results": {"msg": [{"data": "If you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n\nWe display the objective and KPI values after the solve by calling the method report() on the model.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nassert mdl.solve(), \"Solve failed\"\nmdl.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Investigate the solution and then run an example analysis\n\n#### Displaying the solution\nFirst, get the KPIs values and store them in a *pandas* DataFrame.", "apps": [], "results": {"msg": [{"data": "First, get the KPIs values and store them in a pandas DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nall_kpis = [(kp.name, kp.compute()) for kp in mdl.iter_kpis()]\nkpis_bd = pd.DataFrame(all_kpis, columns=['kpi', 'value'])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nblend_values = [ [ blends[o,g].solution_value for g in range_gas] for o in range_oil]\ntotal_gas_prods = [sum(blend_values[o][g] for o in range_oil) for g in range_gas]\n\nprods = list(zip(gas_names, total_gas_prods))\nprods_bd = pd.DataFrame(prods)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's display some KPIs in pie charts using the Python package [*matplotlib*](http://matplotlib.org/).", "apps": [], "results": {"msg": [{"data": "Let's display some KPIs in pie charts using the Python package matplotlib.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport matplotlib.pyplot as plt\ndef display_pie(pie_values, pie_labels, colors=None,title=''):\n plt.axis(\"equal\")\n plt.pie(pie_values, labels=pie_labels, colors=colors, autopct=\"%1.1f%%\")\n plt.title(title)\n plt.show()\n \ndisplay_pie( [kpnv[1] for kpnv in all_kpis], [kpnv[0] for kpnv in all_kpis],title='KPIs: Revenue - Oil Cost - Production Cost')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Production", "apps": [], "results": {"msg": [{"data": "We see that the most produced gasoline type is by far regular.
\n\nNow, let's plot the breakdown of oil blend quantities per gasoline type.
\nWe are using a multiple bar chart diagram, displaying all blend values for each couple of oil and gasoline type.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nsblends = [(gas_names[n], oil_names[o], round(blends[o,n].solution_value)) for n in range_gas for o in range_oil]\n\nblends_bd = pd.DataFrame(sblends)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nf, barplot = plt.subplots(1, figsize=(16,5))\n\nbar_width = 0.1\noffset = 0.12\nrho = 0.7\n\n# position of left-bar boundaries\nbar_l = [o for o in range_oil]\n\nmbar_w = 3*bar_width+2*max(0, offset-bar_width)\n\ntick_pos = [b*rho + mbar_w/2.0 for b in bar_l]\n\ncolors = ['olive', 'lightgreen', 'cadetblue']\n\nfor i in range_oil:\n barplot.bar([b*rho + (i*offset) for b in bar_l], \n blend_values[i], width=bar_width, color=colors[i], label=oil_names[i])\n\nplt.xticks(tick_pos, gas_names)\nbarplot.set_xlabel(\"gasolines\")\nbarplot.set_ylabel(\"blend\")\nplt.legend(loc=\"upper right\")\nplt.title('Blend Repartition\\n')\n \n\n# Set a buffer around the edge\nplt.xlim([0, max(tick_pos)+mbar_w +0.5])\n\nplt.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNotice the missing bar for (crude2, diesel) which is expected since blend[crude2, diesel] is zero in the solution.\n\nWe can check the solution value of blends for *crude2* and *diesel*, remembering that crude2 has offset 1 and diesel has offset 2.\nNote how the decision variable is automatically converted to a float here. This would raise an exception if called before submitting a solve, as no solution value would be present.", "apps": [], "results": {"msg": [{"data": "Notice the missing bar for (crude2, diesel) which is expected since blend[crude2, diesel] is zero in the solution.
\n\nWe can check the solution value of blends for crude2 and diesel, remembering that crude2 has offset 1 and diesel has offset 2.
\nNote how the decision variable is automatically converted to a float here. This would raise an exception if called before submitting a solve, as no solution value would be present.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nprint(\"* value of blend[crude2, diesel] is %g\" % blends[1,2])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with CPLEX.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/pasta_production.json b/examples/mp/zeppelin/pasta_production.json deleted file mode 100644 index 29ef479..0000000 --- a/examples/mp/zeppelin/pasta_production.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\pasta_production", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# The Pasta Production Problem\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n- Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nThis notebook describes how to use CPLEX Modeling for Python to manage the production of pasta to meet demand with your resources.
\n\nThe model aims at minimizing the production cost for a number of products while satisfying customer demand.
\n\nThe model first declares the products and the resources.
\nThe data consists of the description of the products (the demand, the inside and outside costs,
\nand the resource consumption) and the capacity of the various resources.
\nThe variables for this problem are the inside and outside production for each product.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\n* Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It takes into account specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \nWith prescriptive analytics, you can:
\n\nRun the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\n\nThe data consists of the description of the products (the demand, the inside and outside costs,\nand the resource consumption) and the capacity of the various resources.", "apps": [], "results": {"msg": [{"data": "The data consists of the description of the products (the demand, the inside and outside costs,
\nand the resource consumption) and the capacity of the various resources.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nproducts = [(\"kluski\", 100, 0.6, 0.8),\n (\"capellini\", 200, 0.8, 0.9),\n (\"fettucine\", 300, 0.3, 0.4)]\n\n# resources are a list of simple tuples (name, capacity)\nresources = [(\"flour\", 20),\n (\"eggs\", 40)]\n\nconsumptions = {(\"kluski\", \"flour\"): 0.5,\n (\"kluski\", \"eggs\"): 0.2,\n (\"capellini\", \"flour\"): 0.4,\n (\"capellini\", \"eggs\"): 0.4,\n (\"fettucine\", \"flour\"): 0.3,\n (\"fettucine\", \"eggs\"): 0.6}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data\n\nData is very simple and is ready to use without any cleasning, massage, refactoring.", "apps": [], "results": {"msg": [{"data": "Data is very simple and is ready to use without any cleasning, massage, refactoring.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n\nWe now use CPLEX Modeling for Python to build a Mixed Integer Programming (MIP) model for this problem.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\nmdl = Model(name=\"pasta\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "Minimizing the production cost for a number of products while satisfying customer demand
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntotal_inside_cost = mdl.sum(inside_vars[p] * p[2] for p in products)\ntotal_outside_cost = mdl.sum(outside_vars[p] * p[3] for p in products)\n\nmdl.minimize(total_inside_cost + total_outside_cost)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization\n\nNow we have everything we need to solve the model, using `Model.solve()`. The following cell solves using your local CPLEX (if any, and provided you have added it to your `PYTHONPATH` variable). \n", "apps": [], "results": {"msg": [{"data": "Now we have everything we need to solve the model, using Model.solve()
. The following cell solves using your local CPLEX (if any, and provided you have added it to your PYTHONPATH
variable).
In the above figure, all nurses but one are assigned the average of 7 shifts, which is what we expected.
\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/sports_scheduling.json b/examples/mp/zeppelin/sports_scheduling.json deleted file mode 100644 index c41a67c..0000000 --- a/examples/mp/zeppelin/sports_scheduling.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\sports_scheduling", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# Use decision optimization to help a sports league schedule its games\n\nThis tutorial includes everything you need to set up decision optimization engines, build mathematical programming models, and arrive at a good working schedule for a sports league's games.\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of the [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n\n>Running the sample requires the installation of\n [CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n (Commercial or free \n [CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n This sample automatically installs *CPLEX CE* if needed.\n\n\nTable of contents:\n\n- The business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n - Step 2: Model the Data\n * Step 3: Prepare the data\n - Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up decision optimization engines, build mathematical programming models, and arrive at a good working schedule for a sports league's games.
\n\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of the Prescriptive Analytics for Python
\n
\n\nRunning the sample requires the installation of
\n
[CPLEX Optimization studio](https://www.ibm.com/products/ilog-cplex-optimization-studio)\n
\n(Commercial or free\n
\n[CPLEX Community edition](https://www.ibm.com/account/reg/us-en/signup?formid=urx-20028>`)).\n
\nThis sample automatically installs *CPLEX CE* if needed.\n
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n- Step 2: Model the Data\n
\n* Step 3: Prepare the data\n
\n- Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\n* To model this preference, there is an incentive for intradivisional games that increases each week as a square of the week.\n
\n* An opponent must be assigned to each team each week to maximize the total of the incentives..\n
\n\n\n\nThis is a type of discrete optimization problem that can be solved by using either Integer Programming (IP) or Constraint Programming (CP).
\n\n\n\n\nInteger Programming is the class of problems defined as the optimization of a linear function, subject to linear constraints over integer variables.
\n
\n\n\nConstraint Programming problems generally have discrete decision variables, but the constraints can be logical, and the arithmetic expressions are not restricted to being linear.
\n
For the purposes of this tutorial, we will illustrate a solution with mathematical programming (MIP).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## How decision optimization can help\n\n* Prescriptive analytics (decision optimization) technology recommends actions that are based on desired outcomes. It takes into account specific scenarios, resources, and knowledge of past and current events. With this insight, your organization can make better decisions and have greater control of business outcomes. \n\n* Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes. \n\n* Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage. \nWith prescriptive analytics, you can:
\n\nRun the following code to import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nIf *CPLEX* is not installed, install CPLEX Community edition.", "apps": [], "results": {"msg": [{"data": "If CPLEX is not installed, install CPLEX Community edition.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry:\n import cplex\nexcept:\n raise Exception('Please install CPLEX. See https://pypi.org/project/cplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\nIn this scenario, the data is simple. There are eight teams in each division, and the teams must play each team in the division once and each team outside the division once.\n\nUse a Python module, *Collections*, which implements some data structures that will help solve some problems. *Named tuples* helps to define meaning of each position in a tuple. This helps the code be more readable and self-documenting. You can use named tuples in any place where you use tuples. \n\nIn this example, you create a *namedtuple* to contain information for points. You are also defining some of the parameters.", "apps": [], "results": {"msg": [{"data": "In this scenario, the data is simple. There are eight teams in each division, and the teams must play each team in the division once and each team outside the division once.
\n\nUse a Python module, Collections, which implements some data structures that will help solve some problems. Named tuples helps to define meaning of each position in a tuple. This helps the code be more readable and self-documenting. You can use named tuples in any place where you use tuples.
\n\nIn this example, you create a namedtuple to contain information for points. You are also defining some of the parameters.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Teams in 1st division\nteam_div1 = [\"Baltimore Ravens\",\"Cincinnati Bengals\", \"Cleveland Browns\",\"Pittsburgh Steelers\",\"Houston Texans\",\n \"Indianapolis Colts\",\"Jacksonville Jaguars\",\"Tennessee Titans\",\"Buffalo Bills\",\"Miami Dolphins\",\n \"New England Patriots\",\"New York Jets\",\"Denver Broncos\",\"Kansas City Chiefs\",\"Oakland Raiders\",\n \"San Diego Chargers\"]\n\n# Teams in 2nd division\nteam_div2 = [\"Chicago Bears\",\"Detroit Lions\",\"Green Bay Packers\",\"Minnesota Vikings\",\"Atlanta Falcons\",\n \"Carolina Panthers\",\"New Orleans Saints\",\"Tampa Bay Buccaneers\",\"Dallas Cowboys\",\"New York Giants\",\n \"Philadelphia Eagles\",\"Washington Redskins\",\"Arizona Cardinals\",\"San Francisco 49ers\",\n \"Seattle Seahawks\",\"St. Louis Rams\"]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n#number_of_matches_to_play = 1 # Number of match to play between two teams on the league\n# Schedule parameters\nnb_teams_in_division = 5\nmax_teams_in_division = 10\nnumber_of_matches_inside_division = 1\nnumber_of_matches_outside_division = 1", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nUse basic HTML and a stylesheet to format the data.", "apps": [], "results": {"msg": [{"data": "Use basic HTML and a stylesheet to format the data.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nCSS = \"\"\"\nbody {\n margin: 0;\n font-family: Helvetica;\n}\ntable.dataframe {\n border-collapse: collapse;\n border: none;\n}\ntable.dataframe tr {\n border: none;\n}\ntable.dataframe td, table.dataframe th {\n margin: 0;\n border: 1px solid white;\n padding-left: 0.25em;\n padding-right: 0.25em;\n}\ntable.dataframe th:not(:empty) {\n background-color: #fec;\n text-align: left;\n font-weight: normal;\n}\ntable.dataframe tr:nth-child(2) th:empty {\n border-left: none;\n border-right: 1px dashed #888;\n}\ntable.dataframe td {\n border: 2px solid #ccf;\n background-color: #f4f4ff;\n}\n table.dataframe thead th:first-child {\n display: none;\n }\n table.dataframe tbody th {\n display: none;\n }\n\"\"\"\n\nfrom IPython.core.display import HTML\nHTML(''.format(CSS))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow you will import the *pandas* library. Pandas is an open source Python library for data analysis. It uses two data structures, *Series* and *DataFrame*, which are built on top of *NumPy*.\n\nA **Series** is a one-dimensional object similar to an array, list, or column in a table. It will assign a labeled index to each item in the series. By default, each item receives an index label from 0 to N, where N is the length of the series minus one.\n\nA **DataFrame** is a tabular data structure comprised of rows and columns, similar to a spreadsheet, database table, or R's data.frame object. Think of a DataFrame as a group of Series objects that share an index (the column names).\n\nIn the example, each division (the AFC and the NFC) is part of a DataFrame.", "apps": [], "results": {"msg": [{"data": "Now you will import the pandas library. Pandas is an open source Python library for data analysis. It uses two data structures, Series and DataFrame, which are built on top of NumPy.
\n\nA Series is a one-dimensional object similar to an array, list, or column in a table. It will assign a labeled index to each item in the series. By default, each item receives an index label from 0 to N, where N is the length of the series minus one.
\n\nA DataFrame is a tabular data structure comprised of rows and columns, similar to a spreadsheet, database table, or R's data.frame object. Think of a DataFrame as a group of Series objects that share an index (the column names).
\n\nIn the example, each division (the AFC and the NFC) is part of a DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pandas as pd\n\nteam1 = pd.DataFrame(team_div1)\nteam2 = pd.DataFrame(team_div2)\nteam1.columns = [\"AFC\"]\nteam2.columns = [\"NFC\"]\n\nteams = pd.concat([team1,team2], axis=1)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe following *display* function is a tool to show different representations of objects. When you issue the *display(teams)* command, you are sending the output to the notebook so that the result is stored in the document.", "apps": [], "results": {"msg": [{"data": "The following display function is a tool to show different representations of objects. When you issue the display(teams) command, you are sending the output to the notebook so that the result is stored in the document.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom IPython.display import display\n\ndisplay(teams)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data\n\nGiven the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week. \n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.", "apps": [], "results": {"msg": [{"data": "Given the number of teams in each division and the number of intradivisional and interdivisional games to be played, you can calculate the total number of teams and the number of weeks in the schedule, assuming every team plays exactly one game per week.
\n\n\nThe season is split into halves, and the number of the intradivisional games that each team must play in the first half of the season is calculated.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport numpy as np\n \nnb_teams = 2 * nb_teams_in_division\nteams = range(nb_teams)\n\n# Calculate the number of weeks necessary\nnb_inside_div = (nb_teams_in_division - 1) * number_of_matches_inside_division\nnb_outside_div = nb_teams_in_division * number_of_matches_outside_division\nnb_weeks = nb_inside_div + nb_outside_div\n\n\n# Weeks to schedule\nweeks = range(nb_weeks)\n\n# Season is split into two halves\nfirst_half_weeks = range(int(np.floor(nb_weeks / 2)))\nnb_first_half_games = int(np.floor(nb_weeks / 3))\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom collections import namedtuple\n\nmatch = namedtuple(\"match\",[\"team1\",\"team2\",\"is_divisional\"])\n\nmatches = {match(t1,t2, 1 if ( t2 <= nb_teams_in_division or t1 > nb_teams_in_division) else 0) \n for t1 in teams for t2 in teams if t1 < t2}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNumber of games to play between pairs depends on whether the pairing is intradivisional or not.", "apps": [], "results": {"msg": [{"data": "Number of games to play between pairs depends on whether the pairing is intradivisional or not.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnb_play = { m : number_of_matches_inside_division if m.is_divisional==1 \n else number_of_matches_outside_division\n for m in matches}", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nmdl = Model(\"sports\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables", "apps": [], "results": {"msg": [{"data": "The objective function for this example is designed to force intradivisional games to occur as late in the season as possible. The incentive for intradivisional games increases by week. There is no incentive for interdivisional games.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ngain = { w : w*w for w in weeks}\n\n# If an intradivisional pair plays in week w, Gain[w] is added to the objective.\nmdl.maximize( mdl.sum (m.is_divisional * gain[w] * plays[m,w] for m in matches for w in weeks) )", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Solve with Decision Optimization \n\nYou will get the best solution found after n seconds, due to a time limit parameter.\n", "apps": [], "results": {"msg": [{"data": "You will get the best solution found after n seconds, due to a time limit parameter.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmdl.print_information()\n\nassert mdl.solve(), \"!!! Solve of the model fails\"\nmdl.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Investigate the solution and then run an example analysis", "apps": [], "results": {"msg": [{"data": "Determine which of the scheduled games will be a replay of one of the last 10 Super Bowls.
We start by creating a pandas DataFrame that contains the year and teams who played the last 10 Super Bowls.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry: # Python 2\n team_league = dict({t : team_div1[t] for t in range(nb_teams_in_division) }.items() + \\\n {t+nb_teams_in_division : team_div2[t] for t in range(nb_teams_in_division) }.items()\n )\nexcept: # Python 3\n team_league = dict(list({t : team_div1[t] for t in range(nb_teams_in_division) }.items()) + \\\n list({t+nb_teams_in_division : team_div2[t] for t in range(nb_teams_in_division) }.items()))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nsol = namedtuple(\"solution\",[\"week\",\"is_divisional\", \"team1\", \"team2\"])\n\nsolution = [sol(w, m.is_divisional, team_league[m.team1], team_league[m.team2]) for m in matches for w in weeks if plays[m,w].solution_value == 1]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nnfl_finals = [(\"2016\", \"Carolina Panthers\", \"Denver Broncos\"),\n (\"2015\", \"New England Patriots\", \"Seattle Seahawks\"),\n (\"2014\", \"Seattle Seahawks\", \"Denver Broncos\"),\n (\"2013\", \"Baltimore Ravens\", \"San Francisco 49ers\"),\n (\"2012\", \"New York Giants\", \"New England Patriots \"),\n (\"2011\", \"Green Bay Packers\", \"Pittsburgh Steelers\"),\n (\"2010\", \"New Orleans Saints\", \"Indianapolis Colts\"),\n (\"2009\", \"Pittsburgh Steelers\", \"Arizona Cardinals\"),\n (\"2008\", \"New York Giants\", \"New England Patriots\"),\n (\"2007\", \"Indianapolis Colts\", \"Chicago Bears\")\n ]\nnfl_meetings = {(t[1], t[2]) for t in nfl_finals}\nwinners_bd = pd.DataFrame(nfl_finals)\nwinners_bd.columns = [\"year\", \"team1\", \"team2\"]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndisplay(winners_bd)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nWe now look for the games in our solution that are replays of one of the past 10 Super Bowls.", "apps": [], "results": {"msg": [{"data": "We now look for the games in our solution that are replays of one of the past 10 Super Bowls.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmonths = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"]\nreport = []\nfor m in solution:\n if (m.team1, m.team2) in nfl_meetings:\n report.append((m.week, months[m.week//4], m.team1, m.team2))\n if (m.team2, m.team1) in nfl_meetings: \n report.append((m.week, months[m.week//4], m.team2, m.team1))\n\nprint(report)\nmatches_bd = pd.DataFrame(report)\nmatches_bd.columns = [\"week\", \"Month\", \"Team1\", \"Team2\"]", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ntry: #pandas >= 0.17\n display(matches_bd.sort_values(by='week'))\nexcept:\n display(matches_bd.sort('week'))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with CPLEX.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Constraint Programming model and solve it with CPLEX.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [Decision Optimization CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.\n", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file diff --git a/examples/mp/zeppelin/ucp_pandas.json b/examples/mp/zeppelin/ucp_pandas.json deleted file mode 100644 index fd8b972..0000000 --- a/examples/mp/zeppelin/ucp_pandas.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {}, "config": {"looknfeel": "default", "personalizedMode": "false"}, "name": "C:\\Users\\AURELIEFolacci\\python\\workspace\\docplex\\docplex\\src\\samples\\examples\\delivery\\jupyter\\ucp_pandas", "paragraphs": [{"settings": {"forms": {}, "params": {}}, "text": "%md\n# The Unit Commitment Problem (UCP)\n\nThis tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.\n\nWhen you finish this tutorial, you'll have a foundational knowledge of _Prescriptive Analytics_.\n\n>This notebook is part of [Prescriptive Analytics for Python](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html).\n\n>It requires an [installation of CPLEX Optimizers](http://ibmdecisionoptimization.github.io/docplex-doc/getting_started.html)\n\nDiscover us [here](https://developer.ibm.com/docloud)\n\n\nTable of contents:\n\n* Describe the business problem\n* How decision optimization (prescriptive analytics) can help\n* Use decision optimization\n * Step 1: Import the library\n * Step 2: Model the Data\n * Step 3: Prepare the data\n * Step 4: Set up the prescriptive model\n * Define the decision variables\n * Express the business constraints\n * Express the objective\n * Solve with Decision Optimization\n * Step 5: Investigate the solution and run an example analysis\n* Summary\n\n****", "apps": [], "results": {"msg": [{"data": "This tutorial includes everything you need to set up IBM Decision Optimization CPLEX Modeling for Python (DOcplex), build a Mathematical Programming model, and get its solution by solving the model on the cloud with IBM ILOG CPLEX Optimizer.
\n\nWhen you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.
\n\n\n\n\nThis notebook is part of Prescriptive Analytics for Python.
\n
\n\n\nIt requires an installation of CPLEX Optimizers
\n
Discover us here
\n\n\nTable of contents:
\n\n* Step 1: Import the library\n
\n* Step 2: Model the Data\n
\n* Step 3: Prepare the data\n
\n* Step 4: Set up the prescriptive model\n
\n * Define the decision variables\n
\n * Express the business constraints\n
\n * Express the objective\n
\n * Solve with Decision Optimization\n
\n* Step 5: Investigate the solution and run an example analysis\n
\nDepending on the demand for electricity, we turn on or off units that generate power and which have operational properties and costs.
\n\nWith prescriptive analytics, you can:
\n\nThis notebook uses some features of pandas that are available in version 0.17.1 or above.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pip\nREQUIRED_MINIMUM_PANDAS_VERSION = '0.17.1'\ntry:\n import pandas as pd\n assert pd.__version__ >= REQUIRED_MINIMUM_PANDAS_VERSION\nexcept:\n raise Exception(\"Version \" + REQUIRED_MINIMUM_PANDAS_VERSION + \" or above of Pandas is required to run this notebook\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Use decision optimization", "apps": [], "results": {"msg": [{"data": "Run the following code to the import the Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming (docplex.mp) and Constraint Programming (docplex.cp).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport sys\ntry:\n import docplex.mp\nexcept:\n raise Exception('Please install docplex. See https://pypi.org/project/docplex/')", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 2: Model the data\n#### Load data from a *pandas* DataFrame\n\nData for the Unit Commitment Problem is provided as a *pandas* DataFrame.\nFor a standalone notebook, we provide the raw data as Python collections,\nbut real data could be loaded\nfrom an Excel sheet, also using *pandas*.", "apps": [], "results": {"msg": [{"data": "Data for the Unit Commitment Problem is provided as a pandas DataFrame.
\nFor a standalone notebook, we provide the raw data as Python collections,
\nbut real data could be loaded
\nfrom an Excel sheet, also using pandas.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pandas as pd\nfrom pandas import DataFrame, Series\n\n# make matplotlib plots appear inside the notebook\nimport matplotlib.pyplot as plt\nfrom pylab import rcParams\nrcParams['figure.figsize'] = 11, 5 ############################ <-Use this to change the plot", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nUpdate the configuration of notebook so that display matches browser window width.", "apps": [], "results": {"msg": [{"data": "Update the configuration of notebook so that display matches browser window width.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom IPython.core.display import HTML\nHTML(\"\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Available energy technologies\n\nThe following *df_energy* DataFrame stores CO2 cost information, indexed by energy type.", "apps": [], "results": {"msg": [{"data": "The following df_energy DataFrame stores CO2 cost information, indexed by energy type.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nenergies = [\"coal\", \"gas\", \"diesel\", \"wind\"]\ndf_energy = DataFrame({\"co2_cost\": [30, 5, 15, 0]}, index=energies)\n\n# Display the 'df_energy' Data Frame\ndf_energy", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe following *df_units* DataFrame stores common elements for units of a given technology.", "apps": [], "results": {"msg": [{"data": "The following df_units DataFrame stores common elements for units of a given technology.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nall_units = [\"coal1\", \"coal2\", \n \"gas1\", \"gas2\", \"gas3\", \"gas4\", \n \"diesel1\", \"diesel2\", \"diesel3\", \"diesel4\"]\n \nucp_raw_unit_data = {\n \"energy\": [\"coal\", \"coal\", \"gas\", \"gas\", \"gas\", \"gas\", \"diesel\", \"diesel\", \"diesel\", \"diesel\"],\n \"initial\" : [400, 350, 205, 52, 155, 150, 78, 76, 0, 0],\n \"min_gen\": [100, 140, 78, 52, 54.25, 39, 17.4, 15.2, 4, 2.4],\n \"max_gen\": [425, 365, 220, 210, 165, 158, 90, 87, 20, 12],\n \"operating_max_gen\": [400, 350, 205, 197, 155, 150, 78, 76, 20, 12],\n \"min_uptime\": [15, 15, 6, 5, 5, 4, 3, 3, 1, 1],\n \"min_downtime\":[9, 8, 7, 4, 3, 2, 2, 2, 1, 1],\n \"ramp_up\": [212, 150, 101.2, 94.8, 58, 50, 40, 60, 20, 12],\n \"ramp_down\": [183, 198, 95.6, 101.7, 77.5, 60, 24, 45, 20, 12],\n \"start_cost\": [5000, 4550, 1320, 1291, 1280, 1105, 560, 554, 300, 250],\n \"fixed_cost\": [208.61, 117.37, 174.12, 172.75, 95.353, 144.52, 54.417, 54.551, 79.638, 16.259],\n \"variable_cost\": [22.536, 31.985, 70.5, 69, 32.146, 54.84, 40.222, 40.522, 116.33, 76.642],\n }\n\ndf_units = DataFrame(ucp_raw_unit_data, index=all_units)\n\n# Display the 'df_units' Data Frame\ndf_units", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 3: Prepare the data", "apps": [], "results": {"msg": [{"data": "The pandas merge operation is used to create a join between the df_units and df_energy DataFrames. Here, the join is performed based on the 'energy' column of df_units and index column of df_energy.
\n\nBy default, merge performs an inner join. That is, the resulting DataFrame is based on the intersection of keys from both input DataFrames.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Add a derived co2-cost column by merging with df_energies\n# Use energy key from units and index from energy dataframe\ndf_up = pd.merge(df_units, df_energy, left_on=\"energy\", right_index=True)\ndf_up.index.names=['units']\n\n# Display first rows of new 'df_up' Data Frame\ndf_up.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThe demand is stored as a *pandas* _Series_ indexed from 1 to the number of periods.", "apps": [], "results": {"msg": [{"data": "The demand is stored as a pandas Series indexed from 1 to the number of periods.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nraw_demand = [1259.0, 1439.0, 1289.0, 1211.0, 1433.0, 1287.0, 1285.0, 1227.0, 1269.0, 1158.0, 1277.0, 1417.0, 1294.0, 1396.0, 1414.0, 1386.0,\n 1302.0, 1215.0, 1433.0, 1354.0, 1436.0, 1285.0, 1332.0, 1172.0, 1446.0, 1367.0, 1243.0, 1275.0, 1363.0, 1208.0, 1394.0, 1345.0, \n 1217.0, 1432.0, 1431.0, 1356.0, 1360.0, 1364.0, 1286.0, 1440.0, 1440.0, 1313.0, 1389.0, 1385.0, 1265.0, 1442.0, 1435.0, 1432.0, \n 1280.0, 1411.0, 1440.0, 1258.0, 1333.0, 1293.0, 1193.0, 1440.0, 1306.0, 1264.0, 1244.0, 1368.0, 1437.0, 1236.0, 1354.0, 1356.0, \n 1383.0, 1350.0, 1354.0, 1329.0, 1427.0, 1163.0, 1339.0, 1351.0, 1174.0, 1235.0, 1439.0, 1235.0, 1245.0, 1262.0, 1362.0, 1184.0, \n 1207.0, 1359.0, 1443.0, 1205.0, 1192.0, 1364.0, 1233.0, 1281.0, 1295.0, 1357.0, 1191.0, 1329.0, 1294.0, 1334.0, 1265.0, 1207.0, \n 1365.0, 1432.0, 1199.0, 1191.0, 1411.0, 1294.0, 1244.0, 1256.0, 1257.0, 1224.0, 1277.0, 1246.0, 1243.0, 1194.0, 1389.0, 1366.0, \n 1282.0, 1221.0, 1255.0, 1417.0, 1358.0, 1264.0, 1205.0, 1254.0, 1276.0, 1435.0, 1335.0, 1355.0, 1337.0, 1197.0, 1423.0, 1194.0, \n 1310.0, 1255.0, 1300.0, 1388.0, 1385.0, 1255.0, 1434.0, 1232.0, 1402.0, 1435.0, 1160.0, 1193.0, 1422.0, 1235.0, 1219.0, 1410.0, \n 1363.0, 1361.0, 1437.0, 1407.0, 1164.0, 1392.0, 1408.0, 1196.0, 1430.0, 1264.0, 1289.0, 1434.0, 1216.0, 1340.0, 1327.0, 1230.0, \n 1362.0, 1360.0, 1448.0, 1220.0, 1435.0, 1425.0, 1413.0, 1279.0, 1269.0, 1162.0, 1437.0, 1441.0, 1433.0, 1307.0, 1436.0, 1357.0, \n 1437.0, 1308.0, 1207.0, 1420.0, 1338.0, 1311.0, 1328.0, 1417.0, 1394.0, 1336.0, 1160.0, 1231.0, 1422.0, 1294.0, 1434.0, 1289.0]\nnb_periods = len(raw_demand)\nprint(\"nb periods = {}\".format(nb_periods))\n\ndemand = Series(raw_demand, index = range(1, nb_periods+1))\n\n# plot demand\ndemand.plot(title=\"Demand\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 4: Set up the prescriptive model", "apps": [], "results": {"msg": [{"data": "The model contains all the business constraints and defines the objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nfrom docplex.mp.model import Model\n\nucpm = Model(\"ucp\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Define the decision variables\n\nDecision variables are:\n\n- The variable *in_use[u,t]* is 1 if and only if unit _u_ is working at period _t_.\n- The variable *turn_on[u,t]* is 1 if and only if unit _u_ is in production at period _t_.\n- The variable *turn_off[u,t]* is 1 if unit _u_ is switched off at period _t_.\n- The variable *production[u,t]* is a continuous variables representing the production of energy for unit _u_ at period _t_.", "apps": [], "results": {"msg": [{"data": "Decision variables are:
\n\nWhenever the unit is in use, the production must be within the minimum and maximum generation.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Create a join between 'df_decision_vars' and 'df_up' Data Frames based on common index id (ie: 'units')\n# In 'df_up', one keeps only relevant columns: 'min_gen' and 'max_gen'\ndf_join_decision_vars_up = df_decision_vars.join(df_up[['min_gen', 'max_gen']], how='inner')\n\n# Display first few rows of joined Data Frames\ndf_join_decision_vars_up.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nimport pandas as pb\nprint(pd.__version__)\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# When in use, the production level is constrained to be between min and max generation.\nfor item in df_join_decision_vars_up.itertuples(index=False):\n ucpm += (item.production <= item.max_gen * item.in_use)\n ucpm += (item.production >= item.min_gen * item.in_use)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Initial state\nThe solution must take into account the initial state. The initial state of use of the unit is determined by its initial production level.", "apps": [], "results": {"msg": [{"data": "The solution must take into account the initial state. The initial state of use of the unit is determined by its initial production level.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Initial state\n# If initial production is nonzero, then period #1 is not a turn_on\n# else turn_on equals in_use\n# Dual logic is implemented for turn_off\nfor u in units:\n if df_up.initial[u] > 0:\n # if u is already running, not starting up\n ucpm.add_constraint(turn_on[u, 1] == 0)\n # turnoff iff not in use\n ucpm.add_constraint(turn_off[u, 1] + in_use[u, 1] == 1)\n else:\n # turn on at 1 iff in use at 1\n ucpm.add_constraint(turn_on[u, 1] == in_use[u, 1])\n # already off, not switched off at t==1\n ucpm.add_constraint(turn_off[u, 1] == 0)\n ucpm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Ramp-up / ramp-down constraint\nVariations of the production level over time in a unit is constrained by a ramp-up / ramp-down process.\n\nWe use the *pandas* *groupby* operation to collect all decision variables for each unit in separate series. Then, we iterate over units to post constraints enforcing the ramp-up / ramp-down process by setting upper bounds on the variation of the production level for consecutive periods.", "apps": [], "results": {"msg": [{"data": "Variations of the production level over time in a unit is constrained by a ramp-up / ramp-down process.
\n\nWe use the pandas groupby operation to collect all decision variables for each unit in separate series. Then, we iterate over units to post constraints enforcing the ramp-up / ramp-down process by setting upper bounds on the variation of the production level for consecutive periods.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Use groupby operation to process each unit\nfor unit, r in df_decision_vars.groupby(level='units'):\n u_ramp_up = df_up.ramp_up[unit]\n u_ramp_down = df_up.ramp_down[unit]\n u_initial = df_up.initial[unit]\n # Initial ramp up/down\n # Note that r.production is a Series that can be indexed as an array (ie: first item index = 0)\n ucpm.add_constraint(r.production[0] - u_initial <= u_ramp_up)\n ucpm.add_constraint(u_initial - r.production[0] <= u_ramp_down)\n for (p_curr, p_next) in zip(r.production, r.production[1:]):\n ucpm.add_constraint(p_next - p_curr <= u_ramp_up)\n ucpm.add_constraint(p_curr - p_next <= u_ramp_down)\n\n ucpm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Turn on / turn off\nThe following constraints determine when a unit is turned on or off.\n\nWe use the same *pandas* *groupby* operation as in the previous constraint to iterate over the sequence of decision variables for each unit.", "apps": [], "results": {"msg": [{"data": "The following constraints determine when a unit is turned on or off.
\n\nWe use the same pandas groupby operation as in the previous constraint to iterate over the sequence of decision variables for each unit.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Turn_on, turn_off\n# Use groupby operation to process each unit\nfor unit, r in df_decision_vars.groupby(level='units'):\n for (in_use_curr, in_use_next, turn_on_next, turn_off_next) in zip(r.in_use, r.in_use[1:], r.turn_on[1:], r.turn_off[1:]):\n # if unit is off at time t and on at time t+1, then it was turned on at time t+1\n ucpm.add_constraint(in_use_next - in_use_curr <= turn_on_next)\n\n # if unit is on at time t and time t+1, then it was not turned on at time t+1\n # mdl.add_constraint(in_use_next + in_use_curr + turn_on_next <= 2)\n\n # if unit is on at time t and off at time t+1, then it was turned off at time t+1\n ucpm.add_constraint(in_use_curr - in_use_next + turn_on_next == turn_off_next)\nucpm.print_information() ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Minimum uptime and downtime\nWhen a unit is turned on, it cannot be turned off before a *minimum uptime*. Conversely, when a unit is turned off, it cannot be turned on again before a *minimum downtime*.\n\nAgain, let's use the same *pandas* *groupby* operation to implement this constraint for each unit.", "apps": [], "results": {"msg": [{"data": "When a unit is turned on, it cannot be turned off before a minimum uptime. Conversely, when a unit is turned off, it cannot be turned on again before a minimum downtime.
\n\nAgain, let's use the same pandas groupby operation to implement this constraint for each unit.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Minimum uptime, downtime\nfor unit, r in df_decision_vars.groupby(level='units'):\n min_uptime = df_up.min_uptime[unit]\n min_downtime = df_up.min_downtime[unit]\n # Note that r.turn_on and r.in_use are Series that can be indexed as arrays (ie: first item index = 0)\n for t in range(min_uptime, nb_periods):\n ctname = \"min_up_{0!s}_{1}\".format(*r.index[t])\n ucpm.add_constraint(ucpm.sum(r.turn_on[(t - min_uptime) + 1:t + 1]) <= r.in_use[t], ctname)\n\n for t in range(min_downtime, nb_periods):\n ctname = \"min_down_{0!s}_{1}\".format(*r.index[t])\n ucpm.add_constraint(ucpm.sum(r.turn_off[(t - min_downtime) + 1:t + 1]) <= 1 - r.in_use[t], ctname)\n", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n##### Demand constraint\nTotal production level must be equal or higher than demand on any period.\n\nThis time, the *pandas* operation *groupby* is performed on *\"periods\"* since we have to iterate over the list of all units for each period.", "apps": [], "results": {"msg": [{"data": "Total production level must be equal or higher than demand on any period.
\n\nThis time, the pandas operation groupby is performed on \"periods\" since we have to iterate over the list of all units for each period.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Enforcing demand\n# we use a >= here to be more robust, \n# objective will ensure we produce efficiently\nfor period, r in df_decision_vars.groupby(level='periods'):\n total_demand = demand[period]\n ctname = \"ct_meet_demand_%d\" % period\n ucpm.add_constraint(ucpm.sum(r.production) >= total_demand, ctname) ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Express the objective\n\nOperating the different units incur different costs: fixed cost, variable cost, startup cost, co2 cost.\n\nIn a first step, we define the objective as a non-weighted sum of all these costs.\n\nThe following *pandas* *join* operation groups all the data to calculate the objective in a single DataFrame.", "apps": [], "results": {"msg": [{"data": "Operating the different units incur different costs: fixed cost, variable cost, startup cost, co2 cost.
\n\nIn a first step, we define the objective as a non-weighted sum of all these costs.
\n\nThe following pandas join operation groups all the data to calculate the objective in a single DataFrame.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# Create a join between 'df_decision_vars' and 'df_up' Data Frames based on common index ids (ie: 'units')\n# In 'df_up', one keeps only relevant columns: 'fixed_cost', 'variable_cost', 'start_cost' and 'co2_cost'\ndf_join_obj = df_decision_vars.join(\n df_up[['fixed_cost', 'variable_cost', 'start_cost', 'co2_cost']], how='inner')\n\n# Display first few rows of joined Data Frame\ndf_join_obj.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# objective\ntotal_fixed_cost = ucpm.sum(df_join_obj.in_use * df_join_obj.fixed_cost)\ntotal_variable_cost = ucpm.sum(df_join_obj.production * df_join_obj.variable_cost)\ntotal_startup_cost = ucpm.sum(df_join_obj.turn_on * df_join_obj.start_cost)\ntotal_co2_cost = ucpm.sum(df_join_obj.production * df_join_obj.co2_cost)\ntotal_economic_cost = total_fixed_cost + total_variable_cost + total_startup_cost\n\ntotal_nb_used = ucpm.sum(df_decision_vars.in_use)\ntotal_nb_starts = ucpm.sum(df_decision_vars.turn_on)\n\n# store expression kpis to retrieve them later.\nucpm.add_kpi(total_fixed_cost , \"Total Fixed Cost\")\nucpm.add_kpi(total_variable_cost, \"Total Variable Cost\")\nucpm.add_kpi(total_startup_cost , \"Total Startup Cost\")\nucpm.add_kpi(total_economic_cost, \"Total Economic Cost\")\nucpm.add_kpi(total_co2_cost , \"Total CO2 Cost\")\nucpm.add_kpi(total_nb_used, \"Total #used\")\nucpm.add_kpi(total_nb_starts, \"Total #starts\")\n\n# minimize sum of all costs\nucpm.minimize(total_fixed_cost + total_variable_cost + total_startup_cost + total_co2_cost)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Solve with Decision Optimization\n\nIf you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.", "apps": [], "results": {"msg": [{"data": "If you're using a Community Edition of CPLEX runtimes, depending on the size of the problem, the solve stage may fail and will need a paying subscription or product installation.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nucpm.print_information()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nassert ucpm.solve(), \"!!! Solve of the model fails\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nucpm.report()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n### Step 5: Investigate the solution and then run an example analysis\n\nNow let's store the results in a new *pandas* DataFrame.\n\nFor convenience, the different figures are organized into pivot tables with *periods* as row index and *units* as columns. The *pandas* *unstack* operation does this for us.", "apps": [], "results": {"msg": [{"data": "Now let's store the results in a new pandas DataFrame.
\n\nFor convenience, the different figures are organized into pivot tables with periods as row index and units as columns. The pandas unstack operation does this for us.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_prods = df_decision_vars.production.apply(lambda v: v.solution_value).unstack(level='units')\ndf_used = df_decision_vars.in_use.apply(lambda v: v.solution_value).unstack(level='units')\ndf_started = df_decision_vars.turn_on.apply(lambda v: v.solution_value).unstack(level='units')\n\n# Display the first few rows of the pivoted 'production' data\ndf_prods.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nFrom these raw DataFrame results, we can compute _derived_ results.\nFor example, for a given unit and period, the _reserve_ r(u,t) is defined as\nthe unit's maximum generation minus the current production.", "apps": [], "results": {"msg": [{"data": "From these raw DataFrame results, we can compute derived results.
\nFor example, for a given unit and period, the reserve r(u,t) is defined as
\nthe unit's maximum generation minus the current production.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_spins = DataFrame(df_up.max_gen.to_dict(), index=periods) - df_prods\n\n# Display the first few rows of the 'df_spins' Data Frame, representing the reserve for each unit, over time\ndf_spins.head()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nLet's plot the evolution of the reserves for the *\"coal2\"* unit:", "apps": [], "results": {"msg": [{"data": "Let's plot the evolution of the reserves for the \"coal2\" unit:
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_spins.coal2.plot(style='o-', ylim=[0,200])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nNow we want to sum all unit reserves to compute the _global_ spinning reserve.\nWe need to sum all columns of the DataFrame to get an aggregated time series. We use the *pandas* **sum** method\nwith axis=1 (for rows).", "apps": [], "results": {"msg": [{"data": "Now we want to sum all unit reserves to compute the global spinning reserve.
\nWe need to sum all columns of the DataFrame to get an aggregated time series. We use the pandas sum method
\nwith axis=1 (for rows).
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nglobal_spin = df_spins.sum(axis=1)\nglobal_spin.plot(title=\"Global spinning reserve\")", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Number of plants online by period\n\nThe total number of plants online at each period t is the sum of in_use variables for all units at this period.\nAgain, we use the *pandas* sum with axis=1 (for rows) to sum over all units.", "apps": [], "results": {"msg": [{"data": "The total number of plants online at each period t is the sum of in_use variables for all units at this period.
\nAgain, we use the pandas sum with axis=1 (for rows) to sum over all units.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\ndf_used.sum(axis=1).plot(title=\"Number of plants online\", kind='line', style=\"r-\", ylim=[0, len(units)])", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### Costs by period", "apps": [], "results": {"msg": [{"data": "Economic cost and CO2 cost usually push in opposite directions.
\nIn the above discussion, we have minimized the raw sum of economic cost and CO2 cost, without weights.
\nBut how good could we be on CO2, regardless of economic constraints?
\nTo know this, let's solve again with CO2 cost as the only objective.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# first retrieve the co2 and economic kpis\nco2_kpi = ucpm.kpi_by_name(\"co2\") # does a name matching\neco_kpi = ucpm.kpi_by_name(\"eco\")\nprev_co2_cost = co2_kpi.compute()\nprev_eco_cost = eco_kpi.compute()\nprint(\"* current CO2 cost is: {}\".format(prev_co2_cost))\nprint(\"* current $$$ cost is: {}\".format(prev_eco_cost))\n# now set the objective\nold_objective = ucpm.objective_expr # save it\nucpm.minimize(co2_kpi.as_expression())", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nassert ucpm.solve(), \"Solve failed\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmin_co2_cost = ucpm.objective_value\nmin_co2_eco_cost = eco_kpi.compute()\nprint(\"* absolute minimum for CO2 cost is {}\".format(min_co2_cost))\nprint(\"* at this point $$$ cost is {}\".format(min_co2_eco_cost))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAs expected, we get a significantly lower CO2 cost when minimized alone, at the price of a higher economic cost.\n\nWe could do a similar analysis for economic cost to estimate the absolute minimum of\nthe economic cost, regardless of CO2 cost.", "apps": [], "results": {"msg": [{"data": "As expected, we get a significantly lower CO2 cost when minimized alone, at the price of a higher economic cost.
\n\nWe could do a similar analysis for economic cost to estimate the absolute minimum of
\nthe economic cost, regardless of CO2 cost.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# minimize only economic cost\nucpm.minimize(eco_kpi.as_expression())", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nassert ucpm.solve(), \"Solve failed\"", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nmin_eco_cost = ucpm.objective_value\nmin_eco_co2_cost = co2_kpi.compute()\nprint(\"* absolute minimum for $$$ cost is {}\".format(min_eco_cost))\nprint(\"* at this point CO2 cost is {}\".format(min_eco_co2_cost))", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nAgain, the absolute minimum for economic cost is lower than the figure we obtained in the original model where we minimized the _sum_ of economic and CO2 costs, but here we significantly increase the CO2.\n\nBut what happens in between these two extreme points?\n\nTo investigate, we will divide the interval of CO2 cost values in smaller intervals, add an upper limit on CO2,\nand minimize economic cost with this constraint. This will give us a Pareto optimal point with at most this CO2 value.\n\nTo avoid adding many constraints, we add only one constraint with an extra variable, and we change only the upper bound\nof this CO2 limit variable between successive solves.\n\nThen we iterate (with a fixed number of iterations) and collect the cost values. ", "apps": [], "results": {"msg": [{"data": "Again, the absolute minimum for economic cost is lower than the figure we obtained in the original model where we minimized the sum of economic and CO2 costs, but here we significantly increase the CO2.
\n\nBut what happens in between these two extreme points?
\n\nTo investigate, we will divide the interval of CO2 cost values in smaller intervals, add an upper limit on CO2,
\nand minimize economic cost with this constraint. This will give us a Pareto optimal point with at most this CO2 value.
\n\nTo avoid adding many constraints, we add only one constraint with an extra variable, and we change only the upper bound
\nof this CO2 limit variable between successive solves.
\n\nThen we iterate (with a fixed number of iterations) and collect the cost values.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# add extra variable\nco2_limit = ucpm.continuous_var(lb=0)\n# add a named constraint which limits total co2 cost to this variable:\nmax_co2_ctname = \"ct_max_co2\"\nco2_ct = ucpm.add_constraint(co2_kpi.as_expression() <= co2_limit, max_co2_ctname) ", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\nco2min = min_co2_cost\nco2max = min_eco_co2_cost\ndef explore_ucp(nb_iters, eps=1e-5):\n\n step = (co2max-co2min)/float(nb_iters)\n co2_ubs = [co2min + k * step for k in range(nb_iters+1)]\n\n # ensure we minimize eco\n ucpm.minimize(eco_kpi.as_expression())\n all_co2s = []\n all_ecos = []\n for k in range(nb_iters+1):\n co2_ub = co2min + k * step\n print(\" iteration #{0} co2_ub={1}\".format(k, co2_ub))\n co2_limit.ub = co2_ub + eps\n assert ucpm.solve() is not None, \"Solve failed\"\n cur_co2 = co2_kpi.compute()\n cur_eco = eco_kpi.compute()\n all_co2s.append(cur_co2)\n all_ecos.append(cur_eco)\n return all_co2s, all_ecos", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n#explore the co2/eco frontier in 50 points\nco2s, ecos = explore_ucp(nb_iters=50)", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%python\n# normalize all values by dividing by their maximum\neco_max = min_co2_eco_cost\nnxs = [c / co2max for c in co2s]\nnys = [e / eco_max for e in ecos]\n# plot a scatter chart of x=co2, y=costs\nplt.scatter(nxs, nys)\n# plot as one point\nplt.plot(prev_co2_cost/co2max, prev_eco_cost/eco_max, \"rH\", markersize=16)\nplt.xlabel(\"co2 cost\")\nplt.ylabel(\"economic cost\")\nplt.show()", "apps": [], "results": {"msg": [{"data": "", "type": "ANGULAR"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": false, "language": "python"}, "editorMode": "ace/mode/python", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\nThis figure demonstrates that the result obtained in the initial model clearly favored\neconomic cost over CO2 cost: CO2 cost is well above 95% of its maximum value.", "apps": [], "results": {"msg": [{"data": "This figure demonstrates that the result obtained in the initial model clearly favored
\neconomic cost over CO2 cost: CO2 cost is well above 95% of its maximum value.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n## Summary\n\nYou learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.", "apps": [], "results": {"msg": [{"data": "You learned how to set up and use IBM Decision Optimization CPLEX Modeling for Python to formulate a Mathematical Programming model and solve it with IBM Decision Optimization on Cloud.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}, {"settings": {"forms": {}, "params": {}}, "text": "%md\n#### References\n* [CPLEX Modeling for Python documentation](https://rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/index.html)\n* [Decision Optimization on Cloud](https://developer.ibm.com/docloud/)\n* Need help with DOcplex or to report a bug? Please go [here](https://developer.ibm.com/answers/smartspace/docloud).\n* Contact us at dofeedback@wwpdl.vnet.ibm.com.", "apps": [], "results": {"msg": [{"data": "Copyright \u00a9 2017-2018 IBM. IPLA licensed Sample Materials.
\n", "type": "HTML"}], "code": "SUCCESS"}, "user": "anonymous", "config": {"editorSetting": {"editOnDblClick": true, "language": "markdown"}, "editorMode": "ace/mode/markdown", "colWidth": 12, "enabled": true, "results": {}}}]} \ No newline at end of file