Skip to content

Commit e59d45e

Browse files
authored
Merge pull request #36 from Gromwud/main
Common factors removal added
2 parents 3c2bd58 + 43c252f commit e59d45e

2 files changed

Lines changed: 63 additions & 9 deletions

File tree

epde/operators/common/right_part_selection.py

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,41 +45,93 @@ class EqRightPartSelector(CompoundOperator):
4545
@HistoryExtender('\n -> The equation structure was detected: ', 'a')
4646
def apply(self, objective : Equation, arguments : dict):
4747
self_args, subop_args = self.parse_suboperator_args(arguments = arguments)
48-
49-
if not objective.right_part_selected:
48+
49+
objective.reset_state(True)
50+
51+
while not (objective.right_part_selected and objective.simplified):
5052
min_fitness = np.inf
53+
weights_internal = np.zeros_like(objective.structure)
5154
min_idx = 0
5255
if not objective.contains_deriv(objective.main_var_to_explain):
5356
objective.restore_property(deriv = True)
5457
if not objective.contains_variable(objective.main_var_to_explain):
5558
objective.restore_property(mandatory_family = objective.main_var_to_explain)
5659

57-
58-
5960
for target_idx, target_term in enumerate(objective.structure):
6061
if not objective.structure[target_idx].contains_deriv(objective.main_var_to_explain):
6162
continue
6263
objective.target_idx = target_idx
63-
# self.suboperators['sparsity'].apply(objective, subop_args['sparsity'])
64-
# self.suboperators['coeff_calc'].apply(objective, subop_args['coeff_calc'])
6564
fitness = self.suboperators['fitness_calculation'].apply(objective,
6665
arguments = subop_args['fitness_calculation'],
6766
force_out_of_place = True)
6867
if fitness < min_fitness:
6968
min_fitness = fitness
7069
min_idx = target_idx
70+
weights_internal = objective.weights_internal
7171
else:
7272
pass
7373

74+
objective.weights_internal = weights_internal
7475
objective.target_idx = min_idx
75-
objective.reset_explaining_term(objective.target_idx)
7676
# self.suboperators['fitness_calculation'].apply(objective, arguments = subop_args['fitness_calculation'])
7777
# if not np.isclose(objective.fitness_value, max_fitness) and global_var.verbose.show_warnings:
7878
# warnings.warn('Reevaluation of fitness function for equation has obtained different result. Not an error, if ANN DE solver is used.')
79-
objective.right_part_selected = True
79+
self.simplify_equation(objective)
80+
else:
81+
objective.reset_explaining_term(objective.target_idx)
82+
83+
def simplify_equation(self, objective: Equation):
84+
# Get nonzero terms
85+
nonzero_terms_mask = np.array([False if weight == 0 else True for weight in objective.weights_internal], dtype=np.integer)
86+
nonrs_terms = [term for i, term in enumerate(objective.structure) if i != objective.target_idx]
87+
nonzero_terms = [item for item, keep in zip(nonrs_terms, nonzero_terms_mask) if keep]
88+
nonzero_terms.append(objective.structure[objective.target_idx])
89+
nonzero_terms_labels = [[term.cache_label[0]] if not isinstance(term.cache_label[0], tuple) else list(next(zip(*term.cache_label))) for term in nonzero_terms]
90+
91+
# If amount nonzero terms is more than one -- get their intersection
92+
if len(nonzero_terms) > 1:
93+
common_factor = np.array(list(set.intersection(*map(set, nonzero_terms_labels)))).flatten()
94+
common_dim = []
95+
if len(common_factor) > 0:
96+
# Find if this intersection in the same dimension (i.e. trigonometry functions) + it's minimal order
97+
min_order = np.inf
98+
for term in nonzero_terms:
99+
for factor in term.structure:
100+
if factor.cache_label[0] == common_factor[0]:
101+
if len(factor.params) > 1:
102+
common_dim.append(factor.params[-1])
103+
if factor.cache_label[1][0] < min_order:
104+
min_order = factor.cache_label[1][0]
105+
if len(set(common_dim)) < 2:
106+
# If dimension is the same -- reduce order of terms' factor
107+
for term in nonzero_terms:
108+
temp = deepcopy(term)
109+
factors_simplified = []
110+
for factor in term.structure:
111+
if factor.cache_label[0] == common_factor[0]:
112+
for i, value in enumerate(factor.params_description):
113+
if factor.params_description[i]["name"] == "power":
114+
factor.params[i] -= min_order
115+
if factor.params[i] == 0:
116+
factors_simplified.append(factor)
117+
term.structure = [factor for factor in term.structure if factor not in factors_simplified]
118+
term.reset_saved_state()
119+
# If term's order became zero -- replace term
120+
if len(term.structure) == 0:
121+
term.randomize()
122+
term.reset_saved_state()
123+
while objective.structure.count(term) > 1 or term == temp:
124+
term.randomize()
125+
term.reset_saved_state()
126+
objective.simplified = False
127+
objective.right_part_selected = False
128+
return
129+
objective.simplified = True
130+
objective.right_part_selected = True
80131

81132
def use_default_tags(self):
82133
self._tags = {'equation right part selection', 'gene level', 'contains suboperators', 'inplace'}
134+
83135

84136
class RandomRHPSelector(CompoundOperator):
85137
'''

epde/structure/main_structures.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ def __deepcopy__(self, memo=None):
357357
class Equation(ComplexStructure):
358358
__slots__ = ['_history', 'structure', 'interelement_operator', 'n_immutable', 'pool',
359359
# '_target', '_features', 'saved', 'saved_as','max_factors_in_term', 'operator',
360-
'target_idx', 'right_part_selected', '_weights_final', 'weights_final_evald',
360+
'target_idx', 'right_part_selected', '_weights_final', 'weights_final_evald', 'simplified',
361361
'_weights_internal', 'weights_internal_evald', 'fitness_calculated', 'stability_calculated', 'aic_calculated', 'solver_form_defined',
362362
'_fitness_value', '_coefficients_stability', '_aic', 'metaparameters', 'main_var_to_explain'] # , '_solver_form'
363363

@@ -596,6 +596,7 @@ def reset_state(self, reset_right_part: bool = True):
596596
self.fitness_calculated = False
597597
self.stability_calculated = False
598598
self.aic_calculated = False
599+
self.simplified = False
599600
self.solver_form_defined = False
600601

601602
@HistoryExtender('\n -> was copied by deepcopy(self)', 'n')
@@ -629,6 +630,7 @@ def copy_properties_to(self, new_equation):
629630
new_equation.fitness_calculated = self.fitness_calculated
630631
new_equation.stability_calculated = self.stability_calculated
631632
new_equation.aic_calculated = self.aic_calculated
633+
new_equation.simplified = self.simplified
632634
new_equation.solver_form_defined = False
633635

634636
try:

0 commit comments

Comments
 (0)