{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Facility location assignment\n", "\n", "Instructor: Frans de Ruiter\n", "\n", "For assignment and data, see https://www.fransderuiter.com/JADS/\n", "\n", "***" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setup" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "from pyomo.environ import *\n", "import matplotlib.pyplot as plt # optional for plotting\n", "from matplotlib import cm # optional for plotting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Read data\n", "Here we load the distance table between the cities." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data_path = \"https://www.fransderuiter.com/JADS/Facilitylocation/FacilityLocation.xlsx\"\n", "# Create pandas table\n", "distances = pd.read_excel(data_path, sheet_name=0, header=0, skiprows=2, index_col=1)\n", "\n", "# Show table\n", "distances.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some data processing" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "#remove 1st column ('unnamed', because there is a comment in first column it was added in the database)\n", "distances = distances.drop(distances.columns[0],1)\n", "\n", "# Show table with removed column\n", "distances.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "## Show index names\n", "cities = distances.columns\n", "print(cities)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Model parameters" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Fixed cost for opening a DC (same for each city)\n", "fixed_cost = 150000\n", "\n", "# demand equals 100 for each city\n", "demand_per_city = 100\n", "\n", "# Supply capacity of each city is 4000\n", "M = 4000\n", "\n", "# Create pandas dataframe with supply\n", "city_params_dict = {'supply': M*np.ones(cities.size, int), \n", " 'demand': demand_per_city*np.ones(cities.size, int), \n", " 'fixed cost': fixed_cost*np.ones(cities.size, int)}\n", "city_params = pd.DataFrame(data=city_params_dict, index = cities)\n", "city_params.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# extract the fixed costs for a city (in this case \"Athens\") as follows:\n", "i_1 = 'Athens'\n", "city_params.loc[i_1,'fixed cost']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# extract the fixed costs for a city (in this case \"Athens\" to \"Amsterdam\") as follows:\n", "i_1 = 'Athens'\n", "j_1 = 'Amsterdam'\n", "distances[i_1][j_1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Model implementation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# TODO\n", "# write your optimization model in the cell here by replacing the XXXX in the cells\n", "\n", "# Create model\n", "m = ConcreteModel()\n", "\n", "# Variables\n", "m.locations = Var(cities, within=Binary)\n", "m.shipments = Var(cities, cities, within = NonNegativeReals)\n", "\n", "# Objective\n", "m.value = Objective(\n", " expr=sum( XXXX for i in cities)\n", " + sum( XXXX for i in cities for j in cities)\n", " , sense=minimize)\n", " \n", "# Constraints on supplying only when facility is open\n", "m.supply_restriction = ConstraintList()\n", "for i in cities:\n", " m.supply_restriction.add( XXXX )\n", "\n", "# Constraints on demand fulfillment\n", "m.demand_fulfillment = ConstraintList()\n", "for j in cities:\n", " m.demand_fulfillment.add( XXXX )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Solve the model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Optimize\n", "solver = SolverFactory('cbc') # Take the cbc solver, glpk is very slow\n", "status = solver.solve(m,tee=False,) # Set tee to True to see log of the solver\n", "\n", "# Print the status of the solved mixed integer linear model once it is done\n", "print(\"Status = %s \\n\" % status.solver.termination_condition)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Show the solution\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Show some visualization via tables and/or plots to present your solution.\n", "#TODO (optional): add more visualization, print your solution etc\n", "\n", "# Make a vector with all the shipments\n", "totalshipments = [sum(value(m.shipments[i,j]) for j in cities) for i in cities]\n", "\n", "plt.figure(figsize=(3,10))\n", "\n", "# make a horizontal bar plots\n", "plt.barh(range(cities.size),totalshipments, color=\"blue\",align=\"center\") \n", "\n", "# Use city names on the vertical axis\n", "plt.yticks(range(cities.size),cities,rotation=0)\n", "\n", "# Set title and show plot\n", "plt.title('Total shipments per DC',fontsize=20)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.1" } }, "nbformat": 4, "nbformat_minor": 2 }