From 85f4cff962ab4428bab9f31cd820d6b2a6682b48 Mon Sep 17 00:00:00 2001 From: dilpath Date: Sat, 23 Nov 2024 02:43:02 +0100 Subject: [PATCH 01/88] closes #120 --- doc/examples/example_cli_famos.ipynb | 6 +- .../example_cli_famos_calibration_tool.py | 6 +- doc/examples/workflow_cli.ipynb | 58 ++- doc/examples/workflow_python.ipynb | 8 +- petab_select/__init__.py | 1 + petab_select/candidate_space.py | 50 +-- petab_select/cli.py | 109 +---- petab_select/constants.py | 3 + petab_select/model.py | 104 +---- petab_select/models.py | 393 ++++++++++++++++++ petab_select/problem.py | 23 +- petab_select/ui.py | 26 +- 12 files changed, 525 insertions(+), 262 deletions(-) create mode 100644 petab_select/models.py diff --git a/doc/examples/example_cli_famos.ipynb b/doc/examples/example_cli_famos.ipynb index 5956c661..a1d32a11 100644 --- a/doc/examples/example_cli_famos.ipynb +++ b/doc/examples/example_cli_famos.ipynb @@ -33,6 +33,7 @@ "\n", "from example_cli_famos_helpers import (\n", " parse_summary_to_progress_list,\n", + " petab_select_problem_yaml, # noqa: F401\n", ")\n", "\n", "output_path = Path().resolve() / \"output_famos\"\n", @@ -141,8 +142,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/dilan/Documents/future_annex/model_selection/packages/petab_select/petab_select/candidate_space.py:376: RuntimeWarning: Model `model_subspace_1-0001011010010010` has been previously excluded from the candidate space so is skipped here.\n", - " warnings.warn(\n" + "petab_select/candidate_space.py:1137: RuntimeWarning: Model `model_subspace_1-0001011010010010` has been previously excluded from the candidate space so is skipped here.\n", + " return_value = self.inner_candidate_space.consider(model)\n" ] }, { @@ -173,7 +174,6 @@ ], "source": [ "%%bash -s \"$petab_select_problem_yaml\" \"$output_path_str\"\n", - "\n", "petab_select_problem_yaml=$1\n", "output_path_str=$2\n", "\n", diff --git a/doc/examples/example_cli_famos_calibration_tool.py b/doc/examples/example_cli_famos_calibration_tool.py index c78cabbe..f5b58c2d 100644 --- a/doc/examples/example_cli_famos_calibration_tool.py +++ b/doc/examples/example_cli_famos_calibration_tool.py @@ -7,14 +7,12 @@ models_yaml = sys.argv[1] calibrated_models_yaml = sys.argv[2] -models = petab_select.model.models_from_yaml_list(models_yaml) +models = petab_select.Models.from_yaml(models_yaml) predecessor_model_hashes = set() for model in models: calibrate(model=model) predecessor_model_hashes |= {model.predecessor_model_hash} -petab_select.model.models_to_yaml_list( - models=models, output_yaml=calibrated_models_yaml -) +models.to_yaml(output_yaml=calibrated_models_yaml) if len(predecessor_model_hashes) == 0: pass diff --git a/doc/examples/workflow_cli.ipynb b/doc/examples/workflow_cli.ipynb index 46c5a516..6f4cf836 100644 --- a/doc/examples/workflow_cli.ipynb +++ b/doc/examples/workflow_cli.ipynb @@ -177,7 +177,7 @@ "output_path_str=$1\n", "\n", "petab_select end_iteration \\\n", - "--state=output/state.dill \\\n", + "--state=$output_path_str/state.dill \\\n", "--calibrated-models=model_selection/calibrated_models_1.yaml \\\n", "--output-models=$output_path_str/models_1.yaml \\\n", "--output-metadata=$output_path_str/metadata.yaml \\\n", @@ -289,7 +289,7 @@ "petab_select get_best \\\n", "--problem model_selection/petab_select_problem.yaml \\\n", "--models model_selection/calibrated_models_1.yaml \\\n", - "--output output_cli/predecessor_model.yaml\n", + "--output $output_path_str/predecessor_model.yaml\n", "# create a copy of the original PEtab select problem and update its paths\n", "cp model_selection/petab_select_problem.yaml $output_path_str/custom_problem.yaml\n", "sed -i 's|- model_space.tsv|- ../model_selection/model_space.tsv|' $output_path_str/custom_problem.yaml\n", @@ -470,7 +470,7 @@ "id": "889dedc1", "metadata": {}, "source": [ - "As we are performing a forward search from `M1_4`, which has two parameters, then all models in this iteration with have 3+ parameters. This model space contains only one model with 3 or more estimated parameters. We finalize the iteration with its calibration results." + "As we are performing a forward search from `M1_4`, which has two parameters, then all models in this iteration will have 3+ parameters. This model space contains only one model with 3 or more estimated parameters. We finalize the iteration with its calibration results." ] }, { @@ -531,7 +531,7 @@ "metadata": {}, "source": [ "## Fourth iteration\n", - "As there are no models in the model space with 4+ parameters, subsequent forward searches will return no candidate models. This can be used by tools to detect when model selection terminates." + "As there are no models in the model space with 4+ parameters, subsequent forward searches will return no candidate models. Tools can detect when to terminate by inspecting the metadata produced by `end_iteration`, as demonstrated at the end of this iteration." ] }, { @@ -600,8 +600,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "null\n", - "...\n", + "[]\n", "\n" ] } @@ -611,6 +610,43 @@ " print(f.read())" ] }, + { + "cell_type": "code", + "execution_count": 16, + "id": "02df7ed9-422d-4f28-9b01-8670be873933", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash -s \"$output_path_str\"\n", + "output_path_str=$1\n", + "\n", + "petab_select end_iteration \\\n", + "--state=$output_path_str/state.dill \\\n", + "--output-models=$output_path_str/models_4.yaml \\\n", + "--output-metadata=$output_path_str/metadata.yaml \\\n", + "--relative-paths" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "57e483fd-5ffa-48a4-8c2a-359f6ebd1422", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "terminate: true\n", + "\n" + ] + } + ], + "source": [ + "with open(\"output_cli/metadata.yaml\") as f:\n", + " print(f.read())" + ] + }, { "cell_type": "markdown", "id": "7b0b1123", @@ -622,7 +658,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "id": "d5b5087d", "metadata": {}, "outputs": [], @@ -643,7 +679,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 19, "id": "30721bfa", "metadata": {}, "outputs": [ @@ -716,7 +752,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 20, "id": "73d54111", "metadata": {}, "outputs": [], @@ -736,7 +772,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "id": "c36564f1", "metadata": {}, "outputs": [ @@ -781,7 +817,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "d5d03cd6", "metadata": {}, "outputs": [ diff --git a/doc/examples/workflow_python.ipynb b/doc/examples/workflow_python.ipynb index 2a203987..170c767b 100644 --- a/doc/examples/workflow_python.ipynb +++ b/doc/examples/workflow_python.ipynb @@ -35,7 +35,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Information about the model selection problem.\n", + "Information about the model selection problem:\n", "YAML: model_selection/petab_select_problem.yaml\n", "Method: forward\n", "Criterion: Criterion.AIC\n", @@ -306,7 +306,7 @@ "Model ID: M1_2-000\n", "Criterion.AIC: 140\n", "\n", - "\u001B[1mBEST MODEL OF CURRENT ITERATION\u001B[0m\n", + "\u001b[1mBEST MODEL OF CURRENT ITERATION\u001b[0m\n", "Model subspace ID: M1_3\n", "PEtab YAML location: model_selection/petab_problem.yaml\n", "Custom model parameters: {'k1': 'estimate', 'k2': 0.1, 'k3': 0}\n", @@ -356,7 +356,7 @@ "Model ID: M1_5-000\n", "Criterion.AIC: -70\n", "\n", - "\u001B[1mBEST MODEL OF CURRENT ITERATION\u001B[0m\n", + "\u001b[1mBEST MODEL OF CURRENT ITERATION\u001b[0m\n", "Model subspace ID: M1_6\n", "PEtab YAML location: model_selection/petab_problem.yaml\n", "Custom model parameters: {'k1': 'estimate', 'k2': 'estimate', 'k3': 0}\n", @@ -399,7 +399,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001B[1mBEST MODEL OF CURRENT ITERATION\u001B[0m\n", + "\u001b[1mBEST MODEL OF CURRENT ITERATION\u001b[0m\n", "Model subspace ID: M1_7\n", "PEtab YAML location: model_selection/petab_problem.yaml\n", "Custom model parameters: {'k1': 'estimate', 'k2': 'estimate', 'k3': 'estimate'}\n", diff --git a/petab_select/__init__.py b/petab_select/__init__.py index 233d233b..665c4102 100644 --- a/petab_select/__init__.py +++ b/petab_select/__init__.py @@ -9,6 +9,7 @@ from .model import * from .model_space import * from .model_subspace import * +from .models import * from .problem import * from .ui import * diff --git a/petab_select/candidate_space.py b/petab_select/candidate_space.py index 865bebf6..fad615e6 100644 --- a/petab_select/candidate_space.py +++ b/petab_select/candidate_space.py @@ -27,6 +27,7 @@ ) from .handlers import TYPE_LIMIT, LimitHandler from .model import Model, ModelHash, default_compare +from .models import Models __all__ = [ "BackwardCandidateSpace", @@ -102,7 +103,7 @@ def __init__( limit: TYPE_LIMIT = np.inf, summary_tsv: TYPE_PATH = None, previous_predecessor_model: Model | None = None, - calibrated_models: dict[ModelHash, Model] = None, + calibrated_models: Models | None = None, ): """See class attributes for arguments.""" self.method = method @@ -125,15 +126,13 @@ def __init__( if self.previous_predecessor_model is None: self.previous_predecessor_model = self.predecessor_model - self.set_iteration_user_calibrated_models({}) + self.set_iteration_user_calibrated_models(Models()) self.criterion = criterion - self.calibrated_models = calibrated_models - if self.calibrated_models is None: - self.calibrated_models = {} - self.latest_iteration_calibrated_models = {} + self.calibrated_models = calibrated_models or Models() + self.latest_iteration_calibrated_models = Models() def set_iteration_user_calibrated_models( - self, user_calibrated_models: dict[str, Model] | None + self, user_calibrated_models: Models | None ) -> None: """Hide previously-calibrated models from the calibration tool. @@ -146,18 +145,17 @@ def set_iteration_user_calibrated_models( Args: user_calibrated_models: - The previously-calibrated models. Keys are model hashes, values - are models. + The previously-calibrated models. """ if not user_calibrated_models: - self.iteration_user_calibrated_models = {} + self.iteration_user_calibrated_models = Models() return - iteration_uncalibrated_models = [] - iteration_user_calibrated_models = {} + iteration_uncalibrated_models = Models() + iteration_user_calibrated_models = Models() for model in self.models: if ( - (user_model := user_calibrated_models.get(model.get_hash())) + (user_model := user_calibrated_models[model.get_hash()]) is not None ) and ( user_model.get_criterion( @@ -209,11 +207,11 @@ def get_iteration_calibrated_models( The full list of calibrated models. """ combined_calibrated_models = ( - self.iteration_user_calibrated_models | calibrated_models + self.iteration_user_calibrated_models + calibrated_models ) if reset: self.set_iteration_user_calibrated_models( - user_calibrated_models={} + user_calibrated_models=Models() ) return combined_calibrated_models @@ -418,7 +416,7 @@ def consider(self, model: Model | None) -> bool: def reset_accepted(self) -> None: """Reset the accepted models.""" - self.models = [] + self.models = Models() self.distances = [] def set_predecessor_model(self, predecessor_model: Model | str | None): @@ -452,6 +450,7 @@ def set_excluded_hashes( extend: Whether to replace or extend the current excluded hashes. """ + # FIXME refactor to use `Models` and rename `set_excluded_models`? if isinstance(hashes, Model | ModelHash): hashes = [hashes] excluded_hashes = set() @@ -642,7 +641,7 @@ def distances_in_estimated_parameters( def update_after_calibration( self, *args, - iteration_calibrated_models: dict[ModelHash, Model], + iteration_calibrated_models: Models, **kwargs, ): """Do work in the candidate space after calibration. @@ -654,7 +653,7 @@ def update_after_calibration( are here, to ensure candidate spaces can be switched easily and still receive sufficient arguments. """ - self.calibrated_models |= iteration_calibrated_models + self.calibrated_models += iteration_calibrated_models self.latest_iteration_calibrated_models = iteration_calibrated_models self.set_excluded_hashes( self.latest_iteration_calibrated_models, @@ -999,7 +998,7 @@ def __init__( else: self.most_distant_max_number = 1 - self.best_models = [] + self.best_models = Models() self.best_model_of_current_run = predecessor_model self.jumped_to_most_distant = False @@ -1030,7 +1029,7 @@ def read_arguments_from_yaml_dict(cls, yaml_dict) -> dict: def update_after_calibration( self, *args, - iteration_calibrated_models: dict[str, Model], + iteration_calibrated_models: Models, **kwargs, ) -> None: """See `CandidateSpace.update_after_calibration`.""" @@ -1045,7 +1044,7 @@ def update_after_calibration( # to False and continue to candidate generation if self.jumped_to_most_distant: self.jumped_to_most_distant = False - jumped_to_model = one(iteration_calibrated_models.values()) + jumped_to_model = one(iteration_calibrated_models) self.set_predecessor_model(jumped_to_model) self.previous_predecessor_model = jumped_to_model self.best_model_of_current_run = jumped_to_model @@ -1057,7 +1056,7 @@ def update_after_calibration( logging.info("Switching method") self.switch_method() self.switch_inner_candidate_space( - excluded_hashes=list(self.calibrated_models), + excluded_hashes=self.calibrated_models, ) logging.info( "Method switched to ", self.inner_candidate_space.method @@ -1067,14 +1066,14 @@ def update_after_calibration( def update_from_iteration_calibrated_models( self, - iteration_calibrated_models: dict[str, Model], + iteration_calibrated_models: Models, ) -> bool: """Update ``self.best_models`` with the latest ``iteration_calibrated_models`` and determine if there was a new best model. If so, return ``False``. ``True`` otherwise. """ go_into_switch_method = True - for model in iteration_calibrated_models.values(): + for model in iteration_calibrated_models: if ( self.best_model_of_current_run == VIRTUAL_INITIAL_MODEL or default_compare( @@ -1319,6 +1318,7 @@ def get_most_distant( most_distance = 0 most_distant_indices = [] + # FIXME for multiple PEtab problems? parameter_ids = self.best_models[0].petab_parameters for model in self.best_models: @@ -1334,7 +1334,7 @@ def get_most_distant( # initialize the least distance to the maximal possible value of it complement_least_distance = len(complement_parameters) # get the complement least distance - for calibrated_model in self.calibrated_models.values(): + for calibrated_model in self.calibrated_models: calibrated_model_estimated_parameters = np.array( [ p == ESTIMATE diff --git a/petab_select/cli.py b/petab_select/cli.py index f318205e..37f83551 100644 --- a/petab_select/cli.py +++ b/petab_select/cli.py @@ -12,8 +12,9 @@ from . import ui from .candidate_space import CandidateSpace -from .constants import CANDIDATE_SPACE, MODELS, PETAB_YAML, TERMINATE -from .model import ModelHash, models_from_yaml_list, models_to_yaml_list +from .constants import CANDIDATE_SPACE, MODELS, PETAB_YAML, PROBLEM, TERMINATE +from .model import ModelHash +from .models import Models, models_to_yaml_list from .problem import Problem @@ -21,8 +22,8 @@ def read_state(filename: str) -> dict[str, Any]: with open(filename, "rb") as f: state = dill.load(f) - state["problem"] = dill.loads(state["problem"]) - state["candidate_space"] = dill.loads(state["candidate_space"]) + state[PROBLEM] = dill.loads(state[PROBLEM]) + state[CANDIDATE_SPACE] = dill.loads(state[CANDIDATE_SPACE]) return state @@ -40,8 +41,8 @@ def get_state( candidate_space: CandidateSpace, ) -> dict[str, Any]: state = { - "problem": dill.dumps(problem), - "candidate_space": dill.dumps(candidate_space), + PROBLEM: dill.dumps(problem), + CANDIDATE_SPACE: dill.dumps(candidate_space), } return state @@ -80,34 +81,6 @@ def cli(): default=None, help="The method used to identify the candidate models. Defaults to the method in the problem YAML.", ) -# @click.option( -# '--previous-predecessor-model', -# '-P', -# 'previous_predecessor_model_yaml', -# type=str, -# default=None, -# help='(Optional) The predecessor model used in the previous iteration of model selection.', -# ) -# @click.option( -# '--calibrated-models', -# '-C', -# 'calibrated_models_yamls', -# type=str, -# multiple=True, -# default=None, -# help='(Optional) Models that have been calibrated.', -# ) -# @click.option( -# '--newly-calibrated-models', -# '-N', -# 'newly_calibrated_models_yamls', -# type=str, -# multiple=True, -# default=None, -# help=( -# '(Optional) Models that were calibrated in the most recent iteration.' -# ), -# ) @click.option( "--limit", "-l", @@ -157,10 +130,6 @@ def start_iteration( state_dill: str, uncalibrated_models_yaml: str, method: str = None, - # previous_predecessor_model_yaml: str = None, - # best: str = None, - # calibrated_models_yamls: List[str] = None, - # newly_calibrated_models_yamls: List[str] = None, limit: float = np.inf, limit_sent: float = np.inf, relative_paths: bool = False, @@ -194,11 +163,11 @@ def start_iteration( problem = state["problem"] candidate_space = state["candidate_space"] - excluded_models = [] + excluded_models = Models() # TODO seems like default is `()`, not `None`... if excluded_model_files is not None: - for model_yaml_list in excluded_model_files: - excluded_models.extend(models_from_yaml_list(model_yaml_list)) + for models_yaml in excluded_model_files: + excluded_models.extend(Models.from_yaml(models_yaml)) # TODO test excluded_model_hashes = [] @@ -214,49 +183,12 @@ def start_iteration( ModelHash.from_hash(hash_str) for hash_str in excluded_model_hashes ] - # previous_predecessor_model = candidate_space.predecessor_model - # if previous_predecessor_model_yaml is not None: - # previous_predecessor_model = Model.from_yaml( - # previous_predecessor_model_yaml - # ) - - # # FIXME write single methods to take all models from lists of lists of - # # models recursively - # calibrated_models = None - # if calibrated_models_yamls: - # calibrated_models = {} - # for calibrated_models_yaml in calibrated_models_yamls: - # calibrated_models.update( - # { - # model.get_hash(): model - # for model in models_from_yaml_list(calibrated_models_yaml) - # } - # ) - - # newly_calibrated_models = None - # if newly_calibrated_models_yamls: - # newly_calibrated_models = {} - # for newly_calibrated_models_yaml in newly_calibrated_models_yamls: - # newly_calibrated_models.update( - # { - # model.get_hash(): model - # for model in models_from_yaml_list( - # newly_calibrated_models_yaml - # ) - # } - # ) - ui.start_iteration( problem=problem, candidate_space=candidate_space, - # previous_predecessor_model=previous_predecessor_model, - # calibrated_models=calibrated_models, - # newly_calibrated_models=newly_calibrated_models, limit=limit, limit_sent=limit_sent, excluded_hashes=excluded_hashes, - # excluded_models=excluded_models, - # excluded_model_hashes=excluded_model_hashes, ) # Save state @@ -332,15 +264,10 @@ def end_iteration( problem = state["problem"] candidate_space = state["candidate_space"] - calibrated_models = {} + calibrated_models = Models() if calibrated_models_yamls: for calibrated_models_yaml in calibrated_models_yamls: - calibrated_models.update( - { - model.get_hash(): model - for model in models_from_yaml_list(calibrated_models_yaml) - } - ) + calibrated_models.extend(Models.from_yaml(calibrated_models_yaml)) # Finalize iteration results iteration_results = ui.end_iteration( @@ -409,9 +336,9 @@ def model_to_petab( Documentation for arguments can be viewed with `petab_select model_to_petab --help`. """ - models = [] + models = Models() for models_yaml in models_yamls: - models.extend(models_from_yaml_list(models_yaml)) + models.extend(Models.from_yaml(models_yaml)) model0 = None try: @@ -468,9 +395,9 @@ def models_to_petab( Documentation for arguments can be viewed with `petab_select models_to_petab --help`. """ - models = [] + models = Models() for models_yaml in models_yamls: - models.extend(models_from_yaml_list(models_yaml)) + models.extend(Models.from_yaml(models_yaml)) model_ids = pd.Series([model.model_id for model in models]) duplicates = "\n".join(set(model_ids[model_ids.duplicated()])) @@ -559,9 +486,9 @@ def get_best( problem = Problem.from_yaml(problem_yaml) - models = [] + models = Models() for models_yaml in models_yamls: - models.extend(models_from_yaml_list(models_yaml)) + models.extend(Models.from_yaml(models_yaml)) best_model = ui.get_best( problem=problem, diff --git a/petab_select/constants.py b/petab_select/constants.py index b56e8a41..9afc1cb6 100644 --- a/petab_select/constants.py +++ b/petab_select/constants.py @@ -1,5 +1,7 @@ """Constants for the PEtab Select package.""" +from __future__ import annotations + import string import sys from enum import Enum @@ -84,6 +86,7 @@ VERSION = "version" MODEL_SPACE_FILES = "model_space_files" PROBLEM_ID = "problem_id" +PROBLEM = "problem" CANDIDATE_SPACE = "candidate_space" CANDIDATE_SPACE_ARGUMENTS = "candidate_space_arguments" diff --git a/petab_select/model.py b/petab_select/model.py index 6c7602f4..fbb040d2 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -45,8 +45,6 @@ __all__ = [ "Model", "default_compare", - "models_from_yaml_list", - "models_to_yaml_list", "ModelHash", ] @@ -56,7 +54,7 @@ class Model(PetabMixin): NB: some of these attribute names correspond to constants defined in the `constants.py` file, to facilitate loading models from/saving models to - disk (see the `saved_attributes` attribute). + disk (see the `Model.saved_attributes` class attribute). Attributes: converters_load: @@ -371,9 +369,8 @@ def from_yaml(model_yaml: TYPE_PATH) -> Model: raise raise ValueError( "The provided YAML file contains a list with greater than " - "one element. Use the `models_from_yaml_list` method or " - "provide a PEtab Select model YAML file with only one " - "model specified." + "one element. Use the `Models.from_yaml` or provide a " + "YAML file with only one model specified." ) return Model.from_dict(model_dict, base_path=Path(model_yaml).parent) @@ -656,10 +653,10 @@ def default_compare( model1: The new model. criterion: - The criterion by which models will be compared. + The criterion. criterion_threshold: The value by which the new model must improve on the original - model. Should be non-negative. + model. Should be non-negative, regardless of the criterion. Returns: ``True` if ``model1`` has a better criterion value than ``model0``, else @@ -704,97 +701,6 @@ def default_compare( raise NotImplementedError(f"Unknown criterion: {criterion}.") -def models_from_yaml_list( - model_list_yaml: TYPE_PATH, - petab_problem: petab.Problem = None, - allow_single_model: bool = True, -) -> list[Model]: - """Generate a model from a PEtab Select list of model YAML file. - - Args: - model_list_yaml: - The path to the PEtab Select list of model YAML file. - petab_problem: - See :meth:`Model.from_dict`. - allow_single_model: - Given a YAML file that contains a single model directly (not in - a 1-element list), if ``True`` then the single model will be read in, - else a ``ValueError`` will be raised. - - Returns: - A list of model instances, initialized with the provided - attributes. - """ - with open(str(model_list_yaml)) as f: - model_dict_list = yaml.safe_load(f) - if not model_dict_list: - return [] - - if not isinstance(model_dict_list, list): - if allow_single_model: - return [ - Model.from_dict( - model_dict_list, - base_path=Path(model_list_yaml).parent, - petab_problem=petab_problem, - ) - ] - raise ValueError("The YAML file does not contain a list of models.") - - return [ - Model.from_dict( - model_dict, - base_path=Path(model_list_yaml).parent, - petab_problem=petab_problem, - ) - for model_dict in model_dict_list - ] - - -def models_to_yaml_list( - models: list[Model | str] | dict[ModelHash, Model | str], - output_yaml: TYPE_PATH, - relative_paths: bool = True, -) -> None: - """Generate a YAML listing of models. - - Args: - models: - The models. - output_yaml: - The location where the YAML will be saved. - relative_paths: - Whether to rewrite the paths in each model (e.g. the path to the - model's PEtab problem) relative to the `output_yaml` location. - """ - if isinstance(models, dict): - models = list(models.values()) - - skipped_indices = [] - for index, model in enumerate(models): - if isinstance(model, Model): - continue - if model == VIRTUAL_INITIAL_MODEL: - continue - warnings.warn(f"Unexpected model, skipping: {model}.", stacklevel=2) - skipped_indices.append(index) - models = [ - model - for index, model in enumerate(models) - if index not in skipped_indices - ] - - paths_relative_to = None - if relative_paths: - paths_relative_to = Path(output_yaml).parent - model_dicts = [ - model.to_dict(paths_relative_to=paths_relative_to) for model in models - ] - model_dicts = None if not model_dicts else model_dicts - with open(output_yaml, "w") as f: - yaml.dump(model_dicts, f) - - class ModelHash(str): """A class to handle model hash functionality. diff --git a/petab_select/models.py b/petab_select/models.py new file mode 100644 index 00000000..f712add2 --- /dev/null +++ b/petab_select/models.py @@ -0,0 +1,393 @@ +from __future__ import annotations + +import warnings +from collections import Counter +from collections.abc import Iterable, MutableSequence +from pathlib import Path +from typing import TYPE_CHECKING, TypeAlias + +import yaml + +from .constants import TYPE_PATH +from .model import ( + Model, + ModelHash, +) + +if TYPE_CHECKING: + import petab + + from .problem import Problem + + # `Models` can be constructed from actual `Model`s, + # or `ModelHash`s, or the `str` of a model hash. + ModelLike: TypeAlias = Model | ModelHash | str + ModelsLike: TypeAlias = "Models" | Iterable[Model | ModelHash | str] + # Access a model by list index, model hash, slice of indices, model hash + # string, or an iterable of these things. + ModelIndex: TypeAlias = int | ModelHash | slice | str | Iterable + +__all__ = [ + "Models", + "models_from_yaml_list", + "models_to_yaml_list", +] + + +class Models(MutableSequence): + """A collection of models. + + Behaves like a list of models, but also supports operations + involving objects that can be mapped to model(s). For example, model hashes + can be used to add or access models. + + Some list methods are not yet implemented -- feel free to request anything + that feels intuitive. + + Provide a PEtab Select ``problem`` to the constructor or via + ``set_problem``, to use add models by hashes. This means that all models + must belong to the same PEtab Select problem. + """ + + def set_problem(self, problem: Problem) -> None: + """Set the PEtab Select problem for this set of models.""" + self._problem = problem + + def lint(self): + """Lint the models, e.g. check all hashes are unique. + + Currently raises an exception when invalid. + """ + duplicates = [ + model_hash + for model_hash, count in Counter(self._hashes).items() + if count > 1 + ] + if duplicates: + raise ValueError( + "Multiple models exist with the same hash. " + f"Model hashes: `{duplicates}`." + ) + + @staticmethod + def from_yaml( + models_yaml: TYPE_PATH, + petab_problem: petab.Problem = None, + problem: Problem = None, + ) -> Models: + """Generate models from a PEtab Select list of model YAML file. + + Args: + models_yaml: + The path to the PEtab Select list of model YAML file. + petab_problem: + See :meth:`Model.from_dict`. + problem: + The PEtab Select problem. + + Returns: + The models. + """ + with open(str(models_yaml)) as f: + model_dict_list = yaml.safe_load(f) + if not model_dict_list: + # Empty file + models = [] + elif not isinstance(model_dict_list, list): + # File contains a single model + models = [ + Model.from_dict( + model_dict_list, + base_path=Path(models_yaml).parent, + petab_problem=petab_problem, + ) + ] + else: + # File contains a list of models + models = [ + Model.from_dict( + model_dict, + base_path=Path(models_yaml).parent, + petab_problem=petab_problem, + ) + for model_dict in model_dict_list + ] + + return Models(models=models, problem=problem) + + def to_yaml( + self, + output_yaml: TYPE_PATH, + relative_paths: bool = True, + ) -> None: + """Generate a YAML listing of models. + + Args: + output_yaml: + The location where the YAML will be saved. + relative_paths: + Whether to rewrite the paths in each model (e.g. the path to the + model's PEtab problem) relative to the `output_yaml` location. + """ + paths_relative_to = None + if relative_paths: + paths_relative_to = Path(output_yaml).parent + model_dicts = [ + model.to_dict(paths_relative_to=paths_relative_to) + for model in self + ] + with open(output_yaml, "w") as f: + yaml.safe_dump(model_dicts, f) + + # `list` methods. Compared to `UserList`, some methods are skipped. + # https://github.com/python/cpython/blob/main/Lib/collections/__init__.py + + def __init__( + self, models: Iterable[ModelLike] = None, problem: Problem = None + ) -> Models: + self._models = [] + self._hashes = [] + self._problem = problem + + if models is None: + models = [] + self.extend(models) + + def __repr__(self) -> str: + """Get the model hashes that can regenerate these models. + + N.B.: some information, e.g. criteria, will be lost if the hashes are + used to reproduce the set of models. + """ + return repr(self._hashes) + + # skipped __lt__, __le__ + + def __eq__(self, other) -> bool: + other_hashes = Models(other)._hashes + same_length = len(self._hashes) == len(other_hashes) + same_hashes = set(self._hashes) == set(other_hashes) + return same_length and same_hashes + + # skipped __gt__, __ge__, __cast + + def __contains__(self, item: ModelLike) -> bool: + match item: + case Model(): + return item in self._models + case ModelHash() | str(): + return item in self._hashes + case _: + raise TypeError(f"Unexpected type: `{type(item)}`.") + + def __len__(self) -> int: + return len(self._models) + + def __getitem__( + self, item: ModelIndex | Iterable[ModelIndex] + ) -> Model | Models: + match item: + case int(): + return self._models[item] + case ModelHash() | str(): + return self._models[self._hashes.index(item)] + case slice(): + return self.__class__(self._models[item]) + case Iterable(): + # TODO sensible to yield here? + return [self[item_] for item_ in item] + case _: + raise TypeError(f"Unexpected type: `{type(item)}`.") + + def __setitem__(self, key: ModelIndex, item: ModelLike) -> None: + match key: + case int(): + pass + case ModelHash() | str(): + key = self._hashes.index(key) + case slice(): + for key_, item_ in zip( + range(*key.indices(len(self))), item, strict=True + ): + self[key_] = item_ + case Iterable(): + for key_, item_ in zip(key, item, strict=True): + self[key_] = item_ + case _: + raise TypeError(f"Unexpected type: `{type(key)}`.") + + match item: + case Model(): + pass + case ModelHash() | str(): + item = self._problem.model_hash_to_model(item) + case _: + raise TypeError(f"Unexpected type: `{type(item)}`.") + + if key < len(self._models): + self._models[key] = item + self._hashes[key] = item.get_hash() + else: + # Key doesn't exist, e.g., instead of + # models[1] = model1 + # the user did something like + # models[model1_hash] = model1 + # to add a new model. + self.append(item) + + def __delitem__(self, key: ModelIndex) -> None: + match key: + case ModelHash() | str(): + key = self._hashes.index(key) + case slice(): + for key_ in range(*key.indices(len(self))): + del self[key_] + case Iterable(): + for key_ in key: + del self[key_] + case _: + raise TypeError(f"Unexpected type: `{type(key)}`.") + + del self._models[key] + del self._hashes[key] + + def __add__( + self, other: ModelLike | ModelsLike, left: bool = True + ) -> Models: + match other: + case Models(): + new_models = other._models + case Model(): + new_models = [other] + case ModelHash() | str(): + # Assumes the models belong to the same PEtab Select problem. + new_models = [self._problem.model_hash_to_model(other)] + case Iterable(): + # Assumes the models belong to the same PEtab Select problem. + new_models = Models(other, problem=self._problem)._models + case _: + raise TypeError(f"Unexpected type: `{type(other)}`.") + + models = self._models + new_models + if not left: + models = new_models + self._models + return Models(models=models, problem=self._problem) + + def __radd__(self, other: ModelLike | ModelsLike) -> Models: + return self.__add__(other=other, left=False) + + def __iadd__(self, other: ModelLike | ModelsLike) -> Models: + return self.__add__(other=other) + + # skipped __mul__, __rmul__, __imul__ + + def __copy__(self) -> Models: + return Models(models=self._models, problem=self._problem) + + def append(self, item: ModelLike) -> None: + # Re-use __setitem__ logic + self._models.append(None) + self._hashes.append(None) + self[-1] = item + + def insert(self, index: int, item: ModelLike): + # Re-use __setitem__ logic + self._models.insert(index, None) + self._hashes.insert(index, None) + self[index] = item + + # def pop(self, index: int = -1): + # model = self._models[index] + + # # Re-use __delitem__ logic + # del self[index] + + # return model + + # def remove(self, item: ModelLike): + # # Re-use __delitem__ logic + # if isinstance(item, Model): + # item = item.get_hash() + # del self[item] + + # skipped clear, copy, count + + def index(self, item: ModelLike, *args) -> int: + if isinstance(item, Model): + item = item.get_hash() + return self._hashes.index(item, *args) + + # skipped reverse, sort + + def extend(self, other: Iterable[ModelLike]) -> None: + # Re-use append and therein __setitem__ logic + for model_like in other: + self.append(model_like) + + +def models_from_yaml_list( + model_list_yaml: TYPE_PATH, + petab_problem: petab.Problem = None, + allow_single_model: bool = True, + problem: Problem = None, +) -> Models: + """Generate a model from a PEtab Select list of model YAML file. + + Deprecated. Use `petab_select.Models.from_yaml` instead. + + Args: + model_list_yaml: + The path to the PEtab Select list of model YAML file. + petab_problem: + See :meth:`Model.from_dict`. + allow_single_model: + Given a YAML file that contains a single model directly (not in + a 1-element list), if ``True`` then the single model will be read in, + else a ``ValueError`` will be raised. + problem: + The PEtab Select problem. + + Returns: + The models. + """ + warnings.warn( + ( + "Use `petab_select.Models.from_yaml` instead. " + "The `allow_single_model` argument is fixed to `True` now." + ), + DeprecationWarning, + stacklevel=2, + ) + return Models.from_yaml( + models_yaml=model_list_yaml, + petab_problem=petab_problem, + problem=problem, + ) + + +def models_to_yaml_list( + models: Models, + output_yaml: TYPE_PATH, + relative_paths: bool = True, +) -> None: + """Generate a YAML listing of models. + + Deprecated. Use `petab_select.Models.to_yaml` instead. + + Args: + models: + The models. + output_yaml: + The location where the YAML will be saved. + relative_paths: + Whether to rewrite the paths in each model (e.g. the path to the + model's PEtab problem) relative to the `output_yaml` location. + """ + warnings.warn( + "Use `petab_select.Models.to_yaml` instead.", + DeprecationWarning, + stacklevel=2, + ) + Models(models=models).to_yaml( + output_yaml=output_yaml, relative_paths=relative_paths + ) diff --git a/petab_select/problem.py b/petab_select/problem.py index c7e20146..b0a763bd 100644 --- a/petab_select/problem.py +++ b/petab_select/problem.py @@ -1,5 +1,6 @@ """The model selection problem class.""" +import warnings from collections.abc import Callable, Iterable from functools import partial from pathlib import Path @@ -21,6 +22,7 @@ ) from .model import Model, ModelHash, default_compare from .model_space import ModelSpace +from .models import Models __all__ = [ "Problem", @@ -122,7 +124,7 @@ def get_path(self, relative_path: str | Path) -> Path: def exclude_models( self, - models: Iterable[Model], + models: Models, ) -> None: """Exclude models from the model space. @@ -142,7 +144,13 @@ def exclude_model_hashes( model_hashes: The model hashes. """ - self.model_space.exclude_model_hashes(model_hashes) + # FIXME think about design here -- should we have exclude_models here? + warnings.warn( + "Use `exclude_models` instead. It also accepts hashes.", + DeprecationWarning, + stacklevel=2, + ) + self.exclude_models(models=Models(models=model_hashes, problem=self)) @staticmethod def from_yaml( @@ -212,7 +220,8 @@ def from_yaml( def get_best( self, - models: list[Model] | dict[ModelHash, Model] | None, + models: Models, + # models: list[Model] | dict[ModelHash, Model] | None, criterion: str | None | None = None, compute_criterion: bool = False, ) -> Model: @@ -222,11 +231,9 @@ def get_best( Args: models: - The best model will be taken from these models. + The models. criterion: - The criterion by which models will be compared. Defaults to - ``self.criterion`` (e.g. as defined in the PEtab Select problem YAML - file). + The criterion. Defaults to the problem criterion. compute_criterion: Whether to try computing criterion values, if sufficient information is available (e.g., likelihood and number of @@ -235,8 +242,6 @@ def get_best( Returns: The best model. """ - if isinstance(models, dict): - models = list(models.values()) if criterion is None: criterion = self.criterion diff --git a/petab_select/ui.py b/petab_select/ui.py index f5ed1f10..d2dd3f1a 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -18,6 +18,7 @@ Method, ) from .model import Model, ModelHash, default_compare +from .models import Models from .problem import Problem __all__ = [ @@ -45,7 +46,7 @@ def start_iteration( limit_sent: float | int = np.inf, excluded_hashes: list[ModelHash] | None = None, criterion: Criterion | None = None, - user_calibrated_models: list[Model] | dict[ModelHash, Model] | None = None, + user_calibrated_models: Models | None = None, ) -> CandidateSpace: """Search the model space for candidate models. @@ -71,8 +72,7 @@ def start_iteration( The criterion by which models will be compared. Defaults to the criterion defined in the PEtab Select problem. user_calibrated_models: - Models that were already calibrated by the user. When supplied as a - `dict`, the keys are model hashes. If a model in the + Models that were already calibrated by the user. If a model in the candidates has the same hash as a model in `user_calibrated_models`, then the candidate will be replaced with the calibrated version. Calibration tools will only receive uncalibrated @@ -124,7 +124,7 @@ def start_iteration( ) is None ): - candidate_space.models = [copy.deepcopy(predecessor_model)] + candidate_space.models = Models([copy.deepcopy(predecessor_model)]) # Dummy zero likelihood, which the predecessor model will # improve on after it's actually calibrated. predecessor_model.set_criterion(Criterion.LH, 0.0) @@ -145,7 +145,7 @@ def start_iteration( # this is not the first step of the search. if candidate_space.latest_iteration_calibrated_models: predecessor_model = problem.get_best( - candidate_space.latest_iteration_calibrated_models.values(), + candidate_space.latest_iteration_calibrated_models, criterion=criterion, ) # If the new predecessor model isn't better than the previous one, @@ -194,7 +194,7 @@ def start_iteration( if isinstance(candidate_space, FamosCandidateSpace): try: candidate_space.update_after_calibration( - iteration_calibrated_models={}, + iteration_calibrated_models=Models(), ) continue except StopIteration: @@ -214,8 +214,8 @@ def start_iteration( def end_iteration( candidate_space: CandidateSpace, - calibrated_models: list[Model] | dict[str, Model], -) -> dict[str, dict[ModelHash, Model] | bool | CandidateSpace]: + calibrated_models: Models, +) -> dict[str, Models | bool | CandidateSpace]: """Finalize model selection iteration. All models from the current iteration are provided to the calibration tool. @@ -234,17 +234,11 @@ def end_iteration( Returns: A dictionary, with the following items: :const:`petab_select.constants.MODELS`: - All calibrated models for the current iteration as a - dictionary, where keys are model hashes, and values are models. + All calibrated models for the current iteration. :const:`petab_select.constants.TERMINATE`: Whether PEtab Select has decided to end the model selection, as a boolean. """ - if isinstance(calibrated_models, list): - calibrated_models = { - model.get_hash(): model for model in calibrated_models - } - iteration_results = { MODELS: candidate_space.get_iteration_calibrated_models( calibrated_models=calibrated_models, @@ -288,7 +282,7 @@ def model_to_petab( def models_to_petab( - models: list[Model], + models: Models, output_path_prefix: list[TYPE_PATH] | None = None, ) -> list[dict[str, petab.Problem | TYPE_PATH]]: """Generate the PEtab problems for a list of models. From 5d8faace30faff8f80b24edab976b48a5009101c Mon Sep 17 00:00:00 2001 From: dilpath Date: Fri, 29 Nov 2024 17:38:14 +0100 Subject: [PATCH 02/88] fix tests --- petab_select/candidate_space.py | 6 +- petab_select/models.py | 363 +++++++++++++++++++------------- petab_select/ui.py | 23 ++ test/pypesto/test_pypesto.py | 3 +- test/ui/test_ui.py | 3 +- 5 files changed, 254 insertions(+), 144 deletions(-) diff --git a/petab_select/candidate_space.py b/petab_select/candidate_space.py index fad615e6..b559bbc8 100644 --- a/petab_select/candidate_space.py +++ b/petab_select/candidate_space.py @@ -155,7 +155,11 @@ def set_iteration_user_calibrated_models( iteration_user_calibrated_models = Models() for model in self.models: if ( - (user_model := user_calibrated_models[model.get_hash()]) + ( + user_model := user_calibrated_models.get( + model.get_hash(), None + ) + ) is not None ) and ( user_model.get_criterion( diff --git a/petab_select/models.py b/petab_select/models.py index f712add2..49359b45 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -28,119 +28,38 @@ ModelIndex: TypeAlias = int | ModelHash | slice | str | Iterable __all__ = [ + "ListDict", "Models", "models_from_yaml_list", "models_to_yaml_list", ] -class Models(MutableSequence): - """A collection of models. - - Behaves like a list of models, but also supports operations - involving objects that can be mapped to model(s). For example, model hashes - can be used to add or access models. - - Some list methods are not yet implemented -- feel free to request anything - that feels intuitive. - - Provide a PEtab Select ``problem`` to the constructor or via - ``set_problem``, to use add models by hashes. This means that all models - must belong to the same PEtab Select problem. - """ - - def set_problem(self, problem: Problem) -> None: - """Set the PEtab Select problem for this set of models.""" - self._problem = problem - - def lint(self): - """Lint the models, e.g. check all hashes are unique. +class ListDict(MutableSequence): + """Acts like a ``list`` and a ``dict``. - Currently raises an exception when invalid. - """ - duplicates = [ - model_hash - for model_hash, count in Counter(self._hashes).items() - if count > 1 - ] - if duplicates: - raise ValueError( - "Multiple models exist with the same hash. " - f"Model hashes: `{duplicates}`." - ) - - @staticmethod - def from_yaml( - models_yaml: TYPE_PATH, - petab_problem: petab.Problem = None, - problem: Problem = None, - ) -> Models: - """Generate models from a PEtab Select list of model YAML file. - - Args: - models_yaml: - The path to the PEtab Select list of model YAML file. - petab_problem: - See :meth:`Model.from_dict`. - problem: - The PEtab Select problem. - - Returns: - The models. - """ - with open(str(models_yaml)) as f: - model_dict_list = yaml.safe_load(f) - if not model_dict_list: - # Empty file - models = [] - elif not isinstance(model_dict_list, list): - # File contains a single model - models = [ - Model.from_dict( - model_dict_list, - base_path=Path(models_yaml).parent, - petab_problem=petab_problem, - ) - ] - else: - # File contains a list of models - models = [ - Model.from_dict( - model_dict, - base_path=Path(models_yaml).parent, - petab_problem=petab_problem, - ) - for model_dict in model_dict_list - ] + Not all methods are implemented -- feel free to request anything that you + think makes sense for a ``list`` or ``dict`` object. - return Models(models=models, problem=problem) + The context is a list of objects that may have some metadata (e.g. a hash) + associated with each of them. The objects can be operated on like a list, + or requested like a dict, by their metadata (hash). - def to_yaml( - self, - output_yaml: TYPE_PATH, - relative_paths: bool = True, - ) -> None: - """Generate a YAML listing of models. + Mostly based on ``UserList`` and ``UserDict``, but some methods are + currently not yet implemented. + https://github.com/python/cpython/blob/main/Lib/collections/__init__.py - Args: - output_yaml: - The location where the YAML will be saved. - relative_paths: - Whether to rewrite the paths in each model (e.g. the path to the - model's PEtab problem) relative to the `output_yaml` location. - """ - paths_relative_to = None - if relative_paths: - paths_relative_to = Path(output_yaml).parent - model_dicts = [ - model.to_dict(paths_relative_to=paths_relative_to) - for model in self - ] - with open(output_yaml, "w") as f: - yaml.safe_dump(model_dicts, f) + The typing is currently based on PEtab Select objects. Hence, objects are + in ``_models``, and metadata (model hashes) are in ``_hashes``. - # `list` methods. Compared to `UserList`, some methods are skipped. - # https://github.com/python/cpython/blob/main/Lib/collections/__init__.py + Attributes: + _models: + The list of objects (list items/dictionary values) + (PEtab Select models). + _hashes: + The list of metadata (dictionary keys) (model hashes). + _problem: + """ def __init__( self, models: Iterable[ModelLike] = None, problem: Problem = None @@ -184,27 +103,54 @@ def __len__(self) -> int: return len(self._models) def __getitem__( - self, item: ModelIndex | Iterable[ModelIndex] + self, key: ModelIndex | Iterable[ModelIndex] ) -> Model | Models: - match item: - case int(): - return self._models[item] + try: + match key: + case int(): + return self._models[key] + case ModelHash() | str(): + return self._models[self._hashes.index(key)] + case slice(): + print(key) + return self.__class__(self._models[key]) + case Iterable(): + # TODO sensible to yield here? + return [self[key_] for key_ in key] + case _: + raise TypeError(f"Unexpected type: `{type(key)}`.") + except ValueError as err: + raise KeyError from err + + def _model_like_to_model(self, model_like: ModelLike) -> Model: + """Get the model that corresponds to a model-like object. + + Args: + model_like: + Something that uniquely identifies a model; a model or a model + hash. + + Returns: + The model. + """ + match model_like: + case Model(): + model = model_like case ModelHash() | str(): - return self._models[self._hashes.index(item)] - case slice(): - return self.__class__(self._models[item]) - case Iterable(): - # TODO sensible to yield here? - return [self[item_] for item_ in item] + model = self._problem.model_hash_to_model(model_like) case _: - raise TypeError(f"Unexpected type: `{type(item)}`.") + raise TypeError(f"Unexpected type: `{type(model_like)}`.") + return model def __setitem__(self, key: ModelIndex, item: ModelLike) -> None: match key: case int(): pass case ModelHash() | str(): - key = self._hashes.index(key) + if key in self._hashes: + key = self._hashes.index(key) + else: + key = len(self) case slice(): for key_, item_ in zip( range(*key.indices(len(self))), item, strict=True @@ -216,15 +162,9 @@ def __setitem__(self, key: ModelIndex, item: ModelLike) -> None: case _: raise TypeError(f"Unexpected type: `{type(key)}`.") - match item: - case Model(): - pass - case ModelHash() | str(): - item = self._problem.model_hash_to_model(item) - case _: - raise TypeError(f"Unexpected type: `{type(item)}`.") + item = self._model_like_to_model(model_like=item) - if key < len(self._models): + if key < len(self): self._models[key] = item self._hashes[key] = item.get_hash() else: @@ -235,18 +175,49 @@ def __setitem__(self, key: ModelIndex, item: ModelLike) -> None: # to add a new model. self.append(item) + def _update(self, index: int, item: ModelLike) -> None: + """Update the models by adding a new model or overwriting an old model. + + Args: + index: + The index where the model will be inserted, if it doesn't + already exist. + item: + A model or a model hash. + """ + model = self._model_like_to_model(item) + if model.get_hash() in self: + warnings.warn( + ( + f"A model with hash `{model.get_hash()}` already exists " + "in this collection of models. The previous model will be " + "overwritten." + ), + RuntimeWarning, + stacklevel=2, + ) + self[model.get_hash()] = model + else: + self._models.insert(index, None) + self._hashes.insert(index, None) + # Re-use __setitem__ logic + self[index] = item + def __delitem__(self, key: ModelIndex) -> None: - match key: - case ModelHash() | str(): - key = self._hashes.index(key) - case slice(): - for key_ in range(*key.indices(len(self))): - del self[key_] - case Iterable(): - for key_ in key: - del self[key_] - case _: - raise TypeError(f"Unexpected type: `{type(key)}`.") + try: + match key: + case ModelHash() | str(): + key = self._hashes.index(key) + case slice(): + for key_ in range(*key.indices(len(self))): + del self[key_] + case Iterable(): + for key_ in key: + del self[key_] + case _: + raise TypeError(f"Unexpected type: `{type(key)}`.") + except ValueError as err: + raise KeyError from err del self._models[key] del self._hashes[key] @@ -285,16 +256,10 @@ def __copy__(self) -> Models: return Models(models=self._models, problem=self._problem) def append(self, item: ModelLike) -> None: - # Re-use __setitem__ logic - self._models.append(None) - self._hashes.append(None) - self[-1] = item + self._update(index=len(self), item=item) def insert(self, index: int, item: ModelLike): - # Re-use __setitem__ logic - self._models.insert(index, None) - self._hashes.insert(index, None) - self[index] = item + self._update(index=len(self), item=item) # def pop(self, index: int = -1): # model = self._models[index] @@ -324,6 +289,122 @@ def extend(self, other: Iterable[ModelLike]) -> None: for model_like in other: self.append(model_like) + # __iter__/__next__? Not in UserList... + + # `dict` methods. + + def get( + self, + key: ModelIndex | Iterable[ModelIndex], + default: ModelLike | None = None, + ) -> Model | Models: + try: + return self[key] + except KeyError: + return default + + +class Models(ListDict): + """A collection of models. + + Provide a PEtab Select ``problem`` to the constructor or via + ``set_problem``, to use add models by hashes. This means that all models + must belong to the same PEtab Select problem. + + This permits both ``list`` and ``dict`` operations -- see + :class:``ListDict`` for further details. + """ + + def set_problem(self, problem: Problem) -> None: + """Set the PEtab Select problem for this set of models.""" + self._problem = problem + + def lint(self): + """Lint the models, e.g. check all hashes are unique. + + Currently raises an exception when invalid. + """ + duplicates = [ + model_hash + for model_hash, count in Counter(self._hashes).items() + if count > 1 + ] + if duplicates: + raise ValueError( + "Multiple models exist with the same hash. " + f"Model hashes: `{duplicates}`." + ) + + @staticmethod + def from_yaml( + models_yaml: TYPE_PATH, + petab_problem: petab.Problem = None, + problem: Problem = None, + ) -> Models: + """Generate models from a PEtab Select list of model YAML file. + + Args: + models_yaml: + The path to the PEtab Select list of model YAML file. + petab_problem: + See :meth:`Model.from_dict`. + problem: + The PEtab Select problem. + + Returns: + The models. + """ + with open(str(models_yaml)) as f: + model_dict_list = yaml.safe_load(f) + if not model_dict_list: + # Empty file + models = [] + elif not isinstance(model_dict_list, list): + # File contains a single model + models = [ + Model.from_dict( + model_dict_list, + base_path=Path(models_yaml).parent, + petab_problem=petab_problem, + ) + ] + else: + # File contains a list of models + models = [ + Model.from_dict( + model_dict, + base_path=Path(models_yaml).parent, + petab_problem=petab_problem, + ) + for model_dict in model_dict_list + ] + + return Models(models=models, problem=problem) + + def to_yaml( + self, + output_yaml: TYPE_PATH, + relative_paths: bool = True, + ) -> None: + """Generate a YAML listing of models. + + Args: + output_yaml: + The location where the YAML will be saved. + relative_paths: + Whether to rewrite the paths in each model (e.g. the path to the + model's PEtab problem) relative to the `output_yaml` location. + """ + paths_relative_to = None + if relative_paths: + paths_relative_to = Path(output_yaml).parent + model_dicts = [ + model.to_dict(paths_relative_to=paths_relative_to) + for model in self + ] + with open(output_yaml, "w") as f: + yaml.safe_dump(model_dicts, f) + def models_from_yaml_list( model_list_yaml: TYPE_PATH, diff --git a/petab_select/ui.py b/petab_select/ui.py index d2dd3f1a..b06373f8 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -1,4 +1,5 @@ import copy +import warnings from pathlib import Path from typing import Any @@ -93,6 +94,17 @@ def start_iteration( - add `Iteration` class to manage an iteration, append to `CandidateSpace.iterations`? """ + if isinstance(user_calibrated_models, dict): + warnings.warn( + ( + "`calibrated_models` should be a `petab_select.Models` object." + "e.g. `calibrated_models = " + "petab_select.Models(old_calibrated_models.values())`." + ), + DeprecationWarning, + stacklevel=2, + ) + user_calibrated_models = Models(user_calibrated_models.values()) do_search = True # FIXME might be difficult for a CLI tool to specify a specific predecessor # model if their candidate space has models. Need a way to empty @@ -239,6 +251,17 @@ def end_iteration( Whether PEtab Select has decided to end the model selection, as a boolean. """ + if isinstance(calibrated_models, dict): + warnings.warn( + ( + "`calibrated_models` should be a `petab_select.Models` object." + "e.g. `calibrated_models = " + "petab_select.Models(old_calibrated_models.values())`." + ), + DeprecationWarning, + stacklevel=2, + ) + calibrated_models = Models(calibrated_models.values()) iteration_results = { MODELS: candidate_space.get_iteration_calibrated_models( calibrated_models=calibrated_models, diff --git a/test/pypesto/test_pypesto.py b/test/pypesto/test_pypesto.py index de6f2576..e670d8cc 100644 --- a/test/pypesto/test_pypesto.py +++ b/test/pypesto/test_pypesto.py @@ -19,6 +19,7 @@ # Set to `[]` to test all test_cases = [ + # '0001', # '0006', # '0002', # '0008', @@ -77,7 +78,7 @@ def test_pypesto(test_case_path_stem): # Get the best model best_model = petab_select_problem.get_best( - models=pypesto_select_problem.calibrated_models.values(), + models=pypesto_select_problem.calibrated_models, ) # Load the expected model. diff --git a/test/ui/test_ui.py b/test/ui/test_ui.py index dcfaac7f..7efb442b 100644 --- a/test/ui/test_ui.py +++ b/test/ui/test_ui.py @@ -4,6 +4,7 @@ from more_itertools import one import petab_select +from petab_select import Models from petab_select.constants import ( CANDIDATE_SPACE, MODELS, @@ -30,7 +31,7 @@ def test_user_calibrated_models(petab_select_problem): model_M1_2.set_criterion( criterion=petab_select_problem.criterion, value=12.3 ) - user_calibrated_models = {model_M1_2.get_hash(): model_M1_2} + user_calibrated_models = Models([model_M1_2]) # Initial iteration: expect the "empty" model. Set dummy criterion and continue. iteration = petab_select.ui.start_iteration( From 28da0cd3ddb00d548a465e595adbe0d3a3548b13 Mon Sep 17 00:00:00 2001 From: dilpath Date: Fri, 29 Nov 2024 18:17:14 +0100 Subject: [PATCH 03/88] update notebooks --- doc/examples/example_cli_famos.ipynb | 2 +- doc/examples/workflow_cli.ipynb | 4 ++-- doc/examples/workflow_python.ipynb | 16 ++++++++-------- petab_select/candidate_space.py | 8 +++++++- petab_select/models.py | 5 ++++- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/doc/examples/example_cli_famos.ipynb b/doc/examples/example_cli_famos.ipynb index a1d32a11..c413cb75 100644 --- a/doc/examples/example_cli_famos.ipynb +++ b/doc/examples/example_cli_famos.ipynb @@ -142,7 +142,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "petab_select/candidate_space.py:1137: RuntimeWarning: Model `model_subspace_1-0001011010010010` has been previously excluded from the candidate space so is skipped here.\n", + "petab_select/petab_select/candidate_space.py:1142: RuntimeWarning: Model `model_subspace_1-0001011010010010` has been previously excluded from the candidate space so is skipped here.\n", " return_value = self.inner_candidate_space.consider(model)\n" ] }, diff --git a/doc/examples/workflow_cli.ipynb b/doc/examples/workflow_cli.ipynb index 6f4cf836..9acf36b8 100644 --- a/doc/examples/workflow_cli.ipynb +++ b/doc/examples/workflow_cli.ipynb @@ -817,7 +817,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "id": "d5d03cd6", "metadata": {}, "outputs": [ @@ -825,7 +825,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "output_cli/best_model_petab/problem.yaml\n" + "petab_select/doc/examples/output_cli/best_model_petab/problem.yaml\n" ] } ], diff --git a/doc/examples/workflow_python.ipynb b/doc/examples/workflow_python.ipynb index 170c767b..cbc7afb8 100644 --- a/doc/examples/workflow_python.ipynb +++ b/doc/examples/workflow_python.ipynb @@ -230,7 +230,7 @@ ], "source": [ "local_best_model = petab_select.ui.get_best(\n", - " problem=select_problem, models=iteration_results[MODELS].values()\n", + " problem=select_problem, models=iteration_results[MODELS]\n", ")\n", "print_model(local_best_model)" ] @@ -322,10 +322,10 @@ " problem=select_problem, candidate_space=iteration_results[CANDIDATE_SPACE]\n", ")\n", "local_best_model = petab_select.ui.get_best(\n", - " problem=select_problem, models=iteration_results[MODELS].values()\n", + " problem=select_problem, models=iteration_results[MODELS]\n", ")\n", "\n", - "for candidate_model in iteration_results[MODELS].values():\n", + "for candidate_model in iteration_results[MODELS]:\n", " if candidate_model.get_hash() == local_best_model.get_hash():\n", " print(BOLD_TEXT + \"BEST MODEL OF CURRENT ITERATION\" + NORMAL_TEXT)\n", " print_model(candidate_model)" @@ -372,10 +372,10 @@ " problem=select_problem, candidate_space=iteration_results[CANDIDATE_SPACE]\n", ")\n", "local_best_model = petab_select.ui.get_best(\n", - " problem=select_problem, models=iteration_results[MODELS].values()\n", + " problem=select_problem, models=iteration_results[MODELS]\n", ")\n", "\n", - "for candidate_model in iteration_results[MODELS].values():\n", + "for candidate_model in iteration_results[MODELS]:\n", " if candidate_model.get_hash() == local_best_model.get_hash():\n", " print(BOLD_TEXT + \"BEST MODEL OF CURRENT ITERATION\" + NORMAL_TEXT)\n", " print_model(candidate_model)" @@ -415,10 +415,10 @@ " problem=select_problem, candidate_space=iteration_results[CANDIDATE_SPACE]\n", ")\n", "local_best_model = petab_select.ui.get_best(\n", - " problem=select_problem, models=iteration_results[MODELS].values()\n", + " problem=select_problem, models=iteration_results[MODELS]\n", ")\n", "\n", - "for candidate_model in iteration_results[MODELS].values():\n", + "for candidate_model in iteration_results[MODELS]:\n", " if candidate_model.get_hash() == local_best_model.get_hash():\n", " print(BOLD_TEXT + \"BEST MODEL OF CURRENT ITERATION\" + NORMAL_TEXT)\n", " print_model(candidate_model)" @@ -501,7 +501,7 @@ "source": [ "best_model = petab_select.ui.get_best(\n", " problem=select_problem,\n", - " models=iteration_results[CANDIDATE_SPACE].calibrated_models.values(),\n", + " models=iteration_results[CANDIDATE_SPACE].calibrated_models,\n", ")\n", "print_model(best_model)" ] diff --git a/petab_select/candidate_space.py b/petab_select/candidate_space.py index b559bbc8..8af42c14 100644 --- a/petab_select/candidate_space.py +++ b/petab_select/candidate_space.py @@ -1002,7 +1002,13 @@ def __init__( else: self.most_distant_max_number = 1 - self.best_models = Models() + # TODO update to new `Models` type. Currently problematic because the + # order of `best_models` matters. This would be fine for `Models` to + # handle, except that `Models._update` will use a pre-existing index + # if there is a model with the same hash. FIXME regenerate the expected + # FAMoS models when `best_models` never contains duplicate models... + # Also add a `sort` method to `Models` to sort by criterion. + self.best_models = [] self.best_model_of_current_run = predecessor_model self.jumped_to_most_distant = False diff --git a/petab_select/models.py b/petab_select/models.py index 49359b45..fa0cf579 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -176,7 +176,10 @@ def __setitem__(self, key: ModelIndex, item: ModelLike) -> None: self.append(item) def _update(self, index: int, item: ModelLike) -> None: - """Update the models by adding a new model or overwriting an old model. + """Update the models by adding a new model, with possible replacement. + + If the instance contains a model with a matching hash, that model + will be replaced. Args: index: From 2926e6cde93a010afb6ddbb6184356293ef3c564 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:32:53 +0100 Subject: [PATCH 04/88] Update petab_select/ui.py Co-authored-by: Daniel Weindl --- petab_select/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/petab_select/ui.py b/petab_select/ui.py index b06373f8..df8cc318 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -97,7 +97,7 @@ def start_iteration( if isinstance(user_calibrated_models, dict): warnings.warn( ( - "`calibrated_models` should be a `petab_select.Models` object." + "`calibrated_models` should be a `petab_select.Models` object. " "e.g. `calibrated_models = " "petab_select.Models(old_calibrated_models.values())`." ), From b52fa5377eada8fa0a6318066c1f5eeea4a81f95 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:32:58 +0100 Subject: [PATCH 05/88] Update petab_select/ui.py Co-authored-by: Daniel Weindl --- petab_select/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/petab_select/ui.py b/petab_select/ui.py index df8cc318..301dd3df 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -254,7 +254,7 @@ def end_iteration( if isinstance(calibrated_models, dict): warnings.warn( ( - "`calibrated_models` should be a `petab_select.Models` object." + "`calibrated_models` should be a `petab_select.Models` object. " "e.g. `calibrated_models = " "petab_select.Models(old_calibrated_models.values())`." ), From ffaef407515347aa6931d81d2778bfa77cf876be Mon Sep 17 00:00:00 2001 From: dilpath Date: Mon, 2 Dec 2024 20:56:23 +0100 Subject: [PATCH 06/88] track iterations; fix `ModelHash.get_model`; add `Model.__repr__` --- petab_select/candidate_space.py | 20 ++++++++++++++++---- petab_select/constants.py | 1 + petab_select/model.py | 19 ++++++++++++++----- petab_select/ui.py | 3 +++ 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/petab_select/candidate_space.py b/petab_select/candidate_space.py index 8af42c14..03dd2f78 100644 --- a/petab_select/candidate_space.py +++ b/petab_select/candidate_space.py @@ -63,6 +63,8 @@ class CandidateSpace(abc.ABC): An example of a difference is in the bidirectional method, where ``governing_method`` stores the bidirectional method, whereas `method` may also store the forward or backward methods. + iteration: + The iteration of model selection. limit: A handler to limit the number of accepted models. models: @@ -104,6 +106,7 @@ def __init__( summary_tsv: TYPE_PATH = None, previous_predecessor_model: Model | None = None, calibrated_models: Models | None = None, + iteration: int = 0, ): """See class attributes for arguments.""" self.method = method @@ -130,6 +133,7 @@ def __init__( self.criterion = criterion self.calibrated_models = calibrated_models or Models() self.latest_iteration_calibrated_models = Models() + self.iteration = iteration def set_iteration_user_calibrated_models( self, user_calibrated_models: Models | None @@ -187,9 +191,11 @@ def set_iteration_user_calibrated_models( self.models = iteration_uncalibrated_models def get_iteration_calibrated_models( - self, calibrated_models: dict[str, Model], reset: bool = False - ) -> dict[str, Model]: - """Get the full list of calibrated models for the current iteration. + self, + calibrated_models: Models, + reset: bool = False, + ) -> Models: + """Get all calibrated models for the current iteration. The full list of models identified for calibration in an iteration of model selection may include models for which calibration results are @@ -206,9 +212,12 @@ def get_iteration_calibrated_models( Whether to remove the previously calibrated models from the candidate space, after they are used to produce the full list of calibrated models. + iteration: + If provided, the iteration attribute of each model will be set + to this. Returns: - The full list of calibrated models. + All calibrated models for the current iteration. """ combined_calibrated_models = ( self.iteration_user_calibrated_models + calibrated_models @@ -217,6 +226,9 @@ def get_iteration_calibrated_models( self.set_iteration_user_calibrated_models( user_calibrated_models=Models() ) + for model in combined_calibrated_models: + model.iteration = self.iteration + return combined_calibrated_models def write_summary_tsv(self, row: list[Any]): diff --git a/petab_select/constants.py b/petab_select/constants.py index 9afc1cb6..2946aeb5 100644 --- a/petab_select/constants.py +++ b/petab_select/constants.py @@ -49,6 +49,7 @@ # PEtab Select model selection problem (but may be subsequently stored in the # PEtab Select model report format. PREDECESSOR_MODEL_HASH = "predecessor_model_hash" +ITERATION = "iteration" PETAB_PROBLEM = "petab_problem" PETAB_YAML = "petab_yaml" HASH = "hash" diff --git a/petab_select/model.py b/petab_select/model.py index fbb040d2..62e6d919 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -15,6 +15,7 @@ from .constants import ( CRITERIA, ESTIMATED_PARAMETERS, + ITERATION, MODEL_HASH, MODEL_HASH_DELIMITER, MODEL_ID, @@ -63,6 +64,9 @@ class Model(PetabMixin): Functions to convert attributes from :class:`Model` to YAML. criteria: The criteria values of the calibrated model (e.g. AIC). + iteration: + The iteration of the model selection algorithm where this model was + identified. model_id: The model ID. petab_yaml: @@ -90,6 +94,7 @@ class Model(PetabMixin): PARAMETERS, ESTIMATED_PARAMETERS, CRITERIA, + ITERATION, ) converters_load = { MODEL_ID: lambda x: x, @@ -105,6 +110,7 @@ class Model(PetabMixin): Criterion(criterion_id_value): float(criterion_value) for criterion_id_value, criterion_value in x.items() }, + ITERATION: lambda x: int(x), } converters_save = { MODEL_ID: lambda x: str(x), @@ -126,6 +132,7 @@ class Model(PetabMixin): criterion_id.value: float(criterion_value) for criterion_id, criterion_value in x.items() }, + ITERATION: lambda x: int(x), } def __init__( @@ -138,6 +145,7 @@ def __init__( parameters: dict[str, int | float] = None, estimated_parameters: dict[str, int | float] = None, criteria: dict[str, float] = None, + iteration: int = None, # Optionally provided to reduce repeated parsing of `petab_yaml`. petab_problem: petab.Problem | None = None, model_hash: Any | None = None, @@ -149,6 +157,7 @@ def __init__( self.parameters = parameters self.estimated_parameters = estimated_parameters self.criteria = criteria + self.iteration = iteration self.predecessor_model_hash = predecessor_model_hash if self.predecessor_model_hash is not None: @@ -536,6 +545,10 @@ def __str__(self): # data = f'{self.model_id}\t{self.petab_yaml}\t{parameter_values}' return f"{header}\n{data}" + def __repr__(self) -> str: + """The model hash.""" + return f'' + def get_mle(self) -> dict[str, float]: """Get the maximum likelihood estimate of the model.""" """ @@ -952,11 +965,7 @@ def get_model(self, petab_select_problem: Problem) -> Model: return petab_select_problem.model_space.model_subspaces[ self.model_subspace_id - ].indices_to_model( - self.unhash_model_subspace_indices( - self.model_subspace_indices_hash - ) - ) + ].indices_to_model(self.unhash_model_subspace_indices()) def __hash__(self) -> str: """The PEtab hash. diff --git a/petab_select/ui.py b/petab_select/ui.py index 301dd3df..4de4b3d2 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -121,6 +121,9 @@ def start_iteration( raise ValueError("Please provide a criterion.") candidate_space.criterion = criterion + # Start a new iteration + candidate_space.iteration += 1 + # Set the predecessor model to the previous predecessor model. predecessor_model = candidate_space.previous_predecessor_model From 4d8e36f95ccf2759cd92adfc2fd9af32dcb3fcba Mon Sep 17 00:00:00 2001 From: dilpath Date: Mon, 2 Dec 2024 21:00:44 +0100 Subject: [PATCH 07/88] add analysis module --- petab_select/__init__.py | 1 + petab_select/analyze.py | 163 +++++++++++++++++++++++++++++++++++++++ petab_select/plot.py | 127 +++++++----------------------- petab_select/problem.py | 28 +++---- 4 files changed, 204 insertions(+), 115 deletions(-) create mode 100644 petab_select/analyze.py diff --git a/petab_select/__init__.py b/petab_select/__init__.py index 665c4102..033e6c62 100644 --- a/petab_select/__init__.py +++ b/petab_select/__init__.py @@ -2,6 +2,7 @@ import sys +from .analyze import * from .candidate_space import * from .constants import * from .criteria import * diff --git a/petab_select/analyze.py b/petab_select/analyze.py new file mode 100644 index 00000000..fa22a104 --- /dev/null +++ b/petab_select/analyze.py @@ -0,0 +1,163 @@ +"""Methods to analyze results of model selection.""" + +from collections.abc import Callable + +from .constants import Criterion +from .model import Model, ModelHash, default_compare +from .models import Models + +__all__ = [ + # "get_predecessor_models", + "group_by_predecessor_model", + "group_by_iteration", + "get_best_by_iteration", + "get_relative_criterion_values", +] + + +# def get_predecessor_models(models: Models) -> Models: +# """Get all models that were predecessors to other models. +# +# Args: +# models: +# The models +# +# Returns: +# The predecessor models. +# """ +# predecessor_models = Models([ +# models.get( +# model.predecessor_model_hash, +# # Handle virtual initial model. +# model.predecessor_model_hash, +# ) for model in models +# ]) +# return predecessor_models + + +def group_by_predecessor_model(models: Models) -> dict[ModelHash, Models]: + """Group models by their predecessor model. + + Args: + models: + The models. + + Returns: + Key is predecessor model hash, value is models. + """ + result = {} + for model in models: + if model.predecessor_model_hash not in result: + result[model.predecessor_model_hash] = Models() + result[model.predecessor_model_hash].append(model) + return result + + +def group_by_iteration(models: Models) -> dict[int | None, Models]: + """Group models by their iteration. + + Args: + models: + The models. + + Returns: + Key is iteration, value is models. + """ + result = {} + for model in models: + if model.iteration not in result: + result[model.iteration] = Models() + result[model.iteration].append(model) + return result + + +def get_best( + models: Models, + criterion: Criterion, + compare: Callable[[Model, Model], bool] | None = None, + compute_criterion: bool = False, +) -> Model: + """Get the best model. + + Args: + models: + The models. + criterion. + The criterion. + compare: + The method used to compare two models. + Defaults to :func:``petab_select.model.default_compare``. + compute_criterion: + Whether to try computing criterion values, if sufficient + information is available (e.g., likelihood and number of + parameters, to compute AIC). + + Returns: + The best model. + """ + if compare is None: + compare = default_compare + + best_model = None + for model in models: + if compute_criterion and not model.has_criterion(criterion): + model.get_criterion(criterion) + if best_model is None: + if model.has_criterion(criterion): + best_model = model + # TODO warn if criterion is not available? + continue + if compare(best_model, model, criterion=criterion): + best_model = model + if best_model is None: + raise KeyError( + "None of the supplied models have a value set for the criterion " + f"`{criterion}`." + ) + return best_model + + +def get_best_by_iteration( + models: Models, + *args, + **kwargs, +) -> Models: + """Get the best model of each iteration. + + See :func:``get_best`` for additional required arguments. + + Args: + models: + The models. + *args, **kwargs: + Forwarded to :func:``get_best``. + + Returns: + The strictly improving models. + """ + iterations_models = group_by_iteration(models=models) + best_by_iteration = { + iteration: get_best( + *args, + models=iteration_models, + **kwargs, + ) + for iteration, iteration_models in iterations_models.items() + } + return best_by_iteration + + +def get_relative_criterion_values( + criterion_values: list[float], +) -> list[float]: + """Offset criterion values by their minimum value. + + Args: + criterion_values: + The criterion values. + + Returns: + The relative criterion values. + """ + minimum = min(criterion_values) + return [criterion_value - minimum for criterion_value in criterion_values] diff --git a/petab_select/plot.py b/petab_select/plot.py index 08137c82..fb112822 100644 --- a/petab_select/plot.py +++ b/petab_select/plot.py @@ -14,6 +14,7 @@ from more_itertools import one from toposort import toposort +from .analyze import get_best_by_iteration, get_relative_criterion_values from .constants import VIRTUAL_INITIAL_MODEL, Criterion from .model import Model, ModelHash @@ -25,78 +26,12 @@ "bar_criterion_vs_models", "graph_history", "graph_iteration_layers", - "line_selected", + "line_best_by_iteration", "scatter_criterion_vs_n_estimated", "upset", ] -def get_model_hashes(models: list[Model]) -> dict[str, Model]: - """Get the model hash to model mapping. - - Args: - models: - The models. - - Returns: - The mapping. - """ - model_hashes = {model.get_hash(): model for model in models} - return model_hashes - - -def get_selected_models( - models: list[Model], - criterion: Criterion, -) -> list[Model]: - """Get the models that strictly improved on their predecessors. - - Args: - models: - The models. - criterion: - The criterion - - Returns: - The strictly improving models. - """ - criterion_value0 = np.inf - model0 = None - model_hashes = get_model_hashes(models) - for model in models: - criterion_value = model.get_criterion(criterion) - if criterion_value < criterion_value0: - criterion_value0 = criterion_value - model0 = model - - selected_models = [model0] - while True: - model0 = selected_models[-1] - model1 = model_hashes.get(model0.predecessor_model_hash, None) - if model1 is None: - break - selected_models.append(model1) - - return selected_models[::-1] - - -def get_relative_criterion_values( - criterion_values: dict[str, float] | list[float], -) -> dict[str, float] | list[float]: - values = criterion_values - if isinstance(criterion_values, dict): - values = criterion_values.values() - - value0 = np.inf - for value in values: - if value < value0: - value0 = value - - if isinstance(criterion_values, dict): - return {k: v - value0 for k, v in criterion_values.items()} - return [v - value0 for v in criterion_values] - - def upset( models: list[Model], criterion: Criterion ) -> dict[str, matplotlib.axes.Axes | None]: @@ -137,7 +72,7 @@ def upset( return axes -def line_selected( +def line_best_by_iteration( models: list[Model], criterion: Criterion, relative: bool = True, @@ -168,7 +103,9 @@ def line_selected( Returns: The plot axes. """ - models = get_selected_models(models=models, criterion=criterion) + best_by_iteration = get_best_by_iteration( + models=models, criterion=criterion + ) if labels is None: labels = {} @@ -178,20 +115,22 @@ def line_selected( _, ax = plt.subplots(figsize=(5, 4)) linewidth = 3 - models = [model for model in models if model != VIRTUAL_INITIAL_MODEL] + iterations = sorted(best_by_iteration) + best_models = [best_by_iteration[iteration] for iteration in iterations] + iteration_labels = [ + str(iteration) + f"\n({labels.get(model.get_hash(), model.model_id)})" + for iteration, model in zip(iterations, best_models, strict=True) + ] - criterion_values = { - labels.get(model.get_hash(), model.model_id): model.get_criterion( - criterion - ) - for model in models - } + criterion_values = [ + model.get_criterion(criterion) for model in best_models + ] if relative: criterion_values = get_relative_criterion_values(criterion_values) ax.plot( - criterion_values.keys(), - criterion_values.values(), + iteration_labels, + criterion_values, linewidth=linewidth, color=NORMAL_NODE_COLOR, marker="x", @@ -259,24 +198,22 @@ def graph_history( default_spring_layout_kwargs = {"k": 1, "iterations": 20} if spring_layout_kwargs is None: spring_layout_kwargs = default_spring_layout_kwargs - model_hashes = get_model_hashes(models) criterion_values = { - model_hash: model.get_criterion(criterion) - for model_hash, model in model_hashes.items() + model.get_hash(): model.get_criterion(criterion) for model in models } if relative: criterion_values = get_relative_criterion_values(criterion_values) if labels is None: labels = { - model_hash: model.model_id + model.get_hash(): model.model_id + ( - f"\n{criterion_values[model_hash]:.2f}" + f"\n{criterion_values[model.get_hash()]:.2f}" if criterion is not None else "" ) - for model_hash, model in model_hashes.items() + for model in models } labels = labels.copy() labels[VIRTUAL_INITIAL_MODEL] = "Virtual\nInitial\nModel" @@ -289,8 +226,8 @@ def graph_history( from_ = labels.get(predecessor_model_hash, predecessor_model_hash) # may only not be the case for # COMPARED_MODEL_ID == INITIAL_VIRTUAL_MODEL - if predecessor_model_hash in model_hashes: - predecessor_model = model_hashes[predecessor_model_hash] + if predecessor_model_hash in models: + predecessor_model = models[predecessor_model_hash] from_ = labels.get( predecessor_model.get_hash(), predecessor_model.model_id, @@ -370,16 +307,11 @@ def bar_criterion_vs_models( Returns: The plot axes. """ - model_hashes = get_model_hashes(models) - if bar_kwargs is None: bar_kwargs = {} if labels is None: - labels = { - model_hash: model.model_id - for model_hash, model in model_hashes.items() - } + labels = {model.get_hash(): model.model_id for model in models} if ax is None: _, ax = plt.subplots() @@ -453,11 +385,9 @@ def scatter_criterion_vs_n_estimated( Returns: The plot axes. """ - model_hashes = get_model_hashes(models) - labels = { - model_hash: labels.get(model.model_id, model.model_id) - for model_hash, model in model_hashes.items() + model.get_hash(): labels.get(model.model_id, model.model_id) + for model in models } if scatter_kwargs is None: @@ -553,12 +483,11 @@ def graph_iteration_layers( Returns: The plot axes. """ + # FIXME plot iterations instead of predecessor->successor if ax is None: _, ax = plt.subplots(figsize=(20, 10)) - model_hashes = {model.get_hash(): model for model in models} - default_draw_networkx_kwargs = { #'node_color': NORMAL_NODE_COLOR, "arrowstyle": "-|>", @@ -731,7 +660,7 @@ def __getitem__(self, key): # Add `n=...` labels N = [len(y) for y in Y] - for x, n in zip(X, N, strict=False): + for x, n in zip(X, N, strict=True): ax.annotate( f"n={n}", xy=(x, 1.1), diff --git a/petab_select/problem.py b/petab_select/problem.py index b0a763bd..5260f9e2 100644 --- a/petab_select/problem.py +++ b/petab_select/problem.py @@ -8,6 +8,7 @@ import yaml +from .analyze import get_best from .candidate_space import CandidateSpace, method_to_candidate_space_class from .constants import ( CANDIDATE_SPACE_ARGUMENTS, @@ -242,25 +243,20 @@ def get_best( Returns: The best model. """ + warnings.warn( + "Use ``petab_select.analyze.get_best`` instead.", + DeprecationWarning, + stacklevel=2, + ) if criterion is None: criterion = self.criterion - best_model = None - for model in models: - if compute_criterion and not model.has_criterion(criterion): - model.get_criterion(criterion) - if best_model is None: - if model.has_criterion(criterion): - best_model = model - # TODO warn if criterion is not available? - continue - if self.compare(best_model, model, criterion=criterion): - best_model = model - if best_model is None: - raise KeyError( - f"None of the supplied models have a value set for the criterion {criterion}." - ) - return best_model + return get_best( + models=models, + criterion=criterion, + compare=self.compare, + compute_criterion=compute_criterion, + ) def model_hash_to_model(self, model_hash: str | ModelHash) -> Model: """Get the model that matches a model hash. From 486260be15e514d9215e000db4afc3908b81449c Mon Sep 17 00:00:00 2001 From: dilpath Date: Mon, 2 Dec 2024 21:06:10 +0100 Subject: [PATCH 08/88] fixme: use pypesto PR branch --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 780b7e2b..77e1d38c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,8 @@ test = [ "pytest-cov >= 2.10.0", "amici >= 0.11.25", "fides >= 0.7.5", - "pypesto > 0.2.13", + # "pypesto > 0.2.13", + "pypesto @ git+https://github.com/ICB-DCM/pyPESTO.git@select_class_models#egg=pypesto", "tox >= 3.12.4", ] doc = [ From 74fed0b131c580b21aa3f96e7261505d09bb0cb4 Mon Sep 17 00:00:00 2001 From: dilpath Date: Tue, 3 Dec 2024 00:05:56 +0100 Subject: [PATCH 09/88] unfix pypesto in tox.ini to use pyproject.toml --- tox.ini | 2 -- 1 file changed, 2 deletions(-) diff --git a/tox.ini b/tox.ini index 139c8b0d..2bf5551e 100644 --- a/tox.ini +++ b/tox.ini @@ -18,8 +18,6 @@ description = [testenv:base] extras = test -deps = - git+https://github.com/ICB-DCM/pyPESTO.git@develop\#egg=pypesto commands = pytest --cov=petab_select --cov-report=xml --cov-append test -s coverage report From 8e799eb387d0493ddfdaefff960e0ff3e39d4e13 Mon Sep 17 00:00:00 2001 From: dilpath Date: Tue, 3 Dec 2024 01:05:53 +0100 Subject: [PATCH 10/88] fix tests --- petab_select/models.py | 1 - petab_select/ui.py | 10 +++++++--- test/candidate_space/test_famos.py | 9 ++++----- test/cli/input/models.yaml | 10 ++++++++++ 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/petab_select/models.py b/petab_select/models.py index fa0cf579..1f58a213 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -112,7 +112,6 @@ def __getitem__( case ModelHash() | str(): return self._models[self._hashes.index(key)] case slice(): - print(key) return self.__class__(self._models[key]) case Iterable(): # TODO sensible to yield here? diff --git a/petab_select/ui.py b/petab_select/ui.py index 4de4b3d2..347d1a8e 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -6,6 +6,7 @@ import numpy as np import petab.v1 as petab +from . import analyze from .candidate_space import CandidateSpace, FamosCandidateSpace from .constants import ( CANDIDATE_SPACE, @@ -159,9 +160,10 @@ def start_iteration( # by calling ui.best to find the best model to jump to if # this is not the first step of the search. if candidate_space.latest_iteration_calibrated_models: - predecessor_model = problem.get_best( - candidate_space.latest_iteration_calibrated_models, + predecessor_model = analyze.get_best( + models=candidate_space.latest_iteration_calibrated_models, criterion=criterion, + compare=problem.compare, ) # If the new predecessor model isn't better than the previous one, # keep the previous one. @@ -352,7 +354,9 @@ def get_best( The best model. """ # TODO return list, when multiple models are equally "best" - return problem.get_best(models=models, criterion=criterion) + return analyze.get_best( + models=models, criterion=criterion, compare=problem.compare + ) def write_summary_tsv( diff --git a/test/candidate_space/test_famos.py b/test/candidate_space/test_famos.py index e7cf12e7..f4ad33e1 100644 --- a/test/candidate_space/test_famos.py +++ b/test/candidate_space/test_famos.py @@ -5,7 +5,7 @@ from more_itertools import one import petab_select -from petab_select import Method +from petab_select import Method, Models from petab_select.constants import ( CANDIDATE_SPACE, MODEL_HASH, @@ -126,8 +126,7 @@ def parse_summary_to_progress_list(summary_tsv: str) -> tuple[Method, set]: return progress_list progress_list = [] - all_calibrated_models = {} - calibrated_models = {} + all_calibrated_models = Models() candidate_space = petab_select_problem.new_candidate_space() candidate_space.summary_tsv.unlink(missing_ok=True) @@ -145,7 +144,7 @@ def parse_summary_to_progress_list(summary_tsv: str) -> tuple[Method, set]: ) # Calibrate candidate models - calibrated_models = {} + calibrated_models = Models() for candidate_model in iteration[UNCALIBRATED_MODELS]: calibrate(candidate_model) calibrated_models[candidate_model.get_hash()] = candidate_model @@ -155,7 +154,7 @@ def parse_summary_to_progress_list(summary_tsv: str) -> tuple[Method, set]: candidate_space=iteration[CANDIDATE_SPACE], calibrated_models=calibrated_models, ) - all_calibrated_models.update(iteration_results[MODELS]) + all_calibrated_models += iteration_results[MODELS] candidate_space = iteration_results[CANDIDATE_SPACE] # Stop iteration if there are no candidate models diff --git a/test/cli/input/models.yaml b/test/cli/input/models.yaml index d7523afa..06aa3933 100644 --- a/test/cli/input/models.yaml +++ b/test/cli/input/models.yaml @@ -1,5 +1,10 @@ - criteria: {} model_id: model_1 + model_subspace_id: M + model_subspace_indices: + - 0 + - 1 + - 1 parameters: k1: 0.2 k2: estimate @@ -10,6 +15,11 @@ petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml - criteria: {} model_id: model_2 + model_subspace_id: M + model_subspace_indices: + - 1 + - 1 + - 0 parameters: k1: estimate k2: estimate From 7585748ad43306223438c080d6096d310d584448 Mon Sep 17 00:00:00 2001 From: dilpath Date: Tue, 3 Dec 2024 14:17:18 +0100 Subject: [PATCH 11/88] test --- test/analyze/input/models.yaml | 66 ++++++++++++++++++++++++++++ test/analyze/test_analyze.py | 80 ++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 test/analyze/input/models.yaml create mode 100644 test/analyze/test_analyze.py diff --git a/test/analyze/input/models.yaml b/test/analyze/input/models.yaml new file mode 100644 index 00000000..264e1154 --- /dev/null +++ b/test/analyze/input/models.yaml @@ -0,0 +1,66 @@ +- criteria: + AIC: 5 + model_id: model_1 + model_subspace_id: M + model_subspace_indices: + - 0 + - 1 + - 1 + iteration: 1 + parameters: + k1: 0.2 + k2: estimate + k3: estimate + estimated_parameters: + k2: 0.15 + k3: 0.0 + petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + predecessor_model_hash: dummy_p0-0 +- criteria: + AIC: 4 + model_id: model_2 + model_subspace_id: M + model_subspace_indices: + - 1 + - 1 + - 0 + iteration: 5 + parameters: + k1: estimate + k2: estimate + k3: 0 + petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + predecessor_model_hash: virtual_initial_model- +- criteria: + AIC: 3 + model_id: model_3 + model_subspace_id: M2 + model_subspace_indices: + - 0 + - 1 + - 1 + iteration: 1 + parameters: + k1: 0.2 + k2: estimate + k3: estimate + estimated_parameters: + k2: 0.15 + k3: 0.0 + petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + predecessor_model_hash: virtual_initial_model- +- criteria: + AIC: 2 + model_id: model_4 + model_subspace_id: M2 + model_subspace_indices: + - 1 + - 1 + - 0 + iteration: 2 + parameters: + k1: estimate + k2: estimate + k3: 0 + petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + predecessor_model_hash: virtual_initial_model- diff --git a/test/analyze/test_analyze.py b/test/analyze/test_analyze.py new file mode 100644 index 00000000..2b084598 --- /dev/null +++ b/test/analyze/test_analyze.py @@ -0,0 +1,80 @@ +from pathlib import Path + +import pytest + +from petab_select import ( + VIRTUAL_INITIAL_MODEL, + Criterion, + ModelHash, + Models, + analyze, +) + +base_dir = Path(__file__).parent + +DUMMY_HASH = "dummy_p0-0" +VIRTUAL_HASH = ModelHash.from_hash(VIRTUAL_INITIAL_MODEL) + + +@pytest.fixture +def models() -> Models: + return Models.from_yaml(base_dir / "input" / "models.yaml") + + +def test_group_by_predecessor_model(models: Models) -> None: + """Test ``analyze.group_by_predecessor_model``.""" + groups = analyze.group_by_predecessor_model(models) + # Expected groups + assert len(groups) == 2 + assert VIRTUAL_HASH in groups + assert DUMMY_HASH in groups + # Expected group members + assert len(groups[DUMMY_HASH]) == 1 + assert "M-011" in groups[DUMMY_HASH] + assert len(groups[VIRTUAL_HASH]) == 3 + assert "M-110" in groups[VIRTUAL_HASH] + assert "M2-011" in groups[VIRTUAL_HASH] + assert "M2-110" in groups[VIRTUAL_HASH] + + +def test_group_by_iteration(models: Models) -> None: + """Test ``analyze.group_by_iteration``.""" + groups = analyze.group_by_iteration(models) + # Expected groups + assert len(groups) == 3 + assert 1 in groups + assert 2 in groups + assert 5 in groups + # Expected group members + assert len(groups[1]) == 2 + assert "M-011" in groups[1] + assert "M2-011" in groups[1] + assert len(groups[2]) == 1 + assert "M2-110" in groups[2] + assert len(groups[5]) == 1 + assert "M-110" in groups[5] + + +def test_get_best_by_iteration(models: Models) -> None: + """Test ``analyze.get_best_by_iteration``.""" + groups = analyze.get_best_by_iteration(models, criterion=Criterion.AIC) + # Expected groups + assert len(groups) == 3 + assert 1 in groups + assert 2 in groups + assert 5 in groups + # Expected best models + assert groups[1].get_hash() == "M2-011" + assert groups[2].get_hash() == "M2-110" + assert groups[5].get_hash() == "M-110" + + +def test_get_relative_criterion_values(models: Models) -> None: + """Test ``analyze.get_relative_criterion_values``.""" + criterion_values = [model.get_criterion(Criterion.AIC) for model in models] + test_value = analyze.get_relative_criterion_values(criterion_values) + expected_value = [ + criterion_value - min(criterion_values) + for criterion_value in criterion_values + ] + assert test_value == expected_value From 05d17e8d8f61cbe90ab2668792d52a389c36c360 Mon Sep 17 00:00:00 2001 From: dilpath Date: Fri, 13 Dec 2024 22:38:27 +0100 Subject: [PATCH 12/88] sort iterations in `group_by_iteration` --- petab_select/analyze.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/petab_select/analyze.py b/petab_select/analyze.py index fa22a104..1a23073f 100644 --- a/petab_select/analyze.py +++ b/petab_select/analyze.py @@ -53,12 +53,16 @@ def group_by_predecessor_model(models: Models) -> dict[ModelHash, Models]: return result -def group_by_iteration(models: Models) -> dict[int | None, Models]: +def group_by_iteration( + models: Models, sort: bool = True +) -> dict[int | None, Models]: """Group models by their iteration. Args: models: The models. + sort: + Whether to sort the iterations. Returns: Key is iteration, value is models. @@ -68,6 +72,8 @@ def group_by_iteration(models: Models) -> dict[int | None, Models]: if model.iteration not in result: result[model.iteration] = Models() result[model.iteration].append(model) + if sort: + result = {iteration: result[iteration] for iteration in sorted(result)} return result From eaa4796b040cf95a675736021ddd5999b9f5b423 Mon Sep 17 00:00:00 2001 From: dilpath Date: Fri, 13 Dec 2024 22:39:09 +0100 Subject: [PATCH 13/88] add `VIRTUAL_INITIAL_MODEL_HASH` --- petab_select/model.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/petab_select/model.py b/petab_select/model.py index 62e6d919..a9b7ec20 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -47,6 +47,7 @@ "Model", "default_compare", "ModelHash", + "VIRTUAL_INITIAL_MODEL_HASH", ] @@ -990,3 +991,6 @@ def __eq__(self, other_hash: str | ModelHash) -> bool: # petab_hash = ModelHash.from_hash(other_hash).petab_hash # return self.petab_hash == petab_hash return str(self) == str(other_hash) + + +VIRTUAL_INITIAL_MODEL_HASH = ModelHash.from_hash(VIRTUAL_INITIAL_MODEL) From 2d8017cd8c547788854801555087650ff01be71c Mon Sep 17 00:00:00 2001 From: dilpath Date: Fri, 13 Dec 2024 22:52:13 +0100 Subject: [PATCH 14/88] method to convert Models to dataframe; update plotting code --- petab_select/models.py | 90 +++++++++++++++++++++++++++++++++++++++++- petab_select/plot.py | 72 +++++++++++++++++++-------------- 2 files changed, 131 insertions(+), 31 deletions(-) diff --git a/petab_select/models.py b/petab_select/models.py index 1f58a213..8028aaa4 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -4,11 +4,21 @@ from collections import Counter from collections.abc import Iterable, MutableSequence from pathlib import Path -from typing import TYPE_CHECKING, TypeAlias +from typing import TYPE_CHECKING, Any, TypeAlias +import pandas as pd import yaml -from .constants import TYPE_PATH +from .constants import ( + CRITERIA, + ESTIMATED_PARAMETERS, + ITERATION, + MODEL_HASH, + MODEL_ID, + PREDECESSOR_MODEL_HASH, + TYPE_PATH, + Criterion, +) from .model import ( Model, ModelHash, @@ -407,6 +417,82 @@ def to_yaml( with open(output_yaml, "w") as f: yaml.safe_dump(model_dicts, f) + def _getattr( + self, + attr: str, + key: Any = None, + use_default: bool = False, + default: Any = None, + ) -> list[Any]: + """Get an attribute of each model. + + Args: + attr: + The name of the attribute (e.g. ``MODEL_ID``). + key: + The key of the attribute, if you want to further subset. + For example, if ``attr=ESTIMATED_PARAMETERS``, this could + be a specific parameter ID. + use_default: + Whether to use a default value for models that are missing + ``attr`` or ``key``. + default: + Value to use for models that do not have ``attr`` or ``key``, + if ``use_default==True``. + + Returns: + The list of attribute values. + """ + # FIXME remove when model is `dataclass` + values = [] + for model in self: + try: + value = getattr(model, attr) + except: + if not use_default: + raise + value = default + + if key is not None: + try: + value = value[key] + except: + if not use_default: + raise + value = default + + values.append(value) + return values + + @property + def df(self) -> pd.DataFrame: + """Get a dataframe of model attributes.""" + return pd.DataFrame( + { + MODEL_ID: self._getattr(MODEL_ID), + MODEL_HASH: self._getattr(MODEL_HASH), + Criterion.NLLH: self._getattr( + CRITERIA, Criterion.NLLH, use_default=True + ), + Criterion.AIC: self._getattr( + CRITERIA, Criterion.AIC, use_default=True + ), + Criterion.AICC: self._getattr( + CRITERIA, Criterion.AICC, use_default=True + ), + Criterion.BIC: self._getattr( + CRITERIA, Criterion.BIC, use_default=True + ), + ITERATION: self._getattr(ITERATION, use_default=True), + PREDECESSOR_MODEL_HASH: self._getattr( + PREDECESSOR_MODEL_HASH, use_default=True + ), + ESTIMATED_PARAMETERS: self._getattr( + ESTIMATED_PARAMETERS, use_default=True + ), + } + ) + def models_from_yaml_list( model_list_yaml: TYPE_PATH, diff --git a/petab_select/plot.py b/petab_select/plot.py index fb112822..50deb32c 100644 --- a/petab_select/plot.py +++ b/petab_select/plot.py @@ -12,11 +12,15 @@ import numpy as np import upsetplot from more_itertools import one -from toposort import toposort -from .analyze import get_best_by_iteration, get_relative_criterion_values -from .constants import VIRTUAL_INITIAL_MODEL, Criterion -from .model import Model, ModelHash +from .analyze import ( + get_best_by_iteration, + get_relative_criterion_values, + group_by_iteration, +) +from .constants import Criterion +from .model import VIRTUAL_INITIAL_MODEL_HASH, Model, ModelHash +from .models import Models RELATIVE_LABEL_FONTSIZE = -2 NORMAL_NODE_COLOR = "darkgrey" @@ -33,7 +37,7 @@ def upset( - models: list[Model], criterion: Criterion + models: Models, criterion: Criterion ) -> dict[str, matplotlib.axes.Axes | None]: """Plot an UpSet plot of estimated parameters and criterion. @@ -56,7 +60,10 @@ def upset( # Sort by criterion value index = np.argsort(values) values = values[index] - labels = [models[i].get_estimated_parameter_ids_all() for i in index] + labels = [ + model.get_estimated_parameter_ids_all() + for model in np.array(models)[index] + ] with warnings.catch_warnings(): # TODO remove warnings context manager when fixed in upsetplot package @@ -145,11 +152,12 @@ def line_best_by_iteration( ax.set_ylabel((r"$\Delta$" if relative else "") + criterion, fontsize=fz) # could change to compared_model_ids, if all models are plotted ax.set_xticklabels( - criterion_values.keys(), + ax.get_xticklabels(), fontsize=fz + RELATIVE_LABEL_FONTSIZE, ) - for tick in ax.yaxis.get_major_ticks(): - tick.label1.set_fontsize(fz + RELATIVE_LABEL_FONTSIZE) + ax.yaxis.set_tick_params( + which="major", labelsize=fz + RELATIVE_LABEL_FONTSIZE + ) ytl = ax.get_yticks() ax.set_ylim([min(ytl), max(ytl)]) # removing top and right borders @@ -159,7 +167,7 @@ def line_best_by_iteration( def graph_history( - models: list[Model], + models: Models, criterion: Criterion = None, labels: dict[str, str] = None, colors: dict[str, str] = None, @@ -199,11 +207,15 @@ def graph_history( if spring_layout_kwargs is None: spring_layout_kwargs = default_spring_layout_kwargs - criterion_values = { - model.get_hash(): model.get_criterion(criterion) for model in models - } + criterion_values = [model.get_criterion(criterion) for model in models] if relative: criterion_values = get_relative_criterion_values(criterion_values) + criterion_values = { + model.get_hash(): criterion_value + for model, criterion_value in zip( + models, criterion_values, strict=False + ) + } if labels is None: labels = { @@ -216,7 +228,7 @@ def graph_history( for model in models } labels = labels.copy() - labels[VIRTUAL_INITIAL_MODEL] = "Virtual\nInitial\nModel" + labels[VIRTUAL_INITIAL_MODEL_HASH] = "Virtual\nInitial\nModel" G = nx.DiGraph() edges = [] @@ -316,15 +328,15 @@ def bar_criterion_vs_models( if ax is None: _, ax = plt.subplots() - criterion_values = { - labels.get(model.get_hash(), model.model_id): model.get_criterion( - criterion - ) - for model in models - } + criterion_values = [model.get_criterion(criterion) for model in models] + bar_model_labels = [ + labels.get(model.get_hash(), model.model_id) for model in models + ] + if relative: + criterion_values = get_relative_criterion_values(criterion_values) if colors is not None: - if label_diff := set(colors).difference(criterion_values): + if label_diff := set(colors).difference(bar_model_labels): raise ValueError( "Colors were provided for the following model labels, but " f"these are not in the graph: {label_diff}" @@ -335,10 +347,8 @@ def bar_criterion_vs_models( for model_label in criterion_values ] - if relative: - criterion_values = get_relative_criterion_values(criterion_values) - ax.bar(criterion_values.keys(), criterion_values.values(), **bar_kwargs) - ax.set_xlabel("Model labels") + ax.bar(bar_model_labels, criterion_values, **bar_kwargs) + ax.set_xlabel("Model") ax.set_ylabel( (r"$\Delta$" if relative else "") + criterion, ) @@ -483,8 +493,6 @@ def graph_iteration_layers( Returns: The plot axes. """ - # FIXME plot iterations instead of predecessor->successor - if ax is None: _, ax = plt.subplots(figsize=(20, 10)) @@ -502,7 +510,13 @@ def graph_iteration_layers( model.get_hash(): model.predecessor_model_hash for model in models } ancestry_as_set = {k: {v} for k, v in ancestry.items()} - ordering = [list(hashes) for hashes in toposort(ancestry_as_set)] + + ordering = [ + [model.get_hash() for model in iteration_models] + for iteration_models in group_by_iteration(models).values() + ] + if VIRTUAL_INITIAL_MODEL_HASH in ancestry.values(): + ordering.insert(0, [VIRTUAL_INITIAL_MODEL_HASH]) model_estimated_parameters = { model.get_hash(): set(model.estimated_parameters) for model in models @@ -587,7 +601,7 @@ def __getitem__(self, key): labels = { model_hash: ( label0 - if model_hash == ModelHash.from_hash(VIRTUAL_INITIAL_MODEL) + if model_hash == VIRTUAL_INITIAL_MODEL_HASH else "\n".join( [ label0, From 529c799afedb13f0ffe63fb3045a3d68eadb4817 Mon Sep 17 00:00:00 2001 From: dilpath Date: Fri, 13 Dec 2024 22:52:52 +0100 Subject: [PATCH 15/88] update vis example to use iterations --- .../calibrated_models/calibrated_models.yaml | 70 +++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/doc/examples/calibrated_models/calibrated_models.yaml b/doc/examples/calibrated_models/calibrated_models.yaml index e77c5243..8b96bafd 100644 --- a/doc/examples/calibrated_models/calibrated_models.yaml +++ b/doc/examples/calibrated_models/calibrated_models.yaml @@ -2,7 +2,8 @@ AICc: 37.97523003111246 NLLH: 17.48761501555623 estimated_parameters: - sigma_x2: 4.462298385653177 + sigma_x2: 4.462298422134608 + iteration: 1 model_hash: M_0-000 model_id: M_0-000 model_subspace_id: M_0 @@ -17,11 +18,12 @@ petab_yaml: petab_problem.yaml predecessor_model_hash: virtual_initial_model - criteria: - AICc: -0.1754060811089051 - NLLH: -4.0877030405544525 + AICc: -0.17540608110890332 + NLLH: -4.087703040554452 estimated_parameters: k3: 0.0 - sigma_x2: 0.12242920113658744 + sigma_x2: 0.12242920113658338 + iteration: 2 model_hash: M_1-000 model_id: M_1-000 model_subspace_id: M_1 @@ -36,11 +38,12 @@ petab_yaml: petab_problem.yaml predecessor_model_hash: M_0-000 - criteria: - AICc: -0.27451405630430337 - NLLH: -4.137257028152152 + AICc: -0.27451438069575573 + NLLH: -4.137257190347878 estimated_parameters: - k2: 0.10147827639089564 - sigma_x2: 0.12142256779953603 + k2: 0.10147824307890803 + sigma_x2: 0.12142219599557078 + iteration: 2 model_hash: M_2-000 model_id: M_2-000 model_subspace_id: M_2 @@ -55,11 +58,12 @@ petab_yaml: petab_problem.yaml predecessor_model_hash: M_0-000 - criteria: - AICc: -0.7053270517931587 - NLLH: -4.352663525896579 + AICc: -0.7053270766271886 + NLLH: -4.352663538313594 estimated_parameters: - k1: 0.20160888007873565 - sigma_x2: 0.11713858557052499 + k1: 0.20160925279667963 + sigma_x2: 0.11714017664827497 + iteration: 2 model_hash: M_3-000 model_id: M_3-000 model_subspace_id: M_3 @@ -74,12 +78,13 @@ petab_yaml: petab_problem.yaml predecessor_model_hash: M_0-000 - criteria: - AICc: 9.294672948206841 - NLLH: -4.352663525896579 + AICc: 9.294672923372811 + NLLH: -4.352663538313594 estimated_parameters: - k1: 0.20160888007873565 + k1: 0.20160925279667963 k3: 0.0 - sigma_x2: 0.11713858557052499 + sigma_x2: 0.11714017664827497 + iteration: 3 model_hash: M_5-000 model_id: M_5-000 model_subspace_id: M_5 @@ -94,12 +99,13 @@ petab_yaml: petab_problem.yaml predecessor_model_hash: M_3-000 - criteria: - AICc: 7.852170288089528 - NLLH: -5.073914855955236 + AICc: 7.8521704398854 + NLLH: -5.0739147800573 estimated_parameters: - k1: 0.20924739987621038 - k2: 0.0859065470362628 - sigma_x2: 0.1038731029818225 + k1: 0.20924804320838675 + k2: 0.0859052351446815 + sigma_x2: 0.10386846319370771 + iteration: 3 model_hash: M_6-000 model_id: M_6-000 model_subspace_id: M_6 @@ -113,3 +119,25 @@ k3: 0 petab_yaml: petab_problem.yaml predecessor_model_hash: M_3-000 +- criteria: + AICc: 35.94352968170024 + NLLH: -6.028235159149878 + estimated_parameters: + k1: 0.6228488917665873 + k2: 0.020189424009226256 + k3: 0.0010850434974038557 + sigma_x2: 0.08859278245811462 + iteration: 4 + model_hash: M_7-000 + model_id: M_7-000 + model_subspace_id: M_7 + model_subspace_indices: + - 0 + - 0 + - 0 + parameters: + k1: estimate + k2: estimate + k3: estimate + petab_yaml: petab_problem.yaml + predecessor_model_hash: M_3-000 From 722411820b622beb12ac473b2ee81edd7f837bb3 Mon Sep 17 00:00:00 2001 From: dilpath Date: Fri, 13 Dec 2024 22:58:36 +0100 Subject: [PATCH 16/88] update vis notebook --- doc/examples/visualization.ipynb | 192 ++++++++++++++++++------------- 1 file changed, 114 insertions(+), 78 deletions(-) diff --git a/doc/examples/visualization.ipynb b/doc/examples/visualization.ipynb index 8b86ad63..1d038379 100644 --- a/doc/examples/visualization.ipynb +++ b/doc/examples/visualization.ipynb @@ -27,107 +27,161 @@ "metadata": {}, "outputs": [], "source": [ + "import matplotlib\n", + "\n", "import petab_select\n", "import petab_select.plot\n", + "from petab_select import VIRTUAL_INITIAL_MODEL_HASH\n", "\n", - "models = petab_select.models_from_yaml_list(\n", - " model_list_yaml=\"calibrated_models/calibrated_models.yaml\"\n", + "models = petab_select.Models.from_yaml(\n", + " \"calibrated_models/calibrated_models.yaml\"\n", ")" ] }, { "cell_type": "code", "execution_count": 2, - "id": "2574e65a-1f16-4205-8c23-b65ba78f9a1a", + "id": "54532b75-53e4-4670-8e64-21e7adda0c0e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", - "\n", + "
\n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
 Model hashAICc criterionPredecessor model hashEstimated parametersmodel_idmodel_hashCriterion.NLLHCriterion.AICCriterion.AICCCriterion.BICiterationpredecessor_model_hashestimated_parameters
0M_0-00037.975230virtual_initial_model-sigma_x20M_0-000M_0-00017.487615None37.975230None1virtual_initial_model-{'sigma_x2': 4.462298422134608}
1M_1-000-0.175406M_0-000k3, sigma_x21M_1-000M_1-000-4.087703None-0.175406None2M_0-000{'k3': 0.0, 'sigma_x2': 0.12242920113658338}
2M_2-000-0.274514M_0-000k2, sigma_x22M_2-000M_2-000-4.137257None-0.274514None2M_0-000{'k2': 0.10147824307890803, 'sigma_x2': 0.12142219599557078}
3M_3-000-0.705327M_0-000k1, sigma_x23M_3-000M_3-000-4.352664None-0.705327None2M_0-000{'k1': 0.20160925279667963, 'sigma_x2': 0.11714017664827497}
4M_5-0009.294673M_3-000k1, k3, sigma_x24M_5-000M_5-000-4.352664None9.294673None3M_3-000{'k1': 0.20160925279667963, 'k3': 0.0, 'sigma_x2': 0.11714017664827497}
5M_6-0007.852170M_3-000k1, k2, sigma_x25M_6-000M_6-000-5.073915None7.852170None3M_3-000{'k1': 0.20924804320838675, 'k2': 0.0859052351446815, 'sigma_x2': 0.10386846319370771}
6M_7-000M_7-000-6.028235None35.943530None4M_3-000{'k1': 0.6228488917665873, 'k2': 0.020189424009226256, 'k3': 0.0010850434974038557, 'sigma_x2': 0.08859278245811462}
\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -136,27 +190,9 @@ } ], "source": [ - "import matplotlib\n", - "import pandas as pd\n", - "\n", - "pd.DataFrame(\n", - " {\n", - " \"Model hash\": [model.model_id for model in models],\n", - " \"AICc criterion\": [\n", - " model.get_criterion(petab_select.Criterion.AICC)\n", - " for model in models\n", - " ],\n", - " \"Predecessor model hash\": [\n", - " model.predecessor_model_hash for model in models\n", - " ],\n", - " \"Estimated parameters\": [\n", - " \", \".join(model.get_estimated_parameter_ids_all())\n", - " for model in models\n", - " ],\n", - " }\n", - ").style.background_gradient(\n", + "models.df.style.background_gradient(\n", " cmap=matplotlib.colormaps.get_cmap(\"summer\"),\n", - " subset=[\"AICc criterion\"],\n", + " subset=[petab_select.Criterion.AICC],\n", ")" ] }, @@ -182,9 +218,9 @@ " \"1\" if value == petab_select.ESTIMATE else \"0\"\n", " for value in model.parameters.values()\n", " )\n", - "labels[petab_select.ModelHash(petab_select.VIRTUAL_INITIAL_MODEL, \"\")] = (\n", - " \"\\n\".join(petab_select.VIRTUAL_INITIAL_MODEL.split(\"_\")).title()\n", - ")\n", + "labels[VIRTUAL_INITIAL_MODEL_HASH] = \"\\n\".join(\n", + " petab_select.VIRTUAL_INITIAL_MODEL.split(\"_\")\n", + ").title()\n", "\n", "# Custom colors for some models\n", "colors = {\n", @@ -216,9 +252,9 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -234,7 +270,7 @@ "id": "32de6556", "metadata": {}, "source": [ - "## Selected models\n", + "## Best model from each iteration\n", "\n", "This shows strict improvements in the criterion, and the corresponding model, across all iterations of model selection.\n", "\n", @@ -249,7 +285,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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TZPMqbe3N+Lj4912TgHnndexON/P9dB5BYCZM2e67by6w5yOx3jn1K2Kb2trK7y9vYfdmzMsLAxXXXUV/vrXvwIA3n77bSxatAgzZswY1+czmUxQqVSSuJ+fn+35c/872rGjGXeusLAwtLS0jOdLcHqOntPRGuuc+vr62n0fPz8/j5tTwHnndSzO9z3gafPqDnM6HmFhYTCZTDhz5syYXudWxXc01qxZg/3796OmpgYffPDBhA55+Pv7273Hq7e31/b8uf8d7djRjDuXIAiSTtmTTOacjtZY57Svr8/u+/T29nJOhyHHvI7F+b4HOK9Szj6n4yH8e1fesc6rWxXfadOmYWBgwHauzZ6VK1dCpVLhzjvvhNlsntCCBtHR0WhqapJssD54OComJsY27tz40LEajcb21/No3/NcHR0dCA8PH/fX4cwcPaejNThnw80pIJ5/i8WC5uZm0bi+vj60trbandP29na3nVPAeed1LM73c+1p8+oOczoe7e3tCAgIsPvH1kjcqvjqdDoAZ6+6G46/vz9uuOEGfPnll1i2bNmEfhCysrJw5swZFBcXi+Lfffed7Xng7HnZiIgIFBQUSN4jLy/PNm4s7zmovr4efX19kgu03IWj53S0lEolMjMz7c7pd999h5kzZ9qurhycs6FjCwoKYLVaJXM6MDCA2tpat51TwHnndSyGm9eGhgbU1dVJ5hU4+/W667y6w5yOx3jn1K2K74UXXghA+sMw1COPPIKtW7diy5YtE/p8119/PXx8fPCHP/zBFhMEAS+99BJiY2OxaNEiW/ymm27C3r17UVtba4t99tlnMBgMWL169bjeEwAOHz4MAJK4u3D0nI7FqlWrkJ+fL8qtpKQEn3/+uWhOL7/8cmg0Grz44oui17/44osICAjAihUrRPGioiL09va67ZwCzj2vo5WRkQGdToddu3bBYrHY4i+++CIUCgVWrVolGm80GlFeXu628+oOczoeR44cGdecep9/iOuYOXMmZs+ejQMHDuA///M/hx03d+5czJ07d8KfLy4uDhs2bMCOHTvQ39+PnJwcfPDBBzh48CDeeusteHl52cY++uijePfdd3HZZZfhgQceQHd3N3bs2IHMzEz8+Mc/Htd7AsD+/fuRkJCAefPmTfjrcUaOnlMAeOONN1BdXW27gOKrr77Cb37zGwDA2rVrbReI3HvvvfjjH/+IFStW4JFHHoGPjw+ee+45REZG4uGHH7a9n7+/P379619j3bp1WL16NZYvX46DBw/izTffxFNPPQWNRiP6/Pv370dAQACWLVs2KV+PM3LmeTUajfif//kfAD/cwrdz506EhoYiNDQU9913n+09d+zYgZUrV+LKK6/ErbfeipMnT2Lnzp24++67Jd3QgQMHIAgCrr/++kn5epyNu8zpV199ha+++goAcPr0afT09Njec8mSJViyZIlt7OHDh9HW1ja+OR3zshxO7rnnnhOCgoKEM2fO2GIARCtG2bN169Zxr+28bds2YcaMGYKvr6+QkZEhvPnmm3bHnjx5UrjyyiuFgIAAITQ0VLjtttuEpqamcb+nxWIRoqOjhccee2xMObsaR8/pJZdcYltrdujHF198IRpbW1srrFq1SggJCRGCgoKEa6+9VigtLbX7vrt27RJSU1MFX19fITk5WXj++eftrky2cOFCySpB7shZ57WysnLYcTNmzJC87/vvvy9kZWUJKpVKiIuLEx577DGhr69PMu6WW24RFi9ePKacXY07zOlgLvY+hq6gtXHjRiEhIYHLSwqCIHR0dAgajUb405/+JHcqU+79998X/P39hYaGBrlTmVKeNKdHjx4VFAqFcPToUblTmXKeNK+NjY2Cn5+fZHlFd+NJc9rb2ytERUUJv/vd78b1ercrvoIgCM8884yQmppqW5/TXV1wwQXC//t//0/uNBzCU+b0lltuEVavXi13Gg7jKfO6ceNGIScnR+40HMJT5vTFF18U4uPjhd7e3nG9XiEIQ+5pIZhMJhiNxhHHaDSaYRdOIOfDOXVPnFf34zFzOql/CriJV199ddhj/rBzPoGcH+fUPXFe3Y+nzCk7XzsaGxtRWFg44pjs7GyEhYU5KCOaKM6pe+K8uh9PmVMWXyIiIgdzq0U2iIiIXAGLLxERkYOx+BIRETkYiy8REZGDsfgSERE5GIsvERGRg7H4EhEROdj/B3jKilAyAVNPAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -259,7 +295,7 @@ } ], "source": [ - "petab_select.plot.line_selected(\n", + "petab_select.plot.line_best_by_iteration(\n", " models=models,\n", " criterion=petab_select.Criterion.AICC,\n", " labels=labels,\n", @@ -284,7 +320,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA7YAAAOwCAYAAAAKo+iFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAACtV0lEQVR4nOzdd3iUVf7+8XvSKCEJBGbonSBFpKOQUCV0pAqCFIGALMUuinVBUbEtAopkqNKkg0gNJUCigFQpIr0rSA2hpc3vj/0mP1lQCSQ5U96v69rLZebhmRvWJdz5nOcci8PhcAgAAAAAABflZToAAAAAAAAPgmILAAAAAHBpFFsAAAAAgEuj2AIAAAAAXBrFFgAAAADg0ii2AAAAAACXRrEFAAAAALg0ii0AAAAAwKX53MtFKSkpOnPmjAICAmSxWDI7EwAAAADAwzkcDl29elWFChWSl9ffz2TvqdieOXNGRYsWzZBwAAAAAADcq5MnT6pIkSJ/e809FduAgIC0GwYGBj54MgAAAAAA/kZcXJyKFi2a1kf/zj0V29Tlx4GBgRRbAAAAAECWuZfHYdk8CgAAAADg0ii2AAAAAACXRrEFAAAAALg0ii0AAAAAwKVRbAEAAAAALo1iCwAAAABwaRRbAAAAAIBLo9gCAAAAAFwaxRYAAAAA4NIotgAAAAAAl0axBQAAAAC4NIotAAAAAMClUWwBAAAAAC6NYgsAAAAAcGkUWwAAAACAS6PYAgAAAABcGsUWAAAAAODSKLYAAAAAAJdGsQUAAAAAuDSKLQAAAADApVFsAQAAAAAujWILAAAAAHBpFFsAAAAAgEuj2AIAAAAAXBrFFgAAAADg0ii2AAAAAACXRrEFAAAAALg0ii0AAAAAwKVRbAEAAAAALo1iCwAAAABwaRRbAAAAAIBLo9gCAAAAAFwaxRYAAAAA4NIotgAAAAAAl0axBQAAAAC4NIotAAAAAMClUWwBAAAAAC6NYgsAAAAAcGkUWwAAAACAS6PYAgAAAABcGsUWAAAAAODSfEwHAACYcfDgQV29etV0DKcSEBCgkJAQ0zEAAEA6UWwBwAMdPHhQZcuWNR3DKR04cIByCwCAi6HYAoAHSp3UDho0SIULFzacxjmcPn1aY8eOZYoNAIALotgCgAcrXLiwSpUqZToGAADAA2HzKAAAAACAS6PYAgAAAABcGsUWAAAAAODSKLYAAAAAAJdGsQUAAAAAuDSKLQAAAADApVFsAQAAAAAujWILAAAAAHBpFFsAAAAAgEuj2AIAAAAAXBrFFgAAAADg0ii2AAAAAACXRrEFAAAAALg0ii0AAAAAwKVRbAEAAAAALo1iCwAAAABwaRRbAAAAAIBLo9gCAAAAAFwaxRYAAAAA4NIotgAAAAAAl0axBQAAAAC4NIotAAAAAMClUWwBAAAAAC6NYgsAAAAAcGk+pgMAAJxXdHS0xo0bJ0kaNmyYypUrd9v7DodDAwcO1IULF1StWjW99tpr93zvixcvaurUqfr555/lcDhUsWJF9ejRQ/nz57/tulWrVmnPnj06dOiQLly4oPr162vAgAF3vee1a9c0Y8YMbdmyRQkJCSpdurS6d++uUqVKpfNXDgAAXAkTWwDAP/L19VVMTMwdr+/bt08XLlyQr69vuu538+ZNDR8+XL/88ovatm2rJ598UkePHtWwYcN09erV26797rvvtHfvXhUtWlTe3t5/ec+UlBR99NFHiomJUdOmTfX0008rLi5Ow4cP12+//ZaufAAAwLVQbAEA/6hq1aratGmTkpOTb3s9NjZWpUqVUu7cudN1v5UrV+q3337TkCFD1KZNG7Vs2VJvvvmmLl26pO+///62a999911NmDBBQ4cOlY/PXy802rx5sw4cOKABAwboySefVNOmTfXuu+/Ky8tLc+fOTVc+AADgWii2AIB/FBoaqvj4eP38889pryUlJWnTpk0KDQ1N9/02b96s0qVLq0yZMmmvFS5cWA8//LB+/PHH2661Wq2yWCz/eM9NmzYpKChItWrVSnstMDBQjz32mLZu3arExMR05wQAAK6BYgsA+EdWq1UhISGKjY1Ne23Hjh26fv266tSpk657paSk6MSJE3d97rVMmTI6e/asbty4ke6Mx44dU8mSJeXldfuXtjJlyujWrVssRwYAwI1RbAEA9yQsLExbt25VQkKCJCkmJkYVKlRQcHBwuu4THx+vxMRE5cmT5473Upc0X7p0Kd35Ll26dNd7pr528eLFdN8TAAC4BootAOCe1K5dWwkJCdq2bZtu3Lih7du339cy5NRifLfnZf38/G67Jr33vds9Uze2YikyAADui+N+AAD3JDAwUJUqVVJsbKwSEhKUkpKixx57LN33SS2vSUlJd7yXWmhTr0nvfe92z9RCm96dmwEAgOtgYgsAuGehoaHauXOnoqKiVKVKFfn7+6f7Hrly5ZKvr+9dlxtfvnxZku66pPif5MmT5673TH0tvUumAQCA66DYAgDuWa1atWSxWHTw4EGFhYXd1z28vLxUtGhRHTly5I73Dh06pPz58ytHjhzpvm/x4sV19OhRpaSk3HHPbNmyqWDBgveVFwAAOD+KLQDgnmXPnl0RERHq2LGjqlevft/3eeyxx3T48GEdPnw47bUzZ85oz54997W8OfWeV65c0ZYtW9Jei4uL06ZNm1StWjWWIgMA4MZ4xhYAkC7169d/4Hs0adJEa9as0ciRI9WqVSt5e3tr6dKlCgoKUqtWrW67dtu2bTp27JgkKTk5WcePH9f8+fMlSTVq1FDx4sUl/bfYLlu2TOPGjdOpU6cUEBCgVatWKSUlRZ06dXrgzAAAwHlRbAEAWS5Hjhx69913NXXqVC1YsEAOh0MVKlRQz549FRgYeNu1mzdv1vr169N+fOzYsbSimzdv3rRi6+Xlpddff13Tp0/XihUrlJCQoNKlS2vAgAEqVKhQlv3aAABA1rM4HA7HP10UFxenoKAgXbly5Y6/cAAAXM/27dtVvXp1ffjhhypVqpTpOE7hyJEjGjp0qLZt26Zq1aqZjgMAgMdLTw/lGVsAAAAAgEtjKTIAIMPEx8ff9SzZVF5eXqz8AQAAGY5iCwDIMJ999pn27dv3l+9brVaNHTs2CxMBAABPQLEFAGSY7t27Kz4+/i/f9/Pzy8I0AADAU1BsAQAZho2oAACACWweBQAAAABwaRRbAAAAAIBLo9gCAAAAAFwaxRYAAAAA4NIotgAAAAAAl0axBQAAAAC4NIotAAAAAMClUWwBAAAAAC7Nx3SAzHbw4EFdvXrVdAynEhAQoJCQENMxAAAAACBDuHWxPXjwoMqWLWs6hlM6cOAA5RYAAACAW3DrYps6qR00aJAKFy5sOI1zOH36tMaOHcsUGwAAAIDbcOtim6pw4cIqVaqU6RgAAAAAgEzA5lEAAAAAAJdGsQUAAAAAuDSKLQAAAADApVFsAQAAAAAujWILAAAAAHBpFFsAAAAAgEuj2AIAAAAAXBrFFgAAAADg0ii2AAAAAACXRrEFAAAAALg0ii0AAAAAwKX5mA4AADDn9OnTpiM4DX4vAABwXRRbAPBAAQEBkqSxY8caTuJ8Un9vAACA66DYAoAHCgkJ0YEDB3T16lXTUZxKQECAQkJCTMcAAADpRLEFAA9FgQMAAO6CzaMAAAAAAC6NYgsAAAAAcGkUWwAAAACAS6PYAgAAAABcGsUWAOAxunTpotWrV5uOAQAAMhjFFgDgERITE/Xtt98qPDxczz//vOLi4kxHAgAAGYRiCwDwCL6+vsqRI4ckacyYMSpTpoy+/fZbORwOw8kAAMCDotgCADxG4cKFJUkOh0Pnz59Xly5d1KhRIx0/ftxwMgAA8CAotgAAj1GkSJG0/546qY2Ojta0adNMRQIAABnAx3QAZxAdHa1x48ZJkoYNG6Zy5crd9r7D4dDAgQN14cIFVatWTa+99to93ffMmTOKiorSoUOHdPToUSUmJmrMmDGy2Wx3vX7r1q2aO3euTp8+rcDAQDVo0EAdOnSQt7d32jWXLl3S8uXLdfDgQR05ckQ3b97UO++8o4oVK97nrx4APEfhwoXl7e2t5ORkSZKfn58+/PBDPffcc4aTAQCAB8HE9k98fX0VExNzx+v79u3ThQsX5Ovrm677HThwQMuXL9eNGzfSlr/9lR07dujTTz+Vv7+/evXqpZo1a2rBggWaPHnybdedOXNGixcv1qVLl1SsWLF05QEAT1ewYMG0UhsYGKhSpUpp8ODB8vHh+7wAALgyvpL/SdWqVbVp0yb16tXrtilpbGysSpUqpatXr6brfjVq1NDkyZOVI0cOLVmyRMeOHfvLa6dPn65ixYrpzTffTPvsHDlyaNGiRWrevHlaMS5VqpQmTpyoXLlyadOmTTpw4ED6f6EA4KEee+wxlS5dWiNHjlTx4sX16KOPatSoUXr11VdNRwMAAA+Aie2fhIaGKj4+Xj///HPaa0lJSdq0aZNCQ0PTfb9cuXKl7cD5d06dOqVTp07p8ccfv61QN2nSRA6HQ5s2bUp7LUeOHMqVK1e6swAApA4dOujQoUPq0KGDatSooeeee07vvvvu337jEQAAOD+K7Z9YrVaFhIQoNjY27bUdO3bo+vXrqlOnTqZ97tGjRyVJpUuXvu314OBg5c2bl79wAUAmGT58uPLmzauBAwdy7A8AAC6MYvs/wsLCtHXrViUkJEiSYmJiVKFCBQUHB2faZ16+fFmSlDt37jvey507ty5dupRpnw0AniwgIEBffvmlli1bprlz55qOAwAA7hPF9n/Url1bCQkJ2rZtm27cuKHt27ff1zLk9Egt0XfbnMrX1zftfQBAxnviiSfUrl07Pf/882nfaAQAAK6FYvs/AgMDValSJcXGxmrLli1KSUnRY489lqmf6efnJ0lKTEy8473ExMS09wEAmWP06NGKj4/XG2+8YToKAAC4DxTbuwgNDdXOnTsVFRWlKlWqyN/fP1M/L3UJ8t0mBZcvX1aePHky9fMBwNMVKVJEI0aM0Ndff60ff/zRdBwAAJBOFNu7qFWrliwWiw4ePKiwsLBM/7wSJUpIkg4fPnzb6xcvXtSFCxfS3gcAZJ6BAweqevXq6tev311X0AAAAOdFsb2L7NmzKyIiQh07dlT16tUz/fOKFi2qQoUKac2aNUpJSUl7PSoqShaLRY8++mimZwAAT+ft7a3IyEjt27dPn3/+uek4AAAgHXxMB3BW9evXf+B7XL9+XcuXL5ckHThwQJK0cuVK5cyZU/7+/mrWrFnatd26ddMnn3yiESNGqE6dOjp58qRWrFihRo0aqUiRIrfdd/78+ZL+e/6tJG3cuFH79++X9N8zGgEA96dq1ap64YUXNGzYMD355JMqVaqU6UgAAOAeUGwzUXx8vObMmXPba99//72k/56Z++diW716db388suaN2+eJk+erMDAQLVr1+6uRfV/77lu3bq0/06xBYAHM2zYMM2bN08DBgzQ8uXLZbFYTEcCAAD/gGIrqUGDBmrQoME/Xjd27Nh03ddms2n27Nn3fH3NmjVVs2bNf7wuPfcEAKRPrly59OWXX6p169aaPXu2nnrqKdORAADAP+AZWwAA/kerVq3UoUMHPf/887p06ZLpOAAA4B9QbO9DfHy8Ll++/Jf/iYuLMx0RAPCARo8erRs3buj11183HQUAAPwDliLfh88++0z79u37y/etVmu6ly0DAJxLoUKF9OGHH2rQoEHq0aOHQkNDTUcCAAB/gWJ7H7p37674+Pi/fN/Pzy8L0wAAMkv//v31zTff6Nlnn9X27dv58x0AACdFsb0PHP8AAJ4h9Wzb6tWr69NPP9Ubb7xhOhIAALgLnrEFAOBvVK5cWS+99JLee+89HTp0yHQcAABwFxRbAAD+wbvvvqv8+fNrwIABcjgcpuMAAID/QbEFAOAf+Pv766uvvlJUVJRmzpxpOg4AAPgfFFsAAO5BixYt1KlTJ7344ou6ePGi6TgAAOBPKLYAANyjUaNG6datW3rttddMRwEAAH9CsQUA4B4VLFhQH330kSZMmKCNGzeajgMAAP4PxRYAgHR49tln9dhjj6lfv366deuW6TgAAEAUWwAA0sXLy0uRkZE6dOiQPvnkE9NxAACAKLYAAKRbpUqV9PLLL+v999/XgQMHTMcBAMDjUWwBALgP77zzjgoVKqR//etfnG0LAIBhFFsAAO5Dzpw59dVXX2nt2rWaPn266TgAAHg0ii0AAPepWbNmeuqpp/TSSy/p/PnzpuMAAOCxKLYAADyA//znP0pKStKQIUNMRwEAwGNRbAEAeAAFChTQyJEjNXnyZEVHR5uOAwCAR6LYAgDwgCIiIlSnTh3179+fs20BADCAYgsAwAPy8vLS+PHjdfjwYX300Uem4wAA4HEotgAAZICHH35YQ4YM0QcffKBff/3VdBwAADwKxRYAgAzy1ltvqUiRIurfvz9n2wIAkIUotgAAZJAcOXLo66+/VnR0tKZOnWo6DgAAHoNiCwBABgoPD9fTTz+tV155hbNtAQDIIhRbAAAy2Oeff66UlBS98sorpqMAAOARKLYAAGQwm82mjz/+WFOnTtXatWtNxwEAwO1RbAEAyAS9e/dWWFiY+vfvr5s3b5qOAwCAW/MxHSArnD592nQEp8HvBQBkjdSzbatUqaIPP/xQw4YNMx0JAAC35dbFNiAgQJI0duxYw0mcT+rvDQAg81SoUEGvvfaaPvzwQz311FMqX7686UgAALgli+MeDtqLi4tTUFCQrly5osDAwKzIlWEOHjyoq1evmo7hVAICAhQSEmI6BgB4hBs3buiRRx5RwYIFFR0dLS8vngICAOBepKeHuvXEVhIFDgBgVOrZto0bN9aUKVPUu3dv05EAAHA7fNsYAIBM9vjjj6t79+565ZVXdO7cOdNxAABwOxRbAACywGeffSaLxaKXX37ZdBQAANwOxRYAgCxgtVr16aefavr06Vq9erXpOAAAuBW33zwKAABn4XA41KBBA505c0Y///yzcuTIYToSAABOKz09lIktAABZxGKxaPz48Tp+/LhGjBhhOg4AAG6DYgsAQBYqV66chg4dqo8//lh79+41HQcAALfAUmQAALLYzZs3VblyZVmtVm3YsIGzbQEAuAuWIgMA4MSyZ8+ur7/+WrGxsZo4caLpOAAAuDyKLQAABjRs2FA9e/bUkCFDdPbsWdNxAABwaRRbAAAM+fTTT+Xt7a2XXnrJdBQAAFwaxRYAAEPy5cunzz77TDNnztTKlStNxwEAwGVRbA3ZsmWLfv75Z9MxAACG9ejRQw0bNtS//vUvXb9+3XQcAABcEsXWAIfDoccff1x16tTRrVu3TMcBABhksVj09ddf6/Tp03r//fdNxwEAwCVRbA2IiYlRfHy8rl27pk8++cR0HACAYWXLltWbb76pTz75RHv27DEdBwAAl8M5tgZ069ZNM2fOlMPhkJ+fn3755ReVKlXKdCwAgEG3bt1SlSpVFBwcrI0bN3K2LQDA43GOrRO7ePGi5syZo9TvJyQnJ2vAgAG6h+8vAADcWLZs2TR+/Hj98MMPstvtpuMAAOBSKLZZbNq0aUpKSkr7cXJyslauXKnFixcbTAUAcAb16tVT79699dprr+n33383HQcAAJdBsc1i48aNk8PhkMVikST5+PhIkj744AOTsQAATuLjjz+Wr6+vXnjhBdNRAABwGT6mA3iaRx55RDabTX5+flqzZo369u2rRx55RLVr1zYdDQDgBPLmzavPP/9cPXr0UM+ePdW8eXPTkQAAcHpsHmXIsWPHVLJkSa1atUrh4eGm4wAAnIjD4VB4eLgOHz6svXv3KmfOnKYjAQCQ5dg8ygVYrVZJ0h9//GE4CQDA2VgsFo0bN06//fabhg8fbjoOAABOj2JriL+/v3LmzKlz586ZjgIAcEIhISF666239Omnn+rnn382HQcAAKdGsTXIZrNRbAEAf2nIkCEqW7as+vXrp5SUFNNxAABwWhRbg6xWK0uRAQB/yc/PT+PHj9fmzZs1fvx403EAAHBaFFuDmNgCAP5J3bp1FRERoddff11nzpwxHQcAAKdEsTXIZrMxsQUA/KORI0cqe/bsnG0LAMBfoNgaZLVamdgCAP5RcHCw/vOf/2ju3LlaunSp6TgAADgdiq1BLEUGANyrLl26KDw8XAMHDtS1a9dMxwEAwKlQbA2y2Wy6evWqbt68aToKAMDJpZ5te/bsWf373/82HQcAAKdCsTXIarVKEs/ZAgDuSenSpfXOO+/oP//5j3bu3Gk6DgAAToNia5DNZpMkliMDAO7Zyy+/rHLlyunZZ59VcnKy6TgAADgFiq1BTGwBAOmVerbtli1bNG7cONNxAABwChRbg1KLLRNbAEB6hIaG6tlnn9Ubb7yh06dPm44DAIBxFFuDsmfPrsDAQIotACDdPvzwQ+XMmVPPP/+86SgAABhHsTXMarWyFBkAkG558uTRqFGjNH/+fC1ZssR0HAAAjKLYGsZZtgCA+9W5c2c1a9ZMgwYNUnx8vOk4AAAYQ7E1jGILALhfFotFX331lf744w+9++67puMAAGAMxdYwliIDAB5EyZIl9e6772rUqFHasWOH6TgAABhBsTWMiS0A4EG99NJLqlixovr168fZtgAAj0SxNcxmszGxBQA8EF9fX40fP17btm3Tl19+aToOAABZjmJrmNVq1fXr13Xt2jXTUQAALqx27drq37+/3nzzTZ06dcp0HAAAshTF1jCbzSZJLEcGADywDz74QLly5dJzzz1nOgoAAFmKYmtYarFlOTIA4EHlzp1bo0eP1sKFC7V48WLTcQAAyDIUW8OsVqskJrYAgIzRsWNHtWjRQoMGDdLVq1dNxwEAIEtQbA3Lly+fJIotACBjWCwWffnll7p48aLeeecd03EAAMgSFFvDfH19lSdPHpYiAwAyTIkSJTRs2DCNHj1a27ZtMx0HAIBMR7F1ApxlCwDIaM8//7wqVaqkfv36KSkpyXQcAAAyFcXWCVBsAQAZzdfXV5GRkdqxY4fGjh1rOg4AAJmKYusErFYrS5EBABmuVq1aGjhwoN566y2dPHnSdBwAADINxdYJMLEFAGSW999/X0FBQRo0aJAcDofpOAAAZAqKrROw2WxMbAEAmSIoKEijR4/Wd999p0WLFpmOAwBApqDYOgGr1apz587xnXQAQKZo3769WrVqpcGDBysuLs50HAAAMhzF1gnYbDYlJCTwlw0AQKZIPdv28uXLeuutt0zHAQAgw1FsnYDNZpMkliMDADJNsWLFNHz4cI0dO1Y//fST6TgAAGQoiq0TsFqtksQGUgCATPXcc8+pSpUqnG0LAHA7FFsnkDqxpdgCADKTj4+PIiMj9fPPP2v06NGm4wAAkGEotk4gODhYFouFpcgAgExXo0YNDRo0SG+//baOHz9uOg4AABmCYusEvL29lS9fPia2AIAs8d577ylPnjwaOHAgO/IDANwCxdZJ2Gw2ii0AIEsEBgZq7NixWrp0qRYsWGA6DgAAD4xi6ySsVitLkQEAWaZt27Zq06aNBg8erCtXrpiOAwDAA6HYOgkmtgCArDZmzBhdvXpVb775pukoAAA8EIqtk7DZbExsAQBZqmjRonr//ff11VdfafPmzabjAABw3yi2TsJqtTKxBQBkuUGDBqlatWrq16+fEhMTTccBAOC+UGydROrENiUlxXQUAIAH8fb2VmRkpC5evMjKIQCAy/IxHQD/ZbPZlJycrMuXLys4ONh0HACAB6lWrZpOnDghi8ViOgoAAPeFia2TsFqtksRyZACAEZRaAIAro9g6CZvNJoliCwAAAADpRbF1EqkTW55vAgAAAID0odg6idy5c8vHx4eJLQAAAACkE5tHOQkvLy+O/AEAZJqDBw/q6tWrpmM4lYCAAIWEhJiOAQDIABRbJ2K1WlmKDADIcAcPHlTZsmVNx3BKBw4coNwCgBug2DoRm83GxBYAkOFSJ7XdxndT/rL5DadxDmcPnNX0Z6czxQYAN0GxdSI2m02nT582HQMA4Kbyl82vopWLmo4BAECGY/MoJ8JSZAAAAABIP4qtE2EpMgAAAACkH8XWidhsNl24cEHJycmmowAAAACAy6DYOhGr1SqHw6ELFy6YjgIAAAAALoNi60RsNpsksRwZAAAAANKBYutEUostG0gBAAAAwL2j2DoRq9UqiYktAAAAAKQHxdaJBAQEKFu2bBRbAAAAAEgHiq0TsVgsnGULAAAAAOlEsXUynGULAAAAAOlDsXUyFFsAAAAASB+KrZNhKTIAAAAApA/F1skwsQUAAACA9KHYOhmbzcbEFgAAAADSgWLrZKxWqy5duqSEhATTUQAAAADAJVBsnYzNZpMknT9/3nASAAAAAHANFFsnk1psWY4MAAAAAPeGYutkrFarJLGBFAAAAADcI4qtk6HYAgAAAED6UGydjL+/v3LmzMlSZAAAAAC4RxRbJ8RZtgAAAABw7yi2TohiCwAAAAD3jmLrhKxWK0uRAQAAAOAeUWydEBNbAAAAALh3PqYD4E42m03r1683HQMA4GE2z9ysWYNmSZKeW/acSj1W6rb3HQ6HhlUapstnLqtCkwrq922/e7735TOXtejNRdq/br8cKQ6F1A1R2xFtla9Evjuu3TRtk9aOXauLJy4qd+Hcqtevnur1q/dA9wQAuDcmtk6IpcgAAJN8s/tq27xtd7x+KPaQLp+5LJ9s6fu++K34W/qyzZc69MMhhb8UruavN9epn09pbKuxunbx2m3Xxk6J1bfPf6uC5Qqqw0cdVKJmCS14fYFWf7H6vu8JAHB/FFsnZLPZdPXqVd28edN0FACAByrfuLx2Lt6p5KTk217fPm+7ilYpqgBbQLruFzMpRn8c/kP9ZvXT4889rgYDGuhf8/+luLNxWvflurTrEm4kaNn7y1ShSQX1mtpLtXvWVrdx3VT9yepa9ekqXb98Pd33BAB4BoqtE7LZbJLE1BYAYES1DtV0/eJ1/bru17TXkhKStOu7XarWoVq677fru10qVq2YilUrlvZa/rL5FVIvRDsX7Ux77VDMIV27eE1hfcJu+/lhfcKUcC1B+1btS/c9AQCegWLrhKxWqySxgRQAwIjgYsEqUbOEti/YnvbaL6t/0Y24G6rWPn3FNiUlRWf2nlHRKkXveK94teI6f/S8bl797wqlUz+fkqQ7ri1apagsXpa099NzTwCAZ6DYOqHUiS3FFgBgSrWO1bR76W4l3EiQJG2bu01lQssoqGBQuu5z/dJ1Jd1KUmD+wDveCyzw39eu/H5FkhR3Nk5e3l4KsN6+1NnHz0f+wf5p16XnngAAz0CxdUKpE1uWIgMATKnatqoSbyZq38p9unn1pvau2ntfy5ATbyRK0l03nEp9LfFmYtq13n7ed72PTzaf266713sCADwDx/04oWzZsikwMJCJLQDAmFz5cqls/bLaNn+bEm4kKCU5RZXbVE73fXxz+EqSkm4l3fFe6mu+2X3Trk1OSL7jutRr/3zdvd4TAOAZmNg6KZvNRrEFABhVvWN1/bL6F8VOjlX5xuWVMyhnuu+RM09O+WTzUdzZuDvei/v9v68FFfjv8ubA/IFKSU7R1T+u3nZdUkKSrl28lnZdeu4JAPAMFFsnxVm2AADTHmn5iCxeFh3felzVO1S/r3t4eXmpYIWCOrnz5B3vHd92XHlL5FX2gOySpMKVCkvSHdee3HFSjhRH2vvpuScAwDNQbJ0UE1sAgGnZcmXTk58+qWavNVPFZhXv+z6Vn6isE9tP6MSOE2mvnT14Vgc3HlSVNlXSXgupG6KceXIqdlLsbT8/dnKs/HL6qUKTCum+JwDAM/CMrZOy2WzasWOH6RgAAA9Xq0utB75HWO8wbfpmkyKfilSjgY3k5eul6K+iFWALUMOBDdOu88vhpxZvtNC8V+dp8jOTVa5ROR3ZdERb52xVy7dayj+Pf7rvCQDwDBRbJ8VSZACAu8gekF2DvhukhW8u1KrPVsnhcKhMaBm1HdFWufLluu3asD5h8vbx1rqv1mnPij3KUziP2o5oq/r969/3PQEA7o9i66RYigwAyGqPdn1Uj3Z99B+ve3fXu+m+d+7CudVrSq97urZ2z9qq3bN2ht4TAODeeMbWSdlsNt24cUPXrl0zHQUAAAAAnBoTWydltVolSefOnVPJkiUNpwEA4E7XLl37y3NnJcnL24tlwQCALEGxdVI2m00SxRYA4Lwm9Zikw7GH//L9PEXz3NeyZQAA0oti66RSiy0bSAEAnFXb99rq+uXrf/m+b3bfLEwDAPBkFFsnlTdvXkliAykAgNMqWqWo6QgAAEhi8yin5evrq+DgYIotAAAAAPwDiq0T4yxbAAAAAPhnFFsnxlm2AAAAAPDPKLZOjGILAAAAAP+MYuvEWIoMAAAAAP+MYuvEmNgCAAAAwD+j2Doxm82mP/74Qw6Hw3QUAAAAAHBaFFsnZrValZCQoLi4ONNRAAAAAMBp+ZgOgL9ms9kkSefOnVNQUJDhNAAAeK6ffvpJ0dHRypUrl+Lj43X16tW0f9auXVu9e/c2HREAPBrF1omlFts//vhDISEhhtMAAOC5evXqpb1790qSvLy85O3tLUlKTEzU6dOnKbYAYBhLkZ2Y1WqVJDaQAgDAsCVLliggIECSlJKSosTERCUmJkqSBg4caDIaAEAUW6cWHBwsLy8vii0AAIaVLFlSa9askZ+f322ve3l5KTY2VmfOnDGUDAAgUWydmre3t/LmzctZtgAAOIGaNWtq6tSpt71Wr149jRkzRiVKlFD37t21bds2Q+kAwLNRbJ0cZ9kCAOA8nnrqKb355puSpMDAQH3//fc6deqURo4cqZiYGNWoUUP16tXTwoULlZycbDgtAHgOiq2To9gCAOBchg8frkGDBunjjz+Wv7+/goKC9OKLL+rQoUOaP3++HA6H2rdvr5CQEI0aNYpj+wAgC1BsnZzVamUpMgAATsTLy0tjxozRs88+e9vr3t7eat++vTZu3KiffvpJderU0auvvqoiRYropZde0tGjRw0lBgD3R7F1ckxsAQBwPTVq1ND06dN17NgxDRo0SFOnTlWZMmXUoUMHxcTEyOFwmI4IAG6FYuvkKLYAALiuwoUL64MPPtDJkyf11Vdfad++fapbt65q1aqlGTNmKCEhwXREAHALFFsnZ7Vadf78eaWkpJiOAgAA7lPOnDn17LPPau/evVq2bJmCg4PVrVs3lSxZUh988IEuXLhgOiIAuDSKrZOz2WxKTk7WpUuXTEcBAAAPyMvLS82bN9fKlSu1Z88etWjRQsOHD1fRokXVv39//fLLL6YjAoBLotg6OZvNJklsIAUAgJupWLGi7Ha7Tp48qTfeeEOLFy9WhQoV1Lx5c61atYrncAEgHSi2Ts5qtUoSz9kCANItOTlZa9as4XEWJ2e1WvXWW2/p2LFj+uabb3T27Fk1bdpUDz/8sOx2u27cuGE6IgA4PYqtk0ud2FJsAQDpkZCQoK5du6pJkyZ8DXER2bJlU/fu3bVt2zZFR0erbNmyevbZZ1WsWDG9/fbb+u2330xHBACn5WM6AP5e7ty55ePjw1JkAMA9u3btmtq3b6/o6GjNmzdPBQoUkCSdPXDWcDLn4cy/FxaLRfXr11f9+vV1+PBhjR49WqNGjdLIkSP11FNP6cUXX1TVqlVNxwQAp0KxdXIWi0VWq5XvtgMA7snFixfVsmVL7dmzRytWrFDDhg118OBBSdL0Z6cbTud8AgICTEf4W6VLl9YXX3yh4cOHa+LEiRo9erSmTZumevXq6cUXX1Tr1q3l7e1tOiYAGGdx3MPOBHFxcQoKCtKVK1cUGBiYFbnwJ1WqVFFoaKi+/PJL01EAAE7szJkzatq0qX777TetWLFCNWrUSHvv4MGDunr1qsF0zicgIEAhISGmY6RLUlKSFi1apFGjRik2NlalSpXSc889p969ezt9SQeA9EpPD6XYuoDw8HDlyZNHc+bMMR0FAOCkDh06pCZNmigxMVFRUVEqV66c6UjIZFu2bNGoUaM0d+5c5cyZUxERERo8eLBKlChhOhoAZIj09FA2j3IBNpuNpcgAgL+0a9cuhYWFyc/PT7GxsZRaD1GrVi3NnDlTR48e1YABAzR58mSVLl1aHTt2VGxsLMcFAfAoFFsXQLEFAPyV2NhY1a9fX4ULF9bGjRtVrFgx05GQxYoUKaIPP/xQJ0+e1Jdffqk9e/YoLCxMjz76qGbOnKnExETTEQEg01FsXYDVamVXZADAHZYtW6bw8HBVrVpV69atSzv7HJ7J399f/fv31759+7R06VIFBQXp6aefVsmSJfXRRx/p4sWLpiMCQKah2LoAm82mCxcuKDk52XQUAICTmDlzptq0aaMmTZpo+fLl7IGBNF5eXmrRooWioqK0e/duNWvWTP/+979VpEgR/etf/9L+/ftNRwSADEexdQE2m00Oh0MXLlwwHQUA4AS+/PJLdevWTd26ddO8efOUPXt205HgpB5++GFNmDBBJ06c0NChQ7Vw4UKVL18+rfjyHC4Ad0GxdQGpS8t4zhYAPJvD4dDw4cM1aNAgvfDCC5o4caJ8fDiSHv/MZrPp7bff1vHjxzVlyhSdOXNGTZo00SOPPKKJEyfqxo0bpiMCwAOh2LoAm80miWILAJ4sJSVFL7zwgt59912NGDFCn332mby8su7LOI/DuIds2bKpZ8+e2rFjh9atW6dSpUqpb9++KlasmN555x39/vvvpiMCwH2h2LqA1GLLBlIA4JkSExPVs2dPjRkzRuPGjdMbb7whi8WSZZ+/f/9+2Ww2nThxIss+E5nLYrGoQYMGWrx4sX799Vd16dJFn3/+uYoXL65nnnlGO3fuNB0RANKFYusCcuXKpWzZsjGxBQAPdOPGDXXo0EGzZ8/WrFmz1L9//yzPMH78eHl7e6tAgQJZ/tnIfCEhIRo9erROnTqlDz74QOvWrVPVqlXVsGFDfffdd0zrAbgEiq0LsFgsnGULAB7oypUratq0qdasWaMlS5aoc+fOWZ7h5s2b+uabb9SzZ0/5+fll+ecj6+TOnVsvv/yyDh8+rDlz5ujWrVtq06aNHnroIY0ZM0bx8fGmIwLAX6LYugjOsgUAz3L27Fk1aNBAu3fvVlRUlJo2bWokx8KFC3Xx4kVFREQY+XxkPR8fHz355JP64YcftGnTJtWsWVMvvviiihQpoldeeUXHjx83HREA7kCxdRFMbAHAcxw7dkx169bV2bNntWHDBtWpU8dYlsjISNWrV08PPfSQsQww59FHH9WsWbN09OhR9e/fXxMnTlTp0qXVqVMn/fDDDxwXBMBpUGxdBMUWADzDvn37FBYWpuTkZMXExKhSpUrGshw8eFDR0dHq16+fsQxwDkWLFtVHH32kU6dOafTo0dq1a5dCQ0P12GOP6dtvv1ViYqLpiAA8HMXWRbAUGQDc35YtW1S3bl0FBwcrJiZGpUqVMppnwoQJypMnjzp06GA0B5yHv7+/BgwYoF9++UXff/+9AgIC1KVLF5UqVUojR47UpUuXTEcE4KEoti6CiS0AuLfVq1erUaNGKl++vNavX6+CBQsazZOQkKApU6aoe/fuyp49u9EscD5eXl5q2bKlVq9erV27dqlJkyZ69913VaRIEQ0cOFAHDhwwHRGAh6HYugibzabLly8rISHBdBQAQAabP3++WrZsqXr16mnVqlXKkyeP6Uj67rvvdO7cOfXt29d0FDi5Rx55RBMnTtSJEyc0ZMgQzZs3Tw899JBatWqlNWvW8BwugCxBsXURVqtVknT+/HnDSQAAGWnChAnq1KmTOnTooEWLFilnzpymI0mS7Ha7ateurYcffth0FLgIm82md999V8ePH9fkyZN18uRJNW7cWJUrV9akSZN08+ZN0xEBuDGKrYuw2WySxHJkAHAjH3/8sfr27av+/ftr+vTpTnNO7LFjxxQVFcW0Fvcle/bseuaZZ7Rz506tWbNGJUqUUEREhIoXL65///vfOnv2rOmIANwQxdZFpBZbNpACANfncDj02muv6bXXXtPbb7+tsWPHysvLeb4kT5w4UQEBAerUqZPpKHBhFotFjRo10nfffadff/1VTz75pD755BMVK1ZMvXr10q5du0xHBOBGnOerKP5W6lJkJrYA4NqSk5PVr18/ffzxxxo1apSGDx8ui8ViOlaapKQkTZo0SV27dpW/v7/pOHATISEhGjt2rE6dOqX3339fa9asUZUqVdSoUSMtWbJEKSkppiMCcHEUWxeRM2dO+fv7U2wBwIXdunVLnTp10uTJkzV16lQ9//zzpiPdYdmyZTpz5gxn1yJT5MmTR6+++qqOHDmi2bNn68aNG3riiSf00EMPaezYsYqPjzcdEYCLoti6EM6yBQDXdfXqVbVs2VJLly7VggUL1KNHD9OR7sput6t69eqqWrWq6ShwYz4+PurUqZN+/PFH/fjjj6pevbpeeOEFFS1aVEOGDNGJEydMRwTgYii2LoSzbAHANV24cEGNGzfWTz/9pJUrV+qJJ54wHemuTp06pWXLlrFpFLLUY489pm+//VZHjhxR3759FRkZqVKlSqlz587atGmT6XgAXATF1oVQbAHA9Zw6dUp169bV0aNHtW7dOtWvX990pL80efJkZc+eXV26dDEdBR6oWLFi+vjjj3Xq1Cl98cUX2rFjh2rXrq3HHntMs2fPVlJSkumIAJwYxdaFsBQZAFzLgQMHFBoaqmvXrikmJkbVqlUzHekvJScna8KECXrqqacUGBhoOg48WK5cuTRw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jh3aunUrm0YBmaxEiRL69NNPderUKX322WfavHmzHn30UYWGhmrevHlKSkoyHRFwSxRbF5R6li0A4MHExcWpefPmWrlypRYvXqyuXbuajpRp7Ha7ChYsqJYtW5qOAniEgIAAPffcczpw4IAWLVokX19fPfnkkypTpow+++wzXblyxXREwK1QbF0QE1sAeHB//PGHGjVqpB07digqKkotWrQwHSnTXLt2TTNmzFDv3r3l4+NjOg7gUby9vdWmTRtFR0dr27Ztql+/voYOHaoiRYroueee0+HDh01HBNwCxdYFUWwB4MGcOHFCdevW1alTp7R+/XqFhYWZjpSp5s6dq7i4OPXp08d0FMCjVatWTVOnTtXx48f1wgsvaNasWQoJCVHbtm21fv16ORwO0xEBl0WxdUEsRQaA+7d//36Fhobq1q1biomJUeXKlU1HynSRkZEKDw9XyZIlTUcBIKlgwYJ67733dOLECUVGRurQoUNq0KCBqlevrm+++Ua3bt0yHRFwORRbF5Q6seW7egCQPlu3blXdunUVFBSk2NhYlSlTxnSkTLd37179+OOP6tevn+koAP5Hjhw5FBERod27d2vlypUqUKCAevbsqRIlSui9995jkAGkA8XWBdlsNiUmJrLpAACkw7p169SwYUOVKVNGGzZsUKFChUxHyhJ2u11Wq1VPPPGE6SgA/oLFYlGTJk20bNky7du3T23atNGHH36ookWLKiIiQnv27DEdEXB6FFsXZLVaJYnv4gHAPVq0aJGaN2+u2rVrKyoqSsHBwaYjZYmbN29q2rRpeuaZZ+Tn52c6DoB7UL58eX399dc6efKk3n33XS1fvlyVKlVSkyZNtHz5cqWkpJiOCDgliq0LstlsksQGUgBwD6ZMmaIOHTroiSee0JIlS5QrVy7TkbLMggULdPHiRUVERJiOAiCd8ubNq6FDh+ro0aOaMWOGLl26pBYtWqhixYr6+uuvdf36ddMRAadCsXVBqcWWiS0A/L3PP/9cvXr1UkREhGbNmqVs2bKZjpSlIiMjVb9+fZUtW9Z0FAD3yc/PT127dtWWLVu0ceNGVaxYUQMHDlTRokU1dOhQnT592nREwClQbF1QcHCwvLy8mNgCwF9wOBx688039fLLL2vo0KH6+uuv5e3tbTpWljpw4IDWr1/PplGAm7BYLAoLC9O8efN06NAh9ezZU19++aVKlCihp59+Wj/99JPpiIBRFFsX5OXlpXz58lFsAeAukpOT9a9//UsffPCBPv30U33wwQeyWCymY2W5CRMmKDg4WO3btzcdBUAGK1mypD7//HOdOnVKn376qX788UfVqlVLYWFhmj9/vpKTk01HBLIcxdZFcZYtANwpISFBXbt2ld1u16RJk/Tyyy+bjmREQkKCpkyZou7duyt79uym4wDIJIGBgXr++ed18OBBLViwQN7e3urYsaPKlCmjzz//nBM04FEoti4q9SxbAMB/Xbt2Ta1bt9aiRYs0b9489erVy3QkYxYvXqw//vhDffv2NR0FQBbw9vZWu3bttH79em3dulVhYWF6/fXXVaRIET3//PM6fPiw6YhApqPYuiiKLQD8fxcvXlTjxo31ww8/aMWKFWrXrp3pSEbZ7XbVqVNHFStWNB0FQBarXr26pk2bpmPHjun555/XjBkzFBISonbt2mnDhg1yOBymIwKZgmLroliKDAD/debMGdWvX18HDx7UunXr1LBhQ9ORjDp69KiioqKY1gIerlChQnr//fd14sQJjR8/XgcOHFD9+vXTim9CQoLpiECGoti6KCa2ACAdOnRIoaGhunz5smJiYlSjRg3TkYybOHGiAgMD9eSTT5qOAsAJ5MyZU3379tWePXu0YsUK2Ww29ejRQ8WLF9f777+v8+fPm44IZAiKrYuy2Ww6f/68UlJSTEcBACN27dqlsLAw+fn5KTY2VuXKlTMdybikpCRNmjRJTz/9tPz9/U3HAeBELBaLmjZtqhUrVmjv3r164oknNGLECBUtWlT9+vXT3r17TUcEHgjF1kVZrVYlJyfr0qVLpqMAQJaLiYlR/fr1VbhwYcXExKhYsWKmIzmFpUuX6rfffuPsWgB/q0KFCho/frxOnjypt99+W99//70efvjhtOLLc7hwRRRbF2Wz2SSJ5cgAPM6yZcvUpEkTVa1aVevWrZPVajUdyWnY7XbVqFFDVapUMR0FgAvIly+f3njjDR07dkzTpk3T+fPn1bx5c1WsWFHjx4/X9evXTUcE7hnF1kWlFls2kALgSWbOnKk2bdooPDxcy5cvV2BgoOlITuPkyZNavnw5m0YBSDc/Pz9169ZNW7du1YYNG1SuXDn961//UtGiRfXGG2/o9OnTpiMC/8jHdADcn9QJBRNbAJ7iyy+/1ODBg9WjRw9NmDBBPj58CfuzSZMmKUeOHOrSpYvpKABclMViUd26dVW3bl0dOXJEY8aM0dixY/XJJ5+oc+fOevHFF1W9enXTMe/JwYMHdfXqVdMxnEpAQIBCQkJMx8g0Fsc9LKKPi4tTUFCQrly5wnfHnYTD4ZCfn5+++OILDRgwwHQcAMg0DodD7733nt599129+OKL+vTTT+XlxYKjP0tOTlbJkiXVpEkTTZgwwXQcAG4kLi5OkyZN0ujRo3X06FGFhYXpxRdfVJs2beTt7W063l0dPHhQZcuWNR3DKR04cMClym16eijf7nZRFotFNpuNpcgA3FpKSopefPFFjR49WiNGjNDQoUNlsVhMx3I6q1at0smTJ9k0CkCGCwwM1AsvvKDBgwdr8eLF+s9//qMOHTqoRIkSeu6559SnTx+nG3ylTmoHDRqkwoULG07jHE6fPq2xY8e69RSbYuvCrFYrS5EBuK3ExET17t1bM2bM0Lhx49S/f3/TkZyW3W7XI488opo1a5qOAsBNeXt7q3379mrfvr22bt2qUaNGaciQIXr33XfVp08fDR48WKVKlTId8zaFCxd2ukzIPKzlcmE2m41iC8At3bhxQx06dNDs2bM1a9YsSu3f+O2337RkyRL17duXaTaALFGjRg1Nnz5dx44d0+DBg/XNN98oJCRE7du318aNGzkuCEZQbF2Y1WplKTIAt3PlyhU1bdpUa9as0ZIlS9S5c2fTkZzalClT5OPjo6efftp0FAAepnDhwhoxYoROnjypr776Sr/88ovq1aunmjVravr06UpISDAdER6EYuvCmNgCcDdnz55VgwYNtHv3bkVFRalp06amIzm1lJQUTZgwQZ06dVKePHlMxwHgoXLmzKlnn31We/fu1fLly5U3b151795dJUqU0IgRI3T+/HnTEe9bdHS0Onfu7JR/5x42bJiGDRtmOobToNi6MIotAHdy7Ngx1a1bV2fPntWGDRtUp04d05Gc3rp163TkyBHOrgXgFLy8vNSsWTOtXLlSe/bsUatWrfT++++raNGievbZZ7Vv3z7TESVJH3/8sbp3764bN2785TWjR49W165d073Z0sKFC/XTTz89aETcB4qtC7Narbp48aKSkpJMRwGAB7Jv3z6FhYUpOTlZMTExqlSpkulILsFut6t8+fIKDQ01HQUAblOxYkVFRkbqxIkTevPN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769x48bpm2++UXx8vH755RelpaWpZ8+eOnr0qNXRAcB2KLYAAADXWePGjfXUU09p69at2rNnjx5//HGtW7dOd9xxh4YMGSI3NzcVFxdr37596t27N8uSAaCMKLYAAADlqE2bNvrb3/6m1NRUffPNNyosLCw5KujcuXPatWuXevTooZycHIuTAoB9UGwBAAAs4Obmpl9++UVFRUWlxl0ul3766SeFhYVZlAwA7MfD6gAAAABV1dq1a0v+7O7uLofDoaCgIHl6eioiIsLCZABgLxRbAAAAi7zyyisaOXKkmjdvrsDAQHl6elodCQBsiWILAABgET8/P/n5+VkdAwBsj+/YAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1jvsBAACoQtatW6cPP/xQkvTyyy+rTZs2pa67XC49+uijOnbsmMLCwjRlypTLum9GRobi4+OVmpqqAwcOqLCwUO+9995FjzPatGmTtm7dqtTUVGVlZSk0NFQvvfTSRe9bWFiouLg4ffvtt8rNzVWzZs00YsQItWvXrow/OYDKjCe2AAAAVZCnp6c2btx4wfju3bt17NgxeXp6lul+ycnJWrFihfLz8xUYGPi7c+Pj47VlyxY1aNBAtWvX/t25H3zwgb7++mtFRERo7Nixcnd317Rp07R3794y5QNQuVFsAQAAqqAOHTooMTFR586dKzWekJCg4OBg1a1bt0z369ixo2JiYjR9+nRFRET87txHH31UMTExevHFF1WvXr1LzktNTdWmTZsUGRmpUaNGqU+fPnrhhRfUsGFDmaZZpnwAKjeKLQAAQBXUvXt35ebmaseOHSVjRUVFSkxMVPfu3ct8vzp16qhmzZqXNbdhw4Zyd//jv4YmJibK3d1dd9xxR8mYl5eXevXqpeTkZP36669lzgmgcqLYAgAAVEGNGjVSSEiIEhISSsa2bdumvLw8devWzcJk/+fgwYMKCAhQrVq1So23atVKknTo0CErYgGogCi2AAAAVVRERIS2bNmigoICSdLGjRsVGhqq+vXrW5zsNydOnLjoUuXzY8ePHy/vSAAqKIotAABAFdW1a1cVFBRo69atys/PV1JS0hUtQ75eCgsL5eFx4SEe5ze2Ol/IAYDjfgAAAKooHx8f3XzzzUpISFBBQYGKi4vVpUsXq2OV8PT0VFFR0QXjhYWFkn77vi0ASDyxBQAAqNK6d++u7du3Kz4+Xu3bt//D43fKU7169XTixIkLxs+PVZQl0wCsR7EFAACowjp16iQ3NzelpKT84TE95a158+bKzMxUXl5eqfHU1FRJUrNmzayIBaACotgCAABUYTVq1ND48eM1dOhQhYeHWx2nlM6dO6u4uFhr1qwpGSssLNS6devUqlUrNWzY0MJ0ACoSvmMLAABQxfXo0eOq75GXl6cVK1ZIkpKTkyVJq1atUq1atVS7dm3169evZO7u3bu1Z88eSVJOTo7Onj2rBQsWSJLatm2r0NBQSVJISIi6dOmi2bNn69SpU/L399f69et19OhRPfzww1edGUDlQbEFAADAVcvNzVVcXFypsWXLlkn67czc/yy2u3bt0vz580vNPf/aoUOHlhRbSXr00UcVFxenb7/9VqdPn1ZQUJD+/Oc/l5oDAG4ul8v1R5Oys7Pl6+urU6dOycfHpzxyAQAAoAySkpIUHh6u1157TcHBwVbHqTD279+v559/Xlu3blVYWJjVcQCUQVl6KN+xBQAAAADYGkuRAQAAcEm5ubkXPUv2PHd3d1b0AbAcxRYAAACX9Oabb2r37t2XvN6oUSPNmDGjHBMBwIUotgAAALik0aNHKzc395LXvby8yjENAFwcxRYAAACXxEZUAOyAzaMAAAAAALZGsQUAAAAA2BrFFgAAAABgaxRbAAAAAICtUWwBAAAAALZGsQUAAAAA2BrFFgAAAABgaxRbAAAAAICtUWwBAAAAALZGsQUAAAAA2BrFFgAAAABgaxRbAAAAAICtUWwBAAAAALZGsQUAAAAA2BrFFgAAAABgaxRbAAAAAICtUWwBAAAAALZGsQUAAAAA2BrFFgAAAABgaxRbAAAAAICtUWwBAAAAALZGsQUAAAAA2BrFFgAAAABgax5WBwAAAMC1c+TIEasjVCj8PoCqgWILAABQCXh7e0uSZsyYYXGSiun87wdA5USxBQAAqARCQkKUnJysnJwcq6NUON7e3goJCbE6BoDriGILAABQSVDeAFRVbB4FAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1ii0AAAAAwNYotgAAAAAAW6PYAgAAAABsjWILAAAAALA1j8uZ5HK5JEnZ2dnXNQwAAAAAANL/9c/zffT3XFaxzcnJkSQ1bdr0KmIBAAAAAFA2OTk58vX1/d05bq7LqL/FxcXKyMiQt7e33NzcrllAAAAAAAAuxuVyKScnR40bN5a7++9/i/ayii0AAAAAABUVm0cBAAAAAGyNYgsAAAAAsDWKLQAAAADA1ii2AAAAAABbo9gCAAAAAGyNYgsAAAAAsDWKLQAAAADA1v4/GJ6dbbgrgSoAAAAASUVORK5CYII=", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA7YAAAOwCAYAAAAKo+iFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADRYUlEQVR4nOzddVhUaf8G8HtIFQG7E2UMTGzFosUWFRNz7e4EsTuxgwUM7Aal1FVW7FxWwe5YgxDJmd8f+8JP1gKc4Zm4P9e11/ty5sw5N1y7wM33nOdI5HK5HERERERERERqSkd0ACIiIiIiIqJfwWJLREREREREao3FloiIiIiIiNQaiy0RERERERGpNRZbIiIiIiIiUmsstkRERERERKTWWGyJiIiIiIhIrbHYEhERERERkVrTy8xOMpkML168gLGxMSQSibIzERERERERkZaTy+WIjY1FiRIloKPz45lsportixcvULp0aYWEIyIiIiIiIsqsp0+folSpUj/cJ1PF1tjYOP2AJiYmv56MiIiIiIiI6AdiYmJQunTp9D76I5kqtmmXH5uYmLDYEhERERERUY7JzO2wXDyKiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1Jqe6ABEREREPxIVFYXY2FjRMVSKsbExzM3NRccgIlIZLLZERESksqKioiCVSkXHUEmRkZEst0RE/8NiS0RERCorbVI7YsQIlCxZUnAa1fD8+XN4enpyik1E9AUWWyIiIlJ5JUuWhJmZmegYRESkorh4FBEREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1PdEBiEh1REVFITY2VnQMlWJsbAxzc3PRMYiIiIjoB1hsiQjAv6VWKpWKjqGSIiMjWW6JiIiIVBiLLREBQPqkdsSIEShZsqTgNKrh+fPn8PT05BSbiIiISMWx2BJRBiVLloSZmZnoGEREREREmcbFo4iIiIiIiEitsdgSERERERGRWmOxJSKlOH36NFxcXPDmzRvRUb7i4eEBDw8P0TGIiIiISEFYbIko0xYvXozevXvj8+fP391n9erV6NGjR5YXXDp48CAuXbr0qxGJiIiISAux2BJRpllZWSEpKQkXL1785uuJiYm4fPkyatWqhdatW8PX1xeFCxfO1LFZbImIiIgou1hsiSjT6tati9y5cyMsLOybr1++fBmJiYmwsrKCjo4ODAwMIJFIvns8uVyOpKQkZcUlIiIiIi3Bx/0QUaYZGBigfv36OHfuHKKjo2Fqaprh9XPnziF37tyoW7cuTp8+jfXr12PNmjUoUqQIgH+fkVu6dGk4ODhg9+7dePr0Kbp37w4fHx8AwJkzZ3DmzBkAQPPmzTFs2DCsW7cOERER8PT0zHCuvXv3Yt++fdi9e3f6tlOnTuHs2bN4+vQp4uPjUbRoUTg6OsLe3l6ZXxYiIiIiEozFloiyxMrKCmfOnMH58+fh6OiYvj0uLg43btxAkyZNYGBg8N33v3jxAqtXr4atrS2sra1RokQJjBgxAhs3bkSFChVga2sLAChatGiWswUFBaFUqVKoU6cOdHV1ceXKFWzduhVyuRwODg5Z/2SJiIiISC2w2BJRllSrVg358+dHWFhYhmJ7/vx5pKamwsrK6ofvf/XqFaZOnYpatWpl2L5582YULVoUTZs2zXa2WbNmZSjVjo6OmD9/Po4fP85iS0RERKTBeI8tEWWJjo4OGjdujMjIyAyP8gkLC4OpqSmqV6/+w/cXKVLkq1KrKF+W2vj4eMTExKBKlSp4/fo14uPjlXJOIiIiIhKPE1siyjIrKyscP34cYWFh6NixI969e4c7d+7A0dEROjo//ntZ2v22ynDnzh3s3bsXUVFRSExMzPBafHw88uTJo7RzExEREZE4LLZElGVmZmYoUaJEerENCwuDXC7/6WXIAH54/21WyGSyDB+/evUKc+fORYkSJdC7d28UKlQIurq6uH79Oo4fP/7V/kSkWdIWrAMADw8PVK5cOcPrcrkcw4cPx7t372BpaYnJkydn6rgvXrxAUFAQ7t27h4cPHyI5OTnDonj/dfnyZezduxfPnz+HiYkJWrRoAWdnZ+jq6mbY79OnT9ixYwcuXryIpKQkVKhQAb1794aZmVk2PnsiIuKlyESULVZWVnj69CkeP36MsLAwFC9eHBUrVsz28b73WKC8efPi06dPX21/+/Ztho+vXLmC5ORkTJo0CXZ2dqhduzZq1KihsCJNROpBX18f586d+2p7REQE3r17B319/SwdLzIyEgEBAfj8+TNKliz5w32vXbuGpUuXwsjICP369UO9evVw4MABeHl5ZdhPJpNh4cKFOHfuHBwcHNCzZ0/ExMRg9uzZePnyZZbyERHRv1hsiShb0hZ52rNnDx49eoQmTZr80vEMDQ2/WWCLFi2K+Ph4PH78OH3bhw8fcOnSpQz7pV0CLZfL07fFx8fj9OnTv5SLiNRL7dq1ER4ejtTU1Azbw8LCYGZmhnz58mXpeHXr1oWXlxeWLl3606tStm/fjjJlymD69OmwsbFBv3790KFDBwQHB+P58+fp+124cAGRkZEYNmwYunTpAgcHB7i7u0NHRwd79+7NUj4iIvoXiy0RZUuRIkUglUpx+fJlAPil1YyBfy9vvnXrFo4dO4awsDBERUUBABo3bgxDQ0MsW7YM/v7+OHjwIKZPn47ixYtneH/NmjWhp6eHxYsX4+TJkzh8+DCmTJkCExOTX8pFROqlSZMmiIuLw82bN9O3paSkIDw8PFt/gMubNy9y58790/2ePXuGZ8+ewcbGJsNlx/b29pDL5QgPD0/fFh4eDlNTU9SvXz99m4mJCRo2bIjLly8jOTk5yzmJiLQdiy0RZVva9KJixYooVqzYLx3L1dUVZmZm2L17N1avXo2goCAAgLGxMSZMmAADAwPs2LEDf/zxB7p37446depkeH+JEiUwbtw4AICvry+CgoJgY2ODVq1a/VIuIlIvhQsXhrm5OcLCwtK3Xbt2DfHx8WjcuLHSzvvw4UMAQIUKFTJsL1CgAAoWLIhHjx6lb3v06BHKly//1WJ7FStWRGJiIi9HJiLKBi4eRUTZ5uDg8N3nw7Zo0QItWrTIsM3T0/O7xypRogRmzZr1zddq1KiBpUuXfrW9S5cuGT6uU6fOV4UXAFq2bJnhY3d39+/mICL1Z2VlhV27diEpKQkGBgY4d+4cqlatigIFCijtnB8/fgSAb17qnC9fPnz48CH94w8fPqBKlSpf7Zc/f34AwPv371GmTBml5CQi0lSc2BIREZFGadSoEZKSknDlyhV8/vwZV69e/eV1AH4mKSkJAL65OJW+vn7662n76ul9PVtIey8vRSYiyjpObImIiEijmJiYoHr16ggLC0NSUhJkMhkaNmyo1HOmrcD+rVKanJycYYV2AwMDpKSkfHM/4NvlmIiIfowTWyIiItI4TZo0wfXr1xEUFIRatWrByMhIqedLuwQ57ZLkL338+DH9MmPg30uOv7w0OU3aNmVeMk1EpKlYbImIiEjj1K9fHxKJBFFRUT99TI8ilCtXDgBw//79DNvfv3+Pd+/epb8OAGXLlsXDhw8hk8ky7Hvv3j0YGhp+teo7ERH9HIstERERaZxcuXJh4MCB6Ny58zcXlVO00qVLo0SJEggJCclQWIOCgiCRSNCgQYP0bQ0bNkR0dDQuXryYvi0mJgbh4eGwtLTkpchERNnAe2yJiIhIIzVv3vyXjxEfH4+AgAAAQGRkJADg5MmTyJMnD4yMjODo6Ji+b69evbBkyRLMmzcPjRs3xtOnT3HixAlYW1ujVKlS6fs1bNgQ/v7+WL9+PZ49ewZjY2MEBgZCJpOha9euv5yZiEgbcWJLRMK4uLhg7969mdp3xIgRWLduXZbP8ebNG7i4uOD06dNZfi8RUVxcHPbs2YM9e/bg+vXrAIBjx45hz549OHbsWIZ969Spg/HjxyMuLg5eXl64ePEiOnbsiP79+2fYT0dHB1OmTEGjRo1w4sQJ7NixAyYmJpg5cyZKlCiRU58aEZFG4cSWiH7J6dOnsX79esyfPx8VKlT4pWPdvXsXN2/ehJOTk9IXeiEizfKtZ2d/y4+ep/0tRYoUwe7duzO9f7169VCvXr2f7pc3b14MGTIkS1mIiOj7WGyJSBhfX1/o6uqmfxwZGYl9+/ahefPmXxXbFStWQCKR5HREIiIiIlIDLLZEJMyXz3X8GS6mQkSKFBcX981nyabR0dGBiYlJDiYiIqJfwWJLRAq1bt06hIeHY+XKldi6dStu3boFAwMDNG/eHD179oSOzv/f2u/i4oLOnTujS5cu2Lt3L/bt2wcAGDlyZPo+a9asQZEiRTBixAhUrVoVw4YNA/DvL6UHDx7EjRs38ObNG+jo6KBSpUro3r17hsdqEBF9y7JlyxAREfHd1wsXLpzly5aJiEgcFlsiUjiZTIZ58+bB3NwcvXv3xq1bt3Ds2DEULVoU9vb233xP/fr18fLlS4SFhcHV1TV9UvK9icnr169x6dIlNGzYEEWKFEF0dDSCg4Ph4eGBZcuWoUCBAkr7/IhI/fXu3RtxcXHffT0rV5QQEZF4LLZEpHDJyclo3LgxnJ2dAQB2dnaYPHkyTp069d1iW7ZsWZQvXx5hYWGoV68eihQp8sNzlClTBitXrswwAW7atCnGjRuHU6dOpZ+biOhbzMzMREcgIiIF4uN+iEgp7OzsMnxcpUoVvH79WmHH19fXTy+1MpkMsbGxyJUrF4oXL46HDx8q7DxEREREpPo4sSUihdPX1//qEmIjIyN8+vRJYeeQyWQICAhAYGAg3rx5A5lMlv6asbGxws5DRERERKqPxZaIFO7Ly4OV5eDBg9izZw9atmyJrl27Im/evJBIJPD29oZcLlf6+YmIiIhIdbDYEpFaunDhAiwsLDBkyJAM2+Pj4/mIDiIiIiItw3tsiUhl5MqVC8C/5fRndHR0vprMnj9/Hu/fv1dKNiIiIiJSXZzYEpHKKF++PADAz88PjRs3hq6uLurUqZNeeL9kaWmJ/fv3Y926dahUqRKePHmCc+fOoWjRojkdm4iIiIgEY7ElIpVRsWJFdO3aFcHBwbh+/TrkcjnWrFnzzWLbsWNHJCYmIiwsDOfPn0f58uUxefJk7Nq1S0ByIiIiIhJJIs/EKisxMTEwNTVFdHQ0710j0lBXr15FnTp1sGDBAj7f8X8ePHiAqVOn4sqVK7C0tBQdh0gr8XvT1/i9iYi0RVZ6KO+xJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2RKRWXFxcsHfv3iy/782bN3BxccHp06cVH4qIiIiIhGKxJaJsOX36NFxcXODi4oI7d+589bpcLsewYcPg4uKCRYsWCUhIRERERNqCxZaIfom+vj7OnTv31faIiAi8e/cO+vr6AlIREWkfmUyGjRs34uXLl6KjEBHlOBZbIvoltWvXRnh4OFJTUzNsDwsLg5mZGfLlyycmGBGRlomPj8fs2bNRtWpVeHt7Qy6Xi45ERJRj9EQHICL11qRJE1y6dAk3b95E7dq1AQApKSkIDw9Hp06dcOLEiQz7JyQkYM+ePQgPD0d0dDQKFy4MGxsbtGnTBhKJJH2/5ORk7Ny5E2fPnkVycjIsLCwwYMCAb2Z4//49du/ejWvXruHTp08oVqwY2rRpg5YtWyrvEyciUjF58+bFzZs3MWbMGPTt2xd+fn7YtGkTSpcuLToaEZHScWJLRL+kcOHCMDc3R1hYWPq2a9euIT4+Ho0bN86wr1wux5IlS+Dv74+aNWvC1dUVJUqUwPbt2+Hj45Nh340bN8Lf3x81atRAjx49oKuri4ULF351/o8fP2LGjBm4desWHBwc0LdvXxQrVgwbNmzA8ePHlfNJExGpqIIFC8LX1xdHjx7FzZs3YWFhgU2bNnF6S0Qaj8WWiH6ZlZUVLl++jKSkJADAuXPnULVqVRQoUCDDfpcvX8bt27fRtWtXDB48GA4ODpg0aRIaNGiAgIAAvHr1CgDw6NEjnD17Fvb29hg1ahQcHBwwfvz4b04d/Pz8IJPJsGjRIjg7O8POzg4TJ05E48aNsW/fvvRMRETapE2bNvjrr7/Sv9/a2tri4cOHomMRESkNiy0R/bJGjRohKSkJV65cwefPn3H16lU0adLkq/2uXbsGHR0dtGrVKsP2Nm3aQC6X4/r16+n7AfhqPycnpwwfy+VyXLx4EZaWlpDL5YiJiUn/p2bNmoiPj8eDBw8U+JkSEamPfPnyYcuWLTh58iTu3buHatWqYc2aNZDJZKKjEREpHO+xJaJfZmJigurVqyMsLAxJSUmQyWRo2LDhV/v9888/yJ8/P3Lnzp1he6lSpdJfT/tfiUSCokWLZtivRIkSGT6OiYnBp0+fEBISgpCQkG9mi4mJyfbnRUSkCezt7XH79m1MmTIFo0aNwp49e7B161ZIpVLR0YiIFIbFlogUokmTJti0aRM+fvyIWrVqwcjISOnnTLtnrGnTpmjWrNk39ylbtqzScxARqTpjY2OsXbsWXbp0wYABA1CzZk3MmTMHY8eOha6uruh4RES/jMWWiBSifv362Lx5M6KiojBmzJhv7lOoUCHcunULnz9/zjC1ff78efrraf8rl8vx+vXrDFPaFy9eZDieiYkJcufODZlMhho1aij4MyIiVfDhwwcA//99gn7ta9GiRQvcvHkTM2fOxKRJk7B3715s27YNFhYWCkxIRJTzWGyJSCFy5cqFgQMH4s2bN6hTp84396lduzZCQkJw4sQJdOzYMX378ePHIZFIUKtWrfT9/Pz8EBAQkOERP/7+/hmOp6Ojg/r16yMsLAxPnjxBmTJlMrweExMDExMTBX2GRJTTXrx4kf49wNPTU3Aa1WNsbJyt9xkZGWH58uXo0qUL+vfvD0tLS7i5uWHSpEnQ19dXcEoiopzBYktECtO8efMfvl6nTh1YWFhg9+7dePv2LcqWLYubN2/i8uXLcHJyQrFixQAA5cqVQ5MmTRAYGIj4+HhIpVLcvn07fdXkL/Xo0QMRERGYMWMGrK2tUapUKcTFxeHhw4e4desWtm3bppTPlYiU6/Xr17CxsUFqaiqCg4ORP39+0ZFUirGxMczNzX/pGI0aNcK1a9fg4eEBNzc37N+/H9u2bUv/IyMRkTphsSWiHKOjo4NJkyZhz549+PPPP3H69GkUKVIEvXr1Qps2bTLsO2TIEJiYmODcuXO4dOkSqlWrhilTpmDYsGEZ9suXLx/mzZuH/fv34+LFiwgMDISxsTFKlSqFnj175uSnR0QK8vbtW9jY2CA6Ohpnzpz55QJH35crVy4sWLAAzs7O6N+/P+rVq4epU6di+vTpMDQ0FB2PiCjTJPJMPLE7JiYGpqamiI6O5mV9RBrq6tWrqFOnDhYsWAAzMzPRcVTCgwcPMHXqVFy5cgWWlpai4xBphffv38Pa2hovX77EmTNnULlyZdGRtEZSUhLmz5+PefPmoVKlSvDy8kK9evVExyIiLZaVHsrn2BIREZFK+PjxI+zt7fH8+XOEhISw1OYwAwMDzJo1C5cvX4aBgQEaNmyIyZMn4/Pnz6KjERH9FIstERERCRcTEwNHR0c8ePAAwcHBqFatmuhIWqtmzZq4cOEC5s6di5UrV6J27doICwsTHYuI6IdYbImIiEiouLg4ODk54c6dOwgKCkLNmjV/uP+1a9dQuXJlLg6nRPr6+pg6dSquX7+O/Pnzo2nTphgzZgw+ffokOhoR0Tex2BIREZEw8fHxaNu2LW7evImTJ09+93FhwL/Pb017PM3du3cRGRmZg0m1U5UqVXDu3DksXboUGzduRI0aNXDq1CnRsYiIvsJiS0REREIkJCSgffv2uHTpEvz9/dGgQYNv7hcbG4uZM2eiQoUK8PHxSd9ua2ubU1GVJjo6Ghs2bEBqaqroKN+lq6uLcePG4ebNmyhVqhSsra0xdOhQxMTEiI5GRJSOxZaIiIhyXGJiIjp16oSwsDAcO3YMVlZW39zvwYMHKF++PObPn4/ExMQMBbBixYo5FVdpXr58iaFDh2Lv3r2io/yUubk5Tp06BU9PT/j6+qJatWo4efKk6FhERABYbImIiCiHJSUloUuXLggNDcWRI0fQokWL7+5rZGSE/Pnzf7VdT08PpUuXVmLKnFG5cmW0atUKc+bMUempbRodHR0MHz4ct2/fRqVKleDo6Ij+/fvjw4cPoqMRkZbTEx2AiFTL8+fPRUdQGfxaEClecnIyunfvjpMnT+Lw4cM/vZy4aNGiuHnzJvr27Ys9e/ZAIpFALpejdOnS0NXVzaHUyuXu7o6GDRti3759cHFxER0nU8qVK4fAwEBs3boV48ePx4kTJ7Bhwwa0a9dOdDQi0lISuVwu/9lOWXkwLhGpp6ioKEilUtExVFJkZCTMzc1FxyBSeykpKejduzf27duHAwcOoG3btpl6X1xcHGrVqgVDQ0N8+PABL1++hKOjIwICApScOOe0atUKT548wa1bt6Cjo14X1D179gyDBw+Gv78/evTogVWrVqFQoUKiYxGRBshKD2WxJaJ0UVFRiI2NFR1DpRgbG7PUEilAamoq+vXrh507d2LPnj3o1KlTpt87bNgweHt74/r16yhSpAjc3d3RtGlTODs7KzFxzgoPD0ejRo2we/dudO3aVXScLJPL5di+fTtGjx4NfX19rF27Fp07dxYdi4jUHIstERERqQyZTIZBgwbBy8sLO3bsQLdu3TL93pMnT8LR0RHr1q3D0KFDlZhSPEdHRzx79gw3b95Uu6ltmpcvX2LYsGE4dOgQnJ2dsXbtWhQtWlR0LCJSU1npoer5XZOIiIjUglwux/Dhw7Ft2zb8/vvvWSq179+/R//+/eHg4IAhQ4YoMaVqcHd3x19//YX9+/eLjpJtxYsXx4EDB7B7926cOXMGVatWxY4dO5CJOQoR0S9hsSUiIiKlkMvlGDNmDDZs2IAtW7agd+/eWXr/8OHDER8fj61bt0IikSgppepo1KgR7O3tMXv2bMhkMtFxsk0ikaBr166IiIiAvb09evXqhXbt2nFBPiJSKhZbIiIiUji5XI6JEydi9erV2LBhA/r375+l9/v5+cHPzw/r1q1DyZIllZRS9bi7u+P27ds4cOCA6Ci/rHDhwti1axcOHjyIy5cvw8LCAtu2beP0loiUgvfYEhERkULJ5XJMnz4dCxYswOrVqzFy5Mgsvf/FixeoVq0a7Ozs4OfnpxXT2i/Z29vj5cuXuHHjhtrea/tf79+/x7hx4+Dt7Q07Ozts3rwZZcuWFR2LiFQc77ElIiIiYWbPno0FCxZg2bJlWS61crkcAwYMQK5cubBu3TqtK7XA/09tDx48KDqKwhQoUAC///47/P398ffff6NatWpYv369Wl9yTUSqhcWWiIiIFGbBggWYNWsW5s+fj3HjxmX5/Zs2bcKJEyewdetWFCxYUAkJVV+TJk1ga2sLDw8PjSt+rVq1wu3bt9GjRw8MGzYMNjY2uH//vuhYRKQBWGyJiIhIIZYtW4Zp06Zh1qxZmDp1apbff+/ePYwbNw6DBw9Gq1atlJBQfbi7u+PWrVs4dOiQ6CgKZ2pqio0bNyI4OBiPHj1C9erVsXLlSqSmpoqORkRqjPfYEhER0S9bs2YNRo0ahWnTpmHu3LlZvoQ4NTUVzZo1w6tXr3Djxg3kzZtXSUnVh62tLd6+fYtr165pzL22/xUXF4dp06ZhzZo1aNSoEbZt24bKlSuLjkVEKoL32BIREVGO2bBhA0aNGoUJEyZkq9QCwNKlS3H+/Hn4+Piw1P6Pu7s7bt68icOHD4uOojR58+bF6tWr8ccff+Cff/5BrVq1sGjRIqSkpIiORkRqhhNbIiIiyrZt27ZhwIABGDVqFFauXJmtUnvz5k3UrVsX48aNw8KFC5WQUn3Z2Njg3bt3uHr1qsZObdPEx8fD3d0dy5cvR+3ateHl5YXq1auLjkVEAnFiS0Qa69KlS3j8+LHoGEQEwNfXFwMHDsTQoUOzXWoTExPRu3dvVK5cGR4eHkpIqd7c3d1x48YNHDlyRHQUpcuTJw+WLFmCP//8E58/f0adOnUwe/ZsJCUliY5GRGqAE1siUivNmzdHhQoVsG3bNtFRiLSan58fevbsiX79+mHTpk3ZniZOnToVy5Ytw6VLl1CzZk0Fp9QM1tbW+PDhA65evao1jz9KTEzEnDlzsHDhQlhYWMDLywuWlpaiYxFRDuPElog0VpkyZXD37l3RMYi02v79+9GrVy/07Nnzl0ptWFgYFi9ejNmzZ7PU/oC7uzuuX7+uFVPbNIaGhpg7dy4uXboEiUSC+vXrY/r06UhISBAdjYhUFIstEakVqVSKyMhI0TGItNaRI0fQrVs3dOnSBV5eXtkutXFxcejTpw8aNmyIiRMnKjilZmnevDlatGgBDw8PZOJCO41Su3ZtXLp0Ce7u7liyZAksLS0RHh4uOhYRqSAWWyJSK1KpFP/88w/ev38vOgqR1gkICECXLl3Qvn17+Pj4QFdXN9vHmjBhAl6+fAlvb+9fOo62cHd3x7Vr13D06FHRUXKcvr4+Zs6ciatXr8LIyAhNmjTBhAkTEB8fLzoaEakQFlsiUitSqRQAEBUVJTgJkXYJDg5Gx44d4ejoiJ07d0JfXz/bxwoICMDGjRuxbNkyVKxYUYEpNVeLFi3QvHlzzJo1S+umtmmqVauG8+fPY8GCBfD09ETNmjXxxx9/iI5FRCqCxZaI1Iq5uTkA8HJkohx0+vRptGvXDtbW1tizZw8MDAyyfax3795hwIABcHR0xODBgxWYUvOlTW2PHTsmOoowenp6mDRpEm7cuIEiRYqgefPmGDlyJOLi4kRHIyLBWGyJSK3kzZsXJUqUYLElyiHnzp1DmzZtYGVlhQMHDsDQ0PCXjjd8+HAkJCRg69atWrPCr6K0aNECzZo10+qpbZpKlSrhjz/+wMqVK7F161ZUr14dwcHBomMRkUAstkSkdriAFFHOCA8Ph5OTE+rVq4dDhw4hV65cv3Q8Pz8/7N69G+vXr0eJEiUUlFJ7SCQSzJo1C1evXsXx48dFxxFOV1cXo0ePxq1bt1CuXDnY2dlh0KBBiI6OFh2NiARgsSUitcNiS6R8ly9fhqOjI2rUqIGjR48iT548v3S858+fY9iwYejWrRtcXFwUlFL7tGjRAk2bNuXU9gsVKlRASEgI1q9fj127dqFatWrw9/cXHYuIchiLLRGpnbRiy1/qiJTj+vXrsLe3R+XKleHv74+8efP+0vHkcjkGDBiAXLlyYe3atQpKqZ3SprZXrlxhefuCjo4OhgwZgr/++gtVq1ZF69at0adPH66gT6RFWGyJSO1IpVLEx8fjxYsXoqMQaZzbt2/Dzs4OZmZmOHHiBExMTH75mBs3bsTJkyexbds2FChQQAEptVvLli1hZWXFqe03lClTBidOnMC2bdtw+PBhWFhY4NChQ6JjEVEOYLElIrWT9sgfXo5MpFh37tyBjY0NSpYsicDAQOTLl++Xj3nv3j2MHz8eQ4YMgaOj46+HpPSp7eXLlxEQECA6jsqRSCTo168fIiIiUK9ePXTs2BHdunXD27dvRUcjIiVisSUitVO+fHno6uqy2BIpUFRUFKytrVGkSBEEBwcrZLKampoKV1dXFC9eHEuWLFFASkpjbW2NJk2acGr7AyVKlMDhw4exY8cOBAUFoWrVqvDz8+PXi0hDsdgSkdoxMDBA+fLlWWyJFOTBgwewtraGqakpgoODUahQIYUcd8mSJbhw4QK8vb1/+T5dyihtanvp0iWcOHFCdByVJZFI0KNHD0RERKBly5bo3r07OnXqhJcvX4qORkQKxmJLRGqJKyMTKcbjx49hbW2N3LlzIzQ0FEWLFlXIcW/cuAE3NzdMmjQJTZo0UcgxKSMbGxs0btyYU9tMKFq0KPbs2YN9+/bhzz//hIWFBXx8fPh1I9IgLLZEpJZYbIl+3bNnz2BtbQ0dHR2EhoaiePHiCjluYmIievfujSpVqmDWrFkKOSZ9LW1qe/HiRZw8eVJ0HLXg7OyMiIgIODk5oU+fPmjdujWePn0qOhYRKQCLLRGpJalUigcPHiA5OVl0FCK19PLlS1hbWyMlJQWhoaEoVaqUwo7t5uaGO3fuwNfXF4aGhgo7Ln3N1tYWjRo14tQ2CwoWLIjt27fjyJEjuHHjBiwsLLB582Z+/YjUHIstEaklqVSKlJQUPHr0SHQUIrXz5s0b2NjYID4+HqGhoShXrpzCjn3u3DksWbIEc+bMQY0aNRR2XPq2tKnthQsXEBgYKDqOWmnbti3++usvdO3aFYMGDYKdnR0ePnwoOhYRZROLLRGpJT7yhyh7/vnnH9ja2uLDhw8IDQ1FhQoVFHbs2NhYuLq6onHjxpgwYYLCjks/Zmdnh4YNG3Jqmw358uXDli1bcPLkSURFRaFatWpYs2YNZDKZ6GhElEUstkSklkqWLIncuXOz2BJlwfv372FnZ4dXr14hNDQ0/Q9EijJhwgS8efMG3t7e0NXVVeix6fvSprbh4eEICgoSHUct2dvb4/bt2+jbty9GjRqF5s2bIyoqSnQsIsoCFlsiUks6OjowNzdnsSXKpOjoaDg4OODp06cICQlBlSpVFHp8f39/bNq0CcuXL1foFJgyx97eHg0aNODU9hcYGxtj7dq1OHXqFF68eIEaNWpg2bJlSE1NFR2NiDKBxZaI1BZXRibKnNjYWDg6OuL+/fsIDg5G9erVFXr8d+/eYcCAAWjVqhV+++03hR6bMidtanv+/HkEBweLjqPWWrRogZs3b2LIkCGYOHEiGjdujIiICNGxiOgnWGyJSG2x2BL93KdPn+Dk5ISIiAgEBgaiVq1aCj2+XC7H0KFDkZSUhK1bt0IikSj0+JR5Dg4OqF+/Pqe2CmBkZIQVK1bg3LlziI6ORu3atTF//nyuxE+kwlhsiUhtSaVSPHv2DJ8+fRIdhUglxcfHo23btrh+/TpOnDiBunXrKvwcfn5+2Lt3L9avX6+w5+BS9qRNbf/880+EhISIjqMRGjdujOvXr2PcuHGYOXMmGjRogOvXr4uORUTfwGJLRGorbeGbe/fuCU5CpHoSEhLQsWNHXLhwAf7+/mjUqJHCz/H8+XMMGzYM3bt3R9euXRV+fMo6R0dH1KtXj1NbBcqVKxcWLFiACxcuIDk5GfXq1YObmxuSkpJERyOiL7DYEpHa4iN/iL4tMTERzs7O+OOPP3Ds2DE0bdpU4eeQy+Xo378/8uTJA09PT4Ufn7InbWobFhaG0NBQ0XE0St26dXHlyhVMmzYNCxYsQJ06dXDp0iXRsYjof1hsiUhtFSxYEAUKFGCxJfpCcnIyXFxcEBISgsOHD6Nly5ZKOc+GDRsQGBiIbdu2oUCBAko5B2VPq1atULduXU5tlcDAwAAeHh64fPky9PX10bBhQ0yZMgUJCQmioxFpPRZbIlJrXECK6P+lpKSgR48e8Pf3x4EDB2Bvb6+U80RFRWHChAkYOnQoHBwclHIOyr60qe25c+dw6tQp0XE0Us2aNXHhwgXMnTsXK1asQK1atfDnn3+KjkWk1VhsiUitSaVSREVFiY5BJFxqaipcXV1x6NAh7N27F05OTko5T0pKClxdXVG8eHEsWbJEKeegX+fk5MSprZLp6+tj6tSpuHbtGvLlywcrKyuMGTOGCxoSCcJiS0RqjRNbIkAmk6F///7Ys2cPdu3ahfbt2yvtXIsXL8bFixfh4+MDIyMjpZ2Hfo1EIoG7uzvOnj2L06dPi46j0apWrYqwsDAsXboUGzduRI0aNfg1JxKAxZaI1JpUKsW7d+/w7t070VGIhJDJZBg8eDC2b98OHx8fdO7cWWnnunbtGtzd3TF58mQ0btxYaechxWjdujXq1KmDWbNmiY6i8XR1dTFu3DjcvHkTJUuWRMuWLTFs2DDExsaKjkakNVhsiUitpa2MzMuRSRvJ5XKMHDkSW7duxbZt29CjRw+lnSshIQGurq6wsLBgUVITaVPbP/74gxPEHGJubo7Tp09jzZo18PHxQbVq1XDy5EnRsYi0AostEam1ihUrAuAjf0j7yOVyjB07FuvWrcOmTZvQp08fpZ7Pzc0NkZGR8PX1hYGBgVLPRYrTpk0bWFpa8o8ROUhHRwcjRozArVu3YG5uDkdHRwwYMAAfP34UHY1Io7HYEpFaMzIyQqlSpVhsSavI5XJMnjwZq1atwrp16zBw4EClnu/s2bNYunQp5s6di+rVqyv1XKRYaVPbM2fOcGqbw8qXL4+goCBs3rwZ+/btg4WFBY4ePSo6FpHGYrElIrXHBaRI27i5uWHJkiVYuXIlhg4dqtRzxcbGok+fPmjSpAnGjRun1HORcrRt2xa1a9eGh4eH6ChaRyKRYODAgbh9+zZq1qyJdu3aoWfPnlwXgkgJWGyJSO2x2JI2mTNnDubOnYslS5Zg9OjRSj/f+PHj8ebNG3h7e0NXV1fp5yPFS5vanj59GmfOnBEdRyuVLl0ax48fh7e3N/z9/VG1alXs27dPdCwijcJiS0RqL+1ZtjKZTHQUIqVauHAh3NzcMHfuXEyYMEHp5zt+/Dg2b96MFStWwMzMTOnnI+Vp164datWqxamtQBKJBK6uroiIiEDjxo3RpUsXdOnSBa9fvxYdjUgjsNgSkdqTSqWIj4/HixcvREchUpoVK1Zg6tSpcHNzw/Tp05V+vn/++QcDBgyAk5OT0u/hJeVLm9qeOnUKf/zxh+g4Wq148eI4cOAA/Pz8cPr0aVhYWGDnzp2Qy+WioxGpNRZbIlJ7aY/84eXIpKnWrl2LcePGYcqUKTmyuq1cLsfQoUORnJyMLVu2QCKRKP2cpHzt27dHzZo1ObVVARKJBC4uLoiIiICtrS169uyJ9u3b4/nz56KjEaktFlsiUnvlypWDnp4eiy1ppE2bNmHEiBEYN24c5s+fnyMlc9euXdi3bx82bNiA4sWLK/18lDPSprahoaE4e/as6DgEoHDhwvDz88OBAwdw6dIlWFhYwMvLi9NbomxgsSUitaevrw8zMzMWW9I4Xl5eGDx4MEaMGIGlS5fmSKl99uwZhg8fjh49eqBLly5KPx/lrPbt26NGjRqc2qqYjh074q+//kKHDh3Qv39/ODo64vHjx6JjEakVFlsi0ghcGZk0zfbt2zFgwAAMHjwYq1evzpFSK5PJ0L9/f+TJkweenp5KPx/lPB0dHbi7uyMkJATnzp0THYe+UKBAAfz+++84fvw4IiIiUK1aNaxfv54LIxJlEostEWkEc3NzFlvSGHv27EGfPn3Qt29frFu3LsfucV2/fj2CgoLg5eWF/Pnz58g5Ked16NAB1atX59RWRTk5OeH27dvo0aMHhg0bBhsbG9y/f190LCKVx2JLRBpBKpXiwYMHSE5OFh2F6JccPHgQPXr0QI8ePbB582bo6OTMj+rIyEhMnDgRw4cPh729fY6ck8RIm9oGBwcjLCxMdBz6BlNTU2zcuBHBwcF49OgRatSogVWrViE1NVV0NCKVxWJLRBpBKpUiNTUVDx8+FB2FKNuOHTsGFxcXODs7w8vLC7q6ujly3pSUFLi6uqJUqVJYtGhRjpyTxOrYsSOqVavGqa2Ks7Gxwa1btzBgwACMGTMGzZo1w507d0THIlJJLLZEpBH4yB9SdydPnoSzszPatGmD7du3Q09PL8fOvWjRIly6dAk+Pj4wMjLKsfOSOGlT26CgIPz555+i49AP5M2bF6tXr8Yff/yBN2/eoFatWli0aBFSUlJERyNSKSy2RKQRSpQogTx58rDYkloKCQlBhw4dYG9vDz8/P+jr6+fYua9du4ZZs2Zh6tSpaNiwYY6dl8Tr1KkTp7ZqpGnTprhx4wZGjhyJadOmoVGjRrh9+7boWEQqg8WWiDSCjo4OF5AitXTmzBm0bdsWLVq0wL59+2BgYJBj505ISEDv3r1RrVo1uLm55dh5STXo6OjAzc0NgYGBOH/+vOg4lAl58uTBkiVL8Oeff+LTp0+wtLTEnDlzuL4EEVhsiUiD8JE/pG7CwsLQunVrNG7cGAcOHIChoWGOnn/mzJmIioqCr69vjhZqUh3Ozs6wsLDg1FbNNGjQANeuXcPEiRPh4eGBevXq4erVq6JjEQnFYktEGoPFltTJxYsX0apVK9StWxdHjhxB7ty5c/T8f/zxB5YtW4Z58+ahWrVqOXpuUh1pU9uTJ08iPDxcdBzKAkNDQ8ybNw8XL16EXC5H/fr1MWPGDCQmJoqORiQEiy0RaQypVIrnz58jLi5OdBSiH7p69Srs7e1RvXp1HDt2DHny5MnR88fGxqJPnz6wsrLC2LFjc/TcpHo6d+6MqlWrcmqrpiwtLXHp0iW4u7tj8eLFsLS0xIULF0THIspxLLZEpDHSVka+d++e4CRE33fjxg3Y2dmhUqVK8Pf3R968eXM8w7hx4/DPP//g999/z7FHCpHqSpvanjhxgoVITRkYGGDmzJm4cuUK8uTJg8aNG2PChAn4/Pmz6GhEOYbFlog0Bh/5Q6rur7/+gq2tLcqVK4cTJ07A1NQ0xzMcO3YMW7ZswYoVK2BmZpbj5yfVxKmtZqhevTrOnz+PBQsWwNPTEzVr1sTZs2dFxyLKESy2RKQxChQogIIFC7LYkkq6e/cubGxsUKJECQQGBiJ//vw5nuHt27cYOHAgWrdujQEDBuT4+Ul16erqYubMmQgICMDFixdFx6FfoKenh0mTJuH69esoVKgQmjdvjlGjRvE2HdJ4LLZEpFG4gBSponv37sHa2hoFCxZEcHAwChYsmOMZ5HI5hgwZgpSUFGzZsgUSiSTHM5Bq69KlC6pUqcKprYaoXLkyzp49i+XLl2PLli2oXr06QkJCRMciUhoWWyLSKCy2pGoePnwIa2trGBsbIyQkBIULFxaSY8eOHThw4AA2btyIYsWKCclAqi1tauvv78+prYbQ1dXFmDFjcOvWLZQtWxa2trYYPHgwoqOjRUcjUjgWWyLSKFKpFHfv3oVcLhcdhQhPnjyBtbU1DA0NERoaKqxQPn36FCNGjECvXr3g7OwsJAOph65du6Jy5cqYPXu26CikQBUqVEBoaCjWrVuHnTt3olq1aggICBAdi0ihWGyJSKNIpVJ8/PgR7969Ex2FtNzz589hbW0NAAgNDUWJEiWE5JDJZOjXrx/y5s2LNWvWCMlA6iNtanv8+HFcunRJdBxSIB0dHQwdOhS3b99G1apV4eTkhL59++L9+/eioxEpBIstEWkUroxMquDVq1ewtrZGUlISQkNDUbp0aWFZ1q1bh5CQEHh5eSFfvnzCcpD6cHFxQaVKlTi11VBly5bFiRMnsHXrVhw6dAgWFhY4dOiQ6FhEv4zFlog0SsWKFQGw2JI4b9++hY2NDeLi4hAaGory5csLy3L37l1MmjQJI0aMgJ2dnbAcpF7SprbHjh3D5cuXRcchJZBIJOjfvz/++usv1K1bFx07dkT37t3x9u1b0dGIso3Flog0Sp48eVC6dGkWWxLi3bt3sLW1xbt37xAaGpr+hxYRUlJS4OrqitKlS2PRokXCcpB66tatG6RSKae2Gq5kyZI4cuQItm/fjsDAQFStWhW7d+/mOhWkllhsiUjjcGVkEuHDhw+ws7PDy5cvERoaikqVKgnNs3DhQly+fBk+Pj7IkyeP0CykftKmtkePHsWVK1dExyElkkgk6NmzJyIiItC8eXN069YNzs7OePXqlehoRFnCYktEGofFlnJadHQ0HBwc8PjxYwQHB6Nq1apC81y9ehUeHh6YNm0aGjRoIDQLqS9ObbVL0aJFsW/fPuzduxfnzp1D1apV4ePjw+ktqQ0WWyLSOFKpFFFRUZDJZKKjkBaIjY2Fk5MToqKiEBQUhBo1agjNk5CQgN69e6N69eqYOXOm0Cyk3vT09DBjxgwcOXIEV69eFR2Hckjnzp0REREBJycn9OnTB23atMGzZ89ExyL6KRZbItI4UqkUCQkJ/EFMSvfp0ye0adMGt27dwsmTJ2FpaSk6EmbMmIH79+/D19cXBgYGouOQmuvevTvMzc05tdUyhQoVwvbt23H48GFcu3YNFhYW2LJlC6e3pNJYbIlI4/CRP5QTPn/+jHbt2uHKlSs4ceIE6tevLzoSzpw5g+XLl2PevHmwsLAQHYc0QNrUNq3gkHZp164dIiIi4OzsjN9++w12dnZ49OiR6FhE38RiS0Qap1y5ctDT02OxJaVJSEhAx44dcf78efj7+6Nx48aiIyEmJgZ9+vRB06ZNMWbMGNFxSIP06NEDFStW5NRWS+XLlw/btm3DiRMnEBkZiWrVqmHt2rW83YdUDostEWkcPT09VKhQgcWWlCIpKQldunTBmTNncPToUTRr1kx0JADA2LFj8e7dO3h7e0NXV1d0HNIgaVPbQ4cO4fr166LjkCAODg64ffs2XF1dMWLECLRo0QJRUVGiYxGlY7ElIo3ElZFJGZKTk9GtWzcEBgbi0KFDsLGxER0JAHDkyBFs27YNq1atQrly5UTHIQ3Us2dPVKhQgVNbLWdiYoJ169YhNDQUz58/R40aNbBs2TKkpqaKjkbEYktEmonFlhQtJSUFvXr1wrFjx7B//344ODiIjgQAePv2LX777Te0bdsW/fr1Ex2HNFTa1PbgwYO4ceOG6DgkWMuWLXHz5k0MGTIEEydORJMmTRARESE6Fmk5Flsi0khSqRQPHz5EUlKS6CikAVJTU9G3b18cOHAAe/bsQZs2bURHAgDI5XIMHjwYMpkMmzdvhkQiER2JNFivXr04taV0RkZGWLFiBc6ePYsPHz6gdu3aWLBgAVJSUkRHIy3FYktEGkkqlUImk+HBgweio5Cak8lkGDhwIHbt2oWdO3eiQ4cOoiOl2759Ow4ePIgNGzagaNGiouOQhtPT08P06dNx4MAB3Lx5U3QcUhFNmjTB9evXMWbMGMyYMQMNGjTgVJ+EYLElIo3ER/6QIsjlcgwdOhTe3t7w8fFBly5dREdK9/TpU4wYMQK9e/eGs7Oz6DikJXr16gUzMzNObSmD3LlzY9GiRQgPD0diYiLq1q2LWbNm8aopylEstkSkkYoXLw4jIyMWW8o2uVyOUaNGYdOmTdi2bRt69uwpOlI6mUyGfv36wcTEBKtXrxYdh7SIvr4+pk+fjv3793NqS1+pV68erly5gmnTpmHevHmoW7curly5IjoWaQkWWyLSSBKJhAtIUbbJ5XKMHz8enp6e2LhxI/r27Ss6UgZr165FSEgIvLy8kC9fPtFxSMv07t0b5cuXx5w5c0RHIRVkaGgIDw8PXLp0CXp6emjQoAGmTp2KhIQE0dFIw7HYEpHGYrGl7JDL5Zg6dSpWrFgBT09PDBo0SHSkDO7cuYNJkyZh5MiRsLW1FR2HtFDa1Hbfvn24deuW6DikomrVqoULFy7Aw8MDy5cvR61atfDnn3+KjkUajMWWiDQWiy1lx6xZs7Bo0SIsX74cw4cPFx0ng5SUFLi6uqJMmTJYuHCh6DikxVxdXVGuXDnea0s/lPZHkKtXr8LU1BRWVlYYN24c4uPjRUcjDcRiS0QaSyqV4uXLl4iNjRUdhdTE3LlzMXv2bCxatAhjx44VHecrCxYswNWrV+Hr64s8efKIjkNa7Mup7e3bt0XHIRVnYWGBP//8E4sXL8b69etRo0YNnD59WnQs0jAstkSksdJWRo6KihKchNTB4sWLMXPmTMyePRuTJk0SHecrV65cwezZszFt2jTUr19fdBwiTm0pS3R1dTFhwgTcuHEDxYsXR8uWLTF8+HD+8ZkUhsWWiDSWubk5AD7yh35u5cqVmDx5MmbMmIGZM2eKjvOVz58/o3fv3qhRo4ZK5iPtZGBggGnTpnFqS1kilUpx5swZrF69Gr///juqVauGwMBA0bFIA7DYEpHGyp8/PwoXLsxiSz+0bt06jB07FpMmTVLZydP06dPx4MED+Pr6Ql9fX3QconR9+vRBmTJluEIyZYmOjg5GjhyJW7duoWLFinBwcMDAgQPx8eNH0dFIjUnkcrn8ZzvFxMTA1NQU0dHRMDExyYlcREQKYWVlhXLlymH79u2io5AK2rJlC3777TeMGTMGy5cvh0QiER3pK6dOnYK1tTWWL1+ukvf9Em3atAlDhgzBrVu3YGFhIToOqRm5XI7NmzdjwoQJMDExwYYNG9CmTZtfPm5UVBQvc/4PY2Pj9KvZ1EVWeiiLLRFptP79++Ovv/7ChQsXREchFePt7Y1+/fph6NCh8PT0VMlSGxMTg+rVq6N8+fIIDQ2Fjg4vtCLVk5SUBHNzczRq1Ah+fn6i45Caevr0KQYNGoQTJ06gV69eWLlyJQoWLJj++uPHj1GwYEHkzZv3p8eKiopKX2eDMoqMjFSrcpuVHqqXQ5mIiISQSqU4ePAg5HK5ShYXEmPnzp3o168fBg4ciDVr1qjsvxtjxozBhw8fcObMGZZaUllp99oOHToUbm5uqFq1quhIpIZKly4Nf39/+Pj4YMyYMQgKCsK6devQqVMnPHv2DNWqVUODBg0QFBT00+/ZaZPaESNGoGTJkjkRX+U9f/4cnp6eGj3FZrElIo0mlUrx8eNH/PPPPyhcuLDoOKQC9u7dC1dXV/Tp0wcbNmxQ2cJ4+PBheHl5Ydu2bShXrpzoOEQ/1K9fP8ybNw9z5szBrl27RMchNSWRSNCnTx/Y29tj6NChcHZ2RufOnfHu3Tt8+vQJISEhOHbsGNq2bZup45UsWRJmZmZKTk2qQjV/mhMRKUjapUhcQIoA4NChQ+jRowdcXFywZcsWlS21b968wW+//YZ27dqhb9++ouMQ/VTa1Hb37t34+++/RcchNVe8eHEcPHgQu3btwokTJ3Dq1CnI5fL0RacSExNFRyQVpJo/0YmIFKRChQqQSCQstoTjx4+ja9eu6NChA7y9vaGrqys60jfJ5XIMGTIEcrkcmzZtUtnLpIn+q1+/fihVqhRXSCaFkEgkaNGiRYZtMpkMT548wapVq8SEIpXGYktEGi137twoU6YMi62WCwwMhLOzM5ycnLBz507o6anunTi+vr44ePAgNm3ahKJFi4qOQ5RphoaGmDp1Kvz8/HDnzh3RcUgDjB07FnFxcRm2yeVyzJw5Ey9fvhSUilQViy0RaTypVMpiq8VCQ0PRvn172NraYvfu3Sr9HNgnT55g5MiRcHV1RceOHUXHIcqy/v37o2TJkpzakkJUqlQJVapU+Wol5KSkJHTv3l1QKlJVLLZEpPFYbLXX2bNn0bZtWzRr1gz79u2DoaGh6EjfJZPJ0K9fP5iamvIyO1JbnNqSIs2aNQsRERGIjY3Fx48fcevWLRw7dgxjx47FxIkTRccjFcNiS0QaTyqVIioqCjKZTHQUykHnz5+Hk5MTGjZsiEOHDiFXrlyiI/2Qp6cnQkND4eXlhXz58omOQ5RtAwYMQPHixTF37lzRUUiDmJqaolq1amjdujWWL1+O1q1bi45EKobFlog0nlQqRWJiIp4+fSo6CuWQS5cuwdHREbVr18aRI0eQO3du0ZF+6O+//8bkyZMxatQo2NjYiI5D9EsMDQ0xbdo07Nq1C3fv3hUdh4i0BIstEWk8PvJHu1y7dg329vawsLDA8ePHYWRkJDrSDyUnJ8PV1RXlypXDwoULRcchUghObYkop7HYEpHGK1u2LPT19VlstcCtW7dga2uLihUrIiAgAMbGxqIj/dT8+fNx7do1+Pj4qPxkmSiz0u613blzJ7/3ElGOYLElIo2nq6uLihUr8pcrDRcREQEbGxuUKVMGgYGBMDU1FR3ppy5fvow5c+ZgxowZqFevnug4RAo1YMAAFCtWjFNbIsoRLLZEpBW4MrJmi4yMhI2NDYoVK4agoCDkz59fdKSf+vz5M3r37o1atWph+vTpouMQKVyuXLkwdepU7NixA1FRUaLjEJGGY7ElIq1gbm7OYquh7t+/D2tra+TPnx/BwcEoVKiQ6EiZMm3aNDx8+BC+vr4q/Wxdol8xcOBATm2JKEew2BKRVpBKpXj06BESExNFRyEFevToEaytrWFkZISQkBAUKVJEdKRMOXXqFFauXImFCxeiSpUqouMQKU2uXLkwZcoU7NixA/fu3RMdh4g0GIstEWkFqVQKmUyGBw8eiI5CCvL06VNYW1tDX18foaGhKF68uOhImRIdHY2+ffuiRYsWGDVqlOg4REr322+/oUiRIpzaEpFSsdgSkVbgI380y4sXL2BtbQ25XI7Q0FCULFlSdKRMGzNmDD58+IDff/8dOjr8MUyaL21qu337dk5tiUhp+BOViLRCsWLFkDdvXhZbDfD69WvY2NggISEBoaGhKFOmjOhImXbo0CH8/vvvWL16NcqWLSs6DlGO+e2331C4cGHMmzdPdBQi0lAstkSkFSQSCVdG1gBv376FjY0NoqOjERoaivLly4uOlGlv3rzBoEGD0L59e/Tp00d0HKIclTt3bkyZMgW+vr64f/++6DhEpIFYbIlIa7DYqrf379/Dzs4Ob9++RWhoKMzNzUVHyjS5XI5BgwYBADZt2gSJRCI4EVHOGzRoEKe2RKQ0LLZEpDVYbNXXx48fYW9vj+fPnyMkJASVK1cWHSlLvL29cfjwYWzatEltVm4mUrTcuXNj8uTJ8PHx4UJ+RKRwLLZEpDWkUilevXqFmJgY0VEoC2JiYuDo6IgHDx4gODgY1apVEx0pSx4/foxRo0ahb9++6NChg+g4REINHjwYhQoV4tSWiBSOxZaItEbayshRUVGCk1BmxcXFwcnJCXfu3EFQUBBq1qwpOlKWyGQy9O3bF/nz58fKlStFxyESjlNbIlIWFlsi0hpp92TycmT1EB8fjzZt2uDmzZs4efIk6tSpIzpSlq1evRqnT5/G77//DlNTU9FxiFTC4MGDUbBgQcyfP190FCLSICy2RKQ18uXLhyJFirDYqoGEhAS0b98ely9fRkBAABo0aCA6UpZFRERgypQpGDNmDFq2bCk6DpHKyJMnDyZNmgRvb288fPhQdBwi0hAstkSkVbiAlOpLTExEp06dEBYWhmPHjqFJkyaiI2VZcnIyXF1dUb58eU6liL5hyJAhKFCgAP/7ICKF0RMdgIgoJ0mlUty8eVN0DPqOpKQkdOnSBaGhoTh27BhatGghOlK2zJs3D9evX0d4eDhy584tOg6Rykmb2k6ZMgXTp09HuXLlREciLXT69GmsX78eAODh4fHVivtyuRzDhw/Hu3fvYGlpicmTJ2fquC9evEBQUBDu3buHhw8fIjk5GWvWrPnuqviXL1/G3r178fz5c5iYmKBFixZwdnaGrq5u+j4fPnxAQEAAoqKi8ODBAyQkJMDNzQ0WFhbZ/Ow1Dye2RKRV0ia2crlcdBT6j+TkZHTv3h0nT57EoUOHYGtrKzpStly6dAlz587FzJkzUbduXdFxiFTWkCFDkD9/fk5tSTh9fX2cO3fuq+0RERF49+4d9PX1s3S8yMhIBAQE4PPnzyhZsuQP97127RqWLl0KIyMj9OvXD/Xq1cOBAwfg5eWVYb8XL17g8OHD+PDhA8qUKZOlPNqCE1si0ipSqRQxMTF48+YNihYtKjoO/U9KSgpcXV1x5MgRHDhwAI6OjqIjZcvnz5/Ru3dv1K5dG9OmTRMdh0ilGRkZYdKkSZg6dSqmT5+OsmXLio5EWqp27doIDw9Hv379MkxJw8LCYGZmhtjY2Cwdr27duvDy8kLu3Llx9OhRPHr06Lv7bt++HWXKlMH06dPTz507d24cOnQIrVq1Si/GZmZm2Lp1K/LmzYvw8HDeVvUNnNgSkVZJe+QPfyCojtTUVPTv3x979+7F7t270bZtW9GRsm3q1Kl4/PgxfHx8svwXfiJtNHToUE5tSbgmTZogLi4uw61KKSkpCA8Pz9Y6D3nz5s3UbSjPnj3Ds2fPYGNjk6FQ29vbQy6XIzw8PH1b7ty5kTdv3ixn0SYstkSkVSpUqACJRMJiqyJkMhkGDRqEHTt2YMeOHejUqZPoSNkWGhqKVatWYeHChahSpYroOERqwcjICBMnToSXlxceP34sOg5pqcKFC8Pc3BxhYWHp265du4b4+Hg0btxYaedNWxW8QoUKGbYXKFAABQsW/OGkl77GYktEWiVXrlwoW7Ysi60KSFuUw8vLC97e3nBxcREdKduio6PRt29ftGzZEiNHjhQdh0itDBs2DKampliwYIHoKKTFrKyscPnyZSQlJQEAzp07h6pVq6JAgQJKO+fHjx8B/Ps4wv/Kly8fPnz4oLRzayIWWyLSOnzkj3hyuRxjxozBhg0bsGXLFvTq1Ut0pF8yevRoREdH4/fff4eODn+0EmVF2tR227ZtePLkieg4pKUaNWqEpKQkXLlyBZ8/f8bVq1eV/ri5tBL9rVtX9PX101+nzOFPXyLSOiy2YsnlckycOBGrV6/Ghg0b0L9/f9GRfsnBgwfh7e2NNWvWcKVKomzi1JZEMzExQfXq1REWFoaLFy9CJpOhYcOGSj2ngYEBgH+fCvBfycnJ6a9T5rDYEpHWkUqluHfvHlJTU0VH0TpyuRzTp0/HsmXLsHr1agwePFh0pF/y+vVrDBo0CB06dEDv3r1FxyFSW3nz5sWECROwdetWPH36VHQc0lJNmjTB9evXERQUhFq1asHIyEip50u7BDntkuQvffz4Efnz51fq+TUNiy0RaR2pVIqkpCRe8ibA7NmzsWDBAixbtkzt70WVy+X47bffoKOjg02bNkEikYiORKTWhg8fDhMTE05tSZj69etDIpEgKioKVlZWSj9fuXLlAAD379/PsP39+/d49+5d+uuUOSy2RKR1+MgfMebPn49Zs2ZhwYIFGDdunOg4v+z333/H0aNHsWnTJhQuXFh0HCK1lza13bJlC6e2JESuXLkwcOBAdO7cGXXq1FH6+UqXLo0SJUogJCQEMpksfXtQUBAkEgkaNGig9AyaRE90ACKinFamTBkYGBggMjISDg4OouNohaVLl2L69Onw8PDAlClTRMf5ZY8ePcLo0aPRr18/tG/fXnQcIo0xfPhwLFmyBAsXLsTatWtFxyEt1Lx5818+Rnx8PAICAgD8/x/RT548iTx58sDIyAiOjo7p+/bq1QtLlizBvHnz0LhxYzx9+hQnTpyAtbU1SpUqleG4+/fvB/Dv828B4OzZs7hz5w4AwNnZ+ZdzqzsWWyLSOrq6uqhYsSIntjlk9erVmDhxIqZNm4aZM2eKjvPLZDIZ+vbtiwIFCmDlypWi4xBpFGNjY0yYMAGzZs3C1KlTv/rFnkgdxMXFYc+ePRm2HTt2DMC/z8z9stjWqVMH48ePx759++Dl5QUTExN07Njxm0X1v8c8depU+v9nsWWxJSItJZVKcffuXdExNN6GDRswevRoTJgwAXPnztWI+1BXrVqFM2fO4NSpUzAxMREdh0jjjBgxAkuXLsXChQvh6ekpOg5psBYtWqBFixY/3S+r/x4WKVIEu3fvzvT+9erVQ7169X66X1aOqY14jy0RaSWpVIqoqCjRMTTatm3bMHToUIwaNQqLFy/WiFIbERGBqVOnYuzYsZn6ZYiIss7Y2Bjjx4/H5s2b0y+5JCL6GRZbItJKUqkUjx8/RkJCgugoGsnX1xcDBw7E0KFDsXLlSo0otcnJyejduzfMzMwwb9480XGINNqIESNgZGSERYsWiY5ClC4uLg4fP3787j8xMTGiI2o1XopMRFpJKpVCLpfj/v37sLCwEB1Ho/j5+aFv377o378/PD09NaLUAsDcuXNx8+ZNhIeHI3fu3KLjEGk0ExMTjB8/HrNnz8aUKVNQsmRJ0ZGIsGzZMkRERHz39cKFC/PyeYFYbIlIK335yB8WW8XZv38/evXqhV69emHTpk3Q0dGMC4MuXryIefPmwc3NLUceAUFEwMiRI7Fs2TIsWrQIq1evFh2HCL1790ZcXNx3XzcwMMjBNPRfLLZEpJWKFCkCExMTroysQEeOHEG3bt3QtWtXbNu2TWNKbXx8PHr37g1LS0tMnTpVdBwirWFiYoJx48Zh7ty5mDJlCkqUKCE6Emk5MzMz0RHoBzTjtw4ioiySSCSQSqUstgoSEBCAzp07o3379vDx8YGurq7oSAozZcoUPHnyBD4+PtDX1xcdh0irjBw5Erlz5+a9tkT0Uyy2RKS1WGwVIzg4GB07dkSrVq2wc+dO6OlpzsVAwcHBWLNmDRYvXozKlSuLjkOkdUxNTTFu3Dhs3LgRL168EB2HiFQYiy0RaS0W2193+vRptGvXDtbW1tizZ49G3V/08eNH9OvXDzY2Nhg+fLjoOERaa9SoUcidOzcWL14sOgoRqTAWWyLSWlKpFG/evMHHjx9FR1FL586dQ5s2bWBlZYUDBw7A0NBQdCSFGjVqFGJjY+Hl5aUx9wsTqSNTU1OMHTsWGzduxMuXL0XHISIVxZ/URKS10lZGjoqKEpxE/YSHh8PJyQn16tXDoUOHkCtXLtGRFGr//v3w9fXFmjVrULp0adFxiLTeqFGjYGhoyKktEX0Xiy0RaS1zc3MA4OXIWXT58mU4OjqiZs2aOHr0KPLkySM6kkK9evUKgwcPRqdOndCrVy/RcYgIQL58+TB27Fhs2LCBU1si+iYWWyLSWiYmJihWrBiLbRZcv34d9vb2qFKlCvz9/ZE3b17RkRRKLpdj0KBB0NXVxYYNGyCRSERHIqL/GT16NAwNDbFkyRLRUYhIBbHYEpFW4wJSmXf79m3Y2trCzMwMAQEBMDY2Fh1J4by8vHD06FFs3rwZhQsXFh2HiL6QL18+jBkzBuvXr8erV69ExyEiFcNiS0RajcU2c+7cuQMbGxuUKlUKgYGByJcvn+hICvfw4UOMHj0a/fv3R7t27UTHIaJvGDNmDKe2RPRNLLZEpNWkUimioqIgl8tFR1FZUVFRsLa2RpEiRRAcHIwCBQqIjqRwMpkMffv2RcGCBbFixQrRcYjoO/Lly4fRo0dj/fr1eP36teg4RKRCWGyJSKtJpVLExsbyF6TvePDgAaytrWFqaorg4GAUKlRIdCSlWLlyJc6ePQtvb2+YmJiIjkNEPzBmzBjo6+tzaktEGbDYEpFWS3vkDy9H/trjx49hbW2N3LlzIzQ0FEWLFhUdSSn++usvTJs2DWPHjkXz5s1FxyGin8ifPz9Gjx6NdevW8Y+SRJSOxZaItJqZmRl0dHRYbP/j2bNnsLa2hq6uLkJDQ1G8eHHRkZQiKSkJvXv3RoUKFTBv3jzRcYgok9KmtkuXLhUdhYhUBIstEWk1Q0NDlCtXjsX2Cy9fvoS1tTVSUlIQGhqKUqVKiY6kNHPmzMGtW7fg6+uLXLlyiY5DRJlUoEABjBo1CmvXrsWbN29ExyEiFcBiS0Rajysj/783b97AxsYG8fHxOHXqFMqWLSs6ktKEh4dj/vz5cHd3h6Wlpeg4RJRFY8eOhZ6eHqe2RASAxZaIiMX2f/755x/Y2triw4cPCA0NhZmZmehIShMfHw9XV1fUrVsXU6ZMER2HiLKBU1si+hKLLRFpPalUinv37iE1NVV0FGHev38POzs7vHr1CqGhoemLammqyZMn49mzZ/Dx8YGenp7oOESUTWPHjoWuri6WLVsmOgoRCcZiS0RaTyqVIjk5GY8fPxYdRYjo6Gg4ODjg6dOnCAkJQZUqVURHUqqgoCB4enpi8eLFqFSpkug4RPQLChYsiJEjR8LT0xNv374VHYeIBGKxJSKtp82P/ImNjYWjoyPu37+P4OBgVK9eXXQkpfrw4QP69esHW1tbDBs2THQcIlKAcePGQUdHh1NbIi3HYktEWq906dIwNDTUumL76dMnODk5ISIiAoGBgahVq5boSEo3atQoxMXFYdu2bdDR4Y9AIk3w5dT2n3/+ER2HiAThT3Ui0no6OjowNzfXqmIbHx+Ptm3b4vr16zh58iTq1q0rOpLS7du3D9u3b4enpydKly4tOg4RKdC4ceMgkUg4tSXSYiy2RETQrpWRExIS0KFDB1y4cAEBAQFo2LCh6EhK9+rVKwwZMgTOzs7o2bOn6DhEpGCFChXCiBEjsGbNGk5tibQUl4IkIsK/xXbXrl2iYyhdYmIinJ2dcfbsWfj7+8PKykp0JKWTy+UYOHAg9PT0sH79ekgkEtGRiEgJxo8fjzVr1mD58uWYP3++6DikAp4/fy46gsrQhq8Fiy0REf4ttk+ePMHnz5+RO3du0XGUIjk5GS4uLggJCcGRI0fQsmVL0ZFyxNatW3H8+HEcOXIEhQsXFh2HiJTky6nt+PHjUbBgQdGRSBBjY2MAgKenp+Akqifta6OJJHK5XP6znWJiYmBqaoro6GiYmJjkRC4iohwVFhYGKysr3Lp1C9WqVRMdR+FSUlLQvXt3HD58GIcOHYKTk5PoSDniwYMHqFmzJlxcXLBlyxbRcYhIyd6+fYvy5ctj9OjRmDdvnug4JFBUVBRiY2NFx1ApxsbGMDc3Fx0jS7LSQzmxJSIC0r/RR0ZGalyxTU1NhaurKw4dOoR9+/ZpTalNTU1F3759UahQIaxYsUJ0HCLKAYULF8bw4cOxevVqjBs3jlNbLaZuBY5+HRePIiLCv78MmZqaatwCUjKZDP3798eePXvg5+eH9u3bi46UY1asWIFz587B29tboy+9IqKMJkyYAJlMxj9oEWkZFlsiIgASiUTjVkaWyWQYPHgwtm/fDl9fXzg7O4uOlGNu376N6dOnY/z48WjWrJnoOESUg76c2r5//150HCLKISy2RET/o0nFVi6XY8SIEdi6dSu8vLzQvXt30ZFyTFJSEnr37g1zc3PMmTNHdBwiEmDChAlITU3l1JZIi7DYEhH9j6YUW7lcjrFjx2L9+vXYtGkTXF1dRUfKUbNnz8bt27fh6+uLXLlyiY5DRAIUKVIEw4YNw6pVqzi1JdISLLZERP8jlUrx9u1bfPjwQXSUbJPL5Zg8eTJWrVqFdevWYeDAgaIj5ajw8HAsWLAAs2bNQu3atUXHISKBJk6ciNTUVKxcuVJ0FCLKASy2RET/I5VKAfz7iAB15ebmhiVLlmDlypUYOnSo6Dg56tOnT3B1dUW9evUwefJk0XGISLAiRYpg6NChnNoSaQkWWyKi//nykT/qaM6cOZg7dy6WLFmC0aNHi46T4yZPnoxnz57Bx8cHenp8mh0R/Tu1TU5O5tSWSAuw2BIR/Y+xsTGKFy+ulsV24cKFcHNzw7x58zBhwgTRcXJcYGAg1q5diyVLlqRP3omIihYtmj61VefbTIjo51hsiYi+oI4LSC1fvhxTp06Fu7s7pk2bJjpOjvvw4QP69esHOzs7rbv8moh+jlNbIu3AYktE9AV1K7aenp4YP348pkyZAnd3d9FxhBgxYgQ+ffqEbdu2QUeHP9aIKKNixYphyJAhWLVqFT5+/Cg6DhEpCX8DICL6QlqxlcvloqP81KZNmzBy5EiMGzcO8+fPh0QiER0px+3Zswc7d+7E2rVrUapUKdFxiEhFTZo0CYmJiZzaEmkwFlsioi9IpVJ8+vQJL1++FB3lh7y8vDB48GCMGDECS5cu1cpS+/LlSwwdOhSdO3dGjx49RMchIhWWNrVduXIlp7ZEGorFlojoC2kLD6ny5cjbt2/HgAEDMHjwYKxevVorS61cLsfAgQNhYGCA9evXa+XXgIiyJm1qu2rVKtFRiEgJWGyJiL5gZmYGHR0dlS22e/bsQZ8+fdC3b1+sW7dOawvdli1b4O/vjy1btqBQoUKi4xCRGihevDgGDx7MqS2RhmKxJSL6goGBAcqXL6+SxfbgwYPo0aMHevTogc2bN2vtQkkPHjzA2LFj8dtvv6F169ai4xCRGpk8eTISEhKwevVq0VGISMG087ciIqIfUMWVkY8ePQoXFxd07twZXl5e0NXVFR1JiNTUVPTp0wdFihTBsmXLRMchIjWTNrVdsWIFoqOjRcchIgVisSUi+g9VK7YnTpxA586d0aZNG/j6+kJPT090JGGWL1+OsLAweHt7w9jYWHQcIlJDkyZNwufPnzm1JdIwLLZERP8hlUpx//59pKSkiI6CkJAQdOzYEfb29vDz84O+vr7oSMLcunULM2bMwIQJE9C0aVPRcYhITZUoUYJTWyINxGJLRPQfUqkUKSkpePTokdAcZ86cQdu2bdGiRQvs27cPBgYGQvOIlJSUhN69e0MqlWL27Nmi4xCRmps8eTLi4+OxZs0a0VGISEFYbImI/kMVHvkTFhaG1q1bo3Hjxjhw4AAMDQ2FZVEFs2bNQkREBHx9fZErVy7RcYhIzZUoUQKDBg3C8uXLERMTIzoOESkAiy0R0X+UKlUKuXLlElZsL168iFatWqFu3bo4cuQIcufOLSSHqvjzzz+xaNEizJo1C7Vq1RIdh4g0xOTJk/Hp0ydObYk0BIstEdF/6OjowNzcXEixvXr1Kuzt7VGjRg0cO3YMefLkyfEMqiQuLg6urq6oX78+Jk2aJDoOEWmQkiVLcmpLpEFYbImIvkHEysg3btyAnZ0dKleuDH9/f+TNmzdHz6+KJk2ahJcvX8LHx0erV4MmIuWYPHky4uLi4OnpKToKEf0iFlsiom/I6WL7119/wdbWFuXKlcOJEydgYmKSY+dWVSdPnsT69euxZMkSmJubi45DRBqoVKlS+O2337Bs2TLExsaKjkNEv4DFlojoG6RSKZ4+fYr4+Hiln+vu3buwsbFBiRIlEBgYiHz58in9nKru/fv36N+/PxwcHDB06FDRcYhIg02ZMoVTWyINwGJLRPQNaSsj37t3T6nnuXfvHqytrVGwYEEEBwejYMGCSj2fuhgxYgTi4+OxdetWSCQS0XGISIOVKlUKAwcO5NSWSM2x2BIRfUNOPPLn4cOHsLa2hrGxMUJCQlC4cGGlnUud7N69G7t27cK6detQsmRJ0XGISAtMmTIFMTExWLt2regoRJRNLLZERN9QsGBB5M+fX2nF9smTJ7C2toahoSFCQ0NRrFgxpZxH3bx48QLDhg1D165d0a1bN9FxiEhLlC5dGgMHDsTSpUsRFxcnOg4RZQOLLRHRN0gkEqUtIPX8+XNYW1tDIpEgNDQUJUqUUPg51JFcLsfAgQNhYGCAdevW8RJkIspRnNoSqTcWWyKi71BGsX316hWsra2RlJSE0NBQlC5dWqHHV2ebN29GQEAAtm7dynuNiSjHlSlTBgMGDODUlkhNsdgSEX2Hoovt27dvYWNjg7i4OJw6dQrlypVT2LHV3f379zFu3DgMGjQITk5OouMQkZaaOnUqoqOjsW7dOtFRiCiLWGyJiL5DKpXi3bt3ePfu3S8f6927d7C1tcW7d+8QGhqKChUqKCChZkhNTYWrqyuKFi2KZcuWiY5DRFqsTJky6N+/P5YsWYJPnz6JjkNEWcBiS0T0HWkrI0dFRf3ScT58+AA7Ozu8fPkSoaGhqFSpkiLiaYylS5fi/Pnz8Pb2Rt68eUXHISItx6ktkXpisSUi+o6KFSsC+LVH/kRHR8PBwQGPHz9GcHAwqlatqqh4GuHmzZuYOXMmJk6cCCsrK9FxiIhQtmxZ9OvXj1NbIjXDYktE9B158+ZFyZIls11sY2Nj4eTkhKioKAQFBaFGjRoKTqjeEhMT0bt3b1SqVAmzZ88WHYeIKN3UqVPx4cMHrF+/XnQUIsokFlsioh/I7gJSnz59Qps2bXD79m0EBgbC0tJSCenU26xZs/D3339j+/btMDQ0FB2HiChduXLlOLUlUjMstkREP5CdYvv582e0a9cOV69eRUBAAOrVq6ekdOorLCwMixcvxuzZs1GzZk3RcYiIvjJt2jS8f/8eGzZsEB2FiDKBxZaI6AekUimioqIgk8kytX9CQgI6duyI8PBwHD9+HI0bN1ZyQvUTFxeHPn36oGHDhpg4caLoOERE31SuXDn07dsXixcvRnx8vOg4RPQTLLZERD8glUoRHx+PFy9e/HTfpKQkdOnSBWfOnMGRI0fQrFmzHEiofiZOnIiXL1/C29sburq6ouMQEX0Xp7ZE6oPFlojoB9Ie+fOzy5GTk5PRrVs3BAYG4tChQ7CxscmJeGonICAAGzZswLJly9JXnSYiUlXly5dHnz59sGjRIk5tiVQciy0R0Q+UL18eurq6Pyy2KSkp6NWrF44dO4b9+/fDwcEhBxOqj/fv32PAgAFwcHDA4MGDRcchIsqUadOm4d27d9i4caPoKET0Ayy2REQ/oK+vDzMzs+8W29TUVPTt2xcHDhzAnj170KZNmxxOqD6GDRuGhIQEbN26FRKJRHQcIqJMMTMz49SWSA2w2BIR/cT3VkaWyWQYOHAgdu3ahZ07d6JDhw45H05N+Pn5Yffu3Vi3bh1KliwpOg4RUZZMnz4d//zzDzZt2iQ6ChF9B4stEdFPpK2M/CWZTIYhQ4bA29sbvr6+6NKli6B0qu/58+cYNmwYXFxc0K1bN9FxiIiyzMzMDK6urli0aBE+f/4sOg4RfQOLLRHRT0ilUjx48ADJyckAALlcjlGjRmHz5s3Ytm0bevToITih6pLL5RgwYABy5cqFtWvXio5DRJRt06dPx9u3bzm1JVJRLLZERD8hlUqRkpKCR48eQS6XY/z48Vi7di02btyIvn37io6n0jZu3IiTJ09i69atKFiwoOg4RETZVqFCBfTu3RsLFy7k1JZIBbHYEhH9RNojf+7evYupU6dixYoV8PT0xKBBgwQnU2337t3D+PHjMXjwYLRq1Up0HCKiX5Y2td28ebPoKET0HxK5XC7/2U4xMTEwNTVFdHQ0TExMciIXEZHKkMlkMDY2hpWVFQIDA7F8+XKMHTtWdCyVlpqaiqZNm+L169e4ceMG8ubNKzoSEZFC9O3bF4GBgXjw4AFy5colOg6RRstKD+XElojoJ3R0dGBiYoLAwEAsWrSIpTYTlixZggsXLsDHx4ellog0yowZM/DmzRtObYlUDIstEdFPLF68GK9evUL58uUxadIk0XFU3o0bN+Dm5oZJkyahSZMmouMQESlUxYoV0bNnTyxcuBAJCQmi4xDR/7DYEhH9wMqVKzF58mRYWVmlr4pM35eYmIjevXujSpUqmDVrlug4RERKMWPGDLx69QpbtmwRHYWI/ofFlojoO9atW4exY8di0qRJGDhwIJ49e4ZPnz6JjqXS3N3dcefOHfj6+sLQ0FB0HCIipTA3N0fPnj2xYMECTm2JVASLLRHRN2zZsgXDhw/HmDFjsHDhQlSqVAnAvyv90redO3cOixcvxpw5c1CjRg3RcYiIlCptart161bRUYgILLZERF/x9vbGoEGDMGzYMCxfvhwSiST9kT+RkZGC06mm2NhY9OnTB40aNcKECRNExyEiUjqpVIoePXpgwYIFSExMFB2HSOux2BIRfWHnzp3o168fBg4ciDVr1kAikQAAChQogIIFC7LYfseECRPw+vVr+Pj4QFdXV3QcIqIcMWPGDLx8+ZJTWyIVwGJLRPQ/e/fuhaurK/r06YMNGzZARyfjt0ipVMpi+w3+/v7YtGkTli1bhgoVKoiOQ0SUYypVqoTu3btzakukAlhsiYgAHDp0CD169ICLiwu2bNnyVakFWGy/5d27dxgwYAAcHR0xaNAg0XGIiHLcjBkz8OLFC2zbtk10FCKtxmJLRFrv+PHj6Nq1Kzp27Ahvb+/vXkrLYpuRXC7H0KFDkZiYiK1bt6Zftk1EpE0qV66Mbt26Yf78+ZzaEgnEYktEWi0wMBCdOnVC69atsWPHDujp6X13X6lUivfv3+Pdu3c5mFB1+fn5Ye/evVi/fj1KlCghOg4RkTAzZ87E8+fP4eXlJToKkdZisSUirRUaGor27dvDzs4Ofn5+0NfX/+H+5ubmALgyMgA8f/4cw4YNQ7du3eDi4iI6DhGRUJzaEonHYktEWuns2bNo27YtmjVrhn379sHQ0PCn76lYsSIAFlu5XI7+/fsjT548WLt2reg4REQqYebMmXj27Bl+//130VGItBKLLRFpnfPnz8PJyQkNGzbEoUOHkCtXrky9z8jICKVKldL6YrthwwYEBgZi27ZtKFCggOg4REQqoUqVKnBxccH8+fORlJQkOg6R1mGxJSKtcunSJTg6OqJ27do4cuQIcufOnaX3a/sCUlFRUZgwYQKGDh0KBwcH0XGIiFTKzJkz8fTpU05tiQRgsSUirXHt2jXY29vDwsICx48fh5GRUZaPoc3FNiUlBX369EHx4sWxZMkS0XGIiFRO1apV0bVrV8ybN49TW6IcxmJLRFrh5s2bsLW1hbm5OQICAmBsbJyt40ilUkRFRUEmkyk4oepbvHgxLly4AB8fn2z9UYCISBukTW29vb1FRyHSKiy2RKTxIiIiYGtri7Jly+LkyZMwNTXN9rGkUik+f/6M58+fKzCh6rt27Rrc3d0xefJkNG7cWHQcIiKVZWFhgS5dunBqS5TDWGyJSKNFRkbCxsYGxYoVQ2BgIPLnz/9Lx5NKpenH1RYJCQlwdXWFhYUFZs2aJToOEZHKmzlzJp48eQIfHx/RUYi0BostEWms+/fvw9raGvnz50dwcDAKFSr0y8csV64c9PT0tKrYurm5ITIyEj4+PjAwMBAdh4hI5VWrVg2dO3fGvHnzkJycLDoOkVZgsSUijfTo0SNYW1vDyMgIISEhKFKkiEKOq6+vDzMzM60ptmfPnsXSpUsxZ84c1KhRQ3QcIiK14ebmhkePHnFqS5RDJHK5XP6znWJiYmBqaoro6GiYmJjkRC4iomx7+vQpmjdvDh0dHZw5cwYlS5ZU6PHbtm0LmUyG48ePK/S4qiY2NhY1a9ZEiRIlcObMGejq6oqORESkVrp06YLLly8jMjIS+vr6ouMQqZ2s9FBObIlIo7x48QLW1taQy+UIDQ1VeKkFtOeRP+PHj8ebN2/g7e3NUktElA2c2hLlHBZbItIYr1+/hrW1NRISEhAaGooyZcoo5TxSqRQPHz7U6NUujx8/js2bN2P58uWoUKGC6DhERGqpevXqvNeWKIew2BKRRnj79i1sbGwQExODU6dOoXz58ko7l1QqRWpqKh4+fKi0c4j0zz//YMCAAXBycsJvv/0mOg4RkVpzc3PDw4cP4evrKzoKkUZjsSUitff+/XvY2dnh7du3CA0NRcWKFZV6Pk1+5I9cLsfQoUORnJyMLVu2QCKRiI5ERKTWqlevDmdnZ05tiZSMxZaI1NrHjx9hb2+P58+fIyQkBJUrV1b6OUuUKIE8efJoZLHdtWsX9u3bhw0bNqB48eKi4xARaQQ3Nzc8ePAA27dvFx2FSGOx2BKR2oqJiYGjoyMePHiA4OBgVKtWLUfOK5FINHIBqWfPnmH48OHo0aMHunTpIjoOEZHGqFGjBjp16oR58+YhJSVFdBwijcRiS0RqKS4uDk5OTrhz5w6CgoJQs2bNHD2/phVbmUyGfv36IU+ePPD09BQdh4hI47i5ueH+/fuc2hIpCYstEamd+Ph4tGnTBjdv3sTJkydRp06dHM+gacV2/fr1CA4OhpeXF/Lnzy86DhGRxqlZsyY6duyIuXPncmpLpAQstkSkVj5//oz27dvj8uXLCAgIQIMGDYTkkEqlePHiBeLi4oScX5EiIyMxceJEDBs2DPb29qLjEBFprLSp7Y4dO0RHIdI4LLZEpDYSExPRqVMnhIWF4fjx42jSpImwLGkrI0dFRQnLoAgpKSlwdXVFyZIlsXjxYtFxiIg0Wq1atdChQwdObYmUgMWWiNRCUlISunTpglOnTuHIkSNo3ry50Dzm5uYA1P+RP4sWLcKlS5fg4+MDIyMj0XGIiDSem5sb7t27h507d4qOQqRRWGyJSOUlJyeje/fuOHnyJA4dOgRbW1vRkVCgQAEUKlRIrYvttWvXMGvWLEyZMgWNGjUSHYeISCvUrl0b7du359SWSMFYbIlIpaVdKnvkyBHs27cPjo6OoiOlU+cFpBISEtC7d29YWFjA3d1ddBwiIq3i5uaGqKgo7Nq1S3QUIo3BYktEKis1NRX9+/fH3r17sXv3brRt21Z0JACAXC7HmzdvYGpqirCwMEyZMgWdOnXCoUOHREfLtJkzZyIqKgq+vr4wMDAQHYeISKtYWlqiXbt2nNoSKRCLLRGpJJlMhkGDBmHHjh3YsWMHOnXqJDoSAOD169coXrw4ihYtioCAADx8+BDLli3DwYMHcfXqVdHxMuWPP/7AsmXLMHfuXFSvXl10HCIireTm5obIyEj4+fmJjkKkESRyuVz+s51iYmJgamqK6OhomJiY5EQuItJicrkcQ4cOxaZNm+Dj44NevXqJjpQuISEB1atXx/379/Hfb5/Xr19HzZo1BSXLnNjYWNSoUQOlS5fGqVOnoKurKzoSEZHWateuHe7evYuIiAh+Pyb6hqz0UE5siUilyOVyjB49Ghs3bsTWrVtVqtQCQK5cueDn5wcdnYzfPsuWLYsaNWoISpV548aNwz///IPff/+dv0QREQnm7u7OqS2RgrDYEpHKkMvlmDhxItasWYMNGzagX79+oiN9U506dTB79mxIJBIAgI6ODrp165b+sao6evQotmzZghUrVsDMzEx0HCIirVenTh20adMGc+bMQWpqqug4RGqNxZaIVIJcLsf06dOxbNkyrF69GoMHDxYd6YcmT56MBg0aAPj3fuDOnTsLTvRjb9++xcCBA9G6dWsMGDBAdBwiIvofd3d33L17F7t37xYdhUit8R5bIlIJHh4emDVrFpYtW4Zx48aJjpMpDx8+RMWKFWFoaIhPnz6p7MRWLpejc+fOOHPmDG7fvo1ixYqJjkRERF9o06YN7t+/j9u3b/M2EaIvZKWH6uVQJiKi75o/fz5mzZqFBQsWqE2pBYDy5ctjw4YNSEhIUNlSCwA7duzAgQMHsHfvXpZaIiIV5O7ujvr162PPnj3o3r276DhEaokTWyISaunSpZg4cSI8PDzg5uYmOo7Gefr0KapXr442bdpg+/btouMQEdF3tG7dGg8fPsStW7c4tSX6H66KTERqYfXq1Zg4cSKmT5+OmTNnio6jcWQyGfr164e8efNizZo1ouMQEdEPuLu74++//8bevXtFRyFSSyy2RCTE+vXrMXr0aEycOBFz5sxR6Ut51dW6desQEhICLy8v5M+fX3QcIiL6gfr166NVq1ZcIZkom1hsiSjHbd26FcOGDcPo0aOxaNEilloluHv3LiZNmoThw4fDzs5OdBwiIsoEd3d3REREYN++faKjEKkd3mNLRDnK19cXffr0wZAhQ7B27VqWWiVISUlBkyZN8OHDB1y7dg1GRkaiIxERUSa1atUKT548wa1bt6CjwxkUaTfeY0tEKsnPzw99+/ZF//794enpyVKrJAsXLsTly5fh4+PDUktEpGY4tSXKHk5siShH7N+/Hy4uLujZsye8vLz4V2gluXr1Kho0aIDJkydj7ty5ouMQEVE2ODo64tmzZ7h58yZ/XpJWy0oPZbElIqU7cuQInJ2d0aVLF/j6+vIxBkqSkJCAOnXqwNDQEOHh4TAwMBAdiYiIsuH8+fNo3Lgx9uzZgy5duoiOQyQML0UmIpXh7++Pzp07o3379vDx8WGpVaLTp0/jwYMH8PHxYaklIlJjjRo1gr29PWbPng2ZTCY6DpFaYLElIqUJCgpCp06d4OTkhF27dkFPT090JI3m4OCA58+fo1q1aqKjEBHRL3J3d8ft27dx4MAB0VGI1AIvRSYipTh9+jRatWoFa2trHDhwAIaGhqIjERERqRV7e3u8evUK169f5722pJV4KTIRCXXu3Dm0adMGTZs2xf79+1lqiYiIssHd3R23bt3CwYMHRUchUnmc2BKRQoWHh8Pe3h516tTB8ePHkSdPHtGRiIiI1JadnR1ev37NqS1ppaz0UN7wRkQKc/nyZTg6OqJmzZo4evSo0FIbFRWF2NhYYedXRcbGxjA3Nxcdg4iIssDd3R1NmzbFoUOH0KlTJ9FxiFQWJ7ZEpBDXr1+HtbU1KlWqhMDAQBgbGwvLEhUVBalUKuz8qiwyMpLllohIzdja2uLt27e4du0ap7akVTixJaIcdfv2bdja2qJChQoICAgQWmoBpE9qe23shaLSokKzqIrXka+xffB2TrGJiNSQu7s7mjVrhsOHD6Njx46i4xCpJBZbIvolf//9N2xsbFC6dGmcPHkS+fLlEx0pXVFpUZSuWVp0DCIiol/StGlTWFtbw8PDA+3bt+fUlugb+F8FEWVbVFQUbGxsUKRIEQQFBaFAgQKiIxEREWkkd3d33LhxA0eOHBEdhUglsdgSUbY8ePAA1tbWMDU1RXBwMAoVKiQ6EhERkcZq1qwZWrZsCQ8PD2RiiRwircNiS0RZ9vjxY1hbWyN37twIDQ1F0aK8j5WIiEjZ3N3dcf36dU5tib6BxZaIsuTZs2ewtraGrq4uQkNDUbx4cdGRiIiItELz5s3RokULTm2JvoHFlogy7eXLl7C2tkZKSgpCQ0NRqlQp0ZGIiIi0iru7O65du4ajR4+KjkKkUlhsiShTXr9+DWtra8THx+PUqVMoW7as6EhERERap0WLFmjevDlmzZrFqS3RF1hsiein/vnnH9ja2iI6OhqnTp2CmZmZ6EhERERaa9asWbh27RqOHTsmOgqRymCxJaIfev/+Pezs7PDmzRuEhITA3NxcdCQiIiKt1qJFCzRr1oxTW6IvsNgS0XdFR0fDwcEBT58+RXBwMKpUqSI6EhEREeHfqe3Vq1dx/Phx0VGIVAKLLRF9U2xsLBwdHXH//n0EBwejevXqoiMRERHR/7Ro0QJNmzbl1Jbof1hsiegrnz59gpOTEyIiIhAYGIhatWqJjkRERERfkEgkmDVrFq5cuQJ/f3/RcYiEY7Elogzi4+PRtm1bXL9+HSdPnkTdunVFRyIiIqJvaNmyJaysrDi1JQKLLRF9ISEhAR06dMCFCxcQEBCAhg0bio5ERERE35E2tb18+TICAgJExyESisWWiAAAiYmJcHZ2xrlz53D8+HFYWVmJjkREREQ/YW1tjSZNmnBqS1qPxZaIkJSUhK5duyIkJASHDx9GixYtREciIiKiTEib2l66dAknTpwQHYdIGBZbIi2XkpKCHj16ICAgAAcOHICdnZ3oSERERJQFNjY2aNy4Mae2pNVYbIm0WGpqKlxdXXH48GHs3bsXTk5OoiMRERFRFqVNbS9evIiTJ0+KjkMkBIstkZaSyWTo378/9uzZAz8/P7Rv3150JCIiIsomW1tbTm1Jq7HYEmkhmUyGwYMHY/v27fD19YWzs7PoSERERPQLJBIJ3N3dceHCBQQGBoqOQ5TjWGyJtIxcLseIESOwdetWeHl5oXv37qIjERERkQLY2dmhUaNGnNqSVmKxJdIicrkcY8eOxfr167F582a4urqKjkREREQKkja1DQ8PR1BQkOg4RDmKxZZIS8jlckyaNAmrVq3C+vXrMWDAANGRiIiISMHs7e3RsGFDTm1J67DYEmmJmTNnYunSpVi1ahWGDBkiOg4REREpQdrU9vz58wgODhYdhyjHsNgSaYE5c+Zg3rx5WLJkCUaNGiU6DhERESmRg4MDGjRowKktaRU90QGISLkWLlwINzc3zJs3DxMmTBAdR6Vc2HkBu0bsAgCM8h8Fs4ZmGV6Xy+XwqO6Bjy8+oqp9VQzyG5TpY3988RGHph/CnVN3IJfJYd7UHB3mdUChcoW+2jfcNxyhnqF4/+Q98pXMh2aDmqHZoGa/dEwiItJeaVNbJycnhISEwNbWVnQkIqXjxJZIgy1fvhxTp06Fu7s7pk2bJjqOytLPpY8r+658tf1e2D18fPEReoZZ+xtgYlwi1rZfi3t/3oPdODu0mtIKz24+g2cbT3x6/ynDvmG/h8FvtB+KVy4O54XOKFevHA5MOYDgVcHZPiYREZGjoyPq16/PqS1pDRZbIg3l6emJ8ePHpxdb+r4qtlVw/fB1pKakZth+dd9VlK5VGsZFjLN0vHPbzuHt/bcYtGsQbEbZoMWwFhi6fyhiXsfg1NpT6fslfU6C/1x/VLWvin7e/dCoTyP0Wt8LdbrUQeDSQMR/jM/yMYmIiID/n9qGhYUhJCREdBwipWOxJdJAGzduxMiRIzF+/HjMmzcPEolEdCSVZulsifj38bh76m76tpSkFNw4cgOWzpZZPt6NIzdQxrIMyliWSd9WVFoU5s3Mcf3Q9fRt987dw6f3n2A1wCrD+60GWCHpUxIiAiOyfEwiIqI0rVq1Qr169eDh4cGpLWk8FlsiDbNt2zYMGTIEI0eOxJIlS1hqM6FAmQIoV68crh64mr7t7+C/8TnmMyw7Za3YymQyvPjrBUrXKv3Va2Uty+Kfh/8gITYBAPDs5jMA+Grf0rVKQ6IjSX89K8ckIiJKkza1PXfuHEJDQ0XHIVIqFlsiDbJ9+3YMHDgQgwcPxqpVq1hqs8CysyVuHb+FpM9JAIAre6+gYpOKMC1umqXjxH+IR0piCkyKmnz1mkmxf7dFv4oGAMS8joGOrg6MC2e81FnPQA9GBYzS98vKMYmIiL7k5OSEunXrcmpLGo/FlkhD7NmzB3369EHfvn2xbt06ltosqt2hNpITkhFxMgIJsQn4K/CvbF2GnPw5GQC+ueBU2rbkhOT0fXUNdL95HD1DvQz7ZfaYREREX0qb2p49exanTnFNBtJcLLZEGuDgwYPo0aMHevTogc2bN0NHh/9pZ1XeQnkhbS7Flf1XcPPYTchSZajZvmaWj6OfWx8AkJKY8tVradv0c+mn75ualPrVfmn7frlfZo9JRET0X61bt0adOnU4tSWNxt9+idTc0aNH4eLigs6dO8PLywu6ut+eANLP1elcB38H/40wrzBUsa2CPKZ5snyMPPnzQM9QDzGvY756LebVv9tMi/17ebNJURPIUmWIfRubYb+UpBR8ev8pfb+sHJOIiOi/0qa2f/zxB06fPi06DpFSsNgSqbETJ06gc+fOaNu2LXx9faGnl7XnrVJGNVrXgERHgseXH6OOc51sHUNHRwfFqxbH0+tPv3rt8ZXHKFiuIHIZ5wIAlKxeEgC+2vfptaeQy+Tpr2flmERERN/Spk0bWFpawsPDQ3QUIqVgsSVSU8HBwejQoQMcHBywa9cu6OvzUtRfZZjXEF2WdoHjZEdYOFpk+zg129XEk6tP8OTak/Rtr6NeI+psFGq1r5W+zbypOfLkz4OwbWEZ3h/mFQaDPAaoal81y8ckIiL6lrSp7ZkzZzi1JY3E8Q6RGjpz5gzatWuHli1bYu/evTAwMBAdSWPU717/l49h1d8K4T7h2NRtE6yHW0NHXwen152GcRFjtBzeMn0/g9wGcJrmhH0T98GrrxcqW1fGg/AHuLznMlrPaA2j/EZZPiYREdH3tG3bFrVr14aHhwdatGghOg6RQrHYEqmZsLAwtG7dGk2aNMGBAwdgaGgoOhL9Ry7jXBhxZAQOTj+IwGWBkMvlqNikIjrM64C8hfJm2NdqgBV09XRxat0p3D5xG/lL5keHeR3QfEjzbB+TiIjoW9Kmth06dMCZM2fQvHnzn7+JSE1I5JlYGi0mJgampqaIjo6GicnXz1Ekopxx8eJF2NrawtLSEv7+/siTJ+uLG2mDq1evok6dOhh/ajxK1ywtOo5KeHrjKZa1XIYrV67A0jLrjzEiIiLNIJfLYWlpifz58yM0NFR0HKIfykoP5T22RGri6tWrsLe3R40aNXDs2DGWWiIiIsqytKntqVOn8Mcff4iOQ6QwvBSZSA3cuHEDdnZ2qFy5Mvz9/ZE3Ly89FeHTh0/ffe4sAOjo6vCyYCIiUnnt27dHrVq14OHhgZCQENFxiBSCxZZIxf3111+wtbVFuXLlcOLECd4OINA21224H3b/u6/nL50f7jfcczARERFR1kkkEri5uaFTp044e/YsmjZtKjoS0S9jsSVSYXfu3IGNjQ1KliyJoKAg5MuXT3QkrdZhTgfEf4z/7uv6ufjIJSIiUg/t27dHzZo14eHhgeDgYNFxiH4Ziy2RioqKioK1tTUKFSqEoKAgFChQQHQkrVe6FheiIiIizaCjowM3Nzc4Ozvj3LlzsLKyEh2J6Jdw8SgiFfTw4UNYW1vDxMQEISEhKFy4sOhIREREpGE6dOiAGjVqwMPDQ3QUol/GYkukYp48eQJra2vkypULoaGhKFq0qOhIREREpIF0dHTg7u6O4OBghIWFiY5D9EtYbIlUyPPnz2FtbQ2JRILQ0FCUKFFCdCQiIiLSYB06dED16tU5tSW1x2JLpCJevXoFa2trJCUlITQ0FKVL835OIiIiUq60qW1QUBD+/PNP0XGIso3FlkgFvHnzBjY2NoiLi8OpU6dQrlw50ZGIiIhIS3Ts2BHVqlXj1JbUGostkWDv3r2Dra0t3r9/j9DQUFSoUEF0JCIiItIiaVPbwMBAnD9/XnQcomxhsSUS6MOHD7Czs8OrV68QEhKCSpUqiY5EREREWqhTp06c2pJaY7ElEiQ6OhoODg54/PgxgoODUbVqVdGRiIiISEulPdf25MmTCA8PFx2HKMtYbIkEiI2NRatWrRAVFYWgoCDUqFFDdCQiIiLScs7OzrCwsODUltQSiy1RDvv06RPatGmDv/76C4GBgbC0tBQdiYiIiCh9anvixAlcuHBBdByiLGGxJcpBnz9/Rrt27XD16lUEBASgXr16oiMRERERpevcuTOqVq3KqS2pHRZbohySkJCADh06IDw8HMePH0fjxo1FRyIiIiLKIG1qGxAQgIsXL4qOQ5RpLLZEOSApKQmdO3fGH3/8gaNHj6JZs2aiIxERERF9U+fOnVGlShVObUmtsNgSKVlycjJcXFwQFBSEw4cPw9raWnQkIiIiou/S1dWFm5sb/P39ObUltcFiS6REKSkp6NmzJ44fP44DBw7A3t5edCQiIiKin+rSpQsqV66M2bNni45ClCkstkRKkpqaij59+uDgwYPYs2cPWrduLToSERERUaakTW2PHz+OS5cuiY5D9FMstkRKIJPJMHDgQPj5+WHnzp3o0KGD6EhEREREWdK1a1dUrlyZ99qSWmCxJVIwmUyGIUOGwNvbG76+vujSpYvoSERERERZpquri5kzZ+L48eO4fPmy6DhEP8RiS6RAcrkco0aNwpYtW+Dl5YUePXqIjkRERESUbS4uLqhUqRKntqTyWGyJFEQul2PcuHFYu3YtNm7ciD59+oiORERERPRL0qa2x44dw5UrV0THIfouFlsiBZDL5ZgyZQpWrlyJtWvX4rfffhMdiYiIiEghunXrBqlUmj61lcvleP36teBURBmx2BIpgLu7OxYvXowVK1Zg2LBhouMQERERKUza1Pbo0aNYu3YtGjZsiGLFiiEyMlJ0NKJ0eqIDEKm7uXPnYs6cOVi0aBHGjBkjOg4RERGRQsnlchQoUACGhoYYMWIEdHT+nY19/PhRbDCiL7DYEv2CxYsXY+bMmZgzZw4mTZokOg79x+tIXiaVhl8LIiLKjsTERNjY2CAsLCy90MpkMsGpiL7GYkuUTStXrsTkyZMxc+ZMzJgxQ3Qc+oKxsTEAYPvg7YKTqJ60rw0REVFm6OrqIjExEcDXhVYikYiIRPRNLLZE2bB27VqMHTsWkydP5vL3Ksjc3ByRkZGIjY0VHUUlXLp0CSNGjICjoyMqVKggOg4REakRPT09hIWFYeLEiVi9erXoOETfxWJLlEWbN2/GiBEjMHbsWCxYsIB/rVRR5ubmoiOoDEtLSxQoUADdunXDiBEjsHbtWv57S0REmWZgYIBVq1ahefPm6NOnD+Li4gBwYkuqhcWWKAt+//13DB48GMOHD8eyZcv4DZ3URpcuXRAbG4sBAwYgf/78mDdvnuhIRESkZjp16oRatWqhRYsWePr0Ka+MIpXCYkuUSTt27ED//v3x22+/YfXq1Sy1pHb69++P6OhojBs3DqamplzwjIiIsszMzAx3797F6tWr0bRpU9FxiNKx2BJlwt69e+Hq6oo+ffpg/fr16asCEqmbsWPH4sOHD5g8eTLy5cuHQYMGiY5ERERqJnfu3Jg8ebLoGEQZsNgS/cShQ4fQo0cPdOvWDVu2bGGpJbXn4eGB/2vvvqOjqhP+j38mjVAykwChiigSFrBBcBEkiEASUiiht5AJiKCCoqKi2H5YVncVd1dRFwsmCNKlQxpNQREBERUVkKogIjApBAhJ5vfHLnlEigSSfKe8X+fsOY8z15s3PGddPs6dex0Oh+6++25ZrVYNGDDAdBIAAMAVYdgCF7F06VL169dPPXv2VGpqqnx9fU0nAVfMYrHoX//6l7KzszVkyBAFBQUpPj7edBYAAMBl46Mn4ALS09PVq1cvxcfHa/r06fLz498DwXP4+PjovffeU9euXdWnTx+tWbPGdBIAAMBlY9gC57Fy5UolJCQoKipKs2bNkr+/v+kkoMz5+flp5syZioiIULdu3bRx40bTSQAAAJeFYQv8wccff6xu3bqpQ4cOmjt3rgICAkwnwcs99NBD2r17d7mcu1KlSpo/f76uv/56xcTEaNu2beXycwAAAMoTwxb4nU8//VRxcXFq06aN5s+fr8DAQNNJ8HJOp1OzZ8/WxIkTy+1nVKtWTcuWLVO9evUUFRVVbiMaAACgvDBsgf/54osvFBsbq/DwcC1atEiVK1c2nQTIYrEoMTFRH374oU6dOlVuPyckJEQZGRmqUqWKIiMjdfDgwXL7WQAAAGXN4nQ6nX92UE5Ojmw2m7Kzs2W1WiuiC6hQX375pTp16qRmzZopPT1dQUFBppOAEt99952aN2+uuXPnqnfv3uX6s/bu3auIiAgFBwdrzZo1ql69ern+PACAa9ixY4dyc3NNZ7icoKAghYWFmc7wWqXZoQxbeL2tW7eqY8eOuu6665SZmSmbzWY6CTjHrbfeqlq1amnx4sXl/rO+//57tW/fXo0aNVJWVhb/ogcAPNyOHTvUpEkT0xkua/v27YxbQ0qzQ3l+Cbzatm3bFBkZqYYNGyo9PZ1RC5eVnJys++67T4cOHVLt2rXL9Wc1bdpU6enp6tixoxISErR06VK+bw4AHuzMJ7WjR49W/fr1Dde4jp9//lmTJk3ik2w3wbCF1/rhhx/UqVMn1alTR5mZmQoJCTGdBFzQgAED9MADD2j69Ol66KGHyv3nhYeHa8mSJYqOjtaAAQM0Z84cHnsFAB6ufv36atSokekM4LJw8yh4pZ07d6pTp06qUaOGsrKyVKNGDdNJwEWFhISoR48eSklJ0SV8g6RMtG/fXh999JGWLl2qYcOGqbi4uEJ+LgAAQGkxbOF19uzZo06dOqlatWpasWKFatWqZToJuCTJycn6+uuvtWXLlgr7mbGxsZo+fbqmT5+u+++/v8JGNQAAQGlwKTK8yv79+9WxY0cFBARo5cqVqlOnjukk4JJFR0erTp06SklJUcuWLSvs5/br1085OTm66667FBwcrOeff77CfjYAAMCl4BNbeI0DBw6oU6dOkqSVK1dycwS4HT8/PyUmJmr69OkqKCio0J89fPhwvfLKK3rhhRf08ssvV+jPBgAA+DMMW3iFQ4cOqVOnTjp58qRWrlypq6++2nQScFnsdruOHDmiZcuWVfjPHjt2rJ588kk9+uijeueddyr85wMAAFwIlyLD4x0+fFidO3dWTk6OPv74Y1177bWmk4DLdsMNN6hVq1ZKSUlRQkJChf/8Z599Vg6HQyNHjpTValX//v0rvAEAAOCPGLbwaEeOHFFkZKR+++03rV69Wo0bNzadBFyx5ORkPfjggzp8+LBCQ0Mr9GdbLBb9+9//VnZ2thITExUUFKS4uLgKbQAAAPgjLkWGx3I4HIqOjtaBAwe0YsUKNW3a1HQSUCYGDhwoi8WiDz/80MjP9/Hx0ZQpU9S1a1f17t1bH3/8sZEOAACAMxi28Eg5OTnq0qWL9uzZo6ysLF1//fWmk4AyU6NGDXXr1k0pKSnGGvz8/DRjxgy1a9dOXbt21aZNm4y1AAAAMGzhcfLy8hQbG6sffvhBmZmZuvnmm00nAWXObrdry5Yt+uqrr4w1BAYGasGCBWrevLliYmL03XffGWsBAADejWELj5Kfn6+uXbvq66+/Vnp6usLDw00nAeUiNjZWoaGhSk1NNdpRrVo1LVu2THXq1FFUVJT27NljtAcAAHgnhi08xokTJ9SjRw9t3LhRy5cv16233mo6CSg3/v7+Jc+0PX36tNGW6tWrKyMjQ4GBgYqMjNTBgweN9gAAAO/DsIVHOHXqlHr16qV169Zp6dKlateunekkoNzZ7Xb9+uuvSktLM52iunXrKisrSydPnlR0dLSOHj1qOgkAAHgRhi3cXkFBgfr27avVq1dr8eLF6tChg+kkoELcfPPNatGihdGbSP3eNddco8zMTB08eFBxcXHKy8sznQQAALwEwxZu7fTp0xowYIDS09M1f/58de7c2XQSUKHsdrsWL16sI0eOmE6RJDVr1kzp6enatm2bEhISdPLkSdNJAADACzBs4bYKCws1ZMgQLVmyRPPmzVNMTIzpJKDCDRo0SE6nUzNmzDCdUqJVq1ZasmSJ1q1bpwEDBqiwsNB0EgAA8HAMW7iloqIiDR06VHPnztWsWbPUtWtX00mAEbVq1VJ8fLzxuyP/0e2336558+Zp6dKlGjZsmIqLi00nAQAAD8awhdspLi7WXXfdpQ8//FDTp09Xz549TScBRtntdm3cuFHffPON6ZSzxMXFadq0aZo2bZrGjBkjp9NpOgkAAHgohi3citPp1L333quUlBSlpqaqf//+ppMA4+Lj41WjRg2X+9RWkvr376/Jkydr0qRJevrpp03nAAAAD8WwhdtwOp0aM2aMJk+erPfee0+JiYmmkwCXEBAQoEGDBmnatGku+X3Wu+66S//4xz/0/PPPa+LEiaZzAACAB2LYwi04nU49/PDDev311zV58mQNHTrUdBLgUpKTk/XLL78oIyPDdMp5PfLIIxo/frwefvhhvfvuu6ZzAACAh/EzHQD8GafTqfHjx+vVV1/V66+/rhEjRphOAlxOy5YtdeONNyo1NVVxcXGmc87r+eefl8Ph0IgRI2S1WtWvXz/TSQAAwEMwbOHyJkyYoJdeekmvvvqqRo8ebToHcEkWi0V2u13jx4/XsWPHFBISYjrpHBaLRa+//rpycnKUmJiooKAgxcbGms4CAAAegEuR4dJeeOGFkmH74IMPms4BXNrgwYNVVFSkWbNmmU65IB8fH02ZMkWxsbHq3bu3PvnkE9NJAADAA/CJLVzWK6+8oieffFITJkzQuHHjTOcALq9OnTqKiYlRSkqK7r77btM5F+Tv769Zs2YpLi5OXbt21apVqxQeHm46CwDwJ1avXq233npL0n+vqGvatOlZ7zudTo0aNUpHjhxReHj4Jf/57cCBA8rMzNTOnTu1e/dunT59Wq+//rpq1ap1zrGffvqpNm3apJ07d+qXX35R8+bN9cwzz5xz3MmTJ7Vo0SLt3LlTO3fu1PHjx3XPPffojjvuKP0vHG6BT2zhkl577TU98sgjeuKJJ/TUU0+ZzgHcRnJysj7//HN9//33plMuKjAwUAsXLlTTpk3VpUsXl+8FAPwff39/rV279pzXt23bpiNHjsjf379U59u+fbuWL1+uEydOqH79+hc9NjMzUxs3blSNGjVUtWrVCx6Xk5OjefPm6eeff1bDhg1L1QP3xLCFy3nrrbc0ZswYPfLII3ruuedksVhMJwFuo1u3bgoJCXHJZ9r+UVBQkJYvX646deooMjJSe/bsMZ0EALgELVu21Pr161VUVHTW6+vWrVOjRo0UHBxcqvPdcsstev/99/XKK68oIiLioseOGjVK77//vp5++umL3k8iJCREkydP1htvvMEjIr0EwxYu5b333tO9996rMWPG6O9//zujFiilSpUqaeDAgZo6deo5f+BwRdWrV1dGRoYqVaqkqKgo/fLLL6aTAAB/ol27dsrLy9PWrVtLXissLNT69evVrl27Up+vWrVqqly58iUdW7NmTfn4/PmE8ff3L/XAhntj2MJlTJ06VXfddZfuuece/fOf/2TUApcpOTlZBw4c0IoVK0ynXJK6desqKytL+fn5io6O1rFjx0wnAQAuIjQ0VGFhYVq3bl3Ja19++aXy8/N12223GSyDN2PYwiXMmDFDQ4cO1Z133qlJkyYxaoErcMstt6hZs2ZKSUkxnXLJrr32WmVmZurAgQOKi4tTXl6e6SQAwEVERERo48aNKigokCStXbtWzZs3V/Xq1Q2XwVsxbGHc3LlzNWTIEA0ZMkSTJ0++pMtLAFyYxWJRcnKy5s+fr+zsbNM5l6x58+ZKS0vTt99+q4SEBJ06dcp0EgDgAtq2bauCggJt2rRJJ06c0ObNmy/rMmSgrLAgYNTChQs1cOBA9evXT++99x6jFigjiYmJKigo0OzZs02nlMott9yixYsXa926dRo4cKAKCwtNJwEAzsNqterGG2/UunXrtGHDBhUXF6tNmzams+DFWBEwZtmyZerbt6969OihqVOnytfX13QS4DHq1aun6Ohot7oc+YwOHTpo7ty5Wrx4sYYPH67i4mLTSQCA82jXrp22bNmizMxMtWjR4qKP3wHKG8MWRmRmZqpXr16Ki4vTjBkz5OfnZzoJ8DjJycn69NNPtWPHDtMppRYfH6+pU6dq6tSpeuCBB+R0Ok0nAQD+oHXr1rJYLNqxY8efPqYHKG+sCVS4VatWqXv37urcubNmzZpV6od4A7g0PXr0kM1mU2pqqp5//nnTOaU2cOBA5eTk6O6771ZISIgmTJhgOgkA8DuBgYEaPny4fv31V7Vq1cp0DrwcwxYV6pNPPlHXrl3Vvn17zZs3T5UqVTKdBHiswMBADRgwQFOnTtWzzz7rlt9hHzlypLKzszVu3DjZbDY99NBDppMAAL/ToUOHKz5Hfn6+li9fLknavn27JCk9PV1VqlRR1apVFRMTU3Lstm3b9N1330mScnNzderUKc2bN0+S1KxZMzVv3rzk2LS0NB0/frzkMXKbNm3SkSNHJEmxsbGqUqXKFbfDdTBsUWE+++wzxcXF6dZbb9WCBQsUGBhoOgnweHa7XZMnT9aqVavUuXNn0zmX5dFHH5XD4dDYsWNls9l05513mk4CAJShvLy8c252uGTJEkn/fWbu74ftt99+q7lz55517Jm/t0+fPmcN2yVLlujw4cMlf71hwwZt2LBBktS+fXuGrYexOC/hi0s5OTmy2WzKzs6W1WqtiC54mI0bN6pz5866+eabtXz5cm4uAFQQp9Oppk2bqnXr1vrggw9M51w2p9OpUaNGafLkyZo5c6b69u1rOgkAPMbmzZvVqlUrvfjii2rUqJHpHJexa9cuPf7449q0aZPCw8NN53il0uxQ97suDW5ny5YtioqKUvPmzbV06VJGLVCBzjzTdt68ecrJyTGdc9ksFosmTZqkAQMGaPDgwUpLSzOdBAAAXAjDFuXqm2++UWRkpBo3bqzly5crKCjIdBLgdYYMGaKTJ0+ec+mWu/Hx8VFKSopiYmLUq1cvrV271nQSAOAi8vLy5HA4Lvgfd/4XrnA9fMcW5ea7775T586d1aBBA6Wnpys4ONh0EuCVrrrqKkVGRiolJUXDhg0znXNF/P39NXv2bMXGxio+Pl6rVq3i8jAAcFETJ07Utm3bLvh+aGioJk2aVIFF8GQMW5SL7du3q1OnTqpVq5YyMzNVvXp100mAV7Pb7UpMTNSPP/6o6667znTOFQkMDNSiRYvUuXNnxcTE6JNPPtFf/vIX01kAgD8YMmSI8vLyLvh+QEBABdbA0zFsUeZ+/PFHderUSSEhIVqxYoVq1qxpOgnwej179lRQUJCmTp3qEc+DDQoK0vLly3X77bcrKipKa9eu1dVXX206CwDwO9yIChWJ79iiTO3du1edOnVSlSpVtGLFCtWqVct0EgBJVapUUf/+/TV16lQVFxebzikTNWrUUGZmpvz8/BQZGalDhw6ZTgIAAIYwbFFmfvrpJ3Xs2FF+fn5auXKl6tatazoJwO/Y7Xbt2bNHH3/8semUMlOvXj1lZWUpLy9PXbp00bFjx0wnAQAAAxi2KBMHDx5Up06dVFRUpJUrV+qqq64ynQTgD9q1a6frrrtOKSkpplPKVKNGjZSZman9+/crPj5ex48fN50EAAAqGMMWV+zQoUPq1KmT8vPztWrVKjVs2NB0EoDzsFgsstvtmjt37kVv5uGOrr/+eqWlpenrr79Wz549derUKdNJAACgAjFscUV+++03RUZGKjs7W6tWreImAYCLS0pK0vHjxzVv3jzTKWXur3/9qxYvXqyPP/5YgwYNUmFhoekkAABQQRi2uGxHjx5VVFSUfv31V61YsUJhYWGmkwD8iYYNG6pTp05KTU01nVIu7rjjDs2dO1eLFi3SXXfd5TE3ygIAABfHsMVlcTgcio6O1v79+7VixQo1a9bMdBKAS2S327Vq1Srt2bPHdEq56Nq1q6ZOnarU1FQ9+OCDcjqdppMAAEA5Y9ii1HJychQbG6tdu3YpKytLN9xwg+kkAKXQu3dvVatWTVOnTjWdUm4GDhyoN998U6+99ppHPLcXAABcHMMWpZKXl6f4+Hh99913yszMVIsWLUwnASilqlWrqk+fPkpNTfXoTzPvvvtuvfjii5owYYL++c9/ms4BAADliGGLS5afn69u3bppy5YtSktLU6tWrUwnAbhMycnJ2rVrl9auXWs6pVw99thjGjdunB566CFNmTLFdA4AACgnfqYD4B5OnjyphIQEbdiwQenp6WrTpo3pJABXoH379rr22muVmpqq9u3bm84pVy+++KIcDofuuusu2Ww29e7d23QSAAAoY3xiiz916tQp9e7dW2vXrtXSpUsVERFhOgnAFfLx8VFSUpJmz56t/Px80znlymKx6I033lD//v01cOBApaenm04CAABljGGLiyooKFC/fv20YsUKLVy4UHfccYfpJABlJCkpSbm5uZo/f77plHLn6+ur1NRURUdHq2fPnlq3bp3pJAAAUIYYtrigwsJCDRo0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NH78eNM5AAAvx7AFABhlt9uVnZ2thQsXmk5BKQ0bNkyvvvqqXnrpJb300kumcwAAXszPdAAAwLs1adJEt912m1JTU9W/f3/TOSilBx98UA6HQ48//riCg4N19913m04CAHghhi0AwDi73a577rlHBw4cUL169UznoJT+3//7f3I4HLr33ntltVo1aNAg00kAAC/DpcgAAOP69eungIAATZs2zXQKLoPFYtE///lPJSUlKSkpSYsXLzadBADwMgxbAIBxwcHBSkhI4Jm2bszHx0fvvvuuunfvrr59+2r16tWmkwAAXoRhCwBwCcnJydq2bZs2btxoOgWXyc/PTzNmzNDtt9+ubt266YsvvjCdBADwEgxbAIBLiIyMVL169ZSammo6BVegUqVKmj9/vm688UbFxMTo22+/NZ0EAPACDFsAgEs480zbDz/8UKdOnTKdgytQtWpVLV26VFdddZWioqK0a9cu00kAAA/HsAUAuAy73a5jx45x8yEPEBISooyMDFWtWlVRUVE6cOCA6SQAgAdj2AIAXEazZs3UunVrLkf2ELVr11ZWVpYKCgoUHR2tI0eOmE4CAHgohi0AwKUkJydr+fLlOnTokOkUlIGGDRsqMzNThw4dUmxsrHJzc00nAQA8EMMWAOBSBgwYIF9fX02fPt10CspI06ZNlZ6erh9++EHdu3fXiRMnTCcBADwMwxYA4FJCQkLUo0cPvf/++zzT1oOEh4dryZIl+vzzz9W/f3+dPn3adBIAwIMwbAEALic5OVnffPONvvzyS9MpKEPt27fXRx99pLS0NCUnJ6u4uNh0EgDAQzBsAQAuJzo6WnXq1OEmUh4oJiZG06dP18yZMzV69Gg+lQcAlAmGLQDA5fj5+SkxMVHTp09XQUGB6RyUsb59++rtt9/WW2+9pSeeeMJ0DgDAAzBsAQAuyW6368iRI1q2bJnpFJSDO++8UxMnTtSLL76ov//976ZzAABuzs90AAAA53PDDTeoVatWSklJUUJCgukclIOHHnpIDodDjz32mIKDgzVy5EjTSQAAN8WwBQC4rOTkZD344IM6fPiwQkNDTeegHEyYMEEOh0P33HOPrFarBg4caDoJAOCGuBQZAOCyBg4cKIvFog8//NB0CsqJxWLRv/71Lw0ZMkRJSUlaunSp6SQAgBti2AIAXFaNGjXUrVs3paSkmE5BOfLx8dF7772nrl27qk+fPlqzZo3pJACAm2HYAgBcWnJysrZs2aKvvvrKdArKkZ+fn2bMmKF27dqpW7du2rhxo+kkAIAbYdgCAFxaTEyMQkNDeaatFwgMDNSCBQvUvHlzxcTEaNu2baaTAABugmELAHBp/v7+SkxM1LRp03T69GnTOShn1apV07Jly1SvXj1FRUVp9+7dppMAAG6AYQsAcHl2u12HDx9WWlqa6RRUgOrVqysjI0OVK1dWZGSkDh48aDoJAODiGLYAAJd38803q0WLFtxEyovUqVNHWVlZOnXqlKKionTkyBHTSQAAF8awBQC4heTkZC1evJiB40WuueYaZWZm6tChQ4qLi1Nubq7pJACAi2LYAgDcwqBBg+R0OjVjxgzTKahAzZo1U3p6ur7//nv16NFDJ0+eNJ0EAHBBDFsAgFsIDQ1VfHw8lyN7ofDwcC1ZskSfffaZ+vfvz03EAADnYNgCANyG3W7Xpk2b9M0335hOQQVr3769PvroIy1btkzDhg1TcXGx6SQAgAth2AIA3EZ8fLxq1KjBM229VGxsrKZPn67p06fr/vvvl9PpNJ0EAHARDFsAgNsICAjQ4MGDNW3aNBUWFurUqVN8eutl+vXrp7fffltvvPGGnnrqKdM5AAAXwbAFALiVpKQk/fLLL0pISFCtWrV04403av/+/aazUIGGDx+uV155RS+88IJefvll0zkAABfgZzoAAIBLcerUKf373//Wu+++K0latmxZyaWo1apVM5kGA8aOHatjx47p0UcfVXBwsO666y7TSQAAgxi2AAC3sGrVKo0bN67kr8+M2kqVKik4ONhQFUx67rnn5HA4NHLkSFmtVvXv3990EgDAEC5FBgC4hS5duujxxx8/5/XatWvLYrEYKIJpFotFr732mgYPHqzExEQtW7bMdBIAwBCGLQDALVgsFv3tb3875zuVDRs2NFQEV+Dj46P3339f8fHx6t27tz7++GPTSQAAAxi2AAC38vDDD+vdd98t+ZTWZrMZLoJpfn5+mjlzpm677TZ17dpVmzZtMp0EAKhgDFsAgNu58847NX36dElSUVGR4Rq4gsDAQC1YsEDNmzdXly5d9N1335lOAgBUIIvzEp5unpOTI5vNpuzsbFmt1oroAgDgT3322Wdq3LixQkNDTafARRw9elQdOnTQsWPHtHbtWl1zzTWmkwAA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e6pfv35auXKl6SQAHophCwAAgHLj6+uradOm6Y477lD37t31+eefm04C4IEYtgAAAChXlSpV0rx589SiRQvFxsbqm2++MZ0EwMMwbAEAAFDuqlatqiVLlqhhw4aKiorSjz/+aDoJgAdh2AIAAKBCBAcHKz09XVarVZGRkfr5559NJwHwEAxbAAAAVJhatWopKytLxcXFioqK0m+//WY6CYAHYNgCAACgQjVo0ECZmZk6cuSIYmJilJOTYzoJgJtj2AIAAKDCNWnSRBkZGdq5c6e6d++uEydOmE4C4MYYtgAAADDi5ptv1rJly/TFF1+ob9++On36tOkkAG6KYQsAAABjbrvtNs2fP18ZGRlKSkpSUVGR6SQAbohhCwAAAKOio6M1Y8YMzZ49W6NGjZLT6TSdBMDNMGwBAABgXO/evfXuu+9q8uTJevzxx03nAHAzfqYDAAAAAEkaOnSocnJy9MADDyg4OFiPPfaY6SQAboJhCwAAAJcxZswYORwOPf7447LZbLrnnntMJwFwAwxbAAAAuJSnn35aDodDo0aNktVq1eDBg00nAXBxDFsAAAC4FIvFookTJyo7O1t2u11Wq1XdunUznQXAhXHzKAAAALgcHx8fvf3220pISFDfvn21atUq00kAXBjDFgAAAC7Jz89P06dPV4cOHdS9e3dt2LDBdBIAF8WwBQAAgMuqVKmSPvroI910002KjY3Vt99+azoJgAti2AIAAMClVa1aVUuXLlWDBg0UFRWlXbt2mU4C4GIYtgAAAHB5wcHBSk9PV7Vq1RQZGakDBw5IklJTUzV27FjDdQBMszidTuefHZSTkyObzabs7GxZrdaK6AIAAADOsW/fPkVERCgoKEh9+/bVhAkTJEk//fST6tevb7gOQFkqzQ7lE1sAAAC4jauvvloZGRnavXt3yai1WCxaunSp4TIAJjFsAQAA4DaKi4v12muv6cSJEyWvWSwWLVy40GAVANMYtgAAAHAb7733nt56662zXisuLlZWVpby8/MNVQEwjWELAAAAt9G9e3eNGjVKNptNkuTj898/zhYUFCgrK8tkGgCDGLYAAABwG7Vr19akSZP066+/av78+eratWvJuH355ZcN1wEwxc90AAAAAFBaAQEBSkhIUEJCgn777Tc999xzatGiheksAIbwuB8AAAB4hB07dig3N9d0hksJCgpSWFiY6QzgspRmh/KJLQAAANzejh071KRJE9MZLmn79u2MW3g8hi0AAADc3plPahMnJ6p2k9qGa1zDoe2HNG3kND7Fhldg2AIAAMBj1G5SWw1ubmA6A0AF467IAAAAAAC3xrAFAAAAALg1hi0AAAAAwK0xbAEAAAAAbo1hCwAAAABwawxbAAAAAIBbY9gCAAAAANwawxYAAAAA4NYYtgAAAAAAt8awBQAAAAC4NYYtAAAAAMCtMWwBAAAAAG6NYQsAAAAAcGsMWwAAAACAW2PYAgAAAADcGsMWAAAAAODWGLYAAAAAALfGsAUAAAAAuDWGLQAAAADArTFsAQAAAABujWELAAAAAHBrDFsAAAAAgFtj2AIAAAAA3BrDFgAAAADg1vxMBwAAAAAV5fMPP9eM0TMkSfcvu1+N2jQ6632n06kJN06Q44BDzaOba8TMEZd8bscBhxY8sUDfr/pezmKnwtqHKeGFBNW8puY5x67/YL1WTlqpo/uOKrh+sG4fcbtuH3H7Wccc2nFIn77/qfZu2quftv6kwlOFemrLU6pxdY3L+JUDno1PbAEAAOB1/AP9tWnupnNe37lupxwHHPKrVLrPf07lndIbPd7Qzk93KuqhKMU+Fquftv6kSV0n6fjR42cduy5lnWaOmam6Teuq90u9dc1fr9FHj32krH9nnXXcni/26OO3P9apvFOq3aR26X+RgBfhE1sAAAB4nWaRzbRl4Rb1eqmXfP18S17fPHezGrRooLwjeaU639opa3X4x8N6KOshXR1+dcnP+Hu7v2vVG6vU9amukqSCEwVa9vwyNY9urqGpQyVJbe1t5Sx2KuOVDN1mv01VgqtIkm6IvUEv7n5RgUGBWvn6Sv389c9l8UsHPBKf2AIAAMDrhPcOV/7RfP2w6oeS1woLCvXVoq8U3ju81Of7atFXujr86pJRK0m1m9RW2O1h2rJgS8lrO9fu1PGjxxVxZ8RZf3/EnREqOF6gbRnbSl6rGlJVgUGBpW4BvBHDFgAAAF6n+tXVdc1fr9HmjzaXvPZd1nc6kXNC4b1KN2yLi4t14NsDatCiwTnvNQxvqN92/6aTuSclST9t/UmSzjm2QYsGsvhYSt4HUDoMWwAAAHil8D7h+nrp1yo4USBJ2jRnkxq3ayxbXVupzpN/LF+FpwplrW095z1rnf++lv1LtiQp51COfHx9FBQadNZxfgF+qlq9aslxAEqHYQsAAACv1DKhpU6fPK1t6dt0Mvekvs349rIuQz594rQknfeGU2deO33ydMmxvgG+5xx35tgzxwEoHW4eBQAAAK9UrWY1NenQRJvmbVLBiQIVFxXr5h43l/o8/pX9JUmFpwrPee/Ma/6B/iXHFhUUnfc8hacKS44DUDp8YgsAAACv1apPK32X9Z3Wvb9OzSKbqYqtSqnPUSWkivwq+SnnUM457+X88t/XbHX+e3mztbZVxUXFyj2ce9ZxhQWFOn70eMlxAEqHYQsAAACvdVP8TbL4WLR341616t3qss7h4+Ojus3rav+W/ee8t3fTXtW4pkbJ3Y3r31hfks45dv+X++Usdpa8D6B0GLYAAADwWpWqVVLfV/oqZlyMro+5/rLPc3P3m7Vv8z7t+3JfyWuHdhzSjk92qEWPFiWvhbUPU5WQKlo3Zd1Zf/+699cpoEqAmkc3v+wGwJvxHVsAAAB4tdYDW1/xOSKGRWj91PV6e8Db6jSqk3z8fbT6zdUKqhWkjqM6lhwXUDlAcePjNPeRuXo/+X017dRUu9bv0sbZGxX/ZLyqhlQtOfZEzgl98vYnkqRdn++SJK19Z60q2yqrsq2y2t/V/oq7AU/BsAUAAACuUGBQoEYvGq35T8xXxsQMOZ1ONW7XWAkvJKhazWpnHRtxZ4R8/Xy16s1V+ibtG4XUD1HCCwnqcHeHs47Ld+Rr2d+WnfXaqjdWSZJCGoQwbIHfsTidTuefHZSTkyObzabs7GxZrec+nwsAAAAwafPmzWrVqpXGrhqrBjc3MJ3jEvZ/tV8TO07Upk2bFB5e+scYAaaVZofyHVsAAAAAgFvjUmQAAADgAo4fO37B585Kko+vzzmXGgOoeAxbAAAA4AKmJE3Rj+t+vOD7IQ1C9MxXz1RgEYDzYdgCAAAAF5DwXILyHfkXfN8/0L8CawBcCMMWAAAAuIAGLbgRFeAOuHkUAAAAAMCtMWwBAAAAAG6NYQsAAAAAcGsMWwAAAACAW2PYAgAAAADcGsMWAAAAAODWGLYAAAAAALfGsAUAAAAAuDWGLQAAAADArTFsAQAAAABujWELAAAAAHBrDFsAAAAAgFtj2AIAAAAA3BrDFgAAAADg1hi2AAAAAAC3xrAFAAAAALg1hi0AAAAAwK0xbAEAAAAAbo1hCwAAAABwawxbAAAAAIBbY9gCAAAAANwawxYAAAAA4NYYtgAAAAAAt+ZnOgAAAAAoK4e2HzKd4DL4vYA3YdgCAADA7QUFBUmSpo2cZrjE9Zz5vQE8GcMWAAAAbi8sLEzbt29Xbm6u6RSXEhQUpLCwMNMZQLlj2AIAAMAjMOAA78XNowAAAAAAbo1hCwAAAABwawxbAAAAAIBbY9gCAAAAANwawxYAAAAA4NYYtgAAAAAAt8awBQAAAAC4NYYtAAAAAMCtMWwBAAAAAG6NYQsAAAAAcGsMWwAAAACAW2PYAgAAAADcGsMWAAAAAODWGLYAAAAAALfGsAUAAAAAuDWGLQAAAADArTFsAQAAAABujWELAAAAAHBrDFsAAAAAgFtj2AIAAAAA3BrDFgAAAADg1hi2AAAAAAC3xrAFAAAAALg1hi0AAAAAwK0xbAEAAAAAbo1hCwAAAABwawxbAAAAAIBbY9gCAAAAANwawxYAAAAA4NYYtgAAAAAAt8awBQAAAAC4NYYtAAAAAMCtMWwBAAAAAG6NYQsAAAAAcGsMWwAAAACAW2PYAgAAAADcGsMWAAAAAODWGLYAAAAAALfGsAUAAAAAuDWGLQAAAADArTFsAQAAAABuze9SDnI6nZKknJycco0BAAAAAED6v/15Zo9ezCUN29zcXElSgwYNriALAAAAAIDSyc3Nlc1mu+gxFuclzN/i4mIdOHBAQUFBslgsZRYIAAAAAMD5OJ1O5ebmql69evLxufi3aC9p2AIAAAAA4Kq4eRQAAAAAwK0xbAEAAAAAbo1hCwAAAABwawxbAAAAAIBbY9gCAAAAANwawxYAAAAA4NYYtgAAAAAAt/b/AQOrJtjPF1CIAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -320,7 +356,7 @@ "outputs": [ { "data": { - "image/png": "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6urqFh/Dhg0bdN111ykyMlI9evTQz372M5WVlTWY9+mnn+rHP/6xOnXqpCFDhqioqMhv/8cff6xx48YpPDxc0dHRuvvuu/Xll182+bpPP/20BgwYoE6dOik6Olq33npri48BwLkRZAA0aerUqVq1apXv8fPPP68pU6Y0mPfAAw/otdde0wsvvKAPPvhA/fv3V1pamk6cOCFJKi8v1y233KIJEyaopKRE//Ef/6Hf/OY3fmuUlZUpPT1dGRkZ2r17t15++WVt2bJFs2bNanH91dXVys7O1q5du1RYWKiQkBDdfPPNqq+v95s3f/583X///frwww+VkpKiCRMm6Pjx45KkyspKjR49WldddZV27dqlDRs2qKKiQrfddlujr7lr1y7Nnj1bjzzyiEpLS7VhwwaNHDmyxccA4Dzs/OltAMEpMzPTmjhxonXs2DHL6XRahw4dsg4dOmR16tTJ+uKLL6yJEydamZmZlmVZ1unTp62OHTtaa9as8T2/trbWiouLs5YtW2ZZlmXl5ORYiYmJfq+xYMECS5J18uRJy7Isa9q0adY999zjN+cf//iHFRISYp05c8ayLMvq27ev9fjjj5+37qZ88cUXliRrz549lmVZ1sGDBy1J1pIlS3xz6urqrD59+lhLly61LMuyfve731ljx471W6e8vNySZJWWllqWZVk//elPrTlz5liWZVmvvfaa5XK5LI/H02QdAFoPP9QAoEm9evXS+PHjtXr1almWpfHjx6tnz55+c8rKylRXV6ef/OQnvrGOHTtq2LBh2rdvnyRp3759Gj58uN/zUlJS/B5/9NFH2r17t9asWeMbsyxL9fX1OnjwoAYPHtzs+vfv369FixZpx44d+vLLL32fxBw+fFhDhgxptJbQ0FBdc801vto/+ugjbdq0SeHh4Q3WLysr0+WXX+43duONN6pv37669NJLlZ6ervT0dN18883q0qVLs+sHcH4EGQDnNHXqVN/pnby8vDZ7ndOnT+vee+/V7NmzG+xr6cXFEyZMUN++ffXss88qLi5O9fX1GjJkiGpra5tV14QJE7R06dIG+2JjYxuMdevWTR988IE2b96sv//971q0aJEeeugh7dy5U5GRkS06DgBN4xoZAOeUnp6u2tpa1dXVKS0trcH+yy67TGFhYXr//fd9Y3V1ddq5c6cSExMlSYMHD9Y///lPv+dt377d7/HVV1+tvXv3qn///g22sLCwZtd9/PhxlZaWauHChRozZowGDx6skydPNjr3u7V8/fXXKi4u9n0CdPXVV+uTTz7RJZdc0qCurl27NrpeaGioUlNTtWzZMu3evVuHDh3Su+++2+xjAHB+BBkA59ShQwft27dPe/fuVYcOHRrs79q1q2bOnKn58+drw4YN2rt3r6ZPn66vvvpK06ZNkyTNmDFD+/fv1/z581VaWqr8/HytXr3ab50FCxZo69atmjVrlkpKSrR//3799a9/bfHFvt27d1ePHj30zDPP6MCBA3r33XeVnZ3d6Ny8vDytW7dOn376qbKysnTy5ElNnTpV0jf3zTlx4oTuvPNO7dy5U2VlZdq4caOmTJmis2fPNljrjTfe0JNPPqmSkhJ99tlnevHFF1VfX6+BAwe26DgAnBtBBsB5uVwuuVyuJvcvWbJEGRkZuvvuu3X11VfrwIED2rhxo7p37y7pm1NDr732mtavX6/k5GStXLlSf/zjH/3WSEpKUlFRkf7v//5P119/va666iotWrRIcXFxLao5JCREBQUFKi4u1pAhQzRv3jw9+uijTda/ZMkSJScna8uWLfrb3/7muxYoLi5O77//vs6ePauxY8fqyiuv1Ny5cxUZGamQkIZvoZGRkVq7dq1Gjx6twYMHa+XKlXrppZd0xRVXtOg4AJybw7Isy+4iAAAAWoJPZAAAgLEIMgAAwFgEGQAAYCyCDAAAMBZBBgAAGIsgAwAAjEWQAQAAxiLIAAAAYxFkAACAsQgyAADAWAQZAABgrP8HjWjJuiKnxqYAAAAASUVORK5CYII=", + "image/png": "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Li7WjBkzlJSUxDeWAABA8Gdk3n//fS1YsEBz585Vv379muXNc3JyJEkjR44MGM/NzdX06dMlSS+//LJatWql1NRU+Xw+paSk6LXXXmuW9wcAAGYLOsjs2bNHa9eu1ZAhQzRw4EA98cQTeuSRR27pzb/8vabradu2rbKzs5WdnX1L7wUAAG4/QV9aGj58uF5//XWdOXNGTz31lPLz8xUbG6v6+nrt2LFDFy5cCGWdAAAAV2nyt5Y6dOigmTNnas+ePTp8+LCefvpprVy5Uj169NDf/u3fhqJGAACAa7ql58j0799fq1at0ueff678/PyA30gCAAAItSZ9/fpaLly4oLfeekv/+q//quLi4uaoCQAAICjN8kC8n/zkJ4qLi2vOugAAAG6oSUHG6/Vq5cqV6tevnx566CF98cUX2rhxo86cOcPvGwEAgBYX9KWliRMnqqCgQKNGjdJPf/pTTZ48WR06dPBvd7lcISkQAACgMUEHmX//93/XY489poULF+ree+8NZU0AAABBCfrS0r59+9SuXTuNHj1a/fv313PPPacTJ06EsjYAAIDruqkH4i1ZskT/8R//oTvvvFPDhw/Xq6++qvLy8lDWCQAAcJVbeiDekSNHNGLECP385z9XcnJyKOoDAABoVLM9EG/z5s2aMGFCc9UFAABwQ7cUZL7UunVrTZ48Wb/73e+aYzoAAICgNEuQAQAAsANBBgAAGIsgAwAAjEWQAQAAxiLIAAAAYxFkAACAsQgyAADAWAQZAABgLIIMAAAwFkEGAAAYiyADAACMRZABAADGIsgAAABjEWQAAICxCDIAAMBYBBkAAGAsggwAADAWQQYAABiLIAMAAIxFkAEAAMYiyAAAAGMRZAAAgLFsDTK7d+/WxIkTFRsbK5fLpa1btwZsnz59ulwuV8Aybtw4e4oFAACOY2uQqa6u1uDBg5Wdnd3oPuPGjdOZM2f8y1tvvdWCFQIAACcLs/PNx48fr/Hjx193H7fbrejo6KDn9Pl88vl8/vWqqqqbrg8AADib4++R2bVrl3r06KH+/ftr7ty5Onfu3HX3z8rKUkREhH+Ji4troUoBAEBLc3SQGTdunN58800VFBTohRdeUGFhocaPH68rV640+prMzExVVlb6l7KyshasGAAAtCRbLy3dyCOPPOL/8913363ExET16dNHu3bt0pgxY675Grfb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9e3bVykpKTp//rwkqaysTFOmTNHEiRNVUlKiv//7v9ePf/zjgDlOnDihcePGKTU1VYcOHdLbb7+tPXv2aN68eaE/SAAhR5ABYIvHH39ce/bs0WeffabPPvtMe/fu1eOPP+7fXl1drZycHL344osaP368EhIS9Prrr6tdu3Zau3atJCknJ0d9+vTRv/zLv6h///6aNm3aVffXZGVladq0aVq4cKH69eun7373u3rllVf05ptvqqampiUPGUAI/P/8YQYAtuvevbsmTJig9evXy7IsTZgwQd26dfNvP3HihOrq6nT//ff7x9q0aaOhQ4fq6NGjkqSjR49q2LBhAfMmJSUFrP/xj3/UoUOHtGHDBv+YZVmqr6/XyZMnNXDgwFAcHoAWQpABYJuZM2f6L/FkZ2eH5D0uXryop556SgsWLLhqGzcWA+YjyACwzbhx41RbWyuXy6WUlJSAbX369FF4eLj27t2rXr16SZLq6up08OBBLVy4UJI0cOBA/e53vwt4XVFRUcD6PffcoyNHjqhv376hOxAAtuEeGQC2ad26tY4ePaojR46odevWAds6dOiguXPnavHixdq2bZuOHDmi2bNn69KlS5o1a5Ykac6cOTp27JgWL16s0tJS5eXlaf369QHzLFmyRPv27dO8efNUUlKiY8eO6be//S03+wK3CYIMAFt5PB55PJ5rblu5cqVSU1P1xBNP6J577tHx48e1fft2denSRVLDpaHf/OY32rp1qwYPHqw1a9bo5z//ecAciYmJKiws1P/8z//owQcf1He+8x0tX75csbGxIT82AKHnsizLsrsIAACAm8EZGQAAYCyCDAAAMBZBBgAAGIsgAwAAjEWQAQAAxiLIAAAAYxFkAACAsQgyAADAWAQZAABgLIIMAAAwFkEGAAAY6/8AYlKKr5rH46wAAAAASUVORK5CYII=", "text/plain": [ "
" ] @@ -360,7 +396,7 @@ "outputs": [ { "data": { - "image/png": "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Tp1UWlqqVatWKSsrSxs2bFB+fr5WrVqlW2+9VR06dND+/fs1e/ZsDRs2TP369fNn2QAAIAD5NdQcP35cP/zhD1VYWCin06l+/fppw4YNGj16tAoKCvTBBx9o2bJlKi8vV2JioiZNmqSHH37YnyUDAIAAFXBzahpbQ+7JAQAA/2rI9TtgnlMDAABwJQg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEgg1AADAEvwaap5//nn169dPDodDDodDqampev/99z3bKyoqlJ6erg4dOigsLEyTJk1ScXGxHysGAACByq+hJiEhQYsXL1ZOTo52796tESNGaMKECfr4448lSbNnz9af/vQnvfHGG8rOztaxY8d02223+bNkAAAQoGzGGOPvIi4UGRmpJ598UpMnT1ZUVJRWrVqlyZMnS5IOHTqknj17avv27RoyZIhP/blcLjmdTpWUlMjhcDRl6QAAoJE05PodMHNqqqurtXr1apWXlys1NVU5OTmqqqrSqFGjPPv06NFDnTp10vbt2+vsx+12y+VyeS0AAMD6/B5qPvroI4WFhclut+tnP/uZ1q5dq169eqmoqEht2rRRRESE1/4xMTEqKiqqs7/MzEw5nU7PkpiY2MSvAAAABAK/h5qUlBTt3btXO3fu1D333KMpU6bok08+aXB/GRkZKikp8SwFBQWNWC0AAAhUwf4uoE2bNurWrZskaeDAgdq1a5eefvppff/731dlZaVOnz7tNVpTXFys2NjYOvuz2+2y2+1NXTYAAAgwfh+p+aaamhq53W4NHDhQrVu31qZNmzzbcnNzdfToUaWmpvqxQgAAEIj8OlKTkZGhcePGqVOnTiotLdWqVauUlZWlDRs2yOl0avr06ZozZ44iIyPlcDg0c+ZMpaam+vzJJwAAcPXwa6g5fvy4fvjDH6qwsFBOp1P9+vXThg0bNHr0aEnSb37zGwUFBWnSpElyu91KS0vTc88958+SAQBA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Dg7WoEGDPOs9evRQRESEDh48qBtuuEFlZWVasGCB3n33XRUWFurcuXM6e/asjh496tXP9ddff1Hfr7/+up555hnl5+errKxM586dk8Ph8Nqnc+fOXq8rJiZGrVq1uujP6fn3cN++fSorK7toPtXZs2eVn59f5+v09bikpCRFRUV51vv376+RI0eqb9++SktL05gxYzR58mS1b9++znMBviDU4Ko2bNgwpaWlKSMjQ1OnTvXaFhQUdNHF68K5C+e1bt3aa91ms9XaVlNT43NdZWVlGj9+vJYsWXLRtri4OM+v27Vr53OfV6KsrEyS9O677+pb3/qW1za73S5JGjdunD7//HO999572rhxo0aOHKn09HQ99dRT9TrX5d7P859QO/9+rl69Wvfff79+/etfKzU1VeHh4XryySe1c+fOy76mgQMH6tVXX71o24UX4KZw//33a+PGjXrqqafUrVs3hYaGavLkyRdNov3m7+/27dt11113aeHChUpLS5PT6dTq1av161//2mu/+v6ZLCsrU1xcnGeu0YUuNZHb1+O++TpatWqljRs3atu2bfrzn/+sZ599Vg899JB27tzpmX8FNAShBle9xYsXa8CAAUpJSfFqj4qKUlFRkYwxngtpYz5bZseOHRo2bJgk6dy5c8rJydGMGTMkSdddd53++Mc/qnPnzgoObviPqcPhUHx8vLZu3apvf/vbnvatW7fqhhtu8LmfXr16yW636+jRo179fFNUVJSmTJmiKVOm6Oabb9YDDzygp556Sm3atJH09cTbxrZ161bdeOONuvfeez1t3xxdaNOmzUXnvu666/T6668rOjr6opGO8+Li4rRz586Lfp+uu+66S9Z07tw57d692/Me5+bm6vTp0+rZs6en5qlTp+q73/2upK/DwYUTlOuybds2JSUl6aGHHvK0ff7555c97nKuu+46FRUVKTg42Gsi/IXqeg8vd1xdbDabhg4dqqFDh+rRRx9VUlKS1q5dqzlz5jTwVQB8+glQ3759ddddd+mZZ57xar/lllv05Zdf6oknnlB+fr6WL1/u9ambK7V8+XKtXbtWhw4dUnp6uk6dOqUf/ehHkqT09HR99dVXuuOOO7Rr1y7l5+drw4YNmjZtWr2DwQMPPKAlS5bo9ddfV25urn7xi19o7969uu+++3zuIzw8XPfff79mz56tV155Rfn5+dqzZ4+effZZvfLKK5KkRx99VG+99Zby8vL08ccf65133vFcxKOjoxUaGqr169eruLhYJSUl9XoNl5KcnKzdu3drw4YNOnz4sB555BHt2rXLa5/OnTtr//79ys3N1YkTJ1RVVaW77rpLHTt21IQJE/S3v/1NR44cUVZWln7+85/riy++kCTdd999Wrx4sdatW6dDhw7p3nvv1enTpy9bU+vWrTVz5kzt3LlTOTk5mjp1qoYMGeIJOcnJyVqzZo327t2rffv26c477/RpJC85OVlHjx7V6tWrlZ+fr2eeeUZr166t/5v2DaNGjVJqaqomTpyoP//5z/rss8+0bds2PfTQQ9q9e7ekr9/DI0eOaO/evTpx4oTcbrdPx9Vm586d+tWvfqXdu3fr6NGjWrNmjb788kvPnxegoQg1gKTHHnvsootKz5499dxzz2n58uXq37+//v73v1/R3JtvWrx4sRYvXqz+/ftry5Ytevvtt9WxY0dJ8oyuVFdXa8yYMerbt69mzZqliIgIr3kRvvj5z3+uOXPmaO7cuerbt6/Wr1+vt99+W8nJyfXqZ9GiRXrkkUeUmZmpnj17auzYsXr33Xc9twvatGmjjIwM9evXT8OGDVOrVq20evVqSV/PMXnmmWf04osvKj4+XhMmTKjXuS/lpz/9qW677TZ9//vf1+DBg3Xy5EmvURtJuvvuu5WSkqLrr79eUVFR2rp1q9q2bavNmzerU6dOuu2229SzZ09Nnz5dFRUVnpGbuXPn6gc/+IGmTJniubV1fnTlUtq2bat58+bpzjvv1NChQxUWFqbXX3/ds33p0qVq3769brzxRo0fP15paWmXHf2RpH//93/X7NmzNWPGDA0YMEDbtm3TI488Us937GI2m03vvfeehg0bpmnTpql79+66/fbb9fnnn3vmME2aNEljx47V8OHDFRUVpddee82n42rjcDi0efNm3Xrrrerevbsefvhh/frXv9a4ceOu+LXg6mYzl5vxBgDw2cqVKzVr1iyfRnQANC5GagAAgCUQagAAgCVw+wkAAFgCIzUAAMASCDUAAMASCDUAAMASCDUAAMASCDUAAMASCDUAAMASCDUAAMASCDUAAMASCDUAAMAS/h+a8TAoH6v8pwAAAABJRU5ErkJggg==", + "image/png": "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pPvvv18dO3ZUXFyc9u/frzlz5ignJ0dr1qypdX9ut1tut9sz73K5bvhrAAAA/mEzvjzG8gaqqKjQsWPHVFxcrHfffVe/+93vtGXLFk+YudJf//pXjRgxQrm5uerSpUuN+5s3b57mz59/VXtxcbEcDkeD1w8AABqey+WS0+ms8/zt9yDzVSkpKerSpYuWL19+1bKysjJFRERow4YNSk1NrXH7mnpk4uPjCTIAAFiIr0HG75eWvqq6utoriFwpOztbktSuXbtat7fb7bLb7TeiNAAAEGD8GmTS09M1evRodejQQSUlJVq1apUyMzO1ceNG5eXladWqVbrrrrvUqlUr7d+/XzNnztSQIUOUlJTkz7IBAECA8GuQOXnypB588EEVFBTI6XQqKSlJGzdu1J133qn8/Hx9+OGHWrJkicrKyhQfH6/x48frySef9GfJAAAggATcGJmG5us1NgAAEDh8PX8HzH1kAAAA6osgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALMuvQWbZsmVKSkqSw+GQw+FQcnKyPvjgA8/y8vJypaWlqVWrVoqIiND48eNVVFTkx4oBAEAg8WuQad++vRYuXKisrCzt2bNHw4cP19ixY/XJJ59IkmbOnKk//vGPeuedd7RlyxadOHFC99xzjz9LBgAAAcRmjDH+LuJK0dHRev755zVhwgS1adNGq1at0oQJEyRJhw8fVo8ePbRjxw4NGjTIp/25XC45nU4VFxfL4XDcyNIBAEAD8fX8HTBjZKqqqrR69WqVlZUpOTlZWVlZqqysVEpKimed7t27q0OHDtqxY0et+3G73XK5XF4TAABomvweZA4cOKCIiAjZ7Xb99Kc/1dq1a9WzZ08VFhaqefPmioqK8lo/JiZGhYWFte4vIyNDTqfTM8XHx9/gVwAAAPzF70GmW7duys7O1q5duzR16lRNnDhRn3766XXvLz09XcXFxZ4pPz+/AasF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831knnzySa1Zs0Zdu3bVtGnT1K1bN0lfXupZunSpqqqq9MQTT1x3IWlpaTp48KA+/vjj696HJKWnp2vWrFmeeZfLRZgBAKCJ8jnIxMTEaPv27Zo6darS09N1eWiNzWZTamqqli5dqpiYmOsqYtq0afrTn/6krVu3qn379p722NhYVVRU6Pz58169MkVFRYqNja1xX3a7PWDvaQMAABpWve7s27FjR/35z3/WuXPnlJubK2OMEhIS1LJly+s6uDFG06dP19q1a5WZmanOnTt7Le/fv7+aNWumzZs3a/z48ZKknJwcHTt2TMnJydd1TAAA0HTU+xEFktSyZUsNGDDgax88LS1Nq1at0nvvvafIyEjPuBen06mwsDA5nU5NmTJFs2bNUnR0tBwOh6ZPn67k5GSfvrEEAACatut+REGDHNxmq7F9xYoVmjRpkqQvb4g3e/ZsvfXWW3K73UpNTdXLL79c66Wlr+Lr1wAAWI+v52+fg4yvN6Fbs2aNbxU2EoIMAADW4+v52+dLS06ns0EKAwAAaCg+B5kVK1bUuc61bpgHAADQ0Hy+IV5tSkpK9Nvf/lYDBw5Unz59GqImAAAAn1x3kNm6dasmTpyodu3a6YUXXtCwYcO0c+fOhqwNAADgmur19evCwkKtXLlSr732mlwul773ve/J7XZr3bp16tmz542qEQAAoEY+98iMGTNG3bp10/79+7VkyRKdOHFCL7300o2sDQAA4Jp87pH54IMP9LOf/UxTp05VQkLCjawJAADAJz73yHz88ccqKSlR//79NXDgQP3Hf/yHTp8+fSNrAwAAuCafg8ygQYP06quvqqCgQD/5yU+0evVqxcXFqbq6Wps2bVJJScmNrBMAAOAqX+sRBTk5OXrttdf0+9//XufPn9edd96p9evXN2R9Xxt39gUAwHp8PX9/rfvIdOvWTc8995yOHz+u1atXq6ys7OvsDgAAoF6u6+nXVyopKdFbb72l3/3ud8rKymqImgAAAHzSIDfEe+KJJxQfH9+QdQEAANSpXkGmsLBQCxcuVEJCgu666y5dunRJ//3f/62CggLNnz//RtUIAABQI58vLY0ZM0abN2/WsGHDNG/ePI0bN07h4eGe5Tab7YYUCAAAUBufg8z777+v+++/XzNmzNBtt912I2sCAADwic+XlrZv366wsDANHz5c3bp10zPPPKO8vLwbWRsAAMA1XdcN8ebMmaO//OUv6tq1qwYNGqSXXnpJRUVFN7JOAACAqzTYDfGKiopks9lUVVXVkPV9bdwQDwAA62n0G+KtWbNG3/3ud7/O7gAAAOrla/XIWAE9MgAAWE+j9MgAAAD4E0EGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYll+DzNatWzVmzBjFxcXJZrNp3bp1XssnTZokm83mNY0aNco/xQIAgIDj1yBTVlamPn36aOnSpbWuM2rUKBUUFHimt956qxErBAAAgSzEnwcfPXq0Ro8efc117Ha7YmNjG6kiAABgJQE/RiYzM1Nt27ZVt27dNHXqVJ05c8bfJQEAgADh1x6ZuowaNUr33HOPOnfurLy8PP37v/+7Ro8erR07dig4OLjGbdxut9xut2fe5XI1VrkAAKCRBXSQuffeez0/JyYmKikpSV26dFFmZqZGjBhR4zYZGRmaP39+Y5UIAAD8KOAvLV3plltuUevWrZWbm1vrOunp6SouLvZM+fn5jVghAABoTAHdI/NVx48f15kzZ9SuXbta17Hb7bLb7Y1YFQAA8Be/BpnS0lKv3pWjR48qOztb0dHRio6O1vz58zV+/HjFxsYqLy9Pjz/+uG699Valpqb6sWoAABAo/Bpk9uzZo2HDhnnmZ82aJUmaOHGili1bpv379+uNN97Q+fPnFRcXp5EjR2rBggX0uAAAAEmSzRhj/F3EjeRyueR0OlVcXCyHw+HvcgAAgA98PX9barAvAADAlQgyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAskL8XQAA4EtVVVU6fvy4Pv/8c7ndboWHh+uWW25RbGysbDabv8sDApJfe2S2bt2qMWPGKC4uTjabTevWrfNabozR008/rXbt2iksLEwpKSn67LPP/FMsANxAbrdbH374oXbt2qWioiKdP39e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51l++fdUV5D5akg4dOiQkWR27dpV63a9evUyL730kme+Y8eOZty4cbWuf9nzzz9v+vfv75mfO3euadGihXG5XJ621NRU06lTp6s+pxkZGcYYYz766CPjcDhMeXm51767dOlili9f7tnvV/8++Lpds2bNzMmTJz3Ls7KyjCTz+eef1/n6gLqE+KUbCAgQixYt0vDhw/Xoo49e9z569eqloKD/u0obExOj3r17e+aDg4PVqlUrnTx50mu75ORkz88hISG67bbbdOjQIUnSvn379Le//U0RERFXHS8vL09du3aVJPXv3/+atblcLp04cUKDBw/2ah88eLBX939dcnNzdeHCBd15551e7RUVFfrmN78pSZo6darGjx+vvXv3auTIkRo3bpxuv/12n49xWVJSkufny+9dYmKipy0mJkaSvN7PpUuX6vXXX9exY8d08eJFVVRU1Dkwdd++fcrNzVVkZKRXe3l5ufLy8lRcXKyCggINHDjQs+zy78nUcXkpJCREAwYM8Mx3795dUVFROnTokL71rW+ptLRU8+bN0/vvv6+CggJdunRJFy9e1LFjx7z2c9ttt12177ffflsvvvii8vLyVFpaqkuXLsnhcHit06lTJ6/XFRMTo+Dg4Ks+p5ffw3379qm0tPSq8VEXL15UXl5era/T1+06duyoNm3aeOb79OmjESNGKDExUampqRo5cqQmTJigli1b1nosoDYEGdzUhgwZotTUVKWnp2vSpEley4KCgq46YV05FuGyZs2aec3bbLYa26qrq32uq7S0VGPGjNGiRYuuWtauXTvPz+Hh4T7v8+soLS2VJL3//vv6xje+4bXMbrdLkkaPHq0vvvhCf/7zn7Vp0yaNGDFCaWlpeuGFF+p1rLrez8vfLLv8fq5evVqPPvqofvWrXyk5OVmRkZF6/vnntWvXrjpfU//+/fXmm29etezKk+6N8Oijj2rTpk164YUXdOuttyosLEwTJky4aiDsV3+/O3bs0AMPPKD58+crNTVVTqdTq1ev1q9+9Suv9er7mSwtLVW7du08Y4eudK3B2L5u99XXERwcrE2bNmn79u36y1/+opdeeklPPPGEdu3a5RlPBfiKIIOb3sKFC9W3b19169bNq71NmzYqLCyUMcZz8mzIe7/s3LlTQ4YMkSRdunRJWVlZmjZtmiSpX79++sMf/qBOnTopJOT6/5o6HA7FxcVp27Zt+s53vuNp37Ztm771rW/5vJ+ePXvKbrfr2LFjXvv5qjZt2mjixImaOHGivv3tb+uxxx7TCy+8oObNm0v6cvBsQ9u2bZtuv/12Pfzww562r/YiNG/e/Kpj9+vXT2+//bbatm17VY/GZe3atdOuXbuu+j3169fvmjVdunRJe/bs8bzHOTk5On/+vHr06OGpedKkSbr77rslfRkIrhxkXJvt27erY8eOeuKJJzxtX3zxRZ3b1aVfv34qLCxUSEiI12D2K9X2Hta1XW1sNpsGDx6swYMH6+mnn1bHjh21du1azZo16zpfBW5WfGsJN73ExEQ98MADevHFF73ahw4dqlOnTum5555TXl6eli5d6vVtma9r6dKlWrt2rQ4fPqy0tDSdO3dOP/zhDyVJaWlpOnv2rO677z7t3r1beXl52rhxoyZPnlzvMPDYY49p0aJFevvtt5WTk6Of//znys7O1iOPPOLzPiIjI/Xoo49q5syZeuONN5SXl6e9e/fqpZde0htvvCFJevrpp/Xee+8pNzdXn3zyif70pz95Ttxt27ZVWFiYNmzYoKKiIhUXF9frNVxLQkKC9uzZo40bN+rIkSN66qmntHv3bq91OnXqpP379ysnJ0enT59WZWWlHnjgAbVu3Vpjx47VRx99pKNHjyozM1M/+9nPdPz4cUnSI488ooULF2rdunU6fPiwHn74YZ0/f77Ompo1a6bp06dr165dysrK0qRJkzRo0CBPsElISNCaNWuUnZ2tffv26f777/epxy4hIUHHjh3T6tWrlZeXpxdffFFr166t/5v2FSkpKUpOTta4ceP0l7/8RZ9//rm2b9+uJ554Qnv27JH05Xt49OhRZWdn6/Tp03K73T5tV5Ndu3bpl7/8pfbs2aNjx45pzZo1OnXqlOfzAtQHQQaQ9Mwzz1x1IunRo4defvllLV26VH369NHf//73rzWW5qsWLlyohQsXqk+fPvr444+1fv16tW7dWpI8vShVVVUaOXKkEhMTNWPGDEVFRXmNc/DFz372M82aNUuzZ89WYmKiNmzYoPXr1yshIaFe+1mwYIGeeuopZWRkqEePHho1apTef/99z6WA5s2bKz09XUlJSRoyZIiCg4O1evVqSV+OGXnxxRe1fPlyxcXFaezYsfU69rX85Cc/0T333KPvf//7GjhwoM6cOePVOyNJDz30kLp166bbbrtNbdq00bZt29SiRQtt3bpVHTp00D333KMePXpoypQpKi8v9/TQzJ49Wz/4wQ80ceJEz2Wry70o19KiRQvNmTNH999/vwYPHqyIiAi9/fbbnuWLFy9Wy5Ytdfvtt2vMmDFKTU2ts5dHkv71X/9VM2fO1LRp09S3b19t375dTz31VD3fsavZbDb9+c9/1pAhQzR58mR17dpV9957r7744gvPmKTx48dr1KhRGjZsmNq0aaO33nrLp+1q4nA4tHXrVt11113q2rWrnnzySf3qV7/S6NGjv/Zrwc3HZuoatQYA8NnKlSs1Y8YMn3puAHx99MgAAADLIsgAAADL4tISAACwLHpkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZf1/hAG65neKXQcAAAAASUVORK5CYII=", "text/plain": [ "
" ] @@ -389,7 +425,7 @@ "\n", "This shows the relative change in parameters of each model, compared to its predecessor model.\n", "\n", - "N.B.: this may give a misleading impression of the models calibrated in each iteration, since it's only based on \"predecessor model\" relationships. In this example, each layer is indeed an iteration." + "Each column is an iteration." ] }, { @@ -400,7 +436,7 @@ "outputs": [ { "data": { - "image/png": "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44036oMPPpAkVapUKXc9hRYAJeHqq6/Whx9+KCn7A6ijOAcBsM24aHErxjgAAAAALmOMUUxMjC688EL99NNPGjZsmObPn5+v6AIAxSk2NlaNGzfWL7/8os8++0zTp09XjRo1bMcCAJyCY9w6TRgAAADwU5MnT1abNm00Y8YMtW7d2nYcAH5m1qxZat26tSZOnKg2bdrYjgPAzyUmJioyMlI//PGDQsNDbcfJdTjpsK5vcr0SEhIUERFhO04uir0AAACAi2RlZalZs2aqVq2aZs2aZTsOAD/j9Xp12WWXKSgoSAsWLJDjOLYjAfBzR4u9s1bPcl2x94Zzb3BdsZeZvQAAAICLfPbZZ1q9erUGDBhgOwoAPzR+/HgtX75cAwYMoNALAEVo6NChatasmSIiIhQREaGWLVvq+++/z33+yJEj6ty5sypVqqSwsDC1bdtWu3fvLvRxKPYCAAAALpGamqru3bvr/vvv1yWXXGI7DgA/k5GRoa5du+q2227TVVddZTsOAPiUmjVrasCAAVq+fLmWLVum6667TnfddZdWrVolSXrppZf07bffaty4cZo7d6527Nihe+65p9DH4QZtAAAAgEt88MEH2rVrl/r06WM7CgA/NGzYMG3YsEETJkywHQUAjmFyFrc4miUxMTHf+uDgYAUHBx+z/R133JHv5759+2ro0KFatGiRatasqU8++USjR4/WddddJ0kaMWKEmjRpokWLFqlFixYFzkVnLwAAAOAChw4dUr9+/dSpUyc1aNDAdhwAfiY5OVk9e/bUI488ovPPP992HAAoNWrVqqXIyMjcr/79+5/yNVlZWRo7dqwOHz6sli1bavny5crIyNANN9yQu03jxo1Vu3ZtLVy4sFB56OwFAAAAXOD1119XWlqaunfvbjsKAD/0zjvv6ODBg+rVq5ftKABQqmzdujXfDdqO19V71O+//66WLVvqyJEjCgsL08SJE3Xuuefq119/VVBQkMqXL59v+ypVqmjXrl2FykOxFwAAALBs+/btGjx4sF555RVVrVrVdhwAfmbfvn0aOHCgOnfurDp16tiOAwDHZYyRMS4a45CT5egN1wqiUaNG+vXXX5WQkKDx48fr0Ucf1dy5c4s0F8VeAAAAwLKePXuqXLlyevXVV21HAeCH+vbtK8dxFBsbazsKAPi0oKAg1a9fX5J08cUXa+nSpRo8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srJ0wQUXqEqVKpo1a5Ycx7EdCYAfMcbosssuU0BAgBYuXMg5CACKUGJioiIjIzV80XCVC3PPiJyU5BQ93uJxJSQkKCIiwnacXHzcCAAAgFLv888/16pVqzRixAiKLABK3Pjx47Vs2TLNmTOHcxAAFBNjjNzUs+qmLHlxfRsAAABKtSNHjqh79+669957demll9qOA8DPZGRkqGvXrrrlllt09dVX244DAPBzdPYCAACgVPvggw+0Y8cO9e3b13YUAH7ok08+0fr16zVu3DjbUQAAoNgLAACA0uvQoUPq27ev/vOf/6hhw4a24wDwM4cPH1bPnj318MMP64ILLrAdBwB8mslZ3MJNWfJijAMAAABKrYEDByotLU09evSwHQWAH3rnnXd04MAB9e7d23YUAIDL9e/fX5deeqnCw8NVuXJltWnTRmvWrMm3zTXXXCPHcfJ9PfXUU4U6DsVeAAAAlEo7duzQO++8oxdffFHVqlWzHQeAn9m3b58GDhyop59+WmeffbbtOAAAl5s7d646d+6sRYsWaebMmcrIyNCNN96ow4cP59uuU6dO2rlzZ+7XwIEDC3UcxjgAAACgVOrZs6fKli2r1157zXYUAH6oX79+Msaoa9eutqMAgF8wxsgY94xOKGyWadOm5ft55MiRqly5spYvX66rrroqd325cuVUtWrV085FZy8AAABKnTVr1uiTTz5R165dFRkZaTsOAD/z119/6YMPPtCrr76qs846y3YcAIBFiYmJ+b7S0tIK9LqEhARJUsWKFfOtHzVqlKKiotS0aVPFxMQoJSWlUHno7AUAAECp07VrV1WvXl3PPPOM7SgA/FCPHj1UoUIFvfTSS7ajAAAsq1WrVr6fe/Toofj4+JO+xuv16sUXX1SrVq3UtGnT3PUPPfSQ6tSpo+rVq2vFihXq0qWL1qxZowkTJhQ4D8VeAAAAlCqLFy/W119/rZEjRyokJMR2HAB+5vfff9dnn32m999/X2FhYbbjAIDfMDmLWxzNsnXrVkVEROSuDw4OPuVrO3furJUrV2r+/Pn51j/xxBO5359//vmqVq2arr/+em3YsEH16tUrUC6KvQAAACg1jDGKjo5W06ZN9e9//9t2HAB+KDY2Vuecc446depkOwoAwAUiIiLyFXtP5dlnn9WUKVM0b9481axZ86TbXn755ZKk9evXU+wFAACA75k+fbrmzJmjb7/9VgEBAbbjAPAzP/74o6ZMmaKxY8cqMDDQdhwAQClijNFzzz2niRMnas6cOapbt+4pX/Prr79KkqpVq1bg4zjGTbexAwAAAE7A6/XqoosuUnh4uObNmyfHcWxHAuBHjDFq1aqV0tLStHTpUnk83O8cAEpCYmKiIiMj9dGCj1Q2rKztOLlSk1P1RKsnlJCQUKDO3meeeUajR4/W5MmT1ahRo9z1kZGRKlu2rDZs2KDRo0fr1ltvVaVKlbRixQq99NJLqlmzpubOnVvgXHT2AgAAoFQYM2aMfvvtNy1YsIBCL4AS980332jhwoWaMWMGhV4AQKENHTpUknTNNdfkWz9ixAh16NBBQUFBmjVrlt555x0dPnxYtWrVUtu2bRUXF1eo49DZCwAAANdLS0tT48aNdcEFF2jSpEm24wDwM5mZmWrWrJlq1KihmTNn2o4DAH7FVzp7SwqdvQAAAHC9Dz/8UFu2bNF3331nOwoAP/TZZ5/pjz/+0Oeff247CgD4LZOzuIWbsuTFtScAAABwtcTERPXu3VsdOnTQueeeazsOAD+Tmpqq7t27q127drr44ottxwEA4KQo9gIAAMDVBg0apKSkJMXHx9uOAsAPvf/++9q9e7f69OljOwoAAKfEGAcAAAC41u7duzVo0CA999xzqlWrlu04APzMwYMH1a9fP3Xq1En169e3HQcA/JoxRm669ZibsuRFZy8AAABcq3fv3ipTpoxiYmJsRwHgh15//XWlp6ere/futqMAAFAgFHsBAADgShs2bNCHH36o6OhoVaxY0XYcAH5m+/btGjx4sF5++WVVrVrVdhwAAAqEMQ4AAABwpW7duqly5cp6/vnnbUcB4Ifi4+MVGhqqV1991XYUAIAkk7O4hZuy5EWxFwAAAK7z888/a8yYMfroo49Urlw523EA+Jk///xTw4cP16BBgxQREWE7DgAABcYYBwAAALhOTEyMGjVqpMcee8x2FAB+KDY2VrVq1dLTTz9tOwoAAIVCZy8AAABc5YcfftCMGTP09ddfq0wZ/roKoGQtWrRIEydO1Geffabg4GDbcQAAOYwxMsY9oxPclCUvx7g1GQAAAPyOMUaXXXaZAgICtHDhQjmOYzsSAD9ijNE111yjgwcP6pdfflFAQIDtSADg9xITExUZGakhPw5R2bCytuPkSk1O1TNXPqOEhARXjfyhVQIAAACuMX78eC1btkxz5syh0AugxH3//feaN2+evvvuOwq9AIBSiWIvAAAAXCEjI0OxsbG65ZZbdPXVV9uOA8DPZGVlKTo6WldddZVuueUW23EAAP9gcha3cFOWvCj2AgAAwBU++eQTbdiwQePHj7cdBYAfGj16tH7//XdGyAAASjWP7QAAAADA4cOH1bNnTz388MO64IILbMcB4GfS0tLUrVs33X333WrRooXtOAAAnDY6ewEAAGDdO++8o/3796tXr162owDwQ0OHDtXWrVv1/fff244CADgBY4yMcc/oBDdlyYvOXgAAAFi1b98+vf7663rmmWdUt25d23EA+JnExET17dtXjz/+uJo0aWI7DgAAZ4RiLwAAAKzq16+fJKlr166WkwDwR2+++aaSk5MVHx9vOwoAAGeMMQ4AAACw5q+//tIHH3yguLg4nXXWWbbjAPAzu3bt0qBBg/TCCy+oRo0atuMAAE7C5Cxu4aYsedHZCwAAAGu6d++uChUq6KWXXrIdBYAf6t27t4KCgtSlSxfbUQAAKBJ09gIAAMCK33//XZ9//rnef/99hYWF2Y4DwM+sX79eH330kfr166cKFSrYjgMAQJGg2AsAAAArYmJidM4556hTp062owDwQ3FxcapataqeffZZ21EAAAVgjJEx7hmd4KYseVHsBQAAQImbN2+evvvuO40ZM0aBgYG24wDwM8uXL9eXX36pYcOGqWzZsrbjAABQZJjZCwAAgBJljFGXLl100UUX6f7777cdB4Afio6OVpMmTfToo4/ajgIAQJGisxcAAAAlavLkyVq0aJFmzJghj4feAwAla+bMmZo1a5YmTpyoMmV4SwwApYXJWdzCTVny4m/XAAAAKDGZmZmKjY3VDTfcoNatW9uOA8DPeL1eRUdHq2XLlrrrrrtsxwEAoMjxMSYAAABKzKeffqo//vhDn3/+ue0oAPzQuHHj9PPPP2vevHlyHMd2HAAAihzFXgAAAJSI1NRU9ejRQ/fff78uvvhi23EA+Jn09HR17dpVt912m6688krbcQAAhWSMkTHuGZ3gpix5UewFAABAiXjvvfe0e/du9enTx3YUAH5o2LBh2rhxoyZOnGg7CgAAxYaZvQAAACh2Bw8eVP/+/dWpUyc1aNDAdhwAfiY5OVm9evXSI488ovPPP992HAAAig2d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VapUSWFhYWrbtq12795dqONQ7AUAAPBxxhhFR0frvPPOU/v27W3HgYs4wY6cDo5URzLzjMxsI1WRnMccOaH/KPauzn7ezM4p9u7U3z/vzLNPjyPn347UVDKLjcwMI5WTnEcdOVEUe/1VbGyszj77bD3xxBO2owAASinjwqUw5s6dq86dO2vRokWaOXOmMjIydOONN+rw4cO527z00kv69ttvNW7cOM2dO1c7duzQPffcU6jjlDn1JgAAACjNZsyYof/973+aPHmyAgICbMfBaXAudORceOpCqeelwvdyOJGOnHYF2PfdHunuAu6zrCPnLke6q9Bx4IPmz5+vb7/9VqNHj1ZQUJDtOAAAFKnExMR8PwcHBys4OPiY7aZNm5bv55EjR6py5cpavny5rrrqKiUkJOiTTz7R6NGjdd1110mSRowYoSZNmmjRokVq0aJFgfLQ2QsAAODDvF6vunTpolatWumOO+6wHQeAnzHGqEuXLrrwwgvVrl0723EAAChytWrVUmRkZO5X//79C/S6hIQESVLFihUlScuXL1dGRoZuuOGG3G0aN26s2rVra+HChQXOQ2cvAACADxs7dqx+++03/fjjj3IcLqH3FyYlZ9TCiXh0zJgGoDh8++23+umnnzR9+nR5PPQaAQBOnzFGxhRudEJxOppl69atioiIyF1/vK7ef/J6vXrxxRfVqlUrNW3aVJK0a9cuBQUFqXz58vm2rVKlinbt2lXgXBR7AQAAfFR6erri4uJ0xx136F//+pftOChB5ksjbT7JBuUl5yWKvSheWVlZiomJ0XXXXafWrVvbjgMAQLGIiIjIV+wtiM6dO2vlypWaP39+keeh2AsAAOCjPvzwQ/3111/65ptvbEdBCXNucqTUk2wQWGJR4Mc+++wzrV69WiNHjuTKAgAAcjz77LOaMmWK5s2bp5o1a+aur1q1qtLT03Xo0KF83b27d+9W1apVC7x/ir0AAAA+KCkpSb1791b79u1zLw2D/3CqU1iDXampqerevbvuu+8+XXrppbbjAAB8gMlZ3KKwWYwxeu655zRx4kTNmTNHdevWzff8xRdfrMDAQP3www9q27atJGnNmjXasmWLWrZsWeDjUOwFAADwQYMGDVJiYqJ69uxpOwoAP/TBBx9o586d6tu3r+0oAAC4QufOnTV69GhNnjxZ4eHhuXN4IyMjVbZs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Ro0atiMBx7Vz50699dZbevHFF/n3FABQ6hljZIx7Rie4KUteHtsBAAAAfFX37t1VoUIFvfTSS7ajoIjMmzdP1157rerWrat58+ZRQIOr9e7dW8HBwerSpYvtKAAAoIRQ7AUAACgGK1as0BdffKHu3bsrNDTUdhwUge+++0433XSTLrnkEs2aNUuVKlWyHQk4oXXr1umjjz5STEyMypcvbzsOAAAoIRR7AQAAikFMTIzq1aunTp062Y6CIjBmzBi1adNGN998s7777juFh4fbjgScVFxcnKpVq6Znn33WdhQAAIqEceHiRszsBQAAKGJz587V1KlTNXbsWAUGBtqOgzM0dOhQde7cWe3bt9ewYcNUpgx/hYa7LVu2TF999ZU++eQTlS1b1nYcAABQgujsBQAAKELGGHXp0kUXX3yx7rvvPttxcAaMMerXr5+eeeYZPf/88xo+fDiFXpQK0dHROvfcc9W+fXvbUQAAQAnjb6sAAABFaNKkSVq8eLFmzpwpj4fP1UsrY4xee+01vfnmm+rVq5fi4uLkOI7tWMApzZw5Uz/88IMmTZrEhxMAAJ9jjDtHJ7gJ//cHAAAoIpmZmYqNjVXr1q11ww032I6D05SVlaUnn3xSn3zyid59910999xztiMBBeL1etWlSxddccUVuvPOO23HAQAAFlDsBQAAKCIjR47Un3/+qVGjRtmOgtOUlpamhx9+WJMmTdLnn3+uf//737YjAQX21Vdf6ZdfftGPP/5IJzoAAH6KYi8AAEARSElJUXx8vNq1a6eLLrrIdhychuTkZN1zzz2aN2+eJkyYQGckSpX09HR17dpVt99+u/71r3/ZjgMAQJEzOYtbuClLXhR7AQAAisB7772n3bt3q0+fPraj4DQcOHBAt912m1auXKnvv/9e1157re1IQKF8/PHH2rRpkyZPnmw7CgAAsIhiLwAAwBk6cOCABgwYoCeeeEL169e3HQeFtHPnTt14443auXOn/ve//+mSSy6xHQkolOTkZPXq1Uvt27dX06ZNbccBAAAWUewFAAA4QwMGDFBGRoa6detmOwoKadOmTWrdurWOHDmiH3/8UU2aNLEdCSi0t956SwkJCerVq5ftKAAAFBtjjIxxz+gEN2XJy2M7AAAAQGm2bds2vffee3r55ZdVtWpV23FQCKtWrVKrVq3kOI4WLFhAoRel0t69e/XGG2+oc+fOql27tu04AADAMoq9AAAAZyA+Pl5hYWH673//azsKCmHx4sW66qqrVLlyZc2fP1916tSxHQk4LX369JHH41FsbKztKAAAwAUo9gIAAJym1atXa8SIEYqLi1NERITtOCigH374Qddff72aNGmiOXPmqEqVKrYjAadl06ZNGjp0qLp06aJKlSrZjgMAQLEyLlzciGIvAADAaeratatq166tp556ynYUFNDEiRN166236sorr9T06dNVvnx525GA09atWzdVqlRJL7zwgu0oAADAJbhBGwAAwGn46aefNGnSJH3++ecKDg62HQcFMHLkSHXs2FH33nuvPv/8cwUFBdmOBJy23377TaNHj9bQoUMVGhpqOw4AAHAJir0AAACFZIxRdHS0mjVrpoceesh2HBTAO++8o5deeklPPPGEhgwZooCAANuRgDMSExOj+vXr6/HHH7cdBQCAEmGMkTHuGZ3gpix5UewFAAAopKlTp+rHH3/U1KlT5fEwFcvNjDGKj49Xr1691KVLF/Xv31+O49iOBZyROXPm6Pvvv9e4ceMUGBhoOw4AAHARx7i1DA0AAOBCWVlZat68uSpVqqT//e9/FA5dzOv16sUXX9R7772nAQMGqEuXLrYjAWfMGKMWLVrIGKPFixdzDgIA+LzExERFRkaq41cdFVTOPWO40lPS9cn9nyghIcFVN2umsxcAAKAQRo0apZUrV2rhwoUUWVwsIyNDjz/+uEaNGqUPP/xQTzzxhO1IQJGYMGGClixZoh9++IFzEADAr5icxS3clCUvir0AAAAFdOTIEXXr1k333HOPWrRoYTsOTiA1NVXt2rXTtGnTNGbMGLVr1852JKBIZGZmqmvXrrrpppt03XXX2Y4DAABciGIvAABAAQ0dOlTbtm3T9OnTbUfBCSQmJurOO+/UkiVL9M033+jmm2+2HQkoMiNGjNCaNWs0ZswY21EAAIBLUewFAAAogISEBPXp00cdO3ZU48aNbcfBcezbt08333yz1q9fr5kzZ6pVq1a2IwFFJiUlRT169NBDDz2kCy+80HYcAABKnDFGbrr1mJuy5EWxFwAAoADeeOON3GIL3Gfbtm1q3bq1Dhw4oLlz5+qCCy6wHQkoUu+++6727dun3v/f3n3HVVn+fxx/HzaioLhQM0eOXKk5ytTUEnffsuEqZ/mrTNvlzIHb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AAAgB6PYCwAAHJphGOrTp48qV66sl156yew4Dmfy5Mnq2bOnOnfurK+++kpubrw9BDKqX79+Kl26tLp37252FAAAnJZhGDIM67ROsFKW1Hg3DwAAHNqvv/6q4OBgLV26VK6urmbHcRiGYWj48OH66KOP9Pbbb2vcuHFycaHDF5BRGzZs0M8//6w5c+bI3d3d7DgAACCHsxlWLUMDAADcht1u18MPP6w8efJo/fr1stlsZkdyCIZh6P3339cnn3yioUOHqn///rx2wF0wDEN169ZVbGystm7dygUTAACyQGRkpPz8/PTsd8/KPZd1LqzGR8frh84/KCIiQr6+vmbHScHKXgAA4LDmzJmjP//8U6GhoRQr71BCQoL+7//+T99++60mTpyonj17mh0JcFhLly7Vxo0btXLlSgq9AABkMePawyqslCU1ir0AAMAhxcbGasCAAXr66af12GOPmR3HIcTGxqpDhw5asmSJZs6cSY9j4B4kJCSob9++aty4sQIDA82OAwAAIIliLwAAcFBffvmljh8/rmXLlpkdxSFcuXJFrVu31oYNG7R48WI99dRTZkcCHNqMGTO0b98+zZw50+woAAAAKSj2AgAAh3P58mUNGzZMXbp0UcWKFc2OY3kXL15UixYttHfvXq1YsUINGzY0OxLg0GJiYjRw4EC1bdtWNWrUMDsOAAA5gmEYstKtx6yUJTWKvQAAwOGMGzdOkZGRGjx4sNlRLO/06dNq0qSJTp8+rTVr1qhmzZpmRwIc3qRJk3T27FkNGzbM7CgAAABpUOwFAAAO5ezZsxo7dqx69eql4sWLmx3H0v755x8FBgYqLi5OGzZsUIUKFcyOBDi8S5cuaeTIkerevbvKlCljdhwAAIA0KPYCAACHMmzYMLm5ualv375mR7G0PXv2qEmTJvLx8VFISIhKlChhdiTAKYwePVqxsbEaOHCg2VEAAMhRjGsPq7BSltRczA4AAABwpw4fPqwvvvhCffr0kb+/v9lxLGvz5s16/PHHVahQIQq9QCY6efKkPv30U7377rsKCAgwOw4AAEA6FHsBAIDD+Oijj1SoUCG9+eabZkexrN9++01PPvmkKlasqODgYBUuXNjsSIDTGDx4sHx8fPTBBx+YHQUAAOCGaOMAAAAcwo4dOzRnzhxNnTpVuXLlMjuOJf3www9q3769nnjiCS1atIjX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", + "image/png": "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0aJFGjt2bLnyMI0DAADwCPPnz5ck3XPPPdYGQY2bMGGCnnzySS1YsEAPP/yw1XFq1ODBg/Xss8/qqaee0tVXX6277rrL6kgAAADVwizY7KIwS1JSkoKCgoqO+/n5lfq506ZN0/fff6+NGzeWOB4TE1P056uuukoNGzZU3759tX//frVu3bpMuRjZCwAA3J5pmpo1a5aGDRum0NBQq+OghoWGhioqKqrWLdRW6Mknn1RkZKTGjh2rH374weo4AAAAtUpQUFCJvbSy995779XatWv1ySefqEmTJhc99/rrr5ck7du3r8x5KHsBAIDb++STT7R37145HA6ro8AiDodDe/fu1SeffGJ1lBrn5eWlBQsWqGnTphoyZIhOnTpldSQAAACcxTRN3XvvvVq9erXWr1+vli1blvo533zzjSSpYcOGZb4PZS8AAHB7TqdTHTp00M0332x1FFikV69eat++fa1bqK1QYGCg1qxZo99//11jxoxRXl6e1ZEAAACqlplfmNplL++MEtOmTdPixYsVHx+vwMBAJScnKzk5WWfOnJEk7d+/X//v//0/ffXVVzp48KDeeustjR8/Xr169VLnzp3LfB/KXgAA4NaOHDmihIQEFmar5QoXalu9erWOHj1qdRxLtGnTRkuXLtX777+vp59+2uo4AAAAKObNN99USkqKevfurYYNGxbty5YtkyT5+vrqo48+Uv/+/dW+fXs9/PDDioqK0ttvv12u+7BAGwAAcGvz5s1TnTp1NH78eKujwGL33HOPpk+frnnz5unxxx+3Oo4lbr/9ds2YMUOPP/64rr76ag0bNszqSAAAAJBKXVuiadOm2rBhQ6Xvw8heAADgtlwul2JjYzV8+HCFhIRYHQcWCwkJ0fDhwzVr1iy5XC6r41jm0Ucf1YgRIzRhwgR99913VscBAACoEqYNNzui7AUAAG7ro48+0oEDB1iYDUUcDocOHDigjz/+2OooljEMQ3PmzFGbNm00ZMgQnThxwupIAAAAqCGUvQAAwG05nU516tRJPXr0sDoKbOLGG29Ux44da+1CbYXq16+vxMREpaamauTIkcrNzbU6EgAAAGoAZS8AAHBLhw8f1po1a+RwOFiYDUUMw5DD4dCaNWuUnJxsdRxLtWjRQsuWLdP69es1ffp0q+MAAABUimmattvtiLIXAAC4pblz58rX11djx461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KaY3adLEolQoiNIXX5w5c6a1QZBv2rdvr1deeUUvvviiVqxYYXUcAADylWmatnvaEcVeAADciGmamjx5sjp37qxSpUpZHcdt9erVS//73/9kmqYcjku3U4ULF1aNGjUsToaCpFSpUurUqZMmT55s2182kPuef/55dezYUb169dLevXutjgMAAGyGYi8AAG7kiy++0IEDB1iYLY/t3r1b//vf/9ShQwc1btxYktSoUSN5eHhYnAwFTUREhPbv36/169dbHQX5xOFwaObMmapYsaI6dOigc+fOWR0JAADYCMVeAADcSGRkpO644w56x+ahM2fOKDg4WNWqVdPcuXO1fv16jRo1SiNGjLA6Ggqge++9VzVq1NCkSZOsjoJ85Ofnp+XLl+vkyZPq2bNnpt7hAAC4K9OGDzui2AsAgJs4ceKEli5dysJseSg1NVXdunVTbGysYmJiVKRIEXl5eemll17SI488YnU8FEDpC7UtW7ZMJ0+etDoO8lG1atU0f/58ffrppxo1apTVcQAAgE1Q7AUAwE1Mnz5dHh4e6tOnj9VR3NbIkSO1bt06RUdHq3LlylbHASRdWozR4XBo+vTpVkdBPmvbtq3GjBmjV199VYsXL7Y6DgAAsAGKvQAAuAGn06moqCiFhoaqRIkSVsdxS/PmzdO4ceM0btw4tW7d2uo4QIYSJUqoS5cumjx5spxOp9VxkM+effZZhYaGKiwsTLt377Y6DgAAecY0Tds97YhiLwAAbuDzzz/Xr7/+ysJseWT79u3q37+/evfurSeeeMLqOEAWERER+vXXX7V27VqroyCfGYahqVOnqlq1agoODtaZM2esjgQAACxEsRcAADcQGRmpWrVqqWnTplZHcTt//vmnOnbsqFq1aikyMpJ+yLClZs2a6c4771RkZKTVUWCBIkWKKCYmRrGxserWrZtSU1OtjgQAACxCsRcAABf3xx9/aPny5YqIiKAQmctSUlLUtWtXXbhwQUuXLpWvr6/VkYBsGYahQYMGafny5Tp+/LjVcWCBypUrKzo6WuvWrdN///tfq+MAAJDrTBs+7IhiLwAALm7atGny8vJSr169rI7idp555hlt2LBBixcvVsWKFa2OA1xV79695enpqWnTplkdBRZp3bq1xo0bpzfffFPz5s2zOg4AALAAxV4AAFxYWlqaoqKi1K1bNxUrVszqOG5l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WxZBU1JS1LVrV128eFFLly6Vr6+v1ZEA2IRhGIqIiNDy5ct1/Phxq+OggKlcubKio6O1bt06/fe//7U6DgAAlqPYCwBALpg2bZq8vLzUq1cvq6PkiaefflobN27U4sWLVbFiRavjALCZ3r17y9PTU9OmTbM6Cgqg1q1ba9y4cXrzzTc1b948q+MAAPKIacOHHVHsBQDgJqWlpSkqKkrdunVTsWLFrI6T66ZPn673339f48ePV4sWLayOA8CGihUrptDQUEVFRbFQGyzxxBNPqE+fPurfv7+2b99udRwAACxDsRcAgJu0evVqHT582C0XZtuyZYsGDRqkgQMHatCgQVbHAWBjEREROnTokFavXm11FBRAhmFo0qRJqlWrljp27Kg///zT6kgAAFiCYi8AADcpMjJStWvXVqNGjayOkquOHz+ukJAQ1a9fX++//75b9iIGkHsaN26su+++m4XaYBlfX18tXbpUFy5cUNeuXZWSkmJ1JABALjJN03ZPO6LYCwDATfj999/18ccfu93CbMnJyerUqZNM09SSJUvk7e1tdSQANpe+UNtHH32kY8eOWR0HBVTFihW1ePFibdiwQc8884zVcQAAyHcUewEAuAlTp06Vj4+PevbsaXWUXDVs2DBt27ZNS5cuVdmyZa2OA8BF9OzZU97e3po6darVUVCAtWjRQuPHj9f48eM1Y8YMq+MAAJCvKPYCAHCD0tLSNGXKFHXv3l3+/v5Wx8k1kZGRmjx5sj788EM1adLE6jgAXEhAQIC6d++uqKgopaWlWR0HBdigQYM0YMAADRo0SN9++63VcQAAucC04cOOKPYCAHCDPv30Ux09etStFmbbsGGDhg0bpiFDhqhfv35WxwHggiIiInT06FGtWrXK6igowAzD0IQJE1S3bl2FhITo+PHjVkcCACBfUOwFAOAGRUZGql69emrQoIHVUXLFb7/9ps6dO6tp06Z65513rI4DwEU1aNBAdevW1aRJk6yOggLO29tbS5YskdPpVOfOnZWcnGx1JAAA8hzFXgAAbsCRI0f0ySefuM2s3gsXLigkJEReXl5atGiRPD09rY4EwEWlL9T2ySef6OjRo1bHQQFXrlw5LV26VFu3btXw4cOtjgMAuAmmadruaUcUewEAuAFTpkxR4cKF1b17d6uj3DTTNDVo0CDt3r1by5YtU2BgoNWRALi4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2r17t/r06aNy5copODg4R+eh2AsAcHuzZs2S0+lUWFhYvp979OjRiomJ0dy5c1WjRo18Pz8AuIu+ffvK6XRq1qxZVkcB8kRISIheeOEFPffcc1q1apXVcQAAuWzbtm2qW7eu6tatK0l66qmnVLduXb344ouSpGeffVbDhg1TeHi4GjZsqPj4eK1atUo+Pj45Oo9h8hkRAIAbM01Td9xxh+rUqaMFCxbk67lXrFihDh066JVXXtH//d//5eu5AcAdhYaGateuXdqzZ48Mw7A6DpDrnE6nOnTooA0bNujbb79V9erVrY4EAJaLi4tTQECAmn3QTIV8C1kdJ0NqUqo2Dt6o2NhY+fv7Wx0nAzN7AQBu7auvvtK+ffvyfWG2n376Sb169VJISIief/75fD03ALiriIgI7d27V19//bXVUYA84XA4NGfOHJUpU0bBwcE6f/681ZEAAC6GYi8AwK1FRkbqtttuU6tWrfLtnOfOnVOHDh1UqVIlzZgxgwXZACCX3HfffapevToLtcGtBQQEKCYmRkePHlWfPn3kdDqtjgQAcCH89gkAcFunTp3SkiVLFB4enm8f901LS1PPnj31559/KiYmRn5+fvlyXgAoCAzDUHh4uBYvXqxTp05ZHQfIMzVq1NDcuXMVExOjV1991eo4AGALpg0fdkSxFwDgtmbMmCFJeuyxx/LtnC+++KJWrVqlBQsWqFq1avl2XgAoKNIX25w5c6a1QYA81r59e73yyit68cUXtWLFCqvjAABcBMVeAIBbMk1TkydPVufOnVWqVKl8OeeiRYv02muvacyYMXrooYfy5ZwAUNCUKlVKnTp10uTJk8Va03B3zz//vDp27KhevXpp7969VscBALgAir0AALf0xRdf6MCBA/m2MNuuXbsUFham0NBQjRgxIl/OCQAFVUREhPbv36/169dbHQXIUw6HQzNnzlSlSpXUoUMHxcbGWh0JACxjmqbtnnZEsRcA4JYiIyN1xx13qEWLFnl+rjNnzig4OFjVq1fX1KlT860/MAAUVPfee69q1KihSZMmWR0FyHN+fn6KiYnRyZMn1bNnT6WlpVkdCQBgYxR7AQBu58SJE1q2bFm+LMyWmpqqbt26KS4uTjExMSpSpEieng8AcGmhtoiICC1btkwnT560Og6Q56pVq6YFCxbo008/1ahRo6yOAwCwMYq9AAC3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xowZuv322/XHH3/o5ZdfVosWLfTDDz/Iz88v13JR7IXLKl26tKpXr66NGzdmFHt37NihxMRE3XPPPZmKvaZp6s0339SPP/6o++67T5UrV9b333+vOXPm6MyZM3rssccyjo2MjNTXX3+tZs2a6fbbb9cPP/yg119/Pcv5z507pxdeuPTRoYceekj+/v7auXOnJk2apMTERLVr1y6P/wYA15Lez+jyN1euxOFw3FD/I6BAy8klQ/cGIOfSr7HruH4MBxcZkBPcJwJwZUePHpW//9/tna40q/fhhx/O+O+7775bjRs31i233KKFCxdecZLhjaDYC5fWvHlzzZ8/X8nJyfLy8tKGDRt05513qkSJEpmO27Ztm3744QeFhoYqJCRE0qUC7dtvv61PP/1UDz30kIKCgnTo0CF9/fXXatOmTcaF9tBDD2n8+PE6cuRIpjEXLFggp9OpN998M+MdmAcffFDvvfeeFi9erAcffFBeXtee+QEUFE7npcWiHI5rrw1qGIbS0tLyOhLgXnJQiMp0PIDrklFcus5rzHRykQHXi/tEAK7M398/U7H3ehUrVky33Xabfv7551zNc+3/kwI21rRpUyUnJ+u7775TUlKStm/frmbNmmU5bseOHXI4HJneRZGkRx99VKZpZvQG3bFjhyRlOe6RRx7J9LVpmvr2229Vr149maapuLi4jGft2rWVmJioX3/9NRe/U8D1HTt2TNKlH2jXEhAQoD/++COPEwHuxTz/V2HJ5zoO9pFEpxQgR5LPJkuSChW+9nyZQoULKTk2Oa8jAW4j/b4vICDgmsf6+/vr+B/H8zoSABsyTdN2z5sRHx+vX375RWXLls2lv6FLmNkLl+bv76+77rpLGzduVHJyspxOp5o0aZLluFOnTql48eLy9fXNtL1ChQoZ+9P/NAwjS0/RcuXKZfo6Li5OCQkJWrt2rdauXZtttn826AYKqnPnzumXX37R22+/LX9/fzVs2PCar2nZsqWWL1+uCRMmqEOHDgoKCpKnp2c+pAVcj5lkSmclc5MpeUsqf+3XGLcYMveacm5xyqhhSEUlw4OPnQPZSUlIUdLJJB357Ig8fD3kX+XaM3eK3V5Mp7af0m9rflOpeqXkFeAlRyHm2QD/dO7cOR389aAmvjdR/v7+qteg3jVf06xFM638aKUiP4hUu/btVCaoDPeJAFzCM888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", "text/plain": [ "
" ] From 49dc4a9b56b41aa44d4e0e193cf839322882dfab Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Fri, 13 Dec 2024 23:11:30 +0100 Subject: [PATCH 17/88] doc analysis methods briefly --- doc/analysis.rst | 11 +++++++++++ doc/index.rst | 1 + 2 files changed, 12 insertions(+) create mode 100644 doc/analysis.rst diff --git a/doc/analysis.rst b/doc/analysis.rst new file mode 100644 index 00000000..96d712ba --- /dev/null +++ b/doc/analysis.rst @@ -0,0 +1,11 @@ +Analysis +======== + +After using PEtab Select to perform model selection, you may want to operate on all "good" calibrated models. +The PEtab Select Python library provides some methods to help with this. Please request any missing methods. + +See the Python API docs for the ``Models`` class, which provides some methods. In particular, ``Models.df`` can be used +to get a quick overview over all models, as a pandas dataframe. + +Additionally, see the Python API docs for the ``petab_select.analysis``, which contains some methods to subset and group models, +or compute "weights" (e.g. Akaike weights). diff --git a/doc/index.rst b/doc/index.rst index 697bcba6..13a26268 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -59,6 +59,7 @@ interfaces, and can be installed from PyPI, with: problem_definition examples + analysis Test Suite api From 3ec430b7cdfc95e8a2602df8caf2ae8dcde2ee36 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Fri, 13 Dec 2024 23:14:07 +0100 Subject: [PATCH 18/88] typo --- doc/analysis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/analysis.rst b/doc/analysis.rst index 96d712ba..1f06b66e 100644 --- a/doc/analysis.rst +++ b/doc/analysis.rst @@ -7,5 +7,5 @@ The PEtab Select Python library provides some methods to help with this. Please See the Python API docs for the ``Models`` class, which provides some methods. In particular, ``Models.df`` can be used to get a quick overview over all models, as a pandas dataframe. -Additionally, see the Python API docs for the ``petab_select.analysis``, which contains some methods to subset and group models, +Additionally, see the Python API docs for the ``petab_select.analysis`` module, which contains some methods to subset and group models, or compute "weights" (e.g. Akaike weights). From 94323584031d0343aa9740e466e7e62e1919c045 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sat, 14 Dec 2024 00:04:16 +0100 Subject: [PATCH 19/88] move models criterion getter to `Models`; add `Models.values()` for backwards compatibility; update plot code --- doc/examples/visualization.ipynb | 182 +++++++++++++++---------------- petab_select/analyze.py | 21 +--- petab_select/models.py | 37 +++++++ petab_select/plot.py | 59 ++++------ 4 files changed, 151 insertions(+), 148 deletions(-) diff --git a/doc/examples/visualization.ipynb b/doc/examples/visualization.ipynb index 1d038379..8010b31e 100644 --- a/doc/examples/visualization.ipynb +++ b/doc/examples/visualization.ipynb @@ -17,7 +17,7 @@ "\n", "All dependencies for these plots can be installed with `pip install petab_select[plot]`.\n", "\n", - "Here, some calibrated models that were saved to disk with `petab_select.model.models_to_yaml_list` are loaded and used as input. This is the result of a forward selection with the problem provided in `calibrated_models`." + "In this notebook, some calibrated models that were saved to disk with the `to_yaml` method of a `Models` object, are loaded and used as input here. This is the result of a forward selection with the problem provided in `calibrated_models`. Note that a `Models` object is expect here; if you have a list of models `model_list`, simply use `models = Models(model_list)`." ] }, { @@ -48,140 +48,140 @@ "data": { "text/html": [ "\n", - "\n", + "
\n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
 model_idmodel_hashCriterion.NLLHCriterion.AICCriterion.AICCCriterion.BICiterationpredecessor_model_hashestimated_parametersmodel_idmodel_hashCriterion.NLLHCriterion.AICCriterion.AICCCriterion.BICiterationpredecessor_model_hashestimated_parameters
0M_0-000M_0-00017.487615None37.975230None1virtual_initial_model-{'sigma_x2': 4.462298422134608}0M_0-000M_0-00017.487615None37.975230None1virtual_initial_model-{'sigma_x2': 4.462298422134608}
1M_1-000M_1-000-4.087703None-0.175406None2M_0-000{'k3': 0.0, 'sigma_x2': 0.12242920113658338}1M_1-000M_1-000-4.087703None-0.175406None2M_0-000{'k3': 0.0, 'sigma_x2': 0.12242920113658338}
2M_2-000M_2-000-4.137257None-0.274514None2M_0-000{'k2': 0.10147824307890803, 'sigma_x2': 0.12142219599557078}2M_2-000M_2-000-4.137257None-0.274514None2M_0-000{'k2': 0.10147824307890803, 'sigma_x2': 0.12142219599557078}
3M_3-000M_3-000-4.352664None-0.705327None2M_0-000{'k1': 0.20160925279667963, 'sigma_x2': 0.11714017664827497}3M_3-000M_3-000-4.352664None-0.705327None2M_0-000{'k1': 0.20160925279667963, 'sigma_x2': 0.11714017664827497}
4M_5-000M_5-000-4.352664None9.294673None3M_3-000{'k1': 0.20160925279667963, 'k3': 0.0, 'sigma_x2': 0.11714017664827497}4M_5-000M_5-000-4.352664None9.294673None3M_3-000{'k1': 0.20160925279667963, 'k3': 0.0, 'sigma_x2': 0.11714017664827497}
5M_6-000M_6-000-5.073915None7.852170None3M_3-000{'k1': 0.20924804320838675, 'k2': 0.0859052351446815, 'sigma_x2': 0.10386846319370771}5M_6-000M_6-000-5.073915None7.852170None3M_3-000{'k1': 0.20924804320838675, 'k2': 0.0859052351446815, 'sigma_x2': 0.10386846319370771}
6M_7-000M_7-000-6.028235None35.943530None4M_3-000{'k1': 0.6228488917665873, 'k2': 0.020189424009226256, 'k3': 0.0010850434974038557, 'sigma_x2': 0.08859278245811462}6M_7-000M_7-000-6.028235None35.943530None4M_3-000{'k1': 0.6228488917665873, 'k2': 0.020189424009226256, 'k3': 0.0010850434974038557, 'sigma_x2': 0.08859278245811462}
\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -320,7 +320,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA7YAAAOwCAYAAAAKo+iFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADRYUlEQVR4nOzddVhUaf8G8HtIFQG7E2UMTGzFosUWFRNz7e4EsTuxgwUM7Aal1FVW7FxWwe5YgxDJmd8f+8JP1gKc4Zm4P9e11/ty5sw5N1y7wM33nOdI5HK5HERERERERERqSkd0ACIiIiIiIqJfwWJLREREREREao3FloiIiIiIiNQaiy0RERERERGpNRZbIiIiIiIiUmsstkRERERERKTWWGyJiIiIiIhIrbHYEhERERERkVrTy8xOMpkML168gLGxMSQSibIzERERERERkZaTy+WIjY1FiRIloKPz45lsportixcvULp0aYWEIyIiIiIiIsqsp0+folSpUj/cJ1PF1tjYOP2AJiYmv56MiIiIiIiI6AdiYmJQunTp9D76I5kqtmmXH5uYmLDYEhERERERUY7JzO2wXDyKiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1BqLLREREREREak1FlsiIiIiIiJSayy2REREREREpNZYbImIiIiIiEitsdgSERERERGRWmOxJSIiIiIiIrXGYktERERERERqjcWWiIiIiIiI1Jqe6ABEREREPxIVFYXY2FjRMVSKsbExzM3NRccgIlIZLLZERESksqKioiCVSkXH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9lRQUJCmTp3qEc+DDQoK0vLly3X77bcrKipKa9eu1dVXX206CwDwO9yIChWJ79iiTO3du1edOnVSlSpVtGLFCtWqVct0EgBJVapUUf/+/TV16lQVFxebzikTNWrUUGZmpvz8/BQZGalDhw6ZTgIAAIYwbFFmfvrpJ3Xs2FF+fn5auXKl6tatazoJwO/Y7Xbt2bNHH3/8semUMlOvXj1lZWUpLy9PXbp00bFjx0wnAQAAAxi2KBMHDx5Up06dVFRUpJUrV+qqq64ynQTgD9q1a6frrrtOKSkpplPKVKNGjZSZman9+/crPj5ex48fN50EAAAqGMMWV+zQoUPq1KmT8vPztWrVKjVs2NB0EoDzsFgsstvtmjt37kVv5uGOrr/+eqWlpenrr79Wz549derUKdNJAACgAjFscUV+++03RUZGKjs7W6tWreImAYCLS0pK0vHjxzVv3jzTKWXur3/9qxYvXqyPP/5YgwYNUmFhoekkAABQQRi2uGxHjx5VVFSUfv31V61YsUJhYWGmkwD8iYYNG6pTp05KTU01nVIu7rjjDs2dO1eLFi3SXXfd5TE3ygIAABfHsMVlcTgcio6O1v79+7VixQo1a9bMdBKAS2S327Vq1Srt2bPHdEq56Nq1q6ZOnarU1FQ9+OCDcjqdppMAAEA5Y9ii1HJychQbG6tdu3YpKytLN9xwg+kkAKXQu3dvVatWTVOnTjWdUm4GDhyoN998U6+99ppHPLcXAABcHMMWpZKXl6f4+Hh99913yszMVIsWLUwnASilqlWrqk+fPkpNTfXoTzPvvvtuvfjii5owYYL++c9/ms4BAADliGGLS5afn69u3bppy5YtSktLU6tWrUwnAbhMycnJ2rVrl9auXWs6pVw99thjGjdunB566CFNmTLFdA4AACgnfqYD4B5OnjyphIQEbdiwQenp6WrTpo3pJABXoH379rr22muVmpqq9u3bm84pVy+++KIcDofuuusu2Ww29e7d23QSAAAoY3xiiz916tQp9e7dW2vXrtXSpUsVERFhOgnAFfLx8VFSUpJmz56t/Px80znlymKx6I033lD//v01cOBApaenm04CAABljGGLiyooKFC/fv20YsUKLVy4UHfccYfpJABlJCkpSbm5uZo/f77plHLn6+ur1NRURUdHq2fPnlq3bp3pJAAAUIYYtrigwsJCDRo0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NH78eNM5AAAvx7AFABhlt9uVnZ2thQsXmk5BKQ0bNkyvvvqqXnrpJb300kumcwAAXszPdAAAwLs1adJEt912m1JTU9W/f3/TOSilBx98UA6HQ48//riCg4N19913m04CAHghhi0AwDi73a577rlHBw4cUL169UznoJT+3//7f3I4HLr33ntltVo1aNAg00kAAC/DpcgAAOP69eungIAATZs2zXQKLoPFYtE///lPJSUlKSkpSYsXLzadBADwMgxbAIBxwcHBSkhI4Jm2bszHx0fvvvuuunfvrr59+2r16tWmkwAAXoRhCwBwCcnJydq2bZs2btxoOgWXyc/PTzNmzNDtt9+ubt266YsvvjCdBADwEgxbAIBLiIyMVL169ZSammo6BVegUqVKmj9/vm688UbFxMTo22+/NZ0EAPACDFsAgEs480zbDz/8UKdOnTKdgytQtWpVLV26VFdddZWioqK0a9cu00kAAA/HsAUAuAy73a5jx45x8yEPEBISooyMDFWtWlVRUVE6cOCA6SQAgAdj2AIAXEazZs3UunVrLkf2ELVr11ZWVpYKCgoUHR2tI0eOmE4CAHgohi0AwKUkJydr+fLlOnTokOkUlIGGDRsqMzNThw4dUmxsrHJzc00nAQA8EMMWAOBSBgwYIF9fX02fPt10CspI06ZNlZ6erh9++EHdu3fXiRMnTCcBADwMwxYA4FJCQkLUo0cPvf/++zzT1oOEh4dryZIl+vzzz9W/f3+dPn3adBIAwIMwbAEALic5OVnffPONvvzyS9MpKEPt27fXRx99pLS0NCUnJ6u4uNh0EgDAQzBsAQAuJzo6WnXq1OEmUh4oJiZG06dP18yZMzV69Gg+lQcAlAmGLQDA5fj5+SkxMVHTp09XQUGB6RyUsb59++rtt9/WW2+9pSeeeMJ0DgDAAzBsAQAuyW6368iRI1q2bJnpFJSDO++8UxMnTtSLL76ov//976ZzAABuzs90AAAA53PDDTeoVatWSklJUUJCgukclIOHHnpIDodDjz32mIKDgzVy5EjTSQAAN8WwBQC4rOTkZD344IM6fPiwQkNDTeegHEyYMEEOh0P33HOPrFarBg4caDoJAOCGuBQZAOCyBg4cKIvFog8//NB0CsqJxWLRv/71Lw0ZMkRJSUlaunSp6SQAgBti2AIAXFaNGjXUrVs3paSkmE5BOfLx8dF7772nrl27qk+fPlqzZo3pJACAm2HYAgBcWnJysrZs2aKvvvrKdArKkZ+fn2bMmKF27dqpW7du2rhxo+kkAIAbYdgCAFxaTEyMQkNDeaatFwgMDNSCBQvUvHlzxcTEaNu2baaTAABugmELAHBp/v7+SkxM1LRp03T69GnTOShn1apV07Jly1SvXj1FRUVp9+7dppMAAG6AYQsAcHl2u12HDx9WWlqa6RRUgOrVqysjI0OVK1dWZGSkDh48aDoJAODiGLYAAJd38803q0WLFtxEyovUqVNHWVlZOnXqlKKionTkyBHTSQAAF8awBQC4heTkZC1evJiB40WuueYaZWZm6tChQ4qLi1Nubq7pJACAi2LYAgDcwqBBg+R0OjVjxgzTKahAzZo1U3p6ur7//nv16NFDJ0+eNJ0EAHBBDFsAgFsIDQ1VfHw8lyN7ofDwcC1ZskSfffaZ+vfvz03EAADnYNgCANyG3W7Xpk2b9M0335hOQQVr3769PvroIy1btkzDhg1TcXGx6SQAgAth2AIA3EZ8fLxq1KjBM229VGxsrKZPn67p06fr/vvvl9PpNJ0EAHARDFsAgNsICAjQ4MGDNW3aNBUWFurUqVN8eutl+vXrp7fffltvvPGGnnrqKdM5AAAXwbAFALiVpKQk/fLLL0pISFCtWrV04403av/+/aazUIGGDx+uV155RS+88IJefvll0zkAABfgZzoAAIBLcerUKf373//Wu+++K0latmxZyaWo1apVM5kGA8aOHatjx47p0UcfVXBwsO666y7TSQAAgxi2AAC3sGrVKo0bN67kr8+M2kqVKik4ONhQFUx67rnn5HA4NHLkSFmtVvXv3990EgDAEC5FBgC4hS5duujxxx8/5/XatWvLYrEYKIJpFotFr732mgYPHqzExEQtW7bMdBIAwBCGLQDALVgsFv3tb3875zuVDRs2NFQEV+Dj46P3339f8fHx6t27tz7++GPTSQAAAxi2AAC38vDDD+vdd98t+ZTWZrMZLoJpfn5+mjlzpm677TZ17dpVmzZtMp0EAKhgDFsAgNu58847NX36dElSUVGR4Rq4gsDAQC1YsEDNmzdXly5d9N1335lOAgBUIIvzEp5unpOTI5vNpuzsbFmt1oroAgDgT3322Wdq3LixQkNDTafARRw9elQdOnTQsWPHtHbtWl1zzTWmkwAA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e6pfv35auXKl6SQAHophCwAAgHLj6+uradOm6Y477lD37t31+eefm04C4IEYtgAAAChXlSpV0rx589SiRQvFxsbqm2++MZ0EwMMwbAEAAFDuqlatqiVLlqhhw4aKiorSjz/+aDoJgAdh2AIAAKBCBAcHKz09XVarVZGRkfr5559NJwHwEAxbAAAAVJhatWopKytLxcXFioqK0m+//WY6CYAHYNgCAACgQjVo0ECZmZk6cuSIYmJilJOTYzoJgJtj2AIAAKDCNWnSRBkZGdq5c6e6d++uEydOmE4C4MYYtgAAADDi5ptv1rJly/TFF1+ob9++On36tOkkAG6KYQsAAABjbrvtNs2fP18ZGRlKSkpSUVGR6SQAbohhCwAAAKOio6M1Y8YMzZ49W6NGjZLT6TSdBMDNMGwBAABgXO/evfXuu+9q8uTJevzxx03nAHAzfqYDAAAAAEkaOnSocnJy9MADDyg4OFiPPfaY6SQAboJhCwAAAJcxZswYORwOPf7447LZbLrnnntMJwFwAwxbAAAAuJSnn35aDodDo0aNktVq1eDBg00nAXBxDFsAAAC4FIvFookTJyo7O1t2u11Wq1XdunUznQXAhXHzKAAAALgcHx8fvf3220pISFDfvn21atUq00kAXBjDFgAAAC7Jz89P06dPV4cOHdS9e3dt2LDBdBIAF8WwBQAAgMuqVKmSPvroI910002KjY3Vt99+azoJgAti2AIAAMClVa1aVUuXLlWDBg0UFRWlXbt2mU4C4GIYtgAAAHB5wcHBSk9PV7Vq1RQZGakDBw5IklJTUzV27FjDdQBMszidTuefHZSTkyObzabs7GxZrdaK6AIAAADOsW/fPkVERCgoKEh9+/bVhAkTJEk//fST6tevb7gOQFkqzQ7lE1sAAAC4jauvvloZGRnavXt3yai1WCxaunSp4TIAJjFsAQAA4DaKi4v12muv6cSJEyWvWSwWLVy40GAVANMYtgAAAHAb7733nt56662zXisuLlZWVpby8/MNVQEwjWELAAAAt9G9e3eNGjVKNptNkuTj898/zhYUFCgrK8tkGgCDGLYAAABwG7Vr19akSZP066+/av78+eratWvJuH355ZcN1wEwxc90AAAAAFBaAQEBSkhIUEJCgn777Tc999xzatGiheksAIbwuB8AAAB4hB07dig3N9d0hksJCgpS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", + "image/png": "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fltbt26Vx+PRwIEDdffdd6t9+/bV7lu6dKk+++wz7dmzR2fOnFFycrJmzpx5xWcWFhbq3Xff1dq1a1VWVqbevXtrxowZ6tWrVy2/cwAAEMji4uL017/+Vbt379Yjjzzi8/fr0aOHJGnv3r3q06eP9/rZs2d15swZpaWl+bwGwCx0bBEw6vuw85KSEj3zzDP6/PPPZbfbdeutt2r//v2aNWvWZefLzZs3T9u3b1fXrl2rjc//Orfbreeff16rV6+WzWbTnXfeqYsXL+qZZ57RsWPHalUfAAAIbE2bNtX999+vW265RSNHjvT5+3Xt2lWdOnVSVlaW3G639/qyZctksVg0ZswYn9cAmIWOLQJGfR92vmTJEh07dkzPPfec96eaw4YN02OPPab58+fr9ttv99779NNPq02bNrJYLLr77ruv+sw1a9Zo165d+tGPfuTdR5OQkKBHHnlEH374oR5++OFa1QgAAAJbcnLyNT+jqKhIixYtkiTt2rVL0qXPMc2aNVNkZKTS09O9995111168cUX9dxzz8kwDB06dEiLFy9WamqqunTpUu25//nPfyRdOv9WklatWqWdO3dKkm6++eZrrhtoSARbBIzExEStW7dOW7du1fDhwyX997Dzm266SYsXL67V89asWaPevXtXW6rTuXNnDRo0SPn5+dWCbdu2bWv0zIKCAjVv3lxxcXHeazExMYqPj9fq1atVXl5e684yAABo3Fwulz744INq1+bPny/p0meUrwbbkSNH6tFHH9VHH32kOXPmKCYmRhkZGVcMql9/Zk5OjvevCbYINARbBIyvHnZeFWy/eth5bYKt2+3Wl19+qZSUlMte69Onj7Zu3ari4mJFRETUqsYDBw6oZ8+eslqrr/Lv06ePsrKydOzYMXXr1q1WzwQAAIEhJSXlip8tvm727Nm1em67du30/vvv1/j+0aNHa/To0d96X22eCfg79tgioNTXYecul0vl5eVXnA5YNVGwLoeYnzt37orPrLp29uzZWj8TAAAAwDcj2CKg1Ndh51XBODT08kULVWe81eUQ87Kysis+s2r58ZXOlQMAAI2Ty+XS+fPnr/q/ixcvml0iEDBYioyAUl+HnVeF14qKisteqwq0dTnEPDw8/IrPrAq07K8FAABVXn75Ze3YseOqr7dt27bWy5aBxopgi4CTmJioN954Q+fPn6/z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o0ePZjIyAABBio5t/evcubN69epldhloIAyPAgKEYRjKzc2Vx+MxuxQAAFDP6NgC14ZgCwQIwzB0/PhxHTx40OxSAABAPXK73SosLKRjC1wDgi0QIKr21nLsDwAAwaWwsFCS6Nj6oeXLl2v69Ok6efKk2aVcZtasWZo1a5bZZfgNgi0QINq0aaO+ffsSbAEACDIul0uS6Ng2kN/+9reaMWOGiouLr3rPn/70J91xxx21HraUmZmpdevWXWuJqAOCLRBADMMg2AIAEGSqwhPBtmEkJSWprKxMa9euveLrpaWlWr9+vYYNG6ZJkybpn//8p9q2bVujZxNszUOwBQKIYRjasmWL9ye7AAAg8FUFW5YiN4xRo0YpIiJCubm5V3x9/fr1Ki0tVVJSkqxWq8LDw2WxWK76PI/Ho7KyMl+VixriuB8ggBiGIbfbrbVr1yo1NdXscgAAQD1gKXLDCg8PV1xcnFavXq0LFy6oefPm1V5fvXq1IiIiNGrUKC1fvlyvvfaaXnnlFbVr107SpfNxu3btKpvNpvfff1+HDh3S7bffrn/84x+SpBUrVmjFihWSpOTkZM2cOVOvvvqqduzYodmzZ1d7rw8//FAfffSR3n//fe+1nJwcrVq1SocOHVJRUZHat2+v9PR0TZw40Ze/LQGPji0QQPr376/mzZtzni0AAEGEjm3DS0pKUmVl5WWfqVwul7Zs2aLRo0crPDz8ql9/9OhR/elPf9LgwYP13e9+Vz169NBDDz2ksLAw9evXTw899JAeeughXX/99bWubdmyZWrTpo3sdrtmzJih1q1b680339SSJUtq/azGhI4tEECsVqvi4+PZZwsAQBChY9vwBg0apJYtWyo3N1fp6ene6/n5+aqsrFRSUtI3fv3x48f15JNPatiwYdWu//Wvf1X79u01duzYOtf2y1/+slqoTk9P169//WstWLBANputzs8NdnRsgQBjGIby8/PldrvNLgUAANSDqo5ts2bNTK6k8bBarTIMQ7t27ap2lE9ubq6aN2+uwYMHf+PXt2vX7rJQW1++GmqLiop08eJF9e/fXydOnFBRUZFP3jMY0LEFAoxhGHr66af1xRdfqH///maXAwAArpHL5VJUVJSsVnpODSkpKUkLFixQbm6uMjIydObMGe3cuVPp6enf+veiar+tL+zcuVMffvihdu/erdLS0mqvFRUV8QOQqyDYAgEmLi5OVqtVeXl5BFsAAIKA0+lkf60JevXqpU6dOnmDbW5urjwez7cuQ5b0jftva+PrK/COHz+uZ599Vp06ddKMGTPUpk0bhYSEaPPmzVqwYAEr9r5B0Afb3bt31/pg5WAXHR2t2NhYs8tAHcXExGjw4MHKy8vTfffdZ3Y5AADgGrlcLvbXmiQpKUkffPCBDh48qNzcXHXs2FF9+vSp8/OudixQVFSUCgsLL7t+6tSpar/esGGDysvL9dOf/lRt2rTxXt+xY0eda2osgjrY7t69W3379jW7DL+0a9cuwm0AMwxDOTk5ZpcBAADqgdPpJNiaZOzYsfrggw/0wQcf6MCBA7rllluu6XlNmjS5YoBt3769ioqKdPDgQXXv3l2SdO7cOa1bt67afVVLoD0ej/daUVGRli9ffk11NQZBHWyrOrUPPfSQOnfubHI1/uHIkSOaPXs2XewAl5CQoNdee01nz55Vq1atzC4HAABcA5Yim6ddu3bq27ev1q9fL0nXNM1YurS8edu2bZo/f75atmypdu3aKTY2VoZh6N1339XLL7+s9PR0lZaWatmyZerYsaP279/v/fqhQ4cqNDRUv/3tb3X99derpKREWVlZiomJ0blz566ptmAX1MG2SufOndWrVy+zywDqjWEYki6NpJ80aZLJ1QAAgGvBUmRzJSUladeuXerTp486dOhwTc+6++679cYbb+j9999XWVmZkpOTFRsbq+joaD322GP6xz/+oXfffVft2rXT7bffruPHj1cLtp06ddKPf/xj/fvf/9Y///lPtWjRQhMmTFBMTIxef/31a/1Wg1qjCLZAsOnVq5fatWtHsAUAIAg4nU61bdvW7DIaLZvNdtXzYVNSUpSSklLt2uzZs6/6rE6dOumXv/zlFV8bMmSIXnrppcuu33rrrdV+PXLkSI0cOfKy+8aPH1/t108//fRV62iMmCkOBCCLxSLDMJSXl2d2KQAA4BrRsQWuHcEWCFCGYWjNmjWqqKgwuxQAAHAN2GMLXDuCLRCgDMNQUVGRtm7danYpAADgGtCxBa4dwRYIUCNHjlRYWBjLkQEACHB0bIFrR7AFAlTTpk01cuRIgi0AAAHM4/HQsQXqAcEWCGAJCQnKz883uwwAAFBHpaWlqqioINgC14hgCwQwwzB04MABHT161OxSAABAHTidTkliKXKAmz59uj788MMa3fvQQw/p1VdfrfV7nDx5UtOnT9fy5ctr/bWNAcEWCGCGYUgSXVsAAAKUy+WSJDq2fmD58uWaPn269u7de83P+uKLL/Thhx+qsLCwHipDTYSaXQCAuuvUqZO6d++uvLw83XzzzWaXAwAAaomObXD45z//qZCQEO+vd+3apY8++kjJycmKjIysdu/vf/97WSyWhi4x6BFsgQBnGAYDpAAACFB0bINDeHh4je8NCwvzYSWNF8EWCHCGYeijjz5SSUmJmjZtanY5AACgFujY+q9XX31VBQUF+sMf/qA333xT27ZtU3h4uJKTk3XnnXfKav3vrs7p06frlltu0a233qoPP/xQH330kSTphz/8ofeeV155Re3atdNDDz2kAQMGaObMmZIu/XAjMzNTW7Zs0cmTJ2W1WnXdddfp9ttvV48ePRr0ew5kBFsgwBmGofLycm3YsEGJiYlmlwMAAGqBjq1/c7vdeu655xQbG6sZM2Zo27Ztmj9/vtq3b6+JEyde8Wvi4uJ07Ngx5ebm6u6771ZMTIwkef//606cOKF169YpPj5e7dq104ULF/Tpp59q1qxZevnll9WqVSuffX/BhGALBLghQ4aoWbNmysvLI9gCABBg6Nj6t/LychmG4Z1lMmHCBD3++OPKycm5arDt3r27evbsqdzcXI0ePVrt2rX7xvfo1q2b/vCHP1TrAI8dO1Y//vGPlZOTwxyVGmIqMhDgQkNDFRcXx2RkAAACkMvlUpMmTdh36ccmTJhQ7df9+/fXiRMn6u35YWFh3lDrdrvldDrVtGlTdezYUfv376+39wl2dGyBIGAYht588015PB6m7AEAEECcTifLkP1YWFjYZUuIIyMj6/UYH7fbrUWLFmnp0qU6efKk3G639zX+bNQcwRYIAoZh6Ne//rX279+vXr16mV0OAACoIafTyTJkP/bV5cG+kpmZqQ8++EDjx4/Xd77zHUVFRclisejtt9+Wx+Px+fsHC4ItEATi4+MlSXl5eQRbAAACiMvloivXyK1Zs0YDBw7UAw88UO16UVHRVQdO4XLssQWCQOvWrdWvXz/OswUAIMDQsQ1OVUcwFhUVfeu9Vqv1ss5sfn6+zp4965PaghUdWyBIGIZBsAUAIMDQsQ1OPXv2lCT9+9//lmEYCgkJ0ciRI72B96tGjBih//znP3r11Vd13XXX6csvv9Tq1avVvn37hi47oNGxBYKEYRjatm2b99gAAADg/+jYBqc+ffroO9/5jg4ePKhXX31Vf/rTn3Tx4sUr3puRkaHJkydr69at+vvf/679+/fr8ccfV+vWrRu46sBGxxYIEgkJCXK73Vq7dq3S0tLMLgcAANSAy+VShw4dzC4DklJSUpSSkuL99cyZMzVz5szL7rv11lt16623Vrv2/vvvX3bfzTfffMUzaGfPnl3t12FhYZoxY4ZmzJhR7frTTz9d7dft2rW74vvgEjq2QJDo16+fWrRowXJkAAACCMf9APWDYAsECavVqoSEBIItAAABxOVysRQZqAcsRZa0fPlyvfbaa5KkWbNmqV+/ftVe93g8evDBB3XmzBmNGDFCjz/+eI2ee/ToUS1btkx79uzR/v37VV5erldeeUXt2rW77N68vDxt2LBBe/bs0fHjxzVgwIDLlh9UKS8v1wcffKBVq1bJ5XKpe/fumj59uoYMGVLL7xzBxjAMvfTSS3K73Q1y7hoAALg2dGyB+sEn368ICwvT6tWrL7u+Y8cOnTlzRmFhYbV63q5du7Ro0SIVFxerc+fO33jvsmXLtH79erVu3VqRkZHfeO+rr76qBQsWKCkpSffcc4+sVquef/557dy5s1b1IfgYhqELFy7o888/N7sUAABQAwyPAuoHwfYrhg8froKCAlVWVla7npubq169eqlFixa1et6oUaM0Z84cvfTSS0pKSvrGex988EHNmTNHv/jFL9SyZcur3rdnzx7l5eXp9ttv11133aXrr79eP//5z9WmTRu9++67taoPwScuLk5Wq5XlyAAABICKigqVlJTQsQXqAcH2KxITE+VyubR161bvtYqKChUUFCgxMbHWz4uKilJERESN7m3Tpk2Nlo4WFBTIarVWm3obHh6u8ePHa9euXTp9+nSt60TwiIqK0tChQwm2AAAEAJfLJUl0bIF6QLD9irZt2yo2Nla5ubnea5s2bVJRUZEMwzCxsv86cOCAOnbsqGbNmlW73qdPH0nSwYMHzSgLfsQwDIItAAABoCrY0rFtnKZPn64PP/yw1l938uRJTZ8+XcuXL6//ogIYwfZrkpKStH79epWVlUmSVq9erQEDBqhVq1YmV3bJuXPnrrhUuera2bNnG7ok+JmEhAS69wAABACn0ymJjq3Zli9frunTp2v69OlX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9fUxZsyYtMeBQUXYAgBAhTz33HNpjwCDkqPIAAAAZJqwBQAAINOELQAAAJkmbAEAAMg0YQsAAECmCVsAAAAyTdgCAACQacIWAACATBO2AAAAZJqwBQAAINMKaQ8AMNDtbtid9ggDij8PAGCgEbYAXaitrY2IiF/81S9SnmRgOvrnAwCQNmEL0IX6+vpoaGiIpqamtEcZcGpra6O+vj7tMQAAIkLYApyUeAMYPLZt2+YfKz/BP1QyWAhbAAAGvW3btsX06dPTHmNAamhoELdknrAFAGDQO7pTe/vtt8ekSZNSnmZg2LFjRyxfvtwuNoOCsAUA4LQxadKkmDp1atpjAP3Me2wBAADINGELAABApglbAAAAMk3YAgAAkGnCFgAAgEwTtgAAAGSasAUAACDThC0AAACZJmwBAADINGELAABApglbAAAAMk3YAgAAkGnCFgAAgEwTtgAAAGSasAUAACDThC0AAACZJmwBAADINGELAABApglbAAAAMk3YAgAAkGnCFgAAgEwTtgAAAGSasAUAACDThC0AAACZVkh7AAAAGCiefPLJ+PGPfxwREXfffXecf/75x3xeLpfjtttuiz179sTs2bPjW9/6Vrfuu3Pnzli1alU0NjbG22+/HUeOHIkf/vCHMX78+OPWPvvss7Fx48ZobGyMXbt2xYwZM+Kuu+46bt2hQ4fioYceisbGxmhsbIwDBw7ErbfeGosXL+75Dw4ZZ8cWAAA+obq6OtauXXvc9a1bt8aePXuiurq6R/draGiIRx99NA4ePBiTJk066dpVq1bFhg0bYuzYsTFixIgu1+3fvz8efPDB2LFjR5xzzjk9mgcGGzu2AADwCbNmzYr169fHLbfcEvl8vvP6unXrYurUqdHU1NSj+1166aVx//33x/Dhw+N3v/tdvPPOO12uve2222LMmDFRVVUVX//617tcN3r06PjJT34SdXV18eabb8a3v/3tHs0Eg4kdWwAA+IQFCxZEc3NzvPTSS53X2traYv369bFgwYIe32/kyJExfPjwbq0988wzo6rq1H9Nr66ujrq6uh7PAoORsAUAgE8YN25c1NfXx7p16zqvbd68OVpaWuKKK65IcTLgRIQtAACcwMKFC2PDhg3R2toaERFr166NGTNmxJgxY1KeDPgkYQsAACcwf/78aG1tjY0bN8bBgwdj06ZNvTqGDCTPw6MAAOAERo0aFRdddFGsW7cuWltbo6OjI+bNm5f2WMAJ2LEFAIAuLFiwILZs2RKrVq2KmTNnnvT1O0B6hC0AAHTh8ssvj1wuF9u2bYuFCxemPQ7QBUeRAQCgC8OGDYuvfOUr8ac//SnmzJmT9jhAF4QtAACcxJVXXtnne7S0tMSjjz4aERENDQ0REbFixYqoqamJESNGRKlU6ly7devWeO211yIioqmpKQ4fPhwPPvhgRERccMEFMWPGjM61jz32WBw4cCA+/PDDiIjYuHFj7NmzJyIirr322qipqenz7JAFwhYAABLW3Nwcv/71r4+59vDDD0fEx+/M/f/D9tVXX40HHnjgmLVHf++NN954TNg+/PDD8f7773f++oUXXogXXnghIiIWLVokbDltCFsAAPi/Fi9eHIsXLz7luuXLl/fovuPHj49f/epX3Vp70003xU033dSttT2dAwYrD48CAAAg0+zYAgBALzU3N0dbW1uXn1dVVcWoUaMqOBGcnoQtAAD00ve///3YunVrl5+PGzfOcWGoAGELAAC99MUvfjGam5u7/HzIkCEVnAZOX8IWAAB6aerUqWmPAISHRwEAAJBxwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYJWwAAADJN2AIAAJBpwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYJWwAAADJN2AIAAJBpwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYV0h4AAAAqZceOHWmPMGD4s2AwEbYAAAx6tbW1ERGxfPnylCcZeI7+2UCWCVsAAAa9+vr6aGhoiKamprRHGVBqa2ujvr4+7TGgz4QtAACnBQEHg5eHRwEAAJBpwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYJWwAAADJN2AIAAJBpwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYJWwAAADJN2AIAAJBpwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYJWwAAADJN2AIAAJBpwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYJWwAAADJN2AIAAJBpwhYAAIBME7YAAABkmrAFAAAg04QtAAAAmSZsAQAAyDRhCwAAQKYJWwAAADJN2AIAAJBphe4sKpfLERGxf//+RIcBAACAiP/Xn0d79GS6FbZNTU0RETF58uQ+jAUAAAA909TUFGecccZJ1+TK3cjfjo6O2LlzZ9TW1kYul+u3AQEAAOBEyuVyNDU1xVlnnRVVVSf/Fm23whYAAAAGKg+PAgAAINOELQAAAJkmbAEAAMg0YQsAAECmCVsAAAAyTdgCAACQacIWAACATPs/gHj8YSvKbFIAAAAASUVORK5CYII=", "text/plain": [ "
" ] @@ -396,7 +396,7 @@ "outputs": [ { "data": { - "image/png": "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pPvvv18dO3ZUXFyc9u/frzlz5ignJ0dr1qypdX9ut1tut9sz73K5bvhrAAAA/mEzvjzG8gaqqKjQsWPHVFxcrHfffVe/+93vtGXLFk+YudJf//pXjRgxQrm5uerSpUuN+5s3b57mz59/VXtxcbEcDkeD1w8AABqey+WS0+ms8/zt9yDzVSkpKerSpYuWL19+1bKysjJFRERow4YNSk1NrXH7mnpk4uPjCTIAAFiIr0HG75eWvqq6utoriFwpOztbktSuXbtat7fb7bLb7TeiNAAAEGD8GmTS09M1evRodejQQSUlJVq1apUyMzO1ceNG5eXladWqVbrrrrvUqlUr7d+/XzNnztSQIUOUlJTkz7IBAECA8GuQOXnypB588EEVFBTI6XQqKSlJGzdu1J133qn8/Hx9+OGHWrJkicrKyhQfH6/x48frySef9GfJAAAggATcGJmG5us1NgAAEDh8PX8HzH1kAAAA6osgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALIsgAwAALMuvQWbZsmVKSkqSw+GQw+FQcnKyPvjgA8/y8vJypaWlqVWrVoqIiND48eNVVFTkx4oBAEAg8WuQad++vRYuXKisrCzt2bNHw4cP19ixY/XJJ59IkmbOnKk//vGPeuedd7RlyxadOHFC99xzjz9LBgAAAcRmjDH+LuJK0dHRev755zVhwgS1adNGq1at0oQJEyRJhw8fVo8ePbRjxw4NGjTIp/25XC45nU4VFxfL4XDcyNIBAEAD8fX8HTBjZKqqqrR69WqVlZUpOTlZWVlZqqysVEpKimed7t27q0OHDtqxY0et+3G73XK5XF4TAABomvweZA4cOKCIiAjZ7Xb99Kc/1dq1a9WzZ08VFhaqefPmioqK8lo/JiZGhYWFte4vIyNDTqfTM8XHx9/gVwAAAPzF70GmW7duys7O1q5duzR16lRNnDhRn3766XXvLz09XcXFxZ4pPz+/AasF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831knnzySa1Zs0Zdu3bVtGnT1K1bN0lfXupZunSpqqqq9MQTT1x3IWlpaTp48KA+/vjj696HJKWnp2vWrFmeeZfLRZgBAKCJ8jnIxMTEaPv27Zo6darS09N1eWiNzWZTamqqli5dqpiYmOsqYtq0afrTn/6krVu3qn379p722NhYVVRU6Pz58169MkVFRYqNja1xX3a7PWDvaQMAABpWve7s27FjR/35z3/WuXPnlJubK2OMEhIS1LJly+s6uDFG06dP19q1a5WZmanOnTt7Le/fv7+aNWumzZs3a/z48ZKknJwcHTt2TMnJydd1TAAA0HTU+xEFktSyZUsNGDDgax88LS1Nq1at0nvvvafIyEjPuBen06mwsDA5nU5NmTJFs2bNUnR0tBwOh6ZPn67k5GSfvrEEAACatut+REGDHNxmq7F9xYoVmjRpkqQvb4g3e/ZsvfXWW3K73UpNTdXLL79c66Wlr+Lr1wAAWI+v52+fg4yvN6Fbs2aNbxU2EoIMAADW4+v52+dLS06ns0EKAwAAaCg+B5kVK1bUuc61bpgHAADQ0Hy+IV5tSkpK9Nvf/lYDBw5Unz59GqImAAAAn1x3kNm6dasmTpyodu3a6YUXXtCwYcO0c+fOhqwNAADgmur19evCwkKtXLlSr732mlwul773ve/J7XZr3bp16tmz542qEQAAoEY+98iMGTNG3bp10/79+7VkyRKdOHFCL7300o2sDQAA4Jp87pH54IMP9LOf/UxTp05VQkLCjawJAADAJz73yHz88ccqKSlR//79NXDgQP3Hf/yHTp8+fSNrAwAAuCafg8ygQYP06quvqqCgQD/5yU+0evVqxcXFqbq6Wps2bVJJScmNrBMAAOAqX+sRBTk5OXrttdf0+9//XufPn9edd96p9evXN2R9Xxt39gUAwHp8PX9/rfvIdOvWTc8995yOHz+u1atXq6ys7OvsDgAAoF6u6+nXVyopKdFbb72l3/3ud8rKymqImgAAAHzSIDfEe+KJJxQfH9+QdQEAANSpXkGmsLBQCxcuVEJCgu666y5dunRJ//3f/62CggLNnz//RtUIAABQI58vLY0ZM0abN2/WsGHDNG/ePI0bN07h4eGe5Tab7YYUCAAAUBufg8z777+v+++/XzNmzNBtt912I2sCAADwic+XlrZv366wsDANHz5c3bp10zPPPKO8vLwbWRsAAMA1XdcN8ebMmaO//OUv6tq1qwYNGqSXXnpJRUVFN7JOAACAqzTYDfGKiopks9lUVVXVkPV9bdwQDwAA62n0G+KtWbNG3/3ud7/O7gAAAOrla/XIWAE9MgAAWE+j9MgAAAD4E0EGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYFkEGAABYll+DzNatWzVmzBjFxcXJZrNp3bp1XssnTZokm83mNY0aNco/xQIAgIDj1yBTVlamPn36aOnSpbWuM2rUKBUUFHimt956qxErBAAAgSzEnwcfPXq0Ro8efc117Ha7YmNjG6kiAABgJQE/RiYzM1Nt27ZVt27dNHXqVJ05c8bfJQEAgADh1x6ZuowaNUr33HOPOnfurLy8PP37v/+7Ro8erR07dig4OLjGbdxut9xut2fe5XI1VrkAAKCRBXSQuffeez0/JyYmKikpSV26dFFmZqZGjBhR4zYZGRmaP39+Y5UIAAD8KOAvLV3plltuUevWrZWbm1vrOunp6SouLvZM+fn5jVghAABoTAHdI/NVx48f15kzZ9SuXbta17Hb7bLb7Y1YFQAA8Be/BpnS0lKv3pWjR48qOztb0dHRio6O1vz58zV+/HjFxsYqLy9Pjz/+uG699Valpqb6sWoAABAo/Bpk9uzZo2HDhnnmZ82aJUmaOHGili1bpv379+uNN97Q+fPnFRcXp5EjR2rBggX0uAAAAEmSzRhj/F3EjeRyueR0OlVcXCyHw+HvcgAAgA98PX9barAvAADAlQgyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAsggyAADAskL8XQAA4EtVVVU6fvy4Pv/8c7ndboWHh+uWW25RbGysbDabv8sDApJfe2S2bt2qMWPGKC4uTjabTevWrfNabozR008/rXbt2iksLEwpKSn67LPP/FMsANxAbrdbH374oXbt2qWioiKdP39e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51l++fdUV5D5akg4dOiQkWR27dpV63a9evUyL730kme+Y8eOZty4cbWuf9nzzz9v+vfv75mfO3euadGihXG5XJ621NRU06lTp6s+pxkZGcYYYz766CPjcDhMeXm51767dOlili9f7tnvV/8++Lpds2bNzMmTJz3Ls7KyjCTz+eef1/n6gLqE+KUbCAgQixYt0vDhw/Xoo49e9z569eqloKD/u0obExOj3r17e+aDg4PVqlUrnTx50mu75ORkz88hISG67bbbdOjQIUnSvn379Le//U0RERFXHS8vL09du3aVJPXv3/+atblcLp04cUKDBw/2ah88eLBX939dcnNzdeHCBd15551e7RUVFfrmN78pSZo6darGjx+vvXv3auTIkRo3bpxuv/12n49xWVJSkufny+9dYmKipy0mJkaSvN7PpUuX6vXXX9exY8d08eJFVVRU1Dkwdd++fcrNzVVkZKRXe3l5ufLy8lRcXKyCggINHDjQs+zy78nUcXkpJCREAwYM8Mx3795dUVFROnTokL71rW+ptLRU8+bN0/vvv6+CggJdunRJFy9e1LFjx7z2c9ttt12177ffflsvvvii8vLyVFpaqkuXLsnhcHit06lTJ6/XFRMTo+Dg4Ks+p5ffw3379qm0tPSq8VEXL15UXl5era/T1+06duyoNm3aeOb79OmjESNGKDExUampqRo5cqQmTJigli1b1nosoDYEGdzUhgwZotTUVKWnp2vSpEley4KCgq46YV05FuGyZs2aec3bbLYa26qrq32uq7S0VGPGjNGiRYuuWtauXTvPz+Hh4T7v8+soLS2VJL3//vv6xje+4bXMbrdLkkaPHq0vvvhCf/7zn7Vp0yaNGDFCaWlpeuGFF+p1rLrez8vfLLv8fq5evVqPPvqofvWrXyk5OVmRkZF6/vnntWvXrjpfU//+/fXmm29etezKk+6N8Oijj2rTpk164YUXdOuttyosLEwTJky4aiDsV3+/O3bs0AMPPKD58+crNTVVTqdTq1ev1q9+9Suv9er7mSwtLVW7du08Y4eudK3B2L5u99XXERwcrE2bNmn79u36y1/+opdeeklPPPGEdu3a5RlPBfiKIIOb3sKFC9W3b19169bNq71NmzYqLCyUMcZz8mzIe7/s3LlTQ4YMkSRdunRJWVlZmjZtmiSpX79++sMf/qBOnTopJOT6/5o6HA7FxcVp27Zt+s53vuNp37Ztm771rW/5vJ+ePXvKbrfr2LFjXvv5qjZt2mjixImaOHGivv3tb+uxxx7TCy+8oObNm0v6cvBsQ9u2bZtuv/12Pfzww562r/YiNG/e/Kpj9+vXT2+//bbatm17VY/GZe3atdOuXbuu+j3169fvmjVdunRJe/bs8bzHOTk5On/+vHr06OGpedKkSbr77rslfRkIrhxkXJvt27erY8eOeuKJJzxtX3zxRZ3b1aVfv34qLCxUSEiI12D2K9X2Hta1XW1sNpsGDx6swYMH6+mnn1bHjh21du1azZo16zpfBW5WfGsJN73ExEQ98MADevHFF73ahw4dqlOnTum5555TXl6eli5d6vVtma9r6dKlWrt2rQ4fPqy0tDSdO3dOP/zhDyVJaWlpOnv2rO677z7t3r1beXl52rhxoyZPnlzvMPDYY49p0aJFevvtt5WTk6Of//znys7O1iOPPOLzPiIjI/Xoo49q5syZeuONN5SXl6e9e/fqpZde0htvvCFJevrpp/Xee+8pNzdXn3zyif70pz95Ttxt27ZVWFiYNmzYoKKiIhUXF9frNVxLQkKC9uzZo40bN+rIkSN66qmntHv3bq91OnXqpP379ysnJ0enT59WZWWlHnjgAbVu3Vpjx47VRx99pKNHjyozM1M/+9nPdPz4cUnSI488ooULF2rdunU6fPiwHn74YZ0/f77Ompo1a6bp06dr165dysrK0qRJkzRo0CBPsElISNCaNWuUnZ2tffv26f777/epxy4hIUHHjh3T6tWrlZeXpxdffFFr166t/5v2FSkpKUpOTta4ceP0l7/8RZ9//rm2b9+uJ554Qnv27JH05Xt49OhRZWdn6/Tp03K73T5tV5Ndu3bpl7/8pfbs2aNjx45pzZo1OnXqlOfzAtQHQQaQ9Mwzz1x1IunRo4defvllLV26VH369NHf//73rzWW5qsWLlyohQsXqk+fPvr444+1fv16tW7dWpI8vShVVVUaOXKkEhMTNWPGDEVFRXmNc/DFz372M82aNUuzZ89WYmKiNmzYoPXr1yshIaFe+1mwYIGeeuopZWRkqEePHho1apTef/99z6WA5s2bKz09XUlJSRoyZIiCg4O1evVqSV+OGXnxxRe1fPlyxcXFaezYsfU69rX85Cc/0T333KPvf//7GjhwoM6cOePVOyNJDz30kLp166bbbrtNbdq00bZt29SiRQtt3bpVHTp00D333KMePXpoypQpKi8v9/TQzJ49Wz/4wQ80ceJEz2Wry70o19KiRQvNmTNH999/vwYPHqyIiAi9/fbbnuWLFy9Wy5Ytdfvtt2vMmDFKTU2ts5dHkv71X/9VM2fO1LRp09S3b19t375dTz31VD3fsavZbDb9+c9/1pAhQzR58mR17dpV9957r7744gvPmKTx48dr1KhRGjZsmNq0aaO33nrLp+1q4nA4tHXrVt11113q2rWrnnzySf3qV7/S6NGjv/Zrwc3HZuoatQYA8NnKlSs1Y8YMn3puAHx99MgAAADLIsgAAADL4tISAACwLHpkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZRFkAACAZf1/hAG65neKXQcAAAAASUVORK5CYII=", + "image/png": "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8q9Zs2apdevWysvL04YNGxp9/3WVt1//+tdatmxZox/vUpSPazd79uwmLbmArygyuCGFhYVp/vz5OnPmjL+jNJrKysqr3jY/P1+33nqrkpKSFB0d3YiprszpdCoyMrLJjmdl1/L3G0iay+tA4KDI4IaUnp6uuLg4ZWdn17lObf8PdOHCherYsaPn+cX/p/+LX/xCsbGxioyM1NNPP60LFy7o0UcfVVRUlBISErR06dLL9n/w4EHdcsstCgsLU69evZSTk+O1fP/+/Ro5cqTCw8MVGxur73//+zp16pRn+W233abJkydr6tSpatu2rTIyMmp9HTU1NXr66aeVkJAgu92uvn37au3atZ7lNptNubm5evrpp2Wz2TR79uw695Odna1OnTqpZcuW6tOnj9555x3P8jNnzuj+++9XTEyMWrZsqeTkZM/r7tSpkyTppptuks1m83wB56VnSm677TZNmTJFU6dOVZs2bRQbG6tXXnlF5eXlmjBhgiIiItSlSxd98MEHnm2qq6s1ceJET66UlBT9+te/9iyfPXu2Xn/9da1Zs0Y2m002m00bN26UJBUUFOg73/mOIiMjFRUVpdGjR+uzzz7z2vf06dMVGRmp6OhoPfbYY6rv6+mWLVumyMhIrV69WsnJyQoLC1NGRoYKCgo86+Tn52v06NGKjY1VeHi4BgwYoI8++shrPx07dtTcuXP1wAMPyOFw6Ec/+pEkaebMmeratatatWqlr3/963ryySdVVVXl9Xr79u2r1157TR06dFB4eLgeeughVVdX69lnn1VcXJzatWunZ555xut4Z8+e1Q9/+EPFxMTI4XBo6NCh2rNnj+c1zZkzR3v27PG8hxfPpF1pu6/m+e1vf6tOnTopLCxMkvTOO++od+/eatmypaKjo5Wenq7y8vIrvrdArQxwgxk3bpwZPXq0WblypQkLCzMFBQXGGGNWrVplvvpPYtasWaZPnz5e2/7qV78ySUlJXvuKiIgwmZmZ5uDBg+bVV181kkxGRoZ55plnzKFDh8zcuXNNSEiI5zhHjhwxkkxCQoJ55513zKeffmp++MMfmoiICHPq1CljjDFnzpwxMTExJisryxw4cMDs2rXL3HHHHeb222/3HPtb3/qWCQ8PN48++qg5ePCgOXjwYK2vd8GCBcbhcJg333zTHDx40Dz22GMmJCTEHDp0yBhjTGFhoenZs6eZMWOGKSwsNKWlpbXu5+c//7np1q2bWbt2rcnPzzdLly41drvdbNy40RhjTGZmpunbt6/ZsWOHOXLkiFm/fr159913jTHG/PWvfzWSzEcffWQKCwvN6dOnvf4uvvqaIiIizNy5cz3vXYsWLczIkSPNb37zG3Po0CEzadIkEx0dbcrLy40xxlRWVpqnnnrK7Nixw/zjH/8w//M//2NatWpl3nrrLWOMMaWlpeY73/mOGTFihCksLDSFhYXG7XabyspK0717d/ODH/zA7N2713z66afmvvvuMykpKcbtdhtjjJk/f75p06aN+f3vf28+/fRTM3HiRBMREeGV+VJLly41ISEh5uabbzZbtmwxO3fuNN/4xjfMLbfc4lln9+7d5uWXXzb79u0zhw4dMk888YQJCwszn3/+uWedpKQk43A4zPPPP28OHz5sDh8+bIwxZu7cuWbz5s3myJEj5t133zWxsbFm/vz5nu1mzZplwsPDzT333GM++eQT8+6775rQ0FCTkZFhpkyZYg4ePGhee+01I8ls27bNs116eroZNWqU2bFjhzl06JCZMWOGiY6ONqdPnzbnzp0zM2bMMD179vS8h+fOnat3u4t5WrdubUaMGGF27dpl9uzZY44fP26Cg4PNggULzJEjR8zevXvNokWL6vzZA66EIoMbzlc/PAcNGmR+8IMfGGOuvsgkJSWZ6upqz1hKSor55je/6Xl+4cIF07p1a/Pmm28aY/6vyMybN8+zTlVVlUlISPB8IM2dO9cMHz7c69gFBQVGksnLyzPGfPmhf9NNN9X7euPj480zzzzjNTZgwADz0EMPeZ736dPHzJo1q859VFRUmFatWpktW7Z4jU+cONHce++9xhhjRo0aZSZMmFDr9hdf89/+9jev8dqKzK233up5fvG9+/73v+8ZKywsNJLM1q1b68ybmZlpxo4dW+dxjDHmd7/7nUlJSTE1NTWeMbfbbVq2bGnWrVtnjDGmffv25tlnn/Usv/j3VF+RubQkHDhwwEgy27dvr3O7nj17mhdffNHzPCkpyYwZM6bO9S967rnnTP/+/T3PZ82aZVq1amVcLpdnLCMjw3Ts2PGyn9Ps7GxjjDF/+ctfjMPhMBUVFV777ty5s1myZIlnv5f+e/B1u5CQEHPixAnP8tzcXCPJfPbZZ/W+PqA+wX45DQQEiPnz52vo0KF65JFHrnofPXv2VFDQ/12ljY2NVa9evTzPW7RooejoaJ04ccJru7S0NM+fg4ODdfPNN+vAgQOSpD179ujPf/6zwsPDLztefn6+unbtKknq37//FbO5XC4dP35cgwcP9hofPHiw1+n/+hw+fFjnzp3THXfc4TVeWVmpm266SZI0adIkjR07Vrt27dLw4cM1ZswY3XLLLT4f46LU1FTPny++d7179/aMxcbGSpLX+7lo0SK99tprOnr0qM6fP6/Kysp6J6bu2bNHhw8fVkREhNd4RUWF8vPzVVJSosLCQg0cONCz7OLfk6nn8lJwcLAGDBjged6tWzdFRkbqwIED+sY3vqGysjLNnj1b7733ngoLC3XhwgWdP39eR48e9drPzTfffNm+33rrLb3wwgvKz89XWVmZLly4IIfD4bVOx44dvV5XbGysWrRocdnP6cX3cM+ePSorK7tsftT58+eVn59f5+v0dbukpCTFxMR4nvfp00fDhg1T7969lZGRoeHDh+uee+5RmzZt6jwWUBeKDG5oQ4YMUUZGhrKysjR+/HivZUFBQZd9YH11LsJFISEhXs9tNlutYzU1NT7nKisr06hRozR//vzLlrVv397z59atW/u8z2tRVlYmSXrvvff0ta99zWuZ3W6XJI0cOVKff/653n//fa1fv17Dhg1TZmamnn/++QYdq7738+Jvll18P1esWKFHHnlEv/zlL5WWlqaIiAg999xz2r59e72vqX///nrjjTcuW/bVD93r4ZFHHtH69ev1/PPPq0uXLmrZsqXuueeeyybCXvr3u3XrVt1///2aM2eOMjIy5HQ6tWLFCv3yl7/0Wq+hP5NlZWVq3769Z+7QV11pMrav2136Olq0aKH169dry5Yt+vDDD/Xiiy/q8ccf1/bt2z3zqQBfUWRww5s3b5769u2rlJQUr/GYmBgVFRXJGOP58GzMe79s27ZNQ4YMkSRduHBBubm5mjx5siSpX79++v3vf6+OHTsqOPjq/5k6HA7Fx8dr8+bN+ta3vuUZ37x5s77xjW/4vJ8ePXrIbrfr6NGjXvu5VExMjMaNG6dx48bpm9/8ph599FE9//zzCg0NlfTl5NnGtnnzZt1yyy166KGHPGOXnkUIDQ297Nj9+vXTW2+9pXbt2l12RuOi9u3ba/v27Zf9PfXr1++KmS5cuKCdO3d63uO8vDydPXtW3bt392QeP3687rrrLklfFoKvTjKuy5YtW5SUlKTHH3/cM/b555/Xu119+vXrp6KiIgUHB3tNZv+qut7D+rari81m0+DBgzV48GA99dRTSkpK0qpVqzR9+vSrfBW4UfFbS7jh9e7dW/fff79eeOEFr/HbbrtNJ0+e1LPPPqv8/HwtWrTI67dlrtWiRYu0atUqHTx4UJmZmTpz5ox+8IMfSJIyMzP1xRdf6N5779WOHTuUn5+vdevWacKECQ0uA48++qjmz5+vt956S3l5efrZz36m3bt36+GHH/Z5HxEREXrkkUc0bdo0vf7668rPz9euXbv04osv6vXXX5ckPfXUU1qzZo0OHz6sTz75RH/84x89H9zt2rVTy5YttXbtWhUXF6ukpKRBr+FKkpOTtXPnTq1bt06HDh3Sk08+qR07dnit07FjR+3du1d5eXk6deqUqqqqdP/996tt27YaPXq0/vKXv+jIkSPauHGjfvrTn+rYsWOSpIcffljz5s3T6tWrdfDgQT300EM6e/ZsvZlCQkI0ZcoUbd++Xbm5uRo/frwGDRrkKTbJyclauXKldu/erT179ui+++7z6YxdcnKyjh49qhUrVig/P18vvPCCVq1a1fA37RLp6elKS0vTmDFj9OGHH+qzzz7Tli1b9Pjjj2vnzp2SvnwPjxw5ot27d+vUqVNyu90+bVeb7du36xe/+IV27typo0ePauXKlTp58qTn5wVoCIoMIOnpp5++7IOke/fueumll7Ro0SL16dNHf/3rX69pLs2l5s2bp3nz5qlPnz76+OOP9e6776pt27aS5DmLUl1dreHDh6t3796aOnWqIiMjveY5+OKnP/2ppk+frhkzZqh3795au3at3n33XSUnJzdoP3PnztWTTz6p7Oxsde/eXSNGjNB7773nuRQQGhqqrKwspaamasiQIWrRooVWrFgh6cs5Iy+88IKWLFmi+Ph4jR49ukHHvpIf//jHuvvuu/Xd735XAwcO1OnTp73OzkjSgw8+qJSUFN18882KiYnR5s2b1apVK23atEkdOnTQ3Xffre7du2vixImqqKjwnKGZMWOGvv/972vcuHGey1YXz6JcSatWrTRz5kzdd999Gjx4sMLDw/XWW295li9YsEBt2rTRLbfcolGjRikjI6PeszyS9O///u+aNm2aJk+erL59+2rLli168sknG/iOXc5ms+n999/XkCFDNGHCBHXt2lXf+9739Pnnn3vmJI0dO1YjRozQ7bffrpiYGL355ps+bVcbh8OhTZs26c4771TXrl31xBNP6Je//KVGjhx5za8FNx6bqW/WGgDAZ8uWLdPUqVN9OnMD4NpxRgYAAFgWRQYAAFgWl5YAAIBlcUYGAABYFkUGAABYFkUGAABYFkUGAABYFkUGAABYFkUGAABYFkUGAABYFkUGAABYFkUGAABY1v8Hv1ZtBGJ2H2AAAAAASUVORK5CYII=", "text/plain": [ "
" ] diff --git a/petab_select/analyze.py b/petab_select/analyze.py index 1a23073f..eddf89f3 100644 --- a/petab_select/analyze.py +++ b/petab_select/analyze.py @@ -11,7 +11,6 @@ "group_by_predecessor_model", "group_by_iteration", "get_best_by_iteration", - "get_relative_criterion_values", ] @@ -127,7 +126,7 @@ def get_best_by_iteration( models: Models, *args, **kwargs, -) -> Models: +) -> dict[int, Models]: """Get the best model of each iteration. See :func:``get_best`` for additional required arguments. @@ -139,7 +138,7 @@ def get_best_by_iteration( Forwarded to :func:``get_best``. Returns: - The strictly improving models. + The strictly improving models. Keys are iteration, values are models. """ iterations_models = group_by_iteration(models=models) best_by_iteration = { @@ -151,19 +150,3 @@ def get_best_by_iteration( for iteration, iteration_models in iterations_models.items() } return best_by_iteration - - -def get_relative_criterion_values( - criterion_values: list[float], -) -> list[float]: - """Offset criterion values by their minimum value. - - Args: - criterion_values: - The criterion values. - - Returns: - The relative criterion values. - """ - minimum = min(criterion_values) - return [criterion_value - minimum for criterion_value in criterion_values] diff --git a/petab_select/models.py b/petab_select/models.py index 8028aaa4..72f5c032 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -6,6 +6,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Any, TypeAlias +import numpy as np import pandas as pd import yaml @@ -315,6 +316,15 @@ def get( except KeyError: return default + def values(self) -> Models: + """Get the models. DEPRECATED.""" + warnings.warn( + "`models.values()` is deprecated. Use `models` instead.", + DeprecationWarning, + stacklevel=2, + ) + return self + class Models(ListDict): """A collection of models. @@ -417,6 +427,33 @@ def to_yaml( with open(output_yaml, "w") as f: yaml.safe_dump(model_dicts, f) + def get_criterion( + self, + criterion: Criterion, + as_dict: bool = False, + relative: bool = False, + ) -> list[float] | dict[ModelHash, float]: + """Get the criterion value for all models. + + Args: + criterion: + The criterion. + as_dict: + Whether to return a dictionary, with model hashes for keys. + relative: + Whether to compute criterion values relative to the + smallest criterion value. + + Returns: + The criterion values. + """ + result = [model.get_criterion(criterion=criterion) for model in self] + if relative: + result = list(np.array(result) - min(result)) + if as_dict: + result = dict(zip(self._hashes, result, strict=False)) + return result + def _getattr( self, attr: str, diff --git a/petab_select/plot.py b/petab_select/plot.py index 50deb32c..859c6a33 100644 --- a/petab_select/plot.py +++ b/petab_select/plot.py @@ -15,7 +15,6 @@ from .analyze import ( get_best_by_iteration, - get_relative_criterion_values, group_by_iteration, ) from .constants import Criterion @@ -51,11 +50,7 @@ def upset( The plot axes (see documentation from the `upsetplot `__ package). """ # Get delta criterion values - values = np.array( - get_relative_criterion_values( - [model.get_criterion(criterion) for model in models] - ) - ) + values = np.array(models.get_criterion(criterion=criterion, relative=True)) # Sort by criterion value index = np.argsort(values) @@ -80,7 +75,7 @@ def upset( def line_best_by_iteration( - models: list[Model], + models: Models, criterion: Criterion, relative: bool = True, fz: int = 14, @@ -123,17 +118,17 @@ def line_best_by_iteration( linewidth = 3 iterations = sorted(best_by_iteration) - best_models = [best_by_iteration[iteration] for iteration in iterations] + best_models = Models( + [best_by_iteration[iteration] for iteration in iterations] + ) iteration_labels = [ str(iteration) + f"\n({labels.get(model.get_hash(), model.model_id)})" for iteration, model in zip(iterations, best_models, strict=True) ] - criterion_values = [ - model.get_criterion(criterion) for model in best_models - ] - if relative: - criterion_values = get_relative_criterion_values(criterion_values) + criterion_values = best_models.get_criterion( + criterion=criterion, relative=relative + ) ax.plot( iteration_labels, @@ -207,15 +202,9 @@ def graph_history( if spring_layout_kwargs is None: spring_layout_kwargs = default_spring_layout_kwargs - criterion_values = [model.get_criterion(criterion) for model in models] - if relative: - criterion_values = get_relative_criterion_values(criterion_values) - criterion_values = { - model.get_hash(): criterion_value - for model, criterion_value in zip( - models, criterion_values, strict=False - ) - } + criterion_values = models.get_criterion( + criterion=criterion, relative=relative, as_dict=True + ) if labels is None: labels = { @@ -328,12 +317,12 @@ def bar_criterion_vs_models( if ax is None: _, ax = plt.subplots() - criterion_values = [model.get_criterion(criterion) for model in models] bar_model_labels = [ labels.get(model.get_hash(), model.model_id) for model in models ] - if relative: - criterion_values = get_relative_criterion_values(criterion_values) + criterion_values = models.get_criterion( + criterion=criterion, relative=relative + ) if colors is not None: if label_diff := set(colors).difference(bar_model_labels): @@ -415,12 +404,12 @@ def scatter_criterion_vs_n_estimated( ] n_estimated = [] - criterion_values = [] for model in models: n_estimated.append(len(model.get_estimated_parameter_ids_all())) - criterion_values.append(model.get_criterion(criterion)) - if relative: - criterion_values = get_relative_criterion_values(criterion_values) + + criterion_values = models.get_criterion( + criterion=criterion, relative=relative + ) if max_jitter: n_estimated = np.array(n_estimated, dtype=float) @@ -521,15 +510,9 @@ def graph_iteration_layers( model_estimated_parameters = { model.get_hash(): set(model.estimated_parameters) for model in models } - model_criterion_values = None - model_criterion_values = { - model.get_hash(): model.get_criterion(criterion) for model in models - } - - min_criterion_value = min(model_criterion_values.values()) - model_criterion_values = { - k: v - min_criterion_value for k, v in model_criterion_values.items() - } + model_criterion_values = models.get_criterion( + criterion=criterion, relative=relative, as_dict=True + ) model_parameter_diffs = { model.get_hash(): ( From 53d7afe7805d0a14c26aae3a47d239d89fde25c4 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sat, 14 Dec 2024 00:19:44 +0100 Subject: [PATCH 20/88] update test --- test/analyze/test_analyze.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/analyze/test_analyze.py b/test/analyze/test_analyze.py index 2b084598..32169a85 100644 --- a/test/analyze/test_analyze.py +++ b/test/analyze/test_analyze.py @@ -69,10 +69,11 @@ def test_get_best_by_iteration(models: Models) -> None: assert groups[5].get_hash() == "M-110" -def test_get_relative_criterion_values(models: Models) -> None: +def test_relative_criterion_values(models: Models) -> None: """Test ``analyze.get_relative_criterion_values``.""" - criterion_values = [model.get_criterion(Criterion.AIC) for model in models] - test_value = analyze.get_relative_criterion_values(criterion_values) + # TODO move to test_models.py? + criterion_values = models.get_criterion(criterion=Criterion.AIC) + test_value = models.get_criterion(criterion=Criterion.AIC, relative=True) expected_value = [ criterion_value - min(criterion_values) for criterion_value in criterion_values From ee21f642b0e252464f9fc7989f3ce4d274b0dde9 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sat, 14 Dec 2024 01:12:28 +0100 Subject: [PATCH 21/88] add Model.hashes --- petab_select/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/petab_select/models.py b/petab_select/models.py index 72f5c032..03996adb 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -530,6 +530,10 @@ def df(self) -> pd.DataFrame: } ) + @property + def hashes(self) -> list[ModelHash]: + return self._hashes + def models_from_yaml_list( model_list_yaml: TYPE_PATH, From 74398ae5e8cbace0ec29ce4c0ad99bc480d94bc8 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sat, 14 Dec 2024 11:57:44 +0100 Subject: [PATCH 22/88] test case 0009: add caveat --- test_cases/0009/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test_cases/0009/README.md diff --git a/test_cases/0009/README.md b/test_cases/0009/README.md new file mode 100644 index 00000000..37243b6e --- /dev/null +++ b/test_cases/0009/README.md @@ -0,0 +1,5 @@ +N.B. This original Blasi et al. problem is difficult to solve with a stepwise method. Many forward/backward/forward+backward variants failed. This test case was found by: +1. performing 100 FAMoS starts, initialized at random models. Usually <5% of the starts ended at the best model. +2. assessing reproducibility. Most of the starts that end at the best model are not reproducible. Instead, the path through model space can differ a lot despite "good" calibration, because many pairs of models differ in AICc by less than numerical noise. + +1 start was found that reproducibly ends at the best model. The initial model of that start is the predecessor model in this test case. However, the path through model space is not reproducible -- there are at least two possibilities, perhaps more, depending on simulation tolerances. Hence, you should expect to produce a similar `expected_summary.tsv`, but perhaps with a few rows swapped. If you see a different summary.tsv, please report (or retry a few times). From fb38d2dddd08780c0e86af40230d2c30e247144f Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:34:28 +0100 Subject: [PATCH 23/88] fix notebooks --- doc/examples/example_cli_famos.ipynb | 2 +- .../model_selection/calibrated_M1_4.yaml | 1 + .../model_selection/calibrated_M1_7.yaml | 1 + .../model_selection/calibrated_models_1.yaml | 3 +++ doc/examples/workflow_cli.ipynb | 17 +++++++++++- doc/examples/workflow_python.ipynb | 11 ++++++++ petab_select/model.py | 4 +-- petab_select/ui.py | 27 +++++++++++++++---- 8 files changed, 57 insertions(+), 9 deletions(-) diff --git a/doc/examples/example_cli_famos.ipynb b/doc/examples/example_cli_famos.ipynb index c413cb75..7bc4ceb0 100644 --- a/doc/examples/example_cli_famos.ipynb +++ b/doc/examples/example_cli_famos.ipynb @@ -142,7 +142,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "petab_select/petab_select/candidate_space.py:1142: RuntimeWarning: Model `model_subspace_1-0001011010010010` has been previously excluded from the candidate space so is skipped here.\n", + "petab_select/petab_select/candidate_space.py:1160: RuntimeWarning: Model `model_subspace_1-0001011010010010` has been previously excluded from the candidate space so is skipped here.\n", " return_value = self.inner_candidate_space.consider(model)\n" ] }, diff --git a/doc/examples/model_selection/calibrated_M1_4.yaml b/doc/examples/model_selection/calibrated_M1_4.yaml index b64f141b..c1e94f10 100644 --- a/doc/examples/model_selection/calibrated_M1_4.yaml +++ b/doc/examples/model_selection/calibrated_M1_4.yaml @@ -3,6 +3,7 @@ criteria: estimated_parameters: k2: 0.15 k3: 0.0 +iteration: 1 model_hash: M1_4-000 model_id: M1_4-000 model_subspace_id: M1_4 diff --git a/doc/examples/model_selection/calibrated_M1_7.yaml b/doc/examples/model_selection/calibrated_M1_7.yaml index a3829482..48c64c67 100644 --- a/doc/examples/model_selection/calibrated_M1_7.yaml +++ b/doc/examples/model_selection/calibrated_M1_7.yaml @@ -4,6 +4,7 @@ estimated_parameters: k1: 0.25 k2: 0.1 k3: 0.0 +iteration: 2 model_hash: M1_7-000 model_id: M1_7-000 model_subspace_id: M1_7 diff --git a/doc/examples/model_selection/calibrated_models_1.yaml b/doc/examples/model_selection/calibrated_models_1.yaml index f34ae7bb..9e3a39f0 100644 --- a/doc/examples/model_selection/calibrated_models_1.yaml +++ b/doc/examples/model_selection/calibrated_models_1.yaml @@ -1,6 +1,7 @@ - criteria: AIC: 180 estimated_parameters: {} + iteration: 1 model_hash: M1_0-000 model_id: M1_0-000 model_subspace_id: M1_0 @@ -17,6 +18,7 @@ - criteria: AIC: 100 estimated_parameters: {} + iteration: 1 model_hash: M1_1-000 model_id: M1_1-000 model_subspace_id: M1_1 @@ -33,6 +35,7 @@ - criteria: AIC: 50 estimated_parameters: {} + iteration: 1 model_hash: M1_2-000 model_id: M1_2-000 model_subspace_id: M1_2 diff --git a/doc/examples/workflow_cli.ipynb b/doc/examples/workflow_cli.ipynb index 9acf36b8..930e555e 100644 --- a/doc/examples/workflow_cli.ipynb +++ b/doc/examples/workflow_cli.ipynb @@ -8,7 +8,7 @@ "# Example usage with the CLI\n", "This notebook demonstrates usage of `petab_select` to perform model selection with commands.\n", "\n", - "Note that the criterion values in this notebook are for demonstrative purposes only, and are not real (the models were not calibrated)." + "Note that the criterion values in this notebook are for demonstrative purposes only, and are not real. An additional point is that models store the iteration where they were calibrated, but the iteration counter is stored in the candidate space. Hence, when the candidate space (or method) changes in this notebook, the iteration counter is reset." ] }, { @@ -100,6 +100,7 @@ "text": [ "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_0-000\n", " model_id: M1_0-000\n", " model_subspace_id: M1_0\n", @@ -115,6 +116,7 @@ " predecessor_model_hash: null\n", "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_1-000\n", " model_id: M1_1-000\n", " model_subspace_id: M1_1\n", @@ -130,6 +132,7 @@ " predecessor_model_hash: null\n", "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_2-000\n", " model_id: M1_2-000\n", " model_subspace_id: M1_2\n", @@ -213,6 +216,7 @@ "- criteria:\n", " AIC: 180\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_0-000\n", " model_id: M1_0-000\n", " model_subspace_id: M1_0\n", @@ -229,6 +233,7 @@ "- criteria:\n", " AIC: 100\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_1-000\n", " model_id: M1_1-000\n", " model_subspace_id: M1_1\n", @@ -245,6 +250,7 @@ "- criteria:\n", " AIC: 50\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_2-000\n", " model_id: M1_2-000\n", " model_subspace_id: M1_2\n", @@ -331,6 +337,7 @@ "text": [ "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_4-000\n", " model_id: M1_4-000\n", " model_subspace_id: M1_4\n", @@ -346,6 +353,7 @@ " predecessor_model_hash: M1_2-000\n", "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_6-000\n", " model_id: M1_6-000\n", " model_subspace_id: M1_6\n", @@ -425,6 +433,7 @@ "estimated_parameters:\n", " k2: 0.15\n", " k3: 0.0\n", + "iteration: 1\n", "model_hash: M1_4-000\n", "model_id: M1_4-000\n", "model_subspace_id: M1_4\n", @@ -485,6 +494,7 @@ "text": [ "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 2\n", " model_hash: M1_7-000\n", " model_id: M1_7-000\n", " model_subspace_id: M1_7\n", @@ -550,6 +560,7 @@ " k1: 0.25\n", " k2: 0.1\n", " k3: 0.0\n", + "iteration: 2\n", "model_hash: M1_7-000\n", "model_id: M1_7-000\n", "model_subspace_id: M1_7\n", @@ -689,6 +700,7 @@ "text": [ "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_3-000\n", " model_id: M1_3-000\n", " model_subspace_id: M1_3\n", @@ -704,6 +716,7 @@ " predecessor_model_hash: null\n", "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_5-000\n", " model_id: M1_5-000\n", " model_subspace_id: M1_5\n", @@ -719,6 +732,7 @@ " predecessor_model_hash: null\n", "- criteria: {}\n", " estimated_parameters: {}\n", + " iteration: 1\n", " model_hash: M1_6-000\n", " model_id: M1_6-000\n", " model_subspace_id: M1_6\n", @@ -785,6 +799,7 @@ "estimated_parameters:\n", " k2: 0.15\n", " k3: 0.0\n", + "iteration: 1\n", "model_hash: M1_4-000\n", "model_id: M1_4-000\n", "model_subspace_id: M1_4\n", diff --git a/doc/examples/workflow_python.ipynb b/doc/examples/workflow_python.ipynb index cbc7afb8..a3841421 100644 --- a/doc/examples/workflow_python.ipynb +++ b/doc/examples/workflow_python.ipynb @@ -83,6 +83,7 @@ "Model hash: {model.get_hash()}\n", "Model ID: {model.model_id}\n", "{select_problem.criterion}: {model.get_criterion(select_problem.criterion, compute=False)}\n", + "Model calibrated in iteration: {model.iteration}\n", "\"\"\"\n", " )\n", "\n", @@ -174,6 +175,7 @@ "Model hash: M1_0-000\n", "Model ID: M1_0-000\n", "Criterion.AIC: None\n", + "Model calibrated in iteration: 1\n", "\n" ] } @@ -224,6 +226,7 @@ "Model hash: M1_0-000\n", "Model ID: M1_0-000\n", "Criterion.AIC: 200\n", + "Model calibrated in iteration: 1\n", "\n" ] } @@ -298,6 +301,7 @@ "Model hash: M1_1-000\n", "Model ID: M1_1-000\n", "Criterion.AIC: 150\n", + "Model calibrated in iteration: 2\n", "\n", "Model subspace ID: M1_2\n", "PEtab YAML location: model_selection/petab_problem.yaml\n", @@ -305,6 +309,7 @@ "Model hash: M1_2-000\n", "Model ID: M1_2-000\n", "Criterion.AIC: 140\n", + "Model calibrated in iteration: 2\n", "\n", "\u001b[1mBEST MODEL OF CURRENT ITERATION\u001b[0m\n", "Model subspace ID: M1_3\n", @@ -313,6 +318,7 @@ "Model hash: M1_3-000\n", "Model ID: M1_3-000\n", "Criterion.AIC: 130\n", + "Model calibrated in iteration: 2\n", "\n" ] } @@ -355,6 +361,7 @@ "Model hash: M1_5-000\n", "Model ID: M1_5-000\n", "Criterion.AIC: -70\n", + "Model calibrated in iteration: 3\n", "\n", "\u001b[1mBEST MODEL OF CURRENT ITERATION\u001b[0m\n", "Model subspace ID: M1_6\n", @@ -363,6 +370,7 @@ "Model hash: M1_6-000\n", "Model ID: M1_6-000\n", "Criterion.AIC: -110\n", + "Model calibrated in iteration: 3\n", "\n" ] } @@ -406,6 +414,7 @@ "Model hash: M1_7-000\n", "Model ID: M1_7-000\n", "Criterion.AIC: 50\n", + "Model calibrated in iteration: 4\n", "\n" ] } @@ -494,6 +503,7 @@ "Model hash: M1_6-000\n", "Model ID: M1_6-000\n", "Criterion.AIC: -110\n", + "Model calibrated in iteration: 3\n", "\n" ] } @@ -548,6 +558,7 @@ "Model hash: M1_4-000\n", "Model ID: M1_4-000\n", "Criterion.AIC: None\n", + "Model calibrated in iteration: 1\n", "\n" ] } diff --git a/petab_select/model.py b/petab_select/model.py index a9b7ec20..81d73145 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -111,7 +111,7 @@ class Model(PetabMixin): Criterion(criterion_id_value): float(criterion_value) for criterion_id_value, criterion_value in x.items() }, - ITERATION: lambda x: int(x), + ITERATION: lambda x: int(x) if x is not None else x, } converters_save = { MODEL_ID: lambda x: str(x), @@ -133,7 +133,7 @@ class Model(PetabMixin): criterion_id.value: float(criterion_value) for criterion_id, criterion_value in x.items() }, - ITERATION: lambda x: int(x), + ITERATION: lambda x: int(x) if x is not None else None, } def __init__( diff --git a/petab_select/ui.py b/petab_select/ui.py index 347d1a8e..720a319c 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -33,7 +33,23 @@ ] -def get_iteration(candidate_space: CandidateSpace) -> dict[str, Any]: +def start_iteration_result(candidate_space: CandidateSpace) -> dict[str, Any]: + """Get the state after starting the iteration. + + Args: + candidate_space: + The candidate space. + + Returns: + The candidate space, the uncalibrated models, and the predecessor + model. + """ + # Set model iteration for the models that the calibration tool + # will see. All models (user-supplied and newly-calibrated) will + # have their iteration set (again) in `end_iteration`, via + # `CandidateSpace.get_iteration_calibrated_models` + for model in candidate_space.models: + model.iteration = candidate_space.iteration return { CANDIDATE_SPACE: candidate_space, UNCALIBRATED_MODELS: candidate_space.models, @@ -147,7 +163,7 @@ def start_iteration( candidate_space.set_iteration_user_calibrated_models( user_calibrated_models=user_calibrated_models ) - return get_iteration(candidate_space=candidate_space) + return start_iteration_result(candidate_space=candidate_space) # Exclude the calibrated predecessor model. if not candidate_space.excluded(predecessor_model): @@ -184,7 +200,7 @@ def start_iteration( isinstance(candidate_space, FamosCandidateSpace) and candidate_space.jumped_to_most_distant ): - return get_iteration(candidate_space=candidate_space) + return start_iteration_result(candidate_space=candidate_space) if predecessor_model is not None: candidate_space.reset(predecessor_model) @@ -226,7 +242,7 @@ def start_iteration( candidate_space.set_iteration_user_calibrated_models( user_calibrated_models=user_calibrated_models ) - return get_iteration(candidate_space=candidate_space) + return start_iteration_result(candidate_space=candidate_space) def end_iteration( @@ -337,7 +353,7 @@ def models_to_petab( def get_best( problem: Problem, models: list[Model], - criterion: str | None | None = None, + criterion: str | Criterion | None = None, ) -> Model: """Get the best model from a list of models. @@ -354,6 +370,7 @@ def get_best( The best model. """ # TODO return list, when multiple models are equally "best" + criterion = criterion or problem.criterion return analyze.get_best( models=models, criterion=criterion, compare=problem.compare ) From fe4841638566ee3b7e83b49760632d5df17c0472 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Sat, 14 Dec 2024 21:03:09 +0100 Subject: [PATCH 24/88] update expected test case results --- test/pypesto/generate_expected_models.py | 91 +++++++++++------------- test_cases/0001/expected.yaml | 7 +- test_cases/0002/expected.yaml | 11 +-- test_cases/0003/expected.yaml | 7 +- test_cases/0004/expected.yaml | 11 +-- test_cases/0005/expected.yaml | 11 +-- test_cases/0006/expected.yaml | 9 +-- test_cases/0007/expected.yaml | 7 +- test_cases/0008/expected.yaml | 7 +- test_cases/0009/expected.yaml | 23 +++--- 10 files changed, 94 insertions(+), 90 deletions(-) diff --git a/test/pypesto/generate_expected_models.py b/test/pypesto/generate_expected_models.py index 7d68bd7d..912748ff 100644 --- a/test/pypesto/generate_expected_models.py +++ b/test/pypesto/generate_expected_models.py @@ -19,7 +19,7 @@ # Do not use computationally-expensive test cases in CI skip_test_cases = [ - "0009", + # "0009", ] test_cases_path = Path(__file__).resolve().parent.parent.parent / "test_cases" @@ -41,50 +41,45 @@ def objective_customizer(obj): obj.amici_solver.setRelativeTolerance(1e-12) -# Indentation to match `test_pypesto.py`, to make it easier to keep files similar. -if True: - for test_case_path in test_cases_path.glob("*"): - if test_cases and test_case_path.stem not in test_cases: - continue - - if test_case_path.stem in skip_test_cases: - continue - - expected_model_yaml = test_case_path / "expected.yaml" - - if ( - SKIP_TEST_CASES_WITH_PREEXISTING_EXPECTED_MODEL - and expected_model_yaml.is_file() - ): - # Skip test cases that already have an expected model. - continue - print(f"Running test case {test_case_path.stem}") - - # Setup the pyPESTO model selector instance. - petab_select_problem = petab_select.Problem.from_yaml( - test_case_path / "petab_select_problem.yaml", - ) - pypesto_select_problem = pypesto.select.Problem( - petab_select_problem=petab_select_problem - ) - - # Run the selection process until "exhausted". - pypesto_select_problem.select_to_completion( - minimize_options=minimize_options, - objective_customizer=objective_customizer, - ) - - # Get the best model - best_model = petab_select_problem.get_best( - models=pypesto_select_problem.calibrated_models.values(), - ) - - # Generate the expected model. - best_model.to_yaml( - expected_model_yaml, paths_relative_to=test_case_path - ) - - petab_select.model.models_to_yaml_list( - models=pypesto_select_problem.calibrated_models.values(), - output_yaml="all_models.yaml", - ) +for test_case_path in test_cases_path.glob("*"): + if test_cases and test_case_path.stem not in test_cases: + continue + + if test_case_path.stem in skip_test_cases: + continue + + expected_model_yaml = test_case_path / "expected.yaml" + + if ( + SKIP_TEST_CASES_WITH_PREEXISTING_EXPECTED_MODEL + and expected_model_yaml.is_file() + ): + # Skip test cases that already have an expected model. + continue + print(f"Running test case {test_case_path.stem}") + + # Setup the pyPESTO model selector instance. + petab_select_problem = petab_select.Problem.from_yaml( + test_case_path / "petab_select_problem.yaml", + ) + pypesto_select_problem = pypesto.select.Problem( + petab_select_problem=petab_select_problem + ) + + # Run the selection process until "exhausted". + pypesto_select_problem.select_to_completion( + minimize_options=minimize_options, + objective_customizer=objective_customizer, + ) + + # Get the best model + best_model = petab_select_problem.get_best( + models=pypesto_select_problem.calibrated_models, + ) + + # Generate the expected model. + best_model.to_yaml(expected_model_yaml, paths_relative_to=test_case_path) + + pypesto_select_problem.calibrated_models.to_yaml( + f"all_models_{test_case_path.stem}.yaml" + ) diff --git a/test_cases/0001/expected.yaml b/test_cases/0001/expected.yaml index 7149938b..25c97f14 100644 --- a/test_cases/0001/expected.yaml +++ b/test_cases/0001/expected.yaml @@ -1,8 +1,9 @@ criteria: - AIC: -6.175405094206667 - NLLH: -4.0877025471033335 + AIC: -6.1754055040468785 + NLLH: -4.087702752023439 estimated_parameters: - sigma_x2: 0.1224643186838838 + sigma_x2: 0.12242920616053495 +iteration: 1 model_hash: M1_1-000 model_id: M1_1-000 model_subspace_id: M1_1 diff --git a/test_cases/0002/expected.yaml b/test_cases/0002/expected.yaml index c82acb72..57811a85 100644 --- a/test_cases/0002/expected.yaml +++ b/test_cases/0002/expected.yaml @@ -1,9 +1,10 @@ criteria: - AIC: -4.705325358569107 - NLLH: -4.3526626792845535 + AIC: -4.705325991177407 + NLLH: -4.3526629955887035 estimated_parameters: - k1: 0.20160877227137408 - sigma_x2: 0.11715051179648493 + k1: 0.20160877932991236 + sigma_x2: 0.11714038666761385 +iteration: 2 model_hash: M1_3-000 model_id: M1_3-000 model_subspace_id: M1_3 @@ -16,4 +17,4 @@ parameters: k2: 0.1 k3: 0 petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_0-000 diff --git a/test_cases/0003/expected.yaml b/test_cases/0003/expected.yaml index 48a87a33..a0366cfb 100644 --- a/test_cases/0003/expected.yaml +++ b/test_cases/0003/expected.yaml @@ -1,8 +1,9 @@ criteria: - BIC: -6.383646149270872 - NLLH: -4.087702809249463 + BIC: -6.383646034818824 + NLLH: -4.087702752023439 estimated_parameters: - sigma_x2: 0.12245324237132274 + sigma_x2: 0.12242920723808924 +iteration: 1 model_hash: M1-110 model_id: M1-110 model_subspace_id: M1 diff --git a/test_cases/0004/expected.yaml b/test_cases/0004/expected.yaml index 811edc18..24f8ae41 100644 --- a/test_cases/0004/expected.yaml +++ b/test_cases/0004/expected.yaml @@ -1,9 +1,10 @@ criteria: - AICc: -0.7053253858878037 - NLLH: -4.352662692943902 + AICc: -0.7053259911583094 + NLLH: -4.352662995579155 estimated_parameters: - k1: 0.20160877435934813 - sigma_x2: 0.11714883276066365 + k1: 0.2016087783781175 + sigma_x2: 0.11714035262205941 +iteration: 3 model_hash: M1_3-000 model_id: M1_3-000 model_subspace_id: M1_3 @@ -16,4 +17,4 @@ parameters: k2: 0.1 k3: 0 petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_6-000 diff --git a/test_cases/0005/expected.yaml b/test_cases/0005/expected.yaml index 897a2432..c30365a8 100644 --- a/test_cases/0005/expected.yaml +++ b/test_cases/0005/expected.yaml @@ -1,9 +1,10 @@ criteria: - AIC: -4.705325086169246 - NLLH: -4.352662543084623 + AIC: -4.705325991200599 + NLLH: -4.3526629956003 estimated_parameters: - k1: 0.20160877910494426 - sigma_x2: 0.11716072823171682 + k1: 0.2016087798698859 + sigma_x2: 0.11714036476432785 +iteration: 2 model_hash: M1_3-000 model_id: M1_3-000 model_subspace_id: M1_3 @@ -16,4 +17,4 @@ parameters: k2: 0.1 k3: 0 petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_0-000 diff --git a/test_cases/0006/expected.yaml b/test_cases/0006/expected.yaml index efd80860..c8e92c9c 100644 --- a/test_cases/0006/expected.yaml +++ b/test_cases/0006/expected.yaml @@ -1,8 +1,9 @@ criteria: - AIC: -6.175403277446156 - NLLH: -4.087701638723078 + AIC: -6.1754055040468785 + NLLH: -4.087702752023439 estimated_parameters: - sigma_x2: 0.12248840167611977 + sigma_x2: 0.12242920606535417 +iteration: 1 model_hash: M1_0-000 model_id: M1_0-000 model_subspace_id: M1_0 @@ -15,4 +16,4 @@ parameters: k2: 0.1 k3: 0 petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: virtual_initial_model diff --git a/test_cases/0007/expected.yaml b/test_cases/0007/expected.yaml index b843cd92..4efd158a 100644 --- a/test_cases/0007/expected.yaml +++ b/test_cases/0007/expected.yaml @@ -1,7 +1,8 @@ criteria: - AIC: 11.117195852885663 - NLLH: 5.558597926442832 + AIC: 11.117195861535194 + NLLH: 5.558597930767597 estimated_parameters: {} +iteration: 1 model_hash: M1_0-000 model_id: M1_0-000 model_subspace_id: M1_0 @@ -14,4 +15,4 @@ parameters: k2: 0.1 k3: 0 petab_yaml: petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: virtual_initial_model diff --git a/test_cases/0008/expected.yaml b/test_cases/0008/expected.yaml index 0fb56440..6162ff4c 100644 --- a/test_cases/0008/expected.yaml +++ b/test_cases/0008/expected.yaml @@ -1,7 +1,8 @@ criteria: - AICc: 11.117195852885663 - NLLH: 5.558597926442832 + AICc: 11.117195861535194 + NLLH: 5.558597930767597 estimated_parameters: {} +iteration: 4 model_hash: M1_0-000 model_id: M1_0-000 model_subspace_id: M1_0 @@ -14,4 +15,4 @@ parameters: k2: 0.1 k3: 0 petab_yaml: ../0007/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_3-000 diff --git a/test_cases/0009/expected.yaml b/test_cases/0009/expected.yaml index 1c0260c3..6abbaa99 100644 --- a/test_cases/0009/expected.yaml +++ b/test_cases/0009/expected.yaml @@ -1,15 +1,16 @@ criteria: - AICc: -1708.110992459583 - NLLH: -862.3517925260878 + AICc: -1708.1109924658595 + NLLH: -862.351792529226 estimated_parameters: - a_0ac_k08: 0.4085198712518596 - a_b: 0.06675755142350405 - a_k05_k05k12: 30.888893099662752 - a_k05k12_k05k08k12: 4.872831719884531 - a_k08k12k16_4ac: 53.80209580336034 - a_k12_k05k12: 8.26789880667234 - a_k12k16_k08k12k16: 33.038691003614964 - a_k16_k12k16: 10.424836834041892 + a_0ac_k08: 0.4085141271467614 + a_b: 0.06675812072340812 + a_k05_k05k12: 30.88819982704895 + a_k05k12_k05k08k12: 4.872706275493909 + a_k08k12k16_4ac: 53.80184925213997 + a_k12_k05k12: 8.267871339049703 + a_k12k16_k08k12k16: 33.03793450182137 + a_k16_k12k16: 10.42455614921354 +iteration: 11 model_hash: M-01000100001000010010000000010001 model_id: M-01000100001000010010000000010001 model_subspace_id: M @@ -80,4 +81,4 @@ parameters: a_k16_k08k16: 1 a_k16_k12k16: estimate petab_yaml: petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M-01000100001010010010000000010001 From 1fa657914c3ed8c0ce81c7acd28910805019ab82 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sun, 15 Dec 2024 16:51:40 +0100 Subject: [PATCH 25/88] start sorting of constants --- petab_select/constants.py | 212 +++++++++++++++++++++----------------- 1 file changed, 115 insertions(+), 97 deletions(-) diff --git a/petab_select/constants.py b/petab_select/constants.py index 2946aeb5..482b02b7 100644 --- a/petab_select/constants.py +++ b/petab_select/constants.py @@ -8,110 +8,71 @@ from pathlib import Path from typing import Literal -# Zero-indexed column/row indices -MODEL_ID_COLUMN = 0 -PETAB_YAML_COLUMN = 1 -# It is assumed that all columns after PARAMETER_DEFINITIONS_START contain -# parameter IDs. -PARAMETER_DEFINITIONS_START = 2 -HEADER_ROW = 0 +# Checked -PARAMETER_VALUE_DELIMITER = ";" -CODE_DELIMITER = "-" -ESTIMATE = "estimate" -PETAB_ESTIMATE_FALSE = 0 -PETAB_ESTIMATE_TRUE = 1 +# Criteria +CRITERIA = "criteria" +CRITERION = "criterion" -# TYPING_PATH = Union[str, Path] -TYPE_PATH = str | Path -# Model space file columns -# TODO ensure none of these occur twice in the column header (this would -# suggest that a parameter has a conflicting name) -# MODEL_ID = 'modelId' # TODO already defined, reorganize constants -# YAML = 'YAML' # FIXME +class Criterion(str, Enum): + """String literals for model selection criteria.""" + + #: The Akaike information criterion. + AIC = "AIC" + #: The corrected Akaike information criterion. + AICC = "AICc" + #: The Bayesian information criterion. + BIC = "BIC" + #: The likelihood. + LH = "LH" + #: The log-likelihood. + LLH = "LLH" + #: The negative log-likelihood. + NLLH = "NLLH" + #: The sum of squared residuals. + SSR = "SSR" + + +# Model +ESTIMATED_PARAMETERS = "estimated_parameters" +ITERATION = "iteration" MODEL_ID = "model_id" MODEL_SUBSPACE_ID = "model_subspace_id" MODEL_SUBSPACE_INDICES = "model_subspace_indices" -MODEL_CODE = "model_code" +PARAMETERS = "parameters" +MODEL_SUBSPACE_PETAB_YAML = "model_subspace_petab_yaml" +PETAB_YAML = "petab_yaml" +ESTIMATE = "estimate" + +PETAB_PROBLEM = "petab_problem" + +# Model hash MODEL_HASH = "model_hash" -MODEL_HASHES = "model_hashes" MODEL_HASH_DELIMITER = "-" +MODEL_SUBSPACE_INDICES_HASH = "model_subspace_indices_hash" MODEL_SUBSPACE_INDICES_HASH_DELIMITER = "." MODEL_SUBSPACE_INDICES_HASH_MAP = ( # [0-9]+[A-Z]+[a-z] string.digits + string.ascii_uppercase + string.ascii_lowercase ) -PETAB_HASH_DIGEST_SIZE = None -# If `predecessor_model_hash` is defined for a model, it is the ID of the model that the -# current model was/is to be compared to. This is part of the result and is -# only (optionally) set by the PEtab calibration tool. It is not defined by the -# PEtab Select model selection problem (but may be subsequently stored in the -# PEtab Select model report format. PREDECESSOR_MODEL_HASH = "predecessor_model_hash" -ITERATION = "iteration" -PETAB_PROBLEM = "petab_problem" -PETAB_YAML = "petab_yaml" -HASH = "hash" - -# MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS = [MODEL_ID, PETAB_YAML] -MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS = [MODEL_SUBSPACE_ID, PETAB_YAML] -# COMPARED_MODEL_ID = 'compared_'+MODEL_ID -YAML_FILENAME = "yaml" - -# DISTANCES = { -# FORWARD: { -# 'l1': 1, -# 'size': 1, -# }, -# BACKWARD: { -# 'l1': 1, -# 'size': -1, -# }, -# LATERAL: { -# 'l1': 2, -# 'size': 0, -# }, -# } - -CRITERIA = "criteria" - -PARAMETERS = "parameters" -# PARAMETER_ESTIMATE = 'parameter_estimate' -ESTIMATED_PARAMETERS = "estimated_parameters" - -# Problem keys -CRITERION = "criterion" -METHOD = "method" -VERSION = "version" +# Problem MODEL_SPACE_FILES = "model_space_files" -PROBLEM_ID = "problem_id" PROBLEM = "problem" +PROBLEM_ID = "problem_id" +VERSION = "version" +# Candidate space CANDIDATE_SPACE = "candidate_space" CANDIDATE_SPACE_ARGUMENTS = "candidate_space_arguments" +METHOD = "method" METHOD_SCHEME = "method_scheme" -PREVIOUS_METHODS = "previous_methods" NEXT_METHOD = "next_method" +PREVIOUS_METHODS = "previous_methods" PREDECESSOR_MODEL = "predecessor_model" -MODEL = "model" -MODELS = "models" -UNCALIBRATED_MODELS = "uncalibrated_models" -TERMINATE = "terminate" - -# Parameters can be fixed to a value, or estimated if indicated with the string -# `ESTIMATE`. -TYPE_PARAMETER = float | int | Literal[ESTIMATE] -TYPE_PARAMETER_OPTIONS = list[TYPE_PARAMETER] -# Parameter ID -> parameter value mapping. -TYPE_PARAMETER_DICT = dict[str, TYPE_PARAMETER] -# Parameter ID -> multiple possible parameter values. -TYPE_PARAMETER_OPTIONS_DICT = dict[str, TYPE_PARAMETER_OPTIONS] - -TYPE_CRITERION = float - class Method(str, Enum): """String literals for model selection methods.""" @@ -130,24 +91,12 @@ class Method(str, Enum): MOST_DISTANT = "most_distant" -class Criterion(str, Enum): - """String literals for model selection criteria.""" - - #: The Akaike information criterion. - AIC = "AIC" - #: The corrected Akaike information criterion. - AICC = "AICc" - #: The Bayesian information criterion. - BIC = "BIC" - #: The likelihood. - LH = "LH" - #: The log-likelihood. - LLH = "LLH" - #: The negative log-likelihood. - NLLH = "NLLH" - #: The sum of squared residuals. - SSR = "SSR" +# Typing +TYPE_PATH = str | Path +# UI +UNCALIBRATED_MODELS = "uncalibrated_models" +TERMINATE = "terminate" #: Methods that move through model space by taking steps away from some model. STEPWISE_METHODS = [ @@ -163,6 +112,7 @@ class Criterion(str, Enum): ] #: Virtual initial models can be used to initialize some initial model methods. +# FIXME replace by real "dummy" model object VIRTUAL_INITIAL_MODEL = "virtual_initial_model" #: Methods that are compatible with a virtual initial model. VIRTUAL_INITIAL_MODEL_METHODS = [ @@ -177,3 +127,71 @@ class Criterion(str, Enum): if not x.startswith("_") and x not in ("sys", "Enum", "Path", "Dict", "List", "Literal", "Union") ] + + +# Unchecked +MODEL = "model" +MODELS = "models" + +# Zero-indexed column/row indices +MODEL_ID_COLUMN = 0 +PETAB_YAML_COLUMN = 1 +# It is assumed that all columns after PARAMETER_DEFINITIONS_START contain +# parameter IDs. +PARAMETER_DEFINITIONS_START = 2 +HEADER_ROW = 0 + +PARAMETER_VALUE_DELIMITER = ";" +CODE_DELIMITER = "-" +PETAB_ESTIMATE_FALSE = 0 +PETAB_ESTIMATE_TRUE = 1 + +# TYPING_PATH = Union[str, Path] + +# Model space file columns +# TODO ensure none of these occur twice in the column header (this would +# suggest that a parameter has a conflicting name) +# MODEL_ID = 'modelId' # TODO already defined, reorganize constants +# YAML = 'YAML' # FIXME +MODEL_CODE = "model_code" +MODEL_HASHES = "model_hashes" +PETAB_HASH_DIGEST_SIZE = None +# If `predecessor_model_hash` is defined for a model, it is the ID of the model that the +# current model was/is to be compared to. This is part of the result and is +# only (optionally) set by the PEtab calibration tool. It is not defined by the +# PEtab Select model selection problem (but may be subsequently stored in the +# PEtab Select model report format. +HASH = "hash" + +# MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS = [MODEL_ID, PETAB_YAML] +MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS = [MODEL_SUBSPACE_ID, PETAB_YAML] + +# COMPARED_MODEL_ID = 'compared_'+MODEL_ID +YAML_FILENAME = "yaml" + +# DISTANCES = { +# FORWARD: { +# 'l1': 1, +# 'size': 1, +# }, +# BACKWARD: { +# 'l1': 1, +# 'size': -1, +# }, +# LATERAL: { +# 'l1': 2, +# 'size': 0, +# }, +# } + + +# Parameters can be fixed to a value, or estimated if indicated with the string +# `ESTIMATE`. +TYPE_PARAMETER = float | int | Literal[ESTIMATE] +TYPE_PARAMETER_OPTIONS = list[TYPE_PARAMETER] +# Parameter ID -> parameter value mapping. +TYPE_PARAMETER_DICT = dict[str, TYPE_PARAMETER] +# Parameter ID -> multiple possible parameter values. +TYPE_PARAMETER_OPTIONS_DICT = dict[str, TYPE_PARAMETER_OPTIONS] + +TYPE_CRITERION = float From a7a7db60221ecca6e228d9c3521afffd9296726d Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sun, 15 Dec 2024 16:59:29 +0100 Subject: [PATCH 26/88] refactor `Model` with mkstd --- petab_select/model.py | 1242 +++++++++++--------------------- petab_select/model_subspace.py | 2 +- pyproject.toml | 1 + 3 files changed, 421 insertions(+), 824 deletions(-) diff --git a/petab_select/model.py b/petab_select/model.py index 81d73145..5736a8f6 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -2,489 +2,534 @@ from __future__ import annotations +import copy import warnings from os.path import relpath from pathlib import Path -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar, Literal +import mkstd import petab.v1 as petab -import yaml -from more_itertools import one -from petab.v1.C import ESTIMATE, NOMINAL_VALUE +from petab.v1.C import NOMINAL_VALUE from .constants import ( CRITERIA, - ESTIMATED_PARAMETERS, - ITERATION, + ESTIMATE, MODEL_HASH, MODEL_HASH_DELIMITER, MODEL_ID, MODEL_SUBSPACE_ID, MODEL_SUBSPACE_INDICES, + MODEL_SUBSPACE_INDICES_HASH, MODEL_SUBSPACE_INDICES_HASH_DELIMITER, MODEL_SUBSPACE_INDICES_HASH_MAP, + MODEL_SUBSPACE_PETAB_YAML, PARAMETERS, - PETAB_ESTIMATE_TRUE, PETAB_PROBLEM, PETAB_YAML, - PREDECESSOR_MODEL_HASH, - TYPE_CRITERION, - TYPE_PARAMETER, - TYPE_PATH, - VIRTUAL_INITIAL_MODEL, Criterion, ) from .criteria import CriterionComputer from .misc import ( parameter_string_to_value, ) -from .petab import PetabMixin if TYPE_CHECKING: from .problem import Problem + +from pydantic import ( + BaseModel, + FilePath, + PrivateAttr, + ValidationInfo, + ValidatorFunctionWrapHandler, +) + __all__ = [ "Model", "default_compare", "ModelHash", - "VIRTUAL_INITIAL_MODEL_HASH", + "VIRTUAL_INITIAL_MODEL", ] +from pydantic import Field, model_serializer, model_validator -class Model(PetabMixin): - """A (possibly uncalibrated) model. - NB: some of these attribute names correspond to constants defined in the - `constants.py` file, to facilitate loading models from/saving models to - disk (see the `Model.saved_attributes` class attribute). +def default_compare(): + pass + + +class ModelHash(BaseModel): + """The model hash. + + The model hash is designed to be human-readable and able to be converted + back into the corresponding model. Currently, if two models from two + different model subspaces are actually the same PEtab problem, they will + still have different model hashes. Attributes: - converters_load: - Functions to convert attributes from YAML to :class:`Model`. - converters_save: - Functions to convert attributes from :class:`Model` to YAML. - criteria: - The criteria values of the calibrated model (e.g. AIC). - iteration: - The iteration of the model selection algorithm where this model was - identified. - model_id: - The model ID. - petab_yaml: - The path to the PEtab problem YAML file. - parameters: - Parameter values that will overwrite the PEtab problem definition, - or change parameters to be estimated. - estimated_parameters: - Parameter estimates from a model calibration tool, for parameters - that are specified as estimated in the PEtab problem or PEtab - Select model YAML. These are untransformed values (i.e., not on - log scale). - saved_attributes: - Attributes that will be saved to disk by the :meth:`Model.to_yaml` - method. + model_subspace_id: + The ID of the model subspace of the model. Unique up to a single + PEtab Select problem model space. + model_subspace_indices_hash: + A hash of the location of the model in its model + subspace. Unique up to a single model subspace. """ - saved_attributes = ( - MODEL_ID, - MODEL_SUBSPACE_ID, - MODEL_SUBSPACE_INDICES, - MODEL_HASH, - PREDECESSOR_MODEL_HASH, - PETAB_YAML, - PARAMETERS, - ESTIMATED_PARAMETERS, - CRITERIA, - ITERATION, - ) - converters_load = { - MODEL_ID: lambda x: x, - MODEL_SUBSPACE_ID: lambda x: x, - MODEL_SUBSPACE_INDICES: lambda x: [] if not x else x, - MODEL_HASH: lambda x: x, - PREDECESSOR_MODEL_HASH: lambda x: x, - PETAB_YAML: lambda x: x, - PARAMETERS: lambda x: x, - ESTIMATED_PARAMETERS: lambda x: x, - CRITERIA: lambda x: { - # `criterion_id_value` is the ID of the criterion in the enum `Criterion`. - Criterion(criterion_id_value): float(criterion_value) - for criterion_id_value, criterion_value in x.items() - }, - ITERATION: lambda x: int(x) if x is not None else x, - } - converters_save = { - MODEL_ID: lambda x: str(x), - MODEL_SUBSPACE_ID: lambda x: str(x), - MODEL_SUBSPACE_INDICES: lambda x: [int(xi) for xi in x], - MODEL_HASH: lambda x: str(x), - PREDECESSOR_MODEL_HASH: lambda x: str(x) if x is not None else x, - PETAB_YAML: lambda x: str(x), - PARAMETERS: lambda x: {str(k): v for k, v in x.items()}, - # FIXME handle with a `set_estimated_parameters` method instead? - # to avoid `float` cast here. Reason for cast is because e.g. pyPESTO - # can provide type `np.float64`, which causes issues when writing to - # YAML. - # ESTIMATED_PARAMETERS: lambda x: x, - ESTIMATED_PARAMETERS: lambda x: { - str(id): float(value) for id, value in x.items() - }, - CRITERIA: lambda x: { - criterion_id.value: float(criterion_value) - for criterion_id, criterion_value in x.items() - }, - ITERATION: lambda x: int(x) if x is not None else None, - } + model_subspace_id: str + model_subspace_indices_hash: str - def __init__( - self, - petab_yaml: TYPE_PATH, - model_subspace_id: str = None, - model_id: str = None, - model_subspace_indices: list[int] = None, - predecessor_model_hash: str = None, - parameters: dict[str, int | float] = None, - estimated_parameters: dict[str, int | float] = None, - criteria: dict[str, float] = None, - iteration: int = None, - # Optionally provided to reduce repeated parsing of `petab_yaml`. - petab_problem: petab.Problem | None = None, - model_hash: Any | None = None, - ): - self.model_id = model_id - self.model_subspace_id = model_subspace_id - self.model_subspace_indices = model_subspace_indices - # TODO clean parameters, ensure single float or str (`ESTIMATE`) type - self.parameters = parameters - self.estimated_parameters = estimated_parameters - self.criteria = criteria - self.iteration = iteration + @model_validator(mode="wrap") + def check_kwargs( + kwargs: dict[str, str | list[int]] | ModelHash, + handler: ValidatorFunctionWrapHandler, + info: ValidationInfo, + ) -> ModelHash: + """Handle `ModelHash` creation from different sources. + + See documentation of Pydantic wrap validators. + """ + if isinstance(kwargs, ModelHash): + return kwargs + + if isinstance(kwargs, dict): + kwargs[MODEL_SUBSPACE_INDICES_HASH] = ( + ModelHash.hash_model_subspace_indices( + kwargs[MODEL_SUBSPACE_INDICES] + ) + ) + del kwargs[MODEL_SUBSPACE_INDICES] + + if isinstance(kwargs, str): + kwargs = ModelHash.kwargs_from_str(hash_str=kwargs) + + expected_model_hash = None + if MODEL_HASH in kwargs: + expected_model_hash = kwargs[MODEL_HASH] + if isinstance(expected_model_hash, str): + expected_model_hash = ModelHash.from_str(expected_model_hash) + del kwargs[MODEL_HASH] + + model_hash = handler(kwargs) + + if expected_model_hash is not None: + if model_hash != expected_model_hash: + warnings.warn( + "The provided model hash is inconsistent with its model " + "subspace and model subspace indices. Old hash: " + f"`{expected_model_hash}`. New hash: `{model_hash}`.", + stacklevel=2, + ) + + return model_hash + + @model_serializer() + def _serialize(self) -> str: + return str(self) + + @staticmethod + def kwargs_from_str(hash_str: str) -> dict[str, str]: + """Convert a model hash string into constructor kwargs.""" + return dict( + zip( + [MODEL_SUBSPACE_ID, MODEL_SUBSPACE_INDICES_HASH], + hash_str.split(MODEL_HASH_DELIMITER), + strict=False, + ) + ) + + @staticmethod + def hash_model_subspace_indices(model_subspace_indices: list[int]) -> str: + """Hash the location of a model in its subspace. + + Args: + model_subspace_indices: + The location (indices) of the model in its subspace. + + Returns: + The hash. + """ + if max(model_subspace_indices) < len(MODEL_SUBSPACE_INDICES_HASH_MAP): + return "".join( + MODEL_SUBSPACE_INDICES_HASH_MAP[index] + for index in model_subspace_indices + ) + return MODEL_SUBSPACE_INDICES_HASH_DELIMITER.join( + str(i) for i in model_subspace_indices + ) + + def unhash_model_subspace_indices(self) -> list[int]: + """Get the location of a model in its subspace. + + Returns: + The location, as indices of the subspace. + """ + if ( + MODEL_SUBSPACE_INDICES_HASH_DELIMITER + not in self.model_subspace_indices_hash + ): + return [ + MODEL_SUBSPACE_INDICES_HASH_MAP.index(s) + for s in self.model_subspace_indices_hash + ] + return [ + int(s) + for s in self.model_subspace_indices_hash.split( + MODEL_SUBSPACE_INDICES_HASH_DELIMITER + ) + ] + + def get_model(self, problem: Problem) -> Model: + """Get the model that a hash corresponds to. + + Args: + problem: + The :class:`Problem` that will be used to look up the model. + + Returns: + The model. + """ + return problem.model_space.model_subspaces[ + self.model_subspace_id + ].indices_to_model(self.unhash_model_subspace_indices()) + + def __hash__(self) -> str: + """Not the model hash! Use `Model.hash` instead.""" + return hash(str(self)) + + def __eq__(self, other_hash: str | ModelHash) -> bool: + """Check whether two model hashes are equivalent.""" + return str(self) == str(other_hash) + + def __str__(self) -> str: + """Convert the hash to a string.""" + return MODEL_HASH_DELIMITER.join( + [self.model_subspace_id, self.model_subspace_indices_hash] + ) + + def __repr__(self) -> str: + """Convert the hash to a string representation.""" + return str(self) + + +class ModelBase(BaseModel): + """Definition of the standardized model. + + :class:`Model` is extended with additional helper methods -- use that + instead of ``ModelBase``. + """ + + model_subspace_id: str + """The ID of the subspace that this model belongs to.""" + model_subspace_indices: list[int] + """The location of this model in its subspace.""" + model_subspace_petab_yaml: FilePath | None + """The base PEtab problem for the model subspace. + + N.B.: Not the PEtab problem for this model specifically! + Use :meth:`Model.to_petab` to get the model-specific PEtab + problem. + """ + criteria: dict[Criterion, float] | None = Field(default=None) + """The criterion values of the calibrated model (e.g. AIC).""" + estimated_parameters: dict[str, float] | None = Field(default=None) + """The parameter estimates of the calibrated model (always unscaled).""" + iteration: int | None = Field(default=None) + """The iteration of model selection that calibrated this model.""" + model_id: str = Field(default=None) + """The model ID.""" + model_hash: ModelHash = Field(default=None) + """The model hash (treat as read-only after initialization).""" + parameters: dict[str, float | int | Literal[ESTIMATE]] + """PEtab problem parameters overrides for this model. + + For example, fixes parameters to certain values, or sets them to be + estimated. + """ + predecessor_model_hash: ModelHash | None = Field(default=None) + """The predecessor model hash.""" + + PATH_ATTRIBUTES: ClassVar[list[str]] = [ + MODEL_SUBSPACE_PETAB_YAML, + ] + + @model_validator(mode="after") + def _check_hash(self: ModelBase) -> ModelBase: + kwargs = { + MODEL_SUBSPACE_ID: self.model_subspace_id, + MODEL_SUBSPACE_INDICES: self.model_subspace_indices, + } + if self.model_hash is not None: + kwargs[MODEL_HASH] = self.model_hash + self.model_hash = ModelHash.model_validate(kwargs) - self.predecessor_model_hash = predecessor_model_hash if self.predecessor_model_hash is not None: - self.predecessor_model_hash = ModelHash.from_hash( + self.predecessor_model_hash = ModelHash.model_validate( self.predecessor_model_hash ) - if self.parameters is None: - self.parameters = {} - if self.estimated_parameters is None: - self.estimated_parameters = {} - if self.criteria is None: - self.criteria = {} - - super().__init__(petab_yaml=petab_yaml, petab_problem=petab_problem) + return self - self.model_hash = None - self.get_hash() - if model_hash is not None: - model_hash = ModelHash.from_hash(model_hash) - if self.model_hash != model_hash: - raise ValueError( - "The supplied model hash does not match the computed " - "model hash." - ) + @model_validator(mode="after") + def _check_id(self: ModelBase) -> ModelBase: if self.model_id is None: - self.model_id = self.get_hash() + self.model_id = str(self.hash) + return self + + @property + def hash(self) -> ModelHash: + """Get the model hash.""" + return self.model_hash - self.criterion_computer = CriterionComputer(self) + def __hash__(self) -> None: + """Use ``Model.hash`` instead.""" + raise NotImplementedError("Use ``Model.hash`` instead.") - def set_criterion(self, criterion: Criterion, value: float) -> None: - """Set a criterion value for the model. + @staticmethod + def from_yaml( + yaml_path: str | Path, + root_path: str | Path | bool = True, + ) -> ModelBase: + """Load a model from a YAML file. Args: - criterion: - The criterion (e.g. ``petab_select.constants.Criterion.AIC``). - value: - The criterion value for the (presumably calibrated) model. + yaml_path: + The model YAML file location. + root_path: + All paths will be resolved relative to this. + If ``True``, this will be set to the directory of the + ``yaml_path``. + If ``False``, this will be set to the current working + directory. """ - if criterion in self.criteria: - warnings.warn( - "Overwriting saved criterion value. " - f"Criterion: {criterion}. Value: {self.get_criterion(criterion)}.", - stacklevel=2, - ) - # FIXME debug why value is overwritten during test case 0002. - if False: - print( - "Overwriting saved criterion value. " - f"Criterion: {criterion}. Value: {self.get_criterion(criterion)}." - ) - breakpoint() - self.criteria[criterion] = value + if root_path is True: + root_path = Path(yaml_path).parent + if root_path is False: + root_path = Path() - def has_criterion(self, criterion: Criterion) -> bool: - """Check whether the model provides a value for a criterion. + model = ModelStandard.load_data(filename=yaml_path) + model.resolve_paths(root_path=root_path) + return model + + def to_yaml( + self, + yaml_path: str | Path, + root_path: str | Path | bool = True, + ) -> None: + """Save a model to a YAML file. Args: - criterion: - The criterion (e.g. `petab_select.constants.Criterion.AIC`). + yaml_path: + The model YAML file location. + root_path: + All paths will be converted to paths that are + relative to this directory path. + If ``True``, this will be set to the directory of the + ``yaml_path``. + If ``False``, this will be set to the current working + directory. """ - # TODO also `and self.criteria[id] is not None`? - return criterion in self.criteria + if root_path is True: + root_path = Path(yaml_path).parent + if root_path is False: + root_path = Path() + + model = copy.deepcopy(self) + model.set_relative_paths(root_path=root_path) + ModelStandard.save_data(data=model, filename=yaml_path) + + def resolve_paths(self, root_path: str | Path) -> None: + """Resolve all relative paths with respect to ``root_path``.""" + for path_attribute in self.PATH_ATTRIBUTES: + setattr( + self, + path_attribute, + (Path(root_path) / getattr(self, path_attribute)).resolve(), + ) + + def set_relative_paths(self, root_path: str | Path) -> None: + """Change all paths to be relative to ``root_path``.""" + for path_attribute in self.PATH_ATTRIBUTES: + setattr( + self, + path_attribute, + relpath( + Path(self.model_subspace_petab_yaml).resolve(), + start=Path(root_path).resolve(), + ), + ) + + +class Model(ModelBase): + """A model. + + See :class:`ModelBase` for the standardized attributes. Additional + attributes are available in ``Model`` to improve usability. + + Attributes: + _model_subspace_petab_problem: + The PEtab problem of the model subspace of this model. + If not provided, this is reconstructed from + :attr:`model_subspace_petab_yaml`. + """ + + _model_subspace_petab_problem: petab.Problem = PrivateAttr(default=None) + + @model_validator(mode="after") + def _check_petab_problem(self: Model) -> Model: + if ( + self._model_subspace_petab_problem is None + and self.model_subspace_petab_yaml is not None + ): + self._model_subspace_petab_problem = petab.Problem.from_yaml( + self.model_subspace_petab_yaml + ) + return self + + def model_post_init(self, __context: Any) -> None: + """Add additional instance attributes.""" + self._criterion_computer = CriterionComputer(self) + + def has_criterion(self, criterion: Criterion) -> bool: + """Check whether a value for a criterion has been set.""" + return self.criteria.get(criterion) is not None + + def set_criterion(self, criterion: Criterion, value: float) -> None: + """Set a criterion value.""" + if self.has_criterion(criterion=criterion): + warnings.warn( + f"Overwriting saved criterion value. Criterion: {criterion}. " + f"Value: `{self.get_criterion(criterion)}`.", + stacklevel=2, + ) + self.criteria[criterion] = value def get_criterion( self, criterion: Criterion, compute: bool = True, raise_on_failure: bool = True, - ) -> TYPE_CRITERION | None: + ) -> float | None: """Get a criterion value for the model. Args: criterion: - The ID of the criterion (e.g. ``petab_select.constants.Criterion.AIC``). + The criterion. compute: - Whether to try to compute the criterion value based on other model - attributes. For example, if the ``'AIC'`` criterion is requested, this - can be computed from a predetermined model likelihood and its - number of estimated parameters. + Whether to attempt computing the criterion value. For example, + the AIC can be computed if the likelihood is available. raise_on_failure: - Whether to raise a `ValueError` if the criterion could not be - computed. If `False`, `None` is returned. + Whether to raise a ``ValueError`` if the criterion could not be + computed. If ``False``, ``None`` is returned. Returns: - The criterion value, or `None` if it is not available. - TODO check for previous use of this method before `.get` was used + The criterion value, or ``None`` if it is not available. """ - if criterion not in self.criteria and compute: + if not self.has_criterion(criterion=criterion) and compute: self.compute_criterion( criterion=criterion, raise_on_failure=raise_on_failure, ) - # value = self.criterion_computer(criterion=id) - # self.set_criterion(id=id, value=value) - return self.criteria.get(criterion, None) def compute_criterion( self, criterion: Criterion, raise_on_failure: bool = True, - ) -> TYPE_CRITERION: + ) -> float: """Compute a criterion value for the model. - The value will also be stored, which will overwrite any previously stored value - for the criterion. + The value will also be stored, which will overwrite any previously + stored value for the criterion. Args: criterion: - The ID of the criterion - (e.g. :obj:`petab_select.constants.Criterion.AIC`). + The criterion. raise_on_failure: - Whether to raise a `ValueError` if the criterion could not be - computed. If `False`, `None` is returned. + Whether to raise a ``ValueError`` if the criterion could not be + computed. If ``False``, ``None`` is returned. Returns: The criterion value. """ + criterion_value = None try: - criterion_value = self.criterion_computer(criterion) + criterion_value = self._criterion_computer(criterion) self.set_criterion(criterion, criterion_value) - result = criterion_value except ValueError as err: if raise_on_failure: raise ValueError( - f"Insufficient information to compute criterion `{criterion}`." + "Insufficient information to compute criterion " + f"`{criterion}`." ) from err - result = None - return result + return criterion_value def set_estimated_parameters( self, estimated_parameters: dict[str, float], scaled: bool = False, ) -> None: - """Set the estimated parameters. + """Set parameter estimates. Args: estimated_parameters: The estimated parameters. scaled: - Whether the ``estimated_parameters`` values are on the scale - defined in the PEtab problem (``True``), or untransformed - (``False``). + Whether the parameter estimates are on the scale defined in the + PEtab problem (``True``), or unscaled (``False``). """ if scaled: - estimated_parameters = self.petab_problem.unscale_parameters( - estimated_parameters - ) - self.estimated_parameters = estimated_parameters - - @staticmethod - def from_dict( - model_dict: dict[str, Any], - base_path: TYPE_PATH = None, - petab_problem: petab.Problem = None, - ) -> Model: - """Generate a model from a dictionary of attributes. - - Args: - model_dict: - A dictionary of attributes. The keys are attribute - names, the values are the corresponding attribute values for - the model. Required attributes are the required arguments of - the :meth:`Model.__init__` method. - base_path: - The path that any relative paths in the model are relative to - (e.g. the path to the PEtab problem YAML file - :meth:`Model.petab_yaml` may be relative). - petab_problem: - Optionally provide the PEtab problem, to avoid loading it multiple - times. - NB: This may cause issues if multiple models write to the same PEtab - problem in memory. - - Returns: - A model instance, initialized with the provided attributes. - """ - unknown_attributes = set(model_dict).difference(Model.converters_load) - if unknown_attributes: - warnings.warn( - "Ignoring unknown attributes: " - + ", ".join(unknown_attributes), - stacklevel=2, - ) - - if base_path is not None: - model_dict[PETAB_YAML] = base_path / model_dict[PETAB_YAML] - - model_dict = { - attribute: Model.converters_load[attribute](value) - for attribute, value in model_dict.items() - if attribute in Model.converters_load - } - model_dict[PETAB_PROBLEM] = petab_problem - return Model(**model_dict) - - @staticmethod - def from_yaml(model_yaml: TYPE_PATH) -> Model: - """Generate a model from a PEtab Select model YAML file. - - Args: - model_yaml: - The path to the PEtab Select model YAML file. - - Returns: - A model instance, initialized with the provided attributes. - """ - with open(str(model_yaml)) as f: - model_dict = yaml.safe_load(f) - # TODO check that the hash is reproducible - if isinstance(model_dict, list): - try: - model_dict = one(model_dict) - except ValueError: - if len(model_dict) <= 1: - raise - raise ValueError( - "The provided YAML file contains a list with greater than " - "one element. Use the `Models.from_yaml` or provide a " - "YAML file with only one model specified." + estimated_parameters = ( + self._model_subspace_petab_problem.unscale_parameters( + estimated_parameters ) - - return Model.from_dict(model_dict, base_path=Path(model_yaml).parent) - - def to_dict( - self, - resolve_paths: bool = True, - paths_relative_to: str | Path = None, - ) -> dict[str, Any]: - """Generate a dictionary from the attributes of a :class:`Model` instance. - - Args: - resolve_paths: - Whether to resolve relative paths into absolute paths. - paths_relative_to: - If not ``None``, paths will be converted to be relative to this path. - Takes priority over ``resolve_paths``. - - Returns: - A dictionary of attributes. The keys are attribute - names, the values are the corresponding attribute values for - the model. Required attributes are the required arguments of - the :meth:`Model.__init__` method. - """ - model_dict = {} - for attribute in self.saved_attributes: - model_dict[attribute] = self.converters_save[attribute]( - getattr(self, attribute) ) - # TODO test - if resolve_paths: - if model_dict[PETAB_YAML]: - model_dict[PETAB_YAML] = str( - Path(model_dict[PETAB_YAML]).resolve() - ) - if paths_relative_to is not None: - if model_dict[PETAB_YAML]: - model_dict[PETAB_YAML] = relpath( - Path(model_dict[PETAB_YAML]).resolve(), - Path(paths_relative_to).resolve(), - ) - return model_dict - - def to_yaml(self, petab_yaml: TYPE_PATH, *args, **kwargs) -> None: - """Generate a PEtab Select model YAML file from a :class:`Model` instance. - - Parameters: - petab_yaml: - The location where the PEtab Select model YAML file will be - saved. - args, kwargs: - Additional arguments are passed to ``self.to_dict``. - """ - # FIXME change `getattr(self, PETAB_YAML)` to be relative to - # destination? - # kind of fixed, as the path will be resolved in `to_dict`. - with open(petab_yaml, "w") as f: - yaml.dump(self.to_dict(*args, **kwargs), f) - # yaml.dump(self.to_dict(), str(petab_yaml)) + self.estimated_parameters = estimated_parameters def to_petab( self, - output_path: TYPE_PATH = None, + output_path: str | Path = None, set_estimated_parameters: bool | None = None, - ) -> dict[str, petab.Problem | TYPE_PATH]: - """Generate a PEtab problem. + ) -> dict[str, petab.Problem | str | Path]: + """Generate the PEtab problem for this model. Args: output_path: - The directory where PEtab files will be written to disk. If not - specified, the PEtab files will not be written to disk. + If specified, the PEtab tables will be written to disk, inside + this directory. set_estimated_parameters: - Whether to set the nominal value of estimated parameters to their - estimates. If parameter estimates are available, this - will default to `True`. + Whether to implement ``Model.estimated_parameters`` as the + nominal values of the PEtab problem parameter table. + Defaults to ``True`` if ``Model.estimated_parameters`` is set. Returns: - A 2-tuple. The first value is a PEtab problem that can be used - with a PEtab-compatible tool for calibration of this model. If - ``output_path`` is not ``None``, the second value is the path to a - PEtab YAML file that can be used to load the PEtab problem (the - first value) into any PEtab-compatible tool. + The PEtab problem. Also returns the path of the PEtab problem YAML + file, if ``output_path`` is specified. """ - # TODO could use `copy.deepcopy(self.petab_problem)` from PetabMixin? - petab_problem = petab.Problem.from_yaml(str(self.petab_yaml)) + petab_problem = petab.Problem.from_yaml( + self._model_subspace_petab_yaml + ) if set_estimated_parameters is None and self.estimated_parameters: set_estimated_parameters = True + if set_estimated_parameters and ( + missing_parameter_estimates := set(self.parameters).difference( + self.estimated_parameters + ) + ): + raise ValueError( + "Try again with `set_estimated_parameters=False`, because " + "some parameter estimates are missing. Missing estimates for: " + f"`{missing_parameter_estimates}`." + ) + for parameter_id, parameter_value in self.parameters.items(): # If the parameter is to be estimated. if parameter_value == ESTIMATE: petab_problem.parameter_df.loc[parameter_id, ESTIMATE] = 1 - if set_estimated_parameters: - if parameter_id not in self.estimated_parameters: - raise ValueError( - "Not all estimated parameters are available " - "in `model.estimated_parameters`. Hence, the " - "estimated parameter vector cannot be set as " - "the nominal value in the PEtab problem. " - "Try calling this method with " - "`set_estimated_parameters=False`." - ) petab_problem.parameter_df.loc[ parameter_id, NOMINAL_VALUE ] = self.estimated_parameters[parameter_id] @@ -494,7 +539,6 @@ def to_petab( petab_problem.parameter_df.loc[parameter_id, NOMINAL_VALUE] = ( parameter_string_to_value(parameter_value) ) - # parameter_value petab_yaml = None if output_path is not None: @@ -509,488 +553,40 @@ def to_petab( PETAB_YAML: petab_yaml, } - def get_hash(self) -> str: - """Get the model hash. - - See the documentation for :class:`ModelHash` for more information. - - This is not implemented as ``__hash__`` because Python automatically - truncates values in a system-dependent manner, which reduces - interoperability - ( https://docs.python.org/3/reference/datamodel.html#object.__hash__ ). - - Returns: - The hash. - """ - if self.model_hash is None: - self.model_hash = ModelHash.from_model(model=self) - return self.model_hash - - def __hash__(self) -> None: - """Use `Model.get_hash` instead.""" - raise NotImplementedError("Use `Model.get_hash() instead.`") - - def __str__(self): - """Get a print-ready string representation of the model. - - Returns: - The print-ready string representation, in TSV format. - """ + def __str__(self) -> str: + """Printable model summary.""" parameter_ids = "\t".join(self.parameters.keys()) parameter_values = "\t".join(str(v) for v in self.parameters.values()) - header = "\t".join([MODEL_ID, PETAB_YAML, parameter_ids]) - data = "\t".join( - [self.model_id, str(self.petab_yaml), parameter_values] + header = "\t".join( + [MODEL_ID, MODEL_SUBSPACE_PETAB_YAML, parameter_ids] ) - # header = f'{MODEL_ID}\t{PETAB_YAML}\t{parameter_ids}' - # data = f'{self.model_id}\t{self.petab_yaml}\t{parameter_values}' - return f"{header}\n{data}" - - def __repr__(self) -> str: - """The model hash.""" - return f'' - - def get_mle(self) -> dict[str, float]: - """Get the maximum likelihood estimate of the model.""" - """ - FIXME(dilpath) - # Check if original PEtab problem or PEtab Select model has estimated - # parameters. e.g. can use some of `self.to_petab` to get the parameter - # df and see if any are estimated. - if not self.has_estimated_parameters: - warn('The MLE for this model contains no estimated parameters.') - if not all([ - parameter_id in getattr(self, ESTIMATED_PARAMETERS) - for parameter_id in self.get_estimated_parameter_ids_all() - ]): - warn('Not all estimated parameters have estimates stored.') - petab_problem = petab.Problem.from_yaml(str(self.petab_yaml)) - return { - parameter_id: ( - getattr(self, ESTIMATED_PARAMETERS).get( - # Return estimated parameter from `petab_select.Model` - # if possible. - parameter_id, - # Else return nominal value from PEtab parameter table. - petab_problem.parameter_df.loc[ - parameter_id, NOMINAL_VALUE - ], - ) - ) - for parameter_id in petab_problem.parameter_df.index - } - # TODO rewrite to construct return dict in a for loop, for more - # informative error message as soon as a "should-be-estimated" - # parameter has not estimate available in `self.estimated_parameters`. - """ - # TODO - pass - - def get_estimated_parameter_ids_all(self) -> list[str]: - estimated_parameter_ids = [] - - # Add all estimated parameters in the PEtab problem. - petab_problem = petab.Problem.from_yaml(str(self.petab_yaml)) - for parameter_id in petab_problem.parameter_df.index: - if ( - petab_problem.parameter_df.loc[parameter_id, ESTIMATE] - == PETAB_ESTIMATE_TRUE - ): - estimated_parameter_ids.append(parameter_id) - - # Add additional estimated parameters, and collect fixed parameters, - # in this model's parameterization. - fixed_parameter_ids = [] - for parameter_id, value in self.parameters.items(): - if ( - value == ESTIMATE - and parameter_id not in estimated_parameter_ids - ): - estimated_parameter_ids.append(parameter_id) - elif value != ESTIMATE: - fixed_parameter_ids.append(parameter_id) - - # Remove fixed parameters. - estimated_parameter_ids = [ - parameter_id - for parameter_id in estimated_parameter_ids - if parameter_id not in fixed_parameter_ids - ] - - return estimated_parameter_ids - - def get_parameter_values( - self, - parameter_ids: list[str] | None = None, - ) -> list[TYPE_PARAMETER]: - """Get parameter values. - - Includes ``ESTIMATE`` for parameters that should be estimated. - - The ordering is by ``parameter_ids`` if supplied, else - ``self.petab_parameters``. - - Args: - parameter_ids: - The IDs of parameters that values will be returned for. Order - is maintained. - - Returns: - The values of parameters. - """ - if parameter_ids is None: - parameter_ids = list(self.petab_parameters) - return [ - self.parameters.get( - parameter_id, - # Default to PEtab problem. - self.petab_parameters[parameter_id], - ) - for parameter_id in parameter_ids - ] - - -def default_compare( - model0: Model, - model1: Model, - criterion: Criterion, - criterion_threshold: float = 0, -) -> bool: - """Compare two calibrated models by their criterion values. - - It is assumed that the model ``model0`` provides a value for the criterion - ``criterion``, or is the ``VIRTUAL_INITIAL_MODEL``. - - Args: - model0: - The original model. - model1: - The new model. - criterion: - The criterion. - criterion_threshold: - The value by which the new model must improve on the original - model. Should be non-negative, regardless of the criterion. - - Returns: - ``True` if ``model1`` has a better criterion value than ``model0``, else - ``False``. - """ - if not model1.has_criterion(criterion): - warnings.warn( - f'Model "{model1.model_id}" does not provide a value for the ' - f'criterion "{criterion}".', - stacklevel=2, - ) - return False - if model0 == VIRTUAL_INITIAL_MODEL or model0 is None: - return True - if criterion_threshold < 0: - warnings.warn( - "The provided criterion threshold is negative. " - "The absolute value will be used instead.", - stacklevel=2, - ) - criterion_threshold = abs(criterion_threshold) - if criterion in [ - Criterion.AIC, - Criterion.AICC, - Criterion.BIC, - Criterion.NLLH, - Criterion.SSR, - ]: - return ( - model1.get_criterion(criterion) - < model0.get_criterion(criterion) - criterion_threshold - ) - elif criterion in [ - Criterion.LH, - Criterion.LLH, - ]: - return ( - model1.get_criterion(criterion) - > model0.get_criterion(criterion) + criterion_threshold - ) - else: - raise NotImplementedError(f"Unknown criterion: {criterion}.") - - -class ModelHash(str): - """A class to handle model hash functionality. - - The model hash is designed to be human-readable and able to be converted - back into the corresponding model. Currently, if two models from two - different model subspaces are actually the same PEtab problem, they will - still have different model hashes. - - Attributes: - model_subspace_id: - The ID of the model subspace of the model. Unique up to a single - PEtab Select problem model space. - model_subspace_indices_hash: - A hash of the location of the model in its model - subspace. Unique up to a single model subspace. - """ - - # FIXME petab problem--specific hashes that are cross-platform? - """ - The model hash is designed to be: human-readable; able to be converted - back into the corresponding model, and unique up to the same PEtab - problem and parameters. - - Consider two different models in different model subspaces, with - `ModelHash`s `model_hash0` and `model_hash1`, respectively. Assume that - these two models end up encoding the same PEtab problem (e.g. they set the - same parameters to be estimated). - The string representation will be different, - `str(model_hash0) != str(model_hash1)`, but their hashes will pass the - equality check: `model_hash0 == model_hash1` and - `hash(model_hash0) == hash(model_hash1)`. - - This means that different models in different model subspaces that end up - being the same PEtab problem will have different human-readable hashes, - but if these models arise during model selection, then only one of them - will be calibrated. - - The PEtab hash size is computed automatically as the smallest size that - ensures a collision probability of less than $2^{-64}$. - N.B.: this assumes only one model subspace, and only 2 options for each - parameter (e.g. `0` and `estimate`). You can manually set the size with - :const:`petab_select.constants.PETAB_HASH_DIGEST_SIZE`. - - petab_hash: - A hash that is unique up to the same PEtab problem, which is - determined by: the PEtab problem YAML file location, nominal - parameter values, and parameters set to be estimated. This means - that different models may have the same `unique_petab_hash`, - because they are the same estimation problem. - """ - - def __init__( - self, - model_subspace_id: str, - model_subspace_indices_hash: str, - # petab_hash: str, - ): - self.model_subspace_id = model_subspace_id - self.model_subspace_indices_hash = model_subspace_indices_hash - # self.petab_hash = petab_hash - - def __new__( - cls, - model_subspace_id: str, - model_subspace_indices_hash: str, - # petab_hash: str, - ): - hash_str = MODEL_HASH_DELIMITER.join( + data = "\t".join( [ - model_subspace_id, - model_subspace_indices_hash, - # petab_hash, + self.model_id, + str(self.model_subspace_petab_yaml), + parameter_values, ] ) - instance = super().__new__(cls, hash_str) - return instance - - def __getnewargs_ex__(self): - return ( - (), - { - "model_subspace_id": self.model_subspace_id, - "model_subspace_indices_hash": self.model_subspace_indices_hash, - # 'petab_hash': self.petab_hash, - }, - ) - - def __copy__(self): - return ModelHash( - model_subspace_id=self.model_subspace_id, - model_subspace_indices_hash=self.model_subspace_indices_hash, - # petab_hash=self.petab_hash, - ) - - def __deepcopy__(self, memo): - return self.__copy__() - - # @staticmethod - # def get_petab_hash(model: Model) -> str: - # """Get a hash that is unique up to the same estimation problem. - - # See :attr:`petab_hash` for more information. - - # Args: - # model: - # The model. - - # Returns: - # The unique PEtab hash. - # """ - # digest_size = PETAB_HASH_DIGEST_SIZE - # if digest_size is None: - # petab_info_bits = len(model.model_subspace_indices) - # # Ensure <2^{-64} probability of collision - # petab_info_bits += 64 - # # Convert to bytes, round up. - # digest_size = int(petab_info_bits / 8) + 1 - - # petab_yaml = str(model.petab_yaml.resolve()) - # model_parameter_df = model.to_petab(set_estimated_parameters=False)[ - # PETAB_PROBLEM - # ].parameter_df - # nominal_parameter_hash = hash_parameter_dict( - # model_parameter_df[NOMINAL_VALUE].to_dict() - # ) - # estimate_parameter_hash = hash_parameter_dict( - # model_parameter_df[ESTIMATE].to_dict() - # ) - # return hash_str( - # petab_yaml + estimate_parameter_hash + nominal_parameter_hash, - # digest_size=digest_size, - # ) - - @staticmethod - def from_hash(model_hash: str | ModelHash) -> ModelHash: - """Reconstruct a :class:`ModelHash` object. - - Args: - model_hash: - The model hash. - - Returns: - The :class:`ModelHash` object. - """ - if isinstance(model_hash, ModelHash): - return model_hash - - if model_hash == VIRTUAL_INITIAL_MODEL: - return ModelHash( - model_subspace_id=VIRTUAL_INITIAL_MODEL, - model_subspace_indices_hash="", - # petab_hash=VIRTUAL_INITIAL_MODEL, - ) - - ( - model_subspace_id, - model_subspace_indices_hash, - # petab_hash, - ) = model_hash.split(MODEL_HASH_DELIMITER) - return ModelHash( - model_subspace_id=model_subspace_id, - model_subspace_indices_hash=model_subspace_indices_hash, - # petab_hash=petab_hash, - ) - - @staticmethod - def from_model(model: Model) -> ModelHash: - """Create a hash for a model. - - Args: - model: - The model. - - Returns: - The model hash. - """ - model_subspace_id = "" - model_subspace_indices_hash = "" - if model.model_subspace_id is not None: - model_subspace_id = model.model_subspace_id - model_subspace_indices_hash = ( - ModelHash.hash_model_subspace_indices( - model.model_subspace_indices - ) - ) - - return ModelHash( - model_subspace_id=model_subspace_id, - model_subspace_indices_hash=model_subspace_indices_hash, - # petab_hash=ModelHash.get_petab_hash(model=model), - ) - - @staticmethod - def hash_model_subspace_indices(model_subspace_indices: list[int]) -> str: - """Hash the location of a model in its subspace. - - Args: - model_subspace_indices: - The location (indices) of the model in its subspace. - - Returns: - The hash. - """ - try: - return "".join( - MODEL_SUBSPACE_INDICES_HASH_MAP[index] - for index in model_subspace_indices - ) - except KeyError: - return MODEL_SUBSPACE_INDICES_HASH_DELIMITER.join( - str(i) for i in model_subspace_indices - ) - - def unhash_model_subspace_indices(self) -> list[int]: - """Get the location of a model in its subspace. - - Returns: - The location, as indices of the subspace. - """ - if ( - MODEL_SUBSPACE_INDICES_HASH_DELIMITER - in self.model_subspace_indices_hash - ): - return [ - int(s) - for s in self.model_subspace_indices_hash.split( - MODEL_SUBSPACE_INDICES_HASH_DELIMITER - ) - ] - else: - return [ - MODEL_SUBSPACE_INDICES_HASH_MAP.index(s) - for s in self.model_subspace_indices_hash - ] - - def get_model(self, petab_select_problem: Problem) -> Model: - """Get the model that a hash corresponds to. - - Args: - petab_select_problem: - The PEtab Select problem. The model will be found in its model - space. - - Returns: - The model. - """ - # if self.petab_hash == VIRTUAL_INITIAL_MODEL: - # return self.petab_hash - - return petab_select_problem.model_space.model_subspaces[ - self.model_subspace_id - ].indices_to_model(self.unhash_model_subspace_indices()) + return f"{header}\n{data}" - def __hash__(self) -> str: - """The PEtab hash. + def __repr__(self) -> str: + """The model hash. - N.B.: this is not the model hash! As the equality between two models - is determined by their PEtab hash only, this method only returns the - PEtab hash. However, the model hash is the full string with the - human-readable elements as well. :func:`ModelHash.from_hash` does not - accept the PEtab hash as input, rather the full string. + The hash can be used to reconstruct the model (see + :meth:``ModelHash.get_model``). """ - return hash(str(self)) + return f'' - def __eq__(self, other_hash: str | ModelHash) -> bool: - """Check whether two model hashes are equivalent. - Returns: - Whether the two hashes correspond to equivalent PEtab problems. - """ - # petab_hash = other_hash - # # Check whether the PEtab hash needs to be extracted - # if MODEL_HASH_DELIMITER in other_hash: - # petab_hash = ModelHash.from_hash(other_hash).petab_hash - # return self.petab_hash == petab_hash - return str(self) == str(other_hash) +VIRTUAL_INITIAL_MODEL = Model.parse_obj( + { + MODEL_SUBSPACE_ID: "virtual_initial_model", + MODEL_SUBSPACE_INDICES: [0], + MODEL_SUBSPACE_PETAB_YAML: None, + PARAMETERS: {}, + CRITERIA: {Criterion.NLLH: float("inf")}, + } +) -VIRTUAL_INITIAL_MODEL_HASH = ModelHash.from_hash(VIRTUAL_INITIAL_MODEL) +ModelStandard = mkstd.YamlStandard(model=ModelBase) diff --git a/petab_select/model_subspace.py b/petab_select/model_subspace.py index 1f077996..276cfbff 100644 --- a/petab_select/model_subspace.py +++ b/petab_select/model_subspace.py @@ -748,7 +748,7 @@ def indices_to_model(self, indices: list[int]) -> Model | None: model_subspace_id=self.model_subspace_id, model_subspace_indices=indices, parameters=self.indices_to_parameters(indices), - petab_problem=self.petab_problem, + model_subspace_petab_problem=self.petab_problem, ) if self.excluded(model): return None diff --git a/pyproject.toml b/pyproject.toml index 77e1d38c..1f18088a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ dependencies = [ "pyyaml>=6.0.2", "click>=8.1.7", "dill>=0.3.9", + "mkstd>=0.0.5", ] [project.optional-dependencies] plot = [ From 2e6828c171a73881e633c1cd1b648d597bbba294 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Sun, 15 Dec 2024 17:24:22 +0100 Subject: [PATCH 27/88] add some old petab parameter helpers to `Model`; add default_compare --- petab_select/constants.py | 4 +- petab_select/model.py | 146 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 144 insertions(+), 6 deletions(-) diff --git a/petab_select/constants.py b/petab_select/constants.py index 482b02b7..df8ab8c4 100644 --- a/petab_select/constants.py +++ b/petab_select/constants.py @@ -58,6 +58,9 @@ class Criterion(str, Enum): ) PREDECESSOR_MODEL_HASH = "predecessor_model_hash" +# PEtab +PETAB_ESTIMATE_TRUE = 1 + # Problem MODEL_SPACE_FILES = "model_space_files" PROBLEM = "problem" @@ -144,7 +147,6 @@ class Method(str, Enum): PARAMETER_VALUE_DELIMITER = ";" CODE_DELIMITER = "-" PETAB_ESTIMATE_FALSE = 0 -PETAB_ESTIMATE_TRUE = 1 # TYPING_PATH = Union[str, Path] diff --git a/petab_select/model.py b/petab_select/model.py index 5736a8f6..e6bb0688 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -25,8 +25,10 @@ MODEL_SUBSPACE_INDICES_HASH_MAP, MODEL_SUBSPACE_PETAB_YAML, PARAMETERS, + PETAB_ESTIMATE_TRUE, PETAB_PROBLEM, PETAB_YAML, + TYPE_PARAMETER, Criterion, ) from .criteria import CriterionComputer @@ -56,10 +58,6 @@ from pydantic import Field, model_serializer, model_validator -def default_compare(): - pass - - class ModelHash(BaseModel): """The model hash. @@ -135,7 +133,7 @@ def kwargs_from_str(hash_str: str) -> dict[str, str]: zip( [MODEL_SUBSPACE_ID, MODEL_SUBSPACE_INDICES_HASH], hash_str.split(MODEL_HASH_DELIMITER), - strict=False, + strict=True, ) ) @@ -577,6 +575,144 @@ def __repr__(self) -> str: """ return f'' + def get_estimated_parameter_ids(self, full: bool = True) -> list[str]: + """Get estimated parameter IDs. + + Args: + full: + Whether to provide all IDs, including additional parameters + that are not part of the model selection problem but estimated. + """ + estimated_parameter_ids = [] + + # Add all estimated parameters in the PEtab problem. + if full: + petab_problem = petab.Problem.from_yaml(str(self.petab_yaml)) + for parameter_id in petab_problem.parameter_df.index: + if ( + petab_problem.parameter_df.loc[parameter_id, ESTIMATE] + == PETAB_ESTIMATE_TRUE + ): + estimated_parameter_ids.append(parameter_id) + + # Add additional estimated parameters, and collect fixed parameters, + # in this model's parameterization. + fixed_parameter_ids = [] + for parameter_id, value in self.parameters.items(): + if ( + value == ESTIMATE + and parameter_id not in estimated_parameter_ids + ): + estimated_parameter_ids.append(parameter_id) + elif value != ESTIMATE: + fixed_parameter_ids.append(parameter_id) + + # Remove fixed parameters. + estimated_parameter_ids = [ + parameter_id + for parameter_id in estimated_parameter_ids + if parameter_id not in fixed_parameter_ids + ] + return estimated_parameter_ids + + def get_parameter_values( + self, + parameter_ids: list[str] | None = None, + ) -> list[TYPE_PARAMETER]: + """Get parameter values. + + Includes ``ESTIMATE`` for parameters that should be estimated. + + Args: + parameter_ids: + The IDs of parameters that values will be returned for. Order + is maintained. Defaults to the model subspace PEtab problem + parameters. + + Returns: + The values of parameters. + """ + nominal_values = dict( + zip( + self._model_subspace_petab_problem.x_ids, + self._model_subspace_petab_problem.x_nominal, + strict=True, + ) + ) + for parameter_id in self._model_subspace_petab_problem.x_free_ids: + nominal_values[parameter_id] = ESTIMATE + if parameter_ids is None: + parameter_ids = nominal_values + return [ + self.parameters.get(parameter_id, nominal_values[parameter_id]) + for parameter_id in parameter_ids + ] + + +def default_compare( + model0: Model, + model1: Model, + criterion: Criterion, + criterion_threshold: float = 0, +) -> bool: + """Compare two calibrated models by their criterion values. + + It is assumed that the model ``model0`` provides a value for the criterion + ``criterion``, or is the ``VIRTUAL_INITIAL_MODEL``. + + Args: + model0: + The original model. + model1: + The new model. + criterion: + The criterion. + criterion_threshold: + The non-negative value by which the new model must improve on the + original model. + + Returns: + ``True` if ``model1`` has a better criterion value than ``model0``, + else ``False``. + """ + if not model1.has_criterion(criterion): + warnings.warn( + f'Model "{model1.model_id}" does not provide a value for the ' + f'criterion "{criterion}".', + stacklevel=2, + ) + return False + if model0 == VIRTUAL_INITIAL_MODEL or model0 is None: + return True + if criterion_threshold < 0: + warnings.warn( + "The provided criterion threshold is negative. " + "The absolute value will be used instead.", + stacklevel=2, + ) + criterion_threshold = abs(criterion_threshold) + if criterion in [ + Criterion.AIC, + Criterion.AICC, + Criterion.BIC, + Criterion.NLLH, + Criterion.SSR, + ]: + return ( + model1.get_criterion(criterion) + < model0.get_criterion(criterion) - criterion_threshold + ) + elif criterion in [ + Criterion.LH, + Criterion.LLH, + ]: + return ( + model1.get_criterion(criterion) + > model0.get_criterion(criterion) + criterion_threshold + ) + else: + raise NotImplementedError(f"Unknown criterion: {criterion}.") + VIRTUAL_INITIAL_MODEL = Model.parse_obj( { From f5d0589ef5562d06301b166772bddb05aecc2adc Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:24:37 +0100 Subject: [PATCH 28/88] remove constraint column (constraints aren't implemented yet) --- doc/test_suite.rst | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/doc/test_suite.rst b/doc/test_suite.rst index 9b9aa443..4684963a 100644 --- a/doc/test_suite.rst +++ b/doc/test_suite.rst @@ -15,7 +15,6 @@ the model format. - Method - Model space files - Compressed format - - Constraints files - Predecessor (initial) models files * - 0001 - (all) @@ -23,34 +22,29 @@ the model format. - 1 - - - - * - 0002 [#f1]_ - AIC - forward - 1 - - - - * - 0003 - BIC - - all + - brute force - 1 - Yes - - - * - 0004 - AICc - backward - 1 - - - 1 - * - 0005 - AIC - forward - 1 - - - - 1 * - 0006 - AIC @@ -58,27 +52,23 @@ the model format. - 1 - - - - * - 0007 [#f2]_ - AIC - forward - 1 - - - - * - 0008 [#f2]_ - AICc - backward - 1 - - - - * - 0009 [#f3]_ - AICc - FAMoS - 1 - Yes - - - Yes .. [#f1] Model ``M1_0`` differs from ``M1_1`` in three parameters, but only 1 additional estimated parameter. The effect of this on model selection criteria needs to be clarified. Test case 0006 is a duplicate of 0002 that doesn't have this issue. From 6cad912ce485315363c7f3d130f6e4569289fcd3 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:43:13 +0100 Subject: [PATCH 29/88] update test cases 1-8 expected models --- test/pypesto/generate_expected_models.py | 30 ++++++++++++++---------- test_cases/0001/expected.yaml | 19 ++++++++------- test_cases/0002/expected.yaml | 21 +++++++++-------- test_cases/0003/expected.yaml | 19 ++++++++------- test_cases/0004/expected.yaml | 21 +++++++++-------- test_cases/0005/expected.yaml | 21 +++++++++-------- test_cases/0006/expected.yaml | 19 ++++++++------- test_cases/0007/expected.yaml | 17 +++++++------- test_cases/0008/expected.yaml | 17 +++++++------- 9 files changed, 98 insertions(+), 86 deletions(-) diff --git a/test/pypesto/generate_expected_models.py b/test/pypesto/generate_expected_models.py index 7d68bd7d..0ca6e06c 100644 --- a/test/pypesto/generate_expected_models.py +++ b/test/pypesto/generate_expected_models.py @@ -13,8 +13,8 @@ # Set to `[]` to test all test_cases = [ - #'0004', - #'0008', + #'0001', + # "0003", ] # Do not use computationally-expensive test cases in CI @@ -41,6 +41,12 @@ def objective_customizer(obj): obj.amici_solver.setRelativeTolerance(1e-12) +model_problem_options = { + "minimize_options": minimize_options, + "objective_customizer": objective_customizer, +} + + # Indentation to match `test_pypesto.py`, to make it easier to keep files similar. if True: for test_case_path in test_cases_path.glob("*"): @@ -69,22 +75,20 @@ def objective_customizer(obj): ) # Run the selection process until "exhausted". - pypesto_select_problem.select_to_completion( - minimize_options=minimize_options, - objective_customizer=objective_customizer, - ) + pypesto_select_problem.select_to_completion(**model_problem_options) # Get the best model - best_model = petab_select_problem.get_best( - models=pypesto_select_problem.calibrated_models.values(), + best_model = petab_select.analyze.get_best( + models=pypesto_select_problem.calibrated_models, + criterion=petab_select_problem.criterion, ) # Generate the expected model. best_model.to_yaml( - expected_model_yaml, paths_relative_to=test_case_path + expected_model_yaml, + root_path=test_case_path, ) - petab_select.model.models_to_yaml_list( - models=pypesto_select_problem.calibrated_models.values(), - output_yaml="all_models.yaml", - ) + # pypesto_select_problem.calibrated_models.to_yaml( + # output_yaml="all_models.yaml", + # ) diff --git a/test_cases/0001/expected.yaml b/test_cases/0001/expected.yaml index 7149938b..a230aa28 100644 --- a/test_cases/0001/expected.yaml +++ b/test_cases/0001/expected.yaml @@ -1,18 +1,19 @@ -criteria: - AIC: -6.175405094206667 - NLLH: -4.0877025471033335 -estimated_parameters: - sigma_x2: 0.1224643186838838 -model_hash: M1_1-000 -model_id: M1_1-000 model_subspace_id: M1_1 model_subspace_indices: - 0 - 0 - 0 +criteria: + NLLH: -4.087702752023436 + AIC: -6.175405504046871 +model_hash: M1_1-000 +model_subspace_petab_yaml: petab/petab_problem.yaml +estimated_parameters: + sigma_x2: 0.12242920313036142 +iteration: 1 +model_id: M1_1-000 parameters: k1: 0.2 k2: 0.1 k3: 0 -petab_yaml: petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: virtual_initial_model- diff --git a/test_cases/0002/expected.yaml b/test_cases/0002/expected.yaml index c82acb72..510c60ce 100644 --- a/test_cases/0002/expected.yaml +++ b/test_cases/0002/expected.yaml @@ -1,19 +1,20 @@ -criteria: - AIC: -4.705325358569107 - NLLH: -4.3526626792845535 -estimated_parameters: - k1: 0.20160877227137408 - sigma_x2: 0.11715051179648493 -model_hash: M1_3-000 -model_id: M1_3-000 model_subspace_id: M1_3 model_subspace_indices: - 0 - 0 - 0 +criteria: + NLLH: -4.352662995581719 + AIC: -4.705325991163438 +model_hash: M1_3-000 +model_subspace_petab_yaml: ../0001/petab/petab_problem.yaml +estimated_parameters: + k1: 0.2016087813530968 + sigma_x2: 0.11714041764571122 +iteration: 2 +model_id: M1_3-000 parameters: k1: estimate k2: 0.1 k3: 0 -petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_0-000 diff --git a/test_cases/0003/expected.yaml b/test_cases/0003/expected.yaml index 48a87a33..218cba26 100644 --- a/test_cases/0003/expected.yaml +++ b/test_cases/0003/expected.yaml @@ -1,18 +1,19 @@ -criteria: - BIC: -6.383646149270872 - NLLH: -4.087702809249463 -estimated_parameters: - sigma_x2: 0.12245324237132274 -model_hash: M1-110 -model_id: M1-110 model_subspace_id: M1 model_subspace_indices: - 1 - 1 - 0 +criteria: + NLLH: -4.0877027520227704 + BIC: -6.383646034817486 +model_hash: M1-110 +model_subspace_petab_yaml: ../0001/petab/petab_problem.yaml +estimated_parameters: + sigma_x2: 0.12242924701706556 +iteration: 1 +model_id: M1-110 parameters: k1: 0.2 k2: 0.1 k3: 0 -petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: virtual_initial_model- diff --git a/test_cases/0004/expected.yaml b/test_cases/0004/expected.yaml index 811edc18..8f220f09 100644 --- a/test_cases/0004/expected.yaml +++ b/test_cases/0004/expected.yaml @@ -1,19 +1,20 @@ -criteria: - AICc: -0.7053253858878037 - NLLH: -4.352662692943902 -estimated_parameters: - k1: 0.20160877435934813 - sigma_x2: 0.11714883276066365 -model_hash: M1_3-000 -model_id: M1_3-000 model_subspace_id: M1_3 model_subspace_indices: - 0 - 0 - 0 +criteria: + NLLH: -4.352662995594862 + AICc: -0.7053259911897243 +model_hash: M1_3-000 +model_subspace_petab_yaml: ../0001/petab/petab_problem.yaml +estimated_parameters: + k1: 0.20160877986376358 + sigma_x2: 0.11714041204425464 +iteration: 3 +model_id: M1_3-000 parameters: k1: estimate k2: 0.1 k3: 0 -petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_6-000 diff --git a/test_cases/0005/expected.yaml b/test_cases/0005/expected.yaml index 897a2432..35949e30 100644 --- a/test_cases/0005/expected.yaml +++ b/test_cases/0005/expected.yaml @@ -1,19 +1,20 @@ -criteria: - AIC: -4.705325086169246 - NLLH: -4.352662543084623 -estimated_parameters: - k1: 0.20160877910494426 - sigma_x2: 0.11716072823171682 -model_hash: M1_3-000 -model_id: M1_3-000 model_subspace_id: M1_3 model_subspace_indices: - 0 - 0 - 0 +criteria: + NLLH: -4.352662995589992 + AIC: -4.7053259911799845 +model_hash: M1_3-000 +model_subspace_petab_yaml: ../0001/petab/petab_problem.yaml +estimated_parameters: + k1: 0.20160877971477925 + sigma_x2: 0.11714036509532029 +iteration: 2 +model_id: M1_3-000 parameters: k1: estimate k2: 0.1 k3: 0 -petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_0-000 diff --git a/test_cases/0006/expected.yaml b/test_cases/0006/expected.yaml index efd80860..4a05253a 100644 --- a/test_cases/0006/expected.yaml +++ b/test_cases/0006/expected.yaml @@ -1,18 +1,19 @@ -criteria: - AIC: -6.175403277446156 - NLLH: -4.087701638723078 -estimated_parameters: - sigma_x2: 0.12248840167611977 -model_hash: M1_0-000 -model_id: M1_0-000 model_subspace_id: M1_0 model_subspace_indices: - 0 - 0 - 0 +criteria: + NLLH: -4.087702752023439 + AIC: -6.1754055040468785 +model_hash: M1_0-000 +model_subspace_petab_yaml: ../0001/petab/petab_problem.yaml +estimated_parameters: + sigma_x2: 0.12242920634250658 +iteration: 1 +model_id: M1_0-000 parameters: k1: 0.2 k2: 0.1 k3: 0 -petab_yaml: ../0001/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: virtual_initial_model- diff --git a/test_cases/0007/expected.yaml b/test_cases/0007/expected.yaml index b843cd92..f8d17428 100644 --- a/test_cases/0007/expected.yaml +++ b/test_cases/0007/expected.yaml @@ -1,17 +1,18 @@ -criteria: - AIC: 11.117195852885663 - NLLH: 5.558597926442832 -estimated_parameters: {} -model_hash: M1_0-000 -model_id: M1_0-000 model_subspace_id: M1_0 model_subspace_indices: - 0 - 0 - 0 +criteria: + NLLH: 5.558597930767597 + AIC: 11.117195861535194 +model_hash: M1_0-000 +model_subspace_petab_yaml: petab/petab_problem.yaml +estimated_parameters: {} +iteration: 1 +model_id: M1_0-000 parameters: k1: 0.2 k2: 0.1 k3: 0 -petab_yaml: petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: virtual_initial_model- diff --git a/test_cases/0008/expected.yaml b/test_cases/0008/expected.yaml index 0fb56440..715ec176 100644 --- a/test_cases/0008/expected.yaml +++ b/test_cases/0008/expected.yaml @@ -1,17 +1,18 @@ -criteria: - AICc: 11.117195852885663 - NLLH: 5.558597926442832 -estimated_parameters: {} -model_hash: M1_0-000 -model_id: M1_0-000 model_subspace_id: M1_0 model_subspace_indices: - 0 - 0 - 0 +criteria: + NLLH: 5.558597930767597 + AICc: 11.117195861535194 +model_hash: M1_0-000 +model_subspace_petab_yaml: ../0007/petab/petab_problem.yaml +estimated_parameters: {} +iteration: 4 +model_id: M1_0-000 parameters: k1: 0.2 k2: 0.1 k3: 0 -petab_yaml: ../0007/petab/petab_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: M1_3-000 From c0e61cb6f7e4fbd1fc309f146109fa4422900b6f Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:49:04 +0100 Subject: [PATCH 30/88] split `ModelBase` into `VirtualModelBase` to make virtual object; cast criteria to float in setter; --- petab_select/model.py | 197 ++++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 94 deletions(-) diff --git a/petab_select/model.py b/petab_select/model.py index e6bb0688..b02d4902 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -13,7 +13,6 @@ from petab.v1.C import NOMINAL_VALUE from .constants import ( - CRITERIA, ESTIMATE, MODEL_HASH, MODEL_HASH_DELIMITER, @@ -24,8 +23,6 @@ MODEL_SUBSPACE_INDICES_HASH_DELIMITER, MODEL_SUBSPACE_INDICES_HASH_MAP, MODEL_SUBSPACE_PETAB_YAML, - PARAMETERS, - PETAB_ESTIMATE_TRUE, PETAB_PROBLEM, PETAB_YAML, TYPE_PARAMETER, @@ -35,6 +32,7 @@ from .misc import ( parameter_string_to_value, ) +from .petab import get_petab_parameters if TYPE_CHECKING: from .problem import Problem @@ -42,7 +40,6 @@ from pydantic import ( BaseModel, - FilePath, PrivateAttr, ValidationInfo, ValidatorFunctionWrapHandler, @@ -55,7 +52,13 @@ "VIRTUAL_INITIAL_MODEL", ] -from pydantic import Field, model_serializer, model_validator +from pydantic import ( + Field, + field_serializer, + field_validator, + model_serializer, + model_validator, +) class ModelHash(BaseModel): @@ -148,6 +151,8 @@ def hash_model_subspace_indices(model_subspace_indices: list[int]) -> str: Returns: The hash. """ + if not model_subspace_indices: + return "" if max(model_subspace_indices) < len(MODEL_SUBSPACE_INDICES_HASH_MAP): return "".join( MODEL_SUBSPACE_INDICES_HASH_MAP[index] @@ -211,103 +216,130 @@ def __repr__(self) -> str: return str(self) -class ModelBase(BaseModel): +class VirtualModelBase(BaseModel): + """Sufficient information for the virtual initial model.""" + + model_subspace_id: str + """The ID of the subspace that this model belongs to.""" + model_subspace_indices: list[int] + """The location of this model in its subspace.""" + criteria: dict[Criterion, float] = Field(default_factory=dict) + """The criterion values of the calibrated model (e.g. AIC).""" + model_hash: ModelHash = Field(default=None) + """The model hash (treat as read-only after initialization).""" + + @model_validator(mode="after") + def _check_hash(self: ModelBase) -> ModelBase: + kwargs = { + MODEL_SUBSPACE_ID: self.model_subspace_id, + MODEL_SUBSPACE_INDICES: self.model_subspace_indices, + } + if self.model_hash is not None: + kwargs[MODEL_HASH] = self.model_hash + self.model_hash = ModelHash.model_validate(kwargs) + + return self + + @field_validator("criteria", mode="after") + @classmethod + def _check_criteria( + cls, criteria: dict[str | Criterion, float] + ) -> dict[Criterion, float]: + criteria = { + ( + Criterion[criterion] + if isinstance(criterion, str) + else criterion + ): value + for criterion, value in criteria.items() + } + return criteria + + @field_serializer("criteria") + def _serialize_criteria( + self, criteria: dict[Criterion, float] + ) -> dict[str, float]: + criteria = { + criterion.value: value for criterion, value in criteria.items() + } + return criteria + + @property + def hash(self) -> ModelHash: + """Get the model hash.""" + return self.model_hash + + def __hash__(self) -> None: + """Use ``Model.hash`` instead.""" + raise NotImplementedError("Use `Model.hash` instead.") + + # def __eq__(self, other_model: Model | _VirtualInitialModel) -> bool: + # """Check whether two model hashes are equivalent.""" + # return self.hash == other.hash + + +class ModelBase(VirtualModelBase): """Definition of the standardized model. :class:`Model` is extended with additional helper methods -- use that instead of ``ModelBase``. """ - model_subspace_id: str - """The ID of the subspace that this model belongs to.""" - model_subspace_indices: list[int] - """The location of this model in its subspace.""" - model_subspace_petab_yaml: FilePath | None - """The base PEtab problem for the model subspace. + # TODO would use `FilePath` here (and remove `None` as an option), + # but then need to handle the + # `VIRTUAL_INITIAL_MODEL` dummy path differently. + model_subspace_petab_yaml: Path | None + """The location of the base PEtab problem for the model subspace. N.B.: Not the PEtab problem for this model specifically! Use :meth:`Model.to_petab` to get the model-specific PEtab problem. """ - criteria: dict[Criterion, float] | None = Field(default=None) - """The criterion values of the calibrated model (e.g. AIC).""" estimated_parameters: dict[str, float] | None = Field(default=None) """The parameter estimates of the calibrated model (always unscaled).""" iteration: int | None = Field(default=None) """The iteration of model selection that calibrated this model.""" model_id: str = Field(default=None) """The model ID.""" - model_hash: ModelHash = Field(default=None) - """The model hash (treat as read-only after initialization).""" parameters: dict[str, float | int | Literal[ESTIMATE]] """PEtab problem parameters overrides for this model. For example, fixes parameters to certain values, or sets them to be estimated. """ - predecessor_model_hash: ModelHash | None = Field(default=None) + predecessor_model_hash: ModelHash = Field(default=None) """The predecessor model hash.""" PATH_ATTRIBUTES: ClassVar[list[str]] = [ MODEL_SUBSPACE_PETAB_YAML, ] - @model_validator(mode="after") - def _check_hash(self: ModelBase) -> ModelBase: - kwargs = { - MODEL_SUBSPACE_ID: self.model_subspace_id, - MODEL_SUBSPACE_INDICES: self.model_subspace_indices, - } - if self.model_hash is not None: - kwargs[MODEL_HASH] = self.model_hash - self.model_hash = ModelHash.model_validate(kwargs) - - if self.predecessor_model_hash is not None: - self.predecessor_model_hash = ModelHash.model_validate( - self.predecessor_model_hash - ) - - return self - @model_validator(mode="after") def _check_id(self: ModelBase) -> ModelBase: if self.model_id is None: self.model_id = str(self.hash) return self - @property - def hash(self) -> ModelHash: - """Get the model hash.""" - return self.model_hash - - def __hash__(self) -> None: - """Use ``Model.hash`` instead.""" - raise NotImplementedError("Use ``Model.hash`` instead.") + @model_validator(mode="after") + def _check_predecessor_model_hash(self: ModelBase) -> ModelBase: + if self.predecessor_model_hash is None: + self.predecessor_model_hash = VIRTUAL_INITIAL_MODEL.hash + self.predecessor_model_hash = ModelHash.model_validate( + self.predecessor_model_hash + ) + return self @staticmethod def from_yaml( yaml_path: str | Path, - root_path: str | Path | bool = True, ) -> ModelBase: """Load a model from a YAML file. Args: yaml_path: The model YAML file location. - root_path: - All paths will be resolved relative to this. - If ``True``, this will be set to the directory of the - ``yaml_path``. - If ``False``, this will be set to the current working - directory. """ - if root_path is True: - root_path = Path(yaml_path).parent - if root_path is False: - root_path = Path() - model = ModelStandard.load_data(filename=yaml_path) - model.resolve_paths(root_path=root_path) return model def to_yaml( @@ -337,15 +369,6 @@ def to_yaml( model.set_relative_paths(root_path=root_path) ModelStandard.save_data(data=model, filename=yaml_path) - def resolve_paths(self, root_path: str | Path) -> None: - """Resolve all relative paths with respect to ``root_path``.""" - for path_attribute in self.PATH_ATTRIBUTES: - setattr( - self, - path_attribute, - (Path(root_path) / getattr(self, path_attribute)).resolve(), - ) - def set_relative_paths(self, root_path: str | Path) -> None: """Change all paths to be relative to ``root_path``.""" for path_attribute in self.PATH_ATTRIBUTES: @@ -401,7 +424,7 @@ def set_criterion(self, criterion: Criterion, value: float) -> None: f"Value: `{self.get_criterion(criterion)}`.", stacklevel=2, ) - self.criteria[criterion] = value + self.criteria[criterion] = float(value) def get_criterion( self, @@ -505,9 +528,7 @@ def to_petab( The PEtab problem. Also returns the path of the PEtab problem YAML file, if ``output_path`` is specified. """ - petab_problem = petab.Problem.from_yaml( - self._model_subspace_petab_yaml - ) + petab_problem = petab.Problem.from_yaml(self.model_subspace_petab_yaml) if set_estimated_parameters is None and self.estimated_parameters: set_estimated_parameters = True @@ -584,16 +605,10 @@ def get_estimated_parameter_ids(self, full: bool = True) -> list[str]: that are not part of the model selection problem but estimated. """ estimated_parameter_ids = [] - - # Add all estimated parameters in the PEtab problem. if full: - petab_problem = petab.Problem.from_yaml(str(self.petab_yaml)) - for parameter_id in petab_problem.parameter_df.index: - if ( - petab_problem.parameter_df.loc[parameter_id, ESTIMATE] - == PETAB_ESTIMATE_TRUE - ): - estimated_parameter_ids.append(parameter_id) + estimated_parameter_ids = ( + self._model_subspace_petab_problem.x_free_ids + ) # Add additional estimated parameters, and collect fixed parameters, # in this model's parameterization. @@ -627,22 +642,17 @@ def get_parameter_values( parameter_ids: The IDs of parameters that values will be returned for. Order is maintained. Defaults to the model subspace PEtab problem - parameters. + parameters (including those not part of the model selection + problem). Returns: The values of parameters. """ - nominal_values = dict( - zip( - self._model_subspace_petab_problem.x_ids, - self._model_subspace_petab_problem.x_nominal, - strict=True, - ) + nominal_values = get_petab_parameters( + self._model_subspace_petab_problem ) - for parameter_id in self._model_subspace_petab_problem.x_free_ids: - nominal_values[parameter_id] = ESTIMATE if parameter_ids is None: - parameter_ids = nominal_values + parameter_ids = list(nominal_values) return [ self.parameters.get(parameter_id, nominal_values[parameter_id]) for parameter_id in parameter_ids @@ -682,7 +692,7 @@ def default_compare( stacklevel=2, ) return False - if model0 == VIRTUAL_INITIAL_MODEL or model0 is None: + if model0.hash == VIRTUAL_INITIAL_MODEL_HASH or model0 is None: return True if criterion_threshold < 0: warnings.warn( @@ -714,15 +724,14 @@ def default_compare( raise NotImplementedError(f"Unknown criterion: {criterion}.") -VIRTUAL_INITIAL_MODEL = Model.parse_obj( +VIRTUAL_INITIAL_MODEL = VirtualModelBase.model_validate( { - MODEL_SUBSPACE_ID: "virtual_initial_model", - MODEL_SUBSPACE_INDICES: [0], - MODEL_SUBSPACE_PETAB_YAML: None, - PARAMETERS: {}, - CRITERIA: {Criterion.NLLH: float("inf")}, + "model_subspace_id": "virtual_initial_model", + "model_subspace_indices": [], } ) +# TODO deprecate, use `VIRTUAL_INITIAL_MODEL.hash` instead +VIRTUAL_INITIAL_MODEL_HASH = VIRTUAL_INITIAL_MODEL.hash ModelStandard = mkstd.YamlStandard(model=ModelBase) From 5efaf2f1059cd8729600f782230fee8553a5c830 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:50:25 +0100 Subject: [PATCH 31/88] update cli.py --- petab_select/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/petab_select/cli.py b/petab_select/cli.py index 37f83551..d0def393 100644 --- a/petab_select/cli.py +++ b/petab_select/cli.py @@ -177,7 +177,7 @@ def start_iteration( excluded_model_hashes += f.read().split("\n") excluded_hashes = [ - excluded_model.get_hash() for excluded_model in excluded_models + excluded_model.hash for excluded_model in excluded_models ] excluded_hashes += [ ModelHash.from_hash(hash_str) for hash_str in excluded_model_hashes From bc0b086b4656ecc85c4122b2f81408a3bdc0bddc Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:50:51 +0100 Subject: [PATCH 32/88] update plot.py --- petab_select/plot.py | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/petab_select/plot.py b/petab_select/plot.py index 859c6a33..e485ba07 100644 --- a/petab_select/plot.py +++ b/petab_select/plot.py @@ -56,7 +56,7 @@ def upset( index = np.argsort(values) values = values[index] labels = [ - model.get_estimated_parameter_ids_all() + model.get_estimated_parameter_ids() for model in np.array(models)[index] ] @@ -122,7 +122,7 @@ def line_best_by_iteration( [best_by_iteration[iteration] for iteration in iterations] ) iteration_labels = [ - str(iteration) + f"\n({labels.get(model.get_hash(), model.model_id)})" + str(iteration) + f"\n({labels.get(model.hash, model.model_id)})" for iteration, model in zip(iterations, best_models, strict=True) ] @@ -208,9 +208,9 @@ def graph_history( if labels is None: labels = { - model.get_hash(): model.model_id + model.hash: model.model_id + ( - f"\n{criterion_values[model.get_hash()]:.2f}" + f"\n{criterion_values[model.hash]:.2f}" if criterion is not None else "" ) @@ -230,7 +230,7 @@ def graph_history( if predecessor_model_hash in models: predecessor_model = models[predecessor_model_hash] from_ = labels.get( - predecessor_model.get_hash(), + predecessor_model.hash, predecessor_model.model_id, ) else: @@ -239,7 +239,7 @@ def graph_history( "not yet implemented." ) from_ = "None" - to = labels.get(model.get_hash(), model.model_id) + to = labels.get(model.hash, model.model_id) edges.append((from_, to)) G.add_edges_from(edges) @@ -312,13 +312,13 @@ def bar_criterion_vs_models( bar_kwargs = {} if labels is None: - labels = {model.get_hash(): model.model_id for model in models} + labels = {model.hash: model.model_id for model in models} if ax is None: _, ax = plt.subplots() bar_model_labels = [ - labels.get(model.get_hash(), model.model_id) for model in models + labels.get(model.hash, model.model_id) for model in models ] criterion_values = models.get_criterion( criterion=criterion, relative=relative @@ -385,7 +385,7 @@ def scatter_criterion_vs_n_estimated( The plot axes. """ labels = { - model.get_hash(): labels.get(model.model_id, model.model_id) + model.hash: labels.get(model.model_id, model.model_id) for model in models } @@ -405,7 +405,7 @@ def scatter_criterion_vs_n_estimated( n_estimated = [] for model in models: - n_estimated.append(len(model.get_estimated_parameter_ids_all())) + n_estimated.append(len(model.get_estimated_parameter_ids())) criterion_values = models.get_criterion( criterion=criterion, relative=relative @@ -495,36 +495,34 @@ def graph_iteration_layers( if draw_networkx_kwargs is None: draw_networkx_kwargs = default_draw_networkx_kwargs - ancestry = { - model.get_hash(): model.predecessor_model_hash for model in models - } + ancestry = {model.hash: model.predecessor_model_hash for model in models} ancestry_as_set = {k: {v} for k, v in ancestry.items()} ordering = [ - [model.get_hash() for model in iteration_models] + [model.hash for model in iteration_models] for iteration_models in group_by_iteration(models).values() ] if VIRTUAL_INITIAL_MODEL_HASH in ancestry.values(): ordering.insert(0, [VIRTUAL_INITIAL_MODEL_HASH]) model_estimated_parameters = { - model.get_hash(): set(model.estimated_parameters) for model in models + model.hash: set(model.estimated_parameters) for model in models } model_criterion_values = models.get_criterion( criterion=criterion, relative=relative, as_dict=True ) model_parameter_diffs = { - model.get_hash(): ( + model.hash: ( (set(), set()) if model.predecessor_model_hash not in model_estimated_parameters else ( - model_estimated_parameters[model.get_hash()].difference( + model_estimated_parameters[model.hash].difference( model_estimated_parameters[model.predecessor_model_hash] ), model_estimated_parameters[ model.predecessor_model_hash - ].difference(model_estimated_parameters[model.get_hash()]), + ].difference(model_estimated_parameters[model.hash]), ) ) for model in models @@ -534,9 +532,9 @@ def graph_iteration_layers( labels = ( labels | { - model.get_hash(): model.model_id + model.hash: model.model_id for model in models - if model.get_hash() not in labels + if model.hash not in labels } | { ModelHash.from_hash( @@ -670,8 +668,8 @@ def __getitem__(self, key): # selected_hashes = set(ancestry.values()) # selected_models = {} # for model in models: - # if model.get_hash() in selected_hashes: - # selected_models[model.get_hash()] = model + # if model.hash in selected_hashes: + # selected_models[model.hash] = model # selected_parameters = { # model_hash: sorted(model.estimated_parameters) From 7cf6a5aa624d8da9733126cd527e35882fa15f10 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:51:12 +0100 Subject: [PATCH 33/88] update models.py --- petab_select/models.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/petab_select/models.py b/petab_select/models.py index 03996adb..f2c9b4e7 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -23,6 +23,7 @@ from .model import ( Model, ModelHash, + VirtualModelBase, ) if TYPE_CHECKING: @@ -107,6 +108,8 @@ def __contains__(self, item: ModelLike) -> bool: return item in self._models case ModelHash() | str(): return item in self._hashes + case VirtualModelBase(): + return False case _: raise TypeError(f"Unexpected type: `{type(item)}`.") @@ -176,7 +179,7 @@ def __setitem__(self, key: ModelIndex, item: ModelLike) -> None: if key < len(self): self._models[key] = item - self._hashes[key] = item.get_hash() + self._hashes[key] = item.hash else: # Key doesn't exist, e.g., instead of # models[1] = model1 @@ -199,17 +202,17 @@ def _update(self, index: int, item: ModelLike) -> None: A model or a model hash. """ model = self._model_like_to_model(item) - if model.get_hash() in self: + if model.hash in self: warnings.warn( ( - f"A model with hash `{model.get_hash()}` already exists " + f"A model with hash `{model.hash}` already exists " "in this collection of models. The previous model will be " "overwritten." ), RuntimeWarning, stacklevel=2, ) - self[model.get_hash()] = model + self[model.hash] = model else: self._models.insert(index, None) self._hashes.insert(index, None) @@ -285,14 +288,14 @@ def insert(self, index: int, item: ModelLike): # def remove(self, item: ModelLike): # # Re-use __delitem__ logic # if isinstance(item, Model): - # item = item.get_hash() + # item = item.hash # del self[item] # skipped clear, copy, count def index(self, item: ModelLike, *args) -> int: if isinstance(item, Model): - item = item.get_hash() + item = item.hash return self._hashes.index(item, *args) # skipped reverse, sort From 0df740a44dd52d46fc8dace8d8d0e53778e0290f Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:51:41 +0100 Subject: [PATCH 34/88] update constants.py --- petab_select/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/petab_select/constants.py b/petab_select/constants.py index df8ab8c4..43ce0aa2 100644 --- a/petab_select/constants.py +++ b/petab_select/constants.py @@ -98,6 +98,7 @@ class Method(str, Enum): TYPE_PATH = str | Path # UI +MODELS = "models" UNCALIBRATED_MODELS = "uncalibrated_models" TERMINATE = "terminate" @@ -116,7 +117,7 @@ class Method(str, Enum): #: Virtual initial models can be used to initialize some initial model methods. # FIXME replace by real "dummy" model object -VIRTUAL_INITIAL_MODEL = "virtual_initial_model" +# VIRTUAL_INITIAL_MODEL = "virtual_initial_model" #: Methods that are compatible with a virtual initial model. VIRTUAL_INITIAL_MODEL_METHODS = [ Method.BACKWARD, @@ -134,7 +135,6 @@ class Method(str, Enum): # Unchecked MODEL = "model" -MODELS = "models" # Zero-indexed column/row indices MODEL_ID_COLUMN = 0 From 6ece3fa8aca502349e3a7ecb63e351110130f2bd Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:52:40 +0100 Subject: [PATCH 35/88] update ui.py --- petab_select/ui.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/petab_select/ui.py b/petab_select/ui.py index 720a319c..79083981 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -15,11 +15,10 @@ TERMINATE, TYPE_PATH, UNCALIBRATED_MODELS, - VIRTUAL_INITIAL_MODEL, Criterion, Method, ) -from .model import Model, ModelHash, default_compare +from .model import VIRTUAL_INITIAL_MODEL, Model, ModelHash, default_compare from .models import Models from .problem import Problem @@ -145,10 +144,7 @@ def start_iteration( predecessor_model = candidate_space.previous_predecessor_model # If the predecessor model has not yet been calibrated, then calibrate it. - if ( - predecessor_model is not None - and predecessor_model != VIRTUAL_INITIAL_MODEL - ): + if predecessor_model.hash != VIRTUAL_INITIAL_MODEL.hash: if ( predecessor_model.get_criterion( criterion, @@ -202,8 +198,7 @@ def start_iteration( ): return start_iteration_result(candidate_space=candidate_space) - if predecessor_model is not None: - candidate_space.reset(predecessor_model) + candidate_space.reset(predecessor_model) # FIXME store exclusions in candidate space only problem.model_space.exclude_model_hashes(model_hashes=excluded_hashes) @@ -388,7 +383,7 @@ def write_summary_tsv( previous_predecessor_parameter_ids = set() if isinstance(previous_predecessor_model, Model): previous_predecessor_parameter_ids = set( - previous_predecessor_model.get_estimated_parameter_ids_all() + previous_predecessor_model.get_estimated_parameter_ids() ) if predecessor_model is None: @@ -397,7 +392,7 @@ def write_summary_tsv( predecessor_criterion = None if isinstance(predecessor_model, Model): predecessor_parameter_ids = set( - predecessor_model.get_estimated_parameter_ids_all() + predecessor_model.get_estimated_parameter_ids() ) predecessor_criterion = predecessor_model.get_criterion( problem.criterion @@ -412,7 +407,7 @@ def write_summary_tsv( diff_candidates_parameter_ids = [] for candidate_model in candidate_space.models: candidate_parameter_ids = set( - candidate_model.get_estimated_parameter_ids_all() + candidate_model.get_estimated_parameter_ids() ) diff_candidates_parameter_ids.append( list( From 5b6ea5102ff6e13c2661e0e9739065a4e36c9285 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:53:40 +0100 Subject: [PATCH 36/88] refactor to remove `PetabMixin` --- petab_select/petab.py | 105 +++++++++--------------------------------- 1 file changed, 23 insertions(+), 82 deletions(-) diff --git a/petab_select/petab.py b/petab_select/petab.py index 8d370c8e..792e6ddf 100644 --- a/petab_select/petab.py +++ b/petab_select/petab.py @@ -1,91 +1,32 @@ -from pathlib import Path +"""Helper methods for working with PEtab problems.""" -import petab.v1 as petab -from more_itertools import one -from petab.v1.C import ESTIMATE, NOMINAL_VALUE +from typing import Literal -from .constants import PETAB_ESTIMATE_FALSE, TYPE_PARAMETER_DICT, TYPE_PATH +import numpy as np +import petab.v1 as petab +from petab.v1.C import ESTIMATE +__all__ = ["get_petab_parameters"] -class PetabMixin: - """Useful things for classes that contain a PEtab problem. - All attributes/methods are prefixed with `petab_`. +def get_petab_parameters( + petab_problem: petab.Problem, as_lists: bool = False +) -> dict[str, float | Literal[ESTIMATE] | list[float | Literal[ESTIMATE]]]: + """Convert PEtab problem parameters to the format in model space files. - Attributes: - petab_yaml: - The location of the PEtab problem YAML file. + Args: petab_problem: The PEtab problem. - petab_parameters: - The parameters from the PEtab parameters table, where keys are - parameter IDs, and values are either :obj:`ESTIMATE` if the - parameter is set to be estimated, else the nominal value. - """ - - def __init__( - self, - petab_yaml: TYPE_PATH | None = None, - petab_problem: petab.Problem | None = None, - parameters_as_lists: bool = False, - ): - if petab_yaml is None and petab_problem is None: - raise ValueError( - "Please supply at least one of either the location of the " - "PEtab problem YAML file, or an instance of the PEtab problem." - ) - self.petab_yaml = petab_yaml - if self.petab_yaml is not None: - self.petab_yaml = Path(self.petab_yaml) - - self.petab_problem = petab_problem - if self.petab_problem is None: - self.petab_problem = petab.Problem.from_yaml(str(petab_yaml)) - - self.petab_parameters = { - parameter_id: ( - row[NOMINAL_VALUE] - if row[ESTIMATE] == PETAB_ESTIMATE_FALSE - else ESTIMATE - ) - for parameter_id, row in self.petab_problem.parameter_df.iterrows() - } - if parameters_as_lists: - self.petab_parameters = { - k: [v] for k, v in self.petab_parameters.items() - } + as_lists: + Each value will be provided inside a list object, similar to the + format for multiple values for a parameter in a model subspace. - @property - def petab_parameter_ids_estimated(self) -> list[str]: - """Get the IDs of all estimated parameters. - - Returns: - The parameter IDs. - """ - return [ - parameter_id - for parameter_id, parameter_value in self.petab_parameters.items() - if parameter_value == ESTIMATE - ] - - @property - def petab_parameter_ids_fixed(self) -> list[str]: - """Get the IDs of all fixed parameters. - - Returns: - The parameter IDs. - """ - estimated = self.petab_parameter_ids_estimated - return [ - parameter_id - for parameter_id in self.petab_parameters - if parameter_id not in estimated - ] - - @property - def petab_parameters_singular(self) -> TYPE_PARAMETER_DICT: - """TODO deprecate and remove?""" - return { - parameter_id: one(parameter_value) - for parameter_id, parameter_value in self.petab_parameters - } + Returns: + Keys are parameter IDs, values are the nominal values for fixed + parameters, or :const:`ESTIMATE` for estimated parameters. + """ + values = np.array(petab_problem.x_nominal, dtype=object) + values[petab_problem.x_free_indices] = ESTIMATE + if as_lists: + values = [[v] for v in values] + return dict(zip(petab_problem.x_ids, values, strict=True)) From b03485d10b70392b8048272fcbac8b600b714158 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 00:57:41 +0100 Subject: [PATCH 37/88] update model_subspace.py; fix selector sets --- petab_select/model_subspace.py | 109 ++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 48 deletions(-) diff --git a/petab_select/model_subspace.py b/petab_select/model_subspace.py index 276cfbff..a9bdb733 100644 --- a/petab_select/model_subspace.py +++ b/petab_select/model_subspace.py @@ -7,6 +7,7 @@ import numpy as np import pandas as pd +import petab.v1 as petab from more_itertools import powerset from .candidate_space import CandidateSpace @@ -20,19 +21,18 @@ TYPE_PARAMETER_OPTIONS, TYPE_PARAMETER_OPTIONS_DICT, TYPE_PATH, - VIRTUAL_INITIAL_MODEL, Method, ) from .misc import parameter_string_to_value -from .model import Model -from .petab import PetabMixin +from .model import VIRTUAL_INITIAL_MODEL, Model +from .petab import get_petab_parameters __all__ = [ "ModelSubspace", ] -class ModelSubspace(PetabMixin): +class ModelSubspace: """Efficient representation of exponentially large model subspaces. Attributes: @@ -48,31 +48,23 @@ class ModelSubspace(PetabMixin): for consideration (:meth:`CandidateSpace.consider`). """ - """ - FIXME(dilpath) - #history: - # A history of all models that have been accepted by the candidate - # space. Models are represented as indices (see e.g. - # `ModelSubspace.parameters_to_indices`). - """ - def __init__( self, model_subspace_id: str, - petab_yaml: str, + petab_yaml: str | Path, parameters: TYPE_PARAMETER_OPTIONS_DICT, exclusions: list[Any] | None | None = None, ): self.model_subspace_id = model_subspace_id + self.petab_yaml = Path(petab_yaml) self.parameters = parameters - # TODO switch from mixin to attribute - super().__init__(petab_yaml=petab_yaml, parameters_as_lists=True) - self.exclusions = set() if exclusions is not None: self.exclusions = set(exclusions) + self.petab_problem = petab.Problem.from_yaml(self.petab_yaml) + def check_compatibility_stepwise_method( self, candidate_space: CandidateSpace, @@ -91,9 +83,15 @@ def check_compatibility_stepwise_method( """ if candidate_space.method not in STEPWISE_METHODS: return True - if candidate_space.predecessor_model != VIRTUAL_INITIAL_MODEL and ( - str(candidate_space.predecessor_model.petab_yaml.resolve()) - != str(self.petab_yaml.resolve()) + if ( + candidate_space.predecessor_model.hash + != VIRTUAL_INITIAL_MODEL.hash + and ( + str( + candidate_space.predecessor_model.model_subspace_petab_yaml.resolve() + ) + != str(self.petab_yaml.resolve()) + ) ): warnings.warn( "The supplied candidate space is initialized with a model " @@ -101,10 +99,9 @@ def check_compatibility_stepwise_method( "This is currently not supported for stepwise methods " "(e.g. forward or backward). " f"This model subspace: `{self.model_subspace_id}`. " - "This model subspace PEtab YAML: " - f"`{self.petab_yaml}`. " + f"This model subspace PEtab YAML: `{self.petab_yaml}`. " "The candidate space PEtab YAML: " - f"`{candidate_space.predecessor_model.petab_yaml}`.", + f"`{candidate_space.predecessor_model.model_subspace_petab_yaml}`.", stacklevel=2, ) return False @@ -238,29 +235,37 @@ def continue_searching( # Compute parameter sets that are useful for finding minimal forward or backward # moves in the subspace. # Parameters that are currently estimated in the predecessor model. - if candidate_space.predecessor_model == VIRTUAL_INITIAL_MODEL: + if ( + candidate_space.predecessor_model.hash + == VIRTUAL_INITIAL_MODEL.hash + ): if candidate_space.method == Method.FORWARD: - old_estimated_all = set() - old_fixed_all = set(self.parameters) + old_estimated_all = self.must_estimate_all + old_fixed_all = self.can_fix_all elif candidate_space.method == Method.BACKWARD: - old_estimated_all = set(self.parameters) - old_fixed_all = set() + old_estimated_all = self.can_estimate_all + old_fixed_all = self.must_fix_all + elif candidate_space.method == Method.BRUTE_FORCE: + # doesn't matter what these are set to + old_estimated_all = self.must_estimate_all + old_fixed_all = self.must_fix_all else: # Should already be handled elsewhere (e.g. # `self.check_compatibility_stepwise_method`). raise NotImplementedError( - f"The default parameter set for a candidate space with the virtual initial model and method {candidate_space.method} is not implemented. Please report if this is desired." + "The virtual initial model and method " + f"{candidate_space.method} is not implemented. " + "Please report if this is desired." ) else: - old_estimated_all = set() - old_fixed_all = set() - if isinstance(candidate_space.predecessor_model, Model): - old_estimated_all = candidate_space.predecessor_model.get_estimated_parameter_ids_all() - old_fixed_all = [ - parameter_id - for parameter_id in self.parameters_all - if parameter_id not in old_estimated_all - ] + old_estimated_all = ( + candidate_space.predecessor_model.get_estimated_parameter_ids() + ) + old_fixed_all = [ + parameter_id + for parameter_id in self.parameters_all + if parameter_id not in old_estimated_all + ] # Parameters that are fixed in the candidate space # predecessor model but are necessarily estimated in this subspace. @@ -307,7 +312,8 @@ def continue_searching( # there are no valid "forward" moves. if ( not new_can_estimate_all - and candidate_space.predecessor_model != VIRTUAL_INITIAL_MODEL + and candidate_space.predecessor_model.hash + != VIRTUAL_INITIAL_MODEL.hash ): return # There are estimated parameters in the predecessor model that @@ -318,7 +324,8 @@ def continue_searching( # parameters. if ( new_must_estimate_all - or candidate_space.predecessor_model == VIRTUAL_INITIAL_MODEL + or candidate_space.predecessor_model.hash + == VIRTUAL_INITIAL_MODEL.hash ): # Consider minimal models that have all necessarily-estimated # parameters. @@ -397,7 +404,8 @@ def continue_searching( # are no valid "backward" moves. if ( not new_can_fix_all - and candidate_space.predecessor_model != VIRTUAL_INITIAL_MODEL + and candidate_space.predecessor_model.hash + != VIRTUAL_INITIAL_MODEL.hash ): return # There are fixed parameters in the predecessor model that must be estimated @@ -408,7 +416,8 @@ def continue_searching( # parameters. if ( new_must_fix_all - or candidate_space.predecessor_model == VIRTUAL_INITIAL_MODEL + or candidate_space.predecessor_model.hash + == VIRTUAL_INITIAL_MODEL.hash ): # Consider minimal models that have all necessarily-fixed # parameters. @@ -508,7 +517,8 @@ def continue_searching( if ( # `and` is redundant with the "equal number" check above. (new_must_estimate_all and new_must_fix_all) - or candidate_space.predecessor_model == VIRTUAL_INITIAL_MODEL + or candidate_space.predecessor_model.hash + == VIRTUAL_INITIAL_MODEL.hash ): # Consider all models that have the required estimated and # fixed parameters. @@ -654,7 +664,7 @@ def exclude_model(self, model: Model) -> None: model: The model that will be excluded. """ - self.exclude_model_hash(model_hash=model.get_hash()) + self.exclude_model_hash(model_hash=model.hash) def exclude_models(self, models: Iterable[Model]) -> None: """Exclude models from the model subspace. @@ -674,7 +684,7 @@ def excluded( model: Model, ) -> bool: """Whether a model is excluded.""" - return model.get_hash() in self.exclusions + return model.hash in self.exclusions def reset_exclusions( self, @@ -744,11 +754,11 @@ def indices_to_model(self, indices: list[int]) -> Model | None: ``None``, if the model is excluded from the subspace. """ model = Model( - petab_yaml=self.petab_yaml, model_subspace_id=self.model_subspace_id, model_subspace_indices=indices, + model_subspace_petab_yaml=self.petab_yaml, parameters=self.indices_to_parameters(indices), - model_subspace_petab_problem=self.petab_problem, + _model_subspace_petab_problem=self.petab_problem, ) if self.excluded(model): return None @@ -828,7 +838,10 @@ def parameters_all(self) -> TYPE_PARAMETER_DICT: Parameter values in the PEtab problem are overwritten by the model subspace values. """ - return {**self.petab_parameters, **self.parameters} + return { + **get_petab_parameters(self.petab_problem, as_lists=True), + **self.parameters, + } @property def can_fix(self) -> list[str]: @@ -909,7 +922,7 @@ def must_estimate_all(self) -> list[str]: """All parameters that must be estimated in this subspace.""" must_estimate_petab = [ parameter_id - for parameter_id in self.petab_parameter_ids_estimated + for parameter_id in self.petab_problem.x_free_ids if parameter_id not in self.parameters ] return [*must_estimate_petab, *self.must_estimate] From bb965f84249bc7642a1cb061c484a7aea53cc9b5 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 01:01:28 +0100 Subject: [PATCH 38/88] predecessor_model now always set to virtual or real model; update candidate_space.py --- petab_select/candidate_space.py | 117 +++++++++++++++----------------- 1 file changed, 54 insertions(+), 63 deletions(-) diff --git a/petab_select/candidate_space.py b/petab_select/candidate_space.py index 03dd2f78..bbdf4843 100644 --- a/petab_select/candidate_space.py +++ b/petab_select/candidate_space.py @@ -20,14 +20,20 @@ PREDECESSOR_MODEL, PREVIOUS_METHODS, TYPE_PATH, - VIRTUAL_INITIAL_MODEL, VIRTUAL_INITIAL_MODEL_METHODS, Criterion, Method, ) from .handlers import TYPE_LIMIT, LimitHandler -from .model import Model, ModelHash, default_compare +from .model import ( + VIRTUAL_INITIAL_MODEL, + VIRTUAL_INITIAL_MODEL_HASH, + Model, + ModelHash, + default_compare, +) from .models import Models +from .petab import get_petab_parameters __all__ = [ "BackwardCandidateSpace", @@ -159,11 +165,7 @@ def set_iteration_user_calibrated_models( iteration_user_calibrated_models = Models() for model in self.models: if ( - ( - user_model := user_calibrated_models.get( - model.get_hash(), None - ) - ) + (user_model := user_calibrated_models.get(model.hash, None)) is not None ) and ( user_model.get_criterion( @@ -171,18 +173,14 @@ def set_iteration_user_calibrated_models( ) is not None ): - logging.info( - f"Using user-supplied result for: {model.get_hash()}" - ) + logging.info(f"Using user-supplied result for: {model.hash}") user_model_copy = copy.deepcopy(user_model) user_model_copy.predecessor_model_hash = ( - self.predecessor_model.get_hash() - if isinstance(self.predecessor_model, Model) - else self.predecessor_model + self.predecessor_model.hash + ) + iteration_user_calibrated_models[user_model_copy.hash] = ( + user_model_copy ) - iteration_user_calibrated_models[ - user_model_copy.get_hash() - ] = user_model_copy else: iteration_uncalibrated_models.append(model) self.iteration_user_calibrated_models = ( @@ -345,11 +343,7 @@ def accept( distance: The distance of the model from the predecessor model. """ - model.predecessor_model_hash = ( - self.predecessor_model.get_hash() - if isinstance(self.predecessor_model, Model) - else self.predecessor_model - ) + model.predecessor_model_hash = self.predecessor_model.hash self.models.append(model) self.distances.append(distance) self.set_excluded_hashes(model, extend=True) @@ -376,7 +370,7 @@ def excluded( ``True`` if the ``model`` is excluded, otherwise ``False``. """ if isinstance(model_hash, Model): - model_hash = model_hash.get_hash() + model_hash = model_hash.hash return model_hash in self.get_excluded_hashes() @abc.abstractmethod @@ -417,7 +411,7 @@ def consider(self, model: Model | None) -> bool: return False if self.excluded(model): warnings.warn( - f"Model `{model.get_hash()}` has been previously excluded " + f"Model `{model.hash}` has been previously excluded " "from the candidate space so is skipped here.", RuntimeWarning, stacklevel=2, @@ -435,19 +429,14 @@ def reset_accepted(self) -> None: self.models = Models() self.distances = [] - def set_predecessor_model(self, predecessor_model: Model | str | None): + def set_predecessor_model(self, predecessor_model: Model | None): """Set the predecessor model. See class attributes for arguments. """ + if predecessor_model is None: + predecessor_model = VIRTUAL_INITIAL_MODEL self.predecessor_model = predecessor_model - if ( - self.predecessor_model == VIRTUAL_INITIAL_MODEL - and self.method not in VIRTUAL_INITIAL_MODEL_METHODS - ): - raise ValueError( - f"A virtual initial model was requested for a method ({self.method}) that does not support them." - ) def get_predecessor_model(self) -> str | Model: """Get the predecessor model.""" @@ -472,7 +461,7 @@ def set_excluded_hashes( excluded_hashes = set() for potential_hash in hashes: if isinstance(potential_hash, Model): - potential_hash = potential_hash.get_hash() + potential_hash = potential_hash.hash excluded_hashes.add(potential_hash) if extend: @@ -531,7 +520,7 @@ def wrapper(): def reset( self, - predecessor_model: Model | str | None | None = None, + predecessor_model: Model | None = None, # FIXME change `Any` to some `TYPE_MODEL_HASH` (e.g. union of str/int/float) excluded_hashes: list[ModelHash] | None = None, limit: TYPE_LIMIT = None, @@ -592,18 +581,24 @@ def distances_in_estimated_parameters( model0 = self.predecessor_model model1 = model - if model0 != VIRTUAL_INITIAL_MODEL and not model1.petab_yaml.samefile( - model0.petab_yaml + if ( + model0.hash != VIRTUAL_INITIAL_MODEL_HASH + and not model1.model_subspace_petab_yaml.samefile( + model0.model_subspace_petab_yaml + ) ): + # FIXME raise NotImplementedError( - "Computation of distances between different PEtab problems is " - "currently not supported. This error is also raised if the same " - "PEtab problem is read from YAML files in different locations." + "Computing distances between models that have different " + "model subspace PEtab problems is currently not supported. " + "This check is based on the PEtab YAML file location." ) # All parameters from the PEtab problem are used in the computation. - if model0 == VIRTUAL_INITIAL_MODEL: - parameter_ids = list(model1.petab_parameters) + if model0.hash == VIRTUAL_INITIAL_MODEL_HASH: + parameter_ids = list( + get_petab_parameters(model1._model_subspace_petab_problem) + ) if self.method == Method.FORWARD: parameters0 = np.array([0 for _ in parameter_ids]) elif self.method == Method.BACKWARD: @@ -615,21 +610,12 @@ def distances_in_estimated_parameters( "developers." ) else: - parameter_ids = list(model0.petab_parameters) + parameter_ids = list( + get_petab_parameters(model0._model_subspace_petab_problem) + ) parameters0 = np.array( model0.get_parameter_values(parameter_ids=parameter_ids) ) - # FIXME need to take superset of all parameters amongst all PEtab problems - # in all model subspaces to get an accurate comparable distance. Currently - # only reasonable when working with a single PEtab problem for all models - # in all subspaces. - if model0.petab_yaml.resolve() != model1.petab_yaml.resolve(): - raise ValueError( - "Computing the distance between different models that " - 'have different "base" PEtab problems is not yet ' - f"supported. First base PEtab problem: {model0.petab_yaml}." - f" Second base PEtab problem: {model1.petab_yaml}." - ) parameters1 = np.array( model1.get_parameter_values(parameter_ids=parameter_ids) ) @@ -722,7 +708,7 @@ def is_plausible(self, model: Model) -> bool: # A model is plausible if the number of estimated parameters strictly # increases (or decreases, if `self.direction == -1`), and no # previously estimated parameters become fixed. - if self.predecessor_model == VIRTUAL_INITIAL_MODEL or ( + if self.predecessor_model.hash == VIRTUAL_INITIAL_MODEL_HASH or ( n_steps > 0 and distances["l1"] == n_steps ): return True @@ -914,10 +900,10 @@ def __init__( predecessor_model = VIRTUAL_INITIAL_MODEL if ( - predecessor_model == VIRTUAL_INITIAL_MODEL + predecessor_model.hash == VIRTUAL_INITIAL_MODEL_HASH and critical_parameter_sets ) or ( - predecessor_model != VIRTUAL_INITIAL_MODEL + predecessor_model.hash != VIRTUAL_INITIAL_MODEL_HASH and not self.check_critical(predecessor_model) ): raise ValueError( @@ -925,7 +911,7 @@ def __init__( ) if ( - predecessor_model == VIRTUAL_INITIAL_MODEL + predecessor_model.hash == VIRTUAL_INITIAL_MODEL_HASH and self.initial_method not in VIRTUAL_INITIAL_MODEL_METHODS ): raise ValueError( @@ -978,7 +964,7 @@ def __init__( *args, predecessor_model=( predecessor_model - if predecessor_model != VIRTUAL_INITIAL_MODEL + if predecessor_model.hash != VIRTUAL_INITIAL_MODEL_HASH else None ), max_steps=1, @@ -1097,7 +1083,8 @@ def update_from_iteration_calibrated_models( go_into_switch_method = True for model in iteration_calibrated_models: if ( - self.best_model_of_current_run == VIRTUAL_INITIAL_MODEL + self.best_model_of_current_run.hash + == VIRTUAL_INITIAL_MODEL_HASH or default_compare( model0=self.best_model_of_current_run, model1=model, @@ -1183,9 +1170,9 @@ def check_swap(self, model: Model) -> bool: return True predecessor_estimated_parameters_ids = set( - self.predecessor_model.get_estimated_parameter_ids_all() + self.predecessor_model.get_estimated_parameter_ids() ) - estimated_parameters_ids = set(model.get_estimated_parameter_ids_all()) + estimated_parameters_ids = set(model.get_estimated_parameter_ids()) swapped_parameters_ids = estimated_parameters_ids.symmetric_difference( predecessor_estimated_parameters_ids @@ -1198,7 +1185,7 @@ def check_swap(self, model: Model) -> bool: def check_critical(self, model: Model) -> bool: """Check if the model contains all necessary critical parameters""" - estimated_parameters_ids = set(model.get_estimated_parameter_ids_all()) + estimated_parameters_ids = set(model.get_estimated_parameter_ids()) for critical_set in self.critical_parameter_sets: if not estimated_parameters_ids.intersection(set(critical_set)): return False @@ -1341,7 +1328,11 @@ def get_most_distant( most_distant_indices = [] # FIXME for multiple PEtab problems? - parameter_ids = self.best_models[0].petab_parameters + parameter_ids = list( + get_petab_parameters( + self.best_models[0]._model_subspace_petab_problem + ) + ) for model in self.best_models: model_estimated_parameters = np.array( @@ -1392,7 +1383,7 @@ def get_most_distant( ) most_distant_model = Model( - petab_yaml=model.petab_yaml, + model_subspace_petab_yaml=model.model_subspace_petab_yaml, model_subspace_id=model.model_subspace_id, model_subspace_indices=most_distant_indices, parameters=most_distant_parameters, From 951f16918aaa3f96b402b01fe5f0c6f161b5e1a4 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 01:17:13 +0100 Subject: [PATCH 39/88] model subspace: require explicit parameter definitions; implement `can_fix_all` --- petab_select/model_subspace.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/petab_select/model_subspace.py b/petab_select/model_subspace.py index a9bdb733..5e097c5a 100644 --- a/petab_select/model_subspace.py +++ b/petab_select/model_subspace.py @@ -42,7 +42,7 @@ class ModelSubspace: The location of the PEtab problem YAML file. parameters: The key is the ID of the parameter. The value is a list of values - that the parameter can take (including `ESTIMATE`). + that the parameter can take (including ``ESTIMATE``). exclusions: Hashes of models that have been previously submitted to a candidate space for consideration (:meth:`CandidateSpace.consider`). @@ -65,6 +65,15 @@ def __init__( self.petab_problem = petab.Problem.from_yaml(self.petab_yaml) + for parameter_id, parameter_value in self.parameters.items(): + if not parameter_value: + raise ValueError( + f"The parameter `{parameter_id}` is in the definition " + "of this model subspace. However, its value is empty. " + f"Please specify either its fixed value or `'{ESTIMATE}'` " + "(e.g. in the model space table)." + ) + def check_compatibility_stepwise_method( self, candidate_space: CandidateSpace, @@ -853,10 +862,15 @@ def can_fix(self) -> list[str]: return [ parameter_id for parameter_id, parameter_values in self.parameters.items() - # If the possible parameter values are not only `ESTIMATE`, then - # it is assumed there is a fixed possible parameter value. - # TODO explicitly check for a lack of `ValueError` when cast to - # float? + if parameter_values != [ESTIMATE] + ] + + @property + def can_fix_all(self) -> list[str]: + """All arameters that can be fixed, according to the subspace.""" + return [ + parameter_id + for parameter_id, parameter_values in self.parameters_all.items() if parameter_values != [ESTIMATE] ] From 8eef832a6fd49b52e6a5a77f2a8bcd38f13314bd Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:07:55 +0100 Subject: [PATCH 40/88] update famos candidate space --- petab_select/candidate_space.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/petab_select/candidate_space.py b/petab_select/candidate_space.py index bbdf4843..a9a3be39 100644 --- a/petab_select/candidate_space.py +++ b/petab_select/candidate_space.py @@ -708,7 +708,7 @@ def is_plausible(self, model: Model) -> bool: # A model is plausible if the number of estimated parameters strictly # increases (or decreases, if `self.direction == -1`), and no # previously estimated parameters become fixed. - if self.predecessor_model.hash == VIRTUAL_INITIAL_MODEL_HASH or ( + if self.predecessor_model.hash == VIRTUAL_INITIAL_MODEL.hash or ( n_steps > 0 and distances["l1"] == n_steps ): return True @@ -868,7 +868,7 @@ class FamosCandidateSpace(CandidateSpace): def __init__( self, *args, - predecessor_model: Model | str | None | None = None, + predecessor_model: Model | None = None, critical_parameter_sets: list = [], swap_parameter_sets: list = [], method_scheme: dict[tuple, str] = None, @@ -900,10 +900,10 @@ def __init__( predecessor_model = VIRTUAL_INITIAL_MODEL if ( - predecessor_model.hash == VIRTUAL_INITIAL_MODEL_HASH + predecessor_model.hash == VIRTUAL_INITIAL_MODEL.hash and critical_parameter_sets ) or ( - predecessor_model.hash != VIRTUAL_INITIAL_MODEL_HASH + predecessor_model.hash != VIRTUAL_INITIAL_MODEL.hash and not self.check_critical(predecessor_model) ): raise ValueError( @@ -911,7 +911,7 @@ def __init__( ) if ( - predecessor_model.hash == VIRTUAL_INITIAL_MODEL_HASH + predecessor_model.hash == VIRTUAL_INITIAL_MODEL.hash and self.initial_method not in VIRTUAL_INITIAL_MODEL_METHODS ): raise ValueError( @@ -962,11 +962,7 @@ def __init__( ), Method.LATERAL: LateralCandidateSpace( *args, - predecessor_model=( - predecessor_model - if predecessor_model.hash != VIRTUAL_INITIAL_MODEL_HASH - else None - ), + predecessor_model=predecessor_model, max_steps=1, **kwargs, ), @@ -1290,6 +1286,9 @@ def jump_to_most_distant( # critical parameter from each critical parameter set if not self.check_critical(predecessor_model): for critical_set in self.critical_parameter_sets: + # FIXME is this a good idea? probably better to request + # the model from the model subspace, rather than editing + # the parameters... predecessor_model.parameters[critical_set[0]] = ESTIMATE # self.update_method(self.initial_method) @@ -1404,7 +1403,6 @@ class LateralCandidateSpace(CandidateSpace): def __init__( self, *args, - predecessor_model: Model | None, max_steps: int = None, **kwargs, ): @@ -1416,7 +1414,6 @@ def __init__( super().__init__( *args, method=Method.LATERAL, - predecessor_model=predecessor_model, **kwargs, ) self.max_steps = max_steps From 3106f16a48fcd4d45ea290ffa336412dd904ebda Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:09:33 +0100 Subject: [PATCH 41/88] fix standard type; support resolving relative paths in constructor --- petab_select/model.py | 98 ++++++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 33 deletions(-) diff --git a/petab_select/model.py b/petab_select/model.py index b02d4902..bf5d52ec 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -82,7 +82,7 @@ class ModelHash(BaseModel): model_subspace_indices_hash: str @model_validator(mode="wrap") - def check_kwargs( + def _check_kwargs( kwargs: dict[str, str | list[int]] | ModelHash, handler: ValidatorFunctionWrapHandler, info: ValidationInfo, @@ -230,6 +230,7 @@ class VirtualModelBase(BaseModel): @model_validator(mode="after") def _check_hash(self: ModelBase) -> ModelBase: + """Validate the model hash.""" kwargs = { MODEL_SUBSPACE_ID: self.model_subspace_id, MODEL_SUBSPACE_INDICES: self.model_subspace_indices, @@ -242,9 +243,10 @@ def _check_hash(self: ModelBase) -> ModelBase: @field_validator("criteria", mode="after") @classmethod - def _check_criteria( + def _fix_criteria_typing( cls, criteria: dict[str | Criterion, float] ) -> dict[Criterion, float]: + """Fix criteria typing.""" criteria = { ( Criterion[criterion] @@ -259,6 +261,7 @@ def _check_criteria( def _serialize_criteria( self, criteria: dict[Criterion, float] ) -> dict[str, float]: + """Serialize criteria.""" criteria = { criterion.value: value for criterion, value in criteria.items() } @@ -314,14 +317,38 @@ class ModelBase(VirtualModelBase): MODEL_SUBSPACE_PETAB_YAML, ] + @model_validator(mode="wrap") + def _fix_relative_paths( + data: dict[str, Any] | ModelBase, + handler: ValidatorFunctionWrapHandler, + info: ValidationInfo, + ) -> ModelBase: + if isinstance(data, ModelBase): + return data + model = handler(data) + + root_path = None + if "root_path" in data: + root_path = data.pop("root_path") + if root_path is None: + return model + + model.resolve_paths(root_path=root_path) + return model + @model_validator(mode="after") - def _check_id(self: ModelBase) -> ModelBase: + def _fix_id(self: ModelBase) -> ModelBase: + """Fix a missing ID by setting it to the hash.""" if self.model_id is None: self.model_id = str(self.hash) return self @model_validator(mode="after") - def _check_predecessor_model_hash(self: ModelBase) -> ModelBase: + def _fix_predecessor_model_hash(self: ModelBase) -> ModelBase: + """Fix missing predecessor model hashes. + + Sets them to ``VIRTUAL_INITIAL_MODEL.hash``. + """ if self.predecessor_model_hash is None: self.predecessor_model_hash = VIRTUAL_INITIAL_MODEL.hash self.predecessor_model_hash = ModelHash.model_validate( @@ -329,41 +356,19 @@ def _check_predecessor_model_hash(self: ModelBase) -> ModelBase: ) return self - @staticmethod - def from_yaml( - yaml_path: str | Path, - ) -> ModelBase: - """Load a model from a YAML file. - - Args: - yaml_path: - The model YAML file location. - """ - model = ModelStandard.load_data(filename=yaml_path) - return model - def to_yaml( self, yaml_path: str | Path, - root_path: str | Path | bool = True, ) -> None: """Save a model to a YAML file. + All paths will be made relative to the ``yaml_path`` directory. + Args: yaml_path: The model YAML file location. - root_path: - All paths will be converted to paths that are - relative to this directory path. - If ``True``, this will be set to the directory of the - ``yaml_path``. - If ``False``, this will be set to the current working - directory. """ - if root_path is True: - root_path = Path(yaml_path).parent - if root_path is False: - root_path = Path() + root_path = Path(yaml_path).parent model = copy.deepcopy(self) model.set_relative_paths(root_path=root_path) @@ -371,16 +376,27 @@ def to_yaml( def set_relative_paths(self, root_path: str | Path) -> None: """Change all paths to be relative to ``root_path``.""" + root_path = Path(root_path).resolve() for path_attribute in self.PATH_ATTRIBUTES: setattr( self, path_attribute, relpath( - Path(self.model_subspace_petab_yaml).resolve(), - start=Path(root_path).resolve(), + getattr(self, path_attribute).resolve(), + start=root_path, ), ) + def resolve_paths(self, root_path: str | Path) -> None: + """Resolve all paths to be relative to ``root_path``.""" + root_path = Path(root_path).resolve() + for path_attribute in self.PATH_ATTRIBUTES: + setattr( + self, + path_attribute, + (root_path / getattr(self, path_attribute)).resolve(), + ) + class Model(ModelBase): """A model. @@ -398,7 +414,8 @@ class Model(ModelBase): _model_subspace_petab_problem: petab.Problem = PrivateAttr(default=None) @model_validator(mode="after") - def _check_petab_problem(self: Model) -> Model: + def _fix_petab_problem(self: Model) -> Model: + """Fix a missing PEtab problem by loading it from disk.""" if ( self._model_subspace_petab_problem is None and self.model_subspace_petab_yaml is not None @@ -658,6 +675,21 @@ def get_parameter_values( for parameter_id in parameter_ids ] + @staticmethod + def from_yaml( + yaml_path: str | Path, + ) -> Model: + """Load a model from a YAML file. + + Args: + yaml_path: + The model YAML file location. + """ + model = ModelStandard.load_data( + filename=yaml_path, root_path=yaml_path.parent + ) + return model + def default_compare( model0: Model, @@ -734,4 +766,4 @@ def default_compare( VIRTUAL_INITIAL_MODEL_HASH = VIRTUAL_INITIAL_MODEL.hash -ModelStandard = mkstd.YamlStandard(model=ModelBase) +ModelStandard = mkstd.YamlStandard(model=Model) From d69c0ba72417680b32c088968154c09c3d7a3741 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:09:55 +0100 Subject: [PATCH 42/88] fix 0009 expected yaml --- test_cases/0009/predecessor_model.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_cases/0009/predecessor_model.yaml b/test_cases/0009/predecessor_model.yaml index 4471224b..581fa453 100644 --- a/test_cases/0009/predecessor_model.yaml +++ b/test_cases/0009/predecessor_model.yaml @@ -70,5 +70,5 @@ parameters: a_k16_k05k16: 1 a_k16_k08k16: 1 a_k16_k12k16: estimate -petab_yaml: petab/petab_problem.yaml -predecessor_model_hash: null +model_subspace_petab_yaml: petab/petab_problem.yaml +predecessor_model_hash: virtual_initial_model- From 469a602df5bfb198122316d935b92ab5a88b63ab Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:28:33 +0100 Subject: [PATCH 43/88] test case 0009: update expected.yaml --- test/pypesto/generate_expected_models.py | 8 ++-- test_cases/0009/expected.yaml | 59 ++++++++++++------------ 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/test/pypesto/generate_expected_models.py b/test/pypesto/generate_expected_models.py index 0ca6e06c..a92a7972 100644 --- a/test/pypesto/generate_expected_models.py +++ b/test/pypesto/generate_expected_models.py @@ -15,11 +15,12 @@ test_cases = [ #'0001', # "0003", + "0009", ] # Do not use computationally-expensive test cases in CI skip_test_cases = [ - "0009", + # "0009", ] test_cases_path = Path(__file__).resolve().parent.parent.parent / "test_cases" @@ -84,10 +85,7 @@ def objective_customizer(obj): ) # Generate the expected model. - best_model.to_yaml( - expected_model_yaml, - root_path=test_case_path, - ) + best_model.to_yaml(expected_model_yaml) # pypesto_select_problem.calibrated_models.to_yaml( # output_yaml="all_models.yaml", diff --git a/test_cases/0009/expected.yaml b/test_cases/0009/expected.yaml index 1c0260c3..58bb09fa 100644 --- a/test_cases/0009/expected.yaml +++ b/test_cases/0009/expected.yaml @@ -1,17 +1,3 @@ -criteria: - AICc: -1708.110992459583 - NLLH: -862.3517925260878 -estimated_parameters: - a_0ac_k08: 0.4085198712518596 - a_b: 0.06675755142350405 - a_k05_k05k12: 30.888893099662752 - a_k05k12_k05k08k12: 4.872831719884531 - a_k08k12k16_4ac: 53.80209580336034 - a_k12_k05k12: 8.26789880667234 - a_k12k16_k08k12k16: 33.038691003614964 - a_k16_k12k16: 10.424836834041892 -model_hash: M-01000100001000010010000000010001 -model_id: M-01000100001000010010000000010001 model_subspace_id: M model_subspace_indices: - 0 @@ -46,6 +32,22 @@ model_subspace_indices: - 0 - 0 - 1 +criteria: + NLLH: -862.3517925313981 + AICc: -1708.1109924702037 +model_hash: M-01000100001000010010000000010001 +model_subspace_petab_yaml: petab/petab_problem.yaml +estimated_parameters: + a_0ac_k08: 0.40850355273291267 + a_k05_k05k12: 30.888150959586138 + a_k12_k05k12: 8.267845459216893 + a_k16_k12k16: 10.424629099941777 + a_k05k12_k05k08k12: 4.872747603868694 + a_k12k16_k08k12k16: 33.03769174387633 + a_k08k12k16_4ac: 53.80106471593421 + a_b: 0.06675819571287103 +iteration: 11 +model_id: M-01000100001000010010000000010001 parameters: a_0ac_k05: 1 a_0ac_k08: estimate @@ -54,30 +56,29 @@ parameters: a_k05_k05k08: 1 a_k05_k05k12: estimate a_k05_k05k16: 1 + a_k08_k05k08: 1 + a_k08_k08k12: 1 + a_k08_k08k16: 1 + a_k12_k05k12: estimate + a_k12_k08k12: 1 + a_k12_k12k16: 1 + a_k16_k05k16: 1 + a_k16_k08k16: 1 + a_k16_k12k16: estimate a_k05k08_k05k08k12: 1 a_k05k08_k05k08k16: 1 - a_k05k08k12_4ac: 1 - a_k05k08k16_4ac: 1 a_k05k12_k05k08k12: estimate a_k05k12_k05k12k16: 1 - a_k05k12k16_4ac: 1 a_k05k16_k05k08k16: 1 a_k05k16_k05k12k16: 1 - a_k08_k05k08: 1 - a_k08_k08k12: 1 - a_k08_k08k16: 1 a_k08k12_k05k08k12: 1 a_k08k12_k08k12k16: 1 - a_k08k12k16_4ac: estimate a_k08k16_k05k08k16: 1 a_k08k16_k08k12k16: 1 - a_k12_k05k12: estimate - a_k12_k08k12: 1 - a_k12_k12k16: 1 a_k12k16_k05k12k16: 1 a_k12k16_k08k12k16: estimate - a_k16_k05k16: 1 - a_k16_k08k16: 1 - a_k16_k12k16: estimate -petab_yaml: petab/petab_problem.yaml -predecessor_model_hash: null + a_k05k08k12_4ac: 1 + a_k05k08k16_4ac: 1 + a_k05k12k16_4ac: 1 + a_k08k12k16_4ac: estimate +predecessor_model_hash: M-01000100001010010010000000010001 From e774b1cde6ac3b5312b576a082ad011cf9c8bee7 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:11:31 +0100 Subject: [PATCH 44/88] check subclass first --- petab_select/model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/petab_select/model.py b/petab_select/model.py index bf5d52ec..07ec7416 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -249,9 +249,9 @@ def _fix_criteria_typing( """Fix criteria typing.""" criteria = { ( - Criterion[criterion] - if isinstance(criterion, str) - else criterion + criterion + if isinstance(criterion, Criterion) + else Criterion[criterion] ): value for criterion, value in criteria.items() } From bff07c347305716be42e5e91845b36cca8c1e2cd Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:15:41 +0100 Subject: [PATCH 45/88] dedent --- test/pypesto/generate_expected_models.py | 81 ++++++++++++------------ 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/test/pypesto/generate_expected_models.py b/test/pypesto/generate_expected_models.py index a92a7972..620089b5 100644 --- a/test/pypesto/generate_expected_models.py +++ b/test/pypesto/generate_expected_models.py @@ -49,44 +49,43 @@ def objective_customizer(obj): # Indentation to match `test_pypesto.py`, to make it easier to keep files similar. -if True: - for test_case_path in test_cases_path.glob("*"): - if test_cases and test_case_path.stem not in test_cases: - continue - - if test_case_path.stem in skip_test_cases: - continue - - expected_model_yaml = test_case_path / "expected.yaml" - - if ( - SKIP_TEST_CASES_WITH_PREEXISTING_EXPECTED_MODEL - and expected_model_yaml.is_file() - ): - # Skip test cases that already have an expected model. - continue - print(f"Running test case {test_case_path.stem}") - - # Setup the pyPESTO model selector instance. - petab_select_problem = petab_select.Problem.from_yaml( - test_case_path / "petab_select_problem.yaml", - ) - pypesto_select_problem = pypesto.select.Problem( - petab_select_problem=petab_select_problem - ) - - # Run the selection process until "exhausted". - pypesto_select_problem.select_to_completion(**model_problem_options) - - # Get the best model - best_model = petab_select.analyze.get_best( - models=pypesto_select_problem.calibrated_models, - criterion=petab_select_problem.criterion, - ) - - # Generate the expected model. - best_model.to_yaml(expected_model_yaml) - - # pypesto_select_problem.calibrated_models.to_yaml( - # output_yaml="all_models.yaml", - # ) +for test_case_path in test_cases_path.glob("*"): + if test_cases and test_case_path.stem not in test_cases: + continue + + if test_case_path.stem in skip_test_cases: + continue + + expected_model_yaml = test_case_path / "expected.yaml" + + if ( + SKIP_TEST_CASES_WITH_PREEXISTING_EXPECTED_MODEL + and expected_model_yaml.is_file() + ): + # Skip test cases that already have an expected model. + continue + print(f"Running test case {test_case_path.stem}") + + # Setup the pyPESTO model selector instance. + petab_select_problem = petab_select.Problem.from_yaml( + test_case_path / "petab_select_problem.yaml", + ) + pypesto_select_problem = pypesto.select.Problem( + petab_select_problem=petab_select_problem + ) + + # Run the selection process until "exhausted". + pypesto_select_problem.select_to_completion(**model_problem_options) + + # Get the best model + best_model = petab_select.analyze.get_best( + models=pypesto_select_problem.calibrated_models, + criterion=petab_select_problem.criterion, + ) + + # Generate the expected model. + best_model.to_yaml(expected_model_yaml) + + # pypesto_select_problem.calibrated_models.to_yaml( + # output_yaml="all_models.yaml", + # ) From ec5b631131b7e95d5a7cca96b49d6cd667b8855d Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:45:27 +0100 Subject: [PATCH 46/88] add schema; add to RTD --- doc/problem_definition.rst | 41 +++++++++++++--------- doc/standard/make_schemas.py | 3 ++ doc/standard/model.yaml | 67 ++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 doc/standard/make_schemas.py create mode 100644 doc/standard/model.yaml diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index eb05699d..a9a52b6b 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -7,7 +7,9 @@ Model selection problems for PEtab Select are defined by the following files: #. a specification of the model space, and #. (optionally) a specification of the initial candidate model. -The different file formats are described below. +The different file formats are described below. Each file format is a YAML file +and comes with a YAML-formatted JSON schema, such that these files can be +easily worked with independently of the PEtab Select library. 1. Selection problem -------------------- @@ -122,22 +124,27 @@ contexts (for example, model comparison will require ``criteria``). .. code-block:: yaml - criteria: # dict[string, float] (optional). Criterion ID => criterion value. - estimated_parameters: # dict[string, float] (optional). Parameter ID => parameter value. - model_hash: # string (optional). - model_id: # string (optional). - model_subspace_id: # string (optional). - model_subspace_indices: # string (optional). - parameters: # dict[string, float] (optional). Parameter ID => parameter value or "estimate". - petab_yaml: # string. - predecessor_model_hash: # string (optional). + model_subspace_id: # str (required). + model_subspace_indices: # list[int] (required). + criteria: # dict[str, float] (optional). Criterion ID => criterion value. + model_hash: # str (optional). + model_subspace_petab_yaml: # str (required). + estimated_parameters: # dict[str, float] (optional). Parameter ID => parameter value. + iteration: # int (optional). + model_id: # str (optional). + parameters: # dict[str, float | int | "estimate"] (required). Parameter ID => parameter value or "estimate". + predecessor_model_hash: # str (optional). -- ``criteria``: The value of the criterion by which model selection was performed, at least. Optionally, other criterion values too. -- ``estimated_parameters``: Parameter estimates, not only of parameters specified to be estimated in a model space file, but also parameters specified to be estimated in the original PEtab problem of the model. -- ``model_hash``: The model hash, generated by the PEtab Select library. -- ``model_id``: The model ID. - ``model_subspace_id``: Same as in the model space files. - ``model_subspace_indices``: The indices that locate this model in its model subspace. -- ``parameters``: The parameters from the problem (either values or ``'estimate'``) (a specific combination from a model space file, but uncalibrated). -- ``petab_yaml``: Same as in model space files. -- ``predecessor_model_hash``: The hash of the model that preceded this model during the model selection process. +- ``criteria``: The value of the criterion by which model selection was performed, at least. Optionally, other criterion values too. +- ``model_hash``: The model hash, generated by the PEtab Select library. The format is ``[MODEL_SUBSPACE_ID]-[MODEL_SUBSPACE_INDICES_HASH]``. If all parameters are in the model are defined like ``0;estimate``, then the hash is a string of ``1`` and ``0``, for parameters that are estimated or not, respectively. +- ``model_subspace_petab_yaml``: Same as in model space files (see ``petab_yaml``). +- ``estimated_parameters``: Parameter estimates, including all estimated parameters that are not in the model selection problem; i.e., parameters that are set to be estimated in the model subspace PEtab problem but don't appear in the column header of the model space file. +- ``iteration``: The iteration of model selection in which this model appeared. +- ``model_id``: The model ID. +- ``parameters``: The parameter combination from the model space file that defines this model (either values or ``"estimate"``). Not the calibrated values, which are in ``estimated_parameters``! +- ``predecessor_model_hash``: The hash of the model that preceded this model during the model selection process. Will be ``virtual_initial_model-`` if the model had no predecessor model. + +.. literalinclude:: standard/model.yaml + :language: yaml diff --git a/doc/standard/make_schemas.py b/doc/standard/make_schemas.py new file mode 100644 index 00000000..8e371a11 --- /dev/null +++ b/doc/standard/make_schemas.py @@ -0,0 +1,3 @@ +from petab_select.model import ModelStandard + +ModelStandard.save_schema("model.yaml") diff --git a/doc/standard/model.yaml b/doc/standard/model.yaml new file mode 100644 index 00000000..a49a042d --- /dev/null +++ b/doc/standard/model.yaml @@ -0,0 +1,67 @@ +$defs: + ModelHash: + type: string +description: "A model.\n\nSee :class:`ModelBase` for the standardized attributes.\ + \ Additional\nattributes are available in ``Model`` to improve usability.\n\nAttributes:\n\ + \ _model_subspace_petab_problem:\n The PEtab problem of the model subspace\ + \ of this model.\n If not provided, this is reconstructed from\n :attr:`model_subspace_petab_yaml`." +properties: + model_subspace_id: + title: Model Subspace Id + type: string + model_subspace_indices: + items: + type: integer + title: Model Subspace Indices + type: array + criteria: + additionalProperties: + type: number + title: Criteria + type: object + model_hash: + $ref: '#/$defs/ModelHash' + default: null + model_subspace_petab_yaml: + anyOf: + - format: path + type: string + - type: 'null' + title: Model Subspace Petab Yaml + estimated_parameters: + anyOf: + - additionalProperties: + type: number + type: object + - type: 'null' + default: null + title: Estimated Parameters + iteration: + anyOf: + - type: integer + - type: 'null' + default: null + title: Iteration + model_id: + default: null + title: Model Id + type: string + parameters: + additionalProperties: + anyOf: + - type: number + - type: integer + - const: estimate + type: string + title: Parameters + type: object + predecessor_model_hash: + $ref: '#/$defs/ModelHash' + default: null +required: +- model_subspace_id +- model_subspace_indices +- model_subspace_petab_yaml +- parameters +title: Model +type: object From f36d70b7d31b7c8472d525f9188c926d972ffeee Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:52:37 +0100 Subject: [PATCH 47/88] subheadings --- doc/problem_definition.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index a9a52b6b..ed30681c 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -118,10 +118,13 @@ can be specified like selected model. Here, the format for a single model is shown. Multiple models can be specified -as a YAML list of the same format. The only required key is the ``petab_yaml``, -as a model requires a PEtab problem. Other keys are required in different +as a YAML list of the same format. Some optional keys are required in different contexts (for example, model comparison will require ``criteria``). +Brief format description +^^^^^^^^^^^^^^^^^^^^^^^^ + + .. code-block:: yaml model_subspace_id: # str (required). @@ -146,5 +149,8 @@ contexts (for example, model comparison will require ``criteria``). - ``parameters``: The parameter combination from the model space file that defines this model (either values or ``"estimate"``). Not the calibrated values, which are in ``estimated_parameters``! - ``predecessor_model_hash``: The hash of the model that preceded this model during the model selection process. Will be ``virtual_initial_model-`` if the model had no predecessor model. +Schema +^^^^^^ + .. literalinclude:: standard/model.yaml :language: yaml From e91123d8f4c4535105ac5fc2b4b9fcff4c254cd7 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:59:20 +0100 Subject: [PATCH 48/88] Update petab_select/model_subspace.py Co-authored-by: Daniel Weindl --- petab_select/model_subspace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/petab_select/model_subspace.py b/petab_select/model_subspace.py index 5e097c5a..1f62bd75 100644 --- a/petab_select/model_subspace.py +++ b/petab_select/model_subspace.py @@ -264,7 +264,7 @@ def continue_searching( raise NotImplementedError( "The virtual initial model and method " f"{candidate_space.method} is not implemented. " - "Please report if this is desired." + "Please report at https://github.com/PEtab-dev/petab_select/issues if this is desired." ) else: old_estimated_all = ( From 09470ae4a83d4ee526cba7646eea68a57dde87fb Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Tue, 17 Dec 2024 22:18:07 +0100 Subject: [PATCH 49/88] update test_analyze.py --- petab_select/constants.py | 2 + petab_select/model.py | 5 ++- petab_select/models.py | 71 ++++++++++------------------------ test/analyze/input/models.yaml | 8 ++-- test/analyze/test_analyze.py | 18 ++++----- 5 files changed, 37 insertions(+), 67 deletions(-) diff --git a/petab_select/constants.py b/petab_select/constants.py index 43ce0aa2..b98207f5 100644 --- a/petab_select/constants.py +++ b/petab_select/constants.py @@ -42,7 +42,9 @@ class Criterion(str, Enum): MODEL_SUBSPACE_INDICES = "model_subspace_indices" PARAMETERS = "parameters" MODEL_SUBSPACE_PETAB_YAML = "model_subspace_petab_yaml" +MODEL_SUBSPACE_PETAB_PROBLEM = "_model_subspace_petab_problem" PETAB_YAML = "petab_yaml" +ROOT_PATH = "root_path" ESTIMATE = "estimate" PETAB_PROBLEM = "petab_problem" diff --git a/petab_select/model.py b/petab_select/model.py index 07ec7416..a22d17fb 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -25,6 +25,7 @@ MODEL_SUBSPACE_PETAB_YAML, PETAB_PROBLEM, PETAB_YAML, + ROOT_PATH, TYPE_PARAMETER, Criterion, ) @@ -328,8 +329,8 @@ def _fix_relative_paths( model = handler(data) root_path = None - if "root_path" in data: - root_path = data.pop("root_path") + if ROOT_PATH in data: + root_path = data.pop(ROOT_PATH) if root_path is None: return model diff --git a/petab_select/models.py b/petab_select/models.py index f2c9b4e7..6e770d35 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -16,7 +16,9 @@ ITERATION, MODEL_HASH, MODEL_ID, + MODEL_SUBSPACE_PETAB_PROBLEM, PREDECESSOR_MODEL_HASH, + ROOT_PATH, TYPE_PATH, Criterion, ) @@ -372,7 +374,9 @@ def from_yaml( models_yaml: The path to the PEtab Select list of model YAML file. petab_problem: - See :meth:`Model.from_dict`. + Provide a preloaded copy of the PEtab problem. Note: + all models should share the same PEtab problem if this is + provided. problem: The PEtab Select problem. @@ -384,25 +388,20 @@ def from_yaml( if not model_dict_list: # Empty file models = [] - elif not isinstance(model_dict_list, list): + elif isinstance(model_dict_list, dict): # File contains a single model - models = [ - Model.from_dict( - model_dict_list, - base_path=Path(models_yaml).parent, - petab_problem=petab_problem, - ) - ] - else: - # File contains a list of models - models = [ - Model.from_dict( - model_dict, - base_path=Path(models_yaml).parent, - petab_problem=petab_problem, - ) - for model_dict in model_dict_list - ] + model_dict_list = [model_dict_list] + + models = [ + Model.model_validate( + { + **model_dict, + ROOT_PATH: Path(models_yaml).parent, + MODEL_SUBSPACE_PETAB_PROBLEM: petab_problem, + } + ) + for model_dict in model_dict_list + ] return Models(models=models, problem=problem) @@ -544,25 +543,7 @@ def models_from_yaml_list( allow_single_model: bool = True, problem: Problem = None, ) -> Models: - """Generate a model from a PEtab Select list of model YAML file. - - Deprecated. Use `petab_select.Models.from_yaml` instead. - - Args: - model_list_yaml: - The path to the PEtab Select list of model YAML file. - petab_problem: - See :meth:`Model.from_dict`. - allow_single_model: - Given a YAML file that contains a single model directly (not in - a 1-element list), if ``True`` then the single model will be read in, - else a ``ValueError`` will be raised. - problem: - The PEtab Select problem. - - Returns: - The models. - """ + """Deprecated. Use `petab_select.Models.from_yaml` instead.""" warnings.warn( ( "Use `petab_select.Models.from_yaml` instead. " @@ -583,19 +564,7 @@ def models_to_yaml_list( output_yaml: TYPE_PATH, relative_paths: bool = True, ) -> None: - """Generate a YAML listing of models. - - Deprecated. Use `petab_select.Models.to_yaml` instead. - - Args: - models: - The models. - output_yaml: - The location where the YAML will be saved. - relative_paths: - Whether to rewrite the paths in each model (e.g. the path to the - model's PEtab problem) relative to the `output_yaml` location. - """ + """Deprecated. Use `petab_select.Models.to_yaml` instead.""" warnings.warn( "Use `petab_select.Models.to_yaml` instead.", DeprecationWarning, diff --git a/test/analyze/input/models.yaml b/test/analyze/input/models.yaml index 264e1154..3730b6fc 100644 --- a/test/analyze/input/models.yaml +++ b/test/analyze/input/models.yaml @@ -14,7 +14,7 @@ estimated_parameters: k2: 0.15 k3: 0.0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml predecessor_model_hash: dummy_p0-0 - criteria: AIC: 4 @@ -29,7 +29,7 @@ k1: estimate k2: estimate k3: 0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml predecessor_model_hash: virtual_initial_model- - criteria: AIC: 3 @@ -47,7 +47,7 @@ estimated_parameters: k2: 0.15 k3: 0.0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml predecessor_model_hash: virtual_initial_model- - criteria: AIC: 2 @@ -62,5 +62,5 @@ k1: estimate k2: estimate k3: 0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml predecessor_model_hash: virtual_initial_model- diff --git a/test/analyze/test_analyze.py b/test/analyze/test_analyze.py index 32169a85..f37e6013 100644 --- a/test/analyze/test_analyze.py +++ b/test/analyze/test_analyze.py @@ -5,7 +5,6 @@ from petab_select import ( VIRTUAL_INITIAL_MODEL, Criterion, - ModelHash, Models, analyze, ) @@ -13,7 +12,6 @@ base_dir = Path(__file__).parent DUMMY_HASH = "dummy_p0-0" -VIRTUAL_HASH = ModelHash.from_hash(VIRTUAL_INITIAL_MODEL) @pytest.fixture @@ -26,15 +24,15 @@ def test_group_by_predecessor_model(models: Models) -> None: groups = analyze.group_by_predecessor_model(models) # Expected groups assert len(groups) == 2 - assert VIRTUAL_HASH in groups + assert VIRTUAL_INITIAL_MODEL.hash in groups assert DUMMY_HASH in groups # Expected group members assert len(groups[DUMMY_HASH]) == 1 assert "M-011" in groups[DUMMY_HASH] - assert len(groups[VIRTUAL_HASH]) == 3 - assert "M-110" in groups[VIRTUAL_HASH] - assert "M2-011" in groups[VIRTUAL_HASH] - assert "M2-110" in groups[VIRTUAL_HASH] + assert len(groups[VIRTUAL_INITIAL_MODEL.hash]) == 3 + assert "M-110" in groups[VIRTUAL_INITIAL_MODEL.hash] + assert "M2-011" in groups[VIRTUAL_INITIAL_MODEL.hash] + assert "M2-110" in groups[VIRTUAL_INITIAL_MODEL.hash] def test_group_by_iteration(models: Models) -> None: @@ -64,9 +62,9 @@ def test_get_best_by_iteration(models: Models) -> None: assert 2 in groups assert 5 in groups # Expected best models - assert groups[1].get_hash() == "M2-011" - assert groups[2].get_hash() == "M2-110" - assert groups[5].get_hash() == "M-110" + assert groups[1].hash == "M2-011" + assert groups[2].hash == "M2-110" + assert groups[5].hash == "M-110" def test_relative_criterion_values(models: Models) -> None: From aa2331e4c175e07519f33e7f0b78b528a984ed97 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 16:55:22 +0100 Subject: [PATCH 50/88] update test_famos.py --- petab_select/ui.py | 11 ++--- .../test_files/predecessor_model.yaml | 47 +++++++++++++------ test/candidate_space/test_famos.py | 23 +++++---- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/petab_select/ui.py b/petab_select/ui.py index 79083981..34abc14a 100644 --- a/petab_select/ui.py +++ b/petab_select/ui.py @@ -418,14 +418,13 @@ def write_summary_tsv( ) # FIXME remove once MostDistantCandidateSpace exists... + # which might be difficult to implement because the most + # distant is a hypothetical model, which is then used to find a + # real model in its neighborhood of the model space method = candidate_space.method - if ( - isinstance(candidate_space, FamosCandidateSpace) - and isinstance(candidate_space.predecessor_model, Model) - and candidate_space.predecessor_model.predecessor_model_hash is None - ): + if isinstance(candidate_space, FamosCandidateSpace): with open(candidate_space.summary_tsv) as f: - if sum(1 for _ in f) > 1: + if f.readlines()[-1].startswith("Jumped"): method = Method.MOST_DISTANT candidate_space.write_summary_tsv( diff --git a/test/candidate_space/input/famos_synthetic/test_files/predecessor_model.yaml b/test/candidate_space/input/famos_synthetic/test_files/predecessor_model.yaml index f0442820..3a3aad43 100644 --- a/test/candidate_space/input/famos_synthetic/test_files/predecessor_model.yaml +++ b/test/candidate_space/input/famos_synthetic/test_files/predecessor_model.yaml @@ -1,8 +1,28 @@ +model_subspace_id: model_subspace_1 +model_subspace_indices: +- 1 +- 1 +- 0 +- 0 +- 1 +- 1 +- 0 +- 1 +- 1 +- 1 +- 0 +- 0 +- 0 +- 1 +- 1 +- 1 criteria: AIC: 30330.782621349786 AICc: 30332.80096997364 BIC: 30358.657538777607 NLLH: 15155.391310674893 +model_hash: model_subspace_1-1100110111000111 +model_subspace_petab_yaml: ../petab/FAMoS_2019_problem.yaml estimated_parameters: mu_AB: 0.09706971737957297 mu_AD: -0.6055359156893474 @@ -14,26 +34,23 @@ estimated_parameters: mu_DC: -1.1619119214640863 ro_A: -1.6431508614147425 ro_B: 2.9912966824709097 -model_hash: null -model_id: M_1100110111000111 -model_subspace_id: model_subspace_1 -model_subspace_indices: null +iteration: null +model_id: model_subspace_1-1100110111000111 parameters: + ro_A: estimate + ro_B: estimate + ro_C: 0 + ro_D: 0 mu_AB: estimate + mu_BA: estimate mu_AC: 0 + mu_CA: estimate mu_AD: estimate - mu_BA: estimate + mu_DA: estimate mu_BC: 0 - mu_BD: 0 - mu_CA: estimate mu_CB: 0 - mu_CD: estimate - mu_DA: estimate + mu_BD: 0 mu_DB: estimate + mu_CD: estimate mu_DC: estimate - ro_A: estimate - ro_B: estimate - ro_C: 0 - ro_D: 0 -petab_yaml: ../petab/FAMoS_2019_problem.yaml -predecessor_model_hash: null +predecessor_model_hash: virtual_initial_model- diff --git a/test/candidate_space/test_famos.py b/test/candidate_space/test_famos.py index f4ad33e1..5036dc69 100644 --- a/test/candidate_space/test_famos.py +++ b/test/candidate_space/test_famos.py @@ -5,7 +5,7 @@ from more_itertools import one import petab_select -from petab_select import Method, Models +from petab_select import Method, ModelHash, Models from petab_select.constants import ( CANDIDATE_SPACE, MODEL_HASH, @@ -35,7 +35,7 @@ def expected_criterion_values(input_path): sep="\t", ).set_index(MODEL_HASH) return { - petab_select.model.ModelHash.from_hash(k): v + ModelHash.model_validate(k): v for k, v in calibration_results[Criterion.AICC].items() } @@ -93,7 +93,7 @@ def calibrate( ) -> None: model.set_criterion( criterion=petab_select_problem.criterion, - value=expected_criterion_values[model.get_hash()], + value=expected_criterion_values[model.hash], ) def parse_summary_to_progress_list(summary_tsv: str) -> tuple[Method, set]: @@ -129,6 +129,7 @@ def parse_summary_to_progress_list(summary_tsv: str) -> tuple[Method, set]: all_calibrated_models = Models() candidate_space = petab_select_problem.new_candidate_space() + expected_repeated_model_hash0 = candidate_space.predecessor_model.hash candidate_space.summary_tsv.unlink(missing_ok=True) candidate_space._setup_summary_tsv() @@ -147,7 +148,7 @@ def parse_summary_to_progress_list(summary_tsv: str) -> tuple[Method, set]: calibrated_models = Models() for candidate_model in iteration[UNCALIBRATED_MODELS]: calibrate(candidate_model) - calibrated_models[candidate_model.get_hash()] = candidate_model + calibrated_models[candidate_model.hash] = candidate_model # Finalize iteration iteration_results = petab_select.ui.end_iteration( @@ -162,14 +163,20 @@ def parse_summary_to_progress_list(summary_tsv: str) -> tuple[Method, set]: raise StopIteration("No valid models found.") # A model is encountered twice and therefore skipped. - expected_repeated_model_hash = petab_select_problem.get_model( + expected_repeated_model_hash1 = petab_select_problem.get_model( model_subspace_id=one( petab_select_problem.model_space.model_subspaces ), model_subspace_indices=[int(s) for s in "0001011010010010"], - ).get_hash() - assert len(warning_record) == 1 - assert expected_repeated_model_hash in warning_record[0].message.args[0] + ).hash + # The predecessor model is also re-encountered. + assert len(warning_record) == 2 + assert ( + str(expected_repeated_model_hash0) in warning_record[0].message.args[0] + ) + assert ( + str(expected_repeated_model_hash1) in warning_record[1].message.args[0] + ) progress_list = parse_summary_to_progress_list(candidate_space.summary_tsv) From 241706c838f6db93eb7a3324d2afb7c0461c2605 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 17:17:21 +0100 Subject: [PATCH 51/88] review: add link --- doc/problem_definition.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index ed30681c..3292d934 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -152,5 +152,7 @@ Brief format description Schema ^^^^^^ +The format is provided as `YAML-formatted JSON schema `_, which enables easy validation with various third-party tools. + .. literalinclude:: standard/model.yaml :language: yaml From 173509873c5729fc461bac5c6303a1d89284c4ff Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:04:45 +0100 Subject: [PATCH 52/88] fix link --- doc/problem_definition.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index 3292d934..73bf92cf 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -152,7 +152,7 @@ Brief format description Schema ^^^^^^ -The format is provided as `YAML-formatted JSON schema `_, which enables easy validation with various third-party tools. +The format is provided as `YAML-formatted JSON schema <../standard/model.yaml>`_, which enables easy validation with various third-party tools. .. literalinclude:: standard/model.yaml :language: yaml From 84d099dbd4a22c0fd297ed735e32cbab75eb2fa5 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:22:17 +0100 Subject: [PATCH 53/88] update test_cli.py --- petab_select/model.py | 21 +++++++++++++-------- test/cli/input/model.yaml | 16 +++++++++++----- test/cli/input/models.yaml | 24 +++++++++++++----------- test/cli/test_cli.py | 1 - 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/petab_select/model.py b/petab_select/model.py index a22d17fb..e76793ac 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -551,16 +551,21 @@ def to_petab( if set_estimated_parameters is None and self.estimated_parameters: set_estimated_parameters = True - if set_estimated_parameters and ( - missing_parameter_estimates := set(self.parameters).difference( + if set_estimated_parameters: + required_estimates = { + parameter_id + for parameter_id, value in self.parameters.items() + if value == ESTIMATE + } + missing_estimates = required_estimates.difference( self.estimated_parameters ) - ): - raise ValueError( - "Try again with `set_estimated_parameters=False`, because " - "some parameter estimates are missing. Missing estimates for: " - f"`{missing_parameter_estimates}`." - ) + if missing_estimates: + raise ValueError( + "Try again with `set_estimated_parameters=False`, because " + "some parameter estimates are missing. Missing estimates for: " + f"`{missing_estimates}`." + ) for parameter_id, parameter_value in self.parameters.items(): # If the parameter is to be estimated. diff --git a/test/cli/input/model.yaml b/test/cli/input/model.yaml index dcaaa5a2..7cda4c4a 100644 --- a/test/cli/input/model.yaml +++ b/test/cli/input/model.yaml @@ -1,10 +1,16 @@ -- criteria: {} +- model_subspace_id: M + model_subspace_indices: + - 0 + - 1 + - 1 + criteria: {} + model_hash: M-011 + model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + estimated_parameters: + k2: 0.15 + k3: 0.0 model_id: model parameters: k1: 0.2 k2: estimate k3: estimate - estimated_parameters: - k2: 0.15 - k3: 0.0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml diff --git a/test/cli/input/models.yaml b/test/cli/input/models.yaml index 06aa3933..b6daa42c 100644 --- a/test/cli/input/models.yaml +++ b/test/cli/input/models.yaml @@ -1,27 +1,29 @@ -- criteria: {} - model_id: model_1 - model_subspace_id: M +- model_subspace_id: M model_subspace_indices: - 0 - 1 - 1 + criteria: {} + model_hash: M-011 + model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + estimated_parameters: + k2: 0.15 + k3: 0.0 + model_id: model_1 parameters: k1: 0.2 k2: estimate k3: estimate - estimated_parameters: - k2: 0.15 - k3: 0.0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml -- criteria: {} - model_id: model_2 - model_subspace_id: M +- model_subspace_id: M model_subspace_indices: - 1 - 1 - 0 + criteria: {} + model_hash: M-110 + model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml + model_id: model_2 parameters: k1: estimate k2: estimate k3: 0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml diff --git a/test/cli/test_cli.py b/test/cli/test_cli.py index 0a4dc34d..ccf015ea 100644 --- a/test/cli/test_cli.py +++ b/test/cli/test_cli.py @@ -55,7 +55,6 @@ def test_model_to_petab( ], ) - print(result.stdout) # The new PEtab problem YAML file is output to stdout correctly. assert ( result.stdout == f'{base_dir / "output" / "model" / "problem.yaml"}\n' From 6419dad141f08c206d306017d080a0152d373a42 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:41:40 +0100 Subject: [PATCH 54/88] fix link --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 93865e8e..e21a5944 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -58,7 +58,7 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "sphinx_rtd_theme" -# html_static_path = ['_static'] +html_static_path = ["standard"] html_logo = "logo/logo-wide.svg" From daf876b851e8c95fad649590a6a988e50cff9125 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:46:18 +0100 Subject: [PATCH 55/88] fix test_model.py --- test/model/input/model.yaml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/test/model/input/model.yaml b/test/model/input/model.yaml index dcaaa5a2..233861de 100644 --- a/test/model/input/model.yaml +++ b/test/model/input/model.yaml @@ -1,10 +1,15 @@ -- criteria: {} - model_id: model - parameters: - k1: 0.2 - k2: estimate - k3: estimate - estimated_parameters: - k2: 0.15 - k3: 0.0 - petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml +model_subspace_id: M +model_subspace_indices: +- 0 +- 1 +- 1 +criteria: {} +model_subspace_petab_yaml: ../../../doc/examples/model_selection/petab_problem.yaml +model_id: model +parameters: + k1: 0.2 + k2: estimate + k3: estimate +estimated_parameters: + k2: 0.15 + k3: 0.0 From 1e01423f210d9f270240387a1bf206de86dddae3 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:47:28 +0100 Subject: [PATCH 56/88] temp fix pypesto --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1f18088a..12d1afaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ test = [ "amici >= 0.11.25", "fides >= 0.7.5", # "pypesto > 0.2.13", - "pypesto @ git+https://github.com/ICB-DCM/pyPESTO.git@select_class_models#egg=pypesto", + "pypesto @ git+https://github.com/ICB-DCM/pyPESTO.git@select_mkstd#egg=pypesto", "tox >= 3.12.4", ] doc = [ From 1ef4dcd429212931d95e55e110dce9214ffe3194 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:57:41 +0100 Subject: [PATCH 57/88] fix link --- doc/problem_definition.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index 73bf92cf..9545e300 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -152,7 +152,7 @@ Brief format description Schema ^^^^^^ -The format is provided as `YAML-formatted JSON schema <../standard/model.yaml>`_, which enables easy validation with various third-party tools. +The format is provided as `YAML-formatted JSON schema <_static/model.yaml>`_, which enables easy validation with various third-party tools. .. literalinclude:: standard/model.yaml :language: yaml From 5e5af23e3c10e711a5545375d40fb23f75948163 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:26:33 +0100 Subject: [PATCH 58/88] add schema --- doc/problem_definition.rst | 2 +- doc/standard/make_schemas.py | 2 + doc/standard/models.yaml | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 doc/standard/models.yaml diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index 9545e300..cdbe93fc 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -152,7 +152,7 @@ Brief format description Schema ^^^^^^ -The format is provided as `YAML-formatted JSON schema <_static/model.yaml>`_, which enables easy validation with various third-party tools. +The schema is provided as `YAML-formatted JSON schema <_static/model.yaml>`_, which enables easy validation with various third-party tools. There is an additional schema for a `list of models in a single file <_static/models.yaml>`_. .. literalinclude:: standard/model.yaml :language: yaml diff --git a/doc/standard/make_schemas.py b/doc/standard/make_schemas.py index 8e371a11..c01c62b8 100644 --- a/doc/standard/make_schemas.py +++ b/doc/standard/make_schemas.py @@ -1,3 +1,5 @@ from petab_select.model import ModelStandard +from petab_select.models import ModelsStandard ModelStandard.save_schema("model.yaml") +ModelsStandard.save_schema("models.yaml") diff --git a/doc/standard/models.yaml b/doc/standard/models.yaml new file mode 100644 index 00000000..a90f3d6d --- /dev/null +++ b/doc/standard/models.yaml @@ -0,0 +1,86 @@ +$defs: + Model: + description: "A model.\n\nSee :class:`ModelBase` for the standardized attributes.\ + \ Additional\nattributes are available in ``Model`` to improve usability.\n\n\ + Attributes:\n _model_subspace_petab_problem:\n The PEtab problem of\ + \ the model subspace of this model.\n If not provided, this is reconstructed\ + \ from\n :attr:`model_subspace_petab_yaml`." + properties: + model_subspace_id: + title: Model Subspace Id + type: string + model_subspace_indices: + items: + type: integer + title: Model Subspace Indices + type: array + criteria: + additionalProperties: + type: number + title: Criteria + type: object + model_hash: + $ref: '#/$defs/ModelHash' + default: null + model_subspace_petab_yaml: + anyOf: + - format: path + type: string + - type: 'null' + title: Model Subspace Petab Yaml + estimated_parameters: + anyOf: + - additionalProperties: + type: number + type: object + - type: 'null' + default: null + title: Estimated Parameters + iteration: + anyOf: + - type: integer + - type: 'null' + default: null + title: Iteration + model_id: + default: null + title: Model Id + type: string + parameters: + additionalProperties: + anyOf: + - type: number + - type: integer + - const: estimate + type: string + title: Parameters + type: object + predecessor_model_hash: + $ref: '#/$defs/ModelHash' + default: null + required: + - model_subspace_id + - model_subspace_indices + - model_subspace_petab_yaml + - parameters + title: Model + type: object + ModelHash: + type: string +description: 'A collection of models. + + + Provide a PEtab Select ``problem`` to the constructor or via + + ``set_problem``, to use add models by hashes. This means that all models + + must belong to the same PEtab Select problem. + + + This permits both ``list`` and ``dict`` operations -- see + + :class:``ListDict`` for further details.' +items: + $ref: '#/$defs/Model' +title: Models +type: array From 64159eb85a3ad800d4af2a9c2125b2cd63c612b7 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:27:05 +0100 Subject: [PATCH 59/88] rename path args to `filename` --- petab_select/model.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/petab_select/model.py b/petab_select/model.py index e76793ac..bbe8bb45 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -359,21 +359,21 @@ def _fix_predecessor_model_hash(self: ModelBase) -> ModelBase: def to_yaml( self, - yaml_path: str | Path, + filename: str | Path, ) -> None: """Save a model to a YAML file. - All paths will be made relative to the ``yaml_path`` directory. + All paths will be made relative to the ``filename`` directory. Args: - yaml_path: - The model YAML file location. + filename: + Location of the YAML file. """ - root_path = Path(yaml_path).parent + root_path = Path(filename).parent model = copy.deepcopy(self) model.set_relative_paths(root_path=root_path) - ModelStandard.save_data(data=model, filename=yaml_path) + ModelStandard.save_data(data=model, filename=filename) def set_relative_paths(self, root_path: str | Path) -> None: """Change all paths to be relative to ``root_path``.""" @@ -683,16 +683,16 @@ def get_parameter_values( @staticmethod def from_yaml( - yaml_path: str | Path, + filename: str | Path, ) -> Model: """Load a model from a YAML file. Args: - yaml_path: - The model YAML file location. + filename: + Location of the YAML file. """ model = ModelStandard.load_data( - filename=yaml_path, root_path=yaml_path.parent + filename=filename, root_path=Path(filename).parent ) return model From bda793d24f300aea4ffa0f2c991ef7962f892b37 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:31:14 +0100 Subject: [PATCH 60/88] change `Models` to be a `RootModel` --- petab_select/models.py | 162 +++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 56 deletions(-) diff --git a/petab_select/models.py b/petab_select/models.py index 6e770d35..a681157c 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -1,14 +1,23 @@ from __future__ import annotations +import copy import warnings from collections import Counter from collections.abc import Iterable, MutableSequence from pathlib import Path from typing import TYPE_CHECKING, Any, TypeAlias +import mkstd import numpy as np import pandas as pd -import yaml +from pydantic import ( + Field, + PrivateAttr, + RootModel, + ValidationInfo, + ValidatorFunctionWrapHandler, + model_validator, +) from .constants import ( CRITERIA, @@ -42,14 +51,15 @@ ModelIndex: TypeAlias = int | ModelHash | slice | str | Iterable __all__ = [ - "ListDict", + "_ListDict", "Models", "models_from_yaml_list", "models_to_yaml_list", + "ModelsStandard", ] -class ListDict(MutableSequence): +class _ListDict(RootModel, MutableSequence): """Acts like a ``list`` and a ``dict``. Not all methods are implemented -- feel free to request anything that you @@ -73,18 +83,63 @@ class ListDict(MutableSequence): _hashes: The list of metadata (dictionary keys) (model hashes). _problem: + The PEtab Select problem. """ - def __init__( - self, models: Iterable[ModelLike] = None, problem: Problem = None + root: list[Model] = Field(default_factory=list) + _hashes: list[ModelHash] = PrivateAttr(default_factory=list) + _problem: Problem | None = PrivateAttr(default=None) + + @model_validator(mode="wrap") + def _check_kwargs( + kwargs: dict[str, list[ModelLike] | Problem] | list[ModelLike], + handler: ValidatorFunctionWrapHandler, + info: ValidationInfo, ) -> Models: - self._models = [] - self._hashes = [] - self._problem = problem + """Handle `Models` creation from different sources.""" + _models = [] + _problem = None + if isinstance(kwargs, list): + _models = kwargs + elif isinstance(kwargs, dict): + # Identify the argument with the models + if "models" in kwargs and "root" in kwargs: + raise ValueError("Provide only one of `root` and `models`.") + _models = kwargs.get("models") or kwargs.get("root") or [] + + # Identify the argument with the PEtab Select problem + if "problem" in kwargs and "_problem" in kwargs: + raise ValueError( + "Provide only one of `problem` and `_problem`." + ) + _problem = kwargs.get("problem") or kwargs.get("_problem") + + # Distribute model constructor kwargs to each model dict + if model_kwargs := kwargs.get("model_kwargs"): + for _model_index, _model in enumerate(_models): + if not isinstance(_model, dict): + raise ValueError( + "`model_kwargs` are only intended to be used when " + "constructing models from a YAML file." + ) + _models[_model_index] = {**_model, **model_kwargs} + + models = handler(_models) + models._problem = _problem + return models + + @model_validator(mode="after") + def _check_typing(self: RootModel) -> RootModel: + """Fix model typing.""" + models0 = self._models + self.root = [] + # This also converts all model hashes into models. + self.extend(models0) + return self - if models is None: - models = [] - self.extend(models) + @property + def _models(self) -> list[Model]: + return self.root def __repr__(self) -> str: """Get the model hashes that can regenerate these models. @@ -97,7 +152,7 @@ def __repr__(self) -> str: # skipped __lt__, __le__ def __eq__(self, other) -> bool: - other_hashes = Models(other)._hashes + other_hashes = Models(models=other)._hashes same_length = len(self._hashes) == len(other_hashes) same_hashes = set(self._hashes) == set(other_hashes) return same_length and same_hashes @@ -253,14 +308,16 @@ def __add__( new_models = [self._problem.model_hash_to_model(other)] case Iterable(): # Assumes the models belong to the same PEtab Select problem. - new_models = Models(other, problem=self._problem)._models + new_models = Models( + models=other, _problem=self._problem + )._models case _: raise TypeError(f"Unexpected type: `{type(other)}`.") models = self._models + new_models if not left: models = new_models + self._models - return Models(models=models, problem=self._problem) + return Models(models=models, _problem=self._problem) def __radd__(self, other: ModelLike | ModelsLike) -> Models: return self.__add__(other=other, left=False) @@ -271,7 +328,7 @@ def __iadd__(self, other: ModelLike | ModelsLike) -> Models: # skipped __mul__, __rmul__, __imul__ def __copy__(self) -> Models: - return Models(models=self._models, problem=self._problem) + return Models(models=self._models, _problem=self._problem) def append(self, item: ModelLike) -> None: self._update(index=len(self), item=item) @@ -307,7 +364,11 @@ def extend(self, other: Iterable[ModelLike]) -> None: for model_like in other: self.append(model_like) - # __iter__/__next__? Not in UserList... + def __iter__(self): + return iter(self._models) + + def __next__(self): + raise NotImplementedError # `dict` methods. @@ -331,7 +392,7 @@ def values(self) -> Models: return self -class Models(ListDict): +class Models(_ListDict): """A collection of models. Provide a PEtab Select ``problem`` to the constructor or via @@ -364,70 +425,56 @@ def lint(self): @staticmethod def from_yaml( - models_yaml: TYPE_PATH, + filename: TYPE_PATH, petab_problem: petab.Problem = None, problem: Problem = None, ) -> Models: - """Generate models from a PEtab Select list of model YAML file. + """Load models from a YAML file. Args: - models_yaml: - The path to the PEtab Select list of model YAML file. + filename: + Location of the YAML file. petab_problem: - Provide a preloaded copy of the PEtab problem. Note: + Provide a preloaded copy of the PEtab problem. N.B.: all models should share the same PEtab problem if this is provided. problem: - The PEtab Select problem. + The PEtab Select problem. N.B.: all models should belong to the + same PEtab Select problem if this is provided. Returns: The models. """ - with open(str(models_yaml)) as f: - model_dict_list = yaml.safe_load(f) - if not model_dict_list: - # Empty file - models = [] - elif isinstance(model_dict_list, dict): - # File contains a single model - model_dict_list = [model_dict_list] - - models = [ - Model.model_validate( - { - **model_dict, - ROOT_PATH: Path(models_yaml).parent, - MODEL_SUBSPACE_PETAB_PROBLEM: petab_problem, - } - ) - for model_dict in model_dict_list - ] - - return Models(models=models, problem=problem) + return ModelsStandard.load_data( + filename=filename, + _problem=problem, + model_kwargs={ + ROOT_PATH: Path(filename).parent, + MODEL_SUBSPACE_PETAB_PROBLEM: petab_problem, + }, + ) def to_yaml( self, - output_yaml: TYPE_PATH, + filename: TYPE_PATH, relative_paths: bool = True, ) -> None: - """Generate a YAML listing of models. + """Save models to a YAML file. Args: - output_yaml: - The location where the YAML will be saved. + filename: + Location of the YAML file. relative_paths: Whether to rewrite the paths in each model (e.g. the path to the model's PEtab problem) relative to the `output_yaml` location. """ - paths_relative_to = None + models = self._models if relative_paths: - paths_relative_to = Path(output_yaml).parent - model_dicts = [ - model.to_dict(paths_relative_to=paths_relative_to) - for model in self - ] - with open(output_yaml, "w") as f: - yaml.safe_dump(model_dicts, f) + root_path = Path(filename).parent + models = copy.deepcopy(models) + for model in models: + model.set_relative_paths(root_path=root_path) + ModelsStandard.save_data(data=models, filename=filename) def get_criterion( self, @@ -573,3 +620,6 @@ def models_to_yaml_list( Models(models=models).to_yaml( output_yaml=output_yaml, relative_paths=relative_paths ) + + +ModelsStandard = mkstd.YamlStandard(model=Models) From 643c1207f782a21b466ade2f84199a8a6966a660 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:54:00 +0100 Subject: [PATCH 61/88] update doc links; bump mkstd req --- doc/problem_definition.rst | 7 ++++++- pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index cdbe93fc..0e2d92ca 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -152,7 +152,12 @@ Brief format description Schema ^^^^^^ -The schema is provided as `YAML-formatted JSON schema <_static/model.yaml>`_, which enables easy validation with various third-party tools. There is an additional schema for a `list of models in a single file <_static/models.yaml>`_. +The schema are provided as YAML-formatted JSON schema, which enables easy validation with various third-party tools. Schema are provided for: + +- `a single model <_static/model.yaml>`_, and +- `a list of models <_static/models.yaml>`_, which is simply a YAML list of the single model format. + +Below is the schema for a single model. .. literalinclude:: standard/model.yaml :language: yaml diff --git a/pyproject.toml b/pyproject.toml index 12d1afaf..7043546f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ "pyyaml>=6.0.2", "click>=8.1.7", "dill>=0.3.9", - "mkstd>=0.0.5", + "mkstd>=0.0.7", ] [project.optional-dependencies] plot = [ From 7bc51fde0f3be6db2deae88044138b61cbf13838 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:12:12 +0100 Subject: [PATCH 62/88] update docs --- doc/problem_definition.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index 0e2d92ca..814a64f9 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -34,8 +34,9 @@ A YAML file with a description of the model selection problem. - ``candidate_space_arguments``: Additional arguments used to generate candidate models during model selection. For example, an initial candidate model can be specified with the following code, where - ``predecessor_model.yaml`` is a valid model file. Additional arguments are - provided in the documentation of the ``CandidateSpace`` class. + ``predecessor_model.yaml`` is a valid :ref:`model file `. Additional arguments are + provided in the documentation of the ``CandidateSpace`` class, and an example is provided in + `test case 0009 `_. .. code-block:: yaml @@ -81,6 +82,9 @@ all parameters. - ``0.0;1.1;estimate`` (the parameter can take the values ``0.0`` or ``1.1``, or be estimated) +Example of concise specification +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Using the ``;``-delimited list format, a model subspace that has two parameters (``p1, p2``) and six models: @@ -105,6 +109,8 @@ can be specified like - 0;estimate - 10;20;estimate +.. _section-model-yaml: + 3. Model(s) (Predecessor models / model interchange / report) ------------------------------------------------------------- From d32e92234b84b6b1b11baa95920a0bab3f33a959 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 21:31:14 +0100 Subject: [PATCH 63/88] test problem load/save round-trip --- petab_select/model_space.py | 130 ++---------------- petab_select/models.py | 2 +- test/problem/__init__.py | 0 test/problem/expected_output/model_space.tsv | 9 ++ .../expected_output/petab_select_problem.yaml | 6 + test/problem/test_problem.py | 32 +++++ 6 files changed, 57 insertions(+), 122 deletions(-) create mode 100644 test/problem/__init__.py create mode 100644 test/problem/expected_output/model_space.tsv create mode 100644 test/problem/expected_output/petab_select_problem.yaml create mode 100644 test/problem/test_problem.py diff --git a/petab_select/model_space.py b/petab_select/model_space.py index f3237ae9..9d9dd529 100644 --- a/petab_select/model_space.py +++ b/petab_select/model_space.py @@ -1,24 +1,17 @@ """The `ModelSpace` class and related methods.""" -import itertools import logging import warnings from collections.abc import Iterable from pathlib import Path -from tempfile import NamedTemporaryFile -from typing import Any, TextIO, get_args +from typing import Any, get_args import numpy as np import pandas as pd from .candidate_space import CandidateSpace from .constants import ( - HEADER_ROW, - MODEL_ID_COLUMN, MODEL_SUBSPACE_ID, - PARAMETER_DEFINITIONS_START, - PARAMETER_VALUE_DELIMITER, - PETAB_YAML_COLUMN, TYPE_PATH, ) from .model import Model @@ -27,106 +20,9 @@ __all__ = [ "ModelSpace", "get_model_space_df", - "read_model_space_file", - "write_model_space_df", ] -def read_model_space_file(filename: str) -> TextIO: - """Read a model space file. - - The model space specification is currently expanded and written to a - temporary file. - - Args: - filename: - The name of the file to be unpacked. - - Returns: - A temporary file object, which is the unpacked file. - """ - """ - FIXME(dilpath) - Todo: - * Consider alternatives to `_{n}` suffix for model `modelId` - * How should the selected model be reported to the user? Remove the - `_{n}` suffix and report the original `modelId` alongside the - selected parameters? Generate a set of PEtab files with the - chosen SBML file and the parameters specified in a parameter or - condition file? - * Don't "unpack" file if it is already in the unpacked format - * Sort file after unpacking - * Remove duplicates? - """ - # FIXME rewrite to just generate models from the original file, instead of - # expanding all and writing to a file. - expanded_models_file = NamedTemporaryFile(mode="r+", delete=False) - with open(filename) as fh: - with open(expanded_models_file.name, "w") as ms_f: - # could replace `else` condition with ms_f.readline() here, and - # remove `if` statement completely - for line_index, line in enumerate(fh): - # Skip empty/whitespace-only lines - if not line.strip(): - continue - if line_index != HEADER_ROW: - columns = line2row(line, unpacked=False) - parameter_definitions = [ - definition.split(PARAMETER_VALUE_DELIMITER) - for definition in columns[PARAMETER_DEFINITIONS_START:] - ] - for index, selection in enumerate( - itertools.product(*parameter_definitions) - ): - # TODO change MODEL_ID_COLUMN and YAML_ID_COLUMN - # to just MODEL_ID and YAML_FILENAME? - ms_f.write( - "\t".join( - [ - columns[MODEL_ID_COLUMN] + f"_{index}", - columns[PETAB_YAML_COLUMN], - *selection, - ] - ) - + "\n" - ) - else: - ms_f.write(line) - # FIXME replace with some 'ModelSpaceManager' object - return expanded_models_file - - -def line2row( - line: str, - delimiter: str = "\t", - unpacked: bool = True, - convert_parameters_to_float: bool = True, -) -> list: - """Parse a line from a model space file. - - Args: - line: - A line from a file with delimiter-separated columns. - delimiter: - The string that separates columns in the file. - unpacked: - Whether the line format is in the unpacked format. If ``False``, - parameter values are not converted to ``float``. - convert_parameters_to_float: - Whether parameters should be converted to ``float``. - - Returns: - A list of column values. Parameter values are converted to ``float``. - """ - columns = line.strip().split(delimiter) - metadata = columns[:PARAMETER_DEFINITIONS_START] - if unpacked and convert_parameters_to_float: - parameters = [float(p) for p in columns[PARAMETER_DEFINITIONS_START:]] - else: - parameters = columns[PARAMETER_DEFINITIONS_START:] - return metadata + parameters - - class ModelSpace: """A model space, as a collection of model subspaces. @@ -296,24 +192,16 @@ def reset_exclusions( def get_model_space_df(df: TYPE_PATH | pd.DataFrame) -> pd.DataFrame: - # model_space_df = pd.read_csv(filename, sep='\t', index_col=MODEL_SUBSPACE_ID) # FIXME + """Get a model space dataframe. + + Args: + The model space. + + Returns: + The model space, appropriately formatted. + """ if isinstance(df, get_args(TYPE_PATH)): df = pd.read_csv(df, sep="\t") if df.index.name != MODEL_SUBSPACE_ID: df.set_index([MODEL_SUBSPACE_ID], inplace=True) return df - - -def write_model_space_df(df: pd.DataFrame, filename: TYPE_PATH) -> None: - df.to_csv(filename, sep="\t", index=True) - - -# def get_model_space( -# filename: TYPE_PATH, -# ) -> List[ModelSubspace]: -# model_space_df = get_model_space_df(filename) -# model_subspaces = [] -# for definition in model_space_df.iterrows(): -# model_subspaces.append(ModelSubspace.from_definition(definition)) -# model_space = ModelSpace(model_subspaces=model_subspaces) -# return model_space diff --git a/petab_select/models.py b/petab_select/models.py index a681157c..98e8cbb6 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -466,7 +466,7 @@ def to_yaml( Location of the YAML file. relative_paths: Whether to rewrite the paths in each model (e.g. the path to the - model's PEtab problem) relative to the `output_yaml` location. + model's PEtab problem) relative to the ``filename`` location. """ models = self._models if relative_paths: diff --git a/test/problem/__init__.py b/test/problem/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/problem/expected_output/model_space.tsv b/test/problem/expected_output/model_space.tsv new file mode 100644 index 00000000..32422e01 --- /dev/null +++ b/test/problem/expected_output/model_space.tsv @@ -0,0 +1,9 @@ +model_subspace_id model_subspace_petab_yaml k1 k2 k3 +M1_0 ../../../doc/examples/model_selection/petab_problem.yaml 0 0 0 +M1_1 ../../../doc/examples/model_selection/petab_problem.yaml 0.2 0.1 estimate +M1_2 ../../../doc/examples/model_selection/petab_problem.yaml 0.2 estimate 0 +M1_3 ../../../doc/examples/model_selection/petab_problem.yaml estimate 0.1 0 +M1_4 ../../../doc/examples/model_selection/petab_problem.yaml 0.2 estimate estimate +M1_5 ../../../doc/examples/model_selection/petab_problem.yaml estimate 0.1 estimate +M1_6 ../../../doc/examples/model_selection/petab_problem.yaml estimate estimate 0 +M1_7 ../../../doc/examples/model_selection/petab_problem.yaml estimate estimate estimate diff --git a/test/problem/expected_output/petab_select_problem.yaml b/test/problem/expected_output/petab_select_problem.yaml new file mode 100644 index 00000000..360def46 --- /dev/null +++ b/test/problem/expected_output/petab_select_problem.yaml @@ -0,0 +1,6 @@ +format_version: 1.0.0 +criterion: AIC +method: forward +model_space_files: +- model_space.tsv +candidate_space_arguments: {} diff --git a/test/problem/test_problem.py b/test/problem/test_problem.py new file mode 100644 index 00000000..1f769768 --- /dev/null +++ b/test/problem/test_problem.py @@ -0,0 +1,32 @@ +from pathlib import Path + +import petab_select + +problem_yaml = ( + Path(__file__).parents[2] + / "doc" + / "examples" + / "model_selection" + / "petab_select_problem.yaml" +) + + +def test_round_trip(): + """Test storing/loading of a full problem.""" + problem0 = petab_select.Problem.from_yaml(problem_yaml) + problem0.save("output") + + with open("expected_output/petab_select_problem.yaml") as f: + problem_yaml0 = f.read() + with open("expected_output/model_space.tsv") as f: + model_space_tsv0 = f.read() + + with open("output/petab_select_problem.yaml") as f: + problem_yaml1 = f.read() + with open("output/model_space.tsv") as f: + model_space_tsv1 = f.read() + + # The the exported problem YAML is as expected, with updated relative paths. + assert problem_yaml1 == problem_yaml0 + # The the exported model space TSV is as expected, with updated relative paths. + assert model_space_tsv1 == model_space_tsv0 From 786fb25d0ba456982895fbde9ee0223146600e38 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:30:08 +0100 Subject: [PATCH 64/88] remove unused constant, update doc example --- doc/examples/model_selection/model_space.tsv | 2 +- petab_select/constants.py | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/doc/examples/model_selection/model_space.tsv b/doc/examples/model_selection/model_space.tsv index bcd8cb22..e69a4f0e 100644 --- a/doc/examples/model_selection/model_space.tsv +++ b/doc/examples/model_selection/model_space.tsv @@ -1,4 +1,4 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_0 petab_problem.yaml 0 0 0 M1_1 petab_problem.yaml 0.2 0.1 estimate M1_2 petab_problem.yaml 0.2 estimate 0 diff --git a/petab_select/constants.py b/petab_select/constants.py index b98207f5..52c915d9 100644 --- a/petab_select/constants.py +++ b/petab_select/constants.py @@ -66,7 +66,6 @@ class Criterion(str, Enum): # Problem MODEL_SPACE_FILES = "model_space_files" PROBLEM = "problem" -PROBLEM_ID = "problem_id" VERSION = "version" # Candidate space @@ -167,10 +166,6 @@ class Method(str, Enum): # PEtab Select model report format. HASH = "hash" -# MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS = [MODEL_ID, PETAB_YAML] -MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS = [MODEL_SUBSPACE_ID, PETAB_YAML] - -# COMPARED_MODEL_ID = 'compared_'+MODEL_ID YAML_FILENAME = "yaml" # DISTANCES = { From 5a6f5b9965f6e0ce196d22745e1cfd43234057a4 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:31:07 +0100 Subject: [PATCH 65/88] update doc example --- doc/examples/model_selection/petab_select_problem.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/examples/model_selection/petab_select_problem.yaml b/doc/examples/model_selection/petab_select_problem.yaml index 235b2435..360def46 100644 --- a/doc/examples/model_selection/petab_select_problem.yaml +++ b/doc/examples/model_selection/petab_select_problem.yaml @@ -1,5 +1,6 @@ -version: beta_1 +format_version: 1.0.0 criterion: AIC method: forward model_space_files: - model_space.tsv +candidate_space_arguments: {} From 89f472145a3e04f83a75a38e47faf4b5d229d5d9 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:32:14 +0100 Subject: [PATCH 66/88] clean model.py --- petab_select/model.py | 46 ++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/petab_select/model.py b/petab_select/model.py index bbe8bb45..e128e108 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -11,6 +11,17 @@ import mkstd import petab.v1 as petab from petab.v1.C import NOMINAL_VALUE +from pydantic import ( + BaseModel, + Field, + PrivateAttr, + ValidationInfo, + ValidatorFunctionWrapHandler, + field_serializer, + field_validator, + model_serializer, + model_validator, +) from .constants import ( ESTIMATE, @@ -38,29 +49,14 @@ if TYPE_CHECKING: from .problem import Problem - -from pydantic import ( - BaseModel, - PrivateAttr, - ValidationInfo, - ValidatorFunctionWrapHandler, -) - __all__ = [ "Model", "default_compare", "ModelHash", "VIRTUAL_INITIAL_MODEL", + "ModelStandard", ] -from pydantic import ( - Field, - field_serializer, - field_validator, - model_serializer, - model_validator, -) - class ModelHash(BaseModel): """The model hash. @@ -328,9 +324,7 @@ def _fix_relative_paths( return data model = handler(data) - root_path = None - if ROOT_PATH in data: - root_path = data.pop(ROOT_PATH) + root_path = data.pop(ROOT_PATH, None) if root_path is None: return model @@ -682,17 +676,11 @@ def get_parameter_values( ] @staticmethod - def from_yaml( - filename: str | Path, - ) -> Model: - """Load a model from a YAML file. - - Args: - filename: - Location of the YAML file. - """ + def from_yaml(filename: str | Path) -> Model: + """Load a model from a YAML file.""" model = ModelStandard.load_data( - filename=filename, root_path=Path(filename).parent + filename=filename, + root_path=Path(filename).parent, ) return model From 0f78c9a64fad1555633c63620ad101fd584c5102 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:34:29 +0100 Subject: [PATCH 67/88] add `ModelSubspace.to_definition` --- petab_select/model_subspace.py | 52 +++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/petab_select/model_subspace.py b/petab_select/model_subspace.py index 1f62bd75..92a67903 100644 --- a/petab_select/model_subspace.py +++ b/petab_select/model_subspace.py @@ -2,6 +2,7 @@ import warnings from collections.abc import Iterable, Iterator from itertools import product +from os.path import relpath from pathlib import Path from typing import Any @@ -13,9 +14,9 @@ from .candidate_space import CandidateSpace from .constants import ( ESTIMATE, - MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS, + MODEL_SUBSPACE_ID, + MODEL_SUBSPACE_PETAB_YAML, PARAMETER_VALUE_DELIMITER, - PETAB_YAML, STEPWISE_METHODS, TYPE_PARAMETER_DICT, TYPE_PARAMETER_OPTIONS, @@ -715,38 +716,63 @@ def reset( @staticmethod def from_definition( - model_subspace_id: str, definition: dict[str, str] | pd.Series, - parent_path: TYPE_PATH = None, + root_path: TYPE_PATH = None, ) -> "ModelSubspace": """Create a :class:`ModelSubspace` from a definition. Args: - model_subspace_id: - The model subspace ID. definition: A description of the model subspace. Keys are properties of the - model subspace, including parameters that can take different values. - parent_path: - Any paths in the definition will be set relative to this path. + model subspace, including parameters that can take different + values. + root_path: + Any paths will be resolved relative to this path. Returns: The model subspace. """ + model_subspace_id = definition.pop(MODEL_SUBSPACE_ID) + petab_yaml = definition.pop(MODEL_SUBSPACE_PETAB_YAML) parameters = { column_id: decompress_parameter_values(value) for column_id, value in definition.items() - if column_id not in MODEL_SPACE_FILE_NON_PARAMETER_COLUMNS } - petab_yaml = definition[PETAB_YAML] - if parent_path is not None: - petab_yaml = Path(parent_path) / petab_yaml + if root_path is not None: + petab_yaml = Path(root_path) / petab_yaml return ModelSubspace( model_subspace_id=model_subspace_id, petab_yaml=petab_yaml, parameters=parameters, ) + def to_definition(self, root_path: TYPE_PATH | None = None) -> pd.Series: + """Get the definition of the model subspace. + + Args: + root_path: + If provided, the ``model_subspace_petab_yaml`` will be made + relative to this path. + + Returns: + The definition. + """ + petab_yaml = self.petab_yaml + if root_path: + petab_yaml = relpath(petab_yaml, start=root_path) + return pd.Series( + { + MODEL_SUBSPACE_ID: self.model_subspace_id, + MODEL_SUBSPACE_PETAB_YAML: petab_yaml, + **{ + parameter_id: PARAMETER_VALUE_DELIMITER.join( + str(v) for v in values + ) + for parameter_id, values in self.parameters.items() + }, + } + ) + def indices_to_model(self, indices: list[int]) -> Model | None: """Get a model from the subspace, by indices of possible parameter values. From d5e522d888c19796029afb7fab31f10acf222740 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:36:21 +0100 Subject: [PATCH 68/88] replace with --- petab_select/model_space.py | 112 +++++++++++++++++------------------- 1 file changed, 53 insertions(+), 59 deletions(-) diff --git a/petab_select/model_space.py b/petab_select/model_space.py index 9d9dd529..83633f74 100644 --- a/petab_select/model_space.py +++ b/petab_select/model_space.py @@ -1,10 +1,12 @@ """The `ModelSpace` class and related methods.""" +from __future__ import annotations + import logging import warnings from collections.abc import Iterable from pathlib import Path -from typing import Any, get_args +from typing import Any import numpy as np import pandas as pd @@ -19,7 +21,6 @@ __all__ = [ "ModelSpace", - "get_model_space_df", ] @@ -43,55 +44,71 @@ def __init__( } @staticmethod - def from_files( - filenames: list[TYPE_PATH], - ): - """Create a model space from model space files. + def load( + data: TYPE_PATH | pd.DataFrame | list[TYPE_PATH | pd.DataFrame], + root_path: TYPE_PATH = None, + ) -> ModelSpace: + """Load a model space from dataframe(s) or file(s). Args: - filenames: - The locations of the model space files. + data: + The data. TSV file(s) or pandas dataframe(s). + root_path: + Any paths in dataframe will be resolved relative to this path. + Paths in TSV files will be resolved relative to the directory + of the TSV file. Returns: - The corresponding model space. + The model space. """ - # TODO validate input? - model_space_dfs = [ - get_model_space_df(filename) for filename in filenames + if not isinstance(data, list): + data = [data] + dfs = [ + ( + root_path, + df.reset_index() if df.index.name == MODEL_SUBSPACE_ID else df, + ) + if isinstance(df, pd.DataFrame) + else (Path(df).parent, pd.read_csv(df, sep="\t")) + for df in data ] + model_subspaces = [] - for model_space_df, model_space_filename in zip( - model_space_dfs, filenames, strict=False - ): - for model_subspace_id, definition in model_space_df.iterrows(): + for root_path, df in dfs: + for _, definition in df.iterrows(): model_subspaces.append( ModelSubspace.from_definition( - model_subspace_id=model_subspace_id, definition=definition, - parent_path=Path(model_space_filename).parent, + root_path=root_path, ) ) model_space = ModelSpace(model_subspaces=model_subspaces) return model_space - @staticmethod - def from_df( - df: pd.DataFrame, - parent_path: TYPE_PATH = None, - ): - model_subspaces = [] - for model_subspace_id, definition in df.iterrows(): - model_subspaces.append( - ModelSubspace.from_definition( - model_subspace_id=model_subspace_id, - definition=definition, - parent_path=parent_path, - ) - ) - model_space = ModelSpace(model_subspaces=model_subspaces) - return model_space + def save(self, filename: TYPE_PATH | None = None) -> pd.DataFrame: + """Export the model space to a dataframe (and TSV). - # TODO: `to_df` / `to_file` + Args: + filename: + If provided, the dataframe will be saved here as a TSV. + Paths will be made relative to the parent directory of this + filename. + + Returns: + The dataframe. + """ + root_path = Path(filename).parent if filename else None + + data = [] + for model_subspace in self.model_subspaces.values(): + data.append(model_subspace.to_definition(root_path=root_path)) + df = pd.DataFrame(data) + df = df.set_index(MODEL_SUBSPACE_ID) + + if filename: + df.to_csv(filename, sep="\t") + + return df def search( self, @@ -99,7 +116,7 @@ def search( limit: int = np.inf, exclude: bool = True, ): - """...TODO + """Search all model subspaces according to a candidate space method. Args: candidate_space: @@ -145,13 +162,6 @@ def search_subspaces(only_one_subspace: bool = False): search_subspaces() - ## FIXME implement source_path.. somewhere - # if self.source_path is not None: - # for model in candidate_space.models: - # # TODO do this change elsewhere instead? - # # e.g. model subspace - # model.petab_yaml = self.source_path / model.petab_yaml - if exclude: self.exclude_models(candidate_space.models) @@ -189,19 +199,3 @@ def reset_exclusions( """Reset the exclusions in the model subspaces.""" for model_subspace in self.model_subspaces.values(): model_subspace.reset_exclusions(exclusions) - - -def get_model_space_df(df: TYPE_PATH | pd.DataFrame) -> pd.DataFrame: - """Get a model space dataframe. - - Args: - The model space. - - Returns: - The model space, appropriately formatted. - """ - if isinstance(df, get_args(TYPE_PATH)): - df = pd.read_csv(df, sep="\t") - if df.index.name != MODEL_SUBSPACE_ID: - df.set_index([MODEL_SUBSPACE_ID], inplace=True) - return df From 5f6aee600680e18dba8bb93952bff29624166122 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:38:29 +0100 Subject: [PATCH 69/88] `ProblemStandard` --- petab_select/problem.py | 265 ++++++++++++++++++++-------------------- 1 file changed, 130 insertions(+), 135 deletions(-) diff --git a/petab_select/problem.py b/petab_select/problem.py index 5260f9e2..e3669b05 100644 --- a/petab_select/problem.py +++ b/petab_select/problem.py @@ -1,23 +1,33 @@ """The model selection problem class.""" +from __future__ import annotations + +import copy import warnings from collections.abc import Callable, Iterable from functools import partial +from os.path import relpath from pathlib import Path -from typing import Any - -import yaml +from typing import Annotated, Any + +import mkstd +from pydantic import ( + BaseModel, + Field, + PlainSerializer, + PrivateAttr, + ValidationInfo, + ValidatorFunctionWrapHandler, + model_validator, +) from .analyze import get_best from .candidate_space import CandidateSpace, method_to_candidate_space_class from .constants import ( - CANDIDATE_SPACE_ARGUMENTS, CRITERION, - METHOD, - MODEL_SPACE_FILES, PREDECESSOR_MODEL, - PROBLEM_ID, - VERSION, + ROOT_PATH, + TYPE_PATH, Criterion, Method, ) @@ -27,18 +37,19 @@ __all__ = [ "Problem", + "ProblemStandard", ] -class Problem: +class Problem(BaseModel): """Handle everything related to the model selection problem. Attributes: model_space: The model space. calibrated_models: - Calibrated models. Will be used to augment the model selection problem (e.g. - by excluding them from the model space). + Calibrated models. Will be used to augment the model selection + problem (e.g. by excluding them from the model space). candidate_space_arguments: Arguments are forwarded to the candidate space constructor. compare: @@ -55,74 +66,121 @@ class Problem: paths that exist in e.g. the model space files. """ - """ - FIXME(dilpath) - Unsaved attributes: - candidate_space: - The candidate space that will be used. - Reason for not saving: - Essentially reproducible from :attr:`Problem.method` and - :attr:`Problem.calibrated_models`. - FIXME(dilpath) refactor calibrated_models out, move to e.g. candidate - space args - TODO should the relative paths be relative to the YAML or the file that contains them? - problem relative to file that contains them + format_version: str = Field(default="1.0.0") + criterion: Annotated[ + Criterion, PlainSerializer(lambda x: x.value, return_type=str) + ] + method: Annotated[ + Method, PlainSerializer(lambda x: x.value, return_type=str) + ] + model_space_files: list[Path] + candidate_space_arguments: dict[str, Any] = Field(default_factory=dict) + + _compare: Callable[[Model, Model], bool] = PrivateAttr(default=None) + + @model_validator(mode="wrap") + def _check_input( + data: dict[str, Any] | Problem, + handler: ValidatorFunctionWrapHandler, + info: ValidationInfo, + ) -> Problem: + if isinstance(data, Problem): + return data + + compare = data.pop("compare", None) or data.pop("_compare", None) + root_path = Path(data.pop(ROOT_PATH, "")) + + problem = handler(data) + + if compare is None: + compare = partial(default_compare, criterion=problem.criterion) + problem._compare = compare + + problem._model_space = ModelSpace.load( + [ + root_path / model_space_file + for model_space_file in problem.model_space_files + ] + ) - """ + return problem + + @staticmethod + def from_yaml(filename: TYPE_PATH) -> Problem: + """Load a problem from a YAML file.""" + problem = ProblemStandard.load_data( + filename=filename, + root_path=Path(filename).parent, + ) + return problem + + def to_yaml( + self, + filename: str | Path, + ) -> None: + """Save a problem to a YAML file. + + All paths will be made relative to the ``filename`` directory. - def __init__( + Args: + filename: + Location of the YAML file. + """ + root_path = Path(filename).parent + + problem = copy.deepcopy(self) + problem.model_space_files = [ + relpath( + model_space_file.resolve(), + start=root_path, + ) + for model_space_file in problem.model_space_files + ] + ProblemStandard.save_data(data=problem, filename=filename) + + def save( self, - model_space: ModelSpace, - candidate_space_arguments: dict[str, Any] = None, - compare: Callable[[Model, Model], bool] = None, - criterion: Criterion = None, - problem_id: str = None, - method: str = None, - version: str = None, - yaml_path: Path | str = None, - ): - self.model_space = model_space - self.criterion = criterion - self.problem_id = problem_id - self.method = method - self.version = version - self.yaml_path = Path(yaml_path) - - self.candidate_space_arguments = candidate_space_arguments - if self.candidate_space_arguments is None: - self.candidate_space_arguments = {} - - self.compare = compare - if self.compare is None: - self.compare = partial(default_compare, criterion=self.criterion) + directory: str | Path, + ) -> None: + """Save all data (problem and model space) to a ``directory``. + + Inside the directory, two files will be created: + (1) ``petab_select_problem.yaml``, and + (2) ``model_space.tsv``. + + All paths will be made relative to the ``directory``. + """ + directory = Path(directory) + directory.mkdir(exist_ok=True, parents=True) + + problem = copy.deepcopy(self) + problem.model_space_files = ["model_space.tsv"] + if PREDECESSOR_MODEL in problem.candidate_space_arguments: + problem.candidate_space_arguments[PREDECESSOR_MODEL] = relpath( + problem.candidate_space_arguments[PREDECESSOR_MODEL], + start=directory, + ) + ProblemStandard.save_data( + data=problem, filename=directory / "petab_select_problem.yaml" + ) + + problem.model_space.save(filename=directory / "model_space.tsv") + + @property + def compare(self): + return self._compare + + @property + def model_space(self): + return self._model_space def __str__(self): return ( - f"YAML: {self.yaml_path}\n" f"Method: {self.method}\n" f"Criterion: {self.criterion}\n" - f"Version: {self.version}\n" + f"Format version: {self.format_version}\n" ) - def get_path(self, relative_path: str | Path) -> Path: - """Get the path to a resource, from a relative path. - - Args: - relative_path: - The path to the resource, that is relative to the PEtab Select - problem YAML file location. - - Returns: - The path to the resource. - """ - """ - TODO: - Unused? - """ - if self.yaml_path is None: - return Path(relative_path) - return self.yaml_path.parent / relative_path - def exclude_models( self, models: Models, @@ -153,72 +211,6 @@ def exclude_model_hashes( ) self.exclude_models(models=Models(models=model_hashes, problem=self)) - @staticmethod - def from_yaml( - yaml_path: str | Path, - ) -> "Problem": - """Generate a problem from a PEtab Select problem YAML file. - - Args: - yaml_path: - The location of the PEtab Select problem YAML file. - - Returns: - A `Problem` instance. - """ - yaml_path = Path(yaml_path) - with open(yaml_path) as f: - problem_specification = yaml.safe_load(f) - - if not problem_specification.get(MODEL_SPACE_FILES, []): - raise KeyError( - "The model selection problem specification file is missing " - "model space files." - ) - - model_space = ModelSpace.from_files( - # problem_specification[MODEL_SPACE_FILES], - [ - # `pathlib.Path` appears to handle absolute `model_space_file` paths - # correctly, even if used as a relative path. - # TODO test - # This is similar to the `Problem.get_path` method. - yaml_path.parent / model_space_file - for model_space_file in problem_specification[ - MODEL_SPACE_FILES - ] - ], - # source_path=yaml_path.parent, - ) - - criterion = problem_specification.get(CRITERION, None) - if criterion is not None: - criterion = Criterion(criterion) - - problem_id = problem_specification.get(PROBLEM_ID, None) - - candidate_space_arguments = problem_specification.get( - CANDIDATE_SPACE_ARGUMENTS, - None, - ) - if candidate_space_arguments is not None: - if PREDECESSOR_MODEL in candidate_space_arguments: - candidate_space_arguments[PREDECESSOR_MODEL] = ( - yaml_path.parent - / candidate_space_arguments[PREDECESSOR_MODEL] - ) - - return Problem( - model_space=model_space, - candidate_space_arguments=candidate_space_arguments, - criterion=criterion, - # TODO refactor method to use enum - method=problem_specification.get(METHOD, None), - problem_id=problem_id, - version=problem_specification.get(VERSION, None), - yaml_path=yaml_path, - ) - def get_best( self, models: Models, @@ -311,3 +303,6 @@ def new_candidate_space( **candidate_space_kwargs, ) return candidate_space + + +ProblemStandard = mkstd.YamlStandard(model=Problem) From 3f990156082cdf6abdd877354538fd70f059f134 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:41:53 +0100 Subject: [PATCH 70/88] update docs --- doc/problem_definition.rst | 8 ++++++++ doc/standard/make_schemas.py | 2 ++ 2 files changed, 10 insertions(+) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index 814a64f9..d6516c0d 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -43,6 +43,14 @@ A YAML file with a description of the model selection problem. candidate_space_arguments: predecessor_model: predecessor_model.yaml +Schema +^^^^^^ + +The schema is provided as `YAML-formatted JSON schema <_static/problem.yaml>`_, which enables easy validation with various third-party tools. + +.. literalinclude:: standard/model.yaml + :language: yaml + 2. Model space -------------- diff --git a/doc/standard/make_schemas.py b/doc/standard/make_schemas.py index c01c62b8..d77c9730 100644 --- a/doc/standard/make_schemas.py +++ b/doc/standard/make_schemas.py @@ -1,5 +1,7 @@ from petab_select.model import ModelStandard from petab_select.models import ModelsStandard +from petab_select.problem import ProblemStandard ModelStandard.save_schema("model.yaml") ModelsStandard.save_schema("models.yaml") +ProblemStandard.save_schema("problem.yaml") From c9ae5450d43c9680a1c2be815ad17b618d95708b Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:47:34 +0100 Subject: [PATCH 71/88] update test fixture --- test/candidate_space/test_candidate_space.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/candidate_space/test_candidate_space.py b/test/candidate_space/test_candidate_space.py index 970a3e00..0cca4104 100644 --- a/test/candidate_space/test_candidate_space.py +++ b/test/candidate_space/test_candidate_space.py @@ -12,7 +12,7 @@ from petab_select.constants import ( ESTIMATE, ) -from petab_select.model_space import ModelSpace, get_model_space_df +from petab_select.model_space import ModelSpace @pytest.fixture @@ -98,6 +98,5 @@ def model_space(calibrated_model_space) -> pd.DataFrame: data["k4"].append(k4) data["k5"].append(k5) df = pd.DataFrame(data=data) - df = get_model_space_df(df) - model_space = ModelSpace.from_df(df) + model_space = ModelSpace.load(df) return model_space From 232cded49eae4b594bca6039b422bcbef63eee63 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:49:17 +0100 Subject: [PATCH 72/88] fix doc --- doc/problem_definition.rst | 2 +- doc/standard/problem.yaml | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 doc/standard/problem.yaml diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index d6516c0d..db6d4c94 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -48,7 +48,7 @@ Schema The schema is provided as `YAML-formatted JSON schema <_static/problem.yaml>`_, which enables easy validation with various third-party tools. -.. literalinclude:: standard/model.yaml +.. literalinclude:: standard/problem.yaml :language: yaml 2. Model space diff --git a/doc/standard/problem.yaml b/doc/standard/problem.yaml new file mode 100644 index 00000000..b5529863 --- /dev/null +++ b/doc/standard/problem.yaml @@ -0,0 +1,35 @@ +description: "Handle everything related to the model selection problem.\n\nAttributes:\n\ + \ model_space:\n The model space.\n calibrated_models:\n Calibrated\ + \ models. Will be used to augment the model selection\n problem (e.g. by\ + \ excluding them from the model space).\n candidate_space_arguments:\n \ + \ Arguments are forwarded to the candidate space constructor.\n compare:\n \ + \ A method that compares models by selection criterion. See\n :func:`petab_select.model.default_compare`\ + \ for an example.\n criterion:\n The criterion used to compare models.\n\ + \ method:\n The method used to search the model space.\n version:\n\ + \ The version of the PEtab Select format.\n yaml_path:\n The location\ + \ of the selection problem YAML file. Used for relative\n paths that exist\ + \ in e.g. the model space files." +properties: + format_version: + default: 1.0.0 + title: Format Version + type: string + criterion: + type: string + method: + type: string + model_space_files: + items: + format: path + type: string + title: Model Space Files + type: array + candidate_space_arguments: + title: Candidate Space Arguments + type: object +required: +- criterion +- method +- model_space_files +title: Problem +type: object From 907ddd34da51a7fa449c54266055ee3004c94896 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:07:03 +0100 Subject: [PATCH 73/88] update tests --- .../select/model_space_FAMoS_2019.tsv | 2 +- test/model_space/model_space_file_1.tsv | 2 +- test/model_space/model_space_file_2.tsv | 2 +- test/model_space/test_model_space.py | 2 +- test/model_subspace/test_model_subspace.py | 17 ++++++++--------- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/test/candidate_space/input/famos_synthetic/select/model_space_FAMoS_2019.tsv b/test/candidate_space/input/famos_synthetic/select/model_space_FAMoS_2019.tsv index 9d602c3f..1411532a 100644 --- a/test/candidate_space/input/famos_synthetic/select/model_space_FAMoS_2019.tsv +++ b/test/candidate_space/input/famos_synthetic/select/model_space_FAMoS_2019.tsv @@ -1,2 +1,2 @@ -model_subspace_id petab_yaml ro_A ro_B ro_C ro_D mu_AB mu_BA mu_AC mu_CA mu_AD mu_DA mu_BC mu_CB mu_BD mu_DB mu_CD mu_DC +model_subspace_id model_subspace_petab_yaml ro_A ro_B ro_C ro_D mu_AB mu_BA mu_AC mu_CA mu_AD mu_DA mu_BC mu_CB mu_BD mu_DB mu_CD mu_DC model_subspace_1 ../petab/FAMoS_2019_problem.yaml 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate 0;estimate diff --git a/test/model_space/model_space_file_1.tsv b/test/model_space/model_space_file_1.tsv index 8b6c9f1a..6e04853e 100644 --- a/test/model_space/model_space_file_1.tsv +++ b/test/model_space/model_space_file_1.tsv @@ -1,3 +1,3 @@ -model_subspace_id petab_yaml k1 k2 k3 k4 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 k4 model_subspace_1 ../../doc/examples/model_selection/petab_problem.yaml 0.2;estimate 0.1;estimate estimate 0;0.1;estimate model_subspace_2 ../../doc/examples/model_selection/petab_problem.yaml 0 0 0 estimate diff --git a/test/model_space/model_space_file_2.tsv b/test/model_space/model_space_file_2.tsv index 315fb50f..b02c3a8d 100644 --- a/test/model_space/model_space_file_2.tsv +++ b/test/model_space/model_space_file_2.tsv @@ -1,2 +1,2 @@ -model_subspace_id petab_yaml k1 k2 k3 k4 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 k4 model_subspace_3 ../../doc/examples/model_selection/petab_problem.yaml estimate estimate 0.3;estimate estimate diff --git a/test/model_space/test_model_space.py b/test/model_space/test_model_space.py index ace5560e..3250be9f 100644 --- a/test/model_space/test_model_space.py +++ b/test/model_space/test_model_space.py @@ -26,7 +26,7 @@ def model_space_files() -> list[Path]: @pytest.fixture def model_space(model_space_files) -> ModelSpace: - return ModelSpace.from_files(model_space_files) + return ModelSpace.load(model_space_files) def test_model_space_forward_virtual(model_space): diff --git a/test/model_subspace/test_model_subspace.py b/test/model_subspace/test_model_subspace.py index 5d3d6de9..cdbe94c7 100644 --- a/test/model_subspace/test_model_subspace.py +++ b/test/model_subspace/test_model_subspace.py @@ -13,8 +13,9 @@ ) from petab_select.constants import ( ESTIMATE, + MODEL_SUBSPACE_ID, + MODEL_SUBSPACE_PETAB_YAML, PARAMETER_VALUE_DELIMITER, - PETAB_YAML, Criterion, ) from petab_select.model import Model @@ -22,10 +23,10 @@ @pytest.fixture -def model_subspace_id_and_definition() -> pd.Series: - model_subspace_id = "model_subspace_1" +def model_subspace_definition() -> pd.Series: data = { - PETAB_YAML: Path(__file__).parent.parent.parent + MODEL_SUBSPACE_ID: "model_subspace_1", + MODEL_SUBSPACE_PETAB_YAML: Path(__file__).parent.parent.parent / "doc" / "examples" / "model_selection" @@ -35,15 +36,13 @@ def model_subspace_id_and_definition() -> pd.Series: "k3": ESTIMATE, "k4": PARAMETER_VALUE_DELIMITER.join(["0", "0.1", ESTIMATE]), } - return model_subspace_id, pd.Series(data=data, dtype=str) + return pd.Series(data=data, dtype=str) @pytest.fixture -def model_subspace(model_subspace_id_and_definition) -> ModelSubspace: - model_subspace_id, definition = model_subspace_id_and_definition +def model_subspace(model_subspace_definition) -> ModelSubspace: return petab_select.model_subspace.ModelSubspace.from_definition( - model_subspace_id=model_subspace_id, - definition=definition, + definition=model_subspace_definition, ) From beedfd19ae7c0b3e192505e369075bbdd8df1c7d Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:08:05 +0100 Subject: [PATCH 74/88] update test cases --- test_cases/0001/model_space.tsv | 2 +- test_cases/0002/model_space.tsv | 2 +- test_cases/0003/model_space.tsv | 2 +- test_cases/0004/model_space.tsv | 2 +- test_cases/0005/model_space.tsv | 2 +- test_cases/0006/model_space.tsv | 2 +- test_cases/0007/model_space.tsv | 2 +- test_cases/0008/model_space.tsv | 2 +- test_cases/0009/model_space.tsv | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test_cases/0001/model_space.tsv b/test_cases/0001/model_space.tsv index dff3e821..d7a994ec 100644 --- a/test_cases/0001/model_space.tsv +++ b/test_cases/0001/model_space.tsv @@ -1,2 +1,2 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_1 petab/petab_problem.yaml 0.2 0.1 0 diff --git a/test_cases/0002/model_space.tsv b/test_cases/0002/model_space.tsv index 31f0474d..fbcdbd83 100644 --- a/test_cases/0002/model_space.tsv +++ b/test_cases/0002/model_space.tsv @@ -1,4 +1,4 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_0 ../0001/petab/petab_problem.yaml 0 0 0 M1_1 ../0001/petab/petab_problem.yaml 0.2 0.1 estimate M1_2 ../0001/petab/petab_problem.yaml 0.2 estimate 0 diff --git a/test_cases/0003/model_space.tsv b/test_cases/0003/model_space.tsv index 39f8ae9a..bde9182f 100644 --- a/test_cases/0003/model_space.tsv +++ b/test_cases/0003/model_space.tsv @@ -1,2 +1,2 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1 ../0001/petab/petab_problem.yaml 0;0.2;estimate 0;0.1;estimate 0;estimate diff --git a/test_cases/0004/model_space.tsv b/test_cases/0004/model_space.tsv index 31f0474d..fbcdbd83 100644 --- a/test_cases/0004/model_space.tsv +++ b/test_cases/0004/model_space.tsv @@ -1,4 +1,4 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_0 ../0001/petab/petab_problem.yaml 0 0 0 M1_1 ../0001/petab/petab_problem.yaml 0.2 0.1 estimate M1_2 ../0001/petab/petab_problem.yaml 0.2 estimate 0 diff --git a/test_cases/0005/model_space.tsv b/test_cases/0005/model_space.tsv index 31f0474d..fbcdbd83 100644 --- a/test_cases/0005/model_space.tsv +++ b/test_cases/0005/model_space.tsv @@ -1,4 +1,4 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_0 ../0001/petab/petab_problem.yaml 0 0 0 M1_1 ../0001/petab/petab_problem.yaml 0.2 0.1 estimate M1_2 ../0001/petab/petab_problem.yaml 0.2 estimate 0 diff --git a/test_cases/0006/model_space.tsv b/test_cases/0006/model_space.tsv index 6a2deec2..5c2190f1 100644 --- a/test_cases/0006/model_space.tsv +++ b/test_cases/0006/model_space.tsv @@ -1,4 +1,4 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_0 ../0001/petab/petab_problem.yaml 0.2 0.1 0 M1_1 ../0001/petab/petab_problem.yaml 0.2 0.1 estimate M1_2 ../0001/petab/petab_problem.yaml 0.2 estimate 0 diff --git a/test_cases/0007/model_space.tsv b/test_cases/0007/model_space.tsv index 1c09d4b8..a066a8e4 100644 --- a/test_cases/0007/model_space.tsv +++ b/test_cases/0007/model_space.tsv @@ -1,4 +1,4 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_0 petab/petab_problem.yaml 0.2 0.1 0 M1_1 petab/petab_problem.yaml 0.2 0.1 estimate M1_2 petab/petab_problem.yaml 0.2 estimate 0 diff --git a/test_cases/0008/model_space.tsv b/test_cases/0008/model_space.tsv index 01e8de35..55888545 100644 --- a/test_cases/0008/model_space.tsv +++ b/test_cases/0008/model_space.tsv @@ -1,4 +1,4 @@ -model_subspace_id petab_yaml k1 k2 k3 +model_subspace_id model_subspace_petab_yaml k1 k2 k3 M1_0 ../0007/petab/petab_problem.yaml 0.2 0.1 0 M1_1 ../0007/petab/petab_problem.yaml 0.2 0.1 estimate M1_2 ../0007/petab/petab_problem.yaml 0.2 estimate 0 diff --git a/test_cases/0009/model_space.tsv b/test_cases/0009/model_space.tsv index a2cb8ac2..1dd28263 100644 --- a/test_cases/0009/model_space.tsv +++ b/test_cases/0009/model_space.tsv @@ -1,2 +1,2 @@ -model_subspace_id petab_yaml a_0ac_k05 a_0ac_k08 a_0ac_k12 a_0ac_k16 a_k05_k05k08 a_k05_k05k12 a_k05_k05k16 a_k08_k05k08 a_k08_k08k12 a_k08_k08k16 a_k12_k05k12 a_k12_k08k12 a_k12_k12k16 a_k16_k05k16 a_k16_k08k16 a_k16_k12k16 a_k05k08_k05k08k12 a_k05k08_k05k08k16 a_k05k12_k05k08k12 a_k05k12_k05k12k16 a_k05k16_k05k08k16 a_k05k16_k05k12k16 a_k08k12_k05k08k12 a_k08k12_k08k12k16 a_k08k16_k05k08k16 a_k08k16_k08k12k16 a_k12k16_k05k12k16 a_k12k16_k08k12k16 a_k05k08k12_4ac a_k05k08k16_4ac a_k05k12k16_4ac a_k08k12k16_4ac +model_subspace_id model_subspace_petab_yaml a_0ac_k05 a_0ac_k08 a_0ac_k12 a_0ac_k16 a_k05_k05k08 a_k05_k05k12 a_k05_k05k16 a_k08_k05k08 a_k08_k08k12 a_k08_k08k16 a_k12_k05k12 a_k12_k08k12 a_k12_k12k16 a_k16_k05k16 a_k16_k08k16 a_k16_k12k16 a_k05k08_k05k08k12 a_k05k08_k05k08k16 a_k05k12_k05k08k12 a_k05k12_k05k12k16 a_k05k16_k05k08k16 a_k05k16_k05k12k16 a_k08k12_k05k08k12 a_k08k12_k08k12k16 a_k08k16_k05k08k16 a_k08k16_k08k12k16 a_k12k16_k05k12k16 a_k12k16_k08k12k16 a_k05k08k12_4ac a_k05k08k16_4ac a_k05k12k16_4ac a_k08k12k16_4ac M petab/petab_problem.yaml 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate 1.0;estimate From c3cd1f53156fe681a5db4b89384ab1e4bbd8e2e9 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:09:42 +0100 Subject: [PATCH 75/88] update doccs --- doc/problem_definition.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index db6d4c94..1a220282 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -63,7 +63,7 @@ all parameters. :header-rows: 1 * - ``model_subspace_id`` - - ``petab_yaml`` + - ``model_subspace_petab_yaml`` - ``parameter_id_1`` - ... - ``parameter_id_n`` @@ -74,7 +74,7 @@ all parameters. - ... - ``model_subspace_id``: An ID for the model subspace. -- ``petab_yaml``: The PEtab YAML filename that serves as the basis of all +- ``model_subspace_petab_yaml``: The YAML filename of the PEtab problem that serves as the basis of all models in this subspace. - ``parameter_id_1`` ... ``parameter_id_n``: Specify the values that a parameter can take in the model subspace. For example, this could be: From ab1b84814289fc446863b3ceb94dac8dabc5be10 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:11:46 +0100 Subject: [PATCH 76/88] fix paths in test_problem.py --- test/problem/test_problem.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/problem/test_problem.py b/test/problem/test_problem.py index 1f769768..a2135e9c 100644 --- a/test/problem/test_problem.py +++ b/test/problem/test_problem.py @@ -16,14 +16,16 @@ def test_round_trip(): problem0 = petab_select.Problem.from_yaml(problem_yaml) problem0.save("output") - with open("expected_output/petab_select_problem.yaml") as f: + with open( + Path(__file__) / "expected_output/petab_select_problem.yaml" + ) as f: problem_yaml0 = f.read() - with open("expected_output/model_space.tsv") as f: + with open(Path(__file__) / "expected_output/model_space.tsv") as f: model_space_tsv0 = f.read() - with open("output/petab_select_problem.yaml") as f: + with open(Path(__file__) / "output/petab_select_problem.yaml") as f: problem_yaml1 = f.read() - with open("output/model_space.tsv") as f: + with open(Path(__file__) / "output/model_space.tsv") as f: model_space_tsv1 = f.read() # The the exported problem YAML is as expected, with updated relative paths. From 36c1ebfb6b7f8a66431c05d0a88f2a1333bebbf1 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:13:35 +0100 Subject: [PATCH 77/88] clarify docs --- doc/problem_definition.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/problem_definition.rst b/doc/problem_definition.rst index 1a220282..00c22435 100644 --- a/doc/problem_definition.rst +++ b/doc/problem_definition.rst @@ -7,8 +7,8 @@ Model selection problems for PEtab Select are defined by the following files: #. a specification of the model space, and #. (optionally) a specification of the initial candidate model. -The different file formats are described below. Each file format is a YAML file -and comes with a YAML-formatted JSON schema, such that these files can be +The different file formats are described below. The YAML file formats +come with a YAML-formatted JSON schema, such that these files can be easily worked with independently of the PEtab Select library. 1. Selection problem From c0d999575aa2e54b4a9d1655727480fdd83c381a Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:20:28 +0100 Subject: [PATCH 78/88] fix test_problem paths --- test/problem/test_problem.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/problem/test_problem.py b/test/problem/test_problem.py index a2135e9c..086ff6e4 100644 --- a/test/problem/test_problem.py +++ b/test/problem/test_problem.py @@ -2,8 +2,10 @@ import petab_select +test_path = Path(__file__).parent + problem_yaml = ( - Path(__file__).parents[2] + test_path.parent.parent / "doc" / "examples" / "model_selection" @@ -16,16 +18,14 @@ def test_round_trip(): problem0 = petab_select.Problem.from_yaml(problem_yaml) problem0.save("output") - with open( - Path(__file__) / "expected_output/petab_select_problem.yaml" - ) as f: + with open(test_path / "expected_output/petab_select_problem.yaml") as f: problem_yaml0 = f.read() - with open(Path(__file__) / "expected_output/model_space.tsv") as f: + with open(test_path / "expected_output/model_space.tsv") as f: model_space_tsv0 = f.read() - with open(Path(__file__) / "output/petab_select_problem.yaml") as f: + with open(test_path / "output/petab_select_problem.yaml") as f: problem_yaml1 = f.read() - with open(Path(__file__) / "output/model_space.tsv") as f: + with open(test_path / "output/model_space.tsv") as f: model_space_tsv1 = f.read() # The the exported problem YAML is as expected, with updated relative paths. From e7952198e83e658ea8fe8969fe7adf20bdcb682c Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:30:17 +0100 Subject: [PATCH 79/88] fix test_problem.py path --- test/problem/test_problem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/problem/test_problem.py b/test/problem/test_problem.py index 086ff6e4..f9f68811 100644 --- a/test/problem/test_problem.py +++ b/test/problem/test_problem.py @@ -16,7 +16,7 @@ def test_round_trip(): """Test storing/loading of a full problem.""" problem0 = petab_select.Problem.from_yaml(problem_yaml) - problem0.save("output") + problem0.save(test_path / "output") with open(test_path / "expected_output/petab_select_problem.yaml") as f: problem_yaml0 = f.read() @@ -28,7 +28,7 @@ def test_round_trip(): with open(test_path / "output/model_space.tsv") as f: model_space_tsv1 = f.read() - # The the exported problem YAML is as expected, with updated relative paths. + # The exported problem YAML is as expected, with updated relative paths. assert problem_yaml1 == problem_yaml0 - # The the exported model space TSV is as expected, with updated relative paths. + # The exported model space TSV is as expected, with updated relative paths. assert model_space_tsv1 == model_space_tsv0 From 0caef0ae08448a3dce288bd171e9d8d4ab40f8f7 Mon Sep 17 00:00:00 2001 From: dilpath <59329744+dilpath@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:44:25 +0100 Subject: [PATCH 80/88] handle predecessor model relative path on load --- petab_select/problem.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/petab_select/problem.py b/petab_select/problem.py index e3669b05..c8741322 100644 --- a/petab_select/problem.py +++ b/petab_select/problem.py @@ -103,6 +103,12 @@ def _check_input( ] ) + if PREDECESSOR_MODEL in problem.candidate_space_arguments: + problem.candidate_space_arguments[PREDECESSOR_MODEL] = ( + root_path + / problem.candidate_space_arguments[PREDECESSOR_MODEL] + ) + return problem @staticmethod From 10385e9d0638d969613ed7e91b8a236bf447a3f9 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:31:11 +0100 Subject: [PATCH 81/88] add more repro info to test case 0009 --- test/pypesto/test_pypesto.py | 9 +++++++-- test_cases/0009/README.md | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/test/pypesto/test_pypesto.py b/test/pypesto/test_pypesto.py index e670d8cc..e62af523 100644 --- a/test/pypesto/test_pypesto.py +++ b/test/pypesto/test_pypesto.py @@ -47,6 +47,12 @@ def objective_customizer(obj): obj.amici_solver.setRelativeTolerance(1e-12) +model_problem_options = { + "minimize_options": minimize_options, + "objective_customizer": objective_customizer, +} + + @pytest.mark.parametrize( "test_case_path_stem", sorted( @@ -72,8 +78,7 @@ def test_pypesto(test_case_path_stem): # Run the selection process until "exhausted". pypesto_select_problem.select_to_completion( - minimize_options=minimize_options, - objective_customizer=objective_customizer, + model_problem_options=model_problem_options, ) # Get the best model diff --git a/test_cases/0009/README.md b/test_cases/0009/README.md index 37243b6e..4597dc82 100644 --- a/test_cases/0009/README.md +++ b/test_cases/0009/README.md @@ -2,4 +2,4 @@ N.B. This original Blasi et al. problem is difficult to solve with a stepwise me 1. performing 100 FAMoS starts, initialized at random models. Usually <5% of the starts ended at the best model. 2. assessing reproducibility. Most of the starts that end at the best model are not reproducible. Instead, the path through model space can differ a lot despite "good" calibration, because many pairs of models differ in AICc by less than numerical noise. -1 start was found that reproducibly ends at the best model. The initial model of that start is the predecessor model in this test case. However, the path through model space is not reproducible -- there are at least two possibilities, perhaps more, depending on simulation tolerances. Hence, you should expect to produce a similar `expected_summary.tsv`, but perhaps with a few rows swapped. If you see a different summary.tsv, please report (or retry a few times). +1 start was found that reproducibly ends at the best model. The initial model of that start is the predecessor model in this test case. However, the path through model space is not reproducible -- there are at least two possibilities, perhaps more, depending on simulation tolerances. Hence, you should expect to produce a similar `expected_summary.tsv`, but perhaps with a few rows swapped. If you see a different summary.tsv, please report (or retry a few times). In particular, a different summary.tsv file will have a different sequence of values in the `current model criterion` column (accounting for numerical noise). From 24c0db22c1638f555ae3d375423bfb7d4ef13173 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:53:05 +0100 Subject: [PATCH 82/88] fix cli `start_iteration` --- petab_select/cli.py | 18 ++++++++++++------ petab_select/model.py | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/petab_select/cli.py b/petab_select/cli.py index d0def393..e5bbdbfc 100644 --- a/petab_select/cli.py +++ b/petab_select/cli.py @@ -12,7 +12,14 @@ from . import ui from .candidate_space import CandidateSpace -from .constants import CANDIDATE_SPACE, MODELS, PETAB_YAML, PROBLEM, TERMINATE +from .constants import ( + CANDIDATE_SPACE, + MODELS, + PETAB_YAML, + PROBLEM, + TERMINATE, + UNCALIBRATED_MODELS, +) from .model import ModelHash from .models import Models, models_to_yaml_list from .problem import Problem @@ -183,7 +190,7 @@ def start_iteration( ModelHash.from_hash(hash_str) for hash_str in excluded_model_hashes ] - ui.start_iteration( + result = ui.start_iteration( problem=problem, candidate_space=candidate_space, limit=limit, @@ -201,9 +208,8 @@ def start_iteration( ) # Save candidate models - models_to_yaml_list( - models=candidate_space.models, - output_yaml=uncalibrated_models_yaml, + result[UNCALIBRATED_MODELS].to_yaml( + filename=uncalibrated_models_yaml, relative_paths=relative_paths, ) @@ -495,7 +501,7 @@ def get_best( models=models, criterion=criterion, ) - best_model.to_yaml(output, paths_relative_to=paths_relative_to) + best_model.to_yaml(output) cli.add_command(start_iteration) diff --git a/petab_select/model.py b/petab_select/model.py index e128e108..9db7010c 100644 --- a/petab_select/model.py +++ b/petab_select/model.py @@ -5,11 +5,11 @@ import copy import warnings from os.path import relpath -from pathlib import Path from typing import TYPE_CHECKING, Any, ClassVar, Literal import mkstd import petab.v1 as petab +from mkstd import Path from petab.v1.C import NOMINAL_VALUE from pydantic import ( BaseModel, From 3b6f682099242a10acb5e82d2ed017d87be52534 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:53:40 +0100 Subject: [PATCH 83/88] bump mkstd req --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7043546f..65e8a770 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ "pyyaml>=6.0.2", "click>=8.1.7", "dill>=0.3.9", - "mkstd>=0.0.7", + "mkstd>=0.0.8", ] [project.optional-dependencies] plot = [ From dae060021d78a2b6e20f9bc0a50e6ac6c1db324b Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:54:21 +0100 Subject: [PATCH 84/88] fix `Models.to_yaml` --- petab_select/models.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/petab_select/models.py b/petab_select/models.py index 98e8cbb6..74c38285 100644 --- a/petab_select/models.py +++ b/petab_select/models.py @@ -468,13 +468,13 @@ def to_yaml( Whether to rewrite the paths in each model (e.g. the path to the model's PEtab problem) relative to the ``filename`` location. """ - models = self._models + _models = self._models if relative_paths: root_path = Path(filename).parent - models = copy.deepcopy(models) - for model in models: - model.set_relative_paths(root_path=root_path) - ModelsStandard.save_data(data=models, filename=filename) + _models = copy.deepcopy(_models) + for _model in _models: + _model.set_relative_paths(root_path=root_path) + ModelsStandard.save_data(data=Models(_models), filename=filename) def get_criterion( self, @@ -600,7 +600,7 @@ def models_from_yaml_list( stacklevel=2, ) return Models.from_yaml( - models_yaml=model_list_yaml, + filename=model_list_yaml, petab_problem=petab_problem, problem=problem, ) @@ -618,7 +618,7 @@ def models_to_yaml_list( stacklevel=2, ) Models(models=models).to_yaml( - output_yaml=output_yaml, relative_paths=relative_paths + filename=output_yaml, relative_paths=relative_paths ) From c384102f516b37da92323075df19d60805f7e3d7 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:02:48 +0100 Subject: [PATCH 85/88] change pypesto test tolerance; add test for pypesto+cli --- test/pypesto/test_pypesto.py | 113 ++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/test/pypesto/test_pypesto.py b/test/pypesto/test_pypesto.py index e62af523..7d7bf372 100644 --- a/test/pypesto/test_pypesto.py +++ b/test/pypesto/test_pypesto.py @@ -1,4 +1,7 @@ import os +import shlex +import shutil +import subprocess from pathlib import Path import numpy as np @@ -7,12 +10,14 @@ import pypesto.optimize import pypesto.select import pytest +import yaml import petab_select from petab_select import Model from petab_select.constants import ( CRITERIA, ESTIMATED_PARAMETERS, + TERMINATE, ) os.environ["AMICI_EXPERIMENTAL_SBML_NONCONST_CLS"] = "1" @@ -60,6 +65,7 @@ def objective_customizer(obj): ), ) def test_pypesto(test_case_path_stem): + """Run all test cases with pyPESTO.""" if test_cases and test_case_path_stem not in test_cases: pytest.skip("Test excluded from subset selected for debugging.") @@ -100,5 +106,110 @@ def get_series(model, dict_attribute) -> pd.Series: pd.testing.assert_series_equal( get_series(expected_model, dict_attribute), get_series(best_model, dict_attribute), - atol=1e-2, + rtol=1e-2, ) + # FIXME ensure `current model criterion` trajectory also matches, in summary.tsv file, + # for test case 0009, after summary format is revised + + +@pytest.mark.skipif( + os.getenv("CI"), + reason="Too CPU heavy for CI.", +) +def test_famos_cli(): + """Run test case 0009 with pyPESTO and the CLI interface.""" + test_case_path = test_cases_path / "0009" + expected_model_yaml = test_case_path / "expected.yaml" + problem_yaml = test_case_path / "petab_select_problem.yaml" + + problem = petab_select.Problem.from_yaml(problem_yaml) + + # Setup working directory for intermediate files + work_dir = Path(__file__).parent / "output_famos_cli" + work_dir_str = str(work_dir) + if work_dir.exists(): + shutil.rmtree(work_dir_str) + work_dir.mkdir(exist_ok=True, parents=True) + + models_yamls = [] + metadata_yaml = work_dir / "metadata.yaml" + state_dill = work_dir / "state.dill" + iteration = 0 + while True: + iteration += 1 + uncalibrated_models_yaml = ( + work_dir / f"uncalibrated_models_{iteration}.yaml" + ) + calibrated_models_yaml = ( + work_dir / f"calibrated_models_{iteration}.yaml" + ) + models_yaml = work_dir / f"models_{iteration}.yaml" + models_yamls.append(models_yaml) + # Start iteration + subprocess.run( # noqa: S603 + shlex.split( + f"""petab_select start_iteration + --problem {problem_yaml} + --state {state_dill} + --output-uncalibrated-models {uncalibrated_models_yaml} + """ + ) + ) + # Calibrate models + models = petab_select.Models.from_yaml(uncalibrated_models_yaml) + for model in models: + pypesto.select.ModelProblem( + model=model, + criterion=problem.criterion, + **model_problem_options, + ) + models.to_yaml(filename=calibrated_models_yaml) + # End iteration + subprocess.run( # noqa: S603 + shlex.split( + f"""petab_select end_iteration + --output-models {models_yaml} + --output-metadata {metadata_yaml} + --state {state_dill} + --calibrated-models {calibrated_models_yaml} + """ + ) + ) + with open(metadata_yaml) as f: + metadata = yaml.safe_load(f) + if metadata[TERMINATE]: + break + + # Get the best model + models_yamls_arg = " ".join( + f"--models {models_yaml}" for models_yaml in models_yamls + ) + subprocess.run( # noqa: S603 + shlex.split( + f"""petab_select get_best + --problem {problem_yaml} + {models_yamls_arg} + --output {work_dir / "best_model.yaml"} + """ + ) + ) + best_model = petab_select.Model.from_yaml(work_dir / "best_model.yaml") + + # Load the expected model. + expected_model = Model.from_yaml(expected_model_yaml) + + def get_series(model, dict_attribute) -> pd.Series: + return pd.Series( + getattr(model, dict_attribute), + dtype=np.float64, + ).sort_index() + + # The estimated parameters and criteria values are as expected. + for dict_attribute in [CRITERIA, ESTIMATED_PARAMETERS]: + pd.testing.assert_series_equal( + get_series(expected_model, dict_attribute), + get_series(best_model, dict_attribute), + rtol=1e-2, + ) + # FIXME ensure `current model criterion` trajectory also matches, in summary.tsv file, + # after summary format is revised From e32437f829a9c53dc546fe8c38ea16eb1f6e638f Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:20:52 +0100 Subject: [PATCH 86/88] retry skipping in CI --- test/pypesto/test_pypesto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pypesto/test_pypesto.py b/test/pypesto/test_pypesto.py index 7d7bf372..c508d5ca 100644 --- a/test/pypesto/test_pypesto.py +++ b/test/pypesto/test_pypesto.py @@ -113,7 +113,7 @@ def get_series(model, dict_attribute) -> pd.Series: @pytest.mark.skipif( - os.getenv("CI"), + os.getenv("GITHUB_ACTIONS"), reason="Too CPU heavy for CI.", ) def test_famos_cli(): From fa47dbeec6e7381858a8a8d704e4df44bacf8b9b Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:35:33 +0100 Subject: [PATCH 87/88] fix warnings; fix CI skip condition --- test/pypesto/test_pypesto.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/pypesto/test_pypesto.py b/test/pypesto/test_pypesto.py index c508d5ca..efaf10a4 100644 --- a/test/pypesto/test_pypesto.py +++ b/test/pypesto/test_pypesto.py @@ -88,8 +88,10 @@ def test_pypesto(test_case_path_stem): ) # Get the best model - best_model = petab_select_problem.get_best( + best_model = petab_select.analyze.get_best( models=pypesto_select_problem.calibrated_models, + criterion=petab_select_problem.criterion, + compare=petab_select_problem.compare, ) # Load the expected model. @@ -113,7 +115,7 @@ def get_series(model, dict_attribute) -> pd.Series: @pytest.mark.skipif( - os.getenv("GITHUB_ACTIONS"), + os.getenv("GITHUB_ACTIONS") == "true", reason="Too CPU heavy for CI.", ) def test_famos_cli(): From e0278bd0ce506e27280407f4703d5ba7ab74ace1 Mon Sep 17 00:00:00 2001 From: Dilan Pathirana <59329744+dilpath@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:02:03 +0100 Subject: [PATCH 88/88] Update test_cases/0009/README.md Co-authored-by: Daniel Weindl --- test_cases/0009/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_cases/0009/README.md b/test_cases/0009/README.md index 4597dc82..207ece74 100644 --- a/test_cases/0009/README.md +++ b/test_cases/0009/README.md @@ -2,4 +2,4 @@ N.B. This original Blasi et al. problem is difficult to solve with a stepwise me 1. performing 100 FAMoS starts, initialized at random models. Usually <5% of the starts ended at the best model. 2. assessing reproducibility. Most of the starts that end at the best model are not reproducible. Instead, the path through model space can differ a lot despite "good" calibration, because many pairs of models differ in AICc by less than numerical noise. -1 start was found that reproducibly ends at the best model. The initial model of that start is the predecessor model in this test case. However, the path through model space is not reproducible -- there are at least two possibilities, perhaps more, depending on simulation tolerances. Hence, you should expect to produce a similar `expected_summary.tsv`, but perhaps with a few rows swapped. If you see a different summary.tsv, please report (or retry a few times). In particular, a different summary.tsv file will have a different sequence of values in the `current model criterion` column (accounting for numerical noise). +1 start was found that reproducibly ends at the best model. The initial model of that start is the predecessor model in this test case. However, the path through model space is not reproducible -- there are at least two possibilities, perhaps more, depending on simulation tolerances. Hence, you should expect to produce a similar `expected_summary.tsv`, but perhaps with a few rows swapped. If you see a different `summary.tsv`, please report (or retry a few times). In particular, a different `summary.tsv` file will have a different sequence of values in the `current model criterion` column (accounting for numerical noise).