From 2fd68470f9128bdae4b0fe25d909cc865560806c Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:48:17 +0100 Subject: [PATCH 001/140] pcse --- nevergrad/functions/pcse/__init__.py | 7 ++ nevergrad/functions/pcse/pcse.py | 147 ++++++++++++++++++++++++++ nevergrad/functions/pcse/test_pcse.py | 17 +++ 3 files changed, 171 insertions(+) create mode 100644 nevergrad/functions/pcse/__init__.py create mode 100644 nevergrad/functions/pcse/pcse.py create mode 100644 nevergrad/functions/pcse/test_pcse.py diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py new file mode 100644 index 0000000000..920aa2adda --- /dev/null +++ b/nevergrad/functions/pcse/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Based on https://github.com/facebookresearch/nevergrad/compare/main...fteytaud:opttorch +from .pcse import Pcse as Pcse diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py new file mode 100644 index 0000000000..2f10780b10 --- /dev/null +++ b/nevergrad/functions/pcse/pcse.py @@ -0,0 +1,147 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +Approximate Pcse Simulation +Based on +https://raw.githubusercontent.com/purdue-orbital/pcse-simulation/master/Simulation2.py +""" + + +import math +import pyproj +import numpy as np +from nevergrad.parametrization import parameter +from ..base import ArrayExperimentFunction + +# pylint: disable=too-many-locals,too-many-statements + + +class Pcse(ArrayExperimentFunction): + + + def __init__(self, symmetry: int = 0) -> None: + import sys + import matplotlib + import matplotlib.pyplot as plt + import yaml + import pandas as pd + import numpy as np + from itertools import product + #from progressbar import printProgressBar + + import pcse + from pcse.models import Wofost72_PP + from pcse.base import ParameterProvider + from pcse.db import NASAPowerWeatherDataProvider + from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider + + # Weather data for Netherlands + wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) + # Standard crop parameter library + cropd = YAMLCropDataProvider() + # We don't need soil for potential production, so we use dummy values + soild = DummySoilDataProvider() + # Some site parameters + sited = WOFOST72SiteDataProvider(WAV=50, CO2=360.) + # Package everyting into a single parameter object + params = ParameterProvider(cropdata=cropd, sitedata=sited, soildata=soild) + + # Here we define the agromanagement for sugar beet + agro_yaml = """ + - 2006-01-01: + CropCalendar: + crop_name: sugarbeet + variety_name: Sugarbeet_603 + crop_start_date: 2006-03-31 + crop_start_type: emergence + crop_end_date: 2006-10-20 + crop_end_type: harvest + max_duration: 300 + TimedEvents: null + StateEvents: null + """ + agro = yaml.load(agro_yaml) + + wofost = Wofost72_PP(params, wdp, agro) + wofost.run_till_terminate() + df = pd.DataFrame(wofost.get_output()) + df.index = pd.to_datetime(df.day) + df.tail() + + # get daily observations for those + ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) + df_pseudo_obs = df.loc[ix] + fig, axes = plt.subplots(figsize=(12,8)) + axes.plot_date(df_pseudo_obs.index, df_pseudo_obs.LAI) + r = axes.set_title("Pseudo LAI observations") + + class ModelRerunner(object): + """Reruns a given model with different values of parameters TWDI and SPAN. + + Returns a pandas DataFrame with simulation results of the model with given + parameter values. + """ + parameters = ["TDWI", "SPAN"] + + def __init__(self, params, wdp, agro): + self.params = params + self.wdp = wdp + self.agro = agro + + def __call__(self, par_values): + # Check if correct number of parameter values were provided + if len(par_values) != len(self.parameters): + msg = "Optimizing %i parameters, but only % values were provided!" % (len(self.parameters, len(par_values))) + raise RuntimeError(msg) + # Clear any existing overrides + self.params.clear_override() + # Set overrides for the new parameter values + for parname, value in zip(self.parameters, par_values): + self.params.set_override(parname, value) + # Run the model with given parameter values + wofost = Wofost72_PP(self.params, self.wdp, self.agro) + wofost.run_till_terminate() + df = pd.DataFrame(wofost.get_output()) + df.index = pd.to_datetime(df.day) + return df + + class ObjectiveFunctionCalculator(object): + """Computes the objective function. + + This class runs the simulation model with given parameter values and returns the objective + function as the sum of squared difference between observed and simulated LAI. + . """ + + def __init__(self, params, wdp, agro, observations): + self.modelrerunner = ModelRerunner(params, wdp, agro) + self.df_observations = observations + self.n_calls = 0 + + def __call__(self, par_values, grad=None): + """Runs the model and computes the objective function for given par_values. + + The input parameter 'grad' must be defined in the function call, but is only + required for optimization methods where analytical gradients can be computed. + """ + self.n_calls += 1 + #print(".", end="") + # Run the model and collect output + self.df_simulations = self.modelrerunner(par_values) + # compute the differences by subtracting the DataFrames + # Note that the dataframes automatically join on the index (dates) and column names + df_differences = self.df_simulations - self.df_observations + # Compute the RMSE on the LAI column + obj_func = np.sqrt(np.mean(df_differences.LAI**2)) + return obj_func + + objfunc_calculator = ObjectiveFunctionCalculator(params, wdp, agro, df_pseudo_obs) + # defaults = [cropd["TDWI"], cropd["SPAN"]] + # error = objfunc_calculator(defaults) + # print("Objective function value with default parameters (%s): %s" % (defaults, error)) + + param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) + super().__init__(objfunc_calculator, parametrization=param, symmetry=symmetry) diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py new file mode 100644 index 0000000000..cb05e38700 --- /dev/null +++ b/nevergrad/functions/pcse/test_pcse.py @@ -0,0 +1,17 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +from . import pcse + + +def test_rocket() -> None: + func = pcse.Pcse() + x = 0 * np.random.rand(func.dimension) + value = func(x) + value2 = func(x) + assert value > -1000. + assert value < 1000. + np.testing.assert_almost_equal(value, value2) From 0ea7b9a50bcec51dba654951fd45f6d1bf0443e1 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:51:39 +0100 Subject: [PATCH 002/140] pcse --- nevergrad/benchmark/experiments.py | 20 ++++++++++++++++++++ nevergrad/functions/pcse/pcse.py | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 5a8347a23f..ec6c20fda8 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -25,6 +25,7 @@ from nevergrad.functions.ac import NgAquacrop from nevergrad.functions.stsp import STSP from nevergrad.functions.rocket import Rocket +from nevergrad.functions.pcse import Pcse from nevergrad.functions.mixsimulator import OptimizeMix from nevergrad.functions.unitcommitment import UnitCommitmentProblem from nevergrad.functions import control @@ -1274,6 +1275,25 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe yield xp +@registry.register +def pcse(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + """Crop simulator. + + Low dimensional problem, only 2 vars. + """ + funcs = [Pcse()] + seedg = create_seed_generator(seed) + optims = get_optimizers("basics", seed=next(seedg)) + for budget in [25, 50, 100, 200]: + for num_workers in [1, 10, 40]: + if num_workers < budget: + for algo in optims: + for fu in funcs: + xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg)) + if not xp.is_incoherent: + yield xp + + @registry.register def mono_rocket(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Sequential counterpart of the rocket problem.""" diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 2f10780b10..af76c8af86 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -4,7 +4,7 @@ # LICENSE file in the root directory of this source tree. """ -Approximate Pcse Simulation +Approximate crop Simulation Based on https://raw.githubusercontent.com/purdue-orbital/pcse-simulation/master/Simulation2.py """ @@ -22,7 +22,7 @@ class Pcse(ArrayExperimentFunction): - def __init__(self, symmetry: int = 0) -> None: + def __init__(self) -> None: import sys import matplotlib import matplotlib.pyplot as plt @@ -144,4 +144,4 @@ def __call__(self, par_values, grad=None): # print("Objective function value with default parameters (%s): %s" % (defaults, error)) param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) - super().__init__(objfunc_calculator, parametrization=param, symmetry=symmetry) + super().__init__(objfunc_calculator, parametrization=param) From a53c0e7f566b3da9479b504860bb192e6708470d Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:53:52 +0100 Subject: [PATCH 003/140] fix --- nevergrad/functions/pcse/pcse.py | 60 ++++++++++++++------------- nevergrad/functions/pcse/test_pcse.py | 4 +- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index af76c8af86..0c4b883c55 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -20,8 +20,6 @@ class Pcse(ArrayExperimentFunction): - - def __init__(self) -> None: import sys import matplotlib @@ -30,15 +28,16 @@ def __init__(self) -> None: import pandas as pd import numpy as np from itertools import product - #from progressbar import printProgressBar - + + # from progressbar import printProgressBar + import pcse from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider - + # Weather data for Netherlands wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) # Standard crop parameter library @@ -46,10 +45,10 @@ def __init__(self) -> None: # We don't need soil for potential production, so we use dummy values soild = DummySoilDataProvider() # Some site parameters - sited = WOFOST72SiteDataProvider(WAV=50, CO2=360.) + sited = WOFOST72SiteDataProvider(WAV=50, CO2=360.0) # Package everyting into a single parameter object params = ParameterProvider(cropdata=cropd, sitedata=sited, soildata=soild) - + # Here we define the agromanagement for sugar beet agro_yaml = """ - 2006-01-01: @@ -65,37 +64,40 @@ def __init__(self) -> None: StateEvents: null """ agro = yaml.load(agro_yaml) - + wofost = Wofost72_PP(params, wdp, agro) wofost.run_till_terminate() df = pd.DataFrame(wofost.get_output()) df.index = pd.to_datetime(df.day) df.tail() - + # get daily observations for those ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) df_pseudo_obs = df.loc[ix] - fig, axes = plt.subplots(figsize=(12,8)) + fig, axes = plt.subplots(figsize=(12, 8)) axes.plot_date(df_pseudo_obs.index, df_pseudo_obs.LAI) r = axes.set_title("Pseudo LAI observations") - + class ModelRerunner(object): """Reruns a given model with different values of parameters TWDI and SPAN. - + Returns a pandas DataFrame with simulation results of the model with given parameter values. """ + parameters = ["TDWI", "SPAN"] - + def __init__(self, params, wdp, agro): self.params = params self.wdp = wdp self.agro = agro - + def __call__(self, par_values): # Check if correct number of parameter values were provided if len(par_values) != len(self.parameters): - msg = "Optimizing %i parameters, but only % values were provided!" % (len(self.parameters, len(par_values))) + msg = "Optimizing %i parameters, but only % values were provided!" % ( + len(self.parameters, len(par_values)) + ) raise RuntimeError(msg) # Clear any existing overrides self.params.clear_override() @@ -108,40 +110,42 @@ def __call__(self, par_values): df = pd.DataFrame(wofost.get_output()) df.index = pd.to_datetime(df.day) return df - + class ObjectiveFunctionCalculator(object): """Computes the objective function. - - This class runs the simulation model with given parameter values and returns the objective - function as the sum of squared difference between observed and simulated LAI. - . """ - + + This class runs the simulation model with given parameter values and returns the objective + function as the sum of squared difference between observed and simulated LAI. + .""" + def __init__(self, params, wdp, agro, observations): self.modelrerunner = ModelRerunner(params, wdp, agro) self.df_observations = observations self.n_calls = 0 - + def __call__(self, par_values, grad=None): """Runs the model and computes the objective function for given par_values. - + The input parameter 'grad' must be defined in the function call, but is only required for optimization methods where analytical gradients can be computed. """ self.n_calls += 1 - #print(".", end="") + # print(".", end="") # Run the model and collect output self.df_simulations = self.modelrerunner(par_values) # compute the differences by subtracting the DataFrames # Note that the dataframes automatically join on the index (dates) and column names df_differences = self.df_simulations - self.df_observations # Compute the RMSE on the LAI column - obj_func = np.sqrt(np.mean(df_differences.LAI**2)) + obj_func = np.sqrt(np.mean(df_differences.LAI ** 2)) return obj_func - + objfunc_calculator = ObjectiveFunctionCalculator(params, wdp, agro, df_pseudo_obs) # defaults = [cropd["TDWI"], cropd["SPAN"]] # error = objfunc_calculator(defaults) # print("Objective function value with default parameters (%s): %s" % (defaults, error)) - - param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) + + param = ng.p.Array( + shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) + ) super().__init__(objfunc_calculator, parametrization=param) diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index cb05e38700..8d7d9b410b 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -12,6 +12,6 @@ def test_rocket() -> None: x = 0 * np.random.rand(func.dimension) value = func(x) value2 = func(x) - assert value > -1000. - assert value < 1000. + assert value > -1000.0 + assert value < 1000.0 np.testing.assert_almost_equal(value, value2) From dc88a7e9a8517bfb17ad02cb49c4c31c7d7343b8 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:59:42 +0100 Subject: [PATCH 004/140] pcse --- nevergrad/functions/pcse/pcse.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 0c4b883c55..6302037d6f 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -145,7 +145,11 @@ def __call__(self, par_values, grad=None): # error = objfunc_calculator(defaults) # print("Objective function value with default parameters (%s): %s" % (defaults, error)) + import nevergrad as ng + + TDWI_range = [0.1, 0.6] + SPAN_range = [30, 40] param = ng.p.Array( shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) - ) + ).set_name("2hp") super().__init__(objfunc_calculator, parametrization=param) From 47a63ed90c735dc49588cd6b8a112dae51799d1e Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:06:01 +0100 Subject: [PATCH 005/140] fix --- nevergrad/functions/pcse/pcse.py | 14 -------------- requirements/bench.txt | 1 + 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 6302037d6f..65264181d0 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -10,10 +10,7 @@ """ -import math -import pyproj import numpy as np -from nevergrad.parametrization import parameter from ..base import ArrayExperimentFunction # pylint: disable=too-many-locals,too-many-statements @@ -21,17 +18,9 @@ class Pcse(ArrayExperimentFunction): def __init__(self) -> None: - import sys - import matplotlib - import matplotlib.pyplot as plt import yaml import pandas as pd import numpy as np - from itertools import product - - # from progressbar import printProgressBar - - import pcse from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider @@ -74,9 +63,6 @@ def __init__(self) -> None: # get daily observations for those ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) df_pseudo_obs = df.loc[ix] - fig, axes = plt.subplots(figsize=(12, 8)) - axes.plot_date(df_pseudo_obs.index, df_pseudo_obs.LAI) - r = axes.set_title("Pseudo LAI observations") class ModelRerunner(object): """Reruns a given model with different values of parameters TWDI and SPAN. diff --git a/requirements/bench.txt b/requirements/bench.txt index a5ce9e7788..5fec6d8390 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -41,3 +41,4 @@ pybullet>=3.2.2 box2d-py>=2.3.5 glfw mujoco +pcse From 8dbd1aed4256f8797c889f0948c533d0a427144e Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:47:51 +0100 Subject: [PATCH 006/140] nlopt --- mypy.ini | 3 ++- nevergrad/functions/pcse/pcse.py | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mypy.ini b/mypy.ini index e507d4c99f..d49dc0b586 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3,7 +3,8 @@ [mypy-scipy.*,requests,pandas,compiler_gym,compiler_gym.*,gym_anm,matplotlib.*,pytest,cma,bayes_opt.*,torchvision.models,torch.*,mpl_toolkits.*,fcmaes.*,tqdm,pillow,PIL,PIL.Image,sklearn.*,pyomo.*,pyproj,IOHexperimenter.*,tensorflow,koncept.models,cv2,imquality,imquality.brisque,lpips,mixsimulator.*,networkx.*,cdt.*,pymoo,pymoo.*,bayes_optim.*,olympus.*,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,aquacrop.*] ignore_missing_imports = True -[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] +[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] ignore_missing_imports = True ignore_errors = True diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 65264181d0..24a4d5931a 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -20,11 +20,12 @@ class Pcse(ArrayExperimentFunction): def __init__(self) -> None: import yaml import pandas as pd - import numpy as np from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider - from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + + # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + from pcse.fileinput import YAMLCropDataProvider from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider # Weather data for Netherlands @@ -118,10 +119,10 @@ def __call__(self, par_values, grad=None): self.n_calls += 1 # print(".", end="") # Run the model and collect output - self.df_simulations = self.modelrerunner(par_values) + df_simulations = self.modelrerunner(par_values) # compute the differences by subtracting the DataFrames # Note that the dataframes automatically join on the index (dates) and column names - df_differences = self.df_simulations - self.df_observations + df_differences = df_simulations - self.df_observations # Compute the RMSE on the LAI column obj_func = np.sqrt(np.mean(df_differences.LAI ** 2)) return obj_func From 1fbf9c647fe4ab10dc3965b8624c5e60ea757d8c Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:56:08 +0100 Subject: [PATCH 007/140] nlopt --- mypy.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypy.ini b/mypy.ini index d49dc0b586..bb69b3953e 100644 --- a/mypy.ini +++ b/mypy.ini @@ -4,7 +4,8 @@ ignore_missing_imports = True #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] -[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] +[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] ignore_missing_imports = True ignore_errors = True From 14b86fde70ee5fe2c71d6c9bfc38fcc329accd00 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 15:01:57 +0100 Subject: [PATCH 008/140] nlopt --- nevergrad/functions/pcse/pcse.py | 3 ++- nevergrad/functions/pcse/test_pcse.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 24a4d5931a..f76bc63193 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -83,7 +83,8 @@ def __call__(self, par_values): # Check if correct number of parameter values were provided if len(par_values) != len(self.parameters): msg = "Optimizing %i parameters, but only % values were provided!" % ( - len(self.parameters, len(par_values)) + len(self.parameters), + len(par_values), ) raise RuntimeError(msg) # Clear any existing overrides diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index 8d7d9b410b..70d7a47e16 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -12,6 +12,6 @@ def test_rocket() -> None: x = 0 * np.random.rand(func.dimension) value = func(x) value2 = func(x) - assert value > -1000.0 - assert value < 1000.0 + assert value > -1000.0 # type: ignore + assert value < 1000.0 # type: ignore np.testing.assert_almost_equal(value, value2) From 681d38141a410be6b2f1e302afc36f969b35a6ae Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 15:11:53 +0100 Subject: [PATCH 009/140] fix --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index f76bc63193..e622b2d4a4 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -82,7 +82,7 @@ def __init__(self, params, wdp, agro): def __call__(self, par_values): # Check if correct number of parameter values were provided if len(par_values) != len(self.parameters): - msg = "Optimizing %i parameters, but only % values were provided!" % ( + msg = "Optimizing %i parameters, but %i values were provided!" % ( len(self.parameters), len(par_values), ) From 6a86208999f1a18bab392003b36ec851e1843717 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 15:20:37 +0100 Subject: [PATCH 010/140] fix --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index e622b2d4a4..a5d9295c08 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -53,7 +53,7 @@ def __init__(self) -> None: TimedEvents: null StateEvents: null """ - agro = yaml.load(agro_yaml) + agro = yaml.safe_load(agro_yaml) wofost = Wofost72_PP(params, wdp, agro) wofost.run_till_terminate() From 2e96c9f287a69fb89656683db15aa70b27268b1f Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 15:47:29 +0100 Subject: [PATCH 011/140] fix --- nevergrad/optimization/test_optimizerlib.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index b9e29ce56a..705ba9772f 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -723,7 +723,11 @@ def test_ngopt_selection( # pylint: disable=pointless-statement opt.optim # type: ignore pattern = rf".*{name} selected (?P\w+?) optimizer\." - match = re.match(pattern, caplog.text.splitlines()[-1]) + try: + match = re.match(pattern, caplog.text.splitlines()[-1]) + except Error as e: + print(f"{caplog.text.splitlines()}") + raise e assert match is not None, f"Did not detect selection in logs: {caplog.text}" choice = match.group("name") if expected != "#CONTINUOUS": From af8c9da52fd46f766e575bbe8413d0b3450a100e Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 16:05:27 +0100 Subject: [PATCH 012/140] po --- nevergrad/optimization/test_optimizerlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 705ba9772f..4e602e837e 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -725,7 +725,7 @@ def test_ngopt_selection( pattern = rf".*{name} selected (?P\w+?) optimizer\." try: match = re.match(pattern, caplog.text.splitlines()[-1]) - except Error as e: + except Exception as e: print(f"{caplog.text.splitlines()}") raise e assert match is not None, f"Did not detect selection in logs: {caplog.text}" From f00278e88b34a4f999417c9baee47422b4e8cbae Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 16:18:44 +0100 Subject: [PATCH 013/140] po --- nevergrad/optimization/test_optimizerlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 4e602e837e..96f1b7c10b 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -726,7 +726,7 @@ def test_ngopt_selection( try: match = re.match(pattern, caplog.text.splitlines()[-1]) except Exception as e: - print(f"{caplog.text.splitlines()}") + assert False, f"{caplog.text}" raise e assert match is not None, f"Did not detect selection in logs: {caplog.text}" choice = match.group("name") From 00b5cfb7ff893668a858bce8ceca64868fca03b3 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 16:29:25 +0100 Subject: [PATCH 014/140] po --- nevergrad/optimization/optimizerlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 9f982b84f8..3365c2ad42 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -2614,7 +2614,7 @@ def optim(self) -> base.Optimizer: if self._optim is None: self._optim = self._select_optimizer_cls()(self.parametrization, self.budget, self.num_workers) self._optim = self._optim if not isinstance(self._optim, NGOptBase) else self._optim.optim - logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) + logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) return self._optim def _select_optimizer_cls(self) -> base.OptCls: From 4ad0ba9d2834c43662f9cd0d5692bd6c769cc0e5 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 16:46:16 +0100 Subject: [PATCH 015/140] po --- nevergrad/optimization/test_optimizerlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 96f1b7c10b..bb1436184b 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -721,12 +721,12 @@ def test_ngopt_selection( # pylint: disable=expression-not-assigned opt = optlib.registry[name](param, budget=budget, num_workers=num_workers) # pylint: disable=pointless-statement - opt.optim # type: ignore + o = str(opt.optim) # type: ignore pattern = rf".*{name} selected (?P\w+?) optimizer\." try: match = re.match(pattern, caplog.text.splitlines()[-1]) except Exception as e: - assert False, f"{caplog.text}" + assert False, f"{caplog.text} ==> {o}" raise e assert match is not None, f"Did not detect selection in logs: {caplog.text}" choice = match.group("name") From a7c75019853c4b1c14b04894947d242e5d35a530 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 16:58:52 +0100 Subject: [PATCH 016/140] to --- nevergrad/optimization/test_optimizerlib.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index bb1436184b..9436e697c7 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -722,26 +722,25 @@ def test_ngopt_selection( opt = optlib.registry[name](param, budget=budget, num_workers=num_workers) # pylint: disable=pointless-statement o = str(opt.optim) # type: ignore - pattern = rf".*{name} selected (?P\w+?) optimizer\." - try: - match = re.match(pattern, caplog.text.splitlines()[-1]) - except Exception as e: - assert False, f"{caplog.text} ==> {o}" - raise e - assert match is not None, f"Did not detect selection in logs: {caplog.text}" - choice = match.group("name") + # pattern = rf".*{name} selected (?P\w+?) optimizer\." + # match = re.match(pattern, caplog.text.splitlines()[-1]) + #assert match is not None, f"Did not detect selection in logs: {caplog.text}" + #choice = match.group("name") if expected != "#CONTINUOUS": - assert choice == expected + #assert choice == expected + assert expected in o else: print(f"Continuous param={param} budget={budget} workers={num_workers} --> {choice}") if num_workers >= budget > 600: - assert choice == "MetaTuneRecentering" + #assert choice == "MetaTuneRecentering" + assert "MetaTuneRecentering" in o if num_workers > 1: assert choice not in ["SQP", "Cobyla"] if "CMA" not in choice: assert choice == opt._info()["sub-optim"] else: assert choice in opt._info()["sub-optim"] + #assert expected == opt._info()["sub-optim"] def test_bo_ordering() -> None: From dc33bbf3f773698f2613cdafdfb4fdceff794364 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 17:09:21 +0100 Subject: [PATCH 017/140] fix --- nevergrad/optimization/test_optimizerlib.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 9436e697c7..baa491d08c 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -721,18 +721,20 @@ def test_ngopt_selection( # pylint: disable=expression-not-assigned opt = optlib.registry[name](param, budget=budget, num_workers=num_workers) # pylint: disable=pointless-statement + # The pattern matching from the log does not work anymore, + # hence some modifications below. We might delete the old version. o = str(opt.optim) # type: ignore # pattern = rf".*{name} selected (?P\w+?) optimizer\." # match = re.match(pattern, caplog.text.splitlines()[-1]) - #assert match is not None, f"Did not detect selection in logs: {caplog.text}" - #choice = match.group("name") + # assert match is not None, f"Did not detect selection in logs: {caplog.text}" + # choice = match.group("name") if expected != "#CONTINUOUS": - #assert choice == expected + # assert choice == expected assert expected in o else: - print(f"Continuous param={param} budget={budget} workers={num_workers} --> {choice}") + # print(f"Continuous param={param} budget={budget} workers={num_workers} --> {choice}") if num_workers >= budget > 600: - #assert choice == "MetaTuneRecentering" + # assert choice == "MetaTuneRecentering" assert "MetaTuneRecentering" in o if num_workers > 1: assert choice not in ["SQP", "Cobyla"] From 350602474353ea15ff21c4f50c5f95cb9d435ac3 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 17:24:44 +0100 Subject: [PATCH 018/140] fix --- nevergrad/optimization/test_optimizerlib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index baa491d08c..f5e5cdd997 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -3,7 +3,6 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import re import sys import time import random @@ -724,6 +723,7 @@ def test_ngopt_selection( # The pattern matching from the log does not work anymore, # hence some modifications below. We might delete the old version. o = str(opt.optim) # type: ignore + # import re # pattern = rf".*{name} selected (?P\w+?) optimizer\." # match = re.match(pattern, caplog.text.splitlines()[-1]) # assert match is not None, f"Did not detect selection in logs: {caplog.text}" @@ -743,6 +743,7 @@ def test_ngopt_selection( else: assert choice in opt._info()["sub-optim"] #assert expected == opt._info()["sub-optim"] + #assert opt._info()["sub-optim"] in o def test_bo_ordering() -> None: From 51ecfafeaedaaab72fc08064c7711019fefb86a5 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Fri, 21 Jan 2022 10:02:46 +0100 Subject: [PATCH 019/140] Update __init__.py --- nevergrad/functions/pcse/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py index 920aa2adda..be9fc49370 100644 --- a/nevergrad/functions/pcse/__init__.py +++ b/nevergrad/functions/pcse/__init__.py @@ -3,5 +3,6 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -# Based on https://github.com/facebookresearch/nevergrad/compare/main...fteytaud:opttorch +# Based on https://github.com/ajwdewit/pcse_notebooks +# MIT License. from .pcse import Pcse as Pcse From 707ee80afa32098707c10706ba4784e1570e094b Mon Sep 17 00:00:00 2001 From: Teytaud Date: Fri, 21 Jan 2022 15:01:54 +0100 Subject: [PATCH 020/140] Update experiments.py --- nevergrad/benchmark/experiments.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index ec6c20fda8..bd174e4a3b 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1279,7 +1279,8 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe def pcse(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. - Low dimensional problem, only 2 vars. + Low dimensional problem, only 2 vars. This is optimization for model identification: we want + to find parameters so that the simulation matches observations. """ funcs = [Pcse()] seedg = create_seed_generator(seed) From dcac1a05aaf4ed6a241fe916fbc3f76b80a7eb4e Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:47:50 +0100 Subject: [PATCH 021/140] Update nevergrad/optimization/optimizerlib.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy Rapin --- nevergrad/optimization/optimizerlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 3365c2ad42..9f982b84f8 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -2614,7 +2614,7 @@ def optim(self) -> base.Optimizer: if self._optim is None: self._optim = self._select_optimizer_cls()(self.parametrization, self.budget, self.num_workers) self._optim = self._optim if not isinstance(self._optim, NGOptBase) else self._optim.optim - logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) + logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) return self._optim def _select_optimizer_cls(self) -> base.OptCls: From b809b5b80f99fcba293918a4355cdcbfd31b90a6 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:49:42 +0100 Subject: [PATCH 022/140] Update test_optimizerlib.py --- nevergrad/optimization/test_optimizerlib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index f5e5cdd997..8128802089 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -722,7 +722,7 @@ def test_ngopt_selection( # pylint: disable=pointless-statement # The pattern matching from the log does not work anymore, # hence some modifications below. We might delete the old version. - o = str(opt.optim) # type: ignore + optim_string = str(opt.optim) # type: ignore # import re # pattern = rf".*{name} selected (?P\w+?) optimizer\." # match = re.match(pattern, caplog.text.splitlines()[-1]) @@ -730,12 +730,12 @@ def test_ngopt_selection( # choice = match.group("name") if expected != "#CONTINUOUS": # assert choice == expected - assert expected in o + assert expected in optim_string else: # print(f"Continuous param={param} budget={budget} workers={num_workers} --> {choice}") if num_workers >= budget > 600: # assert choice == "MetaTuneRecentering" - assert "MetaTuneRecentering" in o + assert "MetaTuneRecentering" in optim_string if num_workers > 1: assert choice not in ["SQP", "Cobyla"] if "CMA" not in choice: From d213892be918dbc5f7824d75932bf8b6e46a3510 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:50:29 +0100 Subject: [PATCH 023/140] Update test_pcse.py --- nevergrad/functions/pcse/test_pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index 70d7a47e16..4b5f6455cd 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -7,7 +7,7 @@ from . import pcse -def test_rocket() -> None: +def test_pcse() -> None: func = pcse.Pcse() x = 0 * np.random.rand(func.dimension) value = func(x) From 2b19b402d7bd42ac7cd87efdae60cb307af71a42 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:52:07 +0100 Subject: [PATCH 024/140] Update pcse.py --- nevergrad/functions/pcse/pcse.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index a5d9295c08..3184570ad8 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -9,17 +9,17 @@ https://raw.githubusercontent.com/purdue-orbital/pcse-simulation/master/Simulation2.py """ - +import pandas as pd +import yaml import numpy as np +import nevergrad as ng from ..base import ArrayExperimentFunction # pylint: disable=too-many-locals,too-many-statements -class Pcse(ArrayExperimentFunction): +class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: - import yaml - import pandas as pd from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider @@ -133,8 +133,6 @@ def __call__(self, par_values, grad=None): # error = objfunc_calculator(defaults) # print("Objective function value with default parameters (%s): %s" % (defaults, error)) - import nevergrad as ng - TDWI_range = [0.1, 0.6] SPAN_range = [30, 40] param = ng.p.Array( From 9bc4cfd2ce07591e3edacae33590806a48847e29 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:53:11 +0100 Subject: [PATCH 025/140] Update experiments.py --- nevergrad/benchmark/experiments.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index bd174e4a3b..d038f8904a 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -25,7 +25,7 @@ from nevergrad.functions.ac import NgAquacrop from nevergrad.functions.stsp import STSP from nevergrad.functions.rocket import Rocket -from nevergrad.functions.pcse import Pcse +from nevergrad.functions.pcse import CropSimulator from nevergrad.functions.mixsimulator import OptimizeMix from nevergrad.functions.unitcommitment import UnitCommitmentProblem from nevergrad.functions import control @@ -1276,13 +1276,13 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe @registry.register -def pcse(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: +def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. Low dimensional problem, only 2 vars. This is optimization for model identification: we want to find parameters so that the simulation matches observations. """ - funcs = [Pcse()] + funcs = [CropSimulator()] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) for budget in [25, 50, 100, 200]: From 5569d69ffc2636016a6a8f0c10e16862d0a286bc Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 20:08:49 +0100 Subject: [PATCH 026/140] Pcse2: irrigation challenge (#1341) * irrigation_challenge * flute * fix * Update __init__.py * Update experiments.py * fix * fix * fix * fix * fix * fix * fix * fix * fix_gym * fix_gym * fix_gym * fix * fix --- nevergrad/benchmark/experiments.py | 19 +++ nevergrad/functions/gym/test_multigym.py | 23 ++++ nevergrad/functions/irrigation/__init__.py | 8 ++ .../functions/irrigation/data/meteo/nl1.xlsx | Bin 0 -> 208384 bytes nevergrad/functions/irrigation/irrigation.py | 122 ++++++++++++++++++ .../functions/irrigation/test_irrigation.py | 19 +++ nevergrad/functions/pcse/__init__.py | 2 +- nevergrad/functions/pcse/test_pcse.py | 2 +- requirements/bench.txt | 1 + 9 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 nevergrad/functions/irrigation/__init__.py create mode 100644 nevergrad/functions/irrigation/data/meteo/nl1.xlsx create mode 100644 nevergrad/functions/irrigation/irrigation.py create mode 100644 nevergrad/functions/irrigation/test_irrigation.py diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index d038f8904a..3666aa9da5 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -25,6 +25,7 @@ from nevergrad.functions.ac import NgAquacrop from nevergrad.functions.stsp import STSP from nevergrad.functions.rocket import Rocket +from nevergrad.functions.irrigation import Irrigation from nevergrad.functions.pcse import CropSimulator from nevergrad.functions.mixsimulator import OptimizeMix from nevergrad.functions.unitcommitment import UnitCommitmentProblem @@ -1276,6 +1277,24 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe @registry.register +def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + """Irrigation simulator. Maximize leaf area index, + so that you get a lot of primary production. + Sequential or 30 workers.""" + funcs = [Irrigation(i) for i in range(17)] + seedg = create_seed_generator(seed) + optims = get_optimizers("basics", seed=next(seedg)) + for budget in [25, 50, 100, 200]: + for num_workers in [1, 30, 60]: + if num_workers < budget: + for algo in optims: + for fu in funcs: + xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg)) + skip_ci(reason="Too slow") + if not xp.is_incoherent: + yield xp + + def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. diff --git a/nevergrad/functions/gym/test_multigym.py b/nevergrad/functions/gym/test_multigym.py index c8a792c33c..fd56aaac50 100644 --- a/nevergrad/functions/gym/test_multigym.py +++ b/nevergrad/functions/gym/test_multigym.py @@ -19,9 +19,17 @@ def test_multigym() -> None: assert env_name in GYM_ENV_NAMES, f"{env_name} unknown!" assert env_name not in multigym.NO_LENGTH, f"{env_name} in no length and in ng_gym!" for env_name in multigym.GUARANTEED_GYM_ENV_NAMES: + if any(x in env_name for x in ["MemorizeDigit"]): + continue assert env_name in GYM_ENV_NAMES, f"{env_name} should be guaranteed!" assert len(GYM_ENV_NAMES) >= 10 or os.name == "nt" +#def test_compiler_gym() -> None: +# func = multigym.CompilerGym(17) +# candidate = func.parametrization.sample() +# results = [func.evaluation_function(candidate) for _ in range(4)] +# assert min(results) == max(results), "CompilerGym should be deterministic." + def test_cartpole() -> None: func = multigym.GymMulti(name="CartPole-v0", control="neural", neural_factor=1, randomized=True) @@ -46,9 +54,14 @@ def test_sparse_cartpole() -> None: assert min(results) != max(results), "CartPole should not be deterministic." +<<<<<<< HEAD @pytest.mark.parametrize("name", ["LunarLander-v2"]) # type: ignore def test_run_multigym(name: str) -> None: if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: +======= +def test_default_run_multigym() -> None: + if os.name == "nt": +>>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341)) raise SkipTest("Skipping Windows and running only 1 out of 8") if "ANM" in name: raise SkipTest("We skip ANM6Easy and related problems.") @@ -56,7 +69,17 @@ def test_run_multigym(name: str) -> None: func = multigym.GymMulti(randomized=False, neural_factor=None) x = np.zeros(func.dimension) value = func(x) +<<<<<<< HEAD np.testing.assert_almost_equal(value, 178.2, decimal=2) +======= + np.testing.assert_almost_equal(value, 178.20, decimal=2) + + +@pytest.mark.parametrize("name", GYM_ENV_NAMES) # type: ignore +def test_run_multigym(name: str) -> None: + if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: + raise SkipTest("Skipping Windows and running only 1 out of 8") +>>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341)) i = GYM_ENV_NAMES.index(name) control = multigym.CONTROLLERS[i % len(multigym.CONTROLLERS)] print(f"Working with {control} on {name}.") diff --git a/nevergrad/functions/irrigation/__init__.py b/nevergrad/functions/irrigation/__init__.py new file mode 100644 index 0000000000..02d12312a2 --- /dev/null +++ b/nevergrad/functions/irrigation/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Based on https://github.com/ajwdewit/pcse_notebooks +# (MIT License). +from .irrigation import Irrigation as Irrigation diff --git a/nevergrad/functions/irrigation/data/meteo/nl1.xlsx b/nevergrad/functions/irrigation/data/meteo/nl1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..93c6bfe2d2eab5b848cdb143b88b92bdcbdb556a GIT binary patch literal 208384 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%0AAK(jnzN*&}6F9L>siHM6{WBJQE@EDu)M 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 None: + import nevergrad as ng + + param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") + super().__init__(leaf_area_index, parametrization=param, symmetry=symmetry) + + +import numpy as np + + +def leaf_area_index(x: np.ndarray): + d0 = int(1.01 + 29.98 * x[0]) + d1 = int(1.01 + 30.98 * x[1]) + d2 = int(1.01 + 30.98 * x[2]) + d3 = int(1.01 + 29.98 * x[3]) + a0 = 15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) + a1 = 15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) + a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) + a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) + import os, sys + + # import matplotlib + # matplotlib.style.use("ggplot") + # import matplotlib.pyplot as plt + import pandas as pd + import yaml + + import pcse + from pcse.models import Wofost72_WLP_FD + from pcse.fileinput import CABOFileReader, YAMLCropDataProvider + + # from pcse.db import NASAPowerWeatherDataProvider + from pcse.util import WOFOST72SiteDataProvider + from pcse.base import ParameterProvider + + # data_dir = os.path.join(os.getcwd(), "data") + data_dir = Path(__file__).with_name("data") + + print("This notebook was built with:") + print("python version: %s " % sys.version) + print("PCSE version: %s" % pcse.__version__) + + crop = YAMLCropDataProvider() + if os.environ.get("CIRCLECI", False): + raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") + urllib.request.urlretrieve( + "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", + str(data_dir) + "/soil/ec3.soil", + ) + soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) + site = WOFOST72SiteDataProvider(WAV=100, CO2=360) + parameterprovider = ParameterProvider(soildata=soil, cropdata=crop, sitedata=site) + + crop = YAMLCropDataProvider() + + from pcse.fileinput import ExcelWeatherDataProvider + + weatherfile = os.path.join(data_dir, "meteo", "nl1.xlsx") + weatherdataprovider = ExcelWeatherDataProvider(weatherfile) + + yaml_agro = f""" + - 2006-01-01: + CropCalendar: + crop_name: sugarbeet + variety_name: Sugarbeet_603 + crop_start_date: 2006-03-31 + crop_start_type: emergence + crop_end_date: 2006-10-20 + crop_end_type: harvest + max_duration: 300 + TimedEvents: + - event_signal: irrigate + name: Irrigation application table + comment: All irrigation amounts in cm + events_table: + - 2006-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}} + - 2006-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}} + - 2006-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}} + - 2006-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} + StateEvents: null + """ + try: + agromanagement = yaml.safe_load(yaml_agro) + wofost = Wofost72_WLP_FD(parameterprovider, weatherdataprovider, agromanagement) + wofost.run_till_terminate() + except Exception as e: + assert False, f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + raise e + + output = wofost.get_output() + df = pd.DataFrame(output).set_index("day") + df.tail() + + # print(output) + # print(len(output)) + return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) + # fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16,8)) + # df['LAI'].plot(ax=axes[0], title="Leaf Area Index") + # df['SM'].plot(ax=axes[1], title="Root zone soil moisture") + # fig.autofmt_xdate() diff --git a/nevergrad/functions/irrigation/test_irrigation.py b/nevergrad/functions/irrigation/test_irrigation.py new file mode 100644 index 0000000000..00543842f6 --- /dev/null +++ b/nevergrad/functions/irrigation/test_irrigation.py @@ -0,0 +1,19 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +from . import irrigation + + +def test_irrigation() -> None: + func = irrigation.Irrigation(2) + x = np.random.rand(func.dimension) + value = func(x) + value2 = func(x) + x = np.random.rand(func.dimension) + value3 = func(x) + assert value <= 0.0 # type: ignore + assert value3 != value # this should not be flat. + np.testing.assert_almost_equal(value, value2) diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py index be9fc49370..67dc3fa4cc 100644 --- a/nevergrad/functions/pcse/__init__.py +++ b/nevergrad/functions/pcse/__init__.py @@ -5,4 +5,4 @@ # Based on https://github.com/ajwdewit/pcse_notebooks # MIT License. -from .pcse import Pcse as Pcse +from .pcse import CropSimulator as CropSimulator diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index 4b5f6455cd..9964ee755b 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -8,7 +8,7 @@ def test_pcse() -> None: - func = pcse.Pcse() + func = pcse.CropSimulator() x = 0 * np.random.rand(func.dimension) value = func(x) value2 = func(x) diff --git a/requirements/bench.txt b/requirements/bench.txt index 5fec6d8390..26b6a592d6 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -42,3 +42,4 @@ box2d-py>=2.3.5 glfw mujoco pcse +pygame From fc25af56e5697a0966a668c8bc30da95ba4e835a Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 21:20:23 +0100 Subject: [PATCH 027/140] Update bench.txt --- requirements/bench.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/requirements/bench.txt b/requirements/bench.txt index 26b6a592d6..5b1b2ff1a7 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -41,5 +41,7 @@ pybullet>=3.2.2 box2d-py>=2.3.5 glfw mujoco -pcse -pygame +#pcse +#pygame +pcse>=5.5.0 +pygame>=2.0.2 From 2a429b061837bf0b824e3ea885aae8734cee390b Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 21:23:32 +0100 Subject: [PATCH 028/140] Update irrigation.py --- nevergrad/functions/irrigation/irrigation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 5a373a9e78..67662a750f 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -13,6 +13,7 @@ from pathlib import Path import urllib.request import numpy as np +import warning import nevergrad as ng from ..base import ArrayExperimentFunction @@ -65,6 +66,7 @@ def leaf_area_index(x: np.ndarray): crop = YAMLCropDataProvider() if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") + warnings.warn("Check that you have no problem with the EUPL license.") urllib.request.urlretrieve( "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", str(data_dir) + "/soil/ec3.soil", From 7ad6abf95022aa630df09194a91a451ec414f684 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Wed, 2 Mar 2022 21:30:40 +0100 Subject: [PATCH 029/140] fix --- .../functions/irrigation/data/meteo/nl1.xlsx | Bin 208384 -> 0 bytes nevergrad/functions/irrigation/irrigation.py | 7 ++++++- 2 files changed, 6 insertions(+), 1 deletion(-) delete mode 100644 nevergrad/functions/irrigation/data/meteo/nl1.xlsx diff --git a/nevergrad/functions/irrigation/data/meteo/nl1.xlsx b/nevergrad/functions/irrigation/data/meteo/nl1.xlsx deleted file mode 100644 index 93c6bfe2d2eab5b848cdb143b88b92bdcbdb556a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208384 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%0AAK(jnzN*&}6F9L>siHM6{WBJQE@EDu)M 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 Date: Mon, 7 Mar 2022 09:55:54 +0100 Subject: [PATCH 030/140] Update irrigation.py --- nevergrad/functions/irrigation/irrigation.py | 21 ++++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 94c185d2b9..cd643a0204 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -13,7 +13,6 @@ from pathlib import Path import urllib.request import numpy as np -import warnings import nevergrad as ng from ..base import ArrayExperimentFunction @@ -66,11 +65,11 @@ def leaf_area_index(x: np.ndarray): crop = YAMLCropDataProvider() if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - warnings.warn("Check that you have no problem with the EUPL license.") - urllib.request.urlretrieve( - "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", - str(data_dir) + "/soil/ec3.soil", - ) + raise Error("Check that you have no problem with the EUPL license before uncommenting the lines below.") + # urllib.request.urlretrieve( + # "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", + # str(data_dir) + "/soil/ec3.soil", + # ) soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) site = WOFOST72SiteDataProvider(WAV=100, CO2=360) parameterprovider = ParameterProvider(soildata=soil, cropdata=crop, sitedata=site) @@ -79,11 +78,11 @@ def leaf_area_index(x: np.ndarray): from pcse.fileinput import ExcelWeatherDataProvider - warnings.warn("Check that you have no problem with the EUPL license.") - urllib.request.urlretrieve( - "https://pcse.readthedocs.io/en/stable/_downloads/78c1c853e9911098db9e3d8e6f362550/nl1.xlsx", - str(data_dir) + "/meteo/nl1.xlsx", - ) + raise Error("Check that you have no problem with the EUPL license before uncommenting the lines below.") + # urllib.request.urlretrieve( + # "https://pcse.readthedocs.io/en/stable/_downloads/78c1c853e9911098db9e3d8e6f362550/nl1.xlsx", + # str(data_dir) + "/meteo/nl1.xlsx", + # ) weatherfile = os.path.join(data_dir, "meteo", "nl1.xlsx") weatherdataprovider = ExcelWeatherDataProvider(weatherfile) From 8173a664a57e14dcb0ae474d9aeeca8e935ba433 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:00:32 +0100 Subject: [PATCH 031/140] pcse_license --- nevergrad/functions/irrigation/irrigation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index cd643a0204..a1d6de9e4a 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -47,7 +47,10 @@ def leaf_area_index(x: np.ndarray): import pandas as pd import yaml - import pcse + try: + import pcse + except: + raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_WLP_FD from pcse.fileinput import CABOFileReader, YAMLCropDataProvider From d08d67e4c624605204578e22ab8fd5a0a87531c7 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:18:46 +0100 Subject: [PATCH 032/140] fix_details --- nevergrad/functions/irrigation/irrigation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index a1d6de9e4a..278a578177 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -11,7 +11,7 @@ from pathlib import Path -import urllib.request +#import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. import numpy as np import nevergrad as ng from ..base import ArrayExperimentFunction @@ -68,7 +68,7 @@ def leaf_area_index(x: np.ndarray): crop = YAMLCropDataProvider() if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - raise Error("Check that you have no problem with the EUPL license before uncommenting the lines below.") + raise Exception("Check that you have no problem with the EUPL license before uncommenting the lines below.") # urllib.request.urlretrieve( # "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", # str(data_dir) + "/soil/ec3.soil", @@ -81,7 +81,7 @@ def leaf_area_index(x: np.ndarray): from pcse.fileinput import ExcelWeatherDataProvider - raise Error("Check that you have no problem with the EUPL license before uncommenting the lines below.") + raise Exception("Check that you have no problem with the EUPL license before uncommenting the lines below.") # urllib.request.urlretrieve( # "https://pcse.readthedocs.io/en/stable/_downloads/78c1c853e9911098db9e3d8e6f362550/nl1.xlsx", # str(data_dir) + "/meteo/nl1.xlsx", From 795e757ea3d9eed318e4b44f2c28dd15912638b1 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:37:26 +0100 Subject: [PATCH 033/140] fix --- nevergrad/functions/irrigation/irrigation.py | 11 ++++++++--- requirements/bench.txt | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 278a578177..2e59235c57 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -11,7 +11,8 @@ from pathlib import Path -#import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. + +# import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. import numpy as np import nevergrad as ng from ..base import ArrayExperimentFunction @@ -68,7 +69,9 @@ def leaf_area_index(x: np.ndarray): crop = YAMLCropDataProvider() if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - raise Exception("Check that you have no problem with the EUPL license before uncommenting the lines below.") + raise Exception( + "Check that you have no problem with the EUPL license before uncommenting the lines below." + ) # urllib.request.urlretrieve( # "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", # str(data_dir) + "/soil/ec3.soil", @@ -81,7 +84,9 @@ def leaf_area_index(x: np.ndarray): from pcse.fileinput import ExcelWeatherDataProvider - raise Exception("Check that you have no problem with the EUPL license before uncommenting the lines below.") + raise Exception( + "Check that you have no problem with the EUPL license before uncommenting the lines below." + ) # urllib.request.urlretrieve( # "https://pcse.readthedocs.io/en/stable/_downloads/78c1c853e9911098db9e3d8e6f362550/nl1.xlsx", # str(data_dir) + "/meteo/nl1.xlsx", diff --git a/requirements/bench.txt b/requirements/bench.txt index 5b1b2ff1a7..1aeea77f41 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -45,3 +45,4 @@ mujoco #pygame pcse>=5.5.0 pygame>=2.0.2 +yaml>=5.3.1 From df05c654b582d7462e2bb1e745711d0b8489c5cc Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:40:31 +0100 Subject: [PATCH 034/140] dependencies --- requirements/bench.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/bench.txt b/requirements/bench.txt index 1aeea77f41..2b4bd48ed6 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -45,4 +45,4 @@ mujoco #pygame pcse>=5.5.0 pygame>=2.0.2 -yaml>=5.3.1 +yaml From a465ede52f30bae4d95550d10b770f8ecb2ead5a Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:43:27 +0100 Subject: [PATCH 035/140] dependencies --- requirements/bench.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/bench.txt b/requirements/bench.txt index 2b4bd48ed6..72cc18eeda 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -45,4 +45,4 @@ mujoco #pygame pcse>=5.5.0 pygame>=2.0.2 -yaml +pyyaml>=5.3.1 From 17d989d40beef7dd42d778fee19e8ba9e0e6a0d2 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:58:29 +0100 Subject: [PATCH 036/140] dependencies --- nevergrad/functions/pcse/pcse.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 3184570ad8..43bd654798 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -20,6 +20,10 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: + try: + import pcse + except: + raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider From a49175eab863000734109d88eb7b3e9ff9d3f1c0 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 11:02:36 +0100 Subject: [PATCH 037/140] dependencies --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 43bd654798..5fedc071be 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,7 +21,7 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - import pcse + import pcse # type: ignore except: raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_PP From 96638e7a40531a6c65ba64bdb61549b98c281402 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 11:42:20 +0100 Subject: [PATCH 038/140] dependencies --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 5fedc071be..cb43372c33 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,7 +21,7 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - import pcse # type: ignore + import pcse # pylint: disable=unused-import except: raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_PP From bfbf80daece1df724f6adfd138fd964ade01cb8e Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 12:03:14 +0100 Subject: [PATCH 039/140] dependencies --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index cb43372c33..cbf070005a 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -23,7 +23,7 @@ def __init__(self) -> None: try: import pcse # pylint: disable=unused-import except: - raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") + raise ng.errors.UnsupportedExperiment("You need to install PCSE. Check that the EUPL license is ok for you.") from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider From ce584b3086883c5d261eee5e94a231af45af012c Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 13:16:14 +0100 Subject: [PATCH 040/140] pcse --- nevergrad/functions/pcse/pcse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index cbf070005a..93ca2ddf4f 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -23,7 +23,9 @@ def __init__(self) -> None: try: import pcse # pylint: disable=unused-import except: - raise ng.errors.UnsupportedExperiment("You need to install PCSE. Check that the EUPL license is ok for you.") + raise ng.errors.UnsupportedExperiment( + "You need to install PCSE. Check that the EUPL license is ok for you." + ) from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider From d7e5b8f82863a3275b8139a53da76f7e5f26fa73 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Tue, 8 Mar 2022 10:50:20 +0100 Subject: [PATCH 041/140] Update irrigation.py --- nevergrad/functions/irrigation/irrigation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 2e59235c57..4cd92b8904 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -73,7 +73,7 @@ def leaf_area_index(x: np.ndarray): "Check that you have no problem with the EUPL license before uncommenting the lines below." ) # urllib.request.urlretrieve( - # "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", + # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", # str(data_dir) + "/soil/ec3.soil", # ) soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) @@ -88,7 +88,7 @@ def leaf_area_index(x: np.ndarray): "Check that you have no problem with the EUPL license before uncommenting the lines below." ) # urllib.request.urlretrieve( - # "https://pcse.readthedocs.io/en/stable/_downloads/78c1c853e9911098db9e3d8e6f362550/nl1.xlsx", + # "https://github.com/ajwdewit/pcse_notebooks/blob/master/data/meteo/nl1.xlsx?raw=true", # str(data_dir) + "/meteo/nl1.xlsx", # ) weatherfile = os.path.join(data_dir, "meteo", "nl1.xlsx") From e6cab5bb56deb1b853074ced9542021e02a6e6aa Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Tue, 8 Mar 2022 11:04:47 +0100 Subject: [PATCH 042/140] add_folders --- nevergrad/functions/irrigation/data/meteo/README | 1 + nevergrad/functions/irrigation/data/soil/README | 1 + 2 files changed, 2 insertions(+) create mode 100644 nevergrad/functions/irrigation/data/meteo/README create mode 100644 nevergrad/functions/irrigation/data/soil/README diff --git a/nevergrad/functions/irrigation/data/meteo/README b/nevergrad/functions/irrigation/data/meteo/README new file mode 100644 index 0000000000..2c38a244f7 --- /dev/null +++ b/nevergrad/functions/irrigation/data/meteo/README @@ -0,0 +1 @@ +Folder for storing weather data. diff --git a/nevergrad/functions/irrigation/data/soil/README b/nevergrad/functions/irrigation/data/soil/README new file mode 100644 index 0000000000..d6ccba09b6 --- /dev/null +++ b/nevergrad/functions/irrigation/data/soil/README @@ -0,0 +1 @@ +Folder for storing soil data. From 9ab938bbc60086489205206c6c562d734ffafdd9 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Tue, 8 Mar 2022 11:07:32 +0100 Subject: [PATCH 043/140] Update irrigation.py --- nevergrad/functions/irrigation/irrigation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 4cd92b8904..7ae45ea32e 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -49,6 +49,9 @@ def leaf_area_index(x: np.ndarray): import yaml try: + raise Exception( + "We do not import EUPL-licensed packages by default. Check if EUPL is ok for you." + ) import pcse except: raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") From 1d041388bb340775687f537eb48a3c2ee7c31c4a Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 10 Mar 2022 11:15:25 +0100 Subject: [PATCH 044/140] black --- nevergrad/functions/irrigation/irrigation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 7ae45ea32e..4c66fc24ba 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -49,9 +49,7 @@ def leaf_area_index(x: np.ndarray): import yaml try: - raise Exception( - "We do not import EUPL-licensed packages by default. Check if EUPL is ok for you." - ) + raise Exception("We do not import EUPL-licensed packages by default. Check if EUPL is ok for you.") import pcse except: raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") From af74874779fa987c4d336f93b784e0b6b7a82d58 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 10 Mar 2022 12:03:39 +0100 Subject: [PATCH 045/140] fix --- nevergrad/common/test_testing.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nevergrad/common/test_testing.py b/nevergrad/common/test_testing.py index c09abe0c0e..806c768966 100644 --- a/nevergrad/common/test_testing.py +++ b/nevergrad/common/test_testing.py @@ -79,9 +79,7 @@ def test_header() -> None: missing.append(filepath) if missing: missing_str = "\n - ".join(missing) - raise AssertionError( - f"Following files are missing standard header (see other files):\n - {missing_str}" - ) + raise AssertionError(f"Following files are missing standard header ({header}):\n - {missing_str}") @pytest.mark.skipif(sys.platform == "win32", reason="not compatible test") # type: ignore From 5b85c616a51dbd96dafc2f329b8c550ec69e74f0 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 10 Mar 2022 12:05:19 +0100 Subject: [PATCH 046/140] fix --- nevergrad/functions/irrigation/__init__.py | 2 +- nevergrad/functions/irrigation/irrigation.py | 2 +- nevergrad/functions/irrigation/test_irrigation.py | 2 +- nevergrad/functions/pcse/__init__.py | 2 +- nevergrad/functions/pcse/pcse.py | 2 +- nevergrad/functions/pcse/test_pcse.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nevergrad/functions/irrigation/__init__.py b/nevergrad/functions/irrigation/__init__.py index 02d12312a2..536f23c518 100644 --- a/nevergrad/functions/irrigation/__init__.py +++ b/nevergrad/functions/irrigation/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 4c66fc24ba..6c8f358c62 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -1,4 +1,4 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/irrigation/test_irrigation.py b/nevergrad/functions/irrigation/test_irrigation.py index 00543842f6..2dbacaa732 100644 --- a/nevergrad/functions/irrigation/test_irrigation.py +++ b/nevergrad/functions/irrigation/test_irrigation.py @@ -1,4 +1,4 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py index 67dc3fa4cc..3a478500ec 100644 --- a/nevergrad/functions/pcse/__init__.py +++ b/nevergrad/functions/pcse/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 93ca2ddf4f..3f51a1cd6e 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -1,4 +1,4 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index 9964ee755b..f64a21f651 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -1,4 +1,4 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. From d02b6f1073e3f62cdbe2010bbbc22c17fbc58e17 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 10 Mar 2022 12:50:25 +0100 Subject: [PATCH 047/140] fix --- requirements/bench.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/requirements/bench.txt b/requirements/bench.txt index 72cc18eeda..6419033f67 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -41,8 +41,6 @@ pybullet>=3.2.2 box2d-py>=2.3.5 glfw mujoco -#pcse -#pygame pcse>=5.5.0 pygame>=2.0.2 pyyaml>=5.3.1 From 08ff7c5d879a2cb4916e343c81bf3ede344779ae Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 10 Mar 2022 13:13:55 +0100 Subject: [PATCH 048/140] fix --- nevergrad/functions/irrigation/__init__.py | 2 +- nevergrad/functions/irrigation/irrigation.py | 2 +- nevergrad/functions/irrigation/test_irrigation.py | 2 +- nevergrad/functions/pcse/__init__.py | 2 +- nevergrad/functions/pcse/pcse.py | 2 +- nevergrad/functions/pcse/test_pcse.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nevergrad/functions/irrigation/__init__.py b/nevergrad/functions/irrigation/__init__.py index 536f23c518..e415020b83 100644 --- a/nevergrad/functions/irrigation/__init__.py +++ b/nevergrad/functions/irrigation/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 6c8f358c62..a7da07db4b 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -1,4 +1,4 @@ -# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/irrigation/test_irrigation.py b/nevergrad/functions/irrigation/test_irrigation.py index 2dbacaa732..4fdf40ad9b 100644 --- a/nevergrad/functions/irrigation/test_irrigation.py +++ b/nevergrad/functions/irrigation/test_irrigation.py @@ -1,4 +1,4 @@ -# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py index 3a478500ec..2f131cc36c 100644 --- a/nevergrad/functions/pcse/__init__.py +++ b/nevergrad/functions/pcse/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 3f51a1cd6e..fa585ea333 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -1,4 +1,4 @@ -# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index f64a21f651..72cb2d6346 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -1,4 +1,4 @@ -# Copyright (c) Meta, Inc. and its affiliates. All Rights Reserved. +# Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. From 7d12481b14fadb3570cec1eb9359c296e0bcc080 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Thu, 10 Mar 2022 21:38:24 +0100 Subject: [PATCH 049/140] Update irrigation.py --- nevergrad/functions/irrigation/irrigation.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index a7da07db4b..64d38eb37f 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -52,13 +52,13 @@ def leaf_area_index(x: np.ndarray): raise Exception("We do not import EUPL-licensed packages by default. Check if EUPL is ok for you.") import pcse except: - raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") - from pcse.models import Wofost72_WLP_FD - from pcse.fileinput import CABOFileReader, YAMLCropDataProvider - - # from pcse.db import NASAPowerWeatherDataProvider - from pcse.util import WOFOST72SiteDataProvider - from pcse.base import ParameterProvider + raise ng.errors.UnsupportedExperiment("You need to install PCSE. We remove all imports in case you do not want EUPL code.") + # from pcse.models import Wofost72_WLP_FD + # from pcse.fileinput import CABOFileReader, YAMLCropDataProvider + # + # # from pcse.db import NASAPowerWeatherDataProvider + # from pcse.util import WOFOST72SiteDataProvider + # from pcse.base import ParameterProvider # data_dir = os.path.join(os.getcwd(), "data") data_dir = Path(__file__).with_name("data") From d77375c6c1c65ec8e3a05693ddf1d2fbd14dee73 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Thu, 10 Mar 2022 21:40:39 +0100 Subject: [PATCH 050/140] Update pcse.py --- nevergrad/functions/pcse/pcse.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index fa585ea333..122c11bba0 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,18 +21,19 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - import pcse # pylint: disable=unused-import + raise Exception("We do not import EUPL code by default.") + # import pcse # pylint: disable=unused-import except: raise ng.errors.UnsupportedExperiment( "You need to install PCSE. Check that the EUPL license is ok for you." ) - from pcse.models import Wofost72_PP - from pcse.base import ParameterProvider - from pcse.db import NASAPowerWeatherDataProvider + # from pcse.models import Wofost72_PP + # from pcse.base import ParameterProvider + # from pcse.db import NASAPowerWeatherDataProvider - # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider - from pcse.fileinput import YAMLCropDataProvider - from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider + # # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + # from pcse.fileinput import YAMLCropDataProvider + # from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider # Weather data for Netherlands wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) From 85b6b65c13105c68d8d2631816620d9b67fa46eb Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Fri, 11 Mar 2022 07:00:37 +0100 Subject: [PATCH 051/140] pcse --- nevergrad/functions/irrigation/irrigation.py | 16 +++++++++------- nevergrad/functions/pcse/pcse.py | 12 ++++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 64d38eb37f..40b8110b91 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -52,13 +52,15 @@ def leaf_area_index(x: np.ndarray): raise Exception("We do not import EUPL-licensed packages by default. Check if EUPL is ok for you.") import pcse except: - raise ng.errors.UnsupportedExperiment("You need to install PCSE. We remove all imports in case you do not want EUPL code.") - # from pcse.models import Wofost72_WLP_FD - # from pcse.fileinput import CABOFileReader, YAMLCropDataProvider - # - # # from pcse.db import NASAPowerWeatherDataProvider - # from pcse.util import WOFOST72SiteDataProvider - # from pcse.base import ParameterProvider + raise ng.errors.UnsupportedExperiment( + "You need to install PCSE. We remove all imports in case you do not want EUPL code." + ) + from pcse.models import Wofost72_WLP_FD + from pcse.fileinput import CABOFileReader, YAMLCropDataProvider + + # from pcse.db import NASAPowerWeatherDataProvider + from pcse.util import WOFOST72SiteDataProvider + from pcse.base import ParameterProvider # data_dir = os.path.join(os.getcwd(), "data") data_dir = Path(__file__).with_name("data") diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 122c11bba0..d6f77dfa61 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -27,13 +27,13 @@ def __init__(self) -> None: raise ng.errors.UnsupportedExperiment( "You need to install PCSE. Check that the EUPL license is ok for you." ) - # from pcse.models import Wofost72_PP - # from pcse.base import ParameterProvider - # from pcse.db import NASAPowerWeatherDataProvider + from pcse.models import Wofost72_PP + from pcse.base import ParameterProvider + from pcse.db import NASAPowerWeatherDataProvider - # # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider - # from pcse.fileinput import YAMLCropDataProvider - # from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider + # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + from pcse.fileinput import YAMLCropDataProvider + from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider # Weather data for Netherlands wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) From 588db629f7d452a73f56b61c9c7fb25eb22b3a86 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 2 Apr 2022 22:06:24 +0200 Subject: [PATCH 052/140] fix --- nevergrad/functions/irrigation/irrigation.py | 235 ++++++++++--------- 1 file changed, 119 insertions(+), 116 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 40b8110b91..187467ba55 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -11,129 +11,132 @@ from pathlib import Path - -# import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. +import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. import numpy as np import nevergrad as ng from ..base import ArrayExperimentFunction +import os +import pandas as pd +import yaml +from pcse.fileinput import CABOFileReader, YAMLCropDataProvider +from pcse.models import Wofost72_WLP_FD +from pcse.db import NASAPowerWeatherDataProvider +from pcse.util import WOFOST72SiteDataProvider +from pcse.base import ParameterProvider + # pylint: disable=too-many-locals,too-many-statements class Irrigation(ArrayExperimentFunction): def __init__(self, symmetry: int) -> None: - import nevergrad as ng - + data_dir = Path(__file__).with_name("data") + #urllib.request.urlretrieve( + # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", + # str(data_dir) + "/soil/ec3.soil", + #) + self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") - super().__init__(leaf_area_index, parametrization=param, symmetry=symmetry) - - -import numpy as np - - -def leaf_area_index(x: np.ndarray): - d0 = int(1.01 + 29.98 * x[0]) - d1 = int(1.01 + 30.98 * x[1]) - d2 = int(1.01 + 30.98 * x[2]) - d3 = int(1.01 + 29.98 * x[3]) - a0 = 15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) - a1 = 15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) - a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) - a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) - import os, sys - - # import matplotlib - # matplotlib.style.use("ggplot") - # import matplotlib.pyplot as plt - import pandas as pd - import yaml - - try: - raise Exception("We do not import EUPL-licensed packages by default. Check if EUPL is ok for you.") - import pcse - except: - raise ng.errors.UnsupportedExperiment( - "You need to install PCSE. We remove all imports in case you do not want EUPL code." - ) - from pcse.models import Wofost72_WLP_FD - from pcse.fileinput import CABOFileReader, YAMLCropDataProvider - - # from pcse.db import NASAPowerWeatherDataProvider - from pcse.util import WOFOST72SiteDataProvider - from pcse.base import ParameterProvider - - # data_dir = os.path.join(os.getcwd(), "data") - data_dir = Path(__file__).with_name("data") - - print("This notebook was built with:") - print("python version: %s " % sys.version) - print("PCSE version: %s" % pcse.__version__) - - crop = YAMLCropDataProvider() - if os.environ.get("CIRCLECI", False): - raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - raise Exception( - "Check that you have no problem with the EUPL license before uncommenting the lines below." - ) - # urllib.request.urlretrieve( - # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", - # str(data_dir) + "/soil/ec3.soil", - # ) - soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) - site = WOFOST72SiteDataProvider(WAV=100, CO2=360) - parameterprovider = ParameterProvider(soildata=soil, cropdata=crop, sitedata=site) - - crop = YAMLCropDataProvider() - - from pcse.fileinput import ExcelWeatherDataProvider - - raise Exception( - "Check that you have no problem with the EUPL license before uncommenting the lines below." - ) - # urllib.request.urlretrieve( - # "https://github.com/ajwdewit/pcse_notebooks/blob/master/data/meteo/nl1.xlsx?raw=true", - # str(data_dir) + "/meteo/nl1.xlsx", - # ) - weatherfile = os.path.join(data_dir, "meteo", "nl1.xlsx") - weatherdataprovider = ExcelWeatherDataProvider(weatherfile) - - yaml_agro = f""" - - 2006-01-01: - CropCalendar: - crop_name: sugarbeet - variety_name: Sugarbeet_603 - crop_start_date: 2006-03-31 - crop_start_type: emergence - crop_end_date: 2006-10-20 - crop_end_type: harvest - max_duration: 300 - TimedEvents: - - event_signal: irrigate - name: Irrigation application table - comment: All irrigation amounts in cm - events_table: - - 2006-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}} - - 2006-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}} - - 2006-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}} - - 2006-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} - StateEvents: null - """ - try: - agromanagement = yaml.safe_load(yaml_agro) - wofost = Wofost72_WLP_FD(parameterprovider, weatherdataprovider, agromanagement) - wofost.run_till_terminate() - except Exception as e: - assert False, f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" - raise e - - output = wofost.get_output() - df = pd.DataFrame(output).set_index("day") - df.tail() - - # print(output) - # print(len(output)) - return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) - # fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16,8)) - # df['LAI'].plot(ax=axes[0], title="Leaf Area Index") - # df['SM'].plot(ax=axes[1], title="Root zone soil moisture") - # fig.autofmt_xdate() + super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) + known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': + 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, + 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361} + known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, + 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': + 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336} + for k in range(1000): + self.address = np.random.RandomState(symmetry+3*k).choice( + [ + "Saint-Leger-Bridereix", + "Dun-Le-Palestel", + "Kolkata", + "Antananarivo", + "Santiago", + "Lome", + "Cairo", + "Ouagadougou", + "Yamoussoukro", + "Yaounde", + "Kiev", + ] + ) + if self.address in known_latitudes and self.address in known_longitudes: + self.weatherdataprovider = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) + else: + assert False + from geopy.geocoders import Nominatim + geolocator = Nominatim(user_agent="NG/PCSE") + self.location = geolocator.geocode(self.address) + self.weatherdataprovider = NASAPowerWeatherDataProvider( + latitude=self.location.latitude, longitude=self.location.longitude + ) + + cropd = YAMLCropDataProvider() + crop_types = [c for c in cropd.crop_types if "obacco" not in c] + self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) + self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(cropd.get_crops_varieties()[self.cropname]) + ) + # We check if the problem is challenging. + print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") + crop = YAMLCropDataProvider() + if os.environ.get("CIRCLECI", False): + raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") + site = WOFOST72SiteDataProvider(WAV=100, CO2=360) + self.parameterprovider = ParameterProvider(soildata=self.soil, cropdata=crop, sitedata=site) + self.crop = YAMLCropDataProvider() + v = [self.leaf_area_index(np.random.rand(8)) for _ in range(5)] + if min(v) != max(v): + break + print(f"we work on {self.cropname} with variety {self.cropvariety} in {self.address}.") + + def leaf_area_index(self, x: np.ndarray): + d0 = int(1.01 + 29.98 * x[0]) + d1 = int(1.01 + 30.98 * x[1]) + d2 = int(1.01 + 30.98 * x[2]) + d3 = int(1.01 + 29.98 * x[3]) + a0 = 15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) + a1 = 15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) + a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) + a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) + + + + + + yaml_agro = f""" + - 2006-01-01: + CropCalendar: + crop_name: {self.cropname} + variety_name: {self.cropvariety} + crop_start_date: 2006-03-31 + crop_start_type: emergence + crop_end_date: 2006-10-20 + crop_end_type: harvest + max_duration: 300 + TimedEvents: + - event_signal: irrigate + name: Irrigation application table + comment: All irrigation amounts in cm + events_table: + - 2006-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}} + - 2006-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}} + - 2006-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}} + - 2006-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} + StateEvents: null + """ + try: + agromanagement = yaml.safe_load(yaml_agro) + wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) + wofost.run_till_terminate() + except Exception as e: + return float("inf") + #assert ( + # False + #), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + #raise e + + output = wofost.get_output() + df = pd.DataFrame(output).set_index("day") + df.tail() + + return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) From 091f5c05e90a109d700ce664e71cc76d354f253f Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 2 Apr 2022 22:17:43 +0200 Subject: [PATCH 053/140] fix --- nevergrad/functions/irrigation/irrigation.py | 34 +++++++++----------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 187467ba55..fedad1cf9f 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -38,12 +38,15 @@ def __init__(self, symmetry: int) -> None: self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) + if os.environ.get("CIRCLECI", False): + raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361} known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336} + self.cropd = YAMLCropDataProvider() for k in range(1000): self.address = np.random.RandomState(symmetry+3*k).choice( [ @@ -70,25 +73,24 @@ def __init__(self, symmetry: int) -> None: self.weatherdataprovider = NASAPowerWeatherDataProvider( latitude=self.location.latitude, longitude=self.location.longitude ) - - cropd = YAMLCropDataProvider() - crop_types = [c for c in cropd.crop_types if "obacco" not in c] - self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) - self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(cropd.get_crops_varieties()[self.cropname]) - ) - # We check if the problem is challenging. - print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") - crop = YAMLCropDataProvider() - if os.environ.get("CIRCLECI", False): - raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - site = WOFOST72SiteDataProvider(WAV=100, CO2=360) - self.parameterprovider = ParameterProvider(soildata=self.soil, cropdata=crop, sitedata=site) - self.crop = YAMLCropDataProvider() + self.set_data(symmetry, k) v = [self.leaf_area_index(np.random.rand(8)) for _ in range(5)] if min(v) != max(v): break print(f"we work on {self.cropname} with variety {self.cropvariety} in {self.address}.") + + def set_data(self, symmetry: int, k: int): + crop_types = [c for c in self.cropd.crop_types if "obacco" not in c] + self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) + self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) + ) + # We check if the problem is challenging. + print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") + site = WOFOST72SiteDataProvider(WAV=100, CO2=360) + self.parameterprovider = ParameterProvider(soildata=self.soil, cropdata=self.cropd, sitedata=site) + + def leaf_area_index(self, x: np.ndarray): d0 = int(1.01 + 29.98 * x[0]) d1 = int(1.01 + 30.98 * x[1]) @@ -99,10 +101,6 @@ def leaf_area_index(self, x: np.ndarray): a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) - - - - yaml_agro = f""" - 2006-01-01: CropCalendar: From a417eeba336d3b6eda807645619a3222e2046dd0 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 2 Apr 2022 22:18:32 +0200 Subject: [PATCH 054/140] fix --- nevergrad/functions/irrigation/irrigation.py | 58 ++++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index fedad1cf9f..40220ce54e 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -31,24 +31,44 @@ class Irrigation(ArrayExperimentFunction): def __init__(self, symmetry: int) -> None: data_dir = Path(__file__).with_name("data") - #urllib.request.urlretrieve( + # urllib.request.urlretrieve( # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", # str(data_dir) + "/soil/ec3.soil", - #) + # ) self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': - 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, - 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361} - known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, - 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': - 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336} + known_longitudes = { + "Saint-Leger-Bridereix": 1.5887348, + "Dun-Le-Palestel": 1.6641173, + "Kolkata": 88.35769124388872, + "Antananarivo": 47.5255809, + "Santiago": -70.6504502, + "Lome": 1.215829, + "Cairo": 31.2357257, + "Ouagadougou": -1.5270944, + "Yamoussoukro": -5.273263, + "Yaounde": 11.5213344, + "Kiev": 30.5241361, + } + known_latitudes = { + "Saint-Leger-Bridereix": 46.2861759, + "Dun-Le-Palestel": 46.3052049, + "Kolkata": 22.5414185, + "Antananarivo": -18.9100122, + "Santiago": -33.4377756, + "Lome": 6.130419, + "Cairo": 30.0443879, + "Ouagadougou": 12.3681873, + "Yamoussoukro": 6.809107, + "Yaounde": 3.8689867, + "Kiev": 50.4500336, + } self.cropd = YAMLCropDataProvider() for k in range(1000): - self.address = np.random.RandomState(symmetry+3*k).choice( + self.address = np.random.RandomState(symmetry + 3 * k).choice( [ "Saint-Leger-Bridereix", "Dun-Le-Palestel", @@ -64,10 +84,13 @@ def __init__(self, symmetry: int) -> None: ] ) if self.address in known_latitudes and self.address in known_longitudes: - self.weatherdataprovider = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) - else: + self.weatherdataprovider = NASAPowerWeatherDataProvider( + latitude=known_latitudes[self.address], longitude=known_longitudes[self.address] + ) + else: assert False from geopy.geocoders import Nominatim + geolocator = Nominatim(user_agent="NG/PCSE") self.location = geolocator.geocode(self.address) self.weatherdataprovider = NASAPowerWeatherDataProvider( @@ -79,18 +102,17 @@ def __init__(self, symmetry: int) -> None: break print(f"we work on {self.cropname} with variety {self.cropvariety} in {self.address}.") - def set_data(self, symmetry: int, k: int): crop_types = [c for c in self.cropd.crop_types if "obacco" not in c] - self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) - self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) + self.cropname = np.random.RandomState(symmetry + 3 * k + 1).choice(crop_types) + self.cropvariety = np.random.RandomState(symmetry + 3 * k + 2).choice( + list(self.cropd.get_crops_varieties()[self.cropname]) ) # We check if the problem is challenging. print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") site = WOFOST72SiteDataProvider(WAV=100, CO2=360) self.parameterprovider = ParameterProvider(soildata=self.soil, cropdata=self.cropd, sitedata=site) - def leaf_area_index(self, x: np.ndarray): d0 = int(1.01 + 29.98 * x[0]) d1 = int(1.01 + 30.98 * x[1]) @@ -128,10 +150,10 @@ def leaf_area_index(self, x: np.ndarray): wofost.run_till_terminate() except Exception as e: return float("inf") - #assert ( + # assert ( # False - #), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" - #raise e + # ), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + # raise e output = wofost.get_output() df = pd.DataFrame(output).set_index("day") From fd56e88cd5f159e27b4c7c7e8432acb87361f483 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sun, 3 Apr 2022 07:06:08 +0200 Subject: [PATCH 055/140] fix --- nevergrad/functions/irrigation/irrigation.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 40220ce54e..16ae6c37fe 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -29,6 +29,8 @@ class Irrigation(ArrayExperimentFunction): + variant_choice = {} + def __init__(self, symmetry: int) -> None: data_dir = Path(__file__).with_name("data") # urllib.request.urlretrieve( @@ -68,6 +70,8 @@ def __init__(self, symmetry: int) -> None: } self.cropd = YAMLCropDataProvider() for k in range(1000): + if symmetry in self.variant_choice and k < self.variant_choice[symmetry]: + continue self.address = np.random.RandomState(symmetry + 3 * k).choice( [ "Saint-Leger-Bridereix", @@ -100,6 +104,7 @@ def __init__(self, symmetry: int) -> None: v = [self.leaf_area_index(np.random.rand(8)) for _ in range(5)] if min(v) != max(v): break + self.variant_choice[symmetry] = k print(f"we work on {self.cropname} with variety {self.cropvariety} in {self.address}.") def set_data(self, symmetry: int, k: int): From 42dc439ae3bf2acadcad3b2031e5b9ff3e202862 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sun, 3 Apr 2022 07:09:27 +0200 Subject: [PATCH 056/140] fix --- nevergrad/functions/irrigation/irrigation.py | 61 ++++++-------------- 1 file changed, 19 insertions(+), 42 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 16ae6c37fe..66f55273d9 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -30,49 +30,28 @@ class Irrigation(ArrayExperimentFunction): variant_choice = {} - def __init__(self, symmetry: int) -> None: data_dir = Path(__file__).with_name("data") - # urllib.request.urlretrieve( + #urllib.request.urlretrieve( # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", # str(data_dir) + "/soil/ec3.soil", - # ) + #) self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - known_longitudes = { - "Saint-Leger-Bridereix": 1.5887348, - "Dun-Le-Palestel": 1.6641173, - "Kolkata": 88.35769124388872, - "Antananarivo": 47.5255809, - "Santiago": -70.6504502, - "Lome": 1.215829, - "Cairo": 31.2357257, - "Ouagadougou": -1.5270944, - "Yamoussoukro": -5.273263, - "Yaounde": 11.5213344, - "Kiev": 30.5241361, - } - known_latitudes = { - "Saint-Leger-Bridereix": 46.2861759, - "Dun-Le-Palestel": 46.3052049, - "Kolkata": 22.5414185, - "Antananarivo": -18.9100122, - "Santiago": -33.4377756, - "Lome": 6.130419, - "Cairo": 30.0443879, - "Ouagadougou": 12.3681873, - "Yamoussoukro": 6.809107, - "Yaounde": 3.8689867, - "Kiev": 50.4500336, - } + known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': + 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, + 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361} + known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, + 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': + 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336} self.cropd = YAMLCropDataProvider() for k in range(1000): if symmetry in self.variant_choice and k < self.variant_choice[symmetry]: continue - self.address = np.random.RandomState(symmetry + 3 * k).choice( + self.address = np.random.RandomState(symmetry+3*k).choice( [ "Saint-Leger-Bridereix", "Dun-Le-Palestel", @@ -88,13 +67,10 @@ def __init__(self, symmetry: int) -> None: ] ) if self.address in known_latitudes and self.address in known_longitudes: - self.weatherdataprovider = NASAPowerWeatherDataProvider( - latitude=known_latitudes[self.address], longitude=known_longitudes[self.address] - ) - else: + self.weatherdataprovider = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) + else: assert False from geopy.geocoders import Nominatim - geolocator = Nominatim(user_agent="NG/PCSE") self.location = geolocator.geocode(self.address) self.weatherdataprovider = NASAPowerWeatherDataProvider( @@ -107,17 +83,18 @@ def __init__(self, symmetry: int) -> None: self.variant_choice[symmetry] = k print(f"we work on {self.cropname} with variety {self.cropvariety} in {self.address}.") + def set_data(self, symmetry: int, k: int): crop_types = [c for c in self.cropd.crop_types if "obacco" not in c] - self.cropname = np.random.RandomState(symmetry + 3 * k + 1).choice(crop_types) - self.cropvariety = np.random.RandomState(symmetry + 3 * k + 2).choice( - list(self.cropd.get_crops_varieties()[self.cropname]) + self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) + self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) ) # We check if the problem is challenging. - print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") + #print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") site = WOFOST72SiteDataProvider(WAV=100, CO2=360) self.parameterprovider = ParameterProvider(soildata=self.soil, cropdata=self.cropd, sitedata=site) + def leaf_area_index(self, x: np.ndarray): d0 = int(1.01 + 29.98 * x[0]) d1 = int(1.01 + 30.98 * x[1]) @@ -155,10 +132,10 @@ def leaf_area_index(self, x: np.ndarray): wofost.run_till_terminate() except Exception as e: return float("inf") - # assert ( + #assert ( # False - # ), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" - # raise e + #), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + #raise e output = wofost.get_output() df = pd.DataFrame(output).set_index("day") From 2051ccd8acb54e3b00092dcbd0fd4cab3898f1aa Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 18 Jun 2022 16:37:39 +0200 Subject: [PATCH 057/140] fix --- mypy.ini | 5 +++++ nevergrad/functions/gym/test_multigym.py | 15 --------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/mypy.ini b/mypy.ini index bb69b3953e..8be5a05eaa 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3,9 +3,14 @@ [mypy-scipy.*,requests,pandas,compiler_gym,compiler_gym.*,gym_anm,matplotlib.*,pytest,cma,bayes_opt.*,torchvision.models,torch.*,mpl_toolkits.*,fcmaes.*,tqdm,pillow,PIL,PIL.Image,sklearn.*,pyomo.*,pyproj,IOHexperimenter.*,tensorflow,koncept.models,cv2,imquality,imquality.brisque,lpips,mixsimulator.*,networkx.*,cdt.*,pymoo,pymoo.*,bayes_optim.*,olympus.*,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,aquacrop.*] ignore_missing_imports = True +<<<<<<< HEAD #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] [mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] +======= +[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] +>>>>>>> 22234dac (fix) ignore_missing_imports = True ignore_errors = True diff --git a/nevergrad/functions/gym/test_multigym.py b/nevergrad/functions/gym/test_multigym.py index fd56aaac50..00e53079bc 100644 --- a/nevergrad/functions/gym/test_multigym.py +++ b/nevergrad/functions/gym/test_multigym.py @@ -54,14 +54,9 @@ def test_sparse_cartpole() -> None: assert min(results) != max(results), "CartPole should not be deterministic." -<<<<<<< HEAD @pytest.mark.parametrize("name", ["LunarLander-v2"]) # type: ignore def test_run_multigym(name: str) -> None: if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: -======= -def test_default_run_multigym() -> None: - if os.name == "nt": ->>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341)) raise SkipTest("Skipping Windows and running only 1 out of 8") if "ANM" in name: raise SkipTest("We skip ANM6Easy and related problems.") @@ -69,17 +64,7 @@ def test_default_run_multigym() -> None: func = multigym.GymMulti(randomized=False, neural_factor=None) x = np.zeros(func.dimension) value = func(x) -<<<<<<< HEAD np.testing.assert_almost_equal(value, 178.2, decimal=2) -======= - np.testing.assert_almost_equal(value, 178.20, decimal=2) - - -@pytest.mark.parametrize("name", GYM_ENV_NAMES) # type: ignore -def test_run_multigym(name: str) -> None: - if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: - raise SkipTest("Skipping Windows and running only 1 out of 8") ->>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341)) i = GYM_ENV_NAMES.index(name) control = multigym.CONTROLLERS[i % len(multigym.CONTROLLERS)] print(f"Working with {control} on {name}.") From 91daaf2696aaddadddb3c97644ef6e595e43a5cd Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:51:39 +0100 Subject: [PATCH 058/140] pcse --- nevergrad/functions/pcse/pcse.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index d6f77dfa61..a5c89f851d 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -139,7 +139,6 @@ def __call__(self, par_values, grad=None): # defaults = [cropd["TDWI"], cropd["SPAN"]] # error = objfunc_calculator(defaults) # print("Objective function value with default parameters (%s): %s" % (defaults, error)) - TDWI_range = [0.1, 0.6] SPAN_range = [30, 40] param = ng.p.Array( From 8ce1114344329b969f3440e351e7b0a45c08f5fb Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:06:01 +0100 Subject: [PATCH 059/140] ZZfix --- nevergrad/functions/pcse/pcse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index a5c89f851d..ba9ee34d79 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,8 +21,8 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - raise Exception("We do not import EUPL code by default.") - # import pcse # pylint: disable=unused-import + #raise Exception("We do not import EUPL code by default.") + import pcse # pylint: disable=unused-import except: raise ng.errors.UnsupportedExperiment( "You need to install PCSE. Check that the EUPL license is ok for you." From bd0e147656306041010feab9b2e65c3ee1a2f673 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:47:51 +0100 Subject: [PATCH 060/140] nlopt --- mypy.ini | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mypy.ini b/mypy.ini index 8be5a05eaa..56feda6254 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3,14 +3,13 @@ [mypy-scipy.*,requests,pandas,compiler_gym,compiler_gym.*,gym_anm,matplotlib.*,pytest,cma,bayes_opt.*,torchvision.models,torch.*,mpl_toolkits.*,fcmaes.*,tqdm,pillow,PIL,PIL.Image,sklearn.*,pyomo.*,pyproj,IOHexperimenter.*,tensorflow,koncept.models,cv2,imquality,imquality.brisque,lpips,mixsimulator.*,networkx.*,cdt.*,pymoo,pymoo.*,bayes_optim.*,olympus.*,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,aquacrop.*] ignore_missing_imports = True -<<<<<<< HEAD +[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] -[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] -======= -[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] ->>>>>>> 22234dac (fix) +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] ignore_missing_imports = True ignore_errors = True From 81b33693617acaccb3e43111a01c664093e8bf45 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:56:08 +0100 Subject: [PATCH 061/140] ZZnlopt --- mypy.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mypy.ini b/mypy.ini index 56feda6254..6c130962e1 100644 --- a/mypy.ini +++ b/mypy.ini @@ -9,7 +9,9 @@ ignore_missing_imports = True #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] ignore_missing_imports = True ignore_errors = True From efdcdcb32f57b9316c7094f690ff3235df6d5ca6 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 20:08:49 +0100 Subject: [PATCH 062/140] ZZPcse2: irrigation challenge (#1341) * irrigation_challenge * flute * fix * Update __init__.py * Update experiments.py * fix * fix * fix * fix * fix * fix * fix * fix * fix_gym * fix_gym * fix_gym * fix * fix --- .../functions/irrigation/data/meteo/nl1.xlsx | Bin 0 -> 208384 bytes nevergrad/functions/irrigation/irrigation.py | 110 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 nevergrad/functions/irrigation/data/meteo/nl1.xlsx diff --git a/nevergrad/functions/irrigation/data/meteo/nl1.xlsx b/nevergrad/functions/irrigation/data/meteo/nl1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..93c6bfe2d2eab5b848cdb143b88b92bdcbdb556a GIT binary patch literal 208384 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%0AAK(jnzN*&}6F9L>siHM6{WBJQE@EDu)M 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 c3c99b9c (ZZPcse2: irrigation challenge (#1341)) # pylint: disable=too-many-locals,too-many-statements class Irrigation(ArrayExperimentFunction): +<<<<<<< HEAD variant_choice = {} def __init__(self, symmetry: int) -> None: data_dir = Path(__file__).with_name("data") @@ -142,3 +150,105 @@ def leaf_area_index(self, x: np.ndarray): df.tail() return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) +======= + def __init__(self, symmetry: int) -> None: + import nevergrad as ng + + param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") + super().__init__(leaf_area_index, parametrization=param, symmetry=symmetry) + + +import numpy as np + + +def leaf_area_index(x: np.ndarray): + d0 = int(1.01 + 29.98 * x[0]) + d1 = int(1.01 + 30.98 * x[1]) + d2 = int(1.01 + 30.98 * x[2]) + d3 = int(1.01 + 29.98 * x[3]) + a0 = 15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) + a1 = 15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) + a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) + a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) + import os, sys + + # import matplotlib + # matplotlib.style.use("ggplot") + # import matplotlib.pyplot as plt + import pandas as pd + import yaml + + import pcse + from pcse.models import Wofost72_WLP_FD + from pcse.fileinput import CABOFileReader, YAMLCropDataProvider + + # from pcse.db import NASAPowerWeatherDataProvider + from pcse.util import WOFOST72SiteDataProvider + from pcse.base import ParameterProvider + + # data_dir = os.path.join(os.getcwd(), "data") + data_dir = Path(__file__).with_name("data") + + print("This notebook was built with:") + print("python version: %s " % sys.version) + print("PCSE version: %s" % pcse.__version__) + + crop = YAMLCropDataProvider() + if os.environ.get("CIRCLECI", False): + raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") + urllib.request.urlretrieve( + "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", + str(data_dir) + "/soil/ec3.soil", + ) + soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) + site = WOFOST72SiteDataProvider(WAV=100, CO2=360) + parameterprovider = ParameterProvider(soildata=soil, cropdata=crop, sitedata=site) + + crop = YAMLCropDataProvider() + + from pcse.fileinput import ExcelWeatherDataProvider + + weatherfile = os.path.join(data_dir, "meteo", "nl1.xlsx") + weatherdataprovider = ExcelWeatherDataProvider(weatherfile) + + yaml_agro = f""" + - 2006-01-01: + CropCalendar: + crop_name: sugarbeet + variety_name: Sugarbeet_603 + crop_start_date: 2006-03-31 + crop_start_type: emergence + crop_end_date: 2006-10-20 + crop_end_type: harvest + max_duration: 300 + TimedEvents: + - event_signal: irrigate + name: Irrigation application table + comment: All irrigation amounts in cm + events_table: + - 2006-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}} + - 2006-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}} + - 2006-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}} + - 2006-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} + StateEvents: null + """ + try: + agromanagement = yaml.safe_load(yaml_agro) + wofost = Wofost72_WLP_FD(parameterprovider, weatherdataprovider, agromanagement) + wofost.run_till_terminate() + except Exception as e: + assert False, f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + raise e + + output = wofost.get_output() + df = pd.DataFrame(output).set_index("day") + df.tail() + + # print(output) + # print(len(output)) + return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) + # fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16,8)) + # df['LAI'].plot(ax=axes[0], title="Leaf Area Index") + # df['SM'].plot(ax=axes[1], title="Root zone soil moisture") + # fig.autofmt_xdate() +>>>>>>> c3c99b9c (ZZPcse2: irrigation challenge (#1341)) From 4c1224eb5da34dc582942e42799dff3ac356c506 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 21:20:23 +0100 Subject: [PATCH 063/140] ZZUpdate bench.txt --- requirements/bench.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/bench.txt b/requirements/bench.txt index 6419033f67..4543f08b63 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -36,11 +36,11 @@ Keras-Preprocessing silence_tensorflow # for olymp tensorflow_probability # for olymp bayes-optim==0.2.5.5 +pygame>=2.0.2 +pyyaml>=5.3.1 nlopt pybullet>=3.2.2 box2d-py>=2.3.5 glfw mujoco pcse>=5.5.0 -pygame>=2.0.2 -pyyaml>=5.3.1 From dcabfa159cb8f3a38b83d60da96d52584d1b0c45 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:00:32 +0100 Subject: [PATCH 064/140] pcse_license --- nevergrad/functions/irrigation/irrigation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 4e88b93551..d633edf1ca 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -178,7 +178,10 @@ def leaf_area_index(x: np.ndarray): import pandas as pd import yaml - import pcse + try: + import pcse + except: + raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_WLP_FD from pcse.fileinput import CABOFileReader, YAMLCropDataProvider From 1e40e47233c18c24a5e3d90dd17d89f81412a5fa Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:37:26 +0100 Subject: [PATCH 065/140] fix --- nevergrad/functions/irrigation/irrigation.py | 143 +++---------------- 1 file changed, 18 insertions(+), 125 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index d633edf1ca..92a177cfd8 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -11,7 +11,6 @@ from pathlib import Path -<<<<<<< HEAD import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. import numpy as np import nevergrad as ng @@ -25,36 +24,33 @@ from pcse.util import WOFOST72SiteDataProvider from pcse.base import ParameterProvider -======= -import urllib.request -import numpy as np -import nevergrad as ng -from ..base import ArrayExperimentFunction ->>>>>>> c3c99b9c (ZZPcse2: irrigation challenge (#1341)) # pylint: disable=too-many-locals,too-many-statements class Irrigation(ArrayExperimentFunction): -<<<<<<< HEAD variant_choice = {} def __init__(self, symmetry: int) -> None: data_dir = Path(__file__).with_name("data") - #urllib.request.urlretrieve( - # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", - # str(data_dir) + "/soil/ec3.soil", - #) - self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) + try: + self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) + except: + urllib.request.urlretrieve( + "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", + str(data_dir) + "/soil/ec3.soil", + ) + self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, - 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361} + 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361, 'Porto-Novo': + 2.6289} known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': - 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336} + 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336, 'Porto-Novo': 6.4969} self.cropd = YAMLCropDataProvider() for k in range(1000): if symmetry in self.variant_choice and k < self.variant_choice[symmetry]: @@ -71,6 +67,7 @@ def __init__(self, symmetry: int) -> None: "Ouagadougou", "Yamoussoukro", "Yaounde", + "Porto-Novo", "Kiev", ] ) @@ -93,7 +90,8 @@ def __init__(self, symmetry: int) -> None: def set_data(self, symmetry: int, k: int): - crop_types = [c for c in self.cropd.crop_types if "obacco" not in c] + crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] + crop_types = [c for c in crop_types if "obacco" not in c] self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) ) @@ -108,10 +106,10 @@ def leaf_area_index(self, x: np.ndarray): d1 = int(1.01 + 30.98 * x[1]) d2 = int(1.01 + 30.98 * x[2]) d3 = int(1.01 + 29.98 * x[3]) - a0 = 15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) - a1 = 15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) - a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) - a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) + a0 = x[4] #15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) + a1 = x[5] #15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) + a2 = x[6] #15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) + a3 = x[7] #15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) yaml_agro = f""" - 2006-01-01: @@ -150,108 +148,3 @@ def leaf_area_index(self, x: np.ndarray): df.tail() return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) -======= - def __init__(self, symmetry: int) -> None: - import nevergrad as ng - - param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") - super().__init__(leaf_area_index, parametrization=param, symmetry=symmetry) - - -import numpy as np - - -def leaf_area_index(x: np.ndarray): - d0 = int(1.01 + 29.98 * x[0]) - d1 = int(1.01 + 30.98 * x[1]) - d2 = int(1.01 + 30.98 * x[2]) - d3 = int(1.01 + 29.98 * x[3]) - a0 = 15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) - a1 = 15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) - a2 = 15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) - a3 = 15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) - import os, sys - - # import matplotlib - # matplotlib.style.use("ggplot") - # import matplotlib.pyplot as plt - import pandas as pd - import yaml - - try: - import pcse - except: - raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") - from pcse.models import Wofost72_WLP_FD - from pcse.fileinput import CABOFileReader, YAMLCropDataProvider - - # from pcse.db import NASAPowerWeatherDataProvider - from pcse.util import WOFOST72SiteDataProvider - from pcse.base import ParameterProvider - - # data_dir = os.path.join(os.getcwd(), "data") - data_dir = Path(__file__).with_name("data") - - print("This notebook was built with:") - print("python version: %s " % sys.version) - print("PCSE version: %s" % pcse.__version__) - - crop = YAMLCropDataProvider() - if os.environ.get("CIRCLECI", False): - raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") - urllib.request.urlretrieve( - "https://raw.githubusercontent.com/ajwdewit/ggcmi/master/pcse/doc/ec3.soil", - str(data_dir) + "/soil/ec3.soil", - ) - soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) - site = WOFOST72SiteDataProvider(WAV=100, CO2=360) - parameterprovider = ParameterProvider(soildata=soil, cropdata=crop, sitedata=site) - - crop = YAMLCropDataProvider() - - from pcse.fileinput import ExcelWeatherDataProvider - - weatherfile = os.path.join(data_dir, "meteo", "nl1.xlsx") - weatherdataprovider = ExcelWeatherDataProvider(weatherfile) - - yaml_agro = f""" - - 2006-01-01: - CropCalendar: - crop_name: sugarbeet - variety_name: Sugarbeet_603 - crop_start_date: 2006-03-31 - crop_start_type: emergence - crop_end_date: 2006-10-20 - crop_end_type: harvest - max_duration: 300 - TimedEvents: - - event_signal: irrigate - name: Irrigation application table - comment: All irrigation amounts in cm - events_table: - - 2006-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}} - - 2006-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}} - - 2006-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}} - - 2006-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} - StateEvents: null - """ - try: - agromanagement = yaml.safe_load(yaml_agro) - wofost = Wofost72_WLP_FD(parameterprovider, weatherdataprovider, agromanagement) - wofost.run_till_terminate() - except Exception as e: - assert False, f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" - raise e - - output = wofost.get_output() - df = pd.DataFrame(output).set_index("day") - df.tail() - - # print(output) - # print(len(output)) - return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) - # fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16,8)) - # df['LAI'].plot(ax=axes[0], title="Leaf Area Index") - # df['SM'].plot(ax=axes[1], title="Root zone soil moisture") - # fig.autofmt_xdate() ->>>>>>> c3c99b9c (ZZPcse2: irrigation challenge (#1341)) From 96e0475ed265bd9a6b8ed11b62a94526a88449bb Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 8 Aug 2022 14:18:04 +0200 Subject: [PATCH 066/140] fix --- nevergrad/benchmark/experiments.py | 7 ++++--- nevergrad/functions/irrigation/irrigation.py | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 3666aa9da5..46034e1d0d 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1281,11 +1281,12 @@ def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Irrigation simulator. Maximize leaf area index, so that you get a lot of primary production. Sequential or 30 workers.""" - funcs = [Irrigation(i) for i in range(17)] + funcs = [Irrigation(i) for i in range(179)] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) - for budget in [25, 50, 100, 200]: - for num_workers in [1, 30, 60]: + optims = ["DiagonalCMA"] + for budget in [25]: #, 50, 100, 200]: + for num_workers in [1]: #, 30, 60]: if num_workers < budget: for algo in optims: for fu in funcs: diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 92a177cfd8..3e7053bbd7 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -59,6 +59,7 @@ def __init__(self, symmetry: int) -> None: [ "Saint-Leger-Bridereix", "Dun-Le-Palestel", + "Porto-Novo", "Kolkata", "Antananarivo", "Santiago", @@ -92,6 +93,7 @@ def __init__(self, symmetry: int) -> None: def set_data(self, symmetry: int, k: int): crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] crop_types = [c for c in crop_types if "obacco" not in c] + #crop_types = ["rice"] self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) ) From f95eaa418ea2946e56ac4430f7b5a617703d7415 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 8 Aug 2022 14:48:29 +0200 Subject: [PATCH 067/140] pcse --- nevergrad/benchmark/experiments.py | 4 ++-- nevergrad/functions/irrigation/irrigation.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 46034e1d0d..23689f8ed9 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1304,9 +1304,9 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """ funcs = [CropSimulator()] seedg = create_seed_generator(seed) - optims = get_optimizers("basics", seed=next(seedg)) + optims = ["DE", "PSO", "CMA", "NGOpt"] for budget in [25, 50, 100, 200]: - for num_workers in [1, 10, 40]: + for num_workers in [1]: if num_workers < budget: for algo in optims: for fu in funcs: diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 3e7053bbd7..8e38c9b582 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -93,7 +93,6 @@ def __init__(self, symmetry: int) -> None: def set_data(self, symmetry: int, k: int): crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] crop_types = [c for c in crop_types if "obacco" not in c] - #crop_types = ["rice"] self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) ) From e4aeb3545ef529621fa3c191b6981567be4d9ea6 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Tue, 9 Aug 2022 20:31:40 +0200 Subject: [PATCH 068/140] benin --- nevergrad/benchmark/experiments.py | 26 +++++++++--- nevergrad/functions/irrigation/irrigation.py | 42 +++++++++++++++----- nevergrad/optimization/optimizerlib.py | 9 +++++ 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 23689f8ed9..314b2444dc 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1275,17 +1275,17 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe if not xp.is_incoherent: yield xp - @registry.register -def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: +def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False) -> tp.Iterator[Experiment]: """Irrigation simulator. Maximize leaf area index, so that you get a lot of primary production. Sequential or 30 workers.""" - funcs = [Irrigation(i) for i in range(179)] + funcs = [Irrigation(i, benin=benin, variety_choice=variety_choice) for i in range(23)] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) - optims = ["DiagonalCMA"] - for budget in [25]: #, 50, 100, 200]: + optims = ["DiagonalCMA", "CMA", "DE", "PSO", "TwoPointsDE", "DiscreteLenglerOnePlusOne"] + optims += ["NGOptRW", "NGTuned"] + for budget in [250]: #, 50, 100, 200]: for num_workers in [1]: #, 30, 60]: if num_workers < budget: for algo in optims: @@ -1296,6 +1296,22 @@ def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: yield xp +@registry.register +def variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, variety_choice=True) + + +@registry.register +def benin_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, benin=True) + + +@registry.register +def benin_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, benin=True, variety_choice=True) + + +@registry.register def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 8e38c9b582..67f1b25170 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -28,9 +28,12 @@ # pylint: disable=too-many-locals,too-many-statements +WPD = {} + + class Irrigation(ArrayExperimentFunction): variant_choice = {} - def __init__(self, symmetry: int) -> None: + def __init__(self, symmetry:int, benin: bool, variety_choice: bool) -> None: data_dir = Path(__file__).with_name("data") try: self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) @@ -40,7 +43,7 @@ def __init__(self, symmetry: int) -> None: str(data_dir) + "/soil/ec3.soil", ) self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) - param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") + param = ng.p.Array(shape=(9 if variety_choice else 8,), lower=(0.0), upper=(0.99999999)).set_name("irrigation8") super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") @@ -70,18 +73,33 @@ def __init__(self, symmetry: int) -> None: "Yaounde", "Porto-Novo", "Kiev", + ] if not benin else [ + "Porto-Novo", + "Cotonou", + "Lokossa", + "Allada", + "Abomey", + "Pobe", + "Aplahoue", + "Dassa-Zoume", + "Parakou", + "Djougou", + "Kandi", + "Natitingou", ] ) - if self.address in known_latitudes and self.address in known_longitudes: - self.weatherdataprovider = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) + #if self.address in known_latitudes and self.address in known_longitudes: + # self.weatherdataprovider = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) + if self.address in WPD: + self.weatherdataprovider = WPD[self.address] else: - assert False from geopy.geocoders import Nominatim geolocator = Nominatim(user_agent="NG/PCSE") self.location = geolocator.geocode(self.address) self.weatherdataprovider = NASAPowerWeatherDataProvider( latitude=self.location.latitude, longitude=self.location.longitude ) + WPD[self.address] = self.weatherdataprovider self.set_data(symmetry, k) v = [self.leaf_area_index(np.random.rand(8)) for _ in range(5)] if min(v) != max(v): @@ -94,6 +112,7 @@ def set_data(self, symmetry: int, k: int): crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] crop_types = [c for c in crop_types if "obacco" not in c] self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) + self.total_irrigation = np.random.RandomState(symmetry+3*k+3).choice([15.0, 1.50, 0.15, 150.]) self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) ) # We check if the problem is challenging. @@ -107,10 +126,15 @@ def leaf_area_index(self, x: np.ndarray): d1 = int(1.01 + 30.98 * x[1]) d2 = int(1.01 + 30.98 * x[2]) d3 = int(1.01 + 29.98 * x[3]) - a0 = x[4] #15.0 * x[4] / (x[4] + x[5] + x[6] + x[7]) - a1 = x[5] #15.0 * x[5] / (x[4] + x[5] + x[6] + x[7]) - a2 = x[6] #15.0 * x[6] / (x[4] + x[5] + x[6] + x[7]) - a3 = x[7] #15.0 * x[7] / (x[4] + x[5] + x[6] + x[7]) + c = self.total_irrigation + a0 = c * x[4] / (x[4] + x[5] + x[6] + x[7]) + a1 = c * x[5] / (x[4] + x[5] + x[6] + x[7]) + a2 = c * x[6] / (x[4] + x[5] + x[6] + x[7]) + a3 = c * x[7] / (x[4] + x[5] + x[6] + x[7]) + if len(x) > 8: + assert len(x) == 9, f"my x has size {len(x)}, it is {x}" + varieties = list(self.cropd.get_crops_varieties()[self.cropname]) + self.cropvariety = varieties[int(x[8] * len(varieties))] yaml_agro = f""" - 2006-01-01: diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 9f982b84f8..c0423c5f2b 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -3109,6 +3109,15 @@ class NGOpt(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass +@registry.register +class NGTuned(NGOpt39): + # Learning something automatically so that it's less unreadable would be great. + pass + +NGOptRW = ConfPortfolio( + optimizers=[GeneticDE, PSO, NGOpt], warmup_ratio=0.33 + ).set_name("NGOptRW", register=True) + class _MSR(Portfolio): """This code applies multiple copies of NGOpt with random weights for the different objective functions. From f1ec8dc97abf775b1220f6166346a05ffa8c3c35 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 11 Aug 2022 09:40:08 +0200 Subject: [PATCH 069/140] fix --- nevergrad/benchmark/experiments.py | 13 +++++++--- nevergrad/functions/irrigation/irrigation.py | 27 +++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 314b2444dc..3078facf2b 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1276,16 +1276,18 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe yield xp @registry.register -def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False) -> tp.Iterator[Experiment]: +def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False, rice: bool = False) -> tp.Iterator[Experiment]: """Irrigation simulator. Maximize leaf area index, so that you get a lot of primary production. Sequential or 30 workers.""" - funcs = [Irrigation(i, benin=benin, variety_choice=variety_choice) for i in range(23)] + funcs = [Irrigation(i, benin=benin, variety_choice=variety_choice, rice=rice) for i in range(23)] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) optims = ["DiagonalCMA", "CMA", "DE", "PSO", "TwoPointsDE", "DiscreteLenglerOnePlusOne"] optims += ["NGOptRW", "NGTuned"] - for budget in [250]: #, 50, 100, 200]: + if rice: + optims = optims[-2:] + for budget in [2500]: #, 50, 100, 200]: for num_workers in [1]: #, 30, 60]: if num_workers < budget: for algo in optims: @@ -1311,6 +1313,11 @@ def benin_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterato return irrigation(seed, benin=True, variety_choice=True) +@registry.register +def benin_rice_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, benin=True, variety_choice=True, rice=True) + + @registry.register def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 67f1b25170..e370c29ab3 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -29,11 +29,14 @@ WPD = {} +CURRENT_BEST = {} +CURRENT_BEST_ARGUMENT = {} class Irrigation(ArrayExperimentFunction): variant_choice = {} - def __init__(self, symmetry:int, benin: bool, variety_choice: bool) -> None: + def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool) -> None: + self.rice = rice data_dir = Path(__file__).with_name("data") try: self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) @@ -100,19 +103,21 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool) -> None: latitude=self.location.latitude, longitude=self.location.longitude ) WPD[self.address] = self.weatherdataprovider - self.set_data(symmetry, k) - v = [self.leaf_area_index(np.random.rand(8)) for _ in range(5)] + self.set_data(symmetry, k, rice) + v = [self.leaf_area_index(np.random.rand(9 if variety_choice else 8)) for _ in range(5)] if min(v) != max(v): break self.variant_choice[symmetry] = k print(f"we work on {self.cropname} with variety {self.cropvariety} in {self.address}.") - def set_data(self, symmetry: int, k: int): + def set_data(self, symmetry: int, k: int, rice: bool): crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] crop_types = [c for c in crop_types if "obacco" not in c] + if rice: + crop_types = ["rice"] self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) - self.total_irrigation = np.random.RandomState(symmetry+3*k+3).choice([15.0, 1.50, 0.15, 150.]) + self.total_irrigation = np.random.RandomState(symmetry+3*k+3).choice([15.0, 1.50, 0.15, 150.]) if not rice else 0.15 self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) ) # We check if the problem is challenging. @@ -172,4 +177,14 @@ def leaf_area_index(self, x: np.ndarray): df = pd.DataFrame(output).set_index("day") df.tail() - return -sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) + lai = sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) + specifier = self.address + "_" + str(self.cropname) + "_" + str(self.total_irrigation) + if not self.rice: + specifier += "_" + self.cropvariety + if specifier not in CURRENT_BEST: + CURRENT_BEST[specifier] = 0. + if lai > CURRENT_BEST[specifier]: + CURRENT_BEST[specifier] = lai + CURRENT_BEST_ARGUMENT[specifier] = self.cropvariety if self.rice else str(x) + print(f"for <{specifier}> we recommend {CURRENT_BEST_ARGUMENT[specifier]} and get {lai}") + return - lai From bba579598a1e50d376d4f1c919da3743234f9035 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Tue, 6 Dec 2022 15:30:44 +0100 Subject: [PATCH 070/140] Optimizing simultaneously variety, irrigation and crop (#1467) * fix * Adding costs in dollars per kg for various crops, and weird operations by Lev distance (#1468) * fix * Support for choosing the year(s) in PCSE stuff (#1469) * fix * o * fix --- nevergrad/benchmark/experiments.py | 232 ++++++++++++++++++- nevergrad/functions/irrigation/irrigation.py | 206 +++++++++++++--- 2 files changed, 408 insertions(+), 30 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 3078facf2b..6bb2b81444 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -48,6 +48,184 @@ # pylint: disable=stop-iteration-return, too-many-nested-blocks, too-many-locals +centroids = {} +centroids["Fiji"] = (163.85316464458234, -17.31630942638265) +centroids["Tanzania"] = (34.75298985475595, -6.257732428506092) +centroids["Western Sahara"] = (-12.13783111160779, 24.291172960208623) +centroids["Canada"] = (-98.14238137209708, 61.46907614534896) +centroids["United States"] = (-112.5994359115045, 45.70562800215178) +centroids["Kazakhstan"] = (67.2846109811001, 48.19166075218232) +centroids["Uzbekistan"] = (63.20363952823182, 41.748602664652246) +centroids["Papua New Guinea"] = (145.31757462782247, -6.451644514630347) +centroids["Indonesia"] = (117.42340756227364, -2.221737936520542) +centroids["Argentina"] = (-65.17536077114173, -35.4468214894951) +centroids["Chile"] = (-71.5206439451643, -39.04701430994844) +centroids["Democratic Republic of the Congo"] = (23.582955831479083, -2.8502757110956667) +centroids["Somalia"] = (45.72670076723565, 4.752347756504953) +centroids["Kenya"] = (37.791555286661385, 0.5959662521769523) +centroids["Sudan"] = (29.862604012257922, 15.990585003116717) +centroids["Chad"] = (18.581329525332894, 15.328867399839682) +centroids["Haiti"] = (-72.65801330535574, 18.900700691843337) +centroids["Dominican Republic"] = (-70.46235845697531, 18.884487087982258) +centroids["Russian Federation"] = (96.80331818290134, 61.961663494923) +centroids["Bahamas"] = (-77.92997080393516, 25.515491725336624) +centroids["Falkland Islands / Malvinas"] = (-59.42097279311021, -51.71322176551185) +centroids["Norway"] = (15.468119955206761, 69.15685630975351) +centroids["Greenland"] = (-41.50018111492097, 74.77048769398986) +centroids["French Southern and Antarctic Lands"] = (69.5315804704237, -49.306454911671985) +centroids["Timor-Leste"] = (125.96630027368401, -8.767760362467003) +centroids["South Africa"] = (25.048013879861678, -28.947033259979115) +centroids["Lesotho"] = (28.170105295170494, -29.625290493692013) +centroids["Mexico"] = (-102.5763495239869, 23.935371902244835) +centroids["Uruguay"] = (-56.003278666548475, -32.780904365230825) +centroids["Brazil"] = (-53.05434003576711, -10.806773643498916) +centroids["Bolivia"] = (-64.64140560603113, -16.72898701530584) +centroids["Peru"] = (-74.39180581684722, -9.191562905134553) +centroids["Colombia"] = (-73.07773208697478, 3.927213862709704) +centroids["Panama"] = (-80.10916483549376, 8.530019388864652) +centroids["Costa Rica"] = (-84.17542309600948, 9.965671127464528) +centroids["Nicaragua"] = (-85.02031850080252, 12.848190428036988) +centroids["Honduras"] = (-86.58996383801542, 14.822947081652929) +centroids["El Salvador"] = (-88.87290317032377, 13.726091625794197) +centroids["Guatemala"] = (-90.36945836053154, 15.699360612026911) +centroids["Belize"] = (-88.70342125299318, 17.197089911451545) +centroids["Venezuela"] = (-66.16382727830238, 7.162132267639002) +centroids["Guyana"] = (-58.97120310856251, 4.790225375174759) +centroids["Suriname"] = (-55.91145629952073, 4.1200080317588865) +centroids["France"] = (-2.8766966992706267, 42.46070432663372) +centroids["Ecuador"] = (-78.38416674608374, -1.4547717055405804) +centroids["Puerto Rico"] = (-66.47922227695507, 18.2372245709719) +centroids["Jamaica"] = (-77.32425480164892, 18.137636127868436) +centroids["Cuba"] = (-78.96068490970256, 21.631751541025228) +centroids["Zimbabwe"] = (29.788548371892524, -18.906987947858802) +centroids["Botswana"] = (23.773081465789428, -22.099711378826413) +centroids["Namibia"] = (17.156168126194093, -22.099776931731068) +centroids["Senegal"] = (-14.50980278585943, 14.354139988452022) +centroids["Mali"] = (-3.543294339453343, 17.267772061700715) +centroids["Mauritania"] = (-10.326396925234992, 20.20926720635376) +centroids["Benin"] = (2.337377553496156, 9.647430780663699) +centroids["Niger"] = (9.324427099857923, 17.345552814745542) +centroids["Nigeria"] = (7.995127754089786, 9.548318418209965) +centroids["Cameroon"] = (12.611551546501774, 5.663095287992696) +centroids["Togo"] = (0.9964039436703582, 8.439541954669616) +centroids["Ghana"] = (-1.2369685557063992, 7.928651813099648) +centroids["Côte d'Ivoire"] = (-5.6120436452252225, 7.5537550070104915) +centroids["Guinea"] = (-11.060853741185456, 10.44827287727134) +centroids["Guinea-Bissau"] = (-15.110623751667879, 12.022704382325685) +centroids["Liberia"] = (-9.410836154371117, 6.431619862252993) +centroids["Sierra Leone"] = (-11.795257428559948, 8.53035372615305) +centroids["Burkina Faso"] = (-1.77653745205594, 12.311650494136712) +centroids["Central African Republic"] = (20.374347291243915, 6.5427787059213145) +centroids["Republic of the Congo"] = (15.13446176741353, -0.8378010872252886) +centroids["Gabon"] = (11.687751174902044, -0.6470481398040288) +centroids["Equatorial Guinea"] = (10.366031325064027, 1.6458643199600753) +centroids["Zambia"] = (27.727591918760577, -13.395067553524187) +centroids["Malawi"] = (34.193605326922366, -13.172834992341919) +centroids["Mozambique"] = (35.47261597864435, -17.230448975659677) +centroids["Kingdom of eSwatini"] = (31.39525590206532, -26.48985528852001) +centroids["Angola"] = (17.47057255231345, -12.245869036133188) +centroids["Burundi"] = (29.91389229542573, -3.3773910753554657) +centroids["Israel"] = (35.003851206429005, 31.4849193900197) +centroids["Lebanon"] = (35.87098632001643, 33.91182720781994) +centroids["Madagascar"] = (46.69117091471639, -19.356114077828778) +centroids["Palestine"] = (35.27331962289024, 31.94113662241515) +centroids["The Gambia"] = (-15.431872807730837, 13.47533435870166) +centroids["Tunisia"] = (9.534716120695835, 34.172939036882376) +centroids["Algeria"] = (2.5980477916183444, 28.185481278657537) +centroids["Jordan"] = (36.77945490632519, 31.245490584748417) +centroids["United Arab Emirates"] = (54.20671476159633, 23.86863365334761) +centroids["Qatar"] = (51.1835025789133, 25.32185097420669) +centroids["Kuwait"] = (47.600098887626416, 29.307266634033564) +centroids["Iraq"] = (43.75691096461423, 33.03682096372491) +centroids["Oman"] = (56.09867281997542, 20.611174374229545) +centroids["Vanuatu"] = (167.07375126822674, -15.542677057554924) +centroids["Cambodia"] = (104.87608532525192, 12.684728629393506) +centroids["Thailand"] = (101.00613354626108, 15.01697499141648) +centroids["Lao PDR"] = (103.75025989504465, 18.444978089036088) +centroids["Myanmar"] = (96.50584094206161, 21.016999873773827) +centroids["Vietnam"] = (106.28584079705195, 16.657937753254938) +centroids["Dem. Rep. Korea"] = (127.16501590888976, 40.14302033650109) +centroids["Republic of Korea"] = (127.8213171283307, 36.42759860415487) +centroids["Mongolia"] = (102.94640620846634, 46.82368112626357) +centroids["India"] = (79.59370376325381, 22.92500640740852) +centroids["Bangladesh"] = (90.26792827719598, 23.83946179534406) +centroids["Bhutan"] = (90.4724248062037, 27.427968649102027) +centroids["Nepal"] = (84.01317367692529, 28.23944001904935) +centroids["Pakistan"] = (69.41399806318127, 29.973460025547393) +centroids["Afghanistan"] = (66.08669022192831, 33.85639928169076) +centroids["Tajikistan"] = (71.03443504896113, 38.58308146421082) +centroids["Kyrgyzstan"] = (74.62040481092558, 41.50689371318262) +centroids["Turkmenistan"] = (59.27543026236141, 39.09124018017583) +centroids["Iran"] = (54.285451496891426, 32.51891731762539) +centroids["Syria"] = (38.54423941961137, 35.012614281129) +centroids["Armenia"] = (45.00029001101479, 40.21660761230143) +centroids["Sweden"] = (16.59626584684802, 62.811484968080336) +centroids["Belarus"] = (27.98135261544803, 53.50634479481114) +centroids["Ukraine"] = (31.229122070266495, 49.14882260840351) +centroids["Poland"] = (19.31101430844868, 52.14826021933187) +centroids["Austria"] = (14.076158884337072, 47.6139487927463) +centroids["Hungary"] = (19.357628627745918, 47.19995117195427) +centroids["Moldova"] = (28.41048279080328, 47.20367642606752) +centroids["Romania"] = (24.943252494635377, 45.857101035738005) +centroids["Lithuania"] = (23.88064027584349, 55.284319484766066) +centroids["Latvia"] = (24.833296149803438, 56.80717513427924) +centroids["Estonia"] = (25.824725613026608, 58.643695426630906) +centroids["Germany"] = (10.288485092742851, 51.13372269040778) +centroids["Bulgaria"] = (25.19511095327711, 42.7531187620217) +centroids["Greece"] = (22.719813447095053, 39.066715899713955) +centroids["Turkey"] = (35.116900150938406, 39.06837194061471) +centroids["Albania"] = (20.03242643144321, 41.141353306048785) +centroids["Croatia"] = (16.566189771645533, 45.01623399593114) +centroids["Switzerland"] = (8.118300613385486, 46.79173768366762) +centroids["Luxembourg"] = (5.965223432343999, 49.76570507415103) +centroids["Belgium"] = (4.580834113854935, 50.65244095902296) +centroids["Netherlands"] = (5.512217100965399, 52.298700374441786) +centroids["Portugal"] = (-8.055765588295687, 39.63404977497817) +centroids["Spain"] = (-3.6170206023873743, 40.348656106226734) +centroids["Ireland"] = (-8.010236544877012, 53.18059120995006) +centroids["New Caledonia"] = (165.53447460087543, -21.26135761252651) +centroids["Solomon Islands"] = (159.9666154474296, -8.852497470848528) +centroids["New Zealand"] = (172.70192594405574, -41.662578757158684) +centroids["Australia"] = (134.50277547536595, -25.730654779726077) +centroids["Sri Lanka"] = (80.66723574931648, 7.700534417248105) +centroids["China"] = (103.88361230063249, 36.555066531858685) +centroids["Taiwan"] = (120.97480073748623, 23.740964979784938) +centroids["Italy"] = (12.140788372235871, 42.751183052964265) +centroids["Denmark"] = (9.876372937675002, 56.06393446179454) +centroids["United Kingdom"] = (-2.8531353951805545, 53.91477348053706) +centroids["Iceland"] = (-18.761028770831768, 65.07427633529105) +centroids["Azerbaijan"] = (47.553909558006055, 40.22069054766167) +centroids["Georgia"] = (43.48154265409026, 42.16201501415301) +centroids["Philippines"] = (122.90267236988682, 11.763799362297663) +centroids["Malaysia"] = (109.6981484486297, 3.7255884257737155) +centroids["Brunei Darussalam"] = (114.91510877393951, 4.690250542520635) +centroids["Slovenia"] = (14.938152320795732, 46.12542205901039) +centroids["Finland"] = (26.211764610296353, 64.50409403963651) +centroids["Slovakia"] = (19.507657147433708, 48.7267113517275) +centroids["Czech Republic"] = (15.334558102365815, 49.775245294369) +centroids["Eritrea"] = (38.67818692786484, 15.427276751412931) +centroids["Japan"] = (138.06496213270776, 37.66311081170466) +centroids["Paraguay"] = (-58.387387833505706, -23.248041946292087) +centroids["Yemen"] = (47.535044758543485, 15.913231950143004) +centroids["Saudi Arabia"] = (44.51636376826477, 24.123289839105293) +centroids["Antarctica"] = (20.571000569842635, -80.49198288284343) +centroids["Northern Cyprus"] = (33.5582859592249, 35.273957681259716) +centroids["Cyprus"] = (33.03955380295407, 34.90706085094344) +centroids["Morocco"] = (-8.420479544549693, 29.885394698302058) +centroids["Egypt"] = (29.844461513124415, 26.50661999974957) +centroids["Libya"] = (17.974352779160352, 26.997460407020338) +centroids["Ethiopia"] = (39.551255792937745, 8.653999188132575) +centroids["Djibouti"] = (42.4980197360445, 11.773044395533926) +centroids["Somaliland"] = (46.23074953490769, 9.757971805222988) +centroids["Uganda"] = (32.35755031998686, 1.2954855035097297) +centroids["Rwanda"] = (29.91896392224289, -2.0135144658341346) +centroids["Bosnia and Herzegovina"] = (17.816883270390086, 44.1807677629747) +centroids["North Macedonia"] = (21.697903375280845, 41.60592964714007) +centroids["Serbia"] = (20.819651926382583, 44.23303653365162) +centroids["Montenegro"] = (19.2861817215929, 42.78903960655908) +centroids["Kosovo"] = (20.895355721342227, 42.579367131816994) +centroids["Trinidad and Tobago"] = (-61.33036691444967, 10.428237089201879) +centroids["South Sudan"] = (30.198617582461907, 7.292890133516845) def skip_ci(*, reason: str) -> None: """Only use this if there is a good reason for not testing the xp, such as very slow for instance (>1min) with no way to make it faster. @@ -1276,18 +1454,33 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe yield xp @registry.register -def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False, rice: bool = False) -> tp.Iterator[Experiment]: +def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False, rice: bool = False, multi_crop: bool = False, kenya: bool = False, year_min:int=2006, year_max:int=2006) -> tp.Iterator[Experiment]: """Irrigation simulator. Maximize leaf area index, so that you get a lot of primary production. Sequential or 30 workers.""" - funcs = [Irrigation(i, benin=benin, variety_choice=variety_choice, rice=rice) for i in range(23)] + if kenya: + addresses = [] + #lat_center = float(os.environ.get("ng_latitude", "0.")) + #lon_center = float(os.environ.get("ng_longitude", "37.")) + country = os.environ.get("ng_country", "Kenya") + ng_latitude = centroids[country][1] + ng_longitude = centroids[country][0] + + + for lat in [ng_latitude-4.+8. * e/6. for e in range(7)]: #list(range(-4,5)): + for lon in [ng_longitude-3.+6. * e/6. for e in range(7)]: #list(range(34,40)): + addresses += [(lat, lon)] + funcs = [Irrigation(0, benin=benin, variety_choice=variety_choice, rice=rice, multi_crop=multi_crop, address=ad, year_min=year_min,year_max=year_max) for ad in addresses] + else: + funcs = [Irrigation(i, benin=benin, variety_choice=variety_choice, rice=rice, multi_crop=multi_crop, address=None,year_min=year_min, year_max=year_max) for i in range(67)] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) optims = ["DiagonalCMA", "CMA", "DE", "PSO", "TwoPointsDE", "DiscreteLenglerOnePlusOne"] optims += ["NGOptRW", "NGTuned"] + optims = ["NGOptRW"] if rice: optims = optims[-2:] - for budget in [2500]: #, 50, 100, 200]: + for budget in [int(os.environ.get("ng_budget", "250"))]: #, 50, 100, 200]: for num_workers in [1]: #, 30, 60]: if num_workers < budget: for algo in optims: @@ -1298,6 +1491,39 @@ def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choic yield xp +@registry.register +def crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, variety_choice=True, multi_crop=True) + + +@registry.register +def benin_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, benin=True, variety_choice=True, multi_crop=True) + + +@registry.register +def kenya_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True) + + +@registry.register +def kenya_2011_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2011) + + +@registry.register +def kenya_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2006, year_max=2011) + +@registry.register +def kenya_new_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2016, year_max=2021) + +@registry.register +def kenya_old_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=1996, year_max=2001) + + @registry.register def variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, variety_choice=True) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index e370c29ab3..cf7fc5a561 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -13,6 +13,7 @@ from pathlib import Path import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. import numpy as np +import time import nevergrad as ng from ..base import ArrayExperimentFunction import os @@ -28,6 +29,69 @@ # pylint: disable=too-many-locals,too-many-statements +# dollars per kilogram +crop_value_dollars_per_kg = {} +crop_value_dollars_per_kg["barley"]= 9.6 # Kenya +crop_value_dollars_per_kg["cassava"]= 2 # Kenya +crop_value_dollars_per_kg["chick_pea"]= 0.395 # Kenya +crop_value_dollars_per_kg["cotton"]= 1.83 # Kenya +crop_value_dollars_per_kg["cow_pea"]= 0.185 # Kenya +crop_value_dollars_per_kg["faba_bean"]= 0.1825 # no idea where +crop_value_dollars_per_kg["ground_nut"]= 0.66 # Kenya +crop_value_dollars_per_kg["maize"]= 0.37 # Kenya +crop_value_dollars_per_kg["millet"]= 0.485 # Kenya +crop_value_dollars_per_kg["mung_bean"]= 0.33 # no idea where, unclear# +crop_value_dollars_per_kg["pigeon_pea"]= 0.679 # not clear, kenya +crop_value_dollars_per_kg["potato"]= 0.55 # kenya, difficult +crop_value_dollars_per_kg["rape_seed"]=7.1 # kenya (waow ?) +crop_value_dollars_per_kg["rice"]=0.325 # kenya +crop_value_dollars_per_kg["sorghum"]= 0.25 # kenya +crop_value_dollars_per_kg["soy_bean"]=(0.68+0.93)/2. # kenya +crop_value_dollars_per_kg["sugar_beet"]=(0.75+0.69)/2. # kenya +crop_value_dollars_per_kg["sugar_cane"]=0.34 # kenya, roughly +crop_value_dollars_per_kg["sunflower"]= 1.69 # kenya +crop_value_dollars_per_kg["sweet_potato"]= 1.15 # kenya +crop_value_dollars_per_kg["wheat"]=(0.19+0.42)/2. # roughly, kenya + + +def lev(seq1, seq2): + size_x = len(seq1) + 1 + size_y = len(seq2) + 1 + matrix = np.zeros ((size_x, size_y)) + for x in range(size_x): + matrix [x, 0] = x + for y in range(size_y): + matrix [0, y] = y + + for x in range(1, size_x): + for y in range(1, size_y): + if seq1[x-1] == seq2[y-1]: + matrix [x,y] = min( + matrix[x-1, y] + 1, + matrix[x-1, y-1], + matrix[x, y-1] + 1 + ) + else: + matrix [x,y] = min( + matrix[x-1,y] + 1, + matrix[x-1,y-1] + 1, + matrix[x,y-1] + 1 + ) + return (matrix[size_x - 1, size_y - 1]) + +def get_crop_cost(cropname: str): + min_lev = 100000000 + if cropname in crop_value_dollars_per_kg: + return crop_value_dollars_per_kg[cropname] + for k in crop_value_dollars_per_kg: + dist = lev(cropname, k) + if dist < min_lev: + min_lev = dist + best_crop = k + print(f"best crop for {cropname} is {best_crop}") + crop_value_dollars_per_kg[cropname] = crop_value_dollars_per_kg[best_crop] + return crop_value_dollars_per_kg[cropname] + WPD = {} CURRENT_BEST = {} CURRENT_BEST_ARGUMENT = {} @@ -35,8 +99,12 @@ class Irrigation(ArrayExperimentFunction): variant_choice = {} - def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool) -> None: + def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, multi_crop: bool, address=None, year_min: int = 2006, year_max: int = 2006) -> None: self.rice = rice + if year_max < year_min and year_max == 2006: + year_max = year_min + self.year_min = year_min + self.year_max = year_max data_dir = Path(__file__).with_name("data") try: self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) @@ -46,10 +114,28 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool) str(data_dir) + "/soil/ec3.soil", ) self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) - param = ng.p.Array(shape=(9 if variety_choice else 8,), lower=(0.0), upper=(0.99999999)).set_name("irrigation8") - super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) + self.this_dimension = 8 + if rice or (variety_choice and not multi_crop): + self.this_dimension = 9 + if multi_crop: + self.this_dimension = 10 + assert not rice + + param = ng.p.Array(shape=(self.this_dimension,), lower=(0.0), upper=(0.99999999)).set_name("irrigation8") + super().__init__(self.meta_total_yield, parametrization=param, symmetry=symmetry) if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") +# "Cotonou", +# "Lokossa", +# "Allada", +# "Abomey", +# "Pobe", +# "Aplahoue", +# "Dassa-Zoume", +# "Parakou", +# "Djougou", +# "Kandi", +# "Natitingou", known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361, 'Porto-Novo': @@ -57,6 +143,28 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool) known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336, 'Porto-Novo': 6.4969} + known_longitudes['Cotonou'] = 2.4252507 + known_latitudes['Cotonou'] = 6.3676953 + known_longitudes['Lokossa'] = 1.7171404 + known_latitudes['Lokossa'] = 6.6458524 + known_longitudes['Allada'] = 2.1511876 + known_latitudes['Allada'] = 6.6658411 + known_longitudes['Abomey'] = 1.9828803672675925 + known_latitudes['Abomey'] = 7.165446 + known_longitudes['Pobe'] = -1.751602 + known_latitudes['Pobe'] = 13.882217 + known_longitudes['Aplahoue'] = 1.7041012 + known_latitudes['Aplahoue'] = 6.9489244 + known_longitudes['Dassa-Zoume'] = 2.183606 + known_latitudes['Dassa-Zoume'] = 7.7815402 + known_longitudes['Parakou'] = 2.6278258 + known_latitudes['Parakou'] = 9.3400159 + known_longitudes['Djougou'] = 1.6651614 + known_latitudes['Djougou'] = 9.7106683 + known_longitudes['Kandi'] = 88.11640162351831 + known_latitudes['Kandi'] = 24.00952125 + known_longitudes['Natitingou'] = 1.383540986380074 + known_latitudes['Natitingou'] = 10.251408300000001 self.cropd = YAMLCropDataProvider() for k in range(1000): if symmetry in self.variant_choice and k < self.variant_choice[symmetry]: @@ -91,8 +199,19 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool) "Natitingou", ] ) - #if self.address in known_latitudes and self.address in known_longitudes: - # self.weatherdataprovider = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) + if address is not None: + self.address = str(address) + if len(address) == 2: + known_latitudes[self.address] = address[0] + known_longitudes[self.address] = address[1] + + if self.address in known_latitudes and self.address in known_longitudes and self.address not in WPD: + for k in range(10): + try: + WPD[self.address] = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) + break + except: + time.sleep(10 * (2 **k)) if self.address in WPD: self.weatherdataprovider = WPD[self.address] else: @@ -104,7 +223,7 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool) ) WPD[self.address] = self.weatherdataprovider self.set_data(symmetry, k, rice) - v = [self.leaf_area_index(np.random.rand(9 if variety_choice else 8)) for _ in range(5)] + v = [self.meta_total_yield(np.random.rand(self.this_dimension)) for _ in range(5)] if min(v) != max(v): break self.variant_choice[symmetry] = k @@ -116,6 +235,7 @@ def set_data(self, symmetry: int, k: int, rice: bool): crop_types = [c for c in crop_types if "obacco" not in c] if rice: crop_types = ["rice"] + self.crop_types = crop_types self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) self.total_irrigation = np.random.RandomState(symmetry+3*k+3).choice([15.0, 1.50, 0.15, 150.]) if not rice else 0.15 self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) @@ -126,29 +246,59 @@ def set_data(self, symmetry: int, k: int, rice: bool): self.parameterprovider = ParameterProvider(soildata=self.soil, cropdata=self.cropd, sitedata=site) - def leaf_area_index(self, x: np.ndarray): + def meta_total_yield(self, x: np.ndarray): + lai = 0. + for year in range(self.year_min, self.year_max+1): + print(f"working on {year}") + lai += self.total_yield(x, year) + specifier = self.address + "_" + str(self.total_irrigation) + if not self.this_dimension == 10: + specifier += "_" + str(self.cropname) + if self.dimension == 8: + specifier += "_" + self.cropvariety + if specifier not in CURRENT_BEST: + CURRENT_BEST[specifier] = 0. + if lai > CURRENT_BEST[specifier]: + CURRENT_BEST[specifier] = lai + argument = str(x) + if self.dimension > 9: + argument += "_" + self.cropname + if self.dimension > 8: + argument += "_" + self.cropvariety + CURRENT_BEST_ARGUMENT[specifier] = argument + print(f"for <{specifier}> we recommend {CURRENT_BEST_ARGUMENT[specifier]} and get {lai}") + + return -lai + + def total_yield(self, x: np.ndarray, year:int=2006): d0 = int(1.01 + 29.98 * x[0]) d1 = int(1.01 + 30.98 * x[1]) d2 = int(1.01 + 30.98 * x[2]) d3 = int(1.01 + 29.98 * x[3]) c = self.total_irrigation + if len(x) == 10: + c = 0 a0 = c * x[4] / (x[4] + x[5] + x[6] + x[7]) a1 = c * x[5] / (x[4] + x[5] + x[6] + x[7]) a2 = c * x[6] / (x[4] + x[5] + x[6] + x[7]) a3 = c * x[7] / (x[4] + x[5] + x[6] + x[7]) if len(x) > 8: - assert len(x) == 9, f"my x has size {len(x)}, it is {x}" + if self.this_dimension == 10: + assert len(x) == 10 + self.cropname = self.crop_types[int(x[9] * len(self.crop_types))] + else: + assert len(x) == 9, f"my x has size {len(x)}, it is {x}" varieties = list(self.cropd.get_crops_varieties()[self.cropname]) self.cropvariety = varieties[int(x[8] * len(varieties))] yaml_agro = f""" - - 2006-01-01: + - {year}-01-01: CropCalendar: crop_name: {self.cropname} variety_name: {self.cropvariety} - crop_start_date: 2006-03-31 + crop_start_date: {year}-03-31 crop_start_type: emergence - crop_end_date: 2006-10-20 + crop_end_date: {year}-10-20 crop_end_type: harvest max_duration: 300 TimedEvents: @@ -156,18 +306,28 @@ def leaf_area_index(self, x: np.ndarray): name: Irrigation application table comment: All irrigation amounts in cm events_table: - - 2006-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}} - - 2006-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}} - - 2006-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}} - - 2006-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} + - {year}-06-{d0:02}: {{amount: {a0}, efficiency: 0.7}} + - {year}-07-{d1:02}: {{amount: {a1}, efficiency: 0.7}} + - {year}-08-{d2:02}: {{amount: {a2}, efficiency: 0.7}} + - {year}-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} StateEvents: null """ try: agromanagement = yaml.safe_load(yaml_agro) wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) wofost.run_till_terminate() +# for i in range(10): +# try: +# wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) +# wofost.run_till_terminate() +# break +# except: +# print(f"failure {i} for {yaml_agro}") +# time.sleep(2 ** i) +# return -float("inf") except Exception as e: - return float("inf") + print(e) + return -float("inf") #assert ( # False #), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" @@ -177,14 +337,6 @@ def leaf_area_index(self, x: np.ndarray): df = pd.DataFrame(output).set_index("day") df.tail() - lai = sum([float(o["LAI"]) for o in output if o["LAI"] is not None]) - specifier = self.address + "_" + str(self.cropname) + "_" + str(self.total_irrigation) - if not self.rice: - specifier += "_" + self.cropvariety - if specifier not in CURRENT_BEST: - CURRENT_BEST[specifier] = 0. - if lai > CURRENT_BEST[specifier]: - CURRENT_BEST[specifier] = lai - CURRENT_BEST_ARGUMENT[specifier] = self.cropvariety if self.rice else str(x) - print(f"for <{specifier}> we recommend {CURRENT_BEST_ARGUMENT[specifier]} and get {lai}") - return - lai + lai = sum([float(o["TWSO"]) for o in output if o["TWSO"] is not None]) + value = lai * get_crop_cost(self.cropname) + return value From 3f9d3fa73e663f96e2be19a7d5744792d2c7486a Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Tue, 6 Dec 2022 16:55:44 +0100 Subject: [PATCH 071/140] fix --- nevergrad/functions/irrigation/irrigation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index cf7fc5a561..0cfa8878f0 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -312,6 +312,8 @@ def total_yield(self, x: np.ndarray, year:int=2006): - {year}-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} StateEvents: null """ + print(list(self.weatherdataprovider.keys())) + assert False try: agromanagement = yaml.safe_load(yaml_agro) wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) From 2e53add362a7d6441a1bf83c792217324ef3484c Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Fri, 9 Dec 2022 09:43:53 +0100 Subject: [PATCH 072/140] fixngoptrw --- nevergrad/optimization/optimizerlib.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index c0423c5f2b..8ffdac0471 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -3109,15 +3109,12 @@ class NGOpt(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass + @registry.register class NGTuned(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass -NGOptRW = ConfPortfolio( - optimizers=[GeneticDE, PSO, NGOpt], warmup_ratio=0.33 - ).set_name("NGOptRW", register=True) - class _MSR(Portfolio): """This code applies multiple copies of NGOpt with random weights for the different objective functions. From 2cfe119f0f8d06a5bcd058f753d04590730e2a37 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 14:57:34 +0100 Subject: [PATCH 073/140] ClimateChange --- nevergrad/functions/irrigation/irrigation.py | 84 +++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 0cfa8878f0..bb1d1e2fc3 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -10,6 +10,8 @@ """ +import copy +from datetime import date from pathlib import Path import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. import numpy as np @@ -222,6 +224,7 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, latitude=self.location.latitude, longitude=self.location.longitude ) WPD[self.address] = self.weatherdataprovider + self.wdp_extend(self.weatherdataprovider) self.set_data(symmetry, k, rice) v = [self.meta_total_yield(np.random.rand(self.this_dimension)) for _ in range(5)] if min(v) != max(v): @@ -229,6 +232,85 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, self.variant_choice[symmetry] = k print(f"we work on {self.cropname} with variety {self.cropvariety} in {self.address}.") + def wdp_extend(self, wdp): + + my_keys = copy.deepcopy(list(wdp.store.keys())) + #print("ooo", min([k[1] for k in my_keys])) + #print("ooo", max([k[1] for k in my_keys])) + #print("==>",wdp.store[my_keys[0]]) + #print("==>",type(wdp.store[my_keys[0]])) + #print("==>",wdp.store[my_keys[0]].__slots__) + #print(list(wdp.store.keys())) + + def we_have(y, m, d): + try: + date(y, m, d) + except ValueError: + return False + if date(y, m, d) in [k[0] for k in my_keys]: + return True + + def get_val(y, m, d, slot): + my_vals = [getattr(wdp.store[(date(y_, m, d), 0)], slot) for y_ in range(y-3, y+4) if we_have(y_, m, d)] + assert len(my_vals) >= 3, f"big issue with data {y} {m} {d}!" + return sum(my_vals) / len(my_vals) + + def extrapolate(wdp, y, m, od): + d = od + if m == 2 and d == 29: + d = 28 + if we_have(y, m, d): + return + first_y = None + last_y = None + container = None + for y_ in range(y-40, y+1): + try: + we_have(y_, m, d) + except ValueError: + continue + if we_have(y_, m, d): + last_y = y_ + if first_y is None: + first_y = y_ + container = copy.deepcopy(wdp.store[(date(last_y, m, d), 0)]) + assert container is not None, "No data found even in 40 years !" + for slot in container.__slots__: + if slot not in ["IRRAD", "TMIN", "TMAX", "VAP", "RAIN", "E0", "ES0", "ET0", "WIND", "SNOWDEPTH", "TEMP", "TMINRA"]: + continue + try: + value = get_val(last_y, m, d, slot) + except AttributeError: + continue + delta = (get_val(last_y, m, d, slot) - get_val(first_y, m, d, slot)) / (last_y - first_y) + value += delta * (y - last_y) + vmin, vmax = container.ranges[slot] + if value < vmin: + value = vmin + if value > vmax: + value = vmax + setattr(container, slot, value) + wdp.store[(date(y, m, od), 0)] = container + + # Extension for the future + for y in range(2020, 2050): + for m in range(1, 12): + for d in range(1,31): + try: + date(y, m, d) + except ValueError: + continue + extrapolate(self.weatherdataprovider, y, m, d) + ok = [k for k in my_keys if k[0].year == y and k[0].month == m and k[0].day == d] + assert len(ok) < 2 + assert len(ok) >= (1 if we_have(y, m, d) else 0) + + my_keys = list(wdp.store.keys()) + for y in range(2020, 2050): + ok = [k for k in my_keys if k[0].year == y] + print(y, len(ok)) + assert False + def set_data(self, symmetry: int, k: int, rice: bool): crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] @@ -312,8 +394,6 @@ def total_yield(self, x: np.ndarray, year:int=2006): - {year}-09-{d3:02}: {{amount: {a3}, efficiency: 0.7}} StateEvents: null """ - print(list(self.weatherdataprovider.keys())) - assert False try: agromanagement = yaml.safe_load(yaml_agro) wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) From 9ac9d161e89fe4398be34db4996bf2de510e3045 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 15:05:44 +0100 Subject: [PATCH 074/140] merge_and_small_fix --- nevergrad/functions/irrigation/irrigation.py | 4 ++-- nevergrad/optimization/optimizerlib.py | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 8f8d4ce088..daf7f81ed1 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -247,11 +247,11 @@ def we_have(y, m, d): date(y, m, d) except ValueError: return False - if date(y, m, d) in [k[0] for k in my_keys]: + if (date(y, m, d), 0) in my_keys: return True def get_val(y, m, d, slot): - my_vals = [getattr(wdp.store[(date(y_, m, d), 0)], slot) for y_ in range(y-3, y+4) if we_have(y_, m, d)] + my_vals = [getattr(wdp.store[(date(y_, m, d), 0)], slot) for y_ in range(y-4, y+5) if we_have(y_, m, d)] assert len(my_vals) >= 3, f"big issue with data {y} {m} {d}!" return sum(my_vals) / len(my_vals) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 56c95a6f33..edc14ac5a7 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -3109,15 +3109,12 @@ class NGOpt(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass + @registry.register class NGTuned(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass -NGOptRW = ConfPortfolio( - optimizers=[GeneticDE, PSO, NGOpt], warmup_ratio=0.33 - ).set_name("NGOptRW", register=True) - @registry.register class NGTuned(NGOpt39): From 09e4865f70bb87d13c6bbceabe42af9b348fd43b Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 15:59:20 +0100 Subject: [PATCH 075/140] merge --- nevergrad/functions/pcse/__init__.py | 2 +- nevergrad/functions/pcse/pcse.py | 115 ++++++++++++++++----------- 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py index 2f131cc36c..a516986ced 100644 --- a/nevergrad/functions/pcse/__init__.py +++ b/nevergrad/functions/pcse/__init__.py @@ -5,4 +5,4 @@ # Based on https://github.com/ajwdewit/pcse_notebooks # MIT License. -from .pcse import CropSimulator as CropSimulator +from .pcse import Pcse as Pcse diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index ba9ee34d79..f57db52396 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -4,37 +4,41 @@ # LICENSE file in the root directory of this source tree. """ -Approximate crop Simulation +Approximate Pcse Simulation Based on https://raw.githubusercontent.com/purdue-orbital/pcse-simulation/master/Simulation2.py """ -import pandas as pd -import yaml + +import math +import pyproj import numpy as np -import nevergrad as ng +from nevergrad.parametrization import parameter from ..base import ArrayExperimentFunction # pylint: disable=too-many-locals,too-many-statements -class CropSimulator(ArrayExperimentFunction): - def __init__(self) -> None: - try: - #raise Exception("We do not import EUPL code by default.") - import pcse # pylint: disable=unused-import - except: - raise ng.errors.UnsupportedExperiment( - "You need to install PCSE. Check that the EUPL license is ok for you." - ) +class Pcse(ArrayExperimentFunction): + + + def __init__(self, symmetry: int = 0) -> None: + import sys + import matplotlib + import matplotlib.pyplot as plt + import yaml + import pandas as pd + import numpy as np + from itertools import product + #from progressbar import printProgressBar + + import pcse from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider - - # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider - from pcse.fileinput import YAMLCropDataProvider + from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider - + # Weather data for Netherlands wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) # Standard crop parameter library @@ -42,10 +46,10 @@ def __init__(self) -> None: # We don't need soil for potential production, so we use dummy values soild = DummySoilDataProvider() # Some site parameters - sited = WOFOST72SiteDataProvider(WAV=50, CO2=360.0) + sited = WOFOST72SiteDataProvider(WAV=50, CO2=360.) # Package everyting into a single parameter object params = ParameterProvider(cropdata=cropd, sitedata=sited, soildata=soild) - + # Here we define the agromanagement for sugar beet agro_yaml = """ - 2006-01-01: @@ -60,39 +64,53 @@ def __init__(self) -> None: TimedEvents: null StateEvents: null """ - agro = yaml.safe_load(agro_yaml) - + #agro = yaml.safe_load(agro_yaml) + agro = yaml.load(agro_yaml) + wofost = Wofost72_PP(params, wdp, agro) wofost.run_till_terminate() df = pd.DataFrame(wofost.get_output()) df.index = pd.to_datetime(df.day) df.tail() + ## get daily observations for those + #ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) + #df_pseudo_obs = df.loc[ix] +# +# class ModelRerunner(object): +# """Reruns a given model with different values of parameters TWDI and SPAN. +# +# Returns a pandas DataFrame with simulation results of the model with given +# parameter values. +# """ +# +# parameters = ["TDWI", "SPAN"] + + # get daily observations for those ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) df_pseudo_obs = df.loc[ix] - + fig, axes = plt.subplots(figsize=(12,8)) + axes.plot_date(df_pseudo_obs.index, df_pseudo_obs.LAI) + r = axes.set_title("Pseudo LAI observations") + class ModelRerunner(object): """Reruns a given model with different values of parameters TWDI and SPAN. - + Returns a pandas DataFrame with simulation results of the model with given parameter values. """ - parameters = ["TDWI", "SPAN"] - + def __init__(self, params, wdp, agro): self.params = params self.wdp = wdp self.agro = agro - + def __call__(self, par_values): # Check if correct number of parameter values were provided if len(par_values) != len(self.parameters): - msg = "Optimizing %i parameters, but %i values were provided!" % ( - len(self.parameters), - len(par_values), - ) + msg = "Optimizing %i parameters, but only % values were provided!" % (len(self.parameters, len(par_values))) raise RuntimeError(msg) # Clear any existing overrides self.params.clear_override() @@ -105,43 +123,46 @@ def __call__(self, par_values): df = pd.DataFrame(wofost.get_output()) df.index = pd.to_datetime(df.day) return df - + class ObjectiveFunctionCalculator(object): """Computes the objective function. - - This class runs the simulation model with given parameter values and returns the objective - function as the sum of squared difference between observed and simulated LAI. - .""" - + + This class runs the simulation model with given parameter values and returns the objective + function as the sum of squared difference between observed and simulated LAI. + . """ + def __init__(self, params, wdp, agro, observations): self.modelrerunner = ModelRerunner(params, wdp, agro) self.df_observations = observations self.n_calls = 0 - + def __call__(self, par_values, grad=None): """Runs the model and computes the objective function for given par_values. - + The input parameter 'grad' must be defined in the function call, but is only required for optimization methods where analytical gradients can be computed. """ self.n_calls += 1 - # print(".", end="") + #print(".", end="") # Run the model and collect output - df_simulations = self.modelrerunner(par_values) + self.df_simulations = self.modelrerunner(par_values) # compute the differences by subtracting the DataFrames # Note that the dataframes automatically join on the index (dates) and column names - df_differences = df_simulations - self.df_observations + df_differences = self.df_simulations - self.df_observations # Compute the RMSE on the LAI column - obj_func = np.sqrt(np.mean(df_differences.LAI ** 2)) + obj_func = np.sqrt(np.mean(df_differences.LAI**2)) return obj_func - + objfunc_calculator = ObjectiveFunctionCalculator(params, wdp, agro, df_pseudo_obs) # defaults = [cropd["TDWI"], cropd["SPAN"]] # error = objfunc_calculator(defaults) # print("Objective function value with default parameters (%s): %s" % (defaults, error)) TDWI_range = [0.1, 0.6] SPAN_range = [30, 40] - param = ng.p.Array( - shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) - ).set_name("2hp") - super().__init__(objfunc_calculator, parametrization=param) + #param = ng.p.Array( + # shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) + #).set_name("2hp") + #super().__init__(objfunc_calculator, parametrization=param) + + param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) + super().__init__(objfunc_calculator, parametrization=param, symmetry=symmetry) From c934de26d2ababcc499371b881f01b0c23ea667c Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:48:17 +0100 Subject: [PATCH 076/140] pcse --- nevergrad/benchmark/experiments.py | 11 +++++++++-- nevergrad/functions/pcse/test_pcse.py | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 6bb2b81444..d01c8343b3 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -26,7 +26,6 @@ from nevergrad.functions.stsp import STSP from nevergrad.functions.rocket import Rocket from nevergrad.functions.irrigation import Irrigation -from nevergrad.functions.pcse import CropSimulator from nevergrad.functions.mixsimulator import OptimizeMix from nevergrad.functions.unitcommitment import UnitCommitmentProblem from nevergrad.functions import control @@ -1519,6 +1518,14 @@ def kenya_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp. def kenya_new_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2016, year_max=2021) +@registry.register +def kenya_future_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2026, year_max=2031) + +@registry.register +def kenya_farfuture_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2036, year_max=2041) + @registry.register def kenya_old_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=1996, year_max=2001) @@ -1551,7 +1558,7 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: Low dimensional problem, only 2 vars. This is optimization for model identification: we want to find parameters so that the simulation matches observations. """ - funcs = [CropSimulator()] + funcs = [Pcse()] seedg = create_seed_generator(seed) optims = ["DE", "PSO", "CMA", "NGOpt"] for budget in [25, 50, 100, 200]: diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index 72cb2d6346..3776675da0 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -8,7 +8,7 @@ def test_pcse() -> None: - func = pcse.CropSimulator() + func = pcse.Pcse() x = 0 * np.random.rand(func.dimension) value = func(x) value2 = func(x) From 1257db52dfa47a90110572f28f632b0355d8bdea Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:51:39 +0100 Subject: [PATCH 077/140] pcse --- nevergrad/benchmark/experiments.py | 20 ++++++++++++++++++++ nevergrad/functions/pcse/pcse.py | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index d01c8343b3..126aefbf2e 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -26,6 +26,7 @@ from nevergrad.functions.stsp import STSP from nevergrad.functions.rocket import Rocket from nevergrad.functions.irrigation import Irrigation +#from nevergrad.functions.pcse import Pcse from nevergrad.functions.mixsimulator import OptimizeMix from nevergrad.functions.unitcommitment import UnitCommitmentProblem from nevergrad.functions import control @@ -1571,6 +1572,25 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: yield xp +@registry.register +def pcse(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + """Crop simulator. + + Low dimensional problem, only 2 vars. + """ + funcs = [Pcse()] + seedg = create_seed_generator(seed) + optims = get_optimizers("basics", seed=next(seedg)) + for budget in [25, 50, 100, 200]: + for num_workers in [1, 10, 40]: + if num_workers < budget: + for algo in optims: + for fu in funcs: + xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg)) + if not xp.is_incoherent: + yield xp + + @registry.register def mono_rocket(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Sequential counterpart of the rocket problem.""" diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index f57db52396..7fb84cc588 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -4,7 +4,7 @@ # LICENSE file in the root directory of this source tree. """ -Approximate Pcse Simulation +Approximate crop Simulation Based on https://raw.githubusercontent.com/purdue-orbital/pcse-simulation/master/Simulation2.py """ @@ -22,7 +22,7 @@ class Pcse(ArrayExperimentFunction): - def __init__(self, symmetry: int = 0) -> None: + def __init__(self) -> None: import sys import matplotlib import matplotlib.pyplot as plt @@ -165,4 +165,4 @@ def __call__(self, par_values, grad=None): #super().__init__(objfunc_calculator, parametrization=param) param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) - super().__init__(objfunc_calculator, parametrization=param, symmetry=symmetry) + super().__init__(objfunc_calculator, parametrization=param) From a02c5ea73531ac35838a7ea354ecf569609ab59a Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:53:52 +0100 Subject: [PATCH 078/140] fix --- nevergrad/functions/pcse/pcse.py | 57 +++++++++++++++++--------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 7fb84cc588..4e782ddc9d 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -20,8 +20,6 @@ class Pcse(ArrayExperimentFunction): - - def __init__(self) -> None: import sys import matplotlib @@ -30,15 +28,16 @@ def __init__(self) -> None: import pandas as pd import numpy as np from itertools import product - #from progressbar import printProgressBar - + + # from progressbar import printProgressBar + import pcse from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider - + # Weather data for Netherlands wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) # Standard crop parameter library @@ -46,10 +45,10 @@ def __init__(self) -> None: # We don't need soil for potential production, so we use dummy values soild = DummySoilDataProvider() # Some site parameters - sited = WOFOST72SiteDataProvider(WAV=50, CO2=360.) + sited = WOFOST72SiteDataProvider(WAV=50, CO2=360.0) # Package everyting into a single parameter object params = ParameterProvider(cropdata=cropd, sitedata=sited, soildata=soild) - + # Here we define the agromanagement for sugar beet agro_yaml = """ - 2006-01-01: @@ -66,7 +65,7 @@ def __init__(self) -> None: """ #agro = yaml.safe_load(agro_yaml) agro = yaml.load(agro_yaml) - + wofost = Wofost72_PP(params, wdp, agro) wofost.run_till_terminate() df = pd.DataFrame(wofost.get_output()) @@ -90,27 +89,30 @@ def __init__(self) -> None: # get daily observations for those ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) df_pseudo_obs = df.loc[ix] - fig, axes = plt.subplots(figsize=(12,8)) + fig, axes = plt.subplots(figsize=(12, 8)) axes.plot_date(df_pseudo_obs.index, df_pseudo_obs.LAI) r = axes.set_title("Pseudo LAI observations") - + class ModelRerunner(object): """Reruns a given model with different values of parameters TWDI and SPAN. - + Returns a pandas DataFrame with simulation results of the model with given parameter values. """ + parameters = ["TDWI", "SPAN"] - + def __init__(self, params, wdp, agro): self.params = params self.wdp = wdp self.agro = agro - + def __call__(self, par_values): # Check if correct number of parameter values were provided if len(par_values) != len(self.parameters): - msg = "Optimizing %i parameters, but only % values were provided!" % (len(self.parameters, len(par_values))) + msg = "Optimizing %i parameters, but only % values were provided!" % ( + len(self.parameters, len(par_values)) + ) raise RuntimeError(msg) # Clear any existing overrides self.params.clear_override() @@ -123,36 +125,36 @@ def __call__(self, par_values): df = pd.DataFrame(wofost.get_output()) df.index = pd.to_datetime(df.day) return df - + class ObjectiveFunctionCalculator(object): """Computes the objective function. - - This class runs the simulation model with given parameter values and returns the objective - function as the sum of squared difference between observed and simulated LAI. - . """ - + + This class runs the simulation model with given parameter values and returns the objective + function as the sum of squared difference between observed and simulated LAI. + .""" + def __init__(self, params, wdp, agro, observations): self.modelrerunner = ModelRerunner(params, wdp, agro) self.df_observations = observations self.n_calls = 0 - + def __call__(self, par_values, grad=None): """Runs the model and computes the objective function for given par_values. - + The input parameter 'grad' must be defined in the function call, but is only required for optimization methods where analytical gradients can be computed. """ self.n_calls += 1 - #print(".", end="") + # print(".", end="") # Run the model and collect output self.df_simulations = self.modelrerunner(par_values) # compute the differences by subtracting the DataFrames # Note that the dataframes automatically join on the index (dates) and column names df_differences = self.df_simulations - self.df_observations # Compute the RMSE on the LAI column - obj_func = np.sqrt(np.mean(df_differences.LAI**2)) + obj_func = np.sqrt(np.mean(df_differences.LAI ** 2)) return obj_func - + objfunc_calculator = ObjectiveFunctionCalculator(params, wdp, agro, df_pseudo_obs) # defaults = [cropd["TDWI"], cropd["SPAN"]] # error = objfunc_calculator(defaults) @@ -164,5 +166,8 @@ def __call__(self, par_values, grad=None): #).set_name("2hp") #super().__init__(objfunc_calculator, parametrization=param) - param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) + #param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) + param = ng.p.Array( + shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) + ) super().__init__(objfunc_calculator, parametrization=param) From b069972215903eed24041c7edce7c383e23ff191 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:59:42 +0100 Subject: [PATCH 079/140] pcse --- nevergrad/functions/pcse/pcse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 4e782ddc9d..0d518312ba 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -167,7 +167,9 @@ def __call__(self, par_values, grad=None): #super().__init__(objfunc_calculator, parametrization=param) #param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) + import nevergrad as ng + param = ng.p.Array( shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) - ) + ).set_name("2hp") super().__init__(objfunc_calculator, parametrization=param) From ceb20696215731abc0e57c4df56e90dae03c185e Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:06:01 +0100 Subject: [PATCH 080/140] fix --- nevergrad/functions/pcse/pcse.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 0d518312ba..1e6525a24e 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -10,10 +10,7 @@ """ -import math -import pyproj import numpy as np -from nevergrad.parametrization import parameter from ..base import ArrayExperimentFunction # pylint: disable=too-many-locals,too-many-statements @@ -21,17 +18,9 @@ class Pcse(ArrayExperimentFunction): def __init__(self) -> None: - import sys - import matplotlib - import matplotlib.pyplot as plt import yaml import pandas as pd import numpy as np - from itertools import product - - # from progressbar import printProgressBar - - import pcse from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider @@ -89,9 +78,6 @@ def __init__(self) -> None: # get daily observations for those ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) df_pseudo_obs = df.loc[ix] - fig, axes = plt.subplots(figsize=(12, 8)) - axes.plot_date(df_pseudo_obs.index, df_pseudo_obs.LAI) - r = axes.set_title("Pseudo LAI observations") class ModelRerunner(object): """Reruns a given model with different values of parameters TWDI and SPAN. From 831768d145689db14423974f9522d632f4967945 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:47:51 +0100 Subject: [PATCH 081/140] nlopt --- mypy.ini | 1 + nevergrad/functions/pcse/pcse.py | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mypy.ini b/mypy.ini index 6c130962e1..d983bae164 100644 --- a/mypy.ini +++ b/mypy.ini @@ -4,6 +4,7 @@ ignore_missing_imports = True [mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 1e6525a24e..1a543e4a2e 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -20,11 +20,12 @@ class Pcse(ArrayExperimentFunction): def __init__(self) -> None: import yaml import pandas as pd - import numpy as np from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider - from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + + # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + from pcse.fileinput import YAMLCropDataProvider from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider # Weather data for Netherlands @@ -133,10 +134,10 @@ def __call__(self, par_values, grad=None): self.n_calls += 1 # print(".", end="") # Run the model and collect output - self.df_simulations = self.modelrerunner(par_values) + df_simulations = self.modelrerunner(par_values) # compute the differences by subtracting the DataFrames # Note that the dataframes automatically join on the index (dates) and column names - df_differences = self.df_simulations - self.df_observations + df_differences = df_simulations - self.df_observations # Compute the RMSE on the LAI column obj_func = np.sqrt(np.mean(df_differences.LAI ** 2)) return obj_func From e291e11f9cb7de3ea4cdd58c3167beb735ceafbb Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:56:08 +0100 Subject: [PATCH 082/140] nlopt --- mypy.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/mypy.ini b/mypy.ini index d983bae164..6292f2770c 100644 --- a/mypy.ini +++ b/mypy.ini @@ -13,6 +13,7 @@ ignore_missing_imports = True #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] ignore_missing_imports = True ignore_errors = True From e1bde6c530a8da85338a962cc4680a8ed469c2b4 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 15:01:57 +0100 Subject: [PATCH 083/140] nlopt --- nevergrad/functions/pcse/pcse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 1a543e4a2e..6475d83d9f 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -98,7 +98,8 @@ def __call__(self, par_values): # Check if correct number of parameter values were provided if len(par_values) != len(self.parameters): msg = "Optimizing %i parameters, but only % values were provided!" % ( - len(self.parameters, len(par_values)) + len(self.parameters), + len(par_values), ) raise RuntimeError(msg) # Clear any existing overrides From 1e0cd57e590792b982de201c8686db3dc1d64c93 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 15:11:53 +0100 Subject: [PATCH 084/140] fix --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 6475d83d9f..209ecc4411 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -97,7 +97,7 @@ def __init__(self, params, wdp, agro): def __call__(self, par_values): # Check if correct number of parameter values were provided if len(par_values) != len(self.parameters): - msg = "Optimizing %i parameters, but only % values were provided!" % ( + msg = "Optimizing %i parameters, but %i values were provided!" % ( len(self.parameters), len(par_values), ) From c4c5ad3b6c4a997c7e23986ca27c039a6723419e Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 15:47:29 +0100 Subject: [PATCH 085/140] fix --- nevergrad/optimization/test_optimizerlib.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 8128802089..95a15e96ef 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -728,6 +728,15 @@ def test_ngopt_selection( # match = re.match(pattern, caplog.text.splitlines()[-1]) # assert match is not None, f"Did not detect selection in logs: {caplog.text}" # choice = match.group("name") +# opt.optim # type: ignore +# pattern = rf".*{name} selected (?P\w+?) optimizer\." +# try: +# match = re.match(pattern, caplog.text.splitlines()[-1]) +# except Error as e: +# print(f"{caplog.text.splitlines()}") +# raise e +# assert match is not None, f"Did not detect selection in logs: {caplog.text}" + choice = match.group("name") if expected != "#CONTINUOUS": # assert choice == expected assert expected in optim_string From 3ee1fd51f22d58e05780cd08adb0c9a14d2ef5a5 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 16:29:25 +0100 Subject: [PATCH 086/140] po --- nevergrad/optimization/optimizerlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 8ffdac0471..eb72cb80b1 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -2614,7 +2614,7 @@ def optim(self) -> base.Optimizer: if self._optim is None: self._optim = self._select_optimizer_cls()(self.parametrization, self.budget, self.num_workers) self._optim = self._optim if not isinstance(self._optim, NGOptBase) else self._optim.optim - logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) + logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) return self._optim def _select_optimizer_cls(self) -> base.OptCls: From aa38bee5725abc4f144de120b3cdafe363c1e17c Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 16:58:52 +0100 Subject: [PATCH 087/140] to --- nevergrad/optimization/test_optimizerlib.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 95a15e96ef..f129c1b03f 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -743,16 +743,12 @@ def test_ngopt_selection( else: # print(f"Continuous param={param} budget={budget} workers={num_workers} --> {choice}") if num_workers >= budget > 600: - # assert choice == "MetaTuneRecentering" - assert "MetaTuneRecentering" in optim_string + #assert choice == "MetaTuneRecentering" + assert "MetaTuneRecentering" in o if num_workers > 1: - assert choice not in ["SQP", "Cobyla"] - if "CMA" not in choice: - assert choice == opt._info()["sub-optim"] - else: - assert choice in opt._info()["sub-optim"] - #assert expected == opt._info()["sub-optim"] - #assert opt._info()["sub-optim"] in o + #assert choice not in ["SQP", "Cobyla"] + assert "SQP" not in o and "Cobyla" not in o + assert expected == opt._info()["sub-optim"] def test_bo_ordering() -> None: From 16f0c5763f7357afc9520ff025ce16cc24128927 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 17:09:21 +0100 Subject: [PATCH 088/140] fix --- nevergrad/optimization/test_optimizerlib.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index f129c1b03f..e1bf644356 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -728,27 +728,18 @@ def test_ngopt_selection( # match = re.match(pattern, caplog.text.splitlines()[-1]) # assert match is not None, f"Did not detect selection in logs: {caplog.text}" # choice = match.group("name") -# opt.optim # type: ignore -# pattern = rf".*{name} selected (?P\w+?) optimizer\." -# try: -# match = re.match(pattern, caplog.text.splitlines()[-1]) -# except Error as e: -# print(f"{caplog.text.splitlines()}") -# raise e -# assert match is not None, f"Did not detect selection in logs: {caplog.text}" - choice = match.group("name") if expected != "#CONTINUOUS": # assert choice == expected assert expected in optim_string else: # print(f"Continuous param={param} budget={budget} workers={num_workers} --> {choice}") if num_workers >= budget > 600: - #assert choice == "MetaTuneRecentering" + # assert choice == "MetaTuneRecentering" assert "MetaTuneRecentering" in o if num_workers > 1: - #assert choice not in ["SQP", "Cobyla"] + # assert choice not in ["SQP", "Cobyla"] assert "SQP" not in o and "Cobyla" not in o - assert expected == opt._info()["sub-optim"] + #assert expected == opt._info()["sub-optim"] def test_bo_ordering() -> None: From e467b65e14ae099f7c8a70d3787d7d2874f49d63 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Fri, 21 Jan 2022 15:01:54 +0100 Subject: [PATCH 089/140] Update experiments.py --- nevergrad/benchmark/experiments.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 126aefbf2e..7746bff9e7 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1576,7 +1576,8 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: def pcse(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. - Low dimensional problem, only 2 vars. + Low dimensional problem, only 2 vars. This is optimization for model identification: we want + to find parameters so that the simulation matches observations. """ funcs = [Pcse()] seedg = create_seed_generator(seed) From b0ca2da1e5050642f9a049673eb3b51b4f8364ac Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:47:50 +0100 Subject: [PATCH 090/140] Update nevergrad/optimization/optimizerlib.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémy Rapin --- nevergrad/optimization/optimizerlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index eb72cb80b1..8ffdac0471 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -2614,7 +2614,7 @@ def optim(self) -> base.Optimizer: if self._optim is None: self._optim = self._select_optimizer_cls()(self.parametrization, self.budget, self.num_workers) self._optim = self._optim if not isinstance(self._optim, NGOptBase) else self._optim.optim - logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) + logger.debug("%s selected %s optimizer.", *(x.name for x in (self, self._optim))) return self._optim def _select_optimizer_cls(self) -> base.OptCls: From 3fe8314b8ec7e55441d30c55dce3b641f27c9fa1 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:49:42 +0100 Subject: [PATCH 091/140] Update test_optimizerlib.py --- nevergrad/optimization/test_optimizerlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index e1bf644356..4c1de1dc57 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -735,7 +735,7 @@ def test_ngopt_selection( # print(f"Continuous param={param} budget={budget} workers={num_workers} --> {choice}") if num_workers >= budget > 600: # assert choice == "MetaTuneRecentering" - assert "MetaTuneRecentering" in o + assert "MetaTuneRecentering" in optim_string if num_workers > 1: # assert choice not in ["SQP", "Cobyla"] assert "SQP" not in o and "Cobyla" not in o From c56c5160475b55986a49273c921704c548114356 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:52:07 +0100 Subject: [PATCH 092/140] Update pcse.py --- nevergrad/functions/pcse/pcse.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 209ecc4411..69565af788 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -9,17 +9,17 @@ https://raw.githubusercontent.com/purdue-orbital/pcse-simulation/master/Simulation2.py """ - +import pandas as pd +import yaml import numpy as np +import nevergrad as ng from ..base import ArrayExperimentFunction # pylint: disable=too-many-locals,too-many-statements -class Pcse(ArrayExperimentFunction): +class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: - import yaml - import pandas as pd from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider @@ -147,6 +147,7 @@ def __call__(self, par_values, grad=None): # defaults = [cropd["TDWI"], cropd["SPAN"]] # error = objfunc_calculator(defaults) # print("Objective function value with default parameters (%s): %s" % (defaults, error)) + TDWI_range = [0.1, 0.6] SPAN_range = [30, 40] #param = ng.p.Array( From 9b7b51c02756e9caa1deac18e1ead14ba89dd1aa Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 16 Feb 2022 17:53:11 +0100 Subject: [PATCH 093/140] Update experiments.py --- nevergrad/benchmark/experiments.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 7746bff9e7..5eb8561687 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -26,7 +26,7 @@ from nevergrad.functions.stsp import STSP from nevergrad.functions.rocket import Rocket from nevergrad.functions.irrigation import Irrigation -#from nevergrad.functions.pcse import Pcse +from nevergrad.functions.pcse import Pcse from nevergrad.functions.mixsimulator import OptimizeMix from nevergrad.functions.unitcommitment import UnitCommitmentProblem from nevergrad.functions import control @@ -1573,13 +1573,13 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: @registry.register -def pcse(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: +def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. Low dimensional problem, only 2 vars. This is optimization for model identification: we want to find parameters so that the simulation matches observations. """ - funcs = [Pcse()] + funcs = [CropSimulator()] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) for budget in [25, 50, 100, 200]: From fd6b068b6649e226c72f95216ed9c4e1cbc60212 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 20:08:49 +0100 Subject: [PATCH 094/140] Pcse2: irrigation challenge (#1341) * irrigation_challenge * flute * fix * Update __init__.py * Update experiments.py * fix * fix * fix * fix * fix * fix * fix * fix * fix_gym * fix_gym * fix_gym * fix * fix --- nevergrad/benchmark/experiments.py | 18 ++++++++++++++++++ nevergrad/functions/gym/test_multigym.py | 5 ++--- nevergrad/functions/pcse/__init__.py | 2 +- nevergrad/functions/pcse/test_pcse.py | 2 +- nevergrad/optimization/test_optimizerlib.py | 5 +++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 5eb8561687..06440f8022 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1573,6 +1573,24 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: @registry.register +def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + """Irrigation simulator. Maximize leaf area index, + so that you get a lot of primary production. + Sequential or 30 workers.""" + funcs = [Irrigation(i) for i in range(17)] + seedg = create_seed_generator(seed) + optims = get_optimizers("basics", seed=next(seedg)) + for budget in [25, 50, 100, 200]: + for num_workers in [1, 30, 60]: + if num_workers < budget: + for algo in optims: + for fu in funcs: + xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg)) + skip_ci(reason="Too slow") + if not xp.is_incoherent: + yield xp + + def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. diff --git a/nevergrad/functions/gym/test_multigym.py b/nevergrad/functions/gym/test_multigym.py index 00e53079bc..eeea1262ba 100644 --- a/nevergrad/functions/gym/test_multigym.py +++ b/nevergrad/functions/gym/test_multigym.py @@ -54,9 +54,8 @@ def test_sparse_cartpole() -> None: assert min(results) != max(results), "CartPole should not be deterministic." -@pytest.mark.parametrize("name", ["LunarLander-v2"]) # type: ignore -def test_run_multigym(name: str) -> None: - if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: +def test_default_run_multigym() -> None: + if os.name == "nt": raise SkipTest("Skipping Windows and running only 1 out of 8") if "ANM" in name: raise SkipTest("We skip ANM6Easy and related problems.") diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py index a516986ced..2f131cc36c 100644 --- a/nevergrad/functions/pcse/__init__.py +++ b/nevergrad/functions/pcse/__init__.py @@ -5,4 +5,4 @@ # Based on https://github.com/ajwdewit/pcse_notebooks # MIT License. -from .pcse import Pcse as Pcse +from .pcse import CropSimulator as CropSimulator diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index 3776675da0..72cb2d6346 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -8,7 +8,7 @@ def test_pcse() -> None: - func = pcse.Pcse() + func = pcse.CropSimulator() x = 0 * np.random.rand(func.dimension) value = func(x) value2 = func(x) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 4c1de1dc57..ce19ff77e6 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -738,8 +738,13 @@ def test_ngopt_selection( assert "MetaTuneRecentering" in optim_string if num_workers > 1: # assert choice not in ["SQP", "Cobyla"] +<<<<<<< HEAD assert "SQP" not in o and "Cobyla" not in o #assert expected == opt._info()["sub-optim"] +======= + assert "SQP" not in optim_string and "Cobyla" not in optim_string + assert opt._info()["sub-optim"] in optim_string +>>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341)) def test_bo_ordering() -> None: From 895bcd444a1f2bd89c9ab4d7aed3697bfa5fe362 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Wed, 2 Mar 2022 21:30:40 +0100 Subject: [PATCH 095/140] fix --- .../functions/irrigation/data/meteo/nl1.xlsx | Bin 208384 -> 0 bytes nevergrad/functions/irrigation/irrigation.py | 1 + 2 files changed, 1 insertion(+) delete mode 100644 nevergrad/functions/irrigation/data/meteo/nl1.xlsx diff --git a/nevergrad/functions/irrigation/data/meteo/nl1.xlsx b/nevergrad/functions/irrigation/data/meteo/nl1.xlsx deleted file mode 100644 index 93c6bfe2d2eab5b848cdb143b88b92bdcbdb556a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208384 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%0AAK(jnzN*&}6F9L>siHM6{WBJQE@EDu)M z^*gHY$!&>_a{YYvGF7>Gk18ydZU0fB#o|nY7IY~&|M6F-0dNNyKM_%kj58Wq z(46^=Qu*^a3$CoLcLfI`H_gO(4=rd;dG0yq8}3+m%#PETl~JbSJZ6D6h^+IHH!)C? zChLuriRB$Hc~xwVQLE!E&$fMF*Rr0dZ-A+f3RCCYm@)8;0;6?Ur%`-2C7~4WXv%I^ z*%qkHtDb5m>MCH$^85;zv_A8exPB)LV3fYu396ra;C)*6ouKin`h=&aPAFpc%|z`7 zOt}>Is&|y}+M-K2QKeMxfUy@&bT4!dVQ)DHNuCMQ6E!E0W_fwNrWKuY3~9yDzt3@! zYG=IpZ2L(??WQN{T;R;o`~s%(9oQcDW0rPGQ8%B`J*AL_-1U;ywKTjz?>T>JG2Wa(qxeqa?c0XPH;ppn6%M}e z(@L}v&~cWhmzMI)+ldZ&+;gt4?r>B{X(d_`An#*BUe3Qi!Q74BOG)zZ-ygS%c>)m4mt*<9qN8rJn&_y1>b0&@8 zIUYfucF}85QNE~pqGg4Kvb>pBWO?TnR)D8xM)4gH;kat8yB%6qWe}48-diouDgzOg z=U2)+qPoSNcRY=VG=u%qvq!YuK*V}N1a9THW#<fODk}` z<^rnBdiUx_Zvg0VDSoxYDD57nHf_tFicSpP1w$ryakkBAU%0z>7hh*ij<&t%!J84t z1TW4pbG9$zckTh_7)bKmt(nG-#@|-8MJ9N0cFgJh4aa##RNMB}c_n^Pp+jx8FH-Bv zvnJf5r|$yv49Ju9T7|xOp0D1=9qKoFIKYWH{Zc({xPb>dv;3)k)49e{N6?=?KA-jH z$rk(Y{KzOl zfOd62yC$H0C!k#$(7qecz8BE03uxB|v>O82_XFAw0@{rM?WTZsb3prHK)WTN{ck|K zHK5%V&~6WCKMH7f1hgLy(Wn85KWH}30Kcs4dx_TBn8nsaGkzdzAcU|dDi^R z#5oHMW=@S?&WwndlD)<&Ww(DbI^U6JZ}^(dsa~nER zRjco)R`!N$iN2H3PYcnPP3;Dc%Cc?Q(u}UrXW7?E_7Zw%=mnilzgDtQP1a#xrPWH* zj6js-`DJ-~RE}JCWSzC98s?<_1ftC8HOt5$tVzBRK8y7Z{K-b5mIb16naV+!j_BGe zyiQ(9-ydn>>!}G+JDaoip_fSw4g6SMn|=by{jud;FM00Q_h~L(pXF^KY+hfW!K>iw zGa5?&2YKXGM%q9~yY@S*%h*@CEJ?A%&Zb$5-7sk!ZwTZekG$lKSl)R$-__m+^6Wj; z(x=o4Y6bqm&z>hnn*wy1Q`!SwkvNGIb4IVK))OrcuwzcVdTCGb#==uvs7sA~WA+po zC$4oik<>l#bFe1$M5_htSRQnW<=s@st4rQZl82t^vVI#=UJ$uJc6rGg@5#e=?GAay zXNz+tIOBBz?II9mPOtV>IaWOClmFU=R-*L;cFd_vr6_`&SrNDgJ#P! z^c>FZv~8F3nchmRqv%xD4do1NC889XZ9{1`TXy>d-i1uG>`_*W)TC9z zpSHb|yELC2XMINA$z8ITInNJ1?9c6H;yi%9v%Ks{Z2@^aL1B4!OP=TXGxDVFE-Wzh zU>#ECgVe#(A@#)h1l?!Z@TG0N?wO=F?y=rbL?~-@>uL90w#)Uzxd@GDd7GV=<=tDz zb42J~%X17P@8!~qtcg3PdPt-y{hdF!x#{-4`;k#iExX1azELI~A2r=b} zmIs6w`|^$?R<&y+YBiw5Wf*~2z1mv+Tyl*)TdSYjT6JtUHLBhj>9v*`5h$@dk4?6? zC#toYm1_TB50575P1sFy`b?6~b9p_|TSq^r*4T!6ee+<(f7$QT6Ll_7VtI}@=AGuH zSd)%c!-#KrP5Vp9sHAdD`^$kf9JMu&Q`Sz%@hh-3`2&$BF`B5;ft*hWIX>Z_c4f{~ zy-@p5F|Rq3>fqG8)`_KR#F~lr0C=)IMcndwwf9cy!;=v3uw>^*xK`nPd9)=!ndOZi zLM5KoIzwxaM~c2{CR!$7tSG^6R4^BhwcMjB z;im`R@$JP{{+qPsqb?!Gy}9P?*O*of7_+>*j~8>mCo&$F?EIR?|I^-=$Jbd^YwweE2rY#W83NXLfB>aH z%NPbL9HawtODRywVAABY4Q-Q>q_n~n4-`be0R$NoHGqO%5m7|EUX_D@0|Hh78NG&4 zMlCW3TIhYA_3ZbY_nfS7`+dLOKfdpm^tVn|O)a*}aV4j64CB0db|vQZbtV(sG|R2SyCgLQ&?v!KY*H`SV7ZwDE~l8jk;o#nMaBn%de>k|e9o#z(?w=0sUk+}qgL~J(z31T8 zRpA)pQ~zN3Gy=3TJ7Dv7?NhTAXyv#=RX&(n3d=UbEZa-Ba@3iH$SBTD-Mmw|{{`pH z8)a6MU%t&KnJMCUmv?#EtVKG;f7+~)a@y77pW^_QP5f;9$DEo@Yfzl4h_EWo5)LX_IAtK8`SK-m~*pP&(G}hILtKSt=sur_S`7r*D7Q}slR42(Yq*5 zTjcthY=JV7V2%<>RXt3N_-n+JO3L&$VKCM1z`JzHOE# zu|=F)zMYD~n*u#9H12TIIIZ%IOuNl$qL+u>A}9=$cR%=pEdShTN1 z>%awDaSQd7c$I$Ar^7O-CZ=VweHq)OlL?IcJ!{w)==q^#qBMWY=VVFNnrzhf+9ki% z+M`)>d_&bFm$YGGVAKFD6F>99aqgzQhRU}f-y;dXYZ6uoIz{^3l!O}s;|=JOxZ!?f zX~lb~F~Ce3&c}~BYrY9HbM$CjFE8iN8J93tftDFR*||h2S<+~Q!?I{;2{SUEor=uM z8TIm>7DeiM^OLbS-w;h_<9U}9Bl9q7aAclwa5WCD*1?T%a1iRC=zo-h8|~og9Nb0@ zZj6H)>)2UqXlHgj+d4(g@fDD!ENQ>8Xer$4sII<_dy3Y z-obsy!8JL!4_Dzh0;qqmiy8r&-9@d>(UWE3`jg_iWyH&$MIYD{sHL!WN6^~wZbCev z^<8*o#n+ipj5D-fT|PB4Y9ugm4{61@8x4UP4r^!p0%Bc_?V3?FppZpSE~I7@EwnH? z)v(6Op%tQsslZ)m0f?E}ZCQGba?rlM_$E>*uAv2hJxo(-4I%DEHcKi`U$F|%7-%P;N1}`~ zmHOC*I%|V^M7JB%sSW56_E=r2$8;)Boq9~QF4c~92O4*zX`Jb5%-zI&QSxeATHjPg z6SPjyEu#!a{W|K_7}Kr9pVM!Qv6?df$X+79xDUQ!J-Rv2vO#ymPw!q@CNJK?f*GCW zWn-;n(pAlJ##+nL-h`u&RuQ@*e$#JYx!99L9W&k0zAf!Wv$K8@|JoR6JK!yc=_0+Mit-WwhDQ zs0w}uM!nc{Q2jQI{45HNaa`pnqrHcoiJzi+%ycLz(`}7$y%A_H!jrdLtT+%!G4rq@kHMg{AU;D~4T4zL*$XcY&;b{rsQ%#?w(0@Bd4QtoOo}Pt)jGBBVcdhUZKrXa?^}%bIC1cL(E!hE?(*f`Y`B8 z1-}scb&Em#wn+1fwuAeJ%F?9&gPw?Ad<)#{ioL0k$!R~<0&8WuWzB(J5*i^&yE7Is z*By|9PVz0xiDPH0lvU8of2(N6n=5KU4-1VDzj1f4M6-wK7(T9eG>+WIQI;EhIyAy43)`~Hm_^cC zPcgHOqyjXhvYqt&un{U#S{Qe-OyJXc(@LH|_dl1~$@l<$FUonA8?m`N?;HeW(X6^; zR*|`C42&Ys%c5+jY-w?24VqF~BOlomN3ZcSYgIiS7=fVg#m`n~;{MTZ$>Pql64-kF zBywZCJt4;1Iwg^@G^1`s)k(HnI7Q>a@q6+wo+ytRRA<7sb#U7`xa}QWvxD2g!R_ea zc5-kN9Nf+hZlZ(R#lh|B;C6FxlN{V+2e-R}+rz=_>EQNqaChigWK1^?dRb3 zcW?(dxQ{rvDGu(V4(>n)cTg3M`GqWSuvQuY{Wn6>ky(o)Dr+N3@rc&5vKmpr>`Bbj z?ZVMfvg_1c*sz&q!!CZn_~oNr-!?Tu<*&DmcAa}v@nfHxr}(u5>OCx*@himBgEubH z8rk}tcDIHO(T8$PS^`H0ESpglJN|$t7&)*U#lOtGd$-x)lz5|TRhhaiv9Q1>le|f@ z)jP@5GiGc~c?Z3p+U!PF9E-4hl8^2yl<$tWam_-lk~x3b;xH!Th=uJFrS9E`@19vk z+4B8~3@a%)u3_aw+5amm!Qy_M1{l{Ems1{!U1D$I9CxD}5G8I0)f{L-#T9gQCp|Q6`m93GE4VW|ry9Z&|;1ORchU@_QD~qJ1IV$Fw@oj!Md6xsT23 z$FpB5%cO0Bb{J(mt53VIrC0BhpQi=wqf9%8zBkI;%s)hF z?v|3KR-Sj0H0AY+$3|)HmeMfo&)Ut=u;xI^2|bZabZd{Tsb_wDIVFo6qIzdis&`cG zB&T;81FbH!N9~>Rp!H62Q`+Q|h1lJ8XiT<|!MP|$#pF~OdN*aVQ)isbZe6TL9s3*N;6!i9L#ktdsf&K?SA6N+B; zD!20LJ#22Yms)8nJ$iqya)#d&=&PWK=~im(A2*gN(jJ``_rdmd)WOGG2pqhp`NFM>U!C7@w1# z4;W?9C}Vt|_76>g5f607D062SrR+f1FKYBbR`2xr1qZ2L<7#r5AEW-8;~sZK_BubY z{N^aXB{_BOcu&q*Oip7I6|?L))T^%Qyv2hZ+{YZ;Ar5Y;gPZ2yraQP94(?C~cbJ1a z+`%2;;Er@~M>)8o9o$R@H_O2t_Hw9`uEL*C~O#Nk~8IjynbI2g; ze27M|TN92JST^zdy;%jVPOr3@#B52g)hAsOoRV&og>+5yK6-2eGYv6^UD1Y?z>x-y6T&*Nva{t%iNcyU=c*ZKSDMQJ@8YSDVAW4{;TDCw|BInV=k)&ri%A@u`#e zV-L0j+6j0yQHJmE31!!CP7A&lQzuGhF94=oTUrzJy-^mXo7^OE-797*;;1NT@RO#b z%|S1V^1tq9If|w1K1037;d#E6K+A+U$S8AnJZ_ZqOBtPHm^&8V{a&X1LN6O-@g}=L zJ;t4Tkv_+`)1zz%v~uWWQR4PV&9r8w<_27CX~uK4fjsshKaI9Hzo~3JEhKtbZTPr( zZ)uJ0I8cr)=7`gjO@Ve4y?mUFaQSK5*`3KIH|aQ_PKD z*7$`(?qR(#dKE{^PQ?*>S{yN3aYSK0o{O1C)v}~ZwBOJO@!P9Ne#&y%N&4#1jGa4F zxx&^IXyu_1qI~#XQfiJ>y5Vb%l|JX0Z+_+OtnOf$6Qh9@e7YjyY6|oa&=c`H%i?*> z0r$H;Mi<8!Kiz01e#eQQ)=ok*TUoMm^e)gI@q6Y@mZ<#^Q?HHujyHZCc9pF79WQg9;^@jCG_xk)5E7MlN4`F zPGYwctpwg$y3eVS#)&Cuun}qL($~TU8NXtmjfmZ^Kr1s>-58}i&-m%C!*^}|I?wo} zXE*b#*1UNy&6_?OI;pzGjFIs!-R^Ue@z&aNu=bxci1$h2ZTF#(J@y#09D{4?3akn|R`3|n#!F4#eyn|cd;1)W#MGmgh!JX#d7CX2l4sNM~>vC}24sMx) zJKe$cIJjO1*XQ7tJGe6(+zJP`(!qVg!JX;g&T?@7=HNc*;Ldh%pQ^$!;->z=A8Q2s z{6UT}WqhaD*y-1(Yqimx&ZxHpYANjC31$ZyY}6@o>^I6()KzKmS^{+$7EhFaV(g^T zP?H;y+HIttX85$NYzWkN*fUX{cwdZ0+EdYp_C>Ut)z4gI=PKt;jge^kAj{TnmaVdW z69dN(ESr@Qw9|R@r&%Yv<26%I4yQGzy?7nQLwgr=4qiuvzu@SDHx{>d%^UZhM{c;A zL)ojm*~#==KW{Zfz4%;(cW(|Hxv+MUL6dpUdaj-7t`DC4qCDz?RBM&_Utl$jr@WQo z7LIz@K=Io|`5CKUj4JtVRy^0ZVqLf~&^ADKj52q~!+Z|$jr{l`>j6ncdBa84%8X9s zvACd8?#+RA1sXNiG-?ZrQuTgVt{=P^^{Zu_gId<<^kYk)O@f|@Uz2%Oy<3TUhA3C- zM`v!+5@@-gXGR&~O=q^WDTPyF@t=`sHiL34DvD_SJxuHFh)RorT zI=K*0C0c;FzIuC^)moaQy+O;|-lo-u_MAxVDSlR2VzXGtsexaA8$X>)ZcCtVfSwp- z;Vsh>i*+*NttObsvKQ;@Gu?)kKo0^v5v9!nV+_=28debH=2r4D(w9aZ{S5TPD8u>p z@d=$k{!=S6YmtX#Z{z->5+%J6^hA`4%wj8MQNB|1-~BkcS6{9bB3eJ6T(9(y_1zNVOg)|f6VGRi>8)H{N#8$B#~*(eM5 zQ$OPQr?|75WzLWKc4lgnXg|%FvYQpNqUJ#FjJ`L1xpmeLr5rBX^LDgWXARI_D-BXDyv`N5he!ue`thSCXb-;uX_cg5wP9zSD&=fHFwZ1!%wEh zd}Cnb04*_YLF>6#@03+PJ7v{1&d=63H|rF48CGRV7ubi?<5MyAg20{NNi3a2*z-aXOD7oRvh`%Lcf5caRL9uoIJk2i+$slmo`XBz z!F}4nUEtt8Gy?R7C1$o7QH7M}RKBC25j9|u zcU(Q%t28dikGcyRc#_3Qwl|J3yZD_`=7)R-^A+caUop=S7Edqc9+kwVHU{cFETi}- zlZ&0g;&*Op#48haZmeG$`6-`OVQCuz#|$i^_+gb>Im1;cZ?T<44Xet$)H@F_FyH&`}E}2@$*tM0C}SGjCUrk;#ysuNUt$)+`@Jmzkv6h&?e-F)%Nqt zvW!v9`Kq7o`S8{R8w1BYtf%qIjWsWWC{Fx7o#Lmy{&Z|_JImEOOBK8Qn*;3ytf%Vt z&mWsaCh}?BbW&`OUh9HEUgiR`^BG$~DEBpO4RlfR(_M?D`hBL{9}A>ApHcm?raKl> zXa`Kf4=17nR1tFzGih@8@=F#sru<{g9}wZ?cXl>ciK4UqWHxd74*dW-H2-GqjdKTMM01O?2a{ovyw^AOYEz)MfWHfqEwz-4f`rphv3f9=1NCyS{F@9=t=Su}_OIwTr&gO8PZuj8Wz;P%CYB#GGV3 z@N%oktj}H9)v)S4+m~~Blvu(;Z%;f|&J2Ia_bk6vNfz^D% z-spxfBfl$+AC8fw@U6X9s(!L{6>p0)1p0AkqS|}K-BA;-Dr+M4i12OFt4tGd$*Aec zRaS=f{sfc3Rk6+%Q&!yc&=eRKKod`;CKl(~I4PP8FsdbktBv1pubuXz*Wdl8W!tYd zewu-5N7~h5+w@snfFTV-nsj6$GuqP#-$p*=|RjYM<4 zVztuRmU{XtlB8wCD=kn{U<3nAG=4!hm)T9Q0c)vhxx9cn48+{ew|-k_ZG<)qgg!u>|6{H1-CDXGh_VWPa( zY`S)1%csWix{cMP@?9TlJZzXKZLKkAZ=pqknV4PbW1TDV7dSuNC|gCTH3*$DrHoe0 znOZif!uPiXjvm-0QCf@^Ps3D3D=2r(=)YP*9AmIcMj7t8hqX%Q-xS@+7TV71L_*Dh zBN2814l7>S^Qp?ZMCSudO6xTcrj&f zzGXa;m0x6#~ErH`7J>SZn4`Y7Lc3Cbc6gY>>SYA=*_GS9dOVtDCqZ?&bl#+?rN2A_ zV$tRPYYDV`&<9c48-6jDX(+pL#c zZ)OcGMvd+4SDAz7&p4;tD6>Xc__noEd!3eDM=nKDdZ&3e1X^VDvQaY5RxjV0>SdmF z(TwNV%W>bGER8esZVI&K=w-FxNQ*{WuVU%Q9xF!q;h@Owhc>1ZLsh@`M^6A-Abu93 z#Fb20t}JbyclQs@DL2Y~QGWGD_S{aaiL&^uW-XQJsCt{5UIl$`lm*SEv3FRr{o73r zHc~NzVkYKxYflCX7fBj7GCKK)gG4$uZBcNA1=A^jFK zV!mla%!}_#8d;^H>96f#*1A=>OnSE&AuCFad))-56)TgQPR2pe0p*v*DSaR`LX^7K zR2ggKCJK^x18X4-C{fZ=qVGkiyHst5QXJs}?bc44b5vOT=0JanUN*|YoAgg{eeJ62 ztelQ$eSc<}lGsVU3-mKt->N8+z8K?PHPK!v?ZZ>dZlgEmJgQnxkBz<;rM*!Wf{otr z5!R%*$m+v+U3w*g@#$Q<*)xel^;_o?dV5HcjCT2XVz_sth#FMKr*}HIUpTnC9NgUw z?j8sCO9%HW2ls0S_ZtUyuY>!ogS*ec-S6NYaB#nKaH}2M?;YG99NdEr?jZ;Fu!H-f zgL}lmJ?h{db8wG4xF;OklMe1r4(`7k+@Gs(v}e>m_%Drsfm^8Q+96SzOBc=JrFVc8 zqXjqbz3cZtlh~7nK;4B6Yd0H)o9pFa?o4?Yy#aHlJj|@CZT^3!m9dn`oj>R--8<7| zm`6*>z=`HoMpk8*g-y;i*duzKUl_k%9kK6)2e<0oq+b|6?;Hr6Xm0#+#xKtKb*;WQ1lsXI|T~1mYL(eXFv19Q&}B;-~j$6}@S%wcd#gvi#|m;S_VDEQ)dh zBab8(Vwn!xgB)k_Rb|qSK+iX|tGNFi9#1Dxb8O{9k$(G8#+6(B8}_a*jkVxZrG?ulQFb+;wI`1S!K%naTS)ok-Y z;~}ow>!kD4Y!fG)8@JY2JD!-Kw*t8aBD#qy8KvKm!H?WmXAr72ilFFjTTw%7^gP| zMi$UM@x$HNEVnW8d))Y$l(#0o20T3?pu~Q&UxfuxhaOM$M#gmL@l}iZC7;GSuF}aTjfb>aXLCMjJ>y#z zMo7>@<5&3kT~(KjTFX!Vr2CO^6!c6rv9(*>93Abl7t>kfW9&UUMB9Kw12lu*zd&9xK>EPaSaQ|>{Z#%em9Na%0+`k;$S_k*8gL}`xt*gQ@ zBToH;Wz@LPsmZn`A2VhH^Em<(@mGySYAHPMLbHsQU(e@c?alUPvb2H8j$Y2$6F-FW z(Ty@I%ADC$%bd~!%bq-K_C#kQ%bq-K_9VGEaZZX~OW-(wy%Rs2&5Ck$s;#of1+#40 zSD?2Dqcv^_94)YHqJ-a)Rd_ZP{n4K`+9Q6_9-A|B4My^N z!}ujJJ+=FdC_l5D75rKP{SmZB{NnAH+?gRAh<%7T>foBtYr)Eh(r&bhXJTV_qH6M% z)g-aJoL#(SHA&BL-;z#O?5k@D^nS2I;;k6lBpm|Z8OX%U09Ro6la>#CB=k#^x|>w< z66~W>t==9a@3*78N04__P3T{tU#FRV#r2~`KBu>b7d?e&swA#&SN=RQ!I@+`g!P# z`00#b`2+Y^$z-j`B(aF>skNz|`hevQ)>=;~F4s<yZPz<@ zu&cf6ti5`#Rx!akjgca~Vn*32lb@{!lyI~8V6VF;6^w&95g>@4uEbNgd6SP>Kxog4sMKt8|&aUc5vey+$IigQwLY?;5Kt` z4G!)D4sLS?w}pe-(!p)z;2Is=)(&nP2lqh-H{QX0$iX!^xDQw17@t%BU>h|qbO)g# z58TzrQOV4OZU(J9CA}q3OJ{_z*sNf@8I;~6&X`j%Mzs~BF2f3n((X~zJYIM1#d}d* z|3Zz26%?gvYnGgzNu#)SG&35!rSDJ8e>KluJ9;EA$v%3^yO*pWM+>Z=_{F;*%@gMm zt1!a&z47itD_`7EYYQVHzcbL*%9b?+jx^Xi@r(DNY3I#Ov3?_sU)rjUG=Awk;KKKz*(tpe^kAc7>KbA_H2MrZB-NLF^ zR{Nt6KWk<%Hq{%N8H_c~aSbQ77U!oMzgF?n&58qOvR<0eYQBk{vDU?Uj1J80(W=e} z1ySM_PI=IACMVUOyGWbyoXtIrYrHurzQdA^qFMqi@{G_gewvTB_7*9vKGr993_qjq zJrLg$2{#1VZD^Dz!&$K=o2GiK-g<0P)x`Qclbb~z>M^~g7iH2MX!D^_;%9fR#r-9k zmzHE)Z!%8$iZZE>GEUDIaDKY+3rkI-lnsv7XLGB=3tWlN8#5K>Pd5g773hvAWj|25 z#$G%QRlqI8R;GX-gc-4a(ZgKP=(vd{=o#`{M( zYmNCK)1|1J((Nd>#z0>@BZMyN``Ct#qIz)aR2w+MYr@mkgSHDkdG9uTvdzRmKMsu$ zKh;D%7;V{XN)x&yYqE{$W1^w7CflT}NlRb^0DTa*sF}yJUCK(BM7%eo8v^45=z}P6 z8nZ_K`1I&6vb^!uM$YLN;g7fWC8rT{o;cpdkhg=WF);3c=BNytC*suKD7z0CU$u;p zdJ~?O?AVL48R-5{?*Hb%m<9SIey|gKZf~?UYJ6^Xw4F^>r)cZJy8)E)m}!0uf$*J3F|E4sI6*x2uEO&B0Bo z!ZALjtT3|Ghc=#qy~7djQ{6`8xHKwZH&7C((+NfaxQ zimG=oe(x~|-eZkLd^;FFdBw`JzHz>|@#~NE`w~mEJ+X?s;_WkGdN4#5;%6CC*l`R&_9zk zvG`k*NgPtydXBIep|w;K&-O3zcpOusxhv<7zDmPaD8BpQ}PiG3#jK=Pk ztB`nO;An-l7NyPNa1vv*{*$c5s2IdGe;Ax?d~z*FX~?2(@XKs@9A8)s4v^QysLLnXIFkwmYvnv z)tB#C)|2lOgO2>NJbEPC-DR|Av@KcAXR_`2B}=l?_n(wK4By*&^W-PS2|IiK;I4(e zeLdYvvrD@>@=Kru3-ea@6=*``0|#e!%zg|?kYBK%v%NFl)z_Pyz(RVnQ}^FBJ8l1+ zvnx7LeP|%=|p2=>q~8(_eiTyd zIB?1lo)mE#Y?WImzOZ4XI5J9c)R0mf=}7T`OAo#A*`{p{`PrK*ZhG~|r+&6RQrxp7 z#l41#MJG)2vOLUTTVHn1rP;Rm z-7tveV3+qSXlu8Dy)+MlKDjsF4$taJ^{DreD#EEMsSf;U!z$$HDAl^KW33;jjCQ0t z?$qC$^80IlbmX~5{&KUwUEcWU`bc%>l2j)SCDop`&aMS*a5KFyknnO#m%0+$`F$i- zH%MZ$Hn7C%!t)k|j0w*V;Z5osi8Vf)>3Zw)g{e25{pE2_+_2j@>m#vkOA^~|u*8n- z>RtgKybO+<@qjO>ZQn;y8x4|F_L&W;qM{(ci=DAL&XMCrr>tHu;n-=1U-0ntH-Dk=oGsU9Znd~1$0dX1$SF|8 zG=!q#n5~-0EWl(c-`m%@6pC7&f|VvA*#$kAF>xw{iIpZsuH+X(^7*h3x;uDQyU8HQ z-vZs;@RDa>P05c8JJ*cGe0i{y+{BUm<@X%<+|=0PUX}Vf8;b>#1{&yyMrcXaDx< z-M_v*l5Z{Pe4C^5J#kLYc|3K!y?e>>rCr&>X3su&D$@$fmvnIAT}llw;OvdleJ79L z8R=FiI@34f!!~Fxe>Mu6R9B^4e`VTc%#eR&-f8TRf33w|HyQG;?ALKa{#A)Ozg9{{ zWrm;~W2vT^A^*xc*ADqt)_KH`e`TFV4*6HsdDM`9#cni6d#Dz%AL^XH9$3?0M<0Zc z!xQ}3H47!Hs|VPBVJ0CPqhHzKTi4js&VBr}leXjWk({NwM1bz1=< zJ$}^$q&C;BtDS1&t&AW3ww@ArZyhB^{i^)o7#cYL>wkY|=A!!VTv``)+3D8Db_ebj z0K0{M&jHwXhXU9qtpFyER|4=}5L^;RO9Kc*#PH9s1coIrEP-JO3`<~G0>cs* zmcXzCh9xj8fnf;@OJG<6lEC}T|7#w;|KV#UeX#zrD>47y^_`nJ|Hn$HrD8b$p9SE? zwz+_<0LuVl0i6GHZeIX!-v1c@GV7&$z*YFp`~Y?`4bBI&EzEZzBcAWd9yc3**F3)7 z_~O4q{%%5ntP{(fY1_i`9Vg`5kd5pK8w1I_19J|n-wEA4i+dO4^L@R>o@B#6!x9*l zz_0{{B`_?3VF?UNU|0gf5*U`iumpxBFf4)puO-0AFXzUbXLBuI`$4qE&ozB+yWrjx z&YL-B=XyT&gV?;EbM4IlT=VBVe{;YV0M7N94`>8nD;hfGYr3 z0u$w*cP;{5#+~fSUl{1>6ky z9^e+h_W?fu+zR+1;5NXI0Jj5v4EPVgPXPZ3_$lCLfS&{I02Bdt0)7Fw3vf5!9>6aF zzXJRk@EgFrfZqb{1KbaI0Ps7&YQXOSe*ioPcnI(?;E#Yu0FMG513V6R0`Mf@Pk{dd z{24F+cna_|;2FTPfad_u1O5Vd0q`Q=CBVyoR{*a9{tEaTU=83kz~2F{1Kt3<33veU>sl*z@~tD zz-E93zy|=E1GWHc3D^qI2-q614d8=-@qiBjngAaLWC7a(wgYSrXa?*6*b%T3U;7s2>`x=dm>;S z;3UAwfKvdc0zM9C1+)R?1KI%{fIMIUU?E@;pc8N!U@>3`U@4#r&<$7yI33Uf=mqov zmIKZJtN^S8d;)ML;4Hwu0X_*h8}KPW0q`Dn&z+0ks{rQ#&If!NZ~@>m0RH_V{Jt3Q zS-|H2p9g#aa0!5af42&V8~*u!LjtqmNxI=VvhaLe_}yb3gT`U~ezt_gNLpG0l58D6 zWn1xUy8Wl>gZh!6PC)5B@NV<19*Yz7djD>K^-9X;@AV~oz#<;TJIBIjF2%n#Yx`l4 z!UC%kF@5mA-R5tH;yVH5V;C5>^)3G#64Z<1NJJgo@cyhr-g@BwtUmkwU$p Date: Mon, 7 Mar 2022 10:00:32 +0100 Subject: [PATCH 096/140] pcse_license --- requirements/bench.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/requirements/bench.txt b/requirements/bench.txt index 4543f08b63..cf78ac73a0 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -36,6 +36,10 @@ Keras-Preprocessing silence_tensorflow # for olymp tensorflow_probability # for olymp bayes-optim==0.2.5.5 +<<<<<<< HEAD +======= +# pcse>=5.5.0 # removed due to PCSE license issues. +>>>>>>> 87100b95 (pcse_license) pygame>=2.0.2 pyyaml>=5.3.1 nlopt From 6cb100c6fe6b3402ac1af55fc1482bc5570242fe Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:18:46 +0100 Subject: [PATCH 097/140] fix_details --- nevergrad/functions/irrigation/irrigation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index a5642212e8..2a8e58a392 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -13,7 +13,7 @@ import copy from datetime import date from pathlib import Path -import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. +import urllib.request import numpy as np import time import warnings From 15f06c8bc19584303ade9da1a3f935005d56b635 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:37:26 +0100 Subject: [PATCH 098/140] fix --- requirements/bench.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/requirements/bench.txt b/requirements/bench.txt index cf78ac73a0..914e32e1e5 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -36,10 +36,7 @@ Keras-Preprocessing silence_tensorflow # for olymp tensorflow_probability # for olymp bayes-optim==0.2.5.5 -<<<<<<< HEAD -======= # pcse>=5.5.0 # removed due to PCSE license issues. ->>>>>>> 87100b95 (pcse_license) pygame>=2.0.2 pyyaml>=5.3.1 nlopt @@ -48,3 +45,4 @@ box2d-py>=2.3.5 glfw mujoco pcse>=5.5.0 +#yaml>=5.3.1 From 594b0bccac4169339c16cebed30348950414ec00 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:40:31 +0100 Subject: [PATCH 099/140] dependencies --- requirements/bench.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/bench.txt b/requirements/bench.txt index 914e32e1e5..993a86da7a 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -46,3 +46,4 @@ glfw mujoco pcse>=5.5.0 #yaml>=5.3.1 +#yaml From b177f9ca687db9505f4d74272230cfc5fdd1c34a Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 10:58:29 +0100 Subject: [PATCH 100/140] dependencies --- nevergrad/functions/pcse/pcse.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 69565af788..3c98a01ae0 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -20,6 +20,10 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: + try: + import pcse + except: + raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider From 77e7a0dc52f0515f47ac0e5b17e6cd6cbe122351 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 11:02:36 +0100 Subject: [PATCH 101/140] dependencies --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 3c98a01ae0..8cd6bf5af7 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,7 +21,7 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - import pcse + import pcse # type: ignore except: raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_PP From 35cff8b9958297aab58fc5efcec0a1b96121718c Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 11:42:20 +0100 Subject: [PATCH 102/140] dependencies --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 8cd6bf5af7..0ec35c313f 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,7 +21,7 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - import pcse # type: ignore + import pcse # pylint: disable=unused-import except: raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") from pcse.models import Wofost72_PP From 46882dec75fcabc9da50d6969f30f48f410f984f Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 12:03:14 +0100 Subject: [PATCH 103/140] dependencies --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 0ec35c313f..24cd95af6e 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -23,7 +23,7 @@ def __init__(self) -> None: try: import pcse # pylint: disable=unused-import except: - raise ng.errors.UnsupportedExperiment("You need to install PCSE. Not done in CircleCI.") + raise ng.errors.UnsupportedExperiment("You need to install PCSE. Check that the EUPL license is ok for you.") from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider From 9b9f476a28f967fb1210a0eae8b2761c43846c60 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 7 Mar 2022 13:16:14 +0100 Subject: [PATCH 104/140] pcse --- nevergrad/functions/pcse/pcse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 24cd95af6e..027847f204 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -23,7 +23,9 @@ def __init__(self) -> None: try: import pcse # pylint: disable=unused-import except: - raise ng.errors.UnsupportedExperiment("You need to install PCSE. Check that the EUPL license is ok for you.") + raise ng.errors.UnsupportedExperiment( + "You need to install PCSE. Check that the EUPL license is ok for you." + ) from pcse.models import Wofost72_PP from pcse.base import ParameterProvider from pcse.db import NASAPowerWeatherDataProvider From ce07748ee9880e6f4c0350b0fa09addb33a05ffe Mon Sep 17 00:00:00 2001 From: Teytaud Date: Thu, 10 Mar 2022 21:40:39 +0100 Subject: [PATCH 105/140] Update pcse.py --- nevergrad/functions/pcse/pcse.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 027847f204..fa080a11b9 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,18 +21,19 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - import pcse # pylint: disable=unused-import + raise Exception("We do not import EUPL code by default.") + # import pcse # pylint: disable=unused-import except: raise ng.errors.UnsupportedExperiment( "You need to install PCSE. Check that the EUPL license is ok for you." ) - from pcse.models import Wofost72_PP - from pcse.base import ParameterProvider - from pcse.db import NASAPowerWeatherDataProvider + # from pcse.models import Wofost72_PP + # from pcse.base import ParameterProvider + # from pcse.db import NASAPowerWeatherDataProvider - # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider - from pcse.fileinput import YAMLCropDataProvider - from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider + # # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + # from pcse.fileinput import YAMLCropDataProvider + # from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider # Weather data for Netherlands wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) From ab160a733c24639f27bc7da38856d9fbea0563f9 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Fri, 11 Mar 2022 07:00:37 +0100 Subject: [PATCH 106/140] pcse --- nevergrad/functions/pcse/pcse.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index fa080a11b9..80ba3e3878 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -27,13 +27,13 @@ def __init__(self) -> None: raise ng.errors.UnsupportedExperiment( "You need to install PCSE. Check that the EUPL license is ok for you." ) - # from pcse.models import Wofost72_PP - # from pcse.base import ParameterProvider - # from pcse.db import NASAPowerWeatherDataProvider + from pcse.models import Wofost72_PP + from pcse.base import ParameterProvider + from pcse.db import NASAPowerWeatherDataProvider - # # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider - # from pcse.fileinput import YAMLCropDataProvider - # from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider + # from pcse.fileinput import YAMLAgroManagementReader, YAMLCropDataProvider + from pcse.fileinput import YAMLCropDataProvider + from pcse.util import WOFOST72SiteDataProvider, DummySoilDataProvider # Weather data for Netherlands wdp = NASAPowerWeatherDataProvider(latitude=52, longitude=5) From 0e79f188d9ec3e9fe708ec429644af81e8b5523a Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 2 Apr 2022 22:06:24 +0200 Subject: [PATCH 107/140] fix --- nevergrad/functions/irrigation/irrigation.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 2a8e58a392..82edc2ff8c 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -172,6 +172,22 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, for k in range(1000): if symmetry in self.variant_choice and k < self.variant_choice[symmetry]: continue +# def __init__(self, symmetry: int) -> None: +# data_dir = Path(__file__).with_name("data") +# #urllib.request.urlretrieve( +# # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", +# # str(data_dir) + "/soil/ec3.soil", +# #) +# self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) +# param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") +# super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) +# known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': +# 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, +# 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361} +# known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, +# 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': +# 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336} +# for k in range(1000): self.address = np.random.RandomState(symmetry+3*k).choice( [ "Saint-Leger-Bridereix", From bf2549436c95416064bf714b62b7b94070b44295 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 2 Apr 2022 22:17:43 +0200 Subject: [PATCH 108/140] fix --- nevergrad/functions/irrigation/irrigation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 82edc2ff8c..2f6aacc458 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -244,6 +244,8 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, self.wdp_extend(self.weatherdataprovider) self.set_data(symmetry, k, rice) v = [self.meta_total_yield(np.random.rand(self.this_dimension)) for _ in range(5)] + #self.set_data(symmetry, k) + #v = [self.leaf_area_index(np.random.rand(8)) for _ in range(5)] if min(v) != max(v): break self.variant_choice[symmetry] = k From 8a11ad1c8aa0ee5d2ed500d86358a9e889debfca Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 2 Apr 2022 22:18:32 +0200 Subject: [PATCH 109/140] fix --- nevergrad/functions/irrigation/irrigation.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 2f6aacc458..6cadceb684 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -235,6 +235,7 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, self.weatherdataprovider = WPD[self.address] else: from geopy.geocoders import Nominatim + geolocator = Nominatim(user_agent="NG/PCSE") self.location = geolocator.geocode(self.address) self.weatherdataprovider = NASAPowerWeatherDataProvider( @@ -431,8 +432,8 @@ def total_yield(self, x: np.ndarray, year:int=2006): return -float("inf") #assert ( # False - #), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" - #raise e + # ), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + # raise e output = wofost.get_output() df = pd.DataFrame(output).set_index("day") From 35c880ee2f463eb66819e136c7a7b44389c3617b Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sun, 3 Apr 2022 07:06:08 +0200 Subject: [PATCH 110/140] fix --- nevergrad/functions/irrigation/irrigation.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 6cadceb684..3e21471f5a 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -172,22 +172,6 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, for k in range(1000): if symmetry in self.variant_choice and k < self.variant_choice[symmetry]: continue -# def __init__(self, symmetry: int) -> None: -# data_dir = Path(__file__).with_name("data") -# #urllib.request.urlretrieve( -# # "https://raw.githubusercontent.com/ajwdewit/pcse_notebooks/master/data/soil/ec3.soil", -# # str(data_dir) + "/soil/ec3.soil", -# #) -# self.soil = CABOFileReader(os.path.join(data_dir, "soil", "ec3.soil")) -# param = ng.p.Array(shape=(8,), lower=(0.0), upper=(1.0)).set_name("irrigation8") -# super().__init__(self.leaf_area_index, parametrization=param, symmetry=symmetry) -# known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': -# 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, -# 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361} -# known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, -# 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': -# 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336} -# for k in range(1000): self.address = np.random.RandomState(symmetry+3*k).choice( [ "Saint-Leger-Bridereix", From 347d296fbc56ff7b38bc02ee09d830417f55d7d0 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sun, 3 Apr 2022 07:09:27 +0200 Subject: [PATCH 111/140] fix --- nevergrad/functions/irrigation/irrigation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 3e21471f5a..c966bb6059 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -219,7 +219,6 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, self.weatherdataprovider = WPD[self.address] else: from geopy.geocoders import Nominatim - geolocator = Nominatim(user_agent="NG/PCSE") self.location = geolocator.geocode(self.address) self.weatherdataprovider = NASAPowerWeatherDataProvider( @@ -416,8 +415,8 @@ def total_yield(self, x: np.ndarray, year:int=2006): return -float("inf") #assert ( # False - # ), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" - # raise e + #), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + #raise e output = wofost.get_output() df = pd.DataFrame(output).set_index("day") From fbb42a4aae78fea52c7f27fe845cde6df1100332 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Sat, 18 Jun 2022 16:37:39 +0200 Subject: [PATCH 112/140] fix --- mypy.ini | 5 +++++ nevergrad/functions/gym/test_multigym.py | 1 + nevergrad/optimization/test_optimizerlib.py | 5 ----- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mypy.ini b/mypy.ini index 6292f2770c..6315b6b111 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3,6 +3,7 @@ [mypy-scipy.*,requests,pandas,compiler_gym,compiler_gym.*,gym_anm,matplotlib.*,pytest,cma,bayes_opt.*,torchvision.models,torch.*,mpl_toolkits.*,fcmaes.*,tqdm,pillow,PIL,PIL.Image,sklearn.*,pyomo.*,pyproj,IOHexperimenter.*,tensorflow,koncept.models,cv2,imquality,imquality.brisque,lpips,mixsimulator.*,networkx.*,cdt.*,pymoo,pymoo.*,bayes_optim.*,olympus.*,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,aquacrop.*] ignore_missing_imports = True +<<<<<<< HEAD [mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] @@ -14,6 +15,10 @@ ignore_missing_imports = True #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] +======= +[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] +>>>>>>> 22234dac (fix) ignore_missing_imports = True ignore_errors = True diff --git a/nevergrad/functions/gym/test_multigym.py b/nevergrad/functions/gym/test_multigym.py index eeea1262ba..2191a765d4 100644 --- a/nevergrad/functions/gym/test_multigym.py +++ b/nevergrad/functions/gym/test_multigym.py @@ -56,6 +56,7 @@ def test_sparse_cartpole() -> None: def test_default_run_multigym() -> None: if os.name == "nt": + #if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: raise SkipTest("Skipping Windows and running only 1 out of 8") if "ANM" in name: raise SkipTest("We skip ANM6Easy and related problems.") diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index ce19ff77e6..2b6149029a 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -738,13 +738,8 @@ def test_ngopt_selection( assert "MetaTuneRecentering" in optim_string if num_workers > 1: # assert choice not in ["SQP", "Cobyla"] -<<<<<<< HEAD - assert "SQP" not in o and "Cobyla" not in o - #assert expected == opt._info()["sub-optim"] -======= assert "SQP" not in optim_string and "Cobyla" not in optim_string assert opt._info()["sub-optim"] in optim_string ->>>>>>> 1691eaa4 (Pcse2: irrigation challenge (#1341)) def test_bo_ordering() -> None: From 33fd981a1b0ee575549d3b9c87a189ab3c402486 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Tue, 21 Jun 2022 14:49:32 +0200 Subject: [PATCH 113/140] Adding tabu lists (#1456) * fix * fix * fix * fix * fix * fix * Update core.py * Fix typing * Dict now * fix * fix * fix * fix --- nevergrad/optimization/test_callbacks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/optimization/test_callbacks.py b/nevergrad/optimization/test_callbacks.py index 512add4985..b1f4626b55 100644 --- a/nevergrad/optimization/test_callbacks.py +++ b/nevergrad/optimization/test_callbacks.py @@ -36,9 +36,9 @@ def test_log_parameters(tmp_path: Path) -> None: logs = logger.load_flattened() assert len(logs) == 32 assert isinstance(logs[-1]["1"], float) - assert len(logs[-1]) == 35 + assert len(logs[-1]) == 35 # was 34 logs = logger.load_flattened(max_list_elements=2) - assert len(logs[-1]) == 31 + assert len(logs[-1]) == 31 # was 30 # deletion logger = callbacks.ParametersLogger(filepath, append=False) assert not logger.load() From 82d3bd9f1e18614f8de849135d97cc8d61c8baae Mon Sep 17 00:00:00 2001 From: Teytaud Date: Thu, 23 Jun 2022 22:07:55 +0200 Subject: [PATCH 114/140] Simulated Annealing (#1455) * sa * black * Register DiscreteDE (#1454) This is one of the best algorithms ever for hyperparameter tuning so let us register it. * fix * fix * fix * Fix type * fix * ZZAdding tabu lists (#1456) * fix * fix * fix * fix * fix * fix * Update core.py * Fix typing * Dict now * fix * fix * fix * fix * ZZmerge * fix * fix * Fix num params * Remive duplicate * Update test_callbacks.py * Update test_callbacks.py * fix * fix * fix * fix * Update optimizerlib.py * Update optimizer_groups.txt * Update optimizerlib.py * Update test_tabu.py * Update experiments.py * Update optimizerlib.py * test_sa * fix * Update test_suggest.py * Update test_tabu.py --- nevergrad/optimization/test_tabu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/optimization/test_tabu.py b/nevergrad/optimization/test_tabu.py index 643a9d154b..41bcbe9337 100644 --- a/nevergrad/optimization/test_tabu.py +++ b/nevergrad/optimization/test_tabu.py @@ -50,7 +50,7 @@ def summation(x: tp.ArrayLike) -> float: @skip_win_perf # type: ignore def test_tabu_sum() -> None: - num_tests = 147 + num_tests = 147 # was: num_tests = 107 for o in ["DiscreteOnePlusOne", "DiscreteLenglerOnePlusOne"]: values = [] valuesT = [] From 502ebc081ecb4a58ca464af69bc19636c1b708b8 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 13:51:39 +0100 Subject: [PATCH 115/140] pcse --- nevergrad/functions/pcse/pcse.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 80ba3e3878..22222dfbbc 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -154,7 +154,6 @@ def __call__(self, par_values, grad=None): # defaults = [cropd["TDWI"], cropd["SPAN"]] # error = objfunc_calculator(defaults) # print("Objective function value with default parameters (%s): %s" % (defaults, error)) - TDWI_range = [0.1, 0.6] SPAN_range = [30, 40] #param = ng.p.Array( From a849dd2f6a235dfaf8f0616ba1f22d3edff530a5 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:06:01 +0100 Subject: [PATCH 116/140] ZZfix --- nevergrad/functions/pcse/pcse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 22222dfbbc..2de88b358c 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,8 +21,8 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - raise Exception("We do not import EUPL code by default.") - # import pcse # pylint: disable=unused-import + #raise Exception("We do not import EUPL code by default.") + import pcse # pylint: disable=unused-import except: raise ng.errors.UnsupportedExperiment( "You need to install PCSE. Check that the EUPL license is ok for you." From efd381a84babab68ee100fb894ff87a847bb4838 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:47:51 +0100 Subject: [PATCH 117/140] nlopt --- mypy.ini | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mypy.ini b/mypy.ini index 6315b6b111..06961e277d 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3,7 +3,6 @@ [mypy-scipy.*,requests,pandas,compiler_gym,compiler_gym.*,gym_anm,matplotlib.*,pytest,cma,bayes_opt.*,torchvision.models,torch.*,mpl_toolkits.*,fcmaes.*,tqdm,pillow,PIL,PIL.Image,sklearn.*,pyomo.*,pyproj,IOHexperimenter.*,tensorflow,koncept.models,cv2,imquality,imquality.brisque,lpips,mixsimulator.*,networkx.*,cdt.*,pymoo,pymoo.*,bayes_optim.*,olympus.*,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,aquacrop.*] ignore_missing_imports = True -<<<<<<< HEAD [mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] @@ -15,10 +14,10 @@ ignore_missing_imports = True #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] -======= -[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] ->>>>>>> 22234dac (fix) +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] ignore_missing_imports = True ignore_errors = True From 6c0e0ee8c0bae9c8293a17da80577a3cd9a1d9ab Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 20 Jan 2022 14:56:08 +0100 Subject: [PATCH 118/140] ZZnlopt --- mypy.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mypy.ini b/mypy.ini index 06961e277d..86fc93c988 100644 --- a/mypy.ini +++ b/mypy.ini @@ -17,7 +17,9 @@ ignore_missing_imports = True #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] ignore_missing_imports = True ignore_errors = True From d2b627343c646477f6a113feaf63c9ede65a3398 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 20:08:49 +0100 Subject: [PATCH 119/140] ZZPcse2: irrigation challenge (#1341) * irrigation_challenge * flute * fix * Update __init__.py * Update experiments.py * fix * fix * fix * fix * fix * fix * fix * fix * fix_gym * fix_gym * fix_gym * fix * fix --- .../functions/irrigation/data/meteo/nl1.xlsx | Bin 0 -> 208384 bytes requirements/bench.txt | 5 +++++ 2 files changed, 5 insertions(+) create mode 100644 nevergrad/functions/irrigation/data/meteo/nl1.xlsx diff --git a/nevergrad/functions/irrigation/data/meteo/nl1.xlsx b/nevergrad/functions/irrigation/data/meteo/nl1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..93c6bfe2d2eab5b848cdb143b88b92bdcbdb556a GIT binary patch literal 208384 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%0AAK(jnzN*&}6F9L>siHM6{WBJQE@EDu)M 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.2.2 box2d-py>=2.3.5 glfw mujoco +<<<<<<< HEAD pcse>=5.5.0 #yaml>=5.3.1 #yaml +======= +pcse +pygame +>>>>>>> e4668916 (ZZPcse2: irrigation challenge (#1341)) From 4f141a1d7ef3fbaadc79f4356e848da53c0c1b07 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Wed, 2 Mar 2022 21:20:23 +0100 Subject: [PATCH 120/140] ZZUpdate bench.txt --- requirements/bench.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/requirements/bench.txt b/requirements/bench.txt index 3d0ee7bdce..a2e891da9c 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -36,7 +36,6 @@ Keras-Preprocessing silence_tensorflow # for olymp tensorflow_probability # for olymp bayes-optim==0.2.5.5 -# pcse>=5.5.0 # removed due to PCSE license issues. pygame>=2.0.2 pyyaml>=5.3.1 nlopt @@ -44,11 +43,6 @@ pybullet>=3.2.2 box2d-py>=2.3.5 glfw mujoco -<<<<<<< HEAD pcse>=5.5.0 #yaml>=5.3.1 #yaml -======= -pcse -pygame ->>>>>>> e4668916 (ZZPcse2: irrigation challenge (#1341)) From 3c03ef16211ad2a7462b930ffd85355a9390a6f9 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 8 Aug 2022 14:18:04 +0200 Subject: [PATCH 121/140] fix --- nevergrad/benchmark/experiments.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 06440f8022..26c1bfcc57 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1577,11 +1577,12 @@ def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Irrigation simulator. Maximize leaf area index, so that you get a lot of primary production. Sequential or 30 workers.""" - funcs = [Irrigation(i) for i in range(17)] + funcs = [Irrigation(i) for i in range(179)] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) - for budget in [25, 50, 100, 200]: - for num_workers in [1, 30, 60]: + optims = ["DiagonalCMA"] + for budget in [25]: #, 50, 100, 200]: + for num_workers in [1]: #, 30, 60]: if num_workers < budget: for algo in optims: for fu in funcs: From ab92acea6adbfbd0e729c6775866c13a4a210859 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 8 Aug 2022 14:48:29 +0200 Subject: [PATCH 122/140] pcse --- nevergrad/benchmark/experiments.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 26c1bfcc57..5c1b9871fe 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1600,9 +1600,9 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """ funcs = [CropSimulator()] seedg = create_seed_generator(seed) - optims = get_optimizers("basics", seed=next(seedg)) + optims = ["DE", "PSO", "CMA", "NGOpt"] for budget in [25, 50, 100, 200]: - for num_workers in [1, 10, 40]: + for num_workers in [1]: if num_workers < budget: for algo in optims: for fu in funcs: From 889b7ec2cfbc6eb2e15b416d1aaea0861a21de9f Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Tue, 9 Aug 2022 20:31:40 +0200 Subject: [PATCH 123/140] benin --- nevergrad/benchmark/experiments.py | 51 +++++++++++++------- nevergrad/functions/irrigation/irrigation.py | 2 +- nevergrad/optimization/optimizerlib.py | 9 ++++ 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 5c1b9871fe..f13eea761b 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1572,26 +1572,43 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: yield xp +#@registry.register +#def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False) -> tp.Iterator[Experiment]: +# """Irrigation simulator. Maximize leaf area index, +# so that you get a lot of primary production. +# Sequential or 30 workers.""" +## funcs = [Irrigation(i, benin=benin, variety_choice=variety_choice) for i in range(23)] +# seedg = create_seed_generator(seed) +# optims = get_optimizers("basics", seed=next(seedg)) +# optims = ["DiagonalCMA", "CMA", "DE", "PSO", "TwoPointsDE", "DiscreteLenglerOnePlusOne"] +# optims += ["NGOptRW", "NGTuned"] +# for budget in [250]: #, 50, 100, 200]: +# for num_workers in [1]: #, 30, 60]: +# if num_workers < budget: +# for algo in optims: +# for fu in funcs: +# xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg)) +# skip_ci(reason="Too slow") +# if not xp.is_incoherent: +# yield xp + + @registry.register -def irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: - """Irrigation simulator. Maximize leaf area index, - so that you get a lot of primary production. - Sequential or 30 workers.""" - funcs = [Irrigation(i) for i in range(179)] - seedg = create_seed_generator(seed) - optims = get_optimizers("basics", seed=next(seedg)) - optims = ["DiagonalCMA"] - for budget in [25]: #, 50, 100, 200]: - for num_workers in [1]: #, 30, 60]: - if num_workers < budget: - for algo in optims: - for fu in funcs: - xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg)) - skip_ci(reason="Too slow") - if not xp.is_incoherent: - yield xp +def variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, variety_choice=True) + + +@registry.register +def benin_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, benin=True) +@registry.register +def benin_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, benin=True, variety_choice=True) + + +@registry.register def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index c966bb6059..9a79c4c096 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -362,7 +362,7 @@ def total_yield(self, x: np.ndarray, year:int=2006): d3 = int(1.01 + 29.98 * x[3]) c = self.total_irrigation if len(x) == 10: - c = 0 + c = 0.15 a0 = c * x[4] / (x[4] + x[5] + x[6] + x[7]) a1 = c * x[5] / (x[4] + x[5] + x[6] + x[7]) a2 = c * x[6] / (x[4] + x[5] + x[6] + x[7]) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 8ffdac0471..56c95a6f33 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -3109,6 +3109,15 @@ class NGOpt(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass +@registry.register +class NGTuned(NGOpt39): + # Learning something automatically so that it's less unreadable would be great. + pass + +NGOptRW = ConfPortfolio( + optimizers=[GeneticDE, PSO, NGOpt], warmup_ratio=0.33 + ).set_name("NGOptRW", register=True) + @registry.register class NGTuned(NGOpt39): From 2888a43f280126527db3354efa4b4cb04b73c56b Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Thu, 11 Aug 2022 09:40:08 +0200 Subject: [PATCH 124/140] fix --- nevergrad/benchmark/experiments.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index f13eea761b..ff841f82a9 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1608,6 +1608,11 @@ def benin_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterato return irrigation(seed, benin=True, variety_choice=True) +@registry.register +def benin_rice_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, benin=True, variety_choice=True, rice=True) + + @registry.register def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Crop simulator. From 77c188ce79b3080368e06b4ccb314ef1e630ce46 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Tue, 6 Dec 2022 15:30:44 +0100 Subject: [PATCH 125/140] Optimizing simultaneously variety, irrigation and crop (#1467) * fix * Adding costs in dollars per kg for various crops, and weird operations by Lev distance (#1468) * fix * Support for choosing the year(s) in PCSE stuff (#1469) * fix * o * fix --- nevergrad/benchmark/experiments.py | 39 ------------------------------ 1 file changed, 39 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index ff841f82a9..9c47660050 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1593,45 +1593,6 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: # yield xp -@registry.register -def variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: - return irrigation(seed, variety_choice=True) - - -@registry.register -def benin_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: - return irrigation(seed, benin=True) - - -@registry.register -def benin_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: - return irrigation(seed, benin=True, variety_choice=True) - - -@registry.register -def benin_rice_variety_choice_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: - return irrigation(seed, benin=True, variety_choice=True, rice=True) - - -@registry.register -def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: - """Crop simulator. - - Low dimensional problem, only 2 vars. This is optimization for model identification: we want - to find parameters so that the simulation matches observations. - """ - funcs = [CropSimulator()] - seedg = create_seed_generator(seed) - optims = ["DE", "PSO", "CMA", "NGOpt"] - for budget in [25, 50, 100, 200]: - for num_workers in [1]: - if num_workers < budget: - for algo in optims: - for fu in funcs: - xp = Experiment(fu, algo, budget, num_workers=num_workers, seed=next(seedg)) - if not xp.is_incoherent: - yield xp - @registry.register def mono_rocket(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: From bad5825ec1158246edb45a7858839570f32c2c52 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 15:05:44 +0100 Subject: [PATCH 126/140] merge_and_small_fix --- nevergrad/functions/irrigation/irrigation.py | 4 ++-- nevergrad/optimization/optimizerlib.py | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 9a79c4c096..5eb9928c78 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -250,11 +250,11 @@ def we_have(y, m, d): date(y, m, d) except ValueError: return False - if date(y, m, d) in [k[0] for k in my_keys]: + if (date(y, m, d), 0) in my_keys: return True def get_val(y, m, d, slot): - my_vals = [getattr(wdp.store[(date(y_, m, d), 0)], slot) for y_ in range(y-3, y+4) if we_have(y_, m, d)] + my_vals = [getattr(wdp.store[(date(y_, m, d), 0)], slot) for y_ in range(y-4, y+5) if we_have(y_, m, d)] assert len(my_vals) >= 3, f"big issue with data {y} {m} {d}!" return sum(my_vals) / len(my_vals) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 56c95a6f33..edc14ac5a7 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -3109,15 +3109,12 @@ class NGOpt(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass + @registry.register class NGTuned(NGOpt39): # Learning something automatically so that it's less unreadable would be great. pass -NGOptRW = ConfPortfolio( - optimizers=[GeneticDE, PSO, NGOpt], warmup_ratio=0.33 - ).set_name("NGOptRW", register=True) - @registry.register class NGTuned(NGOpt39): From bf9873b10df3a7b66a4a38ad787ec6ce8c21864f Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 15:10:47 +0100 Subject: [PATCH 127/140] merge --- nevergrad/optimization/optimizerlib.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index edc14ac5a7..8ffdac0471 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -3116,12 +3116,6 @@ class NGTuned(NGOpt39): pass -@registry.register -class NGTuned(NGOpt39): - # Learning something automatically so that it's less unreadable would be great. - pass - - class _MSR(Portfolio): """This code applies multiple copies of NGOpt with random weights for the different objective functions. From 557de3abaa4e08e5497481c4e5830cd7d52dd4cd Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 15:53:22 +0100 Subject: [PATCH 128/140] fix_december --- nevergrad/functions/irrigation/irrigation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 5eb9928c78..8e131e697c 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -297,8 +297,8 @@ def extrapolate(wdp, y, m, od): # Extension for the future for y in range(2020, 2050): - for m in range(1, 12): - for d in range(1,31): + for m in range(1, 13): + for d in range(1,32): try: date(y, m, d) except ValueError: From e3f6891fb1e42d5c62933fd24c668d47ccb15552 Mon Sep 17 00:00:00 2001 From: Teytaud Date: Mon, 12 Dec 2022 17:23:45 +0100 Subject: [PATCH 129/140] Ccmerge (#1483) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * merge * pcse * pcse * fix * pcse * fix * nlopt * nlopt * nlopt * fix * fix * po * to * fix * Update experiments.py * Update nevergrad/optimization/optimizerlib.py Co-authored-by: Jérémy Rapin * Update test_optimizerlib.py * Update pcse.py * Update experiments.py * Pcse2: irrigation challenge (#1341) * irrigation_challenge * flute * fix * Update __init__.py * Update experiments.py * fix * fix * fix * fix * fix * fix * fix * fix * fix_gym * fix_gym * fix_gym * fix * fix * fix * pcse_license * fix_details * fix * dependencies * dependencies * dependencies * dependencies * dependencies * pcse * Update pcse.py * pcse * fix * fix * fix * fix * fix * fix * Adding tabu lists (#1456) * fix * fix * fix * fix * fix * fix * Update core.py * Fix typing * Dict now * fix * fix * fix * fix * Simulated Annealing (#1455) * sa * black * Register DiscreteDE (#1454) This is one of the best algorithms ever for hyperparameter tuning so let us register it. * fix * fix * fix * Fix type * fix * ZZAdding tabu lists (#1456) * fix * fix * fix * fix * fix * fix * Update core.py * Fix typing * Dict now * fix * fix * fix * fix * ZZmerge * fix * fix * Fix num params * Remive duplicate * Update test_callbacks.py * Update test_callbacks.py * fix * fix * fix * fix * Update optimizerlib.py * Update optimizer_groups.txt * Update optimizerlib.py * Update test_tabu.py * Update experiments.py * Update optimizerlib.py * test_sa * fix * Update test_suggest.py * Update test_tabu.py * pcse * ZZfix * nlopt * ZZnlopt * ZZPcse2: irrigation challenge (#1341) * irrigation_challenge * flute * fix * Update __init__.py * Update experiments.py * fix * fix * fix * fix * fix * fix * fix * fix * fix_gym * fix_gym * fix_gym * fix * fix * ZZUpdate bench.txt * fix * pcse * benin * fix * Optimizing simultaneously variety, irrigation and crop (#1467) * fix * Adding costs in dollars per kg for various crops, and weird operations by Lev distance (#1468) * fix * Support for choosing the year(s) in PCSE stuff (#1469) * fix * o * fix * merge_and_small_fix * merge * fix_december * fix * fix * ccmerge * fix Co-authored-by: Jérémy Rapin --- mypy.ini | 9 + nevergrad/benchmark/experiments.py | 73 ++++- nevergrad/functions/gym/test_multigym.py | 7 - nevergrad/functions/irrigation/irrigation.py | 320 +++++++++++-------- nevergrad/functions/pcse/pcse.py | 28 +- nevergrad/optimization/test_optimizerlib.py | 4 +- nevergrad/optimization/test_tabu.py | 2 +- requirements/bench.txt | 2 + 8 files changed, 289 insertions(+), 156 deletions(-) diff --git a/mypy.ini b/mypy.ini index 77e515b6d4..6e968dab96 100644 --- a/mypy.ini +++ b/mypy.ini @@ -4,6 +4,8 @@ ignore_missing_imports = True [mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*,nlopt] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*,nlopt] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] @@ -13,6 +15,13 @@ ignore_missing_imports = True #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env,pcse.*,yaml.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] +#[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] ignore_missing_imports = True ignore_errors = True diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 6bb2b81444..41b83406d8 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -26,7 +26,7 @@ from nevergrad.functions.stsp import STSP from nevergrad.functions.rocket import Rocket from nevergrad.functions.irrigation import Irrigation -from nevergrad.functions.pcse import CropSimulator +from nevergrad.functions.pcse import Pcse from nevergrad.functions.mixsimulator import OptimizeMix from nevergrad.functions.unitcommitment import UnitCommitmentProblem from nevergrad.functions import control @@ -226,6 +226,8 @@ centroids["Kosovo"] = (20.895355721342227, 42.579367131816994) centroids["Trinidad and Tobago"] = (-61.33036691444967, 10.428237089201879) centroids["South Sudan"] = (30.198617582461907, 7.292890133516845) + + def skip_ci(*, reason: str) -> None: """Only use this if there is a good reason for not testing the xp, such as very slow for instance (>1min) with no way to make it faster. @@ -1453,26 +1455,59 @@ def rocket(seed: tp.Optional[int] = None, seq: bool = False) -> tp.Iterator[Expe if not xp.is_incoherent: yield xp + @registry.register -def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False, rice: bool = False, multi_crop: bool = False, kenya: bool = False, year_min:int=2006, year_max:int=2006) -> tp.Iterator[Experiment]: +def irrigation( + seed: tp.Optional[int] = None, + benin: bool = False, + variety_choice: bool = False, + rice: bool = False, + multi_crop: bool = False, + kenya: bool = False, + year_min: int = 2006, + year_max: int = 2006, +) -> tp.Iterator[Experiment]: """Irrigation simulator. Maximize leaf area index, so that you get a lot of primary production. Sequential or 30 workers.""" if kenya: addresses = [] - #lat_center = float(os.environ.get("ng_latitude", "0.")) - #lon_center = float(os.environ.get("ng_longitude", "37.")) + # lat_center = float(os.environ.get("ng_latitude", "0.")) + # lon_center = float(os.environ.get("ng_longitude", "37.")) country = os.environ.get("ng_country", "Kenya") ng_latitude = centroids[country][1] ng_longitude = centroids[country][0] - - for lat in [ng_latitude-4.+8. * e/6. for e in range(7)]: #list(range(-4,5)): - for lon in [ng_longitude-3.+6. * e/6. for e in range(7)]: #list(range(34,40)): + for lat in [ng_latitude - 4.0 + 8.0 * e / 6.0 for e in range(7)]: # list(range(-4,5)): + for lon in [ng_longitude - 3.0 + 6.0 * e / 6.0 for e in range(7)]: # list(range(34,40)): addresses += [(lat, lon)] - funcs = [Irrigation(0, benin=benin, variety_choice=variety_choice, rice=rice, multi_crop=multi_crop, address=ad, year_min=year_min,year_max=year_max) for ad in addresses] + funcs = [ + Irrigation( + 0, + benin=benin, + variety_choice=variety_choice, + rice=rice, + multi_crop=multi_crop, + address=ad, + year_min=year_min, + year_max=year_max, + ) + for ad in addresses + ] else: - funcs = [Irrigation(i, benin=benin, variety_choice=variety_choice, rice=rice, multi_crop=multi_crop, address=None,year_min=year_min, year_max=year_max) for i in range(67)] + funcs = [ + Irrigation( + i, + benin=benin, + variety_choice=variety_choice, + rice=rice, + multi_crop=multi_crop, + address=None, + year_min=year_min, + year_max=year_max, + ) + for i in range(67) + ] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) optims = ["DiagonalCMA", "CMA", "DE", "PSO", "TwoPointsDE", "DiscreteLenglerOnePlusOne"] @@ -1480,8 +1515,8 @@ def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choic optims = ["NGOptRW"] if rice: optims = optims[-2:] - for budget in [int(os.environ.get("ng_budget", "250"))]: #, 50, 100, 200]: - for num_workers in [1]: #, 30, 60]: + for budget in [int(os.environ.get("ng_budget", "250"))]: # , 50, 100, 200]: + for num_workers in [1]: # , 30, 60]: if num_workers < budget: for algo in optims: for fu in funcs: @@ -1515,10 +1550,24 @@ def kenya_2011_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp. def kenya_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2006, year_max=2011) + @registry.register def kenya_new_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2016, year_max=2021) + +@registry.register +def kenya_future_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2026, year_max=2031) + + +@registry.register +def kenya_farfuture_many_crop_and_variety_irrigation( + seed: tp.Optional[int] = None, +) -> tp.Iterator[Experiment]: + return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2036, year_max=2041) + + @registry.register def kenya_old_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=1996, year_max=2001) @@ -1551,7 +1600,7 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: Low dimensional problem, only 2 vars. This is optimization for model identification: we want to find parameters so that the simulation matches observations. """ - funcs = [CropSimulator()] + funcs = [Pcse()] seedg = create_seed_generator(seed) optims = ["DE", "PSO", "CMA", "NGOpt"] for budget in [25, 50, 100, 200]: diff --git a/nevergrad/functions/gym/test_multigym.py b/nevergrad/functions/gym/test_multigym.py index 93d6fc780c..db306aaba4 100644 --- a/nevergrad/functions/gym/test_multigym.py +++ b/nevergrad/functions/gym/test_multigym.py @@ -24,12 +24,6 @@ def test_multigym() -> None: assert env_name in GYM_ENV_NAMES, f"{env_name} should be guaranteed!" assert len(GYM_ENV_NAMES) >= 10 or os.name == "nt" -#def test_compiler_gym() -> None: -# func = multigym.CompilerGym(17) -# candidate = func.parametrization.sample() -# results = [func.evaluation_function(candidate) for _ in range(4)] -# assert min(results) == max(results), "CompilerGym should be deterministic." - def test_cartpole() -> None: func = multigym.GymMulti(name="CartPole-v0", control="neural", neural_factor=1, randomized=True) @@ -53,7 +47,6 @@ def test_sparse_cartpole() -> None: results = [func.evaluation_function(candidate) for _ in range(40)] assert min(results) != max(results), "CartPole should not be deterministic." - @pytest.mark.parametrize("name", ["LunarLander-v2"]) # type: ignore def test_run_multigym(name: str) -> None: if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index daf7f81ed1..ea53e699da 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -13,9 +13,10 @@ import copy from datetime import date from pathlib import Path -import urllib.request # Necessary for people who will uncomment the part using data under EUPL license. +import urllib.request import numpy as np import time +import warnings import nevergrad as ng from ..base import ArrayExperimentFunction import os @@ -33,53 +34,46 @@ # dollars per kilogram crop_value_dollars_per_kg = {} -crop_value_dollars_per_kg["barley"]= 9.6 # Kenya -crop_value_dollars_per_kg["cassava"]= 2 # Kenya -crop_value_dollars_per_kg["chick_pea"]= 0.395 # Kenya -crop_value_dollars_per_kg["cotton"]= 1.83 # Kenya -crop_value_dollars_per_kg["cow_pea"]= 0.185 # Kenya -crop_value_dollars_per_kg["faba_bean"]= 0.1825 # no idea where -crop_value_dollars_per_kg["ground_nut"]= 0.66 # Kenya -crop_value_dollars_per_kg["maize"]= 0.37 # Kenya -crop_value_dollars_per_kg["millet"]= 0.485 # Kenya -crop_value_dollars_per_kg["mung_bean"]= 0.33 # no idea where, unclear# -crop_value_dollars_per_kg["pigeon_pea"]= 0.679 # not clear, kenya -crop_value_dollars_per_kg["potato"]= 0.55 # kenya, difficult -crop_value_dollars_per_kg["rape_seed"]=7.1 # kenya (waow ?) -crop_value_dollars_per_kg["rice"]=0.325 # kenya -crop_value_dollars_per_kg["sorghum"]= 0.25 # kenya -crop_value_dollars_per_kg["soy_bean"]=(0.68+0.93)/2. # kenya -crop_value_dollars_per_kg["sugar_beet"]=(0.75+0.69)/2. # kenya -crop_value_dollars_per_kg["sugar_cane"]=0.34 # kenya, roughly -crop_value_dollars_per_kg["sunflower"]= 1.69 # kenya -crop_value_dollars_per_kg["sweet_potato"]= 1.15 # kenya -crop_value_dollars_per_kg["wheat"]=(0.19+0.42)/2. # roughly, kenya +crop_value_dollars_per_kg["barley"] = 9.6 # Kenya +crop_value_dollars_per_kg["cassava"] = 2 # Kenya +crop_value_dollars_per_kg["chick_pea"] = 0.395 # Kenya +crop_value_dollars_per_kg["cotton"] = 1.83 # Kenya +crop_value_dollars_per_kg["cow_pea"] = 0.185 # Kenya +crop_value_dollars_per_kg["faba_bean"] = 0.1825 # no idea where +crop_value_dollars_per_kg["ground_nut"] = 0.66 # Kenya +crop_value_dollars_per_kg["maize"] = 0.37 # Kenya +crop_value_dollars_per_kg["millet"] = 0.485 # Kenya +crop_value_dollars_per_kg["mung_bean"] = 0.33 # no idea where, unclear# +crop_value_dollars_per_kg["pigeon_pea"] = 0.679 # not clear, kenya +crop_value_dollars_per_kg["potato"] = 0.55 # kenya, difficult +crop_value_dollars_per_kg["rape_seed"] = 7.1 # kenya (waow ?) +crop_value_dollars_per_kg["rice"] = 0.325 # kenya +crop_value_dollars_per_kg["sorghum"] = 0.25 # kenya +crop_value_dollars_per_kg["soy_bean"] = (0.68 + 0.93) / 2.0 # kenya +crop_value_dollars_per_kg["sugar_beet"] = (0.75 + 0.69) / 2.0 # kenya +crop_value_dollars_per_kg["sugar_cane"] = 0.34 # kenya, roughly +crop_value_dollars_per_kg["sunflower"] = 1.69 # kenya +crop_value_dollars_per_kg["sweet_potato"] = 1.15 # kenya +crop_value_dollars_per_kg["wheat"] = (0.19 + 0.42) / 2.0 # roughly, kenya def lev(seq1, seq2): size_x = len(seq1) + 1 size_y = len(seq2) + 1 - matrix = np.zeros ((size_x, size_y)) + matrix = np.zeros((size_x, size_y)) for x in range(size_x): - matrix [x, 0] = x + matrix[x, 0] = x for y in range(size_y): - matrix [0, y] = y + matrix[0, y] = y for x in range(1, size_x): for y in range(1, size_y): - if seq1[x-1] == seq2[y-1]: - matrix [x,y] = min( - matrix[x-1, y] + 1, - matrix[x-1, y-1], - matrix[x, y-1] + 1 - ) + if seq1[x - 1] == seq2[y - 1]: + matrix[x, y] = min(matrix[x - 1, y] + 1, matrix[x - 1, y - 1], matrix[x, y - 1] + 1) else: - matrix [x,y] = min( - matrix[x-1,y] + 1, - matrix[x-1,y-1] + 1, - matrix[x,y-1] + 1 - ) - return (matrix[size_x - 1, size_y - 1]) + matrix[x, y] = min(matrix[x - 1, y] + 1, matrix[x - 1, y - 1] + 1, matrix[x, y - 1] + 1) + return matrix[size_x - 1, size_y - 1] + def get_crop_cost(cropname: str): min_lev = 100000000 @@ -94,6 +88,7 @@ def get_crop_cost(cropname: str): crop_value_dollars_per_kg[cropname] = crop_value_dollars_per_kg[best_crop] return crop_value_dollars_per_kg[cropname] + WPD = {} CURRENT_BEST = {} CURRENT_BEST_ARGUMENT = {} @@ -101,7 +96,18 @@ def get_crop_cost(cropname: str): class Irrigation(ArrayExperimentFunction): variant_choice = {} - def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, multi_crop: bool, address=None, year_min: int = 2006, year_max: int = 2006) -> None: + + def __init__( + self, + symmetry: int, + benin: bool, + variety_choice: bool, + rice: bool, + multi_crop: bool, + address=None, + year_min: int = 2006, + year_max: int = 2006, + ) -> None: self.rice = rice if year_max < year_min and year_max == 2006: year_max = year_min @@ -123,55 +129,78 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, self.this_dimension = 10 assert not rice - param = ng.p.Array(shape=(self.this_dimension,), lower=(0.0), upper=(0.99999999)).set_name("irrigation8") + param = ng.p.Array(shape=(self.this_dimension,), lower=(0.0), upper=(0.99999999)).set_name( + "irrigation8" + ) super().__init__(self.meta_total_yield, parametrization=param, symmetry=symmetry) if os.environ.get("CIRCLECI", False): raise ng.errors.UnsupportedExperiment("No HTTP request in CircleCI") -# "Cotonou", -# "Lokossa", -# "Allada", -# "Abomey", -# "Pobe", -# "Aplahoue", -# "Dassa-Zoume", -# "Parakou", -# "Djougou", -# "Kandi", -# "Natitingou", - known_longitudes = {'Saint-Leger-Bridereix': 1.5887348, 'Dun-Le-Palestel': 1.6641173, 'Kolkata': - 88.35769124388872, 'Antananarivo': 47.5255809, 'Santiago': -70.6504502, 'Lome': 1.215829, 'Cairo': 31.2357257, - 'Ouagadougou': -1.5270944, 'Yamoussoukro': -5.273263, 'Yaounde': 11.5213344, 'Kiev': 30.5241361, 'Porto-Novo': - 2.6289} - known_latitudes = {'Saint-Leger-Bridereix': 46.2861759, 'Dun-Le-Palestel': 46.3052049, 'Kolkata': 22.5414185, - 'Antananarivo': -18.9100122, 'Santiago': -33.4377756, 'Lome': 6.130419, 'Cairo': 30.0443879, 'Ouagadougou': - 12.3681873, 'Yamoussoukro': 6.809107, 'Yaounde': 3.8689867, 'Kiev': 50.4500336, 'Porto-Novo': 6.4969} - known_longitudes['Cotonou'] = 2.4252507 - known_latitudes['Cotonou'] = 6.3676953 - known_longitudes['Lokossa'] = 1.7171404 - known_latitudes['Lokossa'] = 6.6458524 - known_longitudes['Allada'] = 2.1511876 - known_latitudes['Allada'] = 6.6658411 - known_longitudes['Abomey'] = 1.9828803672675925 - known_latitudes['Abomey'] = 7.165446 - known_longitudes['Pobe'] = -1.751602 - known_latitudes['Pobe'] = 13.882217 - known_longitudes['Aplahoue'] = 1.7041012 - known_latitudes['Aplahoue'] = 6.9489244 - known_longitudes['Dassa-Zoume'] = 2.183606 - known_latitudes['Dassa-Zoume'] = 7.7815402 - known_longitudes['Parakou'] = 2.6278258 - known_latitudes['Parakou'] = 9.3400159 - known_longitudes['Djougou'] = 1.6651614 - known_latitudes['Djougou'] = 9.7106683 - known_longitudes['Kandi'] = 88.11640162351831 - known_latitudes['Kandi'] = 24.00952125 - known_longitudes['Natitingou'] = 1.383540986380074 - known_latitudes['Natitingou'] = 10.251408300000001 + # "Cotonou", + # "Lokossa", + # "Allada", + # "Abomey", + # "Pobe", + # "Aplahoue", + # "Dassa-Zoume", + # "Parakou", + # "Djougou", + # "Kandi", + # "Natitingou", + known_longitudes = { + "Saint-Leger-Bridereix": 1.5887348, + "Dun-Le-Palestel": 1.6641173, + "Kolkata": 88.35769124388872, + "Antananarivo": 47.5255809, + "Santiago": -70.6504502, + "Lome": 1.215829, + "Cairo": 31.2357257, + "Ouagadougou": -1.5270944, + "Yamoussoukro": -5.273263, + "Yaounde": 11.5213344, + "Kiev": 30.5241361, + "Porto-Novo": 2.6289, + } + known_latitudes = { + "Saint-Leger-Bridereix": 46.2861759, + "Dun-Le-Palestel": 46.3052049, + "Kolkata": 22.5414185, + "Antananarivo": -18.9100122, + "Santiago": -33.4377756, + "Lome": 6.130419, + "Cairo": 30.0443879, + "Ouagadougou": 12.3681873, + "Yamoussoukro": 6.809107, + "Yaounde": 3.8689867, + "Kiev": 50.4500336, + "Porto-Novo": 6.4969, + } + known_longitudes["Cotonou"] = 2.4252507 + known_latitudes["Cotonou"] = 6.3676953 + known_longitudes["Lokossa"] = 1.7171404 + known_latitudes["Lokossa"] = 6.6458524 + known_longitudes["Allada"] = 2.1511876 + known_latitudes["Allada"] = 6.6658411 + known_longitudes["Abomey"] = 1.9828803672675925 + known_latitudes["Abomey"] = 7.165446 + known_longitudes["Pobe"] = -1.751602 + known_latitudes["Pobe"] = 13.882217 + known_longitudes["Aplahoue"] = 1.7041012 + known_latitudes["Aplahoue"] = 6.9489244 + known_longitudes["Dassa-Zoume"] = 2.183606 + known_latitudes["Dassa-Zoume"] = 7.7815402 + known_longitudes["Parakou"] = 2.6278258 + known_latitudes["Parakou"] = 9.3400159 + known_longitudes["Djougou"] = 1.6651614 + known_latitudes["Djougou"] = 9.7106683 + known_longitudes["Kandi"] = 88.11640162351831 + known_latitudes["Kandi"] = 24.00952125 + known_longitudes["Natitingou"] = 1.383540986380074 + known_latitudes["Natitingou"] = 10.251408300000001 self.cropd = YAMLCropDataProvider() for k in range(1000): if symmetry in self.variant_choice and k < self.variant_choice[symmetry]: continue - self.address = np.random.RandomState(symmetry+3*k).choice( + self.address = np.random.RandomState(symmetry + 3 * k).choice( [ "Saint-Leger-Bridereix", "Dun-Le-Palestel", @@ -186,7 +215,9 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, "Yaounde", "Porto-Novo", "Kiev", - ] if not benin else [ + ] + if not benin + else [ "Porto-Novo", "Cotonou", "Lokossa", @@ -202,22 +233,29 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, ] ) if address is not None: - self.address = str(address) - if len(address) == 2: - known_latitudes[self.address] = address[0] - known_longitudes[self.address] = address[1] - - if self.address in known_latitudes and self.address in known_longitudes and self.address not in WPD: + self.address = str(address) + if len(address) == 2: + known_latitudes[self.address] = address[0] + known_longitudes[self.address] = address[1] + + if ( + self.address in known_latitudes + and self.address in known_longitudes + and self.address not in WPD + ): for k in range(10): try: - WPD[self.address] = NASAPowerWeatherDataProvider(latitude=known_latitudes[self.address], longitude=known_longitudes[self.address]) + WPD[self.address] = NASAPowerWeatherDataProvider( + latitude=known_latitudes[self.address], longitude=known_longitudes[self.address] + ) break except: - time.sleep(10 * (2 **k)) + time.sleep(10 * (2**k)) if self.address in WPD: self.weatherdataprovider = WPD[self.address] - else: + else: from geopy.geocoders import Nominatim + geolocator = Nominatim(user_agent="NG/PCSE") self.location = geolocator.geocode(self.address) self.weatherdataprovider = NASAPowerWeatherDataProvider( @@ -227,6 +265,8 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, self.wdp_extend(self.weatherdataprovider) self.set_data(symmetry, k, rice) v = [self.meta_total_yield(np.random.rand(self.this_dimension)) for _ in range(5)] + # self.set_data(symmetry, k) + # v = [self.leaf_area_index(np.random.rand(8)) for _ in range(5)] if min(v) != max(v): break self.variant_choice[symmetry] = k @@ -235,12 +275,12 @@ def __init__(self, symmetry:int, benin: bool, variety_choice: bool, rice: bool, def wdp_extend(self, wdp): my_keys = copy.deepcopy(list(wdp.store.keys())) - #print("ooo", min([k[1] for k in my_keys])) - #print("ooo", max([k[1] for k in my_keys])) - #print("==>",wdp.store[my_keys[0]]) - #print("==>",type(wdp.store[my_keys[0]])) - #print("==>",wdp.store[my_keys[0]].__slots__) - #print(list(wdp.store.keys())) + # print("ooo", min([k[1] for k in my_keys])) + # print("ooo", max([k[1] for k in my_keys])) + # print("==>",wdp.store[my_keys[0]]) + # print("==>",type(wdp.store[my_keys[0]])) + # print("==>",wdp.store[my_keys[0]].__slots__) + # print(list(wdp.store.keys())) def we_have(y, m, d): try: @@ -251,7 +291,11 @@ def we_have(y, m, d): return True def get_val(y, m, d, slot): - my_vals = [getattr(wdp.store[(date(y_, m, d), 0)], slot) for y_ in range(y-4, y+5) if we_have(y_, m, d)] + my_vals = [ + getattr(wdp.store[(date(y_, m, d), 0)], slot) + for y_ in range(y - 4, y + 5) + if we_have(y_, m, d) + ] assert len(my_vals) >= 3, f"big issue with data {y} {m} {d}!" return sum(my_vals) / len(my_vals) @@ -264,19 +308,32 @@ def extrapolate(wdp, y, m, od): first_y = None last_y = None container = None - for y_ in range(y-40, y+1): - try: - we_have(y_, m, d) - except ValueError: - continue - if we_have(y_, m, d): + for y_ in range(y - 40, y + 1): + try: + we_have(y_, m, d) + except ValueError: + continue + if we_have(y_, m, d): last_y = y_ if first_y is None: first_y = y_ container = copy.deepcopy(wdp.store[(date(last_y, m, d), 0)]) assert container is not None, "No data found even in 40 years !" for slot in container.__slots__: - if slot not in ["IRRAD", "TMIN", "TMAX", "VAP", "RAIN", "E0", "ES0", "ET0", "WIND", "SNOWDEPTH", "TEMP", "TMINRA"]: + if slot not in [ + "IRRAD", + "TMIN", + "TMAX", + "VAP", + "RAIN", + "E0", + "ES0", + "ET0", + "WIND", + "SNOWDEPTH", + "TEMP", + "TMINRA", + ]: continue try: value = get_val(last_y, m, d, slot) @@ -291,11 +348,11 @@ def extrapolate(wdp, y, m, od): value = vmax setattr(container, slot, value) wdp.store[(date(y, m, od), 0)] = container - + # Extension for the future for y in range(2020, 2050): - for m in range(1, 12): - for d in range(1,31): + for m in range(1, 13): + for d in range(1, 32): try: date(y, m, d) except ValueError: @@ -309,26 +366,29 @@ def extrapolate(wdp, y, m, od): for y in range(2020, 2050): ok = [k for k in my_keys if k[0].year == y] print(y, len(ok)) - def set_data(self, symmetry: int, k: int, rice: bool): crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] crop_types = [c for c in crop_types if "obacco" not in c] if rice: crop_types = ["rice"] self.crop_types = crop_types - self.cropname = np.random.RandomState(symmetry+3*k+1).choice(crop_types) - self.total_irrigation = np.random.RandomState(symmetry+3*k+3).choice([15.0, 1.50, 0.15, 150.]) if not rice else 0.15 - self.cropvariety = np.random.RandomState(symmetry+3*k+2).choice(list(self.cropd.get_crops_varieties()[self.cropname]) + self.cropname = np.random.RandomState(symmetry + 3 * k + 1).choice(crop_types) + self.total_irrigation = ( + np.random.RandomState(symmetry + 3 * k + 3).choice([15.0, 1.50, 0.15, 150.0]) + if not rice + else 0.15 + ) + self.cropvariety = np.random.RandomState(symmetry + 3 * k + 2).choice( + list(self.cropd.get_crops_varieties()[self.cropname]) ) # We check if the problem is challenging. - #print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") + # print(f"testing {symmetry}: {k} {self.address} {self.cropvariety}") site = WOFOST72SiteDataProvider(WAV=100, CO2=360) self.parameterprovider = ParameterProvider(soildata=self.soil, cropdata=self.cropd, sitedata=site) - def meta_total_yield(self, x: np.ndarray): - lai = 0. - for year in range(self.year_min, self.year_max+1): + lai = 0.0 + for year in range(self.year_min, self.year_max + 1): print(f"working on {year}") lai += self.total_yield(x, year) specifier = self.address + "_" + str(self.total_irrigation) @@ -337,7 +397,7 @@ def meta_total_yield(self, x: np.ndarray): if self.dimension == 8: specifier += "_" + self.cropvariety if specifier not in CURRENT_BEST: - CURRENT_BEST[specifier] = 0. + CURRENT_BEST[specifier] = 0.0 if lai > CURRENT_BEST[specifier]: CURRENT_BEST[specifier] = lai argument = str(x) @@ -350,14 +410,14 @@ def meta_total_yield(self, x: np.ndarray): return -lai - def total_yield(self, x: np.ndarray, year:int=2006): + def total_yield(self, x: np.ndarray, year: int = 2006): d0 = int(1.01 + 29.98 * x[0]) d1 = int(1.01 + 30.98 * x[1]) d2 = int(1.01 + 30.98 * x[2]) d3 = int(1.01 + 29.98 * x[3]) c = self.total_irrigation if len(x) == 10: - c = 0 + c = 0.15 a0 = c * x[4] / (x[4] + x[5] + x[6] + x[7]) a1 = c * x[5] / (x[4] + x[5] + x[6] + x[7]) a2 = c * x[6] / (x[4] + x[5] + x[6] + x[7]) @@ -396,22 +456,22 @@ def total_yield(self, x: np.ndarray, year:int=2006): agromanagement = yaml.safe_load(yaml_agro) wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) wofost.run_till_terminate() -# for i in range(10): -# try: -# wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) -# wofost.run_till_terminate() -# break -# except: -# print(f"failure {i} for {yaml_agro}") -# time.sleep(2 ** i) -# return -float("inf") + # for i in range(10): + # try: + # wofost = Wofost72_WLP_FD(self.parameterprovider, self.weatherdataprovider, agromanagement) + # wofost.run_till_terminate() + # break + # except: + # print(f"failure {i} for {yaml_agro}") + # time.sleep(2 ** i) + # return -float("inf") except Exception as e: print(e) return -float("inf") - #assert ( + # assert ( # False - #), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" - #raise e + # ), f"Problem!\n Dates: {d0} {d1} {d2} {d3},\n amounts: {a0}, {a1}, {a2}, {a3}\n ({e}).\n" + # raise e output = wofost.get_output() df = pd.DataFrame(output).set_index("day") diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index ba9ee34d79..14b1af1547 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -21,7 +21,7 @@ class CropSimulator(ArrayExperimentFunction): def __init__(self) -> None: try: - #raise Exception("We do not import EUPL code by default.") + # raise Exception("We do not import EUPL code by default.") import pcse # pylint: disable=unused-import except: raise ng.errors.UnsupportedExperiment( @@ -60,7 +60,8 @@ def __init__(self) -> None: TimedEvents: null StateEvents: null """ - agro = yaml.safe_load(agro_yaml) + # agro = yaml.safe_load(agro_yaml) + agro = yaml.load(agro_yaml) wofost = Wofost72_PP(params, wdp, agro) wofost.run_till_terminate() @@ -68,6 +69,19 @@ def __init__(self) -> None: df.index = pd.to_datetime(df.day) df.tail() + ## get daily observations for those + # ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) + # df_pseudo_obs = df.loc[ix] + # + # class ModelRerunner(object): + # """Reruns a given model with different values of parameters TWDI and SPAN. + # + # Returns a pandas DataFrame with simulation results of the model with given + # parameter values. + # """ + # + # parameters = ["TDWI", "SPAN"] + # get daily observations for those ix = (df.index.dayofweek == 0) & (df.LAI.notnull()) df_pseudo_obs = df.loc[ix] @@ -132,7 +146,7 @@ def __call__(self, par_values, grad=None): # Note that the dataframes automatically join on the index (dates) and column names df_differences = df_simulations - self.df_observations # Compute the RMSE on the LAI column - obj_func = np.sqrt(np.mean(df_differences.LAI ** 2)) + obj_func = np.sqrt(np.mean(df_differences.LAI**2)) return obj_func objfunc_calculator = ObjectiveFunctionCalculator(params, wdp, agro, df_pseudo_obs) @@ -141,6 +155,14 @@ def __call__(self, par_values, grad=None): # print("Objective function value with default parameters (%s): %s" % (defaults, error)) TDWI_range = [0.1, 0.6] SPAN_range = [30, 40] + # param = ng.p.Array( + # shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) + # ).set_name("2hp") + # super().__init__(objfunc_calculator, parametrization=param) + + # param = ng.p.Array(shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1])) + import nevergrad as ng + param = ng.p.Array( shape=(2,), lower=(TDWI_range[0], SPAN_range[0]), upper=(TDWI_range[1], SPAN_range[1]) ).set_name("2hp") diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index 8128802089..0418fce10d 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -737,13 +737,11 @@ def test_ngopt_selection( # assert choice == "MetaTuneRecentering" assert "MetaTuneRecentering" in optim_string if num_workers > 1: - assert choice not in ["SQP", "Cobyla"] + assert choice not in ["SQP", "Cobyla"] if "CMA" not in choice: assert choice == opt._info()["sub-optim"] else: assert choice in opt._info()["sub-optim"] - #assert expected == opt._info()["sub-optim"] - #assert opt._info()["sub-optim"] in o def test_bo_ordering() -> None: diff --git a/nevergrad/optimization/test_tabu.py b/nevergrad/optimization/test_tabu.py index 643a9d154b..41bcbe9337 100644 --- a/nevergrad/optimization/test_tabu.py +++ b/nevergrad/optimization/test_tabu.py @@ -50,7 +50,7 @@ def summation(x: tp.ArrayLike) -> float: @skip_win_perf # type: ignore def test_tabu_sum() -> None: - num_tests = 147 + num_tests = 147 # was: num_tests = 107 for o in ["DiscreteOnePlusOne", "DiscreteLenglerOnePlusOne"]: values = [] valuesT = [] diff --git a/requirements/bench.txt b/requirements/bench.txt index 4543f08b63..a2e891da9c 100644 --- a/requirements/bench.txt +++ b/requirements/bench.txt @@ -44,3 +44,5 @@ box2d-py>=2.3.5 glfw mujoco pcse>=5.5.0 +#yaml>=5.3.1 +#yaml From 69c6d12a7ac4ea59b667d1dfaef4ba2125d0fbcf Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 17:29:50 +0100 Subject: [PATCH 130/140] mergefck --- mypy.ini | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mypy.ini b/mypy.ini index 2627e6524f..969a5ea6bc 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3,15 +3,12 @@ [mypy-scipy.*,requests,pandas,compiler_gym,compiler_gym.*,gym_anm,matplotlib.*,pytest,cma,bayes_opt.*,torchvision.models,torch.*,mpl_toolkits.*,fcmaes.*,tqdm,pillow,PIL,PIL.Image,sklearn.*,pyomo.*,pyproj,IOHexperimenter.*,tensorflow,koncept.models,cv2,imquality,imquality.brisque,lpips,mixsimulator.*,networkx.*,cdt.*,pymoo,pymoo.*,bayes_optim.*,olympus.*,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,aquacrop.*] ignore_missing_imports = True -<<<<<<< HEAD -[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*] -#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] -======= [mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*,nlopt] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] +#[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*,nlopt] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym.nevergrad.functions.gym.tuple_gym_env,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*,aquacrop.*,nlopt] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*] #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] ->>>>>>> e3f6891fb1e42d5c62933fd24c668d47ccb15552 #[mypy-nevergrad.functions.rl.*,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,nevergrad.functions.gym.multigym,nevergrad.functions.gym.tuple_gym_env] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,pcse.*,yaml.*] #[mypy-nevergrad.functions.rl.agents,torchvision,torchvision.*,nevergrad.functions.games.*,nevergrad.functions.multiobjective.pyhv,nevergrad.optimization.test_doc,,pymoo,pymoo.*,pybullet,pybullet_envs,pybulletgym,pyvirtualdisplay,nlopt,pcse.*,yaml.*,aquacrop.*] From cb48391a43907c0a1443d20ef62076bc82344db8 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 17:53:54 +0100 Subject: [PATCH 131/140] fix --- nevergrad/functions/irrigation/irrigation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index fc565f182a..6ffc68ef33 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -415,7 +415,7 @@ def total_yield(self, x: np.ndarray, year: int = 2006): d3 = int(1.01 + 29.98 * x[3]) c = self.total_irrigation if len(x) == 10: - c = 0.15 + c = 0. a0 = c * x[4] / (x[4] + x[5] + x[6] + x[7]) a1 = c * x[5] / (x[4] + x[5] + x[6] + x[7]) a2 = c * x[6] / (x[4] + x[5] + x[6] + x[7]) From cf28304bcb58b6c73a9755a2cef6e20472797f4b Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:16:51 +0100 Subject: [PATCH 132/140] fix_we_have --- nevergrad/functions/irrigation/irrigation.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 6ffc68ef33..856c884c87 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -285,8 +285,7 @@ def we_have(y, m, d): date(y, m, d) except ValueError: return False - if (date(y, m, d), 0) in my_keys: - return True + return (date(y, m, d), 0) in my_keys def get_val(y, m, d, slot): my_vals = [ @@ -307,9 +306,7 @@ def extrapolate(wdp, y, m, od): last_y = None container = None for y_ in range(y - 40, y + 1): - try: - we_have(y_, m, d) - except ValueError: + if not we_have(y_, m, d): continue if we_have(y_, m, d): last_y = y_ From 5734d8b5aa4ff958d2cacc6e7bae666d5b430e52 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:18:41 +0100 Subject: [PATCH 133/140] no_print --- nevergrad/functions/irrigation/irrigation.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 856c884c87..5e1c0fec66 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -273,12 +273,6 @@ def __init__( def wdp_extend(self, wdp): my_keys = copy.deepcopy(list(wdp.store.keys())) - # print("ooo", min([k[1] for k in my_keys])) - # print("ooo", max([k[1] for k in my_keys])) - # print("==>",wdp.store[my_keys[0]]) - # print("==>",type(wdp.store[my_keys[0]])) - # print("==>",wdp.store[my_keys[0]].__slots__) - # print(list(wdp.store.keys())) def we_have(y, m, d): try: @@ -357,10 +351,6 @@ def extrapolate(wdp, y, m, od): assert len(ok) < 2 assert len(ok) >= (1 if we_have(y, m, d) else 0) - my_keys = list(wdp.store.keys()) - for y in range(2020, 2050): - ok = [k for k in my_keys if k[0].year == y] - print(y, len(ok)) def set_data(self, symmetry: int, k: int, rice: bool): crop_types = [crop for crop, variety in self.cropd.get_crops_varieties().items()] crop_types = [c for c in crop_types if "obacco" not in c] From cadf3be1ec928689357eb16e3f500e31a8a3035a Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:20:56 +0100 Subject: [PATCH 134/140] remove_useless_comment --- nevergrad/optimization/test_callbacks.py | 4 ++-- nevergrad/optimization/test_tabu.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nevergrad/optimization/test_callbacks.py b/nevergrad/optimization/test_callbacks.py index b1f4626b55..512add4985 100644 --- a/nevergrad/optimization/test_callbacks.py +++ b/nevergrad/optimization/test_callbacks.py @@ -36,9 +36,9 @@ def test_log_parameters(tmp_path: Path) -> None: logs = logger.load_flattened() assert len(logs) == 32 assert isinstance(logs[-1]["1"], float) - assert len(logs[-1]) == 35 # was 34 + assert len(logs[-1]) == 35 logs = logger.load_flattened(max_list_elements=2) - assert len(logs[-1]) == 31 # was 30 + assert len(logs[-1]) == 31 # deletion logger = callbacks.ParametersLogger(filepath, append=False) assert not logger.load() diff --git a/nevergrad/optimization/test_tabu.py b/nevergrad/optimization/test_tabu.py index 41bcbe9337..643a9d154b 100644 --- a/nevergrad/optimization/test_tabu.py +++ b/nevergrad/optimization/test_tabu.py @@ -50,7 +50,7 @@ def summation(x: tp.ArrayLike) -> float: @skip_win_perf # type: ignore def test_tabu_sum() -> None: - num_tests = 147 # was: num_tests = 107 + num_tests = 147 for o in ["DiscreteOnePlusOne", "DiscreteLenglerOnePlusOne"]: values = [] valuesT = [] From 97b41831c1304bc7a88a29e931ab463271616d5d Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:22:35 +0100 Subject: [PATCH 135/140] black --- nevergrad/benchmark/experiments.py | 11 +++++++---- nevergrad/functions/gym/test_multigym.py | 1 + nevergrad/functions/irrigation/irrigation.py | 4 ++-- nevergrad/optimization/test_optimizerlib.py | 1 - 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 49d80b7696..974526eb56 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1572,10 +1572,14 @@ def kenya_farfuture_many_crop_and_variety_irrigation( def kenya_future_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2026, year_max=2031) + @registry.register -def kenya_farfuture_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: +def kenya_farfuture_many_crop_and_variety_irrigation( + seed: tp.Optional[int] = None, +) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2036, year_max=2041) + @registry.register def kenya_old_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=1996, year_max=2001) @@ -1621,8 +1625,8 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: yield xp -#@registry.register -#def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False) -> tp.Iterator[Experiment]: +# @registry.register +# def irrigation(seed: tp.Optional[int] = None, benin: bool = False, variety_choice: bool = False) -> tp.Iterator[Experiment]: # """Irrigation simulator. Maximize leaf area index, # so that you get a lot of primary production. # Sequential or 30 workers.""" @@ -1642,7 +1646,6 @@ def crop_simulator(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: # yield xp - @registry.register def mono_rocket(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: """Sequential counterpart of the rocket problem.""" diff --git a/nevergrad/functions/gym/test_multigym.py b/nevergrad/functions/gym/test_multigym.py index adbd08b4f1..1805fc7b28 100644 --- a/nevergrad/functions/gym/test_multigym.py +++ b/nevergrad/functions/gym/test_multigym.py @@ -47,6 +47,7 @@ def test_sparse_cartpole() -> None: results = [func.evaluation_function(candidate) for _ in range(40)] assert min(results) != max(results), "CartPole should not be deterministic." + @pytest.mark.parametrize("name", ["LunarLander-v2"]) # type: ignore def test_run_multigym(name: str) -> None: if os.name == "nt" or np.random.randint(8) or "CubeCrash" in name: diff --git a/nevergrad/functions/irrigation/irrigation.py b/nevergrad/functions/irrigation/irrigation.py index 5e1c0fec66..2aed18f1ce 100644 --- a/nevergrad/functions/irrigation/irrigation.py +++ b/nevergrad/functions/irrigation/irrigation.py @@ -13,7 +13,7 @@ import copy from datetime import date from pathlib import Path -import urllib.request +import urllib.request import numpy as np import time import warnings @@ -402,7 +402,7 @@ def total_yield(self, x: np.ndarray, year: int = 2006): d3 = int(1.01 + 29.98 * x[3]) c = self.total_irrigation if len(x) == 10: - c = 0. + c = 0.0 a0 = c * x[4] / (x[4] + x[5] + x[6] + x[7]) a1 = c * x[5] / (x[4] + x[5] + x[6] + x[7]) a2 = c * x[6] / (x[4] + x[5] + x[6] + x[7]) diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py index fe14b0a704..68b913cf01 100644 --- a/nevergrad/optimization/test_optimizerlib.py +++ b/nevergrad/optimization/test_optimizerlib.py @@ -738,7 +738,6 @@ def test_ngopt_selection( assert "MetaTuneRecentering" in optim_string if num_workers > 1: assert "SQP" not in optim_string and "Cobyla" not in optim_string - assert choice not in ["SQP", "Cobyla"] if "CMA" not in choice: assert choice == opt._info()["sub-optim"] else: From 84e83a4473018ec3ae9ce9cbd8b7ca6641065698 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:23:18 +0100 Subject: [PATCH 136/140] PcseInsteadOfCropSimulator --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 48518da93f..2285f1871a 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -18,7 +18,7 @@ # pylint: disable=too-many-locals,too-many-statements -class CropSimulator(ArrayExperimentFunction): +class Pcse(ArrayExperimentFunction): def __init__(self) -> None: try: # raise Exception("We do not import EUPL code by default.") From af49856fe33224e12b678888a563fa279ca3f2bf Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:26:02 +0100 Subject: [PATCH 137/140] fix --- nevergrad/functions/pcse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/__init__.py b/nevergrad/functions/pcse/__init__.py index 2f131cc36c..a516986ced 100644 --- a/nevergrad/functions/pcse/__init__.py +++ b/nevergrad/functions/pcse/__init__.py @@ -5,4 +5,4 @@ # Based on https://github.com/ajwdewit/pcse_notebooks # MIT License. -from .pcse import CropSimulator as CropSimulator +from .pcse import Pcse as Pcse From cbac29486c8f64548b7cd8833a46e4a154a30c71 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:33:54 +0100 Subject: [PATCH 138/140] fix_namecollision --- nevergrad/benchmark/experiments.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 974526eb56..8a4ecb231d 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1568,18 +1568,6 @@ def kenya_farfuture_many_crop_and_variety_irrigation( return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2036, year_max=2041) -@registry.register -def kenya_future_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: - return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2026, year_max=2031) - - -@registry.register -def kenya_farfuture_many_crop_and_variety_irrigation( - seed: tp.Optional[int] = None, -) -> tp.Iterator[Experiment]: - return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=2036, year_max=2041) - - @registry.register def kenya_old_many_crop_and_variety_irrigation(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: return irrigation(seed, kenya=True, variety_choice=True, multi_crop=True, year_min=1996, year_max=2001) From 61467b9eeb1c54fbfef67844662833fc2243fb99 Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Mon, 12 Dec 2022 18:39:57 +0100 Subject: [PATCH 139/140] fix --- nevergrad/functions/pcse/pcse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/functions/pcse/pcse.py b/nevergrad/functions/pcse/pcse.py index 2285f1871a..750f3bf3c1 100644 --- a/nevergrad/functions/pcse/pcse.py +++ b/nevergrad/functions/pcse/pcse.py @@ -60,7 +60,7 @@ def __init__(self) -> None: TimedEvents: null StateEvents: null """ - agro = yaml.load(agro_yaml) + agro = yaml.safe_load(agro_yaml) wofost = Wofost72_PP(params, wdp, agro) wofost.run_till_terminate() From 8203e1815d0c6ebee9840f9cdda9ab64fc5d7b5d Mon Sep 17 00:00:00 2001 From: Olivier Teytaud Date: Tue, 13 Dec 2022 07:58:38 +0100 Subject: [PATCH 140/140] fix --- nevergrad/benchmark/experiments.py | 2 +- nevergrad/functions/pcse/test_pcse.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index c3fa392674..04ceb09a33 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -1644,7 +1644,7 @@ def pcse(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: Low dimensional problem, only 2 vars. This is optimization for model identification: we want to find parameters so that the simulation matches observations. """ - funcs = [CropSimulator()] + funcs = [Pcse()] seedg = create_seed_generator(seed) optims = get_optimizers("basics", seed=next(seedg)) for budget in [25, 50, 100, 200]: diff --git a/nevergrad/functions/pcse/test_pcse.py b/nevergrad/functions/pcse/test_pcse.py index 72cb2d6346..3776675da0 100644 --- a/nevergrad/functions/pcse/test_pcse.py +++ b/nevergrad/functions/pcse/test_pcse.py @@ -8,7 +8,7 @@ def test_pcse() -> None: - func = pcse.CropSimulator() + func = pcse.Pcse() x = 0 * np.random.rand(func.dimension) value = func(x) value2 = func(x)