Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions epde/operators/common/right_part_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,41 +45,93 @@ class EqRightPartSelector(CompoundOperator):
@HistoryExtender('\n -> The equation structure was detected: ', 'a')
def apply(self, objective : Equation, arguments : dict):
self_args, subop_args = self.parse_suboperator_args(arguments = arguments)

if not objective.right_part_selected:

objective.reset_state(True)

while not (objective.right_part_selected and objective.simplified):
min_fitness = np.inf
weights_internal = np.zeros_like(objective.structure)
min_idx = 0
if not objective.contains_deriv(objective.main_var_to_explain):
objective.restore_property(deriv = True)
if not objective.contains_variable(objective.main_var_to_explain):
objective.restore_property(mandatory_family = objective.main_var_to_explain)



for target_idx, target_term in enumerate(objective.structure):
if not objective.structure[target_idx].contains_deriv(objective.main_var_to_explain):
continue
objective.target_idx = target_idx
# self.suboperators['sparsity'].apply(objective, subop_args['sparsity'])
# self.suboperators['coeff_calc'].apply(objective, subop_args['coeff_calc'])
fitness = self.suboperators['fitness_calculation'].apply(objective,
arguments = subop_args['fitness_calculation'],
force_out_of_place = True)
if fitness < min_fitness:
min_fitness = fitness
min_idx = target_idx
weights_internal = objective.weights_internal
else:
pass

objective.weights_internal = weights_internal
objective.target_idx = min_idx
objective.reset_explaining_term(objective.target_idx)
# self.suboperators['fitness_calculation'].apply(objective, arguments = subop_args['fitness_calculation'])
# if not np.isclose(objective.fitness_value, max_fitness) and global_var.verbose.show_warnings:
# warnings.warn('Reevaluation of fitness function for equation has obtained different result. Not an error, if ANN DE solver is used.')
objective.right_part_selected = True
self.simplify_equation(objective)
else:
objective.reset_explaining_term(objective.target_idx)

def simplify_equation(self, objective: Equation):
# Get nonzero terms
nonzero_terms_mask = np.array([False if weight == 0 else True for weight in objective.weights_internal], dtype=np.integer)
nonrs_terms = [term for i, term in enumerate(objective.structure) if i != objective.target_idx]
nonzero_terms = [item for item, keep in zip(nonrs_terms, nonzero_terms_mask) if keep]
nonzero_terms.append(objective.structure[objective.target_idx])
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]

# If amount nonzero terms is more than one -- get their intersection
if len(nonzero_terms) > 1:
common_factor = np.array(list(set.intersection(*map(set, nonzero_terms_labels)))).flatten()
common_dim = []
if len(common_factor) > 0:
# Find if this intersection in the same dimension (i.e. trigonometry functions) + it's minimal order
min_order = np.inf
for term in nonzero_terms:
for factor in term.structure:
if factor.cache_label[0] == common_factor[0]:
if len(factor.params) > 1:
common_dim.append(factor.params[-1])
if factor.cache_label[1][0] < min_order:
min_order = factor.cache_label[1][0]
if len(set(common_dim)) < 2:
# If dimension is the same -- reduce order of terms' factor
for term in nonzero_terms:
temp = deepcopy(term)
factors_simplified = []
for factor in term.structure:
if factor.cache_label[0] == common_factor[0]:
for i, value in enumerate(factor.params_description):
if factor.params_description[i]["name"] == "power":
factor.params[i] -= min_order
if factor.params[i] == 0:
factors_simplified.append(factor)
term.structure = [factor for factor in term.structure if factor not in factors_simplified]
term.reset_saved_state()
# If term's order became zero -- replace term
if len(term.structure) == 0:
term.randomize()
term.reset_saved_state()
while objective.structure.count(term) > 1 or term == temp:
term.randomize()
term.reset_saved_state()
objective.simplified = False
objective.right_part_selected = False
return
objective.simplified = True
objective.right_part_selected = True

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


class RandomRHPSelector(CompoundOperator):
'''
Expand Down
4 changes: 3 additions & 1 deletion epde/structure/main_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def __deepcopy__(self, memo=None):
class Equation(ComplexStructure):
__slots__ = ['_history', 'structure', 'interelement_operator', 'n_immutable', 'pool',
# '_target', '_features', 'saved', 'saved_as','max_factors_in_term', 'operator',
'target_idx', 'right_part_selected', '_weights_final', 'weights_final_evald',
'target_idx', 'right_part_selected', '_weights_final', 'weights_final_evald', 'simplified',
'_weights_internal', 'weights_internal_evald', 'fitness_calculated', 'stability_calculated', 'aic_calculated', 'solver_form_defined',
'_fitness_value', '_coefficients_stability', '_aic', 'metaparameters', 'main_var_to_explain'] # , '_solver_form'

Expand Down Expand Up @@ -596,6 +596,7 @@ def reset_state(self, reset_right_part: bool = True):
self.fitness_calculated = False
self.stability_calculated = False
self.aic_calculated = False
self.simplified = False
self.solver_form_defined = False

@HistoryExtender('\n -> was copied by deepcopy(self)', 'n')
Expand Down Expand Up @@ -629,6 +630,7 @@ def copy_properties_to(self, new_equation):
new_equation.fitness_calculated = self.fitness_calculated
new_equation.stability_calculated = self.stability_calculated
new_equation.aic_calculated = self.aic_calculated
new_equation.simplified = self.simplified
new_equation.solver_form_defined = False

try:
Expand Down