diff --git a/book/_toc.yml b/book/_toc.yml index abfc447..470d7d5 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -36,10 +36,8 @@ parts: - file: features/jupyterlite/including-jupyterlite - file: features/custom_toc.md - file: features/custom_download.md - - file: features/interactive_element - sections: - - file: feutures/h5p_examples - - file: features/theory_questions.md + - file: features/h5p_examples.md + - file: features/theory_questions.md - file: features/h5p.md - file: features/live_code.md sections: @@ -54,5 +52,4 @@ parts: sections: - file: examples/example_gumbel.ipynb - file: examples/example_quiz_interactive.ipynb - - file: examples/coding_theory_widgets.ipynb - file: examples/parametric_questions.ipynb \ No newline at end of file diff --git a/book/examples/Unconstrained_optimization_stripped.ipynb b/book/examples/Unconstrained_optimization_stripped.ipynb new file mode 100644 index 0000000..6ff49e9 --- /dev/null +++ b/book/examples/Unconstrained_optimization_stripped.ipynb @@ -0,0 +1,540 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Unconstrained optimization\n", + "\n", + "In this chapter, we'll cover how to apply `scipy.optimize.minimize` to unconstrained optimization problems. As a reminder, unconstrained optimization considers:\n", + "\n", + "$$\\mathop {\\min }\\limits_x f\\left( x \\right)$$\n", + "with $x$ the design variable of length $n$ and $f$ the objective function.\n", + "\n", + "## Method\n", + "In this course, we're making use of the function `scipy.optimize.minimize`. The documentation of this function is available here: \n", + "https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html. In this course we'll cover only the relevant parts.\n", + "\n", + "For unconstrained optimization we need to run at least `scipy.optimize.minimize(fun, x0, ...)` with:\n", + "- `fun`, the objective function $f(x)$ to be minimized. `fun` is a callable. The `scipy.optmize.minimize` function takes care of defining and inputing our design variable $x$.\n", + "- `x0`, the initial guess for our design variable $x$. It needs to be a `ndarray` with length $n$\n", + "\n", + "The function `scipy.optimize.minimize` outputs an object `scipy.optimize.OptimizeResult`. with:\n", + "- `scipy.optimize.OptimizeResult.x` the optimized solution of the design variable `x`. It is a `ndarray` with length $n$\n", + "- `scipy.optimize.OptimizeResult.success`, a indication whether or not the optimizer was executed succesfully. It is a `bool`, indicating `True` or `False`\n", + "- `scipy.optimize.OptimizeResult.message`, a message describing the cause of termination of the optimizatino algorithm. It is a `str`.\n", + "- `scipy.optimize.OptimizeResult.fun`, the values of the optimized objective function $f$. It is a `int` or `float`\n", + "- `scipy.optimize.OptimizeResult.nit`, the number of iteration performed by the optimizer. It is a `int`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 1\n", + "\n", + "### Problem\n", + "It is desired to determine the number of bathymetry maps $n$ of a local area that should be produced to maximize the profit of a company. The total cost of production and distribution is €$75$ per unit $n$. The revenues are proportional to the number of units multiplied by its price: $Revenues = n \\cdot Price $\n", + "\n", + "The demand depends on the price ($Price = 150 - 0.01n^2$), as shown in the graph:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "n = np.linspace(0,120,100)\n", + "price = 150 - 0.01 * n**2\n", + "plt.plot(n,price)\n", + "plt.xlabel('$n$ (-)')\n", + "plt.ylabel('$Price$ (€)')\n", + "plt.ylim(0,160)\n", + "plt.xlim(0,120)\n", + "ax = plt.gca()\n", + "ax.grid(True, which='both')\n", + "ax.spines['left'].set_position('zero')\n", + "ax.spines['right'].set_color('none')\n", + "ax.yaxis.tick_left()\n", + "ax.spines['bottom'].set_position('zero')\n", + "ax.spines['top'].set_color('none')\n", + "ax.xaxis.tick_bottom()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The profit can be estimated as the revenues minus the total costs." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Model\n", + "The function for the profit can be found by combining the relations in the problem statement. However, this is the profit which should be maximized. To turn this into a minimization problem, the profit can be multiplied with $-1$. The final model of this problem results in:\n", + "\n", + "$$ \\mathop {\\min }\\limits_n \\left(75n - \\left( 150 - 0.01n^2 \\right) n \\right) $$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Method\n", + "\n", + "This model is described using `scipy.optimize.minimize` according to the standard structure in this course.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Importing libraries\n", + "For this problem, we'll use all three packages `scipy`, `numpy`, `matplotlib`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import scipy as sp \n", + "import numpy as np\n", + "import matplotlib.pylab as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Defining the variables\n", + "There are very few variables in this problem. In fact, the only variable we have to specify is the initial guess for the optimization algorithm. The objective function will be treated later.\n", + "The length of $n$ doesn't have to be specified." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "n0 = 20" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Defining the objective function\n", + "In the objective function, the formula given in the model description can be inserted. Or, each individual step can be calculated on a seperate line. Again, note that the profit is multiplied with $-1$ to maximize the profit in the minimization formulation.\n", + "This results in:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def negprofit(n):\n", + " price = 150 - 0.01 * n**2\n", + " revenues = price * n\n", + " totalcost = 75 * n\n", + " profit = revenues - totalcost\n", + " return -profit" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Solving the problem\n", + "Now, the problem can be solved. The result is stored in the variables `result` which is printed." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " message: Optimization terminated successfully.\n", + " success: True\n", + " status: 0\n", + " fun: -2499.9999999998727\n", + " x: [ 5.000e+01]\n", + " nit: 8\n", + " jac: [ 0.000e+00]\n", + " hess_inv: [[ 3.503e-01]]\n", + " nfev: 22\n", + " njev: 11\n" + ] + } + ], + "source": [ + "result = sp.optimize.minimize(negprofit,n0)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Postprocessing\n", + "As this case is only one-dimensional and the potential range of values is limited, we can easily check this answer by an exhaustive search, evaluating all possible values for $n$. The plot below shows the $\\text{negative profit}$ for $0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "n_range = np.linspace(0,100,100)\n", + "negprofit_result = negprofit(n_range)\n", + "plt.plot(n_range,negprofit_result)\n", + "plt.plot(result.x,result.fun,'o');\n", + "plt.xlabel('$n$')\n", + "plt.ylabel('Negative profit');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 2\n", + "\n", + "### Problem\n", + "8 data points are collected where $X_i$ is the explanatory variable and $Y_i$ the response variable. It is believed that the data follows the trend $Y = aX^b+c$ where $a$, $b$ and $c$ are the parameters to be determined to fit the model.\n", + "\n", + "| $X_i$ | $Y_i$ |\n", + "| :----- | :----- |\n", + "| 0.97 | 0.97 |\n", + "| 0 | 0.06 |\n", + "| 0.5 | 0.7 |\n", + "| 0.85 | 0.74 |\n", + "| 0.7 | 0.2 |\n", + "| 0.19 | 0.34 |\n", + "| 0.41 | 0.29 |\n", + "| 0.78 | 0.94 |" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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esLqzr/zCRMm6MiRIzpx4kRoW11dnZxOpzIzMyM6rw26c8y/+OILOZ1t3zpdLpek/511QM/qsffQLi1xhjHmf3/GuGbNGlNbW2vmz59v+vTpYz744ANjjDELFy40t9xyS2j/1j+pW7BggamtrTVr1qzhz9K7qKvH/PnnnzcpKSlmxYoVprGxMfT47LPPYvUrJJyuHvPv4q+0uq6rx7y5udlkZmaaX/ziF2bfvn1m+/btJjs728ybNy9Wv0LC6eoxf+aZZ0xKSopZuXKlef/9983OnTtNXl6eGTNmTKx+hYTT3NxsampqTE1NjZFkysvLTU1NTeijACL1HkrwdNOKFSvM0KFDTWpqqhk9erTZvn176GuzZs0yV155ZZv933jjDfOjH/3IpKammgsuuMCsWrUqyhMnvq4c8yuvvNJIaveYNWtW9AdPYF39d/5tBE/3dPWY79+/31xzzTWmd+/eJjMz05SUlJgvvvgiylMntq4e84qKCnPZZZeZ3r17m0GDBpmbb77ZHD58OMpTJ65//OMf3/vf50i9hzqM4RwcAACwG2t4AACA9QgeAABgPYIHAABYj+ABAADWI3gAAID1CB4AAGA9ggcAAFiP4AEAANYjeAAAgPUIHgAJLxgM6tJLL9Vvf/vbNttfe+01paamasOGDTGaDEC8IHgAJDyn06nS0lKtWrVKn376qSTpv//9r2688Ub94Q9/0I033hjjCQHEGvfSAmCFU6dOafjw4Zo1a5bmzp2rcePG6ac//alWrFgR69EAxAGCB4A1Vq9erd/97ncaMmSILrjgAm3atEkulyvWYwGIAwQPAGucOHFCAwcO1MUXX6y33npLffr0afP1v//973r77be1YMGCGE0IIFYIHgDWmD17tiorK3XOOefo4MGDSk9Pj/VIAOIEi5YBWOHee+/V3/72N7311ls6deqU1qxZ026fyZMna//+/TGYDkCsETwAEt7TTz+tRx55RK+88opGjRql+fPna+nSpfr666/b7FdfX6/s7OwYTQkglggeAAnt1Vdf1a9//Ws999xzGjdunCTpjjvukN/v15///OfQfj6fT2effbZSUlJiNSqAGCJ4ACSs6upq3XjjjVq6dKl+9rOfhba73W7dcccd+uMf/6hAICBJeueddzRy5MhYjQogxli0DCAprF69Wp988olKS0tjPQqAGOAMD4CksG/fPuXk5MR6DAAxwhkeAABgPc7wAAAA6xE8AADAegQPAACwHsEDAACsR/AAAADrETwAAMB6BA8AALAewQMAAKxH8AAAAOsRPAAAwHoEDwAAsB7BAwAArPf/PM1lxqCxnMcAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xi = np.array([0.97,0,0.5,0.85,0.7,0.19,0.41,0.78])\n", + "yi = np.array([0.97,0.06,0.7,0.74,0.2,0.34,0.29,0.94])\n", + "plt.xlabel('$X_i$')\n", + "plt.ylabel('$Y_i$')\n", + "plt.plot(xi,yi,'x');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Examples of the source of this data can be:\n", + " - Stress of a pre-stressed concrete specimen based on the deformation when applied an axial force\n", + " - Permeability-coefficient for compacted sand based on the grain size\n", + " - Job performance based on the number of working hours\n", + " - etc.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Model\n", + "The problem is modelled as a minimization of the squared error, where error is the difference between $a X_i^b+C$ and $Y_i$\n", + "$$\\mathop {\\min }\\limits_{a,b,c} \\sum\\limits_{i = 1}^8 {{{\\left( {a{X_i}^b + c - {Y_i}} \\right)}^2}} $$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The plot below shows the data points and the total error squared." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "029c3407d1ac46e7a9765bca5443248d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(FloatSlider(value=2.0, description='a', max=5.0, step=0.2), FloatSlider(value=2.0, descr…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from ipywidgets import widgets, interact\n", + "x_range = np.linspace(0.0001,1,100)\n", + "def func(a,b,c):\n", + " fig, ax = plt.subplots(1, 1)\n", + " ax.plot(xi,yi,'x')\n", + " ax.plot(x_range,a * x_range**b + c);\n", + " ax.set_xlim([-0,1])\n", + " ax.set_ylim([-0,1])\n", + " y_est = a * xi ** b + c\n", + " error = np.sum((yi-y_est)**2)\n", + " title = 'Total error squared $=$'+str(round(error,4))\n", + " ax.set_title(title)\n", + " for i in range(8):\n", + " ax.annotate(\"\",xy=[xi[i],yi[i]],xytext=[xi[i],max(min(a * xi[i] ** b + c,1),0)],arrowprops=dict(arrowstyle= '<->'))\n", + " return\n", + " plt.show()\n", + "\n", + "interact(func,\n", + " a = widgets.FloatSlider(min=0, max=5, value=2, step=0.2, description=\"a\"),\n", + " b = widgets.FloatSlider(min=0, max=5, value=2, step=0.2, description=\"b\"),\n", + " c = widgets.FloatSlider(min=0, max=1, value=0.5, step=0.05, description=\"c\"));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Method\n", + "\n", + "Again, this model is described using `scipy.optimize.minimize` according to the [standard structure in this course](./Python_start_3.ipynb)\n", + "\n", + "#### Importing libraries\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "import scipy as sp\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Defining the variables\n", + "In this problem, there are 3 design variables: $a$, $b$ and $c$. In `scipy.optimize`, these variables are part of one array. You don't have to specify this variable beforehand, but the optimization algorithm will define the number of variables on your other input. Furthermore, input data is given which is required to specify explicitly. Additionally, an initial guess is required for the otimization algorithm." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "xi = np.array([0.97, 0 , 0.5, 0.85, 0.7, 0.19, 0.41, 0.78])\n", + "yi = np.array([0.97, 0.06, 0.7, 0.74, 0.2, 0.34, 0.29, 0.94])\n", + "abc0 = np.array([4., 2., 0.5]) #initial guess" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Objective function\n", + "The objective function was alerady defined. Because `a`, `b`, `c` and `xi` are all numpy arrays, we can simply use `*`, `**` and `+` to deal with the multiplication, exponent and summation of those arrays. `np.sum` is used to sum up all components of the array which is the result of `(yi-y_est)**2`" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [], + "source": [ + "def squarederror(abc):\n", + " a = abc[0]\n", + " b = abc[1]\n", + " c = abc[2]\n", + " y_est = a * xi ** b + c\n", + " error = np.sum((yi-y_est)**2)\n", + " return error" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Solve the problem\n", + "Now we can solve the actual problem" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " message: Optimization terminated successfully.\n", + " success: True\n", + " status: 0\n", + " fun: 0.3342203980898386\n", + " x: [ 8.028e-01 1.231e+00 1.233e-01]\n", + " nit: 54\n", + " jac: [-2.332e-06 2.570e-06 -3.166e-06]\n", + " hess_inv: [[ 6.233e-01 -3.674e-01 -3.660e-01]\n", + " [-3.674e-01 1.485e+01 2.251e+00]\n", + " [-3.660e-01 2.251e+00 5.564e-01]]\n", + " nfev: 276\n", + " njev: 69\n" + ] + } + ], + "source": [ + "result = sp.optimize.minimize(squarederror,abc0)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Postprocessing\n", + "As this problem involves three design variables, a plot of all possible design variables with the objective function is not possible because it would require four dimensions. However, we can plot the data which the obtained solution to see how it looks like" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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73kuKiriqquuok2bNmRnZ7PHHntw//33V1Pa5FXe8/zoo4+y//77U7duXZo1a8Y555zD6tWrqyltcnrjjTc44YQTaN68OWlpaTz11FM/+55q/ywMVG7//Oc/g1q1agX33HNPMG/evODSSy8N6tWrF3zxxRelvv6zzz4L6tatG1x66aXBvHnzgnvuuSeoVatWMGnSpGpOnlzKe54vvfTS4Oabbw7+85//BPPnzw+GDx8e1KpVK/jvf/9bzcmTT3nPdbFvv/022H333YM+ffoE+++/f/WETWIVOc8nnnhi0KVLlyAvLy9YtGhR8O677wZvvfVWNaZOPuU9z9OnTw/S09OD22+/Pfjss8+C6dOnB/vuu2/Qv3//ak6eXKZMmRJcddVVwb///e8ACCZPnvyTr4/is9CSUwGHHHJIMGjQoK2O7b333sGVV15Z6uuvuOKKYO+9997q2AUXXBB07dq1yjKmgvKe59Lss88+wYgRIyo7Wsqp6LkeMGBAcPXVVwfXXXedJacMynueX3jhhSA3NzdYvXp1dcRLGeU9z3/729+C3XfffatjY8aMCVq2bFllGVNNWUpOFJ+FXq4qp02bNjFr1iz69Omz1fE+ffowY8aMUt/z9ttvb/P6Y445hpkzZ7J58+Yqy5rMKnKefywej1NYWEijRo2qImLKqOi5fuCBB1i4cCHXXXddVUdMCRU5z8888wydO3fmlltuoUWLFrRv357LLruMDRs2VEfkpFSR89y9e3eWLl3KlClTCIKAr776ikmTJnHcccdVR+QaI4rPwhq9QWdFrFq1ilgsRtOmTbc63rRpU1asWFHqe1asWFHq67ds2cKqVato1qxZleVNVhU5zz926623sm7dOk477bSqiJgyKnKuFyxYwJVXXsn06dPJzPSfkbKoyHn+7LPPePPNN6lduzaTJ09m1apVXHjhhaxZs8Z1OdtRkfPcvXt3Hn30UQYMGMDGjRvZsmULJ554InfccUd1RK4xovgsdCangtLS0rYaB0GwzbGfe31px7W18p7nYo8//jjXX389EydOZJdddqmqeCmlrOc6FotxxhlnMGLECNq3b19d8VJGef5Ox+Nx0tLSePTRRznkkEM49thjGTVqFA8++KCzOT+jPOd53rx5DB48mGuvvZZZs2bx4osvsmjRIgYNGlQdUWuU6v4s9P+ClVPjxo3JyMjY5v8RrFy5cpuGWmzXXXct9fWZmZnsvPPOVZY1mVXkPBebOHEi5557Lk888QRHH310VcZMCeU914WFhcycOZPZs2dz8cUXA+GHcRAEZGZm8vLLL3PUUUdVS/ZkUpG/082aNaNFixbk5uaWHOvQoQNBELB06VLatWtXpZmTUUXO88iRI+nRoweXX345APvttx/16tWjZ8+e3Hjjjc62V5IoPgudySmnrKwsOnXqRF5e3lbH8/Ly6N69e6nv6dat2zavf/nll+ncuTO1atWqsqzJrCLnGcIZnLPPPpvHHnvM6+llVN5znZOTwwcffMCcOXNKvgYNGsRee+3FnDlz6NKlS3VFTyoV+Tvdo0cPli1bxtq1a0uOzZ8/n/T0dFq2bFmleZNVRc7z+vXrSU/f+uMwIyMD+H6mQTsuks/CKlvSnMKKb0+87777gnnz5gVDhgwJ6tWrF3z++edBEATBlVdeGZx55pklry++bW7o0KHBvHnzgvvuu89byMugvOf5scceCzIzM4Nx48YFy5cvL/n69ttvo/oVkkZ5z/WPeXdV2ZT3PBcWFgYtW7YMTjnllGDu3LnBtGnTgnbt2gXnnXdeVL9CUijveX7ggQeCzMzMYPz48cHChQuDN998M+jcuXNwyCGHRPUrJIXCwsJg9uzZwezZswMgGDVqVDB79uySW/UT4bPQklNB48aNC9q0aRNkZWUFBx10UDBt2rSS7w0cODA4/PDDt3r966+/Hhx44IFBVlZWsNtuuwUTJkyo5sTJqTzn+fDDDw+Abb4GDhxY/cGTUHn/Tv+QJafsynueP/roo+Doo48O6tSpE7Rs2TIYNmxYsH79+mpOnXzKe57HjBkT7LPPPkGdOnWCZs2aBb/+9a+DpUuXVnPq5PLaa6/95L+5ifBZmBYEzsVJkqTU45ocSZKUkiw5kiQpJVlyJElSSrLkSJKklGTJkSRJKcmSI0mSUpIlR5IkpSRLjiRJSkmWHEmSlJIsOZKSXjweZ++99+aPf/zjVsdfeuklsrKyeOKJJyJKJilKlhxJSS89PZ3hw4czYcIEvvnmGwDef/99Tj31VG666SZOPfXUiBNKioJ7V0lKCVu2bKF9+/YMHDiQc889l65du9KvXz/GjRsXdTRJEbHkSEoZd911F3/6059o0aIFu+22G5MnTyYjIyPqWJIiYsmRlDLWrl1LkyZN2HPPPXnnnXeoV6/eVt9/5ZVX+OCDDxg6dGhECSVVJ0uOpJRx9tlnM3HiRBo2bMiiRYuoXbt21JEkRciFx5JSwjXXXMPzzz/PO++8w5YtW7jvvvu2eU3fvn356KOPIkgnKQqWHElJ79577+XWW2/l2WefZf/992fIkCHccsstbN68eavXLViwgHbt2kWUUlJ1s+RISmovvPACF110EY888ghdu3YF4JJLLqGgoICHH3645HX5+fnUr1+fzMzMqKJKqmaWHElJa9asWZx66qnccsstnHzyySXHc3JyuOSSS/jrX/9KLBYD4MMPP2TfffeNKqqkCLjwWFKNcNddd7FmzRqGDx8edRRJ1cSZHEk1wty5c+nYsWPUMSRVI2dyJElSSnImR5IkpSRLjiRJSkmWHEmSlJIsOZIkKSVZciRJUkqy5EiSpJRkyZEkSSnJkiNJklKSJUeSJKUkS44kSUpJlhxJkpSSLDmSJCkl/T9bxwpX7Qf61AAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "x_range = np.linspace(0,1,100)\n", + "plt.plot(xi,yi,'x');\n", + "plt.plot(x_range,result.x[0] * x_range ** result.x[1] + result.x[2])\n", + "plt.xlabel('$X_i$')\n", + "plt.ylabel('$Y_i$');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To solve uncontrained optimisation problem like:\n", + "\n", + "$$\n", + " \\mathop {\\min }\\limits_x f\\left( x \\right)\n", + "$$\n", + "\n", + "with $x$ the design variable of length $n$, you can make use of `scipy.optimize.minimize(fun, x0, ...)` which outputs `scipy.optimize.OptimizeResult` with the problem's solution, some characteristics of the problem and the performance of the optimization algorithm." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.17" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/examples/coding_theory_widgets.ipynb b/book/examples/coding_theory_widgets.ipynb deleted file mode 100644 index 81c8255..0000000 --- a/book/examples/coding_theory_widgets.ipynb +++ /dev/null @@ -1,333 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Combining coding theory with interactive questions and potential live coding\n", - "\n", - "This page shows an example of how to combine the introduction of a certain coding implementation with interactive questions. Automatic executation of the thebe live coding has been enables and the download button has been replaced by a custom notebook file." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```{custom_download_link} ./Unconstrained_optimization_stripped.ipynb\n", - ":replace_default: \"True\"\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example unconstrained optimization\n", - "\n", - "In this chapter, we'll cover how to apply `scipy.optimize.minimize` to unconstrained optimization problems. As a reminder, unconstrained optimization considers:\n", - "\n", - "```{math}\n", - ":label: unconstrained_optimizatino\n", - "\n", - "\\mathop {\\min }\\limits_x f\\left( x \\right)\n", - "```\n", - "with $x$ the design variable of length $n$ and $f$ the objective function.\n", - "\n", - "\n", - "### Method\n", - "In this course, we're making use of the function `scipy.optimize.minimize`. The documentation of this function is available here: \n", - "https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html. In this course we'll cover only the relevant parts.\n", - "\n", - "For unconstrained optimization we need to run at least `scipy.optimize.minimize(fun, x0, ...)` with:\n", - "- `fun`, the objective function $f(x)$ to be minimized. `fun` is a callable. The `scipy.optmize.minimize` function takes care of defining and inputing our design variable $x$.\n", - "- `x0`, the initial guess for our design variable $x$. It needs to be a `ndarray` with length $n$\n", - "\n", - "The function `scipy.optimize.minimize` outputs an object `scipy.optimize.OptimizeResult`. with:\n", - "- `scipy.optimize.OptimizeResult.x` the optimized solution of the design variable `x`. It is a `ndarray` with length $n$\n", - "- `scipy.optimize.OptimizeResult.success`, a indication whether or not the optimizer was executed succesfully. It is a `bool`, indicating `True` or `False`\n", - "- `scipy.optimize.OptimizeResult.message`, a message describing the cause of termination of the optimizatino algorithm. It is a `str`.\n", - "- `scipy.optimize.OptimizeResult.fun`, the values of the optimized objective function $f$. It is a `int` or `float`\n", - "- `scipy.optimize.OptimizeResult.nit`, the number of iteration performed by the optimizer. It is a `int`\n", - "\n", - ":::{card}\n", - "\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Example 1\n", - "\n", - "#### Problem\n", - "It is desired to determine the number of bathymetry maps $n$ of a local area that should be produced to maximize the profit of a company. The total cost of production and distribution is €$75$ per unit $n$. The revenues are proportional to the number of units multiplied by its price: $Revenues = n \\cdot Price $\n", - "\n", - "The demand depends on the price ($Price = 150 - 0.01n^2$), as shown in the graph:\n", - "\n", - "```{figure} ./coding_theory_widgets_images/output.png\n", - "---\n", - "width: 600px\n", - "name: demand with respect to pice\n", - "---\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The profit can be estimated as the revenues minus the total costs." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Model\n", - "The function for the profit can be found by combining the relations in the problem statement. However, this is the profit which should be maximized. To turn this into a minimization problem, the profit can be multiplied with $-1$. The final model of this problem results in:\n", - "\n", - "```{math}\n", - ":label: unconstrained_optimization_problem\n", - "\n", - "\\mathop {\\min }\\limits_n \\left(75n - \\left( 150 - 0.01n^2 \\right) n \\right)\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card}\n", - "\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Method\n", - "\n", - "This model is described using `scipy.optimize.minimize`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Importing libraries" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "tags": [ - "auto-execute-page", - "thebe-init" - ] - }, - "outputs": [], - "source": [ - "import scipy as sp \n", - "import numpy as np\n", - "import matplotlib.pylab as plt" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Defining the variables\n", - "There are very few variables in this problem. In fact, the only variable we have to specify is the initial guess for the optimization algorithm. The objective function will be treated later.\n", - "The length of $n$ doesn't have to be specified." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "tags": [ - "thebe-init" - ] - }, - "outputs": [], - "source": [ - "n0 = 20" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card}\n", - "\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Defining the objective function\n", - "In the objective function, the formula given in the model description can be inserted. Or, each individual step can be calculated on a seperate line. Again, note that the profit is multiplied with $-1$ to maximize the profit in the minimization formulation.\n", - "This results in:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "tags": [ - "thebe-init" - ] - }, - "outputs": [], - "source": [ - "def negprofit(n):\n", - " price = 150 - 0.01 * n**2\n", - " revenues = price * n\n", - " totalcost = 75 * n\n", - " profit = revenues - totalcost\n", - " return -profit" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Solving the problem\n", - "Now, the problem can be solved. The result is stored in the variables `result` which is printed." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "tags": [ - "thebe-init" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " message: Optimization terminated successfully.\n", - " success: True\n", - " status: 0\n", - " fun: -2499.9999999998727\n", - " x: [ 5.000e+01]\n", - " nit: 8\n", - " jac: [ 0.000e+00]\n", - " hess_inv: [[ 3.503e-01]]\n", - " nfev: 22\n", - " njev: 11\n" - ] - } - ], - "source": [ - "result = sp.optimize.minimize(negprofit,n0)\n", - "print(result)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card}\n", - "\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Postprocessing\n", - "As this case is only one-dimensional and the potential range of values is limited, we can easily check this answer by an exhaustive search, evaluating all possible values for $n$. The plot below shows the $\\text{negative profit}$ for $0" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "n_range = np.linspace(0,100,100)\n", - "negprofit_result = negprofit(n_range)\n", - "plt.plot(n_range,negprofit_result)\n", - "plt.plot(result.x,result.fun,'o');\n", - "plt.xlabel('$n$')\n", - "plt.ylabel('Negative profit');" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{card}\n", - "\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise\n", - "\n", - ":::{card}\n", - "Adapt the code to answer the following questions.\n", - "\n", - "\n", - "\n", - "\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "base", - "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" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/examples/coding_theory_widgets_images/output.png b/book/examples/coding_theory_widgets_images/output.png new file mode 100644 index 0000000..eafe77b Binary files /dev/null and b/book/examples/coding_theory_widgets_images/output.png differ diff --git a/book/features/interactive_element.ipynb b/book/features/interactive_element.ipynb deleted file mode 100644 index 2563004..0000000 --- a/book/features/interactive_element.ipynb +++ /dev/null @@ -1,752 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "hideCode": true, - "hidePrompt": true - }, - "source": [ - "# Interactive elements not including Python\n", - "\n", - "To add interactivity to the book, you can make use of interactive elements which are embedded in the book. You've four options:\n", - "\n", - " - Admonition: question provided in normal markdown language with answers in a drowdown menu. There's no feedback delivered to the student, only the correct answer no matter what the student's thinking/work.\n", - " - JupyterQuiz: code-based implementation of multiple-choiche questions and numerical answer questions. This is a basic open course tool which requires you to write your quiz questions in Python language as a `dict` or to a `.json` file.\n", - " - H5p: TU-Delft-licensed tool to create questions (and many other interactive elements) using an [online GUI](https://tudelft.h5p.com/). These elements are embedded into the book using an iframe which requires very little coding. This elements are easier to implement than the JupyterQuiz and have more features (although proper numerical answer questions are missing). More information on this is provided in the [CiTG Jupyter Book introduction book](https://interactivetextbooks.citg.tudelft.nl/jupyter-book-manual/cookbook/h5p.html)\n", - " - Grasple-exercises: TU-Delft-licensed tool to creating math-based quiz questions. Again, these elements are embedded into the book using an iframe which requiries very little coding. These elements are very well suited to math-based problems as it allows analytical evaluation of numerical values and formulas. Furthermore, Grasple allows parameterization (not required for formative exercises). More information on this is provided in the [CiTG Jupyter Book introduction book](https://interactivetextbooks.citg.tudelft.nl/jupyter-book-manual/cookbook/grasple.html)\n", - " - Non-kernel-based widgets: You can create interactive widgets with Python which doesn't need a kernel to run online. The use of the [plotly](https://plotly.com/python/getting-started/) package is an example which allows this use.\n", - "\n", - "Examples of each type is shown below based on the following problem:\n", - "\n", - "A pre-fabricated bridge design is being considered for river crossings in a remote region of the world, as shown in Figure 1. Cities 1, 2 and 3 are labelled C1, C2 and C3, with bridges labelled B1-B4.\n", - "\n", - "```{figure} ../figures/pd/simple-city.png\n", - "---\n", - "width: 600px\n", - "name: exercise-simple-city\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "hideCode": true, - "hidePrompt": true - }, - "source": [ - "## Admonition\n", - "If the probability of failure for an individual bridge is 0.1 per year, compute the probability that you cannot drive from City 1 to City 2\n", - "\n", - "\n", - "```{admonition} Answer\n", - ":class: tip, dropdown\n", - "\n", - "$$\n", - " P_{f_{C1-C2}} = P_{f_{B1}} * P_{f_{B4-B3-B2}} = P_{f_{B1}} * (1 - (1 - P_{f_{B4}})(1 - P_{f_{B3}}*P_{f_{B2}}))\n", - "$$\n", - "$$\n", - " P_{f_{C1 - C2}} = 0.1 * (1 - (1 - 0.1)(1 - 0.1 * 0.1)) = 0.0109\n", - "$$\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "hideCode": true, - "hidePrompt": true - }, - "source": [ - "## JupyterQuiz" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "hideCode": true, - "hidePrompt": true, - "tags": [ - "disable-execution-page", - "disable-download-page", - "remove-input" - ] - }, - "outputs": [ - { - "data": { - "text/html": [ - "
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "var questionsabVDrvSsNeVg=[{\"question\": \"If the probability of failure for an individual bridge is 0.1 per year, compute the probability that you cannot drive from City 1 to City 2:\", \"type\": \"numeric\", \"answers\": [{\"type\": \"range\", \"value\": 0.0109, \"correct\": true, \"feedback\": \"Correct.\"}, {\"type\": \"default\", \"feedback\": \"Try again\"}]}];\n // Make a random ID\nfunction makeid(length) {\n var result = [];\n var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n var charactersLength = characters.length;\n for (var i = 0; i < length; i++) {\n result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));\n }\n return result.join('');\n}\n\n// Choose a random subset of an array. Can also be used to shuffle the array\nfunction getRandomSubarray(arr, size) {\n var shuffled = arr.slice(0), i = arr.length, temp, index;\n while (i--) {\n index = Math.floor((i + 1) * Math.random());\n temp = shuffled[index];\n shuffled[index] = shuffled[i];\n shuffled[i] = temp;\n }\n return shuffled.slice(0, size);\n}\n\nfunction printResponses(responsesContainer) {\n var responses=JSON.parse(responsesContainer.dataset.responses);\n var stringResponses='IMPORTANT!To preserve this answer sequence for submission, when you have finalized your answers:
  1. Copy the text in this cell below \"Answer String\"
  2. Double click on the cell directly below the Answer String, labeled \"Replace Me\"
  3. Select the whole \"Replace Me\" text
  4. Paste in your answer string and press shift-Enter.
  5. Save the notebook using the save icon or File->Save Notebook menu item



  6. Answer String:
    ';\n console.log(responses);\n responses.forEach((response, index) => {\n if (response) {\n console.log(index + ': ' + response);\n stringResponses+= index + ': ' + response +\"
    \";\n }\n });\n responsesContainer.innerHTML=stringResponses;\n}\nfunction check_mc() {\n var id = this.id.split('-')[0];\n //var response = this.id.split('-')[1];\n //console.log(response);\n //console.log(\"In check_mc(), id=\"+id);\n //console.log(event.srcElement.id) \n //console.log(event.srcElement.dataset.correct) \n //console.log(event.srcElement.dataset.feedback)\n\n var label = event.srcElement;\n //console.log(label, label.nodeName);\n var depth = 0;\n while ((label.nodeName != \"LABEL\") && (depth < 20)) {\n label = label.parentElement;\n console.log(depth, label);\n depth++;\n }\n\n\n\n var answers = label.parentElement.children;\n\n //console.log(answers);\n\n\n // Split behavior based on multiple choice vs many choice:\n var fb = document.getElementById(\"fb\" + id);\n\n\n\n\n if (fb.dataset.numcorrect == 1) {\n // What follows is for the saved responses stuff\n var outerContainer = fb.parentElement.parentElement;\n var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n if (responsesContainer) {\n //console.log(responsesContainer);\n var response = label.firstChild.innerText;\n if (label.querySelector(\".QuizCode\")){\n response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n }\n console.log(response);\n //console.log(document.getElementById(\"quizWrap\"+id));\n var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n console.log(\"Question \" + qnum);\n //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n var responses=JSON.parse(responsesContainer.dataset.responses);\n console.log(responses);\n responses[qnum]= response;\n responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n printResponses(responsesContainer);\n }\n // End code to preserve responses\n \n for (var i = 0; i < answers.length; i++) {\n var child = answers[i];\n //console.log(child);\n child.className = \"MCButton\";\n }\n\n\n\n if (label.dataset.correct == \"true\") {\n // console.log(\"Correct action\");\n if (\"feedback\" in label.dataset) {\n fb.textContent = jaxify(label.dataset.feedback);\n } else {\n fb.textContent = \"Correct!\";\n }\n label.classList.add(\"correctButton\");\n\n fb.className = \"Feedback\";\n fb.classList.add(\"correct\");\n\n } else {\n if (\"feedback\" in label.dataset) {\n fb.textContent = jaxify(label.dataset.feedback);\n } else {\n fb.textContent = \"Incorrect -- try again.\";\n }\n //console.log(\"Error action\");\n label.classList.add(\"incorrectButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"incorrect\");\n }\n }\n else {\n var reset = false;\n var feedback;\n if (label.dataset.correct == \"true\") {\n if (\"feedback\" in label.dataset) {\n feedback = jaxify(label.dataset.feedback);\n } else {\n feedback = \"Correct!\";\n }\n if (label.dataset.answered <= 0) {\n if (fb.dataset.answeredcorrect < 0) {\n fb.dataset.answeredcorrect = 1;\n reset = true;\n } else {\n fb.dataset.answeredcorrect++;\n }\n if (reset) {\n for (var i = 0; i < answers.length; i++) {\n var child = answers[i];\n child.className = \"MCButton\";\n child.dataset.answered = 0;\n }\n }\n label.classList.add(\"correctButton\");\n label.dataset.answered = 1;\n fb.className = \"Feedback\";\n fb.classList.add(\"correct\");\n\n }\n } else {\n if (\"feedback\" in label.dataset) {\n feedback = jaxify(label.dataset.feedback);\n } else {\n feedback = \"Incorrect -- try again.\";\n }\n if (fb.dataset.answeredcorrect > 0) {\n fb.dataset.answeredcorrect = -1;\n reset = true;\n } else {\n fb.dataset.answeredcorrect--;\n }\n\n if (reset) {\n for (var i = 0; i < answers.length; i++) {\n var child = answers[i];\n child.className = \"MCButton\";\n child.dataset.answered = 0;\n }\n }\n label.classList.add(\"incorrectButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"incorrect\");\n }\n // What follows is for the saved responses stuff\n var outerContainer = fb.parentElement.parentElement;\n var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n if (responsesContainer) {\n //console.log(responsesContainer);\n var response = label.firstChild.innerText;\n if (label.querySelector(\".QuizCode\")){\n response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n }\n console.log(response);\n //console.log(document.getElementById(\"quizWrap\"+id));\n var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n console.log(\"Question \" + qnum);\n //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n var responses=JSON.parse(responsesContainer.dataset.responses);\n if (label.dataset.correct == \"true\") {\n if (typeof(responses[qnum]) == \"object\"){\n if (!responses[qnum].includes(response))\n responses[qnum].push(response);\n } else{\n responses[qnum]= [ response ];\n }\n } else {\n responses[qnum]= response;\n }\n console.log(responses);\n responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n printResponses(responsesContainer);\n }\n // End save responses stuff\n\n\n\n var numcorrect = fb.dataset.numcorrect;\n var answeredcorrect = fb.dataset.answeredcorrect;\n if (answeredcorrect >= 0) {\n fb.textContent = feedback + \" [\" + answeredcorrect + \"/\" + numcorrect + \"]\";\n } else {\n fb.textContent = feedback + \" [\" + 0 + \"/\" + numcorrect + \"]\";\n }\n\n\n }\n\n if (typeof MathJax != 'undefined') {\n var version = MathJax.version;\n console.log('MathJax version', version);\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n MathJax.typeset([fb]);\n }\n } else {\n console.log('MathJax not detected');\n }\n\n}\n\nfunction make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id) {\n var shuffled;\n if (shuffle_answers == \"True\") {\n //console.log(shuffle_answers+\" read as true\");\n shuffled = getRandomSubarray(qa.answers, qa.answers.length);\n } else {\n //console.log(shuffle_answers+\" read as false\");\n shuffled = qa.answers;\n }\n\n\n var num_correct = 0;\n\n\n\n shuffled.forEach((item, index, ans_array) => {\n //console.log(answer);\n\n // Make input element\n var inp = document.createElement(\"input\");\n inp.type = \"radio\";\n inp.id = \"quizo\" + id + index;\n inp.style = \"display:none;\";\n aDiv.append(inp);\n\n //Make label for input element\n var lab = document.createElement(\"label\");\n lab.className = \"MCButton\";\n lab.id = id + '-' + index;\n lab.onclick = check_mc;\n var aSpan = document.createElement('span');\n aSpan.classsName = \"\";\n //qDiv.id=\"quizQn\"+id+index;\n if (\"answer\" in item) {\n aSpan.innerHTML = jaxify(item.answer);\n //aSpan.innerHTML=item.answer;\n }\n lab.append(aSpan);\n\n // Create div for code inside question\n var codeSpan;\n if (\"code\" in item) {\n codeSpan = document.createElement('span');\n codeSpan.id = \"code\" + id + index;\n codeSpan.className = \"QuizCode\";\n var codePre = document.createElement('pre');\n codeSpan.append(codePre);\n var codeCode = document.createElement('code');\n codePre.append(codeCode);\n codeCode.innerHTML = item.code;\n lab.append(codeSpan);\n //console.log(codeSpan);\n }\n\n //lab.textContent=item.answer;\n\n // Set the data attributes for the answer\n lab.setAttribute('data-correct', item.correct);\n if (item.correct) {\n num_correct++;\n }\n if (\"feedback\" in item) {\n lab.setAttribute('data-feedback', item.feedback);\n }\n lab.setAttribute('data-answered', 0);\n\n aDiv.append(lab);\n\n });\n\n if (num_correct > 1) {\n outerqDiv.className = \"ManyChoiceQn\";\n } else {\n outerqDiv.className = \"MultipleChoiceQn\";\n }\n\n return num_correct;\n\n}\nfunction check_numeric(ths, event) {\n\n if (event.keyCode === 13) {\n ths.blur();\n\n var id = ths.id.split('-')[0];\n\n var submission = ths.value;\n if (submission.indexOf('/') != -1) {\n var sub_parts = submission.split('/');\n //console.log(sub_parts);\n submission = sub_parts[0] / sub_parts[1];\n }\n //console.log(\"Reader entered\", submission);\n\n if (\"precision\" in ths.dataset) {\n var precision = ths.dataset.precision;\n // console.log(\"1:\", submission)\n submission = Math.round((1 * submission + Number.EPSILON) * 10 ** precision) / 10 ** precision;\n // console.log(\"Rounded to \", submission, \" precision=\", precision );\n }\n\n\n //console.log(\"In check_numeric(), id=\"+id);\n //console.log(event.srcElement.id) \n //console.log(event.srcElement.dataset.feedback)\n\n var fb = document.getElementById(\"fb\" + id);\n fb.style.display = \"none\";\n fb.textContent = \"Incorrect -- try again.\";\n\n var answers = JSON.parse(ths.dataset.answers);\n //console.log(answers);\n\n var defaultFB = \"\";\n var correct;\n var done = false;\n answers.every(answer => {\n //console.log(answer.type);\n\n correct = false;\n // if (answer.type==\"value\"){\n if ('value' in answer) {\n if (submission == answer.value) {\n if (\"feedback\" in answer) {\n fb.textContent = jaxify(answer.feedback);\n } else {\n fb.textContent = jaxify(\"Correct\");\n }\n correct = answer.correct;\n //console.log(answer.correct);\n done = true;\n }\n // } else if (answer.type==\"range\") {\n } else if ('range' in answer) {\n //console.log(answer.range);\n if ((submission >= answer.range[0]) && (submission < answer.range[1])) {\n fb.textContent = jaxify(answer.feedback);\n correct = answer.correct;\n //console.log(answer.correct);\n done = true;\n }\n } else if (answer.type == \"default\") {\n defaultFB = answer.feedback;\n }\n if (done) {\n return false; // Break out of loop if this has been marked correct\n } else {\n return true; // Keep looking for case that includes this as a correct answer\n }\n });\n\n if ((!done) && (defaultFB != \"\")) {\n fb.innerHTML = jaxify(defaultFB);\n //console.log(\"Default feedback\", defaultFB);\n }\n\n fb.style.display = \"block\";\n if (correct) {\n ths.className = \"Input-text\";\n ths.classList.add(\"correctButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"correct\");\n } else {\n ths.className = \"Input-text\";\n ths.classList.add(\"incorrectButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"incorrect\");\n }\n\n // What follows is for the saved responses stuff\n var outerContainer = fb.parentElement.parentElement;\n var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n if (responsesContainer) {\n console.log(submission);\n var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n //console.log(\"Question \" + qnum);\n //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n var responses=JSON.parse(responsesContainer.dataset.responses);\n console.log(responses);\n if (submission == ths.value){\n responses[qnum]= submission;\n } else {\n responses[qnum]= ths.value + \"(\" + submission +\")\";\n }\n responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n printResponses(responsesContainer);\n }\n // End code to preserve responses\n\n if (typeof MathJax != 'undefined') {\n var version = MathJax.version;\n console.log('MathJax version', version);\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n MathJax.typeset([fb]);\n }\n } else {\n console.log('MathJax not detected');\n }\n return false;\n }\n\n}\n\nfunction isValid(el, charC) {\n //console.log(\"Input char: \", charC);\n if (charC == 46) {\n if (el.value.indexOf('.') === -1) {\n return true;\n } else if (el.value.indexOf('/') != -1) {\n var parts = el.value.split('/');\n if (parts[1].indexOf('.') === -1) {\n return true;\n }\n }\n else {\n return false;\n }\n } else if (charC == 47) {\n if (el.value.indexOf('/') === -1) {\n if ((el.value != \"\") && (el.value != \".\")) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n } else if (charC == 45) {\n var edex = el.value.indexOf('e');\n if (edex == -1) {\n edex = el.value.indexOf('E');\n }\n\n if (el.value == \"\") {\n return true;\n } else if (edex == (el.value.length - 1)) { // If just after e or E\n return true;\n } else {\n return false;\n }\n } else if (charC == 101) { // \"e\"\n if ((el.value.indexOf('e') === -1) && (el.value.indexOf('E') === -1) && (el.value.indexOf('/') == -1)) {\n // Prev symbol must be digit or decimal point:\n if (el.value.slice(-1).search(/\\d/) >= 0) {\n return true;\n } else if (el.value.slice(-1).search(/\\./) >= 0) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n } else {\n if (charC > 31 && (charC < 48 || charC > 57))\n return false;\n }\n return true;\n}\n\nfunction numeric_keypress(evnt) {\n var charC = (evnt.which) ? evnt.which : evnt.keyCode;\n\n if (charC == 13) {\n check_numeric(this, evnt);\n } else {\n return isValid(this, charC);\n }\n}\n\n\n\n\n\nfunction make_numeric(qa, outerqDiv, qDiv, aDiv, id) {\n\n\n\n //console.log(answer);\n\n\n outerqDiv.className = \"NumericQn\";\n aDiv.style.display = 'block';\n\n var lab = document.createElement(\"label\");\n lab.className = \"InpLabel\";\n lab.textContent = \"Type numeric answer here:\";\n aDiv.append(lab);\n\n var inp = document.createElement(\"input\");\n inp.type = \"text\";\n //inp.id=\"input-\"+id;\n inp.id = id + \"-0\";\n inp.className = \"Input-text\";\n inp.setAttribute('data-answers', JSON.stringify(qa.answers));\n if (\"precision\" in qa) {\n inp.setAttribute('data-precision', qa.precision);\n }\n aDiv.append(inp);\n //console.log(inp);\n\n //inp.addEventListener(\"keypress\", check_numeric);\n //inp.addEventListener(\"keypress\", numeric_keypress);\n /*\n inp.addEventListener(\"keypress\", function(event) {\n return numeric_keypress(this, event);\n }\n );\n */\n //inp.onkeypress=\"return numeric_keypress(this, event)\";\n inp.onkeypress = numeric_keypress;\n inp.onpaste = event => false;\n\n inp.addEventListener(\"focus\", function (event) {\n this.value = \"\";\n return false;\n }\n );\n\n\n}\nfunction jaxify(string) {\n var mystring = string;\n\n var count = 0;\n var loc = mystring.search(/([^\\\\]|^)(\\$)/);\n\n var count2 = 0;\n var loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n\n //console.log(loc);\n\n while ((loc >= 0) || (loc2 >= 0)) {\n\n /* Have to replace all the double $$ first with current implementation */\n if (loc2 >= 0) {\n if (count2 % 2 == 0) {\n mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\[\");\n } else {\n mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\]\");\n }\n count2++;\n } else {\n if (count % 2 == 0) {\n mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\(\");\n } else {\n mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\)\");\n }\n count++;\n }\n loc = mystring.search(/([^\\\\]|^)(\\$)/);\n loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n //console.log(mystring,\", loc:\",loc,\", loc2:\",loc2);\n }\n\n //console.log(mystring);\n return mystring;\n}\n\n\nfunction show_questions(json, mydiv) {\n console.log('show_questions');\n //var mydiv=document.getElementById(myid);\n var shuffle_questions = mydiv.dataset.shufflequestions;\n var num_questions = mydiv.dataset.numquestions;\n var shuffle_answers = mydiv.dataset.shuffleanswers;\n var max_width = mydiv.dataset.maxwidth;\n\n if (num_questions > json.length) {\n num_questions = json.length;\n }\n\n var questions;\n if ((num_questions < json.length) || (shuffle_questions == \"True\")) {\n //console.log(num_questions+\",\"+json.length);\n questions = getRandomSubarray(json, num_questions);\n } else {\n questions = json;\n }\n\n //console.log(\"SQ: \"+shuffle_questions+\", NQ: \" + num_questions + \", SA: \", shuffle_answers);\n\n // Iterate over questions\n questions.forEach((qa, index, array) => {\n //console.log(qa.question); \n\n var id = makeid(8);\n //console.log(id);\n\n\n // Create Div to contain question and answers\n var iDiv = document.createElement('div');\n //iDiv.id = 'quizWrap' + id + index;\n iDiv.id = 'quizWrap' + id;\n iDiv.className = 'Quiz';\n iDiv.setAttribute('data-qnum', index);\n iDiv.style.maxWidth =max_width+\"px\";\n mydiv.appendChild(iDiv);\n // iDiv.innerHTML=qa.question;\n \n var outerqDiv = document.createElement('div');\n outerqDiv.id = \"OuterquizQn\" + id + index;\n // Create div to contain question part\n var qDiv = document.createElement('div');\n qDiv.id = \"quizQn\" + id + index;\n \n if (qa.question) {\n iDiv.append(outerqDiv);\n\n //qDiv.textContent=qa.question;\n qDiv.innerHTML = jaxify(qa.question);\n outerqDiv.append(qDiv);\n }\n\n // Create div for code inside question\n var codeDiv;\n if (\"code\" in qa) {\n codeDiv = document.createElement('div');\n codeDiv.id = \"code\" + id + index;\n codeDiv.className = \"QuizCode\";\n var codePre = document.createElement('pre');\n codeDiv.append(codePre);\n var codeCode = document.createElement('code');\n codePre.append(codeCode);\n codeCode.innerHTML = qa.code;\n outerqDiv.append(codeDiv);\n //console.log(codeDiv);\n }\n\n\n // Create div to contain answer part\n var aDiv = document.createElement('div');\n aDiv.id = \"quizAns\" + id + index;\n aDiv.className = 'Answer';\n iDiv.append(aDiv);\n\n //console.log(qa.type);\n\n var num_correct;\n if ((qa.type == \"multiple_choice\") || (qa.type == \"many_choice\") ) {\n num_correct = make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id);\n if (\"answer_cols\" in qa) {\n //aDiv.style.gridTemplateColumns = 'auto '.repeat(qa.answer_cols);\n aDiv.style.gridTemplateColumns = 'repeat(' + qa.answer_cols + ', 1fr)';\n }\n } else if (qa.type == \"numeric\") {\n //console.log(\"numeric\");\n make_numeric(qa, outerqDiv, qDiv, aDiv, id);\n }\n\n\n //Make div for feedback\n var fb = document.createElement(\"div\");\n fb.id = \"fb\" + id;\n //fb.style=\"font-size: 20px;text-align:center;\";\n fb.className = \"Feedback\";\n fb.setAttribute(\"data-answeredcorrect\", 0);\n fb.setAttribute(\"data-numcorrect\", num_correct);\n iDiv.append(fb);\n\n\n });\n var preserveResponses = mydiv.dataset.preserveresponses;\n console.log(preserveResponses);\n console.log(preserveResponses == \"true\");\n if (preserveResponses == \"true\") {\n console.log(preserveResponses);\n // Create Div to contain record of answers\n var iDiv = document.createElement('div');\n iDiv.id = 'responses' + mydiv.id;\n iDiv.className = 'JCResponses';\n // Create a place to store responses as an empty array\n iDiv.setAttribute('data-responses', '[]');\n\n // Dummy Text\n iDiv.innerHTML=\"Select your answers and then follow the directions that will appear here.\"\n //iDiv.className = 'Quiz';\n mydiv.appendChild(iDiv);\n }\n//console.log(\"At end of show_questions\");\n if (typeof MathJax != 'undefined') {\n console.log(\"MathJax version\", MathJax.version);\n var version = MathJax.version;\n setTimeout(function(){\n var version = MathJax.version;\n console.log('After sleep, MathJax version', version);\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n MathJax.typeset([mydiv]);\n }\n }, 500);\nif (typeof version == 'undefined') {\n } else\n {\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n MathJax.typeset([mydiv]);\n } else {\n console.log(\"MathJax not found\");\n }\n }\n }\n return false;\n}\n/* This is to handle asynchrony issues in loading Jupyter notebooks\n where the quiz has been previously run. The Javascript was generally\n being run before the div was added to the DOM. I tried to do this\n more elegantly using Mutation Observer, but I didn't get it to work.\n\n Someone more knowledgeable could make this better ;-) */\n\n function try_show() {\n if(document.getElementById(\"abVDrvSsNeVg\")) {\n show_questions(questionsabVDrvSsNeVg, abVDrvSsNeVg); \n } else {\n setTimeout(try_show, 200);\n }\n };\n \n {\n // console.log(element);\n\n //console.log(\"abVDrvSsNeVg\");\n // console.log(document.getElementById(\"abVDrvSsNeVg\"));\n\n try_show();\n }\n ", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import json\n", - "from jupyterquiz import display_quiz\n", - "with open(\"jupyterquizexample.json\", \"r\") as file:\n", - " questions=json.load(file)\n", - "\n", - "display_quiz(questions, border_radius=0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "hideCode": true, - "hidePrompt": true - }, - "source": [ - "## H5p\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "hideCode": true, - "hidePrompt": true - }, - "source": [ - "## Grasple\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Interactive widget without kernel\n", - "\n", - "The example below is taken from the FEM-module by Frans van der Meer.\n", - "When using Plotly graphs, make sure the notebook is executed in Jupyter Lab / Jupyter Notebook for the figures to be shown in the book. Running the code in VS code might break the result in the book, although the output is visible in VS code. Alternatively, add the following lines of code to your notebook to have a valid output in the book as well:\n", - "\n", - "```python\n", - "import plotly.io as pio\n", - "pio.renderers.default = 'notebook'\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "%matplotlib widget\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import plotly.subplots as sp\n", - "import plotly.graph_objects as go\n", - "import plotly.io as pio\n", - "pio.renderers.default = 'notebook'" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6241088f78f046be86f2e814448e8790", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAIyUlEQVR4nO3WMQEAIAzAMMC/5+ECjiYKenbPzCwAADLO7wAAAN4ygAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIMIABAjAEEAIgxgAAAMQYQACDGAAIAxBhAAIAYAwgAEGMAAQBiDCAAQIwBBACIMYAAADEGEAAgxgACAMQYQACAGAMIABBjAAEAYgwgAECMAQQAiDGAAAAxBhAAIMYAAgDEGEAAgBgDCAAQYwABAGIuJnkHvKensmIAAAAASUVORK5CYII=", - "text/html": [ - "\n", - "
    \n", - "
    \n", - " Figure\n", - "
    \n", - " \n", - "
    \n", - " " - ], - "text/plain": [ - "Canvas(toolbar=None)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.rcParams.update({'font.size': 12, 'lines.linewidth': 2})\n", - "\n", - "def shape_functions(total_length, num_nodes, node_x):\n", - " l = total_length / (num_nodes - 1)\n", - "\n", - " if node_x == 0:\n", - " x = np.array([node_x, node_x + l])\n", - " y = np.array([1.0, 0.0])\n", - " elif node_x == total_length:\n", - " x = np.array([node_x - l, node_x])\n", - " y = np.array([0.0, 1.0])\n", - " else:\n", - " x = np.array([node_x - l, node_x, node_x + l])\n", - " y = np.array([0.0, 1.0, 0.0])\n", - "\n", - " return x, y\n", - "\n", - "def shape_functions_for_plot(num_nodes, beam_length = 15):\n", - "\n", - " x_positions = np.linspace(0, beam_length, num_nodes)\n", - "\n", - " data = {}\n", - "\n", - " for node_num, x_coords in enumerate(x_positions):\n", - "\n", - " x, y = shape_functions(beam_length, num_nodes, x_coords)\n", - " data[node_num + 1] = {'x': x, 'y': y}\n", - "\n", - " return data" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "def linear_lagrange_shape_function(x, nodes_x_values, nodes_displacements):\n", - " \"\"\"\n", - " Compute the linear Lagrange shape function for a given x.\n", - " Args:\n", - " x (float): The x-coordinate.\n", - " x0 (float): Left node position.\n", - " x1 (float): Right node position.\n", - " Returns:\n", - " float: The shape function value.\n", - " \"\"\"\n", - "\n", - " ratio = (x - nodes_x_values[0]) / (nodes_x_values[1] - nodes_x_values[0])\n", - "\n", - " return (1 - ratio) * nodes_displacements[0] + ratio * nodes_displacements[1]\n", - "\n", - "def function(x):\n", - " \"\"\"\n", - " Define the function to be plotted.\n", - " Args:\n", - " x (numpy.ndarray): Input values.\n", - " Returns:\n", - " numpy.ndarray: Corresponding function values.\n", - " \"\"\"\n", - " return np.sin(x) * 0.14*x\n", - "\n", - "def shape_functions_applied(num_elements):\n", - " \"\"\"\n", - " Plot linear Lagrange shape functions on a beam.\n", - " Args:\n", - " num_elements (int): Number of elements (segments).\n", - " \"\"\"\n", - "\n", - " beam_length = 15\n", - "\n", - " num_nodes = num_elements + 1\n", - " x_at_nodes = np.linspace(0, beam_length, num_nodes)\n", - "\n", - " y_at_nodes = function(x_at_nodes)\n", - "\n", - " x_data = np.linspace(0, beam_length, 1000)\n", - "\n", - " # Use NumPy to compute y_vals efficiently\n", - " y_vals = np.zeros_like(x_data)\n", - "\n", - " for element_number in range(num_elements):\n", - " mask = (x_at_nodes[element_number] <= x_data) & (x_data <= x_at_nodes[element_number + 1])\n", - " y_vals[mask] = linear_lagrange_shape_function(x_data[mask], x_at_nodes[element_number:element_number + 2], y_at_nodes[element_number:element_number + 2])\n", - "\n", - " return x_data, function(x_data), y_vals\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "tags": [ - "remove-input" - ] - }, - "outputs": [ - { - "data": { - "text/html": [ - " \n", - " " - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
    " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Colors\n", - "grey = '#eeeeee' # light grey fill\n", - "\n", - "# Prepare all the graphs that are to be plotted\n", - "range_elements = np.concatenate((np.arange(1, 7, 1), np.arange(7, 35, 4), np.arange(35, 55, 8)))\n", - "\n", - "# Create subplots\n", - "fig = sp.make_subplots(rows=1, cols=2, subplot_titles=(\"Shape functions\", \"Exact and approximated solution\"))\n", - "\n", - "base_traces_left = 2 # Number of traces in the left plot that are always visible\n", - "base_traces_right = 0 # Number of traces in the right plot that are always visible\n", - "\n", - "# Add traces to the subplots\n", - "x_data, y_data, y_vals = shape_functions_applied(10)\n", - "\n", - "# Add left plot traces (Cumulative Influx and Cumulative Outflux)\n", - "fig.add_trace(\n", - " go.Scatter(\n", - " visible=True, # Show for the first value of a\n", - " x=x_data,\n", - " y=y_data,\n", - " # line=dict(color='#6a8ba4'),\n", - " mode='lines',\n", - " name='Exact solution'\n", - " ),\n", - " row=1,\n", - " col=2\n", - ")\n", - "\n", - "\n", - "# Add traces to the subplots\n", - "for a in range_elements:\n", - "\n", - " x_data, y_data, y_vals = shape_functions_applied(a)\n", - "\n", - " fig.add_trace(\n", - " go.Scatter(\n", - " visible = True if a == range_elements[0] else False, # Show for the first value of a\n", - " x=x_data,\n", - " y=y_vals,\n", - " # line=dict(color='#FFA500'),\n", - " mode='lines',\n", - " name='Numerical solution'\n", - " ),\n", - " row=1,\n", - " col=2\n", - " )\n", - "\n", - "\n", - "# Add traces to the subplots\n", - "for a in range_elements:\n", - "\n", - " data = shape_functions_for_plot(a + 1)\n", - "\n", - " for i in range(1, a + 2):\n", - "\n", - " info = data[i]\n", - " x, y = info['x'], info['y']\n", - "\n", - " # Add right plot traces (Cumulative Outflux for each 'a' value)\n", - " fig.add_trace(\n", - " go.Scatter(\n", - " visible = True if a == range_elements[0] else False,\n", - " x=x,\n", - " y=y,\n", - " mode='lines',\n", - " name=f'Node shape for node {i}'\n", - " ),\n", - " row=1,\n", - " col=1\n", - " )\n", - "\n", - "# Create and add slider\n", - "steps = []\n", - "for i in range(0, range_elements.shape[0]):\n", - "\n", - " a = range_elements[i]\n", - " visarray = [False] * len(fig.data)\n", - "\n", - " visarray[0] = True\n", - " visarray[i + 1] = True\n", - "\n", - " start_of_second_plot = 1 + len(range_elements)\n", - "\n", - " if i==0:\n", - " start_index=start_of_second_plot\n", - " else:\n", - " start_index = start_of_second_plot + np.sum(range_elements[0:i]) + i\n", - "\n", - " num_lines = range_elements[i] + 1\n", - " end_index = start_index + num_lines\n", - "\n", - " visarray[start_index:end_index] = [True] * (end_index - start_index)\n", - " \n", - " step = dict(\n", - " method=\"update\",\n", - " args=[{\"visible\": visarray}],\n", - " label=str(round(range_elements[i], 1))\n", - " )\n", - " steps.append(step)\n", - "\n", - "sliders = [dict(\n", - " active=0, # Show the first value of 'a' initially\n", - " currentvalue={\"prefix\": r\"Number of elements: \"},\n", - " steps=steps\n", - ")]\n", - "\n", - "fig.update_layout(\n", - " sliders=sliders,\n", - " title=\"Applying shape functions\",\n", - " legend_title=\"Legend\",\n", - " legend=dict(\n", - " x=1.05, # Adjust the legend position\n", - " y=0.5\n", - " )\n", - ")\n", - "\n", - "fig.update_xaxes(title_text='x', row=1, col=1, range=[x_data[0], x_data[-1]])\n", - "fig.update_xaxes(title_text='x', row=1, col=2, range=[x_data[0], x_data[-1]])\n", - "\n", - "# Update y-axis properties\n", - "fig.update_yaxes(title_text='Node shape value', row=1, col=1, range=[-0.1, 1.1])\n", - "fig.update_yaxes(title_text='y', row=1, col=2, range=[-2.1, 2.1])\n", - "\n", - "fig.show()" - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "hide_code_all_hidden": true, - "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": 4 -} diff --git a/book/features/jupyterlite/interactive-wave.ipynb b/book/features/jupyterlite/interactive-wave.ipynb deleted file mode 100644 index c3be4a8..0000000 --- a/book/features/jupyterlite/interactive-wave.ipynb +++ /dev/null @@ -1,91 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "%gui asyncio\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from ipywidgets import interact" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
    " - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4570ae9da644449a87c3fea9c4d7f919", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(FloatSlider(value=3.0, description='omega', max=5.0, min=1.0), Output()), _dom_classes=(…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x = np.linspace(0, 2*np.pi, 100)\n", - "fig, ax = plt.subplots()\n", - "line, = ax.plot(x, np.sin(x))\n", - "\n", - "def plot_sine_wave(omega):\n", - " y = np.sin(omega*x)\n", - " line.set_ydata(y)\n", - " fig.canvas.draw_idle()\n", - "\n", - "interact(plot_sine_wave, omega=(1, 5, 0.1))" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "base", - "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" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/book/features/jupyterlite/jupyterlite-gallery.md b/book/features/jupyterlite/jupyterlite-gallery.md deleted file mode 100644 index 0a6b0e5..0000000 --- a/book/features/jupyterlite/jupyterlite-gallery.md +++ /dev/null @@ -1,11 +0,0 @@ -# Gallery - -On this page, you can find some example usage of `JupyterLite`. The reader is invited to contribute to this gallery with their own interesting examples. - -## Interactive plot - -```{eval-rst} -.. retrolite:: interactive-wave.ipynb - :width: 100% - :height: 600px -``` \ No newline at end of file diff --git a/book/features/pd/1.png b/book/features/pd/1.png new file mode 100644 index 0000000..5227771 Binary files /dev/null and b/book/features/pd/1.png differ diff --git a/book/features/pd/FN-simple.PNG b/book/features/pd/FN-simple.PNG new file mode 100644 index 0000000..7e8eea1 Binary files /dev/null and b/book/features/pd/FN-simple.PNG differ diff --git a/book/features/pd/combined_risk_criteria.png b/book/features/pd/combined_risk_criteria.png new file mode 100644 index 0000000..bb9f78e Binary files /dev/null and b/book/features/pd/combined_risk_criteria.png differ diff --git a/book/features/pd/decision-tree-blank.png b/book/features/pd/decision-tree-blank.png new file mode 100644 index 0000000..cd88fd6 Binary files /dev/null and b/book/features/pd/decision-tree-blank.png differ diff --git a/book/features/pd/decision-tree-example.png b/book/features/pd/decision-tree-example.png new file mode 100644 index 0000000..f7cf16c Binary files /dev/null and b/book/features/pd/decision-tree-example.png differ diff --git a/book/features/pd/decision-tree-filled.png b/book/features/pd/decision-tree-filled.png new file mode 100644 index 0000000..96f45af Binary files /dev/null and b/book/features/pd/decision-tree-filled.png differ diff --git a/book/features/pd/design_1_rv.svg b/book/features/pd/design_1_rv.svg new file mode 100644 index 0000000..bc9fd29 --- /dev/null +++ b/book/features/pd/design_1_rv.svg @@ -0,0 +1,1789 @@ + + + + + + + + 2023-01-08T11:58:13.384461 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/design_2_rv_correct.svg b/book/features/pd/design_2_rv_correct.svg new file mode 100644 index 0000000..65b606f --- /dev/null +++ b/book/features/pd/design_2_rv_correct.svg @@ -0,0 +1,4713 @@ + + + + + + + + 2023-01-08T11:58:19.506423 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/design_2_rv_error_1.svg b/book/features/pd/design_2_rv_error_1.svg new file mode 100644 index 0000000..499e389 --- /dev/null +++ b/book/features/pd/design_2_rv_error_1.svg @@ -0,0 +1,1137 @@ + + + + + + + + 2023-01-08T11:58:13.587795 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/design_2_rv_error_2a.svg b/book/features/pd/design_2_rv_error_2a.svg new file mode 100644 index 0000000..4de95bf --- /dev/null +++ b/book/features/pd/design_2_rv_error_2a.svg @@ -0,0 +1,1128 @@ + + + + + + + + 2023-01-08T11:58:14.020152 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/design_2_rv_error_2b.svg b/book/features/pd/design_2_rv_error_2b.svg new file mode 100644 index 0000000..9c55c4a --- /dev/null +++ b/book/features/pd/design_2_rv_error_2b.svg @@ -0,0 +1,1175 @@ + + + + + + + + 2023-01-08T11:58:14.607877 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/design_2_rv_error_3.svg b/book/features/pd/design_2_rv_error_3.svg new file mode 100644 index 0000000..45a109c --- /dev/null +++ b/book/features/pd/design_2_rv_error_3.svg @@ -0,0 +1,727 @@ + + + + + + + + 2023-01-08T11:58:16.440884 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/dike_heightening_schematic.png b/book/features/pd/dike_heightening_schematic.png new file mode 100644 index 0000000..1520bc3 Binary files /dev/null and b/book/features/pd/dike_heightening_schematic.png differ diff --git a/book/features/pd/dike_rings.jpg b/book/features/pd/dike_rings.jpg new file mode 100644 index 0000000..235c24a Binary files /dev/null and b/book/features/pd/dike_rings.jpg differ diff --git a/book/features/pd/economic_opt.svg b/book/features/pd/economic_opt.svg new file mode 100644 index 0000000..21403f2 --- /dev/null +++ b/book/features/pd/economic_opt.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/ex_FN_curve_step_01_py.svg b/book/features/pd/ex_FN_curve_step_01_py.svg new file mode 100644 index 0000000..3a47dd5 --- /dev/null +++ b/book/features/pd/ex_FN_curve_step_01_py.svg @@ -0,0 +1,936 @@ + + + + + + + + 2022-12-19T21:15:04.881036 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/ex_FN_curve_step_02_py.svg b/book/features/pd/ex_FN_curve_step_02_py.svg new file mode 100644 index 0000000..97eece8 --- /dev/null +++ b/book/features/pd/ex_FN_curve_step_02_py.svg @@ -0,0 +1,1048 @@ + + + + + + + + 2022-12-19T21:15:05.264451 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/ex_FN_curve_step_03_py.svg b/book/features/pd/ex_FN_curve_step_03_py.svg new file mode 100644 index 0000000..a3d71a2 --- /dev/null +++ b/book/features/pd/ex_FN_curve_step_03_py.svg @@ -0,0 +1,822 @@ + + + + + + + + 2022-12-19T21:15:05.437199 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/example-river-excavation-2.png b/book/features/pd/example-river-excavation-2.png new file mode 100644 index 0000000..bf9da6e Binary files /dev/null and b/book/features/pd/example-river-excavation-2.png differ diff --git a/book/features/pd/example-river-excavation-3.PNG b/book/features/pd/example-river-excavation-3.PNG new file mode 100644 index 0000000..70a57e8 Binary files /dev/null and b/book/features/pd/example-river-excavation-3.PNG differ diff --git a/book/features/pd/example-river-excavation.png b/book/features/pd/example-river-excavation.png new file mode 100644 index 0000000..ddffa35 Binary files /dev/null and b/book/features/pd/example-river-excavation.png differ diff --git a/book/features/pd/exercise-FN-curve.png b/book/features/pd/exercise-FN-curve.png new file mode 100644 index 0000000..841146c Binary files /dev/null and b/book/features/pd/exercise-FN-curve.png differ diff --git a/book/features/pd/exercise-dam-fn-limit-line.png b/book/features/pd/exercise-dam-fn-limit-line.png new file mode 100644 index 0000000..bde9712 Binary files /dev/null and b/book/features/pd/exercise-dam-fn-limit-line.png differ diff --git a/book/features/pd/exercise-decision-tree.png b/book/features/pd/exercise-decision-tree.png new file mode 100644 index 0000000..75bbfaa Binary files /dev/null and b/book/features/pd/exercise-decision-tree.png differ diff --git a/book/features/pd/exercise-optimization.png b/book/features/pd/exercise-optimization.png new file mode 100644 index 0000000..b31e233 Binary files /dev/null and b/book/features/pd/exercise-optimization.png differ diff --git a/book/features/pd/exercise-sample-exam-bay.png b/book/features/pd/exercise-sample-exam-bay.png new file mode 100644 index 0000000..9283059 Binary files /dev/null and b/book/features/pd/exercise-sample-exam-bay.png differ diff --git a/book/features/pd/exercise-sample-exam-failure-domain.png b/book/features/pd/exercise-sample-exam-failure-domain.png new file mode 100644 index 0000000..8f37e8d Binary files /dev/null and b/book/features/pd/exercise-sample-exam-failure-domain.png differ diff --git a/book/features/pd/exercise-sample-exam-limit-line.png b/book/features/pd/exercise-sample-exam-limit-line.png new file mode 100644 index 0000000..97bb772 Binary files /dev/null and b/book/features/pd/exercise-sample-exam-limit-line.png differ diff --git a/book/features/pd/exercise-sample-exam-mortality.png b/book/features/pd/exercise-sample-exam-mortality.png new file mode 100644 index 0000000..7fe10aa Binary files /dev/null and b/book/features/pd/exercise-sample-exam-mortality.png differ diff --git a/book/features/pd/exercise_sample_IR.png b/book/features/pd/exercise_sample_IR.png new file mode 100644 index 0000000..047a895 Binary files /dev/null and b/book/features/pd/exercise_sample_IR.png differ diff --git a/book/features/pd/exercise_sample_opt.png b/book/features/pd/exercise_sample_opt.png new file mode 100644 index 0000000..2caeda7 Binary files /dev/null and b/book/features/pd/exercise_sample_opt.png differ diff --git a/book/features/pd/fn_limit.png b/book/features/pd/fn_limit.png new file mode 100644 index 0000000..e8cdf58 Binary files /dev/null and b/book/features/pd/fn_limit.png differ diff --git a/book/features/pd/fn_limit_eq.png b/book/features/pd/fn_limit_eq.png new file mode 100644 index 0000000..f0ed1b0 Binary files /dev/null and b/book/features/pd/fn_limit_eq.png differ diff --git a/book/features/pd/periodic_investments.png b/book/features/pd/periodic_investments.png new file mode 100644 index 0000000..1812b79 Binary files /dev/null and b/book/features/pd/periodic_investments.png differ diff --git a/book/features/pd/present_value_py.svg b/book/features/pd/present_value_py.svg new file mode 100644 index 0000000..e254b81 --- /dev/null +++ b/book/features/pd/present_value_py.svg @@ -0,0 +1,1089 @@ + + + + + + + + 2022-12-21T21:38:21.876407 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/rating_curve.svg b/book/features/pd/rating_curve.svg new file mode 100644 index 0000000..79564c7 --- /dev/null +++ b/book/features/pd/rating_curve.svg @@ -0,0 +1,1073 @@ + + + + + + + + 2023-01-08T11:58:12.535731 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/risk-curve-baecher.PNG b/book/features/pd/risk-curve-baecher.PNG new file mode 100644 index 0000000..560f4c7 Binary files /dev/null and b/book/features/pd/risk-curve-baecher.PNG differ diff --git a/book/features/pd/risk-hazard.svg b/book/features/pd/risk-hazard.svg new file mode 100644 index 0000000..7d2aa08 --- /dev/null +++ b/book/features/pd/risk-hazard.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/risk-steps.PNG b/book/features/pd/risk-steps.PNG new file mode 100644 index 0000000..0a29f92 Binary files /dev/null and b/book/features/pd/risk-steps.PNG differ diff --git a/book/features/pd/risk_contour.png b/book/features/pd/risk_contour.png new file mode 100644 index 0000000..4f12983 Binary files /dev/null and b/book/features/pd/risk_contour.png differ diff --git a/book/features/pd/risk_matrix.png b/book/features/pd/risk_matrix.png new file mode 100644 index 0000000..6791816 Binary files /dev/null and b/book/features/pd/risk_matrix.png differ diff --git a/book/features/pd/risk_types_py.svg b/book/features/pd/risk_types_py.svg new file mode 100644 index 0000000..264ca51 --- /dev/null +++ b/book/features/pd/risk_types_py.svg @@ -0,0 +1,1823 @@ + + + + + + + + 2022-12-21T22:08:56.838936 + image/svg+xml + + + Matplotlib v3.5.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/pd/simple-city.png b/book/features/pd/simple-city.png new file mode 100644 index 0000000..6cbfd7e Binary files /dev/null and b/book/features/pd/simple-city.png differ diff --git a/book/features/pd/system-corr-coeff.PNG b/book/features/pd/system-corr-coeff.PNG new file mode 100644 index 0000000..4009a11 Binary files /dev/null and b/book/features/pd/system-corr-coeff.PNG differ diff --git a/book/features/pd/system_lightbulbs.png b/book/features/pd/system_lightbulbs.png new file mode 100644 index 0000000..66f5c50 Binary files /dev/null and b/book/features/pd/system_lightbulbs.png differ diff --git a/book/features/pd/system_series_parallel.png b/book/features/pd/system_series_parallel.png new file mode 100644 index 0000000..c94edac Binary files /dev/null and b/book/features/pd/system_series_parallel.png differ diff --git a/book/features/pd/system_series_parallel_ex.png b/book/features/pd/system_series_parallel_ex.png new file mode 100644 index 0000000..a285cc5 Binary files /dev/null and b/book/features/pd/system_series_parallel_ex.png differ diff --git a/book/features/pd/temp.svg b/book/features/pd/temp.svg new file mode 100644 index 0000000..96d11d9 --- /dev/null +++ b/book/features/pd/temp.svg @@ -0,0 +1,1054 @@ + + + + +Created by potrace 1.8, written by Peter Selinger 2001-2007 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/features/theory_questions_images/Truss1.svg b/book/features/theory_questions_images/Truss1.svg new file mode 100644 index 0000000..e9b2179 --- /dev/null +++ b/book/features/theory_questions_images/Truss1.svg @@ -0,0 +1,135 @@ + + + + + + + + + + Pagina-1 + + + Vakwerk, 1 pt.16 + + + + Vakwerk, 1 pt.17 + + + + Vakwerk, 1 pt.18 + + + + Vakwerk, 1 pt.19 + + + + Vakwerk, 1 pt.20 + + + + Vakwerk, 1 pt.14 + + + + Vakwerk, 1 pt.15 + + + + Vakwerk, 1 pt.12 + + + + Vakwerk, 1 pt.13 + + + + Vakwerk, 1 pt + + + + Vakwerk, 1 pt.2 + + + + Scharnier + + + + Scharnier.4 + + + + Scharnier.5 + + + + Scharnier.6 + + + + Scharnier.7 + + + + Scharnier.8 + + + + Scharnier.9 + + + + Scharnier.10 + + + + Blad.21 + + + + Blad.22 + + + + Blad.23 + + + + Blad.24 + + + + Blad.25 + hinges + + + + hinges + + Blad.26 + bars + + + + bars + + diff --git a/book/features/theory_questions_images/gifje.gif b/book/features/theory_questions_images/gifje.gif new file mode 100644 index 0000000..20a4d57 Binary files /dev/null and b/book/features/theory_questions_images/gifje.gif differ diff --git a/book/features/theory_questions_images/pic0.jpg b/book/features/theory_questions_images/pic0.jpg new file mode 100644 index 0000000..7f2f938 Binary files /dev/null and b/book/features/theory_questions_images/pic0.jpg differ diff --git a/book/features/theory_questions_images/pic1.jpg b/book/features/theory_questions_images/pic1.jpg new file mode 100644 index 0000000..64c9cb8 Binary files /dev/null and b/book/features/theory_questions_images/pic1.jpg differ diff --git a/book/features/theory_questions_images/rectangle.svg b/book/features/theory_questions_images/rectangle.svg new file mode 100644 index 0000000..bbda50f --- /dev/null +++ b/book/features/theory_questions_images/rectangle.svg @@ -0,0 +1,77 @@ + + + + + + + + + + Pagina-1 + + + Vakwerk, 1 pt.1301 + + + + Vakwerk, 1 pt.1302 + + + + Vakwerk, 1 pt.1308 + + + + Vakwerk, 1 pt.1309 + + + + Scharnier.1305 + + + + Scharnier.1304 + + + + Scharnier.1307 + + + + Scharnier.1306 + + + + Blad.1310 + + + + Blad.1311 + + + + Vakwerk, 1 pt.1312 + + + + Scharnier.1313 + + + + Scharnier.1314 + + + + diff --git a/book/features/theory_questions_images/structure3.svg b/book/features/theory_questions_images/structure3.svg new file mode 100644 index 0000000..9e3a2e6 --- /dev/null +++ b/book/features/theory_questions_images/structure3.svg @@ -0,0 +1,118 @@ + + + + + + + + + + Pagina-1 + + + Vakwerk, 1 pt.1318 + + + + Vakwerk, 1 pt.1323 + + + + Vakwerk, 1 pt.1324 + + + + Vakwerk, 1 pt.1325 + + + + Vakwerk, 1 pt.1334 + + + + Vakwerk, 1 pt.1335 + + + + Vakwerk, 1 pt.1336 + + + + Vakwerk, 1 pt.1337 + + + + Vakwerk, 1 pt.1338 + + + + Vakwerk, 1 pt.1339 + + + + Vakwerk, 1 pt.1340 + + + + Vakwerk, 1 pt.1341 + + + + Vakwerk, 1 pt.1342 + + + + Vakwerk, 1 pt.1343 + + + + Vakwerk, 1 pt.1344 + + + + Scharnier.1329 + + + + Scharnier.1330 + + + + Scharnier.1326 + + + + Scharnier.1328 + + + + Scharnier.1331 + + + + Scharnier.1332 + + + + Scharnier.1345 + + + + Scharnier.1327 + + + + Scharnier.1333 + + + + diff --git a/book/features/theory_questions_images/triangle.svg b/book/features/theory_questions_images/triangle.svg new file mode 100644 index 0000000..ff8d4b5 --- /dev/null +++ b/book/features/theory_questions_images/triangle.svg @@ -0,0 +1,46 @@ + + + + + + + + + + Pagina-1 + + + Vakwerk, 1 pt.1294 + + + + Vakwerk, 1 pt.1295 + + + + Vakwerk, 1 pt.1296 + + + + Scharnier.1297 + + + + Scharnier.1298 + + + + Scharnier.1299 + + + +