{ "cells": [ { "cell_type": "markdown", "id": "2bed477f", "metadata": {}, "source": [ "# Overview" ] }, { "cell_type": "markdown", "id": "3b1f5409", "metadata": {}, "source": [ "[This notebook](https://github.com/nicolaipalm/paref/blob/main/docs/notebooks/main_example.ipynb)\n", "demonstrates almost everything you can do with Paref, from applying an existing MOO algorithm to a bbf to constructing your own MOO algorithm tailored to the problem, using a practical example. " ] }, { "cell_type": "markdown", "id": "ef516a2e", "metadata": {}, "source": [ "## Setup\n", "\n", "Let us imagine the following situation: We have a blackbox function (bbf) that we want to optimize multicriterially or, synonymously, multiobjectively (multi objective optimization, MOO). In other words, we are searching for the bbf Pareto front. The bbf can represent a machine for which we can set certain parameters (vector $x \\in D$, where D represents the domain of the problem, which we also call design space) and which then reacts measurably via certain target variables (vector $y \\in T$, where T represents the co-domain of the problem, which we also call target space). Or the bbf represents a simulation model, where we can also define specifications x for its design and obtain responses y through simulation.\n", " \n", "In our example, we choose as bbf the mathematical test function [Zitzler-Deb-Thiele N.1](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization). In the further course of our example, however, we assume that we do not know this function (which makes it a bbf). We can only \"test\" the bbf qua function calls in places we choose.\n", "\n", "This approach offers the following advantage: ZDT-1 is not only defined analytically, but we also know (analytically) its Pareto front. Thus, we can immediately compare our results with the expected results and see how well our new approach works.\n", "\n", "## What Paref offers\n", "\n", "In many cases, the general MOO problem is formulated as \"find the Pareto front\" and not specified more clearly. Many MOO algorithms are accordingly designed to do just that: They identify Pareto-optimal points (i.e. points on the Pareto front), but they do not guarantee the user any further properties (e.g. to identify co-domain corner points of the Pareto front). The package paref now allows exactly that: besides the general property \"identified points are Pareto-optimal\", paref users can specify further properties of the Pareto front to be identified and construct MOO algorithms based on those defined properties. \n", "On a top level, this works as follows:\n", "- properties of Pareto points are reflected by Pareto reflections or, more generally, by sequences of such \n", "- Paref provides a [library](../description/reflections.md) of such (partly customizable) Pareto reflections including a description of what properties are targeted\n", "- applying an [MOO](../description/moo-algorithms.md) to a blackbox function and a sequence results in an algorithmic search for Pareto points satisfying those properties ([with mathematical guarantees](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4668407)).\n", "\n", "\n", "## This example\n", "\n", "In this example we exploit almost all the functionality Paref provides, from implementing a blackbox function and apply an existing Paref MOO algorithm reflecting some properties all the way to construct our own problem specific MOO algorithm. \n", "Concrete we will do the following:\n", "\n", "1. Implement a blackbox function (ZDT-2)\n", "3. Analyze the optimization process\n", "2. Apply one of Parefs' MOO algorithms to the blackbox function\n", "3. Analyze the results \n", "3. Apply an MOO algorithm to some Pareto reflection in order to target a certain property of Pareto points\n", "4. Construct your own problem tailored MOO by using a customized Pareto reflection" ] }, { "cell_type": "markdown", "id": "bba8082e", "metadata": {}, "source": [ "# Define and implement a blackbox function" ] }, { "cell_type": "markdown", "id": "1a15b91a", "metadata": {}, "source": [ "We first need to define how many dimensions our domain (Design Space) and co-domain (Target Space) have. In our example (ZDT-1) we want to map 3 Design Space dimensions to 2 Target Space dimensions.\n", "Second, we must define how it can retrieve function values at selected points, i.e. we must declare calls to our bbf. Those four information, i.e.\n", "- assignment of vector of design variables to vector of target values (here given by ZDT-1) implemented in the ``__call__`` method\n", "- dimension of design space (here 3)\n", "- dimension of target space (here 2)\n", "- design space definition (here $[0,1]^{3}$)\n", "\n", "must be implemented in Parefs\\` ``BlackboxFunction`` interface.\n", "\n", "In addition, a proper scaling of the objectives is necessary in order for optimization to work properly as explained in [trouble-shooting](../description/trouble-shooting.md).\n", "In our case, we do not need to scale the objectives as they are already approximately in the same range. " ] }, { "cell_type": "code", "execution_count": null, "id": "347151ee", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from paref.blackbox_functions.design_space.bounds import Bounds\n", "from paref.interfaces.moo_algorithms.blackbox_function import BlackboxFunction\n", "\n", "\n", "class ZDT1(BlackboxFunction):\n", " def __call__(self, x: np.ndarray) -> np.ndarray:\n", " n = len(x)\n", " f1 = x[0]\n", " g = 1 + 9 / (n - 1) * np.sum(x[1:])\n", " h = 1 - (f1 / g) ** (1 / 2)\n", " f2 = g * h\n", " return np.array([f1, f2])\n", "\n", " @property\n", " def dimension_design_space(self) -> int:\n", " return 3\n", "\n", " @property\n", " def dimension_target_space(self) -> int:\n", " return 2\n", "\n", " @property\n", " def design_space(self) -> Bounds:\n", " return Bounds(upper_bounds=np.ones(self.dimension_design_space),\n", " lower_bounds=np.zeros(self.dimension_design_space))" ] }, { "cell_type": "markdown", "id": "ee9fa97f", "metadata": {}, "source": [ "We then initialize an instance of this bbf." ] }, { "cell_type": "code", "execution_count": null, "id": "3cdb18f4", "metadata": {}, "outputs": [], "source": [ "bbf = ZDT1()" ] }, { "cell_type": "markdown", "id": "ce1ccf68", "metadata": {}, "source": [ "The Pareto front of ZDT-1 looks as follows:" ] }, { "cell_type": "code", "execution_count": null, "id": "07858e8f", "metadata": { "code_folding": [ 5, 13 ] }, "outputs": [], "source": [ "# This code is exclusively to visualize our results\n", "\n", "import plotly.graph_objects as go\n", "\n", "pareto_points_of_bbf = [\n", " i * np.eye(1, bbf.dimension_design_space, 0)[0]\n", " for i in np.arange(0, 1, 0.01)\n", "]\n", "pareto_front_of_bbf = np.array([bbf(point) for point in pareto_points_of_bbf])\n", "bbf.clear_evaluations()\n", "\n", "data = [\n", " go.Scatter(x=pareto_front_of_bbf.T[0],\n", " y=pareto_front_of_bbf.T[1],\n", " name='Real Pareto front',\n", " line=dict(width=4)),\n", "]\n", "fig = go.Figure(data=data)\n", "fig.update_layout(title=\"Pareto front of ZDT-1\",\n", " width=600,\n", " height=600,\n", " plot_bgcolor='rgba(0,0,0,0)',\n", " legend=dict(\n", " x=0.2,\n", " y=0.9,\n", " ))\n", "fig.show()" ] }, { "cell_type": "markdown", "id": "ae25a084", "metadata": {}, "source": [ "Note that in general we are not able to calculate the Pareto front. In this particular case, we can and use this knowledge in order to validate our results." ] }, { "cell_type": "markdown", "source": [ "# The initial exploration of the target space" ], "metadata": { "collapsed": false }, "id": "48d57bfbdb2e6fd4" }, { "cell_type": "markdown", "source": [ "Every MOO algorithm needs to explore the target space first. This is typically done by a Latin Hypercube Sampling (LHC) which is implemented within the ``BlackboxFunction`` interface.\n", "\n", "As a rule of thumb, you should start with 30 LHC evaluations." ], "metadata": { "collapsed": false }, "id": "3c23e9ab9efea659" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "bbf.perform_lhc(30)" ], "metadata": { "collapsed": false }, "id": "29be54f73fd50adc" }, { "cell_type": "markdown", "source": [ "# Analyze the model fitness" ], "metadata": { "collapsed": false }, "id": "a71d474391c0c60a" }, { "cell_type": "markdown", "source": [ "Paref strongly relies on the capability of the underlying model (GPR) to accurately approximate the bbf. \n", "Unfortunately, there exists no metric to measure the quality of the model in general but rather approximations. \n", "However, we can at least ensure that the training process of the model is successful and analyze the intrinsic \n", "uncertainty of the model." ], "metadata": { "collapsed": false }, "id": "c4f09b9f90352feb" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "from paref.express.info import Info\n", "\n", "info = Info(bbf, training_iter=2000) # 2000 is the default number of training iterations" ], "metadata": { "collapsed": false }, "id": "4c1e7f20563e0309" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "info.model_fitness" ], "metadata": { "collapsed": false }, "id": "c656f9b01611aa05" }, { "cell_type": "markdown", "source": [ "We see that the loss of the GPRs converged and looks convex. This is how it should be.\n", "See [trouble-shooting](./trouble_shooting.md) for more details on how to ensure the quality of the model and the resulting optimization." ], "metadata": { "collapsed": false }, "id": "8dd98345cdc75d6" }, { "cell_type": "markdown", "id": "743bc37b", "metadata": {}, "source": [ "\n", "# Apply a MOO algorithm to blackbox function" ] }, { "cell_type": "markdown", "id": "5f61bfd4", "metadata": {}, "source": [ "Applying an MOO algorithm in Paref is simply given by calling the algorithm to \n", "- a blackbox function (implemented in the ``BlackboxFunction`` interface) and\n", "- a stopping criterion indicating when the algorithm should terminate.\n", "\n", "There are essentially two types of MOO algorithms implemented in Paref:\n", "- generic MOO algorithms (mainly [minimizers](https://github.com/nicolaipalm/paref/tree/main/paref/moo_algorithms/minimizer)) which are not tailored to some user defined properties but used when constructing a tailored MOO algorithm from a (sequence of) Pareto reflection(s)\n", "- tailored MOO algorithms which target certain properties of Pareto points" ] }, { "cell_type": "markdown", "id": "480ba680", "metadata": {}, "source": [ "Let's make it concrete for our example:\n", "From our bbf we want to identify Pareto-optimal solutions that represent the co-domain corners of the Pareto front. This property gives us an answer to the question \"in which target area are the Pareto-optimal trade-offs of our bbf?\".\n", "This is a quite typical questions that arise in the context of a bbf MOO. Let's get down to work and see how all these considerations transfer into code...." ] }, { "cell_type": "markdown", "id": "ec3936f0", "metadata": {}, "source": [ "First, with initialize some stopping criteria.\n", "In our case, we choose the ``MaxIterationsReached`` which tells the algorithm to stop after a defined number ``max_iterations`` of iterations is reached. For an initial MOO, it is wise to grant the minimum number of iterations first. After analyzing the results, we can increase the number of iterations if necessary. Here, we grant one evaluation per component (i.e. per corner)." ] }, { "cell_type": "code", "execution_count": null, "id": "8564669d", "metadata": {}, "outputs": [], "source": [ "from paref.moo_algorithms.stopping_criteria.max_iterations_reached import MaxIterationsReached\n", "\n", "stopping_criteria = MaxIterationsReached(max_iterations=2)" ] }, { "cell_type": "markdown", "id": "c0375efe", "metadata": {}, "source": [ "Next, we initialize the MOO algorithm targeting our desired properties of Pareto points: \n", "the ``FindEdgePoints`` algorithm." ] }, { "cell_type": "code", "execution_count": null, "id": "b3d3a1eb", "metadata": {}, "outputs": [], "source": [ "from paref.moo_algorithms.multi_dimensional.find_edge_points import FindEdgePoints\n", "\n", "moo_find_edge_points = FindEdgePoints()" ] }, { "cell_type": "markdown", "id": "8d0506f5", "metadata": {}, "source": [ "At last, we simply apply the algorithm to the blackbox function and the stopping criteria." ] }, { "cell_type": "code", "execution_count": null, "id": "eff3fbd6", "metadata": {}, "outputs": [], "source": [ "moo_find_edge_points(blackbox_function=bbf,\n", " stopping_criteria=stopping_criteria)" ] }, { "cell_type": "markdown", "source": [ "We access the so found best fitting Pareto points by calling the ``best_fits`` attribute of the algorithm." ], "metadata": { "collapsed": false }, "id": "8cb1cee6b360fdd7" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "moo_find_edge_points.best_fits" ], "metadata": { "collapsed": false }, "id": "20232e654d49b6a7" }, { "cell_type": "code", "execution_count": null, "id": "d9ee0845", "metadata": {}, "outputs": [], "source": [ "# This code is exclusively to visualize our results\n", "data = [\n", " go.Scatter(x=pareto_front_of_bbf.T[0],\n", " y=pareto_front_of_bbf.T[1],\n", " name='Real Pareto front',\n", " line=dict(width=4)),\n", " go.Scatter(x=moo_find_edge_points.best_fits.T[0],\n", " y=moo_find_edge_points.best_fits.T[1],\n", " name='Determined Pareto points',\n", " mode=\"markers\",\n", " marker=dict(size=10)),\n", "]\n", "fig = go.Figure(data=data)\n", "fig.update_layout(title=\"Pareto front of ZDT-1\",\n", " width=600,\n", " height=600,\n", " plot_bgcolor='rgba(0,0,0,0)',\n", " legend=dict(\n", " x=0.2,\n", " y=0.9,\n", " ))\n", "fig.show()" ] }, { "cell_type": "markdown", "source": [ "# Analyze the results " ], "metadata": { "collapsed": false }, "id": "b7ac4368e2a0d718" }, { "cell_type": "markdown", "source": [ "After (or also before) any MOO, we should analyze the results in order to guide further steps. For this task, Paref provides the ``Info`` class." ], "metadata": { "collapsed": false }, "id": "e197110e1794fa01" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "%%capture\n", "info.update()" ], "metadata": { "collapsed": false }, "id": "8e4c5affac18fb95" }, { "cell_type": "markdown", "source": [ "A central question is if the objectives are in fact conflicting (i.e. if there exists no global optimum) or, more generally, what the dimensionality of the Pareto front is." ], "metadata": { "collapsed": false }, "id": "996b49ece46545be" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "info.topology" ], "metadata": { "collapsed": false }, "id": "fdb6e474f2684248" }, { "cell_type": "markdown", "source": [ "After convincing ourselves that the objectives are conflicting (so it is worthwhile to perform a MOO) we can check what minimal values in each objective we can expect." ], "metadata": { "collapsed": false }, "id": "f083cbed9a5d5e0" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "info.minima" ], "metadata": { "collapsed": false }, "id": "b71ae1c4aefa67c1" }, { "cell_type": "markdown", "source": [ "Sometimes it is hard to figure out what Pareto points we should target. In that case, we can simply ask Paref to suggest Pareto points." ], "metadata": { "collapsed": false }, "id": "4ca805ff4d0e12cc" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "info.suggestion_pareto_points" ], "metadata": { "collapsed": false }, "id": "d14a9412aade56bb" }, { "cell_type": "markdown", "id": "cafe421c", "metadata": {}, "source": [ "# Identify Pareto points with defined properties by using Pareto reflections" ] }, { "cell_type": "markdown", "id": "38dd89df", "metadata": {}, "source": [ "If an additional property of Pareto points (reflected by some Pareto reflection) is targeted, we may simply call the ``apply_to_sequence`` method of any MOO algorithm to the blackbox function, stopping criteria and the corresponding Pareto reflection in order to include this property.\n", "\n", "Let's make it concrete for our example:\n", "From our bbf ZDT-1 we want to determine the edge Pareto points of the Pareto front but restricted to a certain area. Here, we choose the area as $(-\\infty,0.5]\\times (-\\infty,10]$, i.e. we demand the maximal $y_1$ resp. $y_2$ value of Pareto points to be $0.5$ resp. $10$.\n" ] }, { "cell_type": "markdown", "id": "47177a2c", "metadata": {}, "source": [ "This is a quite typical constrained that arises in the context of a bbf MOO. \n", "\n", "Paref provides an implementation of a Pareto reflection corresponding to that property: the ``RestrictByPoint`` Pareto reflection. " ] }, { "cell_type": "code", "execution_count": null, "id": "0399799e", "metadata": {}, "outputs": [], "source": [ "from paref.pareto_reflections.restrict_by_point import RestrictByPoint\n", "\n", "restricting_point = np.array([0.5, 10])\n", "restrict_by_point = RestrictByPoint(restricting_point=restricting_point,\n", " nadir=10 * np.ones(2))" ] }, { "cell_type": "markdown", "id": "2cda4eb3", "metadata": {}, "source": [ "Now, we simply apply the ``FindEdgePoint`` algorithm to that Pareto reflection:" ] }, { "cell_type": "code", "execution_count": null, "id": "fff48819", "metadata": {}, "outputs": [], "source": [ "moo_find_edge_points_2 = FindEdgePoints()\n", "moo_find_edge_points_2.apply_to_sequence(\n", " blackbox_function=bbf,\n", " sequence_pareto_reflections=restrict_by_point,\n", " stopping_criteria=MaxIterationsReached(2))" ] }, { "cell_type": "code", "execution_count": null, "id": "8ed618bb", "metadata": {}, "outputs": [], "source": [ "# This code is exclusively to visualize our results\n", "area = np.array([[restricting_point[0], 0], restricting_point])\n", "data = [\n", " go.Scatter(x=pareto_front_of_bbf.T[0],\n", " y=pareto_front_of_bbf.T[1],\n", " name='Real Pareto front',\n", " line=dict(width=4)),\n", " go.Scatter(x=bbf.y[-2:].T[0],\n", " y=bbf.y[-2:].T[1],\n", " name='Determined Pareto points',\n", " mode=\"markers\",\n", " marker=dict(size=10)),\n", " go.Scatter(x=area.T[0],\n", " y=area.T[1],\n", " fill='tozerox',\n", " mode='none',\n", " fillcolor='rgba(255, 0, 0, 0.4)',\n", " name='Allowed area'),\n", "]\n", "fig = go.Figure(data=data)\n", "fig.update_layout(title=\"Pareto front of ZDT-1\",\n", " width=600,\n", " height=600,\n", " plot_bgcolor='rgba(0,0,0,0)',\n", " legend=dict(\n", " x=0.5,\n", " y=0.9,\n", " ))\n", "fig.show()" ] }, { "cell_type": "markdown", "id": "94d75bb8", "metadata": {}, "source": [ "# Customize Pareto reflections to user defined properties" ] }, { "cell_type": "markdown", "source": [ "Imagine we prioritize Pareto points where the values of both objectives are close to each other. \n", "In other words, we want Pareto points $y$ which minimize $|y_1 - y_2|$. Clearly not every point which minimizes $|y_1 - y_2|$ is Pareto optimal. \n", "However, for the purpose of finding Pareto points which minimize some function $g$, there exists a universal Pareto reflection: \n", "the ``MinGParetoReflection``. We simply need to specify $g$ and the Pareto reflection does the rest." ], "metadata": { "collapsed": false }, "id": "992a1a0aa024f0fa" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "from typing import Callable\n", "from paref.pareto_reflections.minimize_g import MinGParetoReflection\n", "\n", "\n", "class MinimizeDifferenceOfObjectives(MinGParetoReflection):\n", " @property\n", " def g(self) -> Callable:\n", " return lambda y: np.abs(y[0] - y[1])\n", "\n", " @property\n", " def dimension_domain(self) -> int:\n", " return 2\n", "\n", "\n", "minimize_difference_of_objectives = MinimizeDifferenceOfObjectives(bbf)" ], "metadata": { "collapsed": false }, "id": "4e1795b7438e7ea8" }, { "cell_type": "markdown", "id": "85fbf6dc", "metadata": {}, "source": [ "In order to apply some MOO to that reflection (i.e. to target the ''minimize distance of objectives'' property), we choose some *generic* MOO algorithm (i.e. some MOO which is not tailored to some properties) which can handle the ``MinimizeDifferenceOfObjectives`` reflection.\n", "The codomain dimension of the Pareto reflection (``dimension_codomain`` property) must be a supported target space dimensions of the MOO (``supported_target_space_dimensions``) which is 1 in our case." ] }, { "cell_type": "code", "execution_count": null, "id": "45ed9a45", "metadata": {}, "outputs": [], "source": [ "minimize_difference_of_objectives.dimension_codomain" ] }, { "cell_type": "markdown", "id": "4ed3bdab", "metadata": {}, "source": [ "In this example, we choose the ``DifferentialEvolutionMinimizer``. This MOO exploits the fact that the underlying bbf is very cheap to sample (for a generic MOO algorithm which is tailored to expensive bbf see for example the ``GPRMinimizer``) and yields typically better results but needs *much* (i.e. thousands of) more evaluations of the blackbox function." ] }, { "cell_type": "code", "execution_count": null, "id": "9f1c1647", "metadata": {}, "outputs": [], "source": [ "from paref.moo_algorithms.minimizer.differential_evolution_minimizer import DifferentialEvolutionMinimizer\n", "\n", "generic_moo = DifferentialEvolutionMinimizer()" ] }, { "cell_type": "markdown", "id": "9fcbc636", "metadata": {}, "source": [ "Notice that the codomain dimension of the Pareto reflection is supported by the MOO:" ] }, { "cell_type": "code", "execution_count": null, "id": "576ff1af", "metadata": {}, "outputs": [], "source": [ "print(\n", " f\"Codomain dimension is supported: {minimize_difference_of_objectives.dimension_codomain in generic_moo.supported_codomain_dimensions}\"\n", ")" ] }, { "cell_type": "markdown", "id": "154287b1", "metadata": {}, "source": [ "Again, we simply apply the MOO to the Pareto reflection by calling its ``apply_to_sequence`` method:" ] }, { "cell_type": "code", "execution_count": null, "id": "21867331", "metadata": {}, "outputs": [], "source": [ "bbf.clear_evaluations()\n", "generic_moo.apply_to_sequence(blackbox_function=bbf,\n", " stopping_criteria=MaxIterationsReached(2),\n", " sequence_pareto_reflections=minimize_difference_of_objectives)" ] }, { "cell_type": "markdown", "source": [ "Note how the algorithm perfectly found the (only) Pareto point which minimizes the difference of the objectives, i.e. has equal values for both objectives:" ], "metadata": { "collapsed": false }, "id": "468e011703d55778" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "generic_moo.best_fits" ], "metadata": { "collapsed": false }, "id": "84682b098536b8" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# This code is exclusively to visualize our results\n", "data = [\n", " go.Scatter(x=pareto_front_of_bbf.T[0],\n", " y=pareto_front_of_bbf.T[1],\n", " name='Real Pareto front',\n", " line=dict(width=4)),\n", " go.Scatter(x=bbf.pareto_front.T[0],\n", " y=bbf.pareto_front.T[1],\n", " name='Pareto point minimizing the distance of objectives',\n", " mode=\"markers\",\n", " marker=dict(size=10)),\n", "]\n", "fig = go.Figure(data=data)\n", "fig.update_layout(title=\"Pareto front of ZDT-1\",\n", " width=600,\n", " height=600,\n", " plot_bgcolor='rgba(0,0,0,0)',\n", " legend=dict(\n", " x=0.2,\n", " y=0.9,\n", " ))\n", "fig.show()" ], "metadata": { "collapsed": false }, "id": "ef58f25f" } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "calc(100% - 180px)", "left": "10px", "top": "150px", "width": "250.390625px" }, "toc_section_display": true, "toc_window_display": true }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 5 }