diff --git a/fedot/api/api_utils/api_params_repository.py b/fedot/api/api_utils/api_params_repository.py index dfc79930f9..964c8c1b86 100644 --- a/fedot/api/api_utils/api_params_repository.py +++ b/fedot/api/api_utils/api_params_repository.py @@ -5,7 +5,8 @@ from golem.core.optimisers.genetic.operators.inheritance import GeneticSchemeTypesEnum from golem.core.optimisers.genetic.operators.mutation import MutationTypesEnum -from fedot.core.composer.gp_composer.specific_operators import parameter_change_mutation, boosting_mutation +from fedot.core.composer.gp_composer.specific_operators import parameter_change_mutation, boosting_mutation, \ + add_resample_mutation from fedot.core.constants import AUTO_PRESET_NAME from fedot.core.repository.tasks import TaskTypesEnum from fedot.core.utils import default_fedot_data_dir @@ -135,5 +136,7 @@ def _get_default_mutations(task_type: TaskTypesEnum, params) -> Sequence[Mutatio # TODO remove workaround after boosting mutation fix if task_type == TaskTypesEnum.ts_forecasting: mutations.append(partial(boosting_mutation, params=params)) + else: + mutations.append(add_resample_mutation) return mutations diff --git a/fedot/core/composer/gp_composer/specific_operators.py b/fedot/core/composer/gp_composer/specific_operators.py index 439bd89fad..2e53c8ae50 100644 --- a/fedot/core/composer/gp_composer/specific_operators.py +++ b/fedot/core/composer/gp_composer/specific_operators.py @@ -90,6 +90,17 @@ def boosting_mutation(pipeline: Pipeline, requirements, graph_gen_params, **kwar return pipeline +def add_resample_mutation(pipeline: Pipeline, **kwargs): + resample_node = PipelineNode('resample') + + p_nodes = [p_node for p_node in pipeline.primary_nodes] + pipeline.add_node(resample_node) + + for node in p_nodes: + pipeline.connect_nodes(resample_node, node) + return pipeline + + def choose_new_model(boosting_model_candidates: List[str]) -> str: """ Since 'linear' and 'dtreg' operations are suitable for solving the problem and they are simpler than others, they are preferred """ diff --git a/fedot/core/pipelines/pipeline.py b/fedot/core/pipelines/pipeline.py index 49c31b0ef7..b6910779d5 100644 --- a/fedot/core/pipelines/pipeline.py +++ b/fedot/core/pipelines/pipeline.py @@ -1,7 +1,7 @@ from copy import deepcopy from datetime import timedelta from os import PathLike -from typing import Optional, Tuple, Union, Sequence +from typing import Optional, Tuple, Union, Sequence, List import func_timeout from golem.core.dag.graph import Graph @@ -327,6 +327,19 @@ def root_node(self) -> Optional[PipelineNode]: raise ValueError(f'{ERROR_PREFIX} More than 1 root_nodes in pipeline') return root[0] + @property + def primary_nodes(self) -> List[PipelineNode]: + """Finds pipelines sink-node + + Returns: + the final predictor-node + """ + if not self.nodes: + return [] + primary_nodes = [node for node in self.nodes + if not node.nodes_from] + return primary_nodes + def pipeline_for_side_task(self, task_type: TaskTypesEnum) -> 'Pipeline': """Returns pipeline formed from the last node solving the given problem and all its parents diff --git a/fedot/core/pipelines/verification_rules.py b/fedot/core/pipelines/verification_rules.py index 214b02ec2f..2125c7e8d3 100644 --- a/fedot/core/pipelines/verification_rules.py +++ b/fedot/core/pipelines/verification_rules.py @@ -166,12 +166,14 @@ def has_correct_location_of_resample(pipeline: Pipeline): is_resample_primary = True else: is_not_resample_primary = True - if node.name == 'resample': - raise ValueError( - f'{ERROR_PREFIX} Pipeline can have only one resample operation located in start of the pipeline') + else: + if node.name == 'resample': + raise ValueError( + f'{ERROR_PREFIX} Pipeline can have only one resample operation located in start of the pipeline') if is_resample_primary and is_not_resample_primary: raise ValueError( f'{ERROR_PREFIX} Pipeline can have only one resample operation located in start of the pipeline') + return True def get_wrong_links(ts_to_table_operations: list, ts_data_operations: list, non_ts_data_operations: list,