diff --git a/golem/serializers/coders/opt_history_serialization.py b/golem/serializers/coders/opt_history_serialization.py index a4390fd9..8e12db2c 100644 --- a/golem/serializers/coders/opt_history_serialization.py +++ b/golem/serializers/coders/opt_history_serialization.py @@ -111,9 +111,11 @@ def opt_history_from_json(cls: Type[OptHistory], json_obj: Dict[str, Any]) -> Op # to `Individual` instances. _deserialize_generations_list(history.generations, uid_to_individual_map) _deserialize_generations_list(history.archive_history, uid_to_individual_map) - # Process older histories to wrap generations into the new class. - if isinstance(history.generations[0], list): - history.generations = [Generation(gen, gen_num) for gen_num, gen in enumerate(history.generations)] + # Process histories with zero generations. + if len(history.generations) > 0: + # Process older histories to wrap generations into the new class. + if isinstance(history.generations[0], list): + history.generations = [Generation(gen, gen_num) for gen_num, gen in enumerate(history.generations)] # Deserialize parents for all generations. _deserialize_parent_individuals(list(chain(*history.generations)), uid_to_individual_map) # The attribute is used only for serialization. diff --git a/test/data/zero_gen_history.json b/test/data/zero_gen_history.json new file mode 100644 index 00000000..40d5cbe3 --- /dev/null +++ b/test/data/zero_gen_history.json @@ -0,0 +1,88 @@ +{ + "_default_save_dir": "C:\\Users\\valery\\AppData\\Local\\Temp\\FEDOT", + "_generations": [], + "_objective": { + "is_multi_objective": false, + "metric_names": [ + "rmse", + "node_number" + ], + "_class_path": "golem.core.optimisers.objective.objective/ObjectiveInfo" + }, + "_tuning_result": { + "operator": { + "_nodes": [ + { + "_nodes_from": [ + "817632c2-de2b-46b5-adea-6f28ed2f2771", + "08035438-c42d-43e3-865a-dbc818f2e23f" + ], + "content": { + "name": "ridge", + "params": {}, + "metadata": { + "metric": null, + "_class_path": "fedot.core.pipelines.node/NodeMetadata" + } + }, + "uid": "a1d02589-f648-4adf-aa56-f0751b6aae37", + "_class_path": "golem.core.dag.linked_graph_node/LinkedGraphNode" + }, + { + "_nodes_from": [], + "content": { + "name": "glm", + "params": { + "family": "gaussian", + "link": "identity" + }, + "metadata": { + "metric": null, + "_class_path": "fedot.core.pipelines.node/NodeMetadata" + } + }, + "uid": "817632c2-de2b-46b5-adea-6f28ed2f2771", + "_class_path": "golem.core.dag.linked_graph_node/LinkedGraphNode" + }, + { + "_nodes_from": [ + "1b96e295-cc71-4913-bf83-31db6424f930" + ], + "content": { + "name": "ridge", + "params": {}, + "metadata": { + "metric": null, + "_class_path": "fedot.core.pipelines.node/NodeMetadata" + } + }, + "uid": "08035438-c42d-43e3-865a-dbc818f2e23f", + "_class_path": "golem.core.dag.linked_graph_node/LinkedGraphNode" + }, + { + "_nodes_from": [], + "content": { + "name": "lagged", + "params": { + "window_size": 10 + }, + "metadata": { + "metric": null, + "_class_path": "fedot.core.pipelines.node/NodeMetadata" + } + }, + "uid": "1b96e295-cc71-4913-bf83-31db6424f930", + "_class_path": "golem.core.dag.linked_graph_node/LinkedGraphNode" + } + ], + "_postprocess_nodes": { + "_class_path": "golem.core.dag.linked_graph/LinkedGraph._empty_postprocess" + }, + "_class_path": "golem.core.dag.linked_graph/LinkedGraph" + }, + "_class_path": "golem.core.dag.graph_delegate/GraphDelegate" + }, + "archive_history": [], + "individuals_pool": [], + "_class_path": "golem.core.optimisers.opt_history_objects.opt_history/OptHistory" +} \ No newline at end of file diff --git a/test/unit/optimizers/test_composing_history.py b/test/unit/optimizers/test_composing_history.py index 15724776..76977ad1 100644 --- a/test/unit/optimizers/test_composing_history.py +++ b/test/unit/optimizers/test_composing_history.py @@ -20,6 +20,7 @@ from golem.core.optimisers.opt_history_objects.parent_operator import ParentOperator from golem.core.optimisers.optimization_parameters import GraphRequirements from golem.core.optimisers.optimizer import GraphGenerationParams +from golem.core.paths import project_root from golem.visualisation.opt_viz import PlotTypesEnum, OptHistoryVisualizer from golem.visualisation.opt_viz_extra import OptHistoryExtraVisualizer from test.unit.mocks.common_mocks import MockAdapter, MockDomainStructure, MockNode, MockObjectiveEvaluate @@ -318,6 +319,16 @@ def test_collect_intermediate_metric(): assert_intermediate_metrics(restored_graph) +def test_load_zero_generations_history(): + """ Test to load histories with zero generations, since it still can contain info about + objective, tuning result, etc. """ + path_to_history = os.path.join(project_root(), 'test', 'data', 'zero_gen_history.json') + history = OptHistory.load(path_to_history) + assert isinstance(history, OptHistory) + assert len(history.archive_history) == 0 + assert history.objective is not None + + def assert_intermediate_metrics(graph: MockDomainStructure): seen_metrics = [] for node in graph.nodes: