{ "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 }