diff --git "a/training/src/.ipynb_checkpoints/MSML-602-HW1-checkpoint.ipynb" "b/training/src/.ipynb_checkpoints/MSML-602-HW1-checkpoint.ipynb" new file mode 100644--- /dev/null +++ "b/training/src/.ipynb_checkpoints/MSML-602-HW1-checkpoint.ipynb" @@ -0,0 +1,1114 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 13, + "id": "90b406fa-994c-4ce8-9d8d-2cf7e9358915", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Data for sum\n", + " x P(X) x * P(X)\n", + "0 10 0.125000 1.250000\n", + "1 11 0.125000 1.375000\n", + "2 9 0.115741 1.041667\n", + "3 12 0.115741 1.388889\n", + "4 8 0.097222 0.777778\n", + "5 13 0.097222 1.263889\n", + "6 7 0.069444 0.486111\n", + "7 14 0.069444 0.972222\n", + "8 6 0.046296 0.277778\n", + "9 15 0.046296 0.694444\n", + "10 5 0.027778 0.138889\n", + "11 16 0.027778 0.444444\n", + "12 4 0.013889 0.055556\n", + "13 17 0.013889 0.236111\n", + "14 3 0.004630 0.013889\n", + "15 18 0.004630 0.083333\n", + "\n", + "Expectation for sum: 10.5\n", + "\n", + "Data for product\n", + " x P(X) x * P(X)\n", + "0 12 0.069444 0.833333\n", + "1 24 0.069444 1.666667\n", + "2 30 0.055556 1.666667\n", + "3 60 0.055556 3.333333\n", + "4 36 0.055556 2.000000\n", + "5 18 0.041667 0.750000\n", + "6 72 0.041667 3.000000\n", + "7 6 0.041667 0.250000\n", + "8 48 0.041667 2.000000\n", + "9 20 0.041667 0.833333\n", + "10 8 0.032407 0.259259\n", + "11 90 0.027778 2.500000\n", + "12 40 0.027778 1.111111\n", + "13 16 0.027778 0.444444\n", + "14 10 0.027778 0.277778\n", + "15 4 0.027778 0.111111\n", + "16 15 0.027778 0.416667\n", + "17 120 0.027778 3.333333\n", + "18 32 0.013889 0.444444\n", + "19 25 0.013889 0.347222\n", + "20 108 0.013889 1.500000\n", + "21 100 0.013889 1.388889\n", + "22 96 0.013889 1.333333\n", + "23 3 0.013889 0.041667\n", + "24 80 0.013889 1.111111\n", + "25 75 0.013889 1.041667\n", + "26 150 0.013889 2.083333\n", + "27 144 0.013889 2.000000\n", + "28 5 0.013889 0.069444\n", + "29 180 0.013889 2.500000\n", + "30 50 0.013889 0.694444\n", + "31 9 0.013889 0.125000\n", + "32 45 0.013889 0.625000\n", + "33 2 0.013889 0.027778\n", + "34 54 0.013889 0.750000\n", + "35 1 0.004630 0.004630\n", + "36 125 0.004630 0.578704\n", + "37 64 0.004630 0.296296\n", + "38 27 0.004630 0.125000\n", + "39 216 0.004630 1.000000\n", + "\n", + " Expectation for product 42.875\n" + ] + } + ], + "source": [ + "# Problem 4\n", + "\n", + "import pandas as pd\n", + " \n", + "dice1 = [1, 2, 3, 4, 5, 6]\n", + "dice2 = [1, 2, 3, 4, 5, 6]\n", + "dice3 = [1, 2, 3, 4, 5, 6]\n", + "\n", + "\n", + "data = [[d1, d2, d3, d1 + d2 + d3, d1 * d2 * d3] for d1 in dice1 for d2 in dice2 for d3 in dice3]\n", + "\n", + "df = pd.DataFrame(data, columns=[\"dice1\", \"dice2\", \"dice3\", \"sum_of_dots\", \"product_of_dots\"])\n", + "total_count = len(dice1) * len(dice2) * len(dice3)\n", + "\n", + "# Expectation of sum of number of dots on the three rolls\n", + "sum_pmf = [(x[0], count_x / (total_count * 1.0)) for x, count_x in df.value_counts([\"sum_of_dots\"]).items()]\n", + "sum_pmf_df = pd.DataFrame(sum_pmf, columns=[\"x\", \"P(X)\"])\n", + "sum_pmf_df[\"x * P(X)\"] = sum_pmf_df[\"x\"] * sum_pmf_df[\"P(X)\"] \n", + "expectation_sum = sum_pmf_df[\"x * P(X)\"].sum()\n", + "\n", + "# Expectation of product of number of dots on the three rolls\n", + "product_pmf = [(x[0], count_x / (total_count * 1.0)) for x, count_x in df.value_counts([\"product_of_dots\"]).items()]\n", + "product_pmf_df = pd.DataFrame(product_pmf, columns=[\"x\", \"P(X)\"])\n", + "product_pmf_df[\"x * P(X)\"] = product_pmf_df[\"x\"] * product_pmf_df[\"P(X)\"] \n", + "expectation_product = product_pmf_df[\"x * P(X)\"].sum()\n", + "\n", + "print(\"\\nData for sum\")\n", + "print(sum_pmf_df)\n", + "print(\"\\nExpectation for sum: {}\".format(expectation_sum))\n", + "\n", + "print(\"\\nData for product\")\n", + "print(product_pmf_df)\n", + "print(\"\\n Expectation for product {}\".format(expectation_product))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "74441428-8bb6-4f30-8f48-52feafa735d6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Welcome to the CBC MILP Solver \n", + "Version: 2.10.3 \n", + "Build Date: Dec 15 2019 \n", + "\n", + "command line - /opt/conda/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/b6c9e0371f914493bd8e01c99d488dc1-pulp.mps max timeMode elapsed branch printingOptions all solution /tmp/b6c9e0371f914493bd8e01c99d488dc1-pulp.sol (default strategy 1)\n", + "At line 2 NAME MODEL\n", + "At line 3 ROWS\n", + "At line 9 COLUMNS\n", + "At line 20 RHS\n", + "At line 25 BOUNDS\n", + "At line 29 ENDATA\n", + "Problem MODEL has 4 rows, 3 columns and 7 elements\n", + "Coin0008I MODEL read with 0 errors\n", + "Option for timeMode changed from cpu to elapsed\n", + "Presolve 0 (-4) rows, 0 (-3) columns and 0 (-7) elements\n", + "Empty problem - 0 rows, 0 columns and 0 elements\n", + "Optimal - objective value 148.4\n", + "After Postsolve, objective 148.4, infeasibilities - dual 0 (0), primal 0 (0)\n", + "Optimal objective 148.4 - 0 iterations time 0.002, Presolve 0.00\n", + "Option for printingOptions changed from normal to all\n", + "Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00\n", + "\n", + "Solution:\n" + ] + }, + { + "data": { + "text/html": [ + "
VariableValue
X8.6
Y8.4
Z2.6
Objective148.4
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "## Problem 5\n", + "from pulp import *\n", + "from IPython.display import HTML, display\n", + "\n", + "def display_table(table):\n", + " display(HTML(\n", + " '{}
'.format(\n", + " ''.join(\n", + " '{}'.format(''.join(str(_) for _ in row)) for row in table)\n", + " )\n", + " ))\n", + " \n", + "problem = LpProblem('MSML_602_PCS2_HW1_Q5', LpMaximize)\n", + "\n", + "X = LpVariable('X', cat='Continuous')\n", + "Y = LpVariable('Y', cat='Continuous')\n", + "Z = LpVariable('Z', cat='Continuous')\n", + "\n", + "problem += 15 * X + 2 * Y + Z, \"Objective Function\"\n", + "problem += X <= 10, \"Constraint X\"\n", + "problem += X + Y <= 17, \"Constraint X, Y\"\n", + "problem += 2 * X + 3 * Z <= 25, \"Constraint X, Z\"\n", + "problem += Y + Z >= 11, \"Constraint Y, Z\"\n", + "\n", + "problem.solve()\n", + "print(\"Solution:\")\n", + "\n", + "data = [[\"Variable\", \"Value\"]] + [[v.name, v.varValue] for v in problem.variables()]\n", + "data += [[\"Objective\", problem.objective.value()]]\n", + "\n", + "display_table(data)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "96979ae9-7c40-41e9-bef1-ec1ef9e89e9e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Welcome to the CBC MILP Solver \n", + "Version: 2.10.3 \n", + "Build Date: Dec 15 2019 \n", + "\n", + "command line - /opt/conda/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/7efaabba2ec74d7a9fa959ed5c88312d-pulp.mps timeMode elapsed branch printingOptions all solution /tmp/7efaabba2ec74d7a9fa959ed5c88312d-pulp.sol (default strategy 1)\n", + "At line 2 NAME MODEL\n", + "At line 3 ROWS\n", + "At line 10 COLUMNS\n", + "At line 65 RHS\n", + "At line 71 BOUNDS\n", + "At line 84 ENDATA\n", + "Problem MODEL has 5 rows, 12 columns and 18 elements\n", + "Coin0008I MODEL read with 0 errors\n", + "Option for timeMode changed from cpu to elapsed\n", + "Continuous objective value is 19 - 0.00 seconds\n", + "Cgl0004I processed model has 5 rows, 11 columns (11 integer (11 of which binary)) and 18 elements\n", + "Cutoff increment increased from 1e-05 to 0.9999\n", + "Cbc0038I Initial state - 0 integers unsatisfied sum - 0\n", + "Cbc0038I Solution found of 19\n", + "Cbc0038I Before mini branch and bound, 11 integers at bound fixed and 0 continuous\n", + "Cbc0038I Mini branch and bound did not improve solution (0.00 seconds)\n", + "Cbc0038I After 0.00 seconds - Feasibility pump exiting with objective of 19 - took 0.00 seconds\n", + "Cbc0012I Integer solution of 19 found by feasibility pump after 0 iterations and 0 nodes (0.00 seconds)\n", + "Cbc0001I Search completed - best objective 19, took 0 iterations and 0 nodes (0.00 seconds)\n", + "Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost\n", + "Cuts at root node changed objective from 19 to 19\n", + "Probing was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Gomory was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Knapsack was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Clique was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "MixedIntegerRounding2 was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "FlowCover was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "TwoMirCuts was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "ZeroHalf was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "\n", + "Result - Optimal solution found\n", + "\n", + "Objective value: 19.00000000\n", + "Enumerated nodes: 0\n", + "Total iterations: 0\n", + "Time (CPU seconds): 0.00\n", + "Time (Wallclock seconds): 0.00\n", + "\n", + "Option for printingOptions changed from normal to all\n", + "Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00\n", + "\n", + "Shortest distance from v1 to v5 = 19.0\n", + "['v1->v3', 'v3->v4', 'v4->v5']\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/opt/conda/lib/python3.9/site-packages/pulp/pulp.py:1352: UserWarning: Spaces are not permitted in the name. Converted to '_'\n", + " warnings.warn(\"Spaces are not permitted in the name. Converted to '_'\")\n" + ] + } + ], + "source": [ + "# HW1 Problem 6\n", + "\n", + "from pulp import *\n", + "import networkx as nx\n", + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "\n", + "# I assumed the following arbitrary graph\n", + "G = nx.Graph()\n", + "G.add_edge(\"v1\", \"v2\", weight=12)\n", + "G.add_edge(\"v1\", \"v3\", weight=5)\n", + "G.add_edge(\"v1\", \"v5\", weight=25)\n", + "G.add_edge(\"v2\", \"v5\", weight=10)\n", + "G.add_edge(\"v3\", \"v4\", weight=6)\n", + "G.add_edge(\"v4\", \"v5\", weight=8)\n", + "\n", + "# I am finding the shortest path from vertex 1 to vertex 5\n", + "source = \"v1\"\n", + "target = \"v5\"\n", + "\n", + "elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d[\"weight\"] > 0.5]\n", + "esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d[\"weight\"] <= 0.5]\n", + "\n", + "pos = nx.spring_layout(G, seed=7) \n", + "\n", + "# nodes\n", + "nx.draw_networkx_nodes(G, pos, node_size=700)\n", + "\n", + "# edges\n", + "nx.draw_networkx_edges(G, pos, edgelist=elarge, width=6)\n", + "nx.draw_networkx_edges(\n", + " G, pos, edgelist=esmall, width=6, alpha=0.5, edge_color=\"b\", style=\"dashed\"\n", + ")\n", + "\n", + "# node labels\n", + "nx.draw_networkx_labels(G, pos, font_size=20, font_family=\"sans-serif\")\n", + "# edge weight labels\n", + "edge_labels = nx.get_edge_attributes(G, \"weight\")\n", + "nx.draw_networkx_edge_labels(G, pos, edge_labels)\n", + "\n", + "ax = plt.gca()\n", + "ax.margins(0.08)\n", + "plt.axis(\"off\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "\n", + "prob = pulp.LpProblem(\"Shortest Path Problem\", LpMinimize)\n", + "cost = nx.get_edge_attributes(G, \"weight\")\n", + "target_vars = {}\n", + "\n", + "for i, j in G.edges:\n", + " x = LpVariable(\"x_{0}_{1}\".format(i,j), cat=\"Binary\")\n", + " y = LpVariable(\"x_{0}_{1}\".format(j, i), cat=\"Binary\")\n", + " target_vars[i, j] = x\n", + " target_vars[j, i] = y\n", + "\n", + "prob += lpSum([cost[i, j] * target_vars[i, j] for i, j in G.edges] + [cost[i, j] * target_vars[j, i] for i, j in G.edges]), \"Objective function\"\n", + "\n", + "for node in G.nodes:\n", + " if node == source:\n", + " prob += pulp.lpSum([target_vars[i, j] for i, j in target_vars if i == node]) == 1\n", + " elif node == target:\n", + " prob += pulp.lpSum([target_vars[i, j] for i, j in target_vars if j == node]) == 1\n", + " else:\n", + " prob += pulp.lpSum([target_vars[i, j] for i, j in target_vars if i == node]) - pulp.lpSum([target_vars[i, j] for i, j in target_vars if j == node]) == 0\n", + "\n", + "prob.solve()\n", + "print(\"Shortest distance from {0} to {1} = \".format(source, target), value(prob.objective))\n", + "\n", + "chosen_vars = list(filter(lambda v: v.varValue > 0, prob.variables()))\n", + "routes = list(map(lambda x: x.name.replace(\"x_\", \"\").replace(\"_\", \"->\"), chosen_vars))\n", + "print(routes)\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "dc74b8c2-e352-4284-b9f6-c936d1a7604d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('job1', 'cpu1'), ('job1', 'cpu2'), ('job1', 'cpu3'), ('job1', 'cpu4'), ('job2', 'cpu1'), ('job2', 'cpu2'), ('job2', 'cpu3'), ('job2', 'cpu4'), ('job3', 'cpu1'), ('job3', 'cpu2'), ('job3', 'cpu3'), ('job3', 'cpu4'), ('job4', 'cpu1'), ('job4', 'cpu2'), ('job4', 'cpu3'), ('job4', 'cpu4')]\n", + "Welcome to the CBC MILP Solver \n", + "Version: 2.10.3 \n", + "Build Date: Dec 15 2019 \n", + "\n", + "command line - /opt/conda/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/c85182008d6145a5a1478dcbce27ffa7-pulp.mps timeMode elapsed branch printingOptions all solution /tmp/c85182008d6145a5a1478dcbce27ffa7-pulp.sol (default strategy 1)\n", + "At line 2 NAME MODEL\n", + "At line 3 ROWS\n", + "At line 13 COLUMNS\n", + "At line 94 RHS\n", + "At line 103 BOUNDS\n", + "At line 120 ENDATA\n", + "Problem MODEL has 8 rows, 16 columns and 32 elements\n", + "Coin0008I MODEL read with 0 errors\n", + "Option for timeMode changed from cpu to elapsed\n", + "Continuous objective value is 10 - 0.00 seconds\n", + "Cgl0004I processed model has 8 rows, 16 columns (16 integer (16 of which binary)) and 32 elements\n", + "Cutoff increment increased from 1e-05 to 0.9999\n", + "Cbc0038I Initial state - 0 integers unsatisfied sum - 0\n", + "Cbc0038I Solution found of 10\n", + "Cbc0038I Before mini branch and bound, 16 integers at bound fixed and 0 continuous\n", + "Cbc0038I Mini branch and bound did not improve solution (0.00 seconds)\n", + "Cbc0038I After 0.00 seconds - Feasibility pump exiting with objective of 10 - took 0.00 seconds\n", + "Cbc0012I Integer solution of 10 found by feasibility pump after 0 iterations and 0 nodes (0.00 seconds)\n", + "Cbc0001I Search completed - best objective 10, took 0 iterations and 0 nodes (0.00 seconds)\n", + "Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost\n", + "Cuts at root node changed objective from 10 to 10\n", + "Probing was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Gomory was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Knapsack was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Clique was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "MixedIntegerRounding2 was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "FlowCover was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "TwoMirCuts was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "ZeroHalf was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "\n", + "Result - Optimal solution found\n", + "\n", + "Objective value: 10.00000000\n", + "Enumerated nodes: 0\n", + "Total iterations: 0\n", + "Time (CPU seconds): 0.00\n", + "Time (Wallclock seconds): 0.00\n", + "\n", + "Option for printingOptions changed from normal to all\n", + "Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00\n", + "\n", + "############ TIME COST MATRIX\n", + "{'job1': {'cpu1': 2, 'cpu2': 6, 'cpu3': 5, 'cpu4': 4}, 'job2': {'cpu1': 4, 'cpu2': 6, 'cpu3': 7, 'cpu4': 9}, 'job3': {'cpu1': 8, 'cpu2': 3, 'cpu3': 4, 'cpu4': 1}, 'job4': {'cpu1': 2, 'cpu2': 3, 'cpu3': 1, 'cpu4': 1}}\n", + "################## VARIABLES\n", + "{'job1': {'cpu1': time_job1_cpu1, 'cpu2': time_job1_cpu2, 'cpu3': time_job1_cpu3, 'cpu4': time_job1_cpu4}, 'job2': {'cpu1': time_job2_cpu1, 'cpu2': time_job2_cpu2, 'cpu3': time_job2_cpu3, 'cpu4': time_job2_cpu4}, 'job3': {'cpu1': time_job3_cpu1, 'cpu2': time_job3_cpu2, 'cpu3': time_job3_cpu3, 'cpu4': time_job3_cpu4}, 'job4': {'cpu1': time_job4_cpu1, 'cpu2': time_job4_cpu2, 'cpu3': time_job4_cpu3, 'cpu4': time_job4_cpu4}}\n", + "########### VALUES ##########\n", + "time_job1_cpu1 = 1.0\n", + "time_job1_cpu2 = 0.0\n", + "time_job1_cpu3 = 0.0\n", + "time_job1_cpu4 = 0.0\n", + "time_job2_cpu1 = 0.0\n", + "time_job2_cpu2 = 1.0\n", + "time_job2_cpu3 = 0.0\n", + "time_job2_cpu4 = 0.0\n", + "time_job3_cpu1 = 0.0\n", + "time_job3_cpu2 = 0.0\n", + "time_job3_cpu3 = 0.0\n", + "time_job3_cpu4 = 1.0\n", + "time_job4_cpu1 = 0.0\n", + "time_job4_cpu2 = 0.0\n", + "time_job4_cpu3 = 1.0\n", + "time_job4_cpu4 = 0.0\n", + "\n", + "####### JOB ASSIGNMENTS ######\n", + "\n", + "job1 is assigned to ['cpu1']\n", + "job2 is assigned to ['cpu2']\n", + "job3 is assigned to ['cpu4']\n", + "job4 is assigned to ['cpu3']\n", + "\n", + "Value of Objective Function = 10.0\n" + ] + } + ], + "source": [ + "## Problem 8a\n", + "\n", + "from pulp import *\n", + "import random\n", + "\n", + "cpus=[\"cpu1\", \"cpu2\", \"cpu3\", \"cpu4\"]\n", + "jobs=[\"job1\", \"job2\", \"job3\", \"job4\"]\n", + "\n", + "\n", + "\n", + "prob = LpProblem(\"CPU Assignment\", LpMinimize) \n", + "time_values = {\n", + " 'job1': {'cpu1': 2, 'cpu2': 6, 'cpu3': 5, 'cpu4': 4}, \n", + " 'job2': {'cpu1': 4, 'cpu2': 6, 'cpu3': 7, 'cpu4': 9}, \n", + " 'job3': {'cpu1': 8, 'cpu2': 3, 'cpu3': 4, 'cpu4': 1}, \n", + " 'job4': {'cpu1': 2, 'cpu2': 3, 'cpu3': 1, 'cpu4': 1}\n", + "}\n", + "time_vars = {}\n", + "for j in jobs:\n", + " time_vars[j] = {}\n", + " for c in cpus:\n", + " time_vars[j][c] = LpVariable(\"time_{0}_{1}\".format(j,c), 0, None, LpInteger)\n", + "\n", + " \n", + "job_cpu_combinations = [(j, c) for j in jobs for c in cpus]\n", + "print(job_cpu_combinations)\n", + "\n", + "prob += (\n", + " lpSum([time_vars[j][c] * time_values[j][c] for (j, c) in job_cpu_combinations]),\n", + " \"Sum_of_Assignment_Costs\",\n", + ")\n", + "\n", + "\n", + "for j in jobs:\n", + " prob+= lpSum(time_vars[j][c] for c in cpus) == 1\n", + "\n", + "for c in cpus:\n", + " prob+= lpSum(time_vars[j][c] for j in jobs) == 1\n", + " \n", + "prob.solve()\n", + "\n", + "print(\"############ TIME COST MATRIX\")\n", + "print(time_values)\n", + "print(\"################## VARIABLES\")\n", + "print(time_vars)\n", + "print(\"########### VALUES ##########\")\n", + "for v in prob.variables():\n", + " print(v.name, \"=\", v.varValue)\n", + "\n", + "\n", + "print(\"\\n####### JOB ASSIGNMENTS ######\\n\")\n", + "assignments = { }\n", + "for job in time_vars:\n", + " cpus = time_vars[job]\n", + " assigned = []\n", + " for cpu in cpus:\n", + " if cpus[cpu].varValue == 1:\n", + " assigned.append(cpu)\n", + " assignments[job] = assigned\n", + " print(\"{0} is assigned to {1}\".format(job, assigned))\n", + "\n", + "print(\"\\nValue of Objective Function = \", value(prob.objective))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "fb2eebbd-59a0-4301-8057-e725ff3cf2ae", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "############ TIME COST MATRIX\n", + "{'cpu1': {'job1': 2, 'job2': 7}, 'cpu2': {'job1': 1, 'job2': 3}}\n", + "################## VARIABLES\n", + "{'cpu1': {'job1': time_job1_cpu1, 'job2': time_job2_cpu1}, 'cpu2': {'job1': time_job1_cpu2, 'job2': time_job2_cpu2}}\n", + "#############################\n", + "[('cpu1', 'job1'), ('cpu1', 'job2'), ('cpu2', 'job1'), ('cpu2', 'job2')]\n", + "Welcome to the CBC MILP Solver \n", + "Version: 2.10.3 \n", + "Build Date: Dec 15 2019 \n", + "\n", + "command line - /opt/conda/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/06652fcfafa94d56aa62c1066888fd9d-pulp.mps timeMode elapsed branch printingOptions all solution /tmp/06652fcfafa94d56aa62c1066888fd9d-pulp.sol (default strategy 1)\n", + "At line 2 NAME MODEL\n", + "At line 3 ROWS\n", + "At line 9 COLUMNS\n", + "At line 30 RHS\n", + "At line 35 BOUNDS\n", + "At line 40 ENDATA\n", + "Problem MODEL has 4 rows, 4 columns and 8 elements\n", + "Coin0008I MODEL read with 0 errors\n", + "Option for timeMode changed from cpu to elapsed\n", + "Continuous objective value is 5 - 0.00 seconds\n", + "Cgl0004I processed model has 0 rows, 0 columns (0 integer (0 of which binary)) and 0 elements\n", + "Cbc3007W No integer variables - nothing to do\n", + "Cuts at root node changed objective from 5 to -1.79769e+308\n", + "Probing was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Gomory was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Knapsack was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "Clique was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "MixedIntegerRounding2 was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "FlowCover was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "TwoMirCuts was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "ZeroHalf was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "\n", + "Result - Optimal solution found\n", + "\n", + "Objective value: 5.00000000\n", + "Enumerated nodes: 0\n", + "Total iterations: 0\n", + "Time (CPU seconds): 0.00\n", + "Time (Wallclock seconds): 0.00\n", + "\n", + "Option for printingOptions changed from normal to all\n", + "Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00\n", + "\n", + "time_job1_cpu1 = 1.0\n", + "time_job1_cpu2 = 0.0\n", + "time_job2_cpu1 = 0.0\n", + "time_job2_cpu2 = 1.0\n", + "Value of Objective Function = 5.0\n" + ] + } + ], + "source": [ + "# Problem 8b\n", + "from pulp import *\n", + "import random\n", + "\n", + "cpus=[\"cpu1\", \"cpu2\"]\n", + "jobs=[\"job1\", \"job2\"]\n", + "\n", + "time_values = {\n", + " \"cpu1\": {\"job1\": 2, \"job2\": 7 },\n", + " \"cpu2\": {\"job1\": 1, \"job2\": 3 }\n", + "}\n", + "\n", + "prob = LpProblem(\"CPU Assignment\", LpMinimize) \n", + "time_vars = {}\n", + "for c in cpus:\n", + " time_vars[c] = {}\n", + " for j in jobs:\n", + " time_vars[c][j] = LpVariable(\"time_{0}_{1}\".format(j,c), 0, cat=\"Integer\")\n", + "\n", + "print(\"############ TIME COST MATRIX\")\n", + "print(time_values)\n", + "print(\"################## VARIABLES\")\n", + "print(time_vars)\n", + "print(\"#############################\")\n", + "cpu_job_combinations = [(c, j) for c in cpus for j in jobs]\n", + "print(cpu_job_combinations)\n", + "\n", + "prob += (\n", + " lpSum([time_vars[c][j] * time_values[c][j] for (c, j) in cpu_job_combinations]),\n", + " \"Sum_of_Assignment_Costs\",\n", + ")\n", + "\n", + "\n", + "for j in jobs:\n", + " prob+= lpSum(time_vars[c][j] for c in cpus) == 1\n", + "\n", + "for c in cpus:\n", + " prob+= lpSum(time_vars[c][j] for j in jobs) == 1\n", + "prob.solve()\n", + "\n", + "for v in prob.variables():\n", + " print(v.name, \"=\", v.varValue)\n", + " \n", + "print(\"Value of Objective Function = \", value(prob.objective))" + ] + }, + { + "cell_type": "markdown", + "id": "ae8280c4-63a0-43d6-b879-89aa85d542ba", + "metadata": {}, + "source": [ + "### Integer LP VS LP Relaxation \n", + "\n", + "I have assumed the following costs for each job, cpu combination:\n", + "\n", + "| | cpu1 | cpu2 |\n", + "|-|------|------|\n", + "|job1|2|1|\n", + "|job2|7|3|\n", + "\n", + "I have set up the following variables in PulPfor ILP & LP Relaxation respectively:\n", + "\n", + "**For ILP**\n", + "\n", + "The variable category is set as Integer \n", + "\n", + "| | cpu1 | cpu2 |\n", + "|-|------|------|\n", + "|job1|x-j1c1-integer|x-j1c2-integer|\n", + "|job2|x-j2c1-integer|x-j2c2-integer|\n", + "\n", + "**For LP Relaxation**\n", + "\n", + "The variable category is set as Continuous\n", + "\n", + "| | cpu1 | cpu2 |\n", + "|-|------|------|\n", + "|job1|x-j1c1-continuous|x-j1c2-continuous|\n", + "|job2|x-j2c1-continuous|x-j2c2-continuous|\n", + "\n", + "I defined two different problems:\n", + "- `prob_integer` for ILP\n", + "- `prob_relaxed` for LP Relaxation \n", + "\n", + "\n", + "### Findings:\n", + "I get the same solution for bot ILP and LP Relaxation. I could not find an optimal solution for LP Relaxation that is lower than the ILP solution.\n", + "\n", + "Here were my results:\n", + "\n", + "**For ILP**\n", + "\n", + "| | cpu1 | cpu2 |\n", + "|-|------|------|\n", + "|job1|1|0|\n", + "|job2|0|1|\n", + "\n", + "Value of Objective Function: 5.0\n", + "\n", + "**For LP Relaxation**\n", + "\n", + "| | cpu1 | cpu2 |\n", + "|-|------|------|\n", + "|job1|1|0|\n", + "|job2|0|1|\n", + "\n", + "Value of Objective Function: 5.0" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0fc0adbe-7980-4ae3-b5f0-9b73e64b902b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU_Assignment_Relaxed:\n", + "MINIMIZE\n", + "2.0*job_1_cpu_1_cont + 1.0*job_1_cpu_2_cont + 7.0*job_2_cpu_1_cont + 3.0*job_2_cpu_2_cont + 0.0\n", + "SUBJECT TO\n", + "_C1: job_1_cpu_1_cont >= 0\n", + "\n", + "_C2: job_1_cpu_1_cont <= 1\n", + "\n", + "_C3: job_2_cpu_1_cont >= 0\n", + "\n", + "_C4: job_2_cpu_1_cont <= 1\n", + "\n", + "_C5: job_1_cpu_2_cont >= 0\n", + "\n", + "_C6: job_1_cpu_2_cont <= 1\n", + "\n", + "_C7: job_2_cpu_2_cont >= 0\n", + "\n", + "_C8: job_2_cpu_2_cont <= 1\n", + "\n", + "_C9: job_1_cpu_1_cont + job_1_cpu_2_cont = 1\n", + "\n", + "_C10: job_2_cpu_1_cont + job_2_cpu_2_cont = 1\n", + "\n", + "_C11: job_1_cpu_1_cont + job_2_cpu_1_cont = 1\n", + "\n", + "_C12: job_1_cpu_2_cont + job_2_cpu_2_cont = 1\n", + "\n", + "VARIABLES\n", + "job_1_cpu_1_cont free Continuous\n", + "job_1_cpu_2_cont free Continuous\n", + "job_2_cpu_1_cont free Continuous\n", + "job_2_cpu_2_cont free Continuous\n", + "\n", + "Welcome to the CBC MILP Solver \n", + "Version: 2.10.3 \n", + "Build Date: Dec 15 2019 \n", + "\n", + "command line - /opt/conda/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/1ae75808cf8a4b5f8ae6348d6e1229dc-pulp.mps timeMode elapsed branch printingOptions all solution /tmp/1ae75808cf8a4b5f8ae6348d6e1229dc-pulp.sol (default strategy 1)\n", + "At line 2 NAME MODEL\n", + "At line 3 ROWS\n", + "At line 9 COLUMNS\n", + "At line 30 RHS\n", + "At line 35 BOUNDS\n", + "At line 40 ENDATA\n", + "Problem MODEL has 4 rows, 4 columns and 8 elements\n", + "Coin0008I MODEL read with 0 errors\n", + "Option for timeMode changed from cpu to elapsed\n", + "Problem is unbounded - 0.00 seconds\n", + "Option for printingOptions changed from normal to all\n", + "Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00\n", + "\n", + "Welcome to the CBC MILP Solver \n", + "Version: 2.10.3 \n", + "Build Date: Dec 15 2019 \n", + "\n", + "command line - /opt/conda/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/57fe04c5ac14421b9bed79f136159511-pulp.mps timeMode elapsed branch printingOptions all solution /tmp/57fe04c5ac14421b9bed79f136159511-pulp.sol (default strategy 1)\n", + "At line 2 NAME MODEL\n", + "At line 3 ROWS\n", + "At line 17 COLUMNS\n", + "At line 38 RHS\n", + "At line 51 BOUNDS\n", + "At line 56 ENDATA\n", + "Problem MODEL has 12 rows, 4 columns and 16 elements\n", + "Coin0008I MODEL read with 0 errors\n", + "Option for timeMode changed from cpu to elapsed\n", + "Presolve 0 (-12) rows, 0 (-4) columns and 0 (-16) elements\n", + "Empty problem - 0 rows, 0 columns and 0 elements\n", + "Optimal - objective value 5\n", + "After Postsolve, objective 5, infeasibilities - dual 0 (0), primal 0 (0)\n", + "Optimal objective 5 - 0 iterations time 0.002, Presolve 0.00\n", + "Option for printingOptions changed from normal to all\n", + "Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00\n", + "\n", + "\n", + "############### Integer LP #################### \n", + "\n", + "job_1_cpu_1_int = 1.0\n", + "job_1_cpu_2_int = 0.0\n", + "job_2_cpu_1_int = 0.0\n", + "job_2_cpu_2_int = 1.0\n", + "Value of Objective Function (Integer LP) = 5.0\n", + "\n", + "############### LP Relaxation #################### \n", + "\n", + "job_1_cpu_1_cont = 1.0\n", + "job_1_cpu_2_cont = 0.0\n", + "job_2_cpu_1_cont = 0.0\n", + "job_2_cpu_2_cont = 1.0\n", + "Value of Objective Function (Relaxed LP) = 5.0\n" + ] + } + ], + "source": [ + "## LP Relaxed\n", + "from pulp import *\n", + "import random\n", + "\n", + "cpus=[\"cpu1\", \"cpu2\"]\n", + "jobs=[\"job1\", \"job2\"]\n", + "\n", + "combinations = [\n", + " (1,1),\n", + " (1,2),\n", + " (2,1),\n", + " (2,2),\n", + "]\n", + "\n", + "# Cost (job, cpu)\n", + "costs = {\n", + " (1,1): 2.0, \n", + " (1,2): 1.0,\n", + " (2,1): 7.0,\n", + " (2,2): 3.0\n", + "}\n", + "variables_integer = {\n", + " (1,1): LpVariable(\"x-j1c1-integer\", cat=\"Integer\"),\n", + " (1,2): LpVariable(\"x-j1c2-integer\", cat=\"Integer\"),\n", + " (2,1): LpVariable(\"x-j1c2-integer\", cat=\"Integer\"),\n", + " (2,2): LpVariable(\"x-j1c2-integer\", cat=\"Integer\")\n", + "}\n", + " \n", + "variables_relaxed = {\n", + " (1,1): LpVariable(\"x-j1c1-continuous\", cat=\"Continuous\"),\n", + " (1,2): LpVariable(\"x-j1c2-continuous\", cat=\"Continuous\"),\n", + " (2,1): LpVariable(\"x-j1c2-continuous\", cat=\"Continuous\"),\n", + " (2,2): LpVariable(\"x-j1c2-continuous\", cat=\"Continuous\")\n", + "}\n", + " \n", + "prob_integer = LpProblem(\"CPU Assignment Integer\", LpMinimize) \n", + "prob_relaxed = LpProblem(\"CPU Assignment Relaxed\", LpMinimize)\n", + "\n", + "prob_integer += (\n", + " lpSum([variables_integer[(j, c)] * costs[(j, c)] for (j, c) in combinations]),\n", + " \"Sum_of_Assignment_Costs (Integer LP)\",\n", + ")\n", + "prob_relaxed += (\n", + " lpSum([variables_relaxed[(j, c)] * costs[(j, c)] for (j, c) in combinations]),\n", + " \"Sum_of_Assignment_Costs (LP Relaxed)\",\n", + ")\n", + "\n", + "prob_integer += lpSum([variables_integer[(1,1)], variables_integer[(1,2)]]) == 1 \n", + "prob_integer += lpSum([variables_integer[(2,1)], variables_integer[(2,2)]]) == 1 \n", + "prob_integer += lpSum([variables_integer[(1,1)], variables_integer[(2,1)]]) == 1 \n", + "prob_integer += lpSum([variables_integer[(1,2)], variables_integer[(2,2)]]) == 1\n", + "\n", + "prob_relaxed += variables_relaxed[(1,1)] >= 0\n", + "prob_relaxed += variables_relaxed[(1,1)] <= 1\n", + "prob_relaxed += variables_relaxed[(2,1)] >= 0\n", + "prob_relaxed += variables_relaxed[(2,1)] <= 1\n", + "prob_relaxed += variables_relaxed[(1,2)] >= 0\n", + "prob_relaxed += variables_relaxed[(1,2)] <= 1\n", + "prob_relaxed += variables_relaxed[(2,2)] >= 0\n", + "prob_relaxed += variables_relaxed[(2,2)] <= 1\n", + "prob_relaxed += lpSum([variables_relaxed[(1,1)], variables_relaxed[(1,2)]]) == 1 \n", + "prob_relaxed += lpSum([variables_relaxed[(2,1)], variables_relaxed[(2,2)]]) == 1 \n", + "prob_relaxed += lpSum([variables_relaxed[(1,1)], variables_relaxed[(2,1)]]) == 1 \n", + "prob_relaxed += lpSum([variables_relaxed[(1,2)], variables_relaxed[(2,2)]]) == 1\n", + "print(prob_relaxed)\n", + "\n", + "prob_integer.solve()\n", + "prob_relaxed.solve()\n", + "\n", + "print(\"\\n############### Integer LP #################### \\n\")\n", + "for v in prob_integer.variables():\n", + " print(v.name, \"=\", v.varValue)\n", + " \n", + "print(\"Value of Objective Function (Integer LP) = \", value(prob_integer.objective))\n", + "\n", + "print(\"\\n############### LP Relaxation #################### \\n\")\n", + "for v in prob_relaxed.variables():\n", + " print(v.name, \"=\", v.varValue)\n", + " \n", + "print(\"Value of Objective Function (Relaxed LP) = \", value(prob_relaxed.objective))" + ] + }, + { + "cell_type": "markdown", + "id": "0ce857f3-4a5b-42b9-b454-7c4a14820320", + "metadata": {}, + "source": [ + "### Problem 9\n", + "\n", + "I set up an arbitrary graph using Networkx and implemented the constraints that I wrote in the homework sheet. The different colors of nodes in the graph represent the two groups the graph is bisected to. " + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "54768339-c33b-4b7f-bedf-d87d2167bfce", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{('v1', 'v2'): edge_v1_v2, ('v1', 'v3'): edge_v1_v3, ('v1', 'v5'): edge_v1_v5, ('v2', 'v5'): edge_v2_v5, ('v3', 'v6'): edge_v3_v6, ('v5', 'v4'): edge_v5_v4, ('v5', 'v6'): edge_v5_v6, ('v4', 'v6'): edge_v4_v6}\n", + "Bisection_problem:\n", + "MINIMIZE\n", + "1*edge_v1_v2 + 1*edge_v1_v3 + 1*edge_v1_v5 + 1*edge_v2_v5 + 1*edge_v3_v6 + 1*edge_v4_v6 + 1*edge_v5_v4 + 1*edge_v5_v6 + 0\n", + "SUBJECT TO\n", + "_C1: partition_v1 + partition_v2 + partition_v3 + partition_v4 + partition_v5\n", + " + partition_v6 = 3\n", + "\n", + "_C2: - edge_v1_v2 + partition_v1 - partition_v2 <= 0\n", + "\n", + "_C3: - edge_v1_v2 - partition_v1 + partition_v2 <= 0\n", + "\n", + "_C4: - edge_v1_v3 + partition_v1 - partition_v3 <= 0\n", + "\n", + "_C5: - edge_v1_v3 - partition_v1 + partition_v3 <= 0\n", + "\n", + "_C6: - edge_v1_v5 + partition_v1 - partition_v5 <= 0\n", + "\n", + "_C7: - edge_v1_v5 - partition_v1 + partition_v5 <= 0\n", + "\n", + "_C8: - edge_v2_v5 + partition_v2 - partition_v5 <= 0\n", + "\n", + "_C9: - edge_v2_v5 - partition_v2 + partition_v5 <= 0\n", + "\n", + "_C10: - edge_v3_v6 + partition_v3 - partition_v6 <= 0\n", + "\n", + "_C11: - edge_v3_v6 - partition_v3 + partition_v6 <= 0\n", + "\n", + "_C12: - edge_v5_v4 - partition_v4 + partition_v5 <= 0\n", + "\n", + "_C13: - edge_v5_v4 + partition_v4 - partition_v5 <= 0\n", + "\n", + "_C14: - edge_v5_v6 + partition_v5 - partition_v6 <= 0\n", + "\n", + "_C15: - edge_v5_v6 - partition_v5 + partition_v6 <= 0\n", + "\n", + "_C16: - edge_v4_v6 + partition_v4 - partition_v6 <= 0\n", + "\n", + "_C17: - edge_v4_v6 - partition_v4 + partition_v6 <= 0\n", + "\n", + "VARIABLES\n", + "edge_v1_v2 free Continuous\n", + "edge_v1_v3 free Continuous\n", + "edge_v1_v5 free Continuous\n", + "edge_v2_v5 free Continuous\n", + "edge_v3_v6 free Continuous\n", + "edge_v4_v6 free Continuous\n", + "edge_v5_v4 free Continuous\n", + "edge_v5_v6 free Continuous\n", + "partition_v1 free Integer\n", + "partition_v2 free Integer\n", + "partition_v3 free Integer\n", + "partition_v4 free Integer\n", + "partition_v5 free Integer\n", + "partition_v6 free Integer\n", + "\n", + "Welcome to the CBC MILP Solver \n", + "Version: 2.10.3 \n", + "Build Date: Dec 15 2019 \n", + "\n", + "command line - /opt/conda/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/96a3ea460af84356a66114e3afc70b73-pulp.mps timeMode elapsed branch printingOptions all solution /tmp/96a3ea460af84356a66114e3afc70b73-pulp.sol (default strategy 1)\n", + "At line 2 NAME MODEL\n", + "At line 3 ROWS\n", + "At line 22 COLUMNS\n", + "At line 97 RHS\n", + "At line 115 BOUNDS\n", + "At line 130 ENDATA\n", + "Problem MODEL has 17 rows, 14 columns and 54 elements\n", + "Coin0008I MODEL read with 0 errors\n", + "Option for timeMode changed from cpu to elapsed\n", + "Continuous objective value is 0 - 0.00 seconds\n", + "Cgl0003I 0 fixed, 12 tightened bounds, 0 strengthened rows, 0 substitutions\n", + "Cgl0004I processed model has 17 rows, 14 columns (6 integer (0 of which binary)) and 54 elements\n", + "Cbc0012I Integer solution of 3 found by DiveCoefficient after 0 iterations and 0 nodes (0.00 seconds)\n", + "Cbc0031I 10 added rows had average density of 13.7\n", + "Cbc0013I At root node, 10 cuts changed objective from 0 to 2.8785087 in 93 passes\n", + "Cbc0014I Cut generator 0 (Probing) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.003 seconds - new frequency is -100\n", + "Cbc0014I Cut generator 1 (Gomory) - 182 row cuts average 13.4 elements, 0 column cuts (0 active) in 0.007 seconds - new frequency is 1\n", + "Cbc0014I Cut generator 2 (Knapsack) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.001 seconds - new frequency is -100\n", + "Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.000 seconds - new frequency is -100\n", + "Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.002 seconds - new frequency is -100\n", + "Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.001 seconds - new frequency is -100\n", + "Cbc0014I Cut generator 6 (TwoMirCuts) - 25 row cuts average 11.4 elements, 0 column cuts (0 active) in 0.002 seconds - new frequency is 1\n", + "Cbc0010I After 0 nodes, 1 on tree, 3 best solution, best possible 2.8785087 (0.05 seconds)\n", + "Cbc0001I Search completed - best objective 3, took 711 iterations and 2 nodes (0.05 seconds)\n", + "Cbc0032I Strong branching done 20 times (158 iterations), fathomed 2 nodes and fixed 0 variables\n", + "Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost\n", + "Cuts at root node changed objective from 0 to 2.87851\n", + "Probing was tried 93 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.003 seconds)\n", + "Gomory was tried 103 times and created 200 cuts of which 0 were active after adding rounds of cuts (0.008 seconds)\n", + "Knapsack was tried 93 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.001 seconds)\n", + "Clique was tried 93 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "MixedIntegerRounding2 was tried 93 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.002 seconds)\n", + "FlowCover was tried 93 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.001 seconds)\n", + "TwoMirCuts was tried 103 times and created 46 cuts of which 0 were active after adding rounds of cuts (0.003 seconds)\n", + "ZeroHalf was tried 1 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)\n", + "\n", + "Result - Optimal solution found\n", + "\n", + "Objective value: 3.00000000\n", + "Enumerated nodes: 2\n", + "Total iterations: 711\n", + "Time (CPU seconds): 0.05\n", + "Time (Wallclock seconds): 0.05\n", + "\n", + "Option for printingOptions changed from normal to all\n", + "Total time (CPU seconds): 0.05 (Wallclock seconds): 0.06\n", + "\n", + "edge_v1_v2 = 0.0\n", + "edge_v1_v3 = 1.0\n", + "edge_v1_v5 = 0.0\n", + "edge_v2_v5 = 0.0\n", + "edge_v3_v6 = 0.0\n", + "edge_v4_v6 = 0.0\n", + "edge_v5_v4 = 1.0\n", + "edge_v5_v6 = 1.0\n", + "partition_v1 = 1.0\n", + "partition_v2 = 1.0\n", + "partition_v3 = 0.0\n", + "partition_v4 = 0.0\n", + "partition_v5 = 1.0\n", + "partition_v6 = 0.0\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# HW1 Problem 9\n", + "\n", + "from pulp import *\n", + "import networkx as nx\n", + "import matplotlib.pyplot as plt\n", + "\n", + "G = nx.Graph()\n", + "G.add_edge(\"v1\", \"v2\")\n", + "G.add_edge(\"v1\", \"v3\")\n", + "G.add_edge(\"v1\", \"v5\")\n", + "G.add_edge(\"v2\", \"v5\")\n", + "G.add_edge(\"v4\", \"v5\")\n", + "G.add_edge(\"v3\", \"v6\")\n", + "G.add_edge(\"v4\", \"v6\")\n", + "G.add_edge(\"v5\", \"v6\")\n", + "\n", + "partitions = {}\n", + "for node in G.nodes:\n", + " partitions[node] = LpVariable(\"partition_{0}\".format(node), cat=\"Integer\")\n", + "\n", + "\n", + "prob = pulp.LpProblem(\"Bisection problem\", LpMinimize)\n", + "\n", + "edge_vars = {}\n", + "\n", + "for edge in G.edges:\n", + " edge_vars[edge] = LpVariable(\"edge_{0}_{1}\".format(edge[0],edge[1]))\n", + " \n", + "print(edge_vars)\n", + "\n", + "prob+= lpSum([edge_vars[edge] for edge in G.edges]), \"Our objective statement\"\n", + "prob+= lpSum([partitions[node] for node in G.nodes]) == 3\n", + " \n", + "for x, y in G.edges:\n", + " prob += partitions[x] - partitions[y] <= edge_vars[(x,y)]\n", + " prob += partitions[y] - partitions[x] <= edge_vars[(x,y)]\n", + " \n", + "print(prob) \n", + "\n", + "prob.solve()\n", + "for v in prob.variables():\n", + " print(v.name, \"=\", v.varValue)\n", + " \n", + "pos = nx.spring_layout(G, seed=7) # positions for all nodes - seed for reproducibility\n", + "\n", + "# nodes\n", + "\n", + "colors = [\"tab:red\" if partitions[node].varValue > 0 else \"tab:blue\" for node in G.nodes()]\n", + "nx.draw_networkx_nodes(G, pos, node_size=700, node_color=colors)\n", + "\n", + "# edges\n", + "nx.draw_networkx_edges(G, pos, width=6)\n", + "nx.draw_networkx_edges(\n", + " G, pos, width=6, alpha=0.5, edge_color=\"b\", style=\"dashed\"\n", + ")\n", + "\n", + "# node labels\n", + "nx.draw_networkx_labels(G, pos, font_size=20, font_family=\"sans-serif\")\n", + "\n", + "ax = plt.gca()\n", + "ax.margins(0.08)\n", + "plt.axis(\"off\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}