{
"cells": [
{
"cell_type": "markdown",
"id": "f350b263",
"metadata": {},
"source": [
"# Breakwater blocks\n",
"\n",
"\n",
"## Problem\n",
"It is desired to design the cheapest breakwater block (box-shaped). The price of the brick will depend only on the amount of used material. It is required that each face has a minimum surface of $0.8$ $\\text{m}^2$. Also, for stability reasons, the block weight has to be larger than $3000$ $\\text{kg}$. Letβs assume concrete density of $2500$ $\\text{kg}/{m}^2$."
]
},
{
"cell_type": "markdown",
"id": "56fc737c",
"metadata": {},
"source": [
"## Model\n",
"\n",
"We need to define our model in the form of a nonlinear constrained optimization model to apply `scipy.optimize.minimize`.\n",
"\n",
"We'll define the model as follows:\n",
"- Design variables: width, height and depth of a block\n",
"- Objective function: minimum volume of the block\n",
"- Inequality constraint functions: minimum surface area of each face of $0.8$ $\\text{m}^2$ and maximum weight of $3000$ $\\text{kg}$\n",
"- Equality constraint functions: none\n",
"- Bounds: positive dimensions\n",
"\n",
"### Design variables\n",
"Let's start with our design variables. In this case a logical choice could be the width, height and depth of our block\n",
"\n",
"$$\n",
"x=\\left[ \\begin{matrix}\n",
" {{x}_{width}} \\\\\n",
" {{x}_{depth}} \\\\\n",
" {{x}_{height}} \\\\\n",
"\\end{matrix} \\right]=\\left[ \\begin{matrix}\n",
" {{x}_{1}} \\\\\n",
" {{x}_{2}} \\\\\n",
" {{x}_{3}} \\\\\n",
"\\end{matrix} \\right]\n",
"$$\n",
"\n",
"### Objective function\n",
"Now we can define the objective function as the product of the dimension to represent $\\mathop {\\min }\\limits_x f\\left(x\\right) $:\n",
"\n",
"$$ \\mathop {\\min }\\limits_x f\\left(x\\right) = x_1 \\cdot x_2 \\cdot x_3 $$"
]
},
{
"cell_type": "markdown",
"id": "cee945ed",
"metadata": {},
"source": [
"### Inequality constraints\n",
"\n",
"Let's continue with the inequality constraints, which should deal with the required positive dimensions, minimum surface area of each face of $0.8$ $\\text{m}^2$ and maximum weight of $3000$ $\\text{kg}$. These can be defined in the form ${{g}}\\left(x_{ij}\\right) \\le 0$ as:\n",
"\n",
"$$\n",
"g_1\\left(x\\right) = -x_{1} \\cdot x_2 + 0.8 \\\\\n",
"g_2\\left(x\\right) = -x_{2} \\cdot x_3 + 0.8 \\\\\n",
"g_3\\left(x\\right) = -x_{1} \\cdot x_3 + 0.8 \\\\\n",
"g_4\\left(x\\right) = -x_{1} \\cdot x_2 \\cdot x_3 \\cdot 2500 + 3000 \\\\\n",
"$$\n",
"\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"id": "86c8ca56",
"metadata": {},
"source": [
"### Bounds\n",
"\n",
"The dimensions of the block cannot be negative. Therefore, the bounds can be defined as:\n",
"\n",
"$$\n",
"0<{{x}_{i}}\\text{ } i=1,2,3\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "242cdb5a",
"metadata": {},
"source": [
"### Find best solution manually\n",
"\n",
"Try and adjust the values for $x_1$, $x_2$ and $x_3$. Can you find the optimal solution?"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "8893850b",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c88d2a133b934d6caa764252d6b826f0",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=2.0, description='x_1', max=5.0, step=0.01), FloatSlider(value=2.0, deβ¦"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"### Find solution manually\n",
"\n",
"from ipywidgets import widgets, interact\n",
"import numpy as np\n",
"\n",
"def func(x):\n",
" vol = x[0]*x[1]*x[2]\n",
" return vol\n",
"\n",
"def nonlinconfun(x):\n",
" c1 = 0.8 - x[0]*x[1]\n",
" c2 = 0.8 - x[0]*x[2]\n",
" c3 = 0.8 - x[1]*x[2]\n",
" c4 = 3000 - 2500 * x[0] * x[1] * x[2]\n",
" return np.array([c1,c2,c3,c4])\n",
"\n",
"def eval(x_1,x_2,x_3):\n",
" x = np.array([x_1,x_2,x_3]) \n",
" print(\"Objective function: \", round(func(x),3),\"m^3\")\n",
" cons = nonlinconfun(x)\n",
" if cons[0] < 0:\n",
" print(\"Constraint functions 1: \", round(cons[0],2),\"m^2\",\"π\")\n",
" else:\n",
" print(\"Constraint functions 1: \", round(cons[0],2),\"m^2\",\"π\")\n",
" if cons[1] < 0:\n",
" print(\"Constraint functions 2: \", round(cons[1],2),\"m^2\",\"π\")\n",
" else:\n",
" print(\"Constraint functions 2: \", round(cons[1],2),\"m^2\",\"π\")\n",
" if cons[2] < 0:\n",
" print(\"Constraint functions 3: \", round(cons[2],2),\"m^2\",\"π\")\n",
" else:\n",
" print(\"Constraint functions 3: \", round(cons[2],2),\"m^2\",\"π\")\n",
" if cons[3] < 0:\n",
" print(\"Constraint functions 4: \", round(cons[3]),\"kg\",\"π\")\n",
" else:\n",
" print(\"Constraint functions 4: \", round(cons[3]),\"kg\",\"π\")\n",
" return\n",
"\n",
"interact(eval,\n",
" \n",
" x_1 = widgets.FloatSlider(min=0, max=5, value=2, step=0.01, description=\"x_1\"),\n",
" x_2 = widgets.FloatSlider(min=0, max=5, value=2, step=0.01, description=\"x_2\"),\n",
" x_3 = widgets.FloatSlider(min=0, max=5, value=2, step=0.01, description=\"x_3\"));"
]
},
{
"cell_type": "markdown",
"id": "2a609af6",
"metadata": {},
"source": [
"## Method\n",
"\n",
"Now let's solve this problem using an optimization method."
]
},
{
"cell_type": "markdown",
"id": "e567e5b5",
"metadata": {},
"source": [
"### Import libraries"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "2871c599",
"metadata": {},
"outputs": [],
"source": [
"import scipy as sp \n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"id": "c1e8ff92",
"metadata": {},
"source": [
"### Define variables\n",
"As before, we don't need to specify our variable $x$ itself. However, this optimization method requires an initial guess. An arbitrary value is chosen here:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "a7a3e663",
"metadata": {},
"outputs": [],
"source": [
"x0 = np.array([5,0,1])"
]
},
{
"cell_type": "markdown",
"id": "1333c1bb",
"metadata": {},
"source": [
"### Define objective function\n",
"\n",
"The objective function gives:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "c753c482",
"metadata": {},
"outputs": [],
"source": [
"def func(x):\n",
" vol = x[0]*x[1]*x[2]\n",
" return vol"
]
},
{
"cell_type": "markdown",
"id": "7d93884f",
"metadata": {},
"source": [
"### Define constrain functions"
]
},
{
"cell_type": "markdown",
"id": "b18490c9",
"metadata": {},
"source": [
" We had no equality constraints. Unlike before with linear constrained problems, we need an object which defines the upper and lower bounds. As this problem has only an upper bound of $0$, the lower bound is set to $\\infty$ which is `np.inf` in python. Note that a single constraint object can include multiple constraints."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "fb2a2361",
"metadata": {},
"outputs": [],
"source": [
"def nonlinconfun(x):\n",
" c1 = 0.8 - x[0]*x[1]\n",
" c2 = 0.8 - x[0]*x[2]\n",
" c3 = 0.8 - x[1]*x[2]\n",
" c4 = 3000 - 2500 * x[0] * x[1] * x[2]\n",
" return np.array([c1,c2,c3,c4])\n",
"\n",
"cons = sp.optimize.NonlinearConstraint(nonlinconfun, np.array([-np.inf,-np.inf,-np.inf,-np.inf]), np.array([0,0,0,0]))"
]
},
{
"cell_type": "markdown",
"id": "0b45073a",
"metadata": {},
"source": [
"### Define bounds\n",
"The bounds result in:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "42656ee2",
"metadata": {},
"outputs": [],
"source": [
"bounds = [[0, None],\n",
" [0, None],\n",
" [0, None]]"
]
},
{
"cell_type": "markdown",
"id": "76ddef0f",
"metadata": {},
"source": [
"### Solve the problem"
]
},
{
"cell_type": "markdown",
"id": "18dba09c",
"metadata": {},
"source": [
"Now let's solve the problem. The `cons` object can be added directly, in the case of equality constraints as well you can define a list of constrainer objects as an input."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "d2d014c1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" message: Optimization terminated successfully\n",
" success: True\n",
" status: 0\n",
" fun: 1.2000000000024624\n",
" x: [ 1.353e+00 1.488e+00 5.962e-01]\n",
" nit: 10\n",
" jac: [ 8.871e-01 8.065e-01 2.013e+00]\n",
" nfev: 41\n",
" njev: 10\n"
]
}
],
"source": [
"result = sp.optimize.minimize(fun = func,x0 = x0,bounds = bounds,constraints=cons)\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"id": "702e8343",
"metadata": {},
"source": [
"## Exercise\n",
"\n",
""
]
}
],
"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.18"
}
},
"nbformat": 4,
"nbformat_minor": 5
}