From feb0f0418d1ad0125d1252df4d40697862715132 Mon Sep 17 00:00:00 2001 From: David Eriksson Date: Wed, 15 Mar 2023 11:13:23 -0600 Subject: [PATCH 1/2] Drop the number of candidates --- scripts/run_tutorials.py | 2 - tutorials/scalable_constrained_bo.ipynb | 377 ++++++++++-------------- 2 files changed, 163 insertions(+), 216 deletions(-) diff --git a/scripts/run_tutorials.py b/scripts/run_tutorials.py index c9849133b6..70ca41109b 100644 --- a/scripts/run_tutorials.py +++ b/scripts/run_tutorials.py @@ -27,8 +27,6 @@ RUN_IF_SMOKE_TEST_IGNORE_IF_STANDARD = { # only used in smoke tests "thompson_sampling.ipynb", # very slow without KeOps + GPU "composite_mtbo.ipynb", # TODO: very slow, figure out if we can make it faster - # Timing out in standard mode - "scalable_constrained_bo.ipynb", } diff --git a/tutorials/scalable_constrained_bo.ipynb b/tutorials/scalable_constrained_bo.ipynb index 637dc355b7..209d496929 100644 --- a/tutorials/scalable_constrained_bo.ipynb +++ b/tutorials/scalable_constrained_bo.ipynb @@ -7,7 +7,7 @@ "# Scalable Constrained Bayesian Optimization (SCBO)\n", "In this tutorial, we show how to implement Scalable Constrained Bayesian Optimization (SCBO) [1] in a closed loop in BoTorch.\n", "\n", - "We optimize the 20𝐷 Ackley function on the domain [−5,10]^20. This implementation uses two simple constraint functions c1 and c2. Our goal is to find values x which maximize Ackley(x) subject to the constraints c1(x) <= 0 and c2(x) <= 0.\n", + "We optimize the 20𝐷 Ackley function on the domain $[−5,10]^{20}$. This implementation uses two simple constraint functions $c1$ and $c2$. Our goal is to find values $x$ which maximizes $Ackley(x)$ subject to the constraints $c1(x) \\leq 0$ and $c2(x) \\leq 0$.\n", "\n", "[1]: David Eriksson and Matthias Poloczek. Scalable constrained Bayesian optimization. In International Conference on Artificial Intelligence and Statistics, pages 730–738. PMLR, 2021.\n", "(https://doi.org/10.48550/arxiv.2002.08526)\n", @@ -17,40 +17,37 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import math\n", + "import os\n", + "import warnings\n", "from dataclasses import dataclass\n", "\n", - "import torch\n", - "from torch import Tensor\n", - "from botorch.fit import fit_gpytorch_mll\n", - "from botorch.models import SingleTaskGP\n", - "from botorch.test_functions import Ackley\n", - "from botorch.utils.transforms import unnormalize\n", - "from torch.quasirandom import SobolEngine\n", - "\n", "import gpytorch\n", + "import torch\n", "from gpytorch.constraints import Interval\n", "from gpytorch.kernels import MaternKernel, ScaleKernel\n", "from gpytorch.likelihoods import GaussianLikelihood\n", "from gpytorch.mlls import ExactMarginalLogLikelihood\n", - "from botorch.models.model_list_gp_regression import ModelListGP\n", + "from torch import Tensor\n", + "from torch.quasirandom import SobolEngine\n", "\n", - "# Constrained Max Posterior Sampling\n", - "# is a new sampling class, similar to MaxPosteriorSampling,\n", - "# which implements the constrained version of Thompson Sampling described in [1]\n", + "from botorch.fit import fit_gpytorch_mll\n", + "# Constrained Max Posterior Sampling s a new sampling class, similar to MaxPosteriorSampling,\n", + "# which implements the constrained version of Thompson Sampling described in [1].\n", "from botorch.generation.sampling import ConstrainedMaxPosteriorSampling\n", - "\n", - "import warnings\n", + "from botorch.models import SingleTaskGP\n", + "from botorch.models.model_list_gp_regression import ModelListGP\n", + "from botorch.test_functions import Ackley\n", + "from botorch.utils.transforms import unnormalize\n", "\n", "warnings.filterwarnings(\"ignore\")\n", "\n", "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", "dtype = torch.double\n", - "import os\n", "\n", "SMOKE_TEST = os.environ.get(\"SMOKE_TEST\")" ] @@ -64,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -102,7 +99,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -136,20 +133,20 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "TurboState(dim=20, batch_size=4, length=0.8, length_min=0.0078125, length_max=1.6, failure_counter=0, failure_tolerance=5, success_counter=0, success_tolerance=10, best_value=-inf, best_constraint_values=tensor([inf, inf]), restart_triggered=False)\n" + "ScboState(dim=20, batch_size=4, length=0.8, length_min=0.0078125, length_max=1.6, failure_counter=0, failure_tolerance=5, success_counter=0, success_tolerance=10, best_value=-inf, best_constraint_values=tensor([inf, inf]), restart_triggered=False)\n" ] } ], "source": [ "@dataclass\n", - "class TurboState:\n", + "class ScboState:\n", " dim: int\n", " batch_size: int\n", " length: float = 0.8\n", @@ -160,12 +157,7 @@ " success_counter: int = 0\n", " success_tolerance: int = 10 # Note: The original paper uses 3\n", " best_value: float = -float(\"inf\")\n", - " best_constraint_values: Tensor = (\n", - " torch.ones(\n", - " 2,\n", - " )\n", - " * torch.inf\n", - " )\n", + " best_constraint_values: Tensor = torch.ones(2,) * torch.inf\n", " restart_triggered: bool = False\n", "\n", " def __post_init__(self):\n", @@ -192,22 +184,20 @@ "\n", "\n", "def update_state(state, Y_next, C_next):\n", - " \"\"\"Method used to update the TuRBO state after each\n", - " step of optimization.\n", - "\n", - " Success and failure counters are updated accoding to\n", - " the objective values (Y_next) and constraint values (C_next)\n", - " of the batch of candidate points evaluated on the optimization step.\n", - "\n", - " As in the original TuRBO paper, a success is counted whenver\n", - " any one of the new candidate points imporves upon the incumbent\n", - " best point. The key difference for SCBO is that we only compare points\n", - " by their objective values when both points are valid (meet all constraints).\n", - " If exactly one of the two points beinc compared voliates a constraint, the\n", - " other valid point is automatically considered to be better. If both points\n", - " violate some constraints, we compare them inated by their constraint values.\n", + " \"\"\"Method used to update the TuRBO state after each step of optimization.\n", + "\n", + " Success and failure counters are updated according to the objective values \n", + " (Y_next) and constraint values (C_next) of the batch of candidate points \n", + " evaluated on the optimization step.\n", + "\n", + " As in the original TuRBO paper, a success is counted whenver any one of the \n", + " new candidate points improves upon the incumbent best point. The key difference \n", + " for SCBO is that we only compare points by their objective values when both points\n", + " are valid (meet all constraints). If exactly one of the two points being compared \n", + " violates a constraint, the other valid point is automatically considered to be better. \n", + " If both points violate some constraints, we compare them inated by their constraint values.\n", " The better point in this case is the one with minimum total constraint violation\n", - " (the minimum sum over constraint values)\"\"\"\n", + " (the minimum sum of constraint values)\"\"\"\n", "\n", " # Determine which candidates meet the constraints (are valid)\n", " bool_tensor = C_next <= 0\n", @@ -234,34 +224,33 @@ " # throw out all invalid candidates\n", " # (a valid candidate is always better than an invalid one)\n", "\n", - " # Case 1: if best valid candidate found has a higher obj value that incumbent best\n", - " # count a success, the obj valuse has been improved\n", - " imporved_obj = max(Valid_Y_next) > state.best_value + 1e-3 * math.fabs(\n", + " # Case 1: if the best valid candidate found has a higher objective value that \n", + " # incumbent best count a success, the obj valuse has been improved\n", + " improved_obj = max(Valid_Y_next) > state.best_value + 1e-3 * math.fabs(\n", " state.best_value\n", " )\n", " # Case 2: if incumbent best violates constraints\n", - " # count a success, we now have suggested a point which is valid and therfore better\n", + " # count a success, we now have suggested a point which is valid and thus better\n", " obtained_validity = torch.all(state.best_constraint_values > 0)\n", - " if imporved_obj or obtained_validity: # If Case 1 or Case 2\n", + " if improved_obj or obtained_validity: # If Case 1 or Case 2\n", " # count a success and update the best value and constraint values\n", " state.success_counter += 1\n", " state.failure_counter = 0\n", " state.best_value = max(Valid_Y_next).item()\n", " state.best_constraint_values = Valid_C_next[Valid_Y_next.argmax()]\n", " else:\n", - " # otherwise, count a fialure\n", + " # otherwise, count a failure\n", " state.success_counter = 0\n", " state.failure_counter += 1\n", "\n", " # Finally, update the length of the trust region according to the\n", - " # updated success and failure counts\n", + " # updated success and failure counters\n", " state = update_tr_length(state)\n", - "\n", " return state\n", "\n", "\n", "# Define example state\n", - "state = TurboState(dim=dim, batch_size=batch_size)\n", + "state = ScboState(dim=dim, batch_size=batch_size)\n", "print(state)" ] }, @@ -276,7 +265,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -292,14 +281,16 @@ "source": [ "### Generating a batch of candidates for SCBO \n", "\n", - "Just as in the TuRBO Tutorial (https://botorch.org/tutorials/turbo_1), we'll define a method generate_batch to generate a new batch of candidate points within the TuRBO trust region using thompson sampling. \n", + "Just as in the TuRBO Tutorial (https://botorch.org/tutorials/turbo_1), we'll define a method generate_batch to generate a new batch of candidate points within the TuRBO trust region using Thompson sampling. \n", + "\n", + "The key difference here from TuRBO is that, instead of using MaxPosteriorSampling to simply grab the candidates within the trust region with the maximum posterior values, we use ConstrainedMaxPosteriorSampling to instead grab the candidates within the trust region with the maximum posterior values subject to the constraint that the posteriors for the constraint models for c1(x) and c2(x) must be less than or equal to 0 for both candidates. \n", "\n", - "The key difference here from TuRBO is that, instead of using MaxPosteriorSampling to simply grab the candidates within the trust region with the maximum posterior values, we use ConstrainedMaxPosteriorSampling to instead grab the candidates within the trust region with the maximum posterior values subject to the constrain that the posteriors for the constraint models for c1(x) and c2(x) must be less than or equal to 0 for each candidate. In otherwords, we use additional GPs ('constraiant models') to model each black-box constraint (c1 and c2), and throw out all candidates for which the posterior prediction of these constraint models is greater than 0 (throw out all predicted constraint violators). According to [1], in the special case when all of the candidaates arae predicted to be constraint violators, we select the candidate with the minimum predicted violation. (See botorch.generation.sampling.ConstrainedMaxPosteriorSampling for implementation details)." + "We use additional GPs ('constraint models') to model each black-box constraint (c1 and c2), and throw out all candidates for which the sampled value for these constraint models is greater than 0. According to [1], in the special case when all of the candidaates are predicted to be constraint violators, we select the candidate with the minimum predicted violation. (See botorch.generation.sampling.ConstrainedMaxPosteriorSampling for implementation details)." ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -309,20 +300,15 @@ " X, # Evaluated points on the domain [0, 1]^d\n", " Y, # Function values\n", " batch_size,\n", - " n_candidates=None, # Number of candidates for Thompson sampling\n", - " constraint_model=None,\n", + " n_candidates, # Number of candidates for Thompson sampling\n", + " constraint_model,\n", "):\n", " assert X.min() >= 0.0 and X.max() <= 1.0 and torch.all(torch.isfinite(Y))\n", - " if n_candidates is None:\n", - " n_candidates = min(5000, max(2000, 200 * X.shape[-1]))\n", "\n", - " # Scale the TR to be proportional to the lengthscales\n", + " # Create the TR bounds\n", " x_center = X[Y.argmax(), :].clone()\n", - " weights = model.covar_module.base_kernel.lengthscale.squeeze().detach()\n", - " weights = weights / weights.mean()\n", - " weights = weights / torch.prod(weights.pow(1.0 / len(weights)))\n", - " tr_lb = torch.clamp(x_center - weights * state.length / 2.0, 0.0, 1.0)\n", - " tr_ub = torch.clamp(x_center + weights * state.length / 2.0, 0.0, 1.0)\n", + " tr_lb = torch.clamp(x_center - state.length / 2.0, 0.0, 1.0)\n", + " tr_ub = torch.clamp(x_center + state.length / 2.0, 0.0, 1.0)\n", "\n", " # Thompson Sampling w/ Constraints (SCBO)\n", " dim = X.shape[-1]\n", @@ -359,21 +345,21 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(tensor(-9.6854, device='cuda:0', dtype=torch.float64),\n", - " tensor(4.8509, device='cuda:0', dtype=torch.float64),\n", - " tensor(-9.8032, device='cuda:0', dtype=torch.float64),\n", - " tensor(4.7317, device='cuda:0', dtype=torch.float64),\n", - " tensor(-15.9292, device='cuda:0', dtype=torch.float64),\n", - " tensor(-12.4023, device='cuda:0', dtype=torch.float64))" + "(tensor(-9.6854, dtype=torch.float64),\n", + " tensor(4.8509, dtype=torch.float64),\n", + " tensor(-9.8032, dtype=torch.float64),\n", + " tensor(4.7317, dtype=torch.float64),\n", + " tensor(-15.9292, dtype=torch.float64),\n", + " tensor(-12.4023, dtype=torch.float64))" ] }, - "execution_count": 10, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -397,107 +383,96 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "44) Best value: -1.34e+01, TR length: 8.00e-01\n", - "48) Best value: -1.27e+01, TR length: 8.00e-01\n", - "52) Best value: -9.77e+00, TR length: 8.00e-01\n", - "56) Best value: -9.77e+00, TR length: 8.00e-01\n", - "60) Best value: -9.77e+00, TR length: 8.00e-01\n", - "64) Best value: -9.77e+00, TR length: 8.00e-01\n", - "68) Best value: -9.77e+00, TR length: 8.00e-01\n", - "72) Best value: -9.08e+00, TR length: 8.00e-01\n", - "76) Best value: -9.06e+00, TR length: 8.00e-01\n", - "80) Best value: -8.26e+00, TR length: 8.00e-01\n", - "84) Best value: -8.26e+00, TR length: 8.00e-01\n", - "88) Best value: -7.34e+00, TR length: 8.00e-01\n", - "92) Best value: -7.34e+00, TR length: 8.00e-01\n", - "96) Best value: -7.34e+00, TR length: 8.00e-01\n", - "100) Best value: -7.34e+00, TR length: 8.00e-01\n", - "104) Best value: -7.34e+00, TR length: 8.00e-01\n", - "108) Best value: -7.34e+00, TR length: 4.00e-01\n", - "112) Best value: -6.99e+00, TR length: 4.00e-01\n", - "116) Best value: -6.85e+00, TR length: 4.00e-01\n", - "120) Best value: -6.00e+00, TR length: 4.00e-01\n", - "124) Best value: -6.00e+00, TR length: 4.00e-01\n", - "128) Best value: -6.00e+00, TR length: 4.00e-01\n", - "132) Best value: -6.00e+00, TR length: 4.00e-01\n", - "136) Best value: -6.00e+00, TR length: 4.00e-01\n", - "140) Best value: -5.67e+00, TR length: 4.00e-01\n", - "144) Best value: -5.67e+00, TR length: 4.00e-01\n", - "148) Best value: -5.67e+00, TR length: 4.00e-01\n", - "152) Best value: -5.67e+00, TR length: 4.00e-01\n", - "156) Best value: -5.67e+00, TR length: 4.00e-01\n", - "160) Best value: -5.67e+00, TR length: 2.00e-01\n", - "164) Best value: -4.99e+00, TR length: 2.00e-01\n", - "168) Best value: -3.85e+00, TR length: 2.00e-01\n", - "172) Best value: -3.85e+00, TR length: 2.00e-01\n", - "176) Best value: -3.85e+00, TR length: 2.00e-01\n", - "180) Best value: -3.85e+00, TR length: 2.00e-01\n", - "184) Best value: -3.85e+00, TR length: 2.00e-01\n", - "188) Best value: -3.85e+00, TR length: 1.00e-01\n", - "192) Best value: -3.85e+00, TR length: 1.00e-01\n", - "196) Best value: -3.70e+00, TR length: 1.00e-01\n", - "200) Best value: -3.70e+00, TR length: 1.00e-01\n", - "204) Best value: -3.62e+00, TR length: 1.00e-01\n", - "208) Best value: -3.31e+00, TR length: 1.00e-01\n", - "212) Best value: -3.17e+00, TR length: 1.00e-01\n", - "216) Best value: -3.17e+00, TR length: 1.00e-01\n", - "220) Best value: -3.14e+00, TR length: 1.00e-01\n", - "224) Best value: -3.14e+00, TR length: 1.00e-01\n", - "228) Best value: -3.10e+00, TR length: 1.00e-01\n", - "232) Best value: -2.34e+00, TR length: 1.00e-01\n", - "236) Best value: -2.34e+00, TR length: 1.00e-01\n", - "240) Best value: -2.34e+00, TR length: 1.00e-01\n", - "244) Best value: -2.34e+00, TR length: 1.00e-01\n", - "248) Best value: -2.34e+00, TR length: 1.00e-01\n", - "252) Best value: -2.34e+00, TR length: 5.00e-02\n", - "256) Best value: -1.93e+00, TR length: 5.00e-02\n", - "260) Best value: -1.93e+00, TR length: 5.00e-02\n", - "264) Best value: -1.93e+00, TR length: 5.00e-02\n", - "268) Best value: -1.72e+00, TR length: 5.00e-02\n", - "272) Best value: -1.72e+00, TR length: 5.00e-02\n", - "276) Best value: -1.72e+00, TR length: 5.00e-02\n", - "280) Best value: -1.72e+00, TR length: 5.00e-02\n", - "284) Best value: -1.72e+00, TR length: 5.00e-02\n", - "288) Best value: -1.72e+00, TR length: 2.50e-02\n", - "292) Best value: -1.54e+00, TR length: 2.50e-02\n", - "296) Best value: -1.54e+00, TR length: 2.50e-02\n", - "300) Best value: -1.54e+00, TR length: 2.50e-02\n", - "304) Best value: -1.54e+00, TR length: 2.50e-02\n", - "308) Best value: -1.54e+00, TR length: 2.50e-02\n", - "312) Best value: -1.38e+00, TR length: 2.50e-02\n", - "316) Best value: -1.22e+00, TR length: 2.50e-02\n", - "320) Best value: -1.22e+00, TR length: 2.50e-02\n", - "324) Best value: -1.22e+00, TR length: 2.50e-02\n", - "328) Best value: -1.22e+00, TR length: 2.50e-02\n", - "332) Best value: -1.22e+00, TR length: 2.50e-02\n", - "336) Best value: -1.09e+00, TR length: 2.50e-02\n", - "340) Best value: -1.09e+00, TR length: 2.50e-02\n", - "344) Best value: -1.09e+00, TR length: 2.50e-02\n", - "348) Best value: -1.09e+00, TR length: 2.50e-02\n", - "352) Best value: -1.09e+00, TR length: 2.50e-02\n", - "356) Best value: -1.09e+00, TR length: 1.25e-02\n", - "360) Best value: -1.09e+00, TR length: 1.25e-02\n", - "364) Best value: -1.09e+00, TR length: 1.25e-02\n", - "368) Best value: -8.61e-01, TR length: 1.25e-02\n", - "372) Best value: -8.54e-01, TR length: 1.25e-02\n", - "376) Best value: -8.54e-01, TR length: 1.25e-02\n", - "380) Best value: -7.06e-01, TR length: 1.25e-02\n", - "384) Best value: -4.93e-01, TR length: 1.25e-02\n", - "388) Best value: -4.93e-01, TR length: 1.25e-02\n", - "392) Best value: -4.34e-01, TR length: 1.25e-02\n", - "396) Best value: -4.21e-01, TR length: 1.25e-02\n", - "400) Best value: -4.21e-01, TR length: 1.25e-02\n", - "404) Best value: -4.21e-01, TR length: 1.25e-02\n", - "408) Best value: -4.21e-01, TR length: 1.25e-02\n", - "412) Best value: -4.21e-01, TR length: 1.25e-02\n", - "416) Best value: -4.21e-01, TR length: 6.25e-03\n" + "44) Best value: -1.27e+01, TR length: 8.00e-01\n", + "48) Best value: -1.19e+01, TR length: 8.00e-01\n", + "52) Best value: -1.02e+01, TR length: 8.00e-01\n", + "56) Best value: -1.02e+01, TR length: 8.00e-01\n", + "60) Best value: -1.02e+01, TR length: 8.00e-01\n", + "64) Best value: -1.02e+01, TR length: 8.00e-01\n", + "68) Best value: -9.97e+00, TR length: 8.00e-01\n", + "72) Best value: -8.17e+00, TR length: 8.00e-01\n", + "76) Best value: -8.17e+00, TR length: 8.00e-01\n", + "80) Best value: -8.16e+00, TR length: 8.00e-01\n", + "84) Best value: -8.16e+00, TR length: 8.00e-01\n", + "88) Best value: -8.16e+00, TR length: 8.00e-01\n", + "92) Best value: -8.16e+00, TR length: 8.00e-01\n", + "96) Best value: -8.16e+00, TR length: 8.00e-01\n", + "100) Best value: -8.16e+00, TR length: 4.00e-01\n", + "104) Best value: -7.50e+00, TR length: 4.00e-01\n", + "108) Best value: -6.87e+00, TR length: 4.00e-01\n", + "112) Best value: -6.87e+00, TR length: 4.00e-01\n", + "116) Best value: -5.65e+00, TR length: 4.00e-01\n", + "120) Best value: -5.65e+00, TR length: 4.00e-01\n", + "124) Best value: -5.65e+00, TR length: 4.00e-01\n", + "128) Best value: -5.65e+00, TR length: 4.00e-01\n", + "132) Best value: -5.65e+00, TR length: 4.00e-01\n", + "136) Best value: -5.65e+00, TR length: 2.00e-01\n", + "140) Best value: -4.71e+00, TR length: 2.00e-01\n", + "144) Best value: -4.71e+00, TR length: 2.00e-01\n", + "148) Best value: -4.71e+00, TR length: 2.00e-01\n", + "152) Best value: -4.36e+00, TR length: 2.00e-01\n", + "156) Best value: -4.20e+00, TR length: 2.00e-01\n", + "160) Best value: -4.20e+00, TR length: 2.00e-01\n", + "164) Best value: -4.20e+00, TR length: 2.00e-01\n", + "168) Best value: -4.20e+00, TR length: 2.00e-01\n", + "172) Best value: -4.20e+00, TR length: 2.00e-01\n", + "176) Best value: -4.00e+00, TR length: 2.00e-01\n", + "180) Best value: -3.98e+00, TR length: 2.00e-01\n", + "184) Best value: -3.98e+00, TR length: 2.00e-01\n", + "188) Best value: -3.89e+00, TR length: 2.00e-01\n", + "192) Best value: -3.89e+00, TR length: 2.00e-01\n", + "196) Best value: -3.89e+00, TR length: 2.00e-01\n", + "200) Best value: -3.89e+00, TR length: 2.00e-01\n", + "204) Best value: -3.77e+00, TR length: 2.00e-01\n", + "208) Best value: -3.77e+00, TR length: 2.00e-01\n", + "212) Best value: -3.77e+00, TR length: 2.00e-01\n", + "216) Best value: -3.61e+00, TR length: 2.00e-01\n", + "220) Best value: -3.61e+00, TR length: 2.00e-01\n", + "224) Best value: -3.61e+00, TR length: 2.00e-01\n", + "228) Best value: -3.61e+00, TR length: 2.00e-01\n", + "232) Best value: -3.61e+00, TR length: 2.00e-01\n", + "236) Best value: -3.61e+00, TR length: 1.00e-01\n", + "240) Best value: -3.22e+00, TR length: 1.00e-01\n", + "244) Best value: -3.06e+00, TR length: 1.00e-01\n", + "248) Best value: -2.85e+00, TR length: 1.00e-01\n", + "252) Best value: -2.85e+00, TR length: 1.00e-01\n", + "256) Best value: -2.70e+00, TR length: 1.00e-01\n", + "260) Best value: -2.70e+00, TR length: 1.00e-01\n", + "264) Best value: -2.69e+00, TR length: 1.00e-01\n", + "268) Best value: -2.69e+00, TR length: 1.00e-01\n", + "272) Best value: -2.69e+00, TR length: 1.00e-01\n", + "276) Best value: -2.69e+00, TR length: 1.00e-01\n", + "280) Best value: -2.69e+00, TR length: 1.00e-01\n", + "284) Best value: -2.69e+00, TR length: 5.00e-02\n", + "288) Best value: -2.66e+00, TR length: 5.00e-02\n", + "292) Best value: -2.16e+00, TR length: 5.00e-02\n", + "296) Best value: -1.60e+00, TR length: 5.00e-02\n", + "300) Best value: -1.60e+00, TR length: 5.00e-02\n", + "304) Best value: -1.60e+00, TR length: 5.00e-02\n", + "308) Best value: -1.60e+00, TR length: 5.00e-02\n", + "312) Best value: -1.60e+00, TR length: 5.00e-02\n", + "316) Best value: -1.60e+00, TR length: 2.50e-02\n", + "320) Best value: -1.56e+00, TR length: 2.50e-02\n", + "324) Best value: -1.37e+00, TR length: 2.50e-02\n", + "328) Best value: -1.37e+00, TR length: 2.50e-02\n", + "332) Best value: -1.37e+00, TR length: 2.50e-02\n", + "336) Best value: -1.28e+00, TR length: 2.50e-02\n", + "340) Best value: -1.26e+00, TR length: 2.50e-02\n", + "344) Best value: -1.26e+00, TR length: 2.50e-02\n", + "348) Best value: -1.26e+00, TR length: 2.50e-02\n", + "352) Best value: -1.26e+00, TR length: 2.50e-02\n", + "356) Best value: -1.26e+00, TR length: 2.50e-02\n", + "360) Best value: -1.26e+00, TR length: 1.25e-02\n", + "364) Best value: -1.21e+00, TR length: 1.25e-02\n", + "368) Best value: -9.79e-01, TR length: 1.25e-02\n", + "372) Best value: -9.79e-01, TR length: 1.25e-02\n" ] } ], @@ -505,8 +480,10 @@ "# Initialize TuRBO state\n", "from botorch.models.transforms.outcome import Standardize\n", "\n", - "state = TurboState(dim, batch_size=batch_size)\n", - "N_CANDIDATES = min(5000, max(2000, 200 * dim)) if not SMOKE_TEST else 4\n", + "state = ScboState(dim, batch_size=batch_size)\n", + "# Note: We use 2000 candidates here to make the tutorial run faster. \n", + "# SCBO actually uses min(5000, max(2000, 200 * dim)) candidate points by default.\n", + "N_CANDIDATES = 2000 if not SMOKE_TEST else 4\n", "\n", "\n", "def get_fitted_model(X, Y):\n", @@ -567,22 +544,18 @@ " # Update TuRBO state\n", " state = update_state(state, Y_next, C_next)\n", "\n", - " # Append data\n", - " # Notice we append all data, even points that violate\n", - " # the constriants, this is so our constraint models\n", - " # can learn more about the constranit functions and\n", - " # gain confidence about where violation occurs\n", + " # Append data. Note that we append all data, even points that violate\n", + " # the constraints. This is so our constraint models can learn more \n", + " # about the constraint functions and gain confidence in where violations occur.\n", " train_X = torch.cat((train_X, X_next), dim=0)\n", " train_Y = torch.cat((train_Y, Y_next), dim=0)\n", " C1 = torch.cat((C1, C1_next), dim=0)\n", " C2 = torch.cat((C2, C2_next), dim=0)\n", "\n", - " # Print current status\n", - " # Note: state.best_value is always the best objective value\n", - " # found so far which meets the constraints, or in the case\n", - " # that no points have been found yet which meet the constraints,\n", - " # it is the objective value of the point with the\n", - " # minimum constraint violation\n", + " # Print current status. Note that state.best_value is always the best \n", + " # objective value found so far which meets the constraints, or in the case\n", + " # that no points have been found yet which meet the constraints, it is the \n", + " # objective value of the point with the minimum constraint violation.\n", " print(\n", " f\"{len(train_X)}) Best value: {state.best_value:.2e}, TR length: {state.length:.2e}\"\n", " )" @@ -590,19 +563,11 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "With constraints, the best value we found is: -0.4209\n" - ] - } - ], + "outputs": [], "source": [ - "# Valid samples must have BOTH c1 <= 0 and c2 <= 0\n", + "# Valid samples must have BOTH c1 <= 0 and c2 <= 0\n", "constraint_vals = torch.cat([C1, C2], dim=-1)\n", "bool_tensor = constraint_vals <= 0\n", "bool_tensor = torch.all(bool_tensor, dim=-1).unsqueeze(-1)\n", @@ -617,30 +582,15 @@ "source": [ "### Plot Results\n", "\n", - "Notice that with these two simple constraints, SCBO preforms about the same as to TuRBO (see TuRBO 1 tutorial notebok)" + "With these two simple constraints, SCBO performs similarly to TuRBO (see TuRBO-1 tutorial notebok)" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ - "# Plot Optimization Results\n", - "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from matplotlib import rc\n", @@ -673,7 +623,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.8.8 ('base')", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -687,9 +637,8 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.9.13" }, - "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "9beb4c3e6521665a47c2b1e65f245d1b2309f4194f15ed6955f5e52622a9d29e" From 48d72834784ed7f7e07e19e04f1efde8d1ece571 Mon Sep 17 00:00:00 2001 From: David Eriksson Date: Wed, 15 Mar 2023 11:13:55 -0600 Subject: [PATCH 2/2] Update scalable_constrained_bo.ipynb --- tutorials/scalable_constrained_bo.ipynb | 37 +++++++++++++++++++++---- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/tutorials/scalable_constrained_bo.ipynb b/tutorials/scalable_constrained_bo.ipynb index 209d496929..94a56fe820 100644 --- a/tutorials/scalable_constrained_bo.ipynb +++ b/tutorials/scalable_constrained_bo.ipynb @@ -383,7 +383,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -472,7 +472,13 @@ "360) Best value: -1.26e+00, TR length: 1.25e-02\n", "364) Best value: -1.21e+00, TR length: 1.25e-02\n", "368) Best value: -9.79e-01, TR length: 1.25e-02\n", - "372) Best value: -9.79e-01, TR length: 1.25e-02\n" + "372) Best value: -9.79e-01, TR length: 1.25e-02\n", + "376) Best value: -9.75e-01, TR length: 1.25e-02\n", + "380) Best value: -9.75e-01, TR length: 1.25e-02\n", + "384) Best value: -9.75e-01, TR length: 1.25e-02\n", + "388) Best value: -9.75e-01, TR length: 1.25e-02\n", + "392) Best value: -9.75e-01, TR length: 1.25e-02\n", + "396) Best value: -9.75e-01, TR length: 6.25e-03\n" ] } ], @@ -563,9 +569,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "With constraints, the best value we found is: -0.9748\n" + ] + } + ], "source": [ "# Valid samples must have BOTH c1 <= 0 and c2 <= 0\n", "constraint_vals = torch.cat([C1, C2], dim=-1)\n", @@ -587,9 +601,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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hZk5JGnSpEnO772dgaRsuWuvvdbyawDgY4HOyAHAF3bu3GlCQkKcvW8ffvih23IrV6506QHMycmpsu7s7GyXc3766acKZWraQ2yMMa+++qpLHVu3bq12He7k5OSYuLg4Z73z5893Of7www87j/Xu3bvK+tasWWMiIyNdzlmxYoXbsvv37zdPPvmkefzxxyscq6qH+PPPP3eZPWTKlCkuM4GUV7btPFm4cKFz5pDw8HDz2GOPmezs7Arl1q5da7p27eqsb/LkyRXKHDt2zMTGxhpJxmazmT/++MPjdY0xZuPGjc76YmJiTFZWVqXlAdQeeogBNAhTp051PojWtm1bl97WssqOO42Li1NUVFSVdZeOLS115MiRGkbrXqdOnVy2Dxw44JN6P/74Y2evdnJyss4++2yX42PHjnX2iK5du9alp92dm2++2dnj27dvX3377bcaMGCA27LNmzfXnXfeqb/97W/Vivntt9/WyJEjnT2zDzzwgF566SWXmUCqq7i4WJMnT1ZxcbGkkl7uu+++2+0Y8pNOOkmLFi1Ss2bNJEn//ve/nfNdl4qNjdXo0aMllYzRfuONNyq9ftne4csvv9zlngIQWCTEAOq9OXPm6KOPPnJuP/roo4qIiHBb9vjx487vvUmG3ZUtW4cvxcfHu2wfPXrUJ/WWHS4xevRohYa6rsmUkpKiM88802358lauXKkffvhBUsnUbXPmzFFsbKxP4iz1zDPPaPz48SosLJTdbteLL76omTNn1rjezz77TL///rsk6aKLLtLFF19cafnmzZvrtttuk1QynMTdg47XXXed8/vZs2d7nB3E4XDorbfecm4zXAKoW0iIAdRrq1at0g033ODcHj16tMaMGeOxfNmxrOHh4V5fp2yCnZubW80ovVM+sSxdza4m9u7dq4ULFzq3x40b57bc+PHjnd+/8847HhO7r776yvn9sGHD1LVr1xrHWNY999yjqVOnyhijsLAwvfPOO7rxxht9UvcXX3zh/L6ye6SsoUOHOr///vvvKxzv16+fTjrpJEklbf3111+7ree///2vDh48KEnq2rWrTj31VG/DBlALWLoZQL21fft2XXDBBc4kt2fPnnrllVcqPScyMtL5fXUWosjPz3d+X52e5eoonwCXPvhWE2+//bZziEDnzp3Vt29ft+UuvfRS3XjjjcrLy1NaWpq+/vprnXfeeRXKrVixwvn9kCFDahxfqaKiIl177bXOYQUxMTH66KOPKgzvqInly5c7v//oo4+0bNmyKs/JzMx0fl86d3V5kyZN0pQpUySVDItw125lh0tcc801XscMoHaQEAOol/bv368RI0Y4ZwpITU3VV199VWUSWbYXtjo9vWXL+nqIQKmyyZckNW7cuMZ1lh3+4Kl3WCpJvkeOHKkPPvjAeZ67xK7suObU1NQax1fq/fffV2FhoaSSoSNff/21x3HJVu3bt8/5fenrrA5PQ1jGjh2ru+66S9nZ2frss8908OBB54InkrRnzx5nz3F4eLhLbzyAuoEhEwDqncOHD2vEiBH6448/JJUs8bxw4UK1aNGiynObNGni/D4rK8ur6cBycnJcem99kai6s2XLFpft5s2b16i+n3/+WZs3b5ZUMt537NixlZYvmzD/97//VUZGRoUyZdvBl38YhIWFOb8/fvy4du7c6bO6S5X/g6O6ShP28uLi4jRq1ChJJWOFyy6AIpWMLS7tpR85cqSSkpJqFAcA3yMhBlCvZGVl6eyzz9bGjRslSUlJSVq4cKHatWvn1fnlZ3LwJvHatWtXpXX4ysqVK53fJycnq3379jWqr2zvsDFGJ5xwgnOFNHdff/nLX5zl8/Ly3Pailp0ZwZcPF1522WXOseBFRUUaM2aMz1frKzt38Zo1a2SMqdZXZasfln24ruzwCGOMZs2a5dzmYTqgbiIhBlBvZGdn67zzztPq1asllXy0/tVXX1Xrwa74+HiXnuS1a9dWec6aNWuc37dq1conY3vLy8vL0/z5853bZ5xxRo3qKygo0HvvvVejOtzNNlE6DZlUMobbV2w2m/71r3+5JMVjx471aVJcNvbSoTa+csopp6hnz56SpM2bNzvHKy9ZskR//vmnpJLZPIYPH+7T6wLwDRJiAPVCXl6eLrzwQueUX9HR0fr888/Vp0+fatdV9mGwpUuXVlm+7MNXZWcd8KU333xThw4dcm5fccUVNapv/vz5zvmSQ0NDNWDAAK+++vXr56xj+fLlLivRSSWJX6nFixfXKMbySpPi66+/XlLJEAVfJsVlxySX3ke+5K6XuGxv8VVXXVWjeZQB+FHtrwUCANVTUFBgzjvvPOcqXxEREWbBggWW65s7d66zroSEhEpXq8vJyTEJCQnO8h999JHbcjVZqW7btm0uK8l16dKl0hXZvHHhhRc667vggguqdW737t2d5957770ux8qu9Gez2cymTZssx+hppbri4mJz/fXXO4+FhoaauXPnVllf2fZ354MPPnAeb9GihcnNzbUcuztHjx41UVFRRpKJjY01u3fvdq7oZ7fbza5du3x6PQC+w5+qAOq00vGkpXPIhoaGau7cuTX66PnCCy9U69atJUkZGRl6+OGHPZb9xz/+4Xy4LCUlxWWcrS+sWrVKQ4cOda4kFxISomeffbZGPYkHDx7Ul19+6dy+8sorq3V+2fJvvfWWjDHO7f79++u0006TVDI+dvz48T5fqMRms+nll1/WpEmTJJX0FI8ZM0Yffvhhjer961//qg4dOkgqmaVkypQpLq+tMsePH1d2dnalZRISEnT55Zc7y1966aXOhzbPOusstWnTpgbRA/CrACfkAOBRcXGxmTBhgrNXz263m/fee88ndb/++usu9T733HMuvbJFRUXmueeeM3a73Vluzpw5HuurTg9xUVGR+fnnn83EiRNNeHi4y3nPP/98jV/bs88+66yvUaNGlfaAu7Nz505js9mcdSxatMjl+OrVq01ERITzeO/evc2KFSvc1rV//37z5JNPmieeeKLCMU89xKWKi4vNpEmTvO4pVhU9xMYYs2DBAhMSEuIsd+6551bay7127Vrzt7/9zSQkJJj169d7LFfq+++/d4mj9GvevHlVngsgcGzGePnnMQDUsn/9618uq5R17NhRZ511ltfnv/jii5UeHz9+vMtyuu3bt3eOkV2xYoVzWjepZPznG2+84bGuHTt2uMx0MX78eJcZGQoKCpSRkaGDBw9qzZo1zh7hUomJiXr55Zed03fVxMknn+x8WHDChAmaPXt2tesYNGiQvv32W0klr6X8A3bvvPOOJk6c6DIVWadOndS7d2/Fx8crMzNTmzZt0oYNG1RcXKxbb71Vzz77rEsds2fP1lVXXVVpnMYYXX/99XrttdcklXxC8N577+nSSy+tUNZms7mc58lrr72myZMnO1fjs9ls6tq1q3r27Km4uDjl5ORo//79+uWXX5yry0nS+vXr1b17d4/1lurevbtzFhRJatq0qfbs2eMytRyAOiaw+TgAeDZ9+nS3vW3eflUlPz/f3HTTTS69oeW/bDabueWWW0xBQUGldZXvIfb2q0mTJmbq1Klmz549PmmzX3/91aV+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W+pvf/ubfv31V61du1a33367mjVrJofDof/+978aNWqUWrRoocmTJ/vicjVSWFioW2+9VU8++aRuuOEGnXjiieratasuv/zyQIcG+F1+YbFMuTU56CEGAAQ7n3cN9erVS//85z/15JNPauHChXrrrbf0ySef6OjRo/q///s/vfzyy76+ZLWsWbNGe/fuld1uV+/evZWWlqaTTjpJTz75pLp37+7xvPz8fOXn/29Bg6ysLEmSw+GQw+Hwe9wNRWlb0WbV46t2y8yu+ElNmM002P8P7jfraDtraDdraDfraLvKedsuNmPK9xf5Tnp6ut5++229/vrr2rx5s2w2m4qKiqo+0Y/ef/99jR49Wm3bttXTTz+tE044Qf/85z/1zTff6LffflPjxo3dnjdjxgzNnDmzwv53331X0dEsN4v64XCe9OBa17+DH+9fqEg6iQEADVBOTo7GjBmjzMxMxcXFeSzn84Q4Ly9PH3/8sd566y0tXLhQRUVFKr1E7969tXr1al9ezmnatGl6/PHHKy2zefNmrVmzRmPHjtWrr76qSZMmSSrp/W3durUeeughXX/99W7PdddD3KZNG+3fv19NmjTx3Qtp4BwOhxYsWKARI0YoLCws0OHUG75qt98PHNd5L/7osm/LzBEKsTfMlSS536yj7ayh3ayh3ayj7SqXlZWlpKSkKhNinw2ZWLJkid566y199NFHOn78uDMJbtmypcaMGaPx48dXOiShpu644w5NnDix0jKpqanav3+/JKlr167O/REREUpNTdWuXbs8nhsREaGIiIgK+8PCwrgBLaDdrKlpu+UXu25HhtkVGRFew6jqPu4362g7a2g3a2g362g797xtkxolxJs3b9Zbb72ld955R3v27JFU8hR7dHS0Lr74Yo0fP17Dhw+Xzeb/3qfk5GQlJydXWa5Pnz6KiIjQ1q1bdfrpp0sq+etqx44dSklh+Vo0bBWmXAtnhgkAACz/Nuzbt6/Wrl0rqSQJttvtGjx4sMaPH6+//vWviomJ8VmQvhQXF6cbbrhB06dPV5s2bZSSkqInn3xSknTZZZcFODrAv8ov2xzFohwAAFhPiNesWSOpZOjBuHHjNHbsWLVu3dpngfnTk08+qdDQUI0bN065ubkaMGCAFi9erMTExECHBvhV+TmIWaUOAIAaJMS33HKLxo0bpz59+vgynloRFham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9u7dG+gwAZ8gIQaC1LRp05SYmKj09HT985//rLRs2d7bynpQMzMzfRafVZX9gs7Pz9fhw4clufbmNm/eXJLnoRC1pTSmyj5+z8vLc/safMEX7XDppZcqKipKWVlZ+vTTTyWVDMFIT09XWFiYcxx2WfPmzVNRUZG6dOmi999/X/369VN4eLhLmbS0NEvxlN67Vu7bL774QllZWUpMTNRnn32mQYMGKSoqyidxecOb+6HscV/fD5IUExOjcePGafbs2frtt9+0Z88ePf7444qMjHTpOQbqOxJiIEglJiZq2rRpkqR//vOfOnjwYKVlS+3evdttmd9++00ZGRk+jdGKZcuWeexF/O6775wfDfft29e5/7TTTpNUMs51//79/g/Sg9KYFi1a5LHM0qVLna/B01hrq0rbYeHChV4NHXGn7EN3pcMkSv8999xzlZSUVOGc0nuqV69estvd/1pauHChpXhK711P960krVy50u3+0nM6deqk6OjoasdV+lqs9mqX3g979uzxuOR6UVGRlixZIsn394M7rVq10t/+9jfdcccdkkoe/AMaAhJiIIjdfPPNat26tY4dO6Z//OMfHsvFxMSoffv2kkpmZHDn4Ycf9kuM1bVr1y7NmTOnwv7i4mI98sgjkqSuXbuqR48ezmOXXXaZEhIS5HA4NHXq1EoTmOLiYr8l/ldccYUkafny5frmm28qHC8sLHQ+2Ne9e3d1797dp9e/+uqrFRoaqkOHDjlns/CkoKDA41Cb0mET33zzjX7//XdnT7Gnh+ni4+MlSevXr3fb9l9++aXb4RneKJ0t4+uvv3Y7znfx4sVavnx5pXH99ttvbv9AWLdunceZHaSSscaSLN8vI0aMUJMmTSR5nmXi1VdfdY79dtf7blXZMdPulPaUe/oDBqhvuJOBIBYVFeX8RfvZZ59VWrb0l+0bb7yhf/3rX87xobt379a1116rDz74wGMvWm2Kj4/X5MmT9dprrzmTmN27d2v06NHOnrSHHnrI5ZyEhAQ9++yzkqT3339f559/vlauXOl8wKu4uFibN2/WP//5T3Xr1k3z58/3S+x//etfNWDAAEnS5Zdfrnfffdf5AOH27dv117/+1Zm8PfHEEz6/fvv27XX//fc76x8/frw2bNjgPF5YWKh169bpwQcfVIcOHdwuIy2VJHLNmzdXYWGhxowZo9zcXCUmJuovf/mL2/LnnHOOpJLp8G688UbnjAfZ2dl69dVXdemllzoTw+q6/PLLZbfbdfjwYY0ePdo5vCA3N1dz5szRxRdfrMaNG7s996yzzpLdbteRI0c0duxY53CcgoICzZ07V2eddValD6yV/sGyceNG/fjjj9WOvezP53vvvacbbrhBBw4ckFTyQOPzzz+v2267TVLJ+Pc+ffpU+xqePP744zr33HP11ltvuQzZyM/P19y5c/Xkk09K+t+0c0C9V2szHgOode4W5iivsLDQdO7cucrlWI8dO2a6du3qLGO3252LWYSFhZn33nvPq4U5PC3ssWTJEmcZTypbeKLs0s2nn366M67ExESX13bfffd5rP/ll192Wao5IiLCNGnSxISFhbnU8fbbb7ucV5OFHcrbs2eP6datm/Na4eHhLstP2+32CksFl/LFSnXFxcXm/vvvd1naNyoqyjRp0sRluWBJ5vvvv/dYT+kS1qVf119/faXXveKKK1zKl12euE+fPs4V29y9tqrav+yKbPr/qwCWrvB20UUXOVfnc3f+3XffXeHc0vuhXbt25p133vF43zocDudiJZJMYmKiSUlJMSkpKebDDz90lqvu0s2JiYkuy1oPGTKkyqWbPfH0c1d2UY/Se6Bx48Yu90WXLl2cK+cB9R09xECQCwkJcQ4lqExsbKy+//57TZ06Ve3atVNoaKjCwsKcvZalH/cHWnh4uBYtWqRHHnlEnTp1Un5+vuLj4zVs2DB9/vnnlQ4NueGGG7R161bdeeed6tWrlyIiIpSRkaHY2Fj17dtXN998sxYsWODTj6bLa9WqlVatWqWnn35ap5xyiqKiopSTk6M2bdpo3LhxWr16tW655Ra/Xd9ms+nBBx/Ur7/+qilTpqhLly4KCQlRZmamEhMTdeqpp+quu+7Sjz/+6Bxz7E754RGehkuUeuedd/Tss8+qZ8+eioiIUFFRkXr06KFHH31UP/zwg8d5dL0xc+ZMvfXWWzrllFMUExOjoqIinXTSSXrllVf0n//8p9LZQR577DG9+eab6t+/v6KiouRwONShQwf9/e9/19q1a53z+LoTGhqqRYsW6dprr1W7du2UnZ2tnTt3aufOndWa2eXpp5/W4sWL9de//lXNmjXT8ePH1ahRIw0ZMkRvvPGGFixYUGlPtRWTJk3S//3f/2n06NHq3r27oqOjnQ8YnnHGGXr22We1Zs0a54OYQH1nM4ZZtgEAABC86CEGAABAUCMhBgAAQFAjIQYAAEBQIyEGAABAUCMhBgAAQFAjIQYAAEBQIyEGAABAUCMhBgAAQFAjIQYAAEBQIyEGAABAUCMhBgAAQFAjIQYAAEBQIyEGAABAUPt/N8q92Gcqqt0AAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n",