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
3 changes: 0 additions & 3 deletions epde/operators/common/coeff_calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ def apply(self, objective : Equation, arguments : dict = None):
if weight_idx in nonzero_features_indexes:
weights[weight_idx] = valueable_weights[nonzero_features_indexes.index(weight_idx)]
weights[-1] = valueable_weights[-1]
# nonzero_terms_mask = np.array([False if np.isclose(weight, 0) else True for weight in weights])
# weights = np.array([item if keep else 0 for item, keep in zip(weights, nonzero_terms_mask)])
# objective.weights_internal = np.array([item if keep else 0 for item, keep in zip(objective.weights_internal, nonzero_terms_mask[:-1])])
objective.weights_final_evald = True
objective.weights_final = weights

Expand Down
219 changes: 100 additions & 119 deletions epde/operators/common/fitness.py

Large diffs are not rendered by default.

18 changes: 6 additions & 12 deletions epde/operators/common/right_part_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ def apply(self, objective : Equation, arguments : dict):
if not (objective.structure[target_idx].contains_variable(objective.main_var_to_explain) and objective.structure[target_idx].contains_deriv(objective.main_var_to_explain)):
continue
objective.target_idx = target_idx
fitness = self.suboperators['fitness_calculation'].apply(objective,
arguments = subop_args['fitness_calculation'],
force_out_of_place = True)
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
Expand All @@ -72,14 +70,10 @@ def apply(self, objective : Equation, arguments : dict):

objective.weights_internal = weights_internal
objective.target_idx = min_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.')
self.simplify_equation(objective)
if objective.structure[objective.target_idx].contains_variable(objective.main_var_to_explain) and objective.structure[objective.target_idx].contains_deriv(objective.main_var_to_explain):
objective.is_correct_right_part = True
else:
objective.reset_explaining_term(objective.target_idx)
objective.right_part_selected = True

def simplify_equation(self, objective: Equation):
Expand All @@ -88,18 +82,18 @@ def simplify_equation(self, objective: Equation):
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]

equation_terms = objective.described_variables
# 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()
if len(equation_terms) > 1:
common_factor = list(frozenset.intersection(*equation_terms))
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 factor.cache_label[0] == common_factor[0][0]:
if len(factor.params) > 1:
common_dim.append(factor.params[-1])
if factor.cache_label[1][0] < min_order:
Expand All @@ -110,7 +104,7 @@ def simplify_equation(self, objective: Equation):
temp = deepcopy(term)
factors_simplified = []
for factor in term.structure:
if factor.cache_label[0] == common_factor[0]:
if factor.cache_label[0] == common_factor[0][0]:
for i, value in enumerate(factor.params_description):
if factor.params_description[i]["name"] == "power":
factor.params[i] -= min_order
Expand Down
15 changes: 9 additions & 6 deletions epde/operators/common/sparsity.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from typing import Union, Callable
import numpy as np
from sklearn.linear_model import Lasso
from sklearn.linear_model import Lasso, LassoLars
from pysindy import STLSQ

import epde.globals as global_var
from epde.operators.utils.template import CompoundOperator
Expand Down Expand Up @@ -60,15 +61,17 @@ def apply(self, objective : Equation, arguments : dict):
# print(f'Metaparameter: {objective.metaparameters}, objective.metaparameters[("sparsity", objective.main_var_to_explain)]')
self_args, subop_args = self.parse_suboperator_args(arguments = arguments)

estimator = Lasso(alpha = objective.metaparameters[('sparsity', objective.main_var_to_explain)]['value'],
copy_X=True, fit_intercept=True, max_iter=1000,
positive=False, precompute=False, random_state=None,
selection='random', tol=0.0001, warm_start=False)
# estimator = Lasso(alpha = objective.metaparameters[('sparsity', objective.main_var_to_explain)]['value'],
# copy_X=True, fit_intercept=True, max_iter=1000,
# positive=False, precompute=False, random_state=None,
# selection='random', tol=0.0001, warm_start=False)
estimator = STLSQ(threshold=objective.metaparameters[('sparsity', objective.main_var_to_explain)]['value'],
copy_X=True, unbias=True, max_iter=1000, alpha=0.05)
_, target, features = objective.evaluate(normalize = True, return_val = False)
self.g_fun_vals = global_var.grid_cache.g_func.reshape(-1)

estimator.fit(features, target, sample_weight = self.g_fun_vals)
objective.weights_internal = estimator.coef_
objective.weights_internal = estimator.coef_[-1]

def use_default_tags(self):
self._tags = {'sparsity', 'gene level', 'no suboperators', 'inplace'}
Expand Down
43 changes: 23 additions & 20 deletions epde/operators/multiobjective/moeadd_specific.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,7 @@ def apply(self, objective : Tuple[Union[SoEq, ParetoLevels]], arguments : dict):
most_crowded_domain = crowded_domains[np.argmax(PBIS)]

if len(last_level_by_domains[most_crowded_domain]) == 1:
worst_solution = locate_pareto_worst(objective[1], self_args['weights'],
self_args['best_obj'], self.params['PBI_penalty'])
worst_solution = last_level_by_domains[most_crowded_domain][0]
else:
PBIS = np.fromiter(map(lambda solution: penalty_based_intersection(solution,
self_args['weights'][most_crowded_domain],
Expand Down Expand Up @@ -367,31 +366,34 @@ def apply(self, objective: ParetoLevels, arguments: dict):

while objective.unplaced_candidates:
offspring = objective.unplaced_candidates.pop()
attempt = 1
attempt_limit = self.params['attempt_limit']
attempt = 0
mutation_attempt_limit = self.params['mutation_attempt_limit']
offspring_attempt_limit = self.params['offspring_attempt_limit']
temp_offspring = deepcopy(offspring)
replaced = 0
while True:
temp_offspring = self.suboperators['chromosome_mutation'].apply(objective=temp_offspring,
arguments=subop_args['chromosome_mutation'])
self.suboperators['right_part_selector'].apply(objective=temp_offspring,
arguments=subop_args['right_part_selector'])
self.suboperators['chromosome_fitness'].apply(objective=temp_offspring,
arguments=subop_args['chromosome_fitness'])

if tuple(temp_offspring.obj_fun) not in objective.history:
temp_offspring.reset_state()
system = temp_offspring.described_variables
if system not in objective.history:
self.suboperators['chromosome_fitness'].apply(objective=temp_offspring,
arguments=subop_args['chromosome_fitness'])
self.suboperators['pareto_level_updater'].apply(objective=(temp_offspring, objective),
arguments=subop_args['pareto_level_updater'])
objective.history.add(tuple(temp_offspring.obj_fun))
# print(tuple(temp_offspring.obj_fun))
objective.history.add(system)
print(temp_offspring.obj_fun)
break
elif replaced == attempt_limit:
elif replaced == offspring_attempt_limit:
print("Could not generate unique offspring")
break
elif attempt == attempt_limit:
elif attempt == mutation_attempt_limit:
temp_offspring = deepcopy(offspring)
replaced += 1
attempt = 0
temp_offspring = self.suboperators['chromosome_mutation'].apply(objective=temp_offspring,
arguments=subop_args[
'chromosome_mutation'])
attempt += 1
return objective

Expand Down Expand Up @@ -437,15 +439,16 @@ def apply(self, objective : ParetoLevels, arguments : dict):
for idx, candidate in enumerate(objective.unplaced_candidates):
self.suboperators['right_part_selector'].apply(objective = candidate,
arguments = subop_args['right_part_selector'])
self.suboperators['chromosome_fitness'].apply(objective = objective.unplaced_candidates[idx],
arguments = subop_args['chromosome_fitness'])
while tuple(candidate.obj_fun) in objective.history:
system = candidate.described_variables
while system in objective.history:
candidate.create()
self.suboperators['right_part_selector'].apply(objective=candidate,
arguments=subop_args['right_part_selector'])
self.suboperators['chromosome_fitness'].apply(objective=objective.unplaced_candidates[idx],
arguments=subop_args['chromosome_fitness'])
objective.history.add(tuple(candidate.obj_fun))
system = candidate.described_variables
self.suboperators['chromosome_fitness'].apply(objective=candidate,
arguments=subop_args['chromosome_fitness'])
objective.history.add(system)
print(candidate.obj_fun)
objective.initial_placing()

# TODO: consider carefully, where normalizer init shall be held. If here, only the initial values are employed
Expand Down
20 changes: 10 additions & 10 deletions epde/operators/multiobjective/mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ class EquationMutation(CompoundOperator):
def apply(self, objective : Equation, arguments : dict):
self_args, subop_args = self.parse_suboperator_args(arguments = arguments)

for term_idx in range(objective.n_immutable, len(objective.structure)):
if np.random.uniform(0, 1) <= self.params['r_mutation']:
objective.structure[term_idx] = self.suboperators['mutation'].apply(objective = (term_idx, objective),
arguments = subop_args['mutation'])
# term_idx = np.random.choice(len(objective.structure))
# objective.structure[term_idx] = self.suboperators['mutation'].apply(objective=(term_idx, objective),
# arguments=subop_args['mutation'])
# for term_idx in range(objective.n_immutable, len(objective.structure)):
# if np.random.uniform(0, 1) <= self.params['r_mutation']:
# objective.structure[term_idx] = self.suboperators['mutation'].apply(objective = (term_idx, objective),
# arguments = subop_args['mutation'])
term_idx = np.random.choice(len(objective.structure))
objective.structure[term_idx] = self.suboperators['mutation'].apply(objective=(term_idx, objective),
arguments=subop_args['mutation'])
return objective

def use_default_tags(self):
Expand All @@ -76,11 +76,11 @@ class MetaparameterMutation(CompoundOperator):
def apply(self, objective : Union[int, float], arguments : dict):
self_args, subop_args = self.parse_suboperator_args(arguments = arguments)

altered_objective = np.random.normal(objective, scale = self.params['std'])
altered_objective = np.random.normal(objective, objective)
if altered_objective < 0:
altered_objective = - altered_objective
return altered_objective

return np.float64(altered_objective)

def use_default_tags(self):
self._tags = {'mutation', 'gene level', 'no suboperators'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"number_of_neighbors" : 4
},
"ParetoLevelUpdater" : {
"attempt_limit" : 5
"mutation_attempt_limit" : 5,
"offspring_attempt_limit" : 5
},
"InitialParetoLevelSorting" : {

Expand Down
16 changes: 4 additions & 12 deletions epde/optimizers/moeadd/moeadd.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,25 +175,17 @@ def delete_point(self, point):
None
"""
new_levels = []
deleted = False
population_cleared = []
point_system = point.described_variables
for level in self.levels:
temp = []
for element in level:
if not np.allclose(element.obj_fun, point.obj_fun) or deleted:
if element.described_variables != point_system:
temp.append(element)
else:
deleted = True
population_cleared.append(element)
if not len(temp) == 0:
new_levels.append(temp)

population_cleared = []
deleted = False
for elem in self.population:
if not np.allclose(elem.obj_fun, point.obj_fun) or deleted:
population_cleared.append(elem)
else:
deleted = True

if len(population_cleared) != sum([len(level) for level in new_levels]):
print(len(population_cleared), len(self.population), sum([len(level) for level in new_levels]))
print('initial population', [solution.vals for solution in self.population], len([solution.vals for solution in self.population]), '\n')
Expand Down
38 changes: 29 additions & 9 deletions epde/structure/main_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,9 @@ def evaluate(self, structural, grids=None):
self.prev_normalized = normalize
value = super().evaluate(structural)
if normalize:
value = value / np.linalg.norm(value, 2)
value = (value - np.mean(value)) / np.std(value)
# value = value / np.linalg.norm(value, 2)

if np.all([len(factor.params) == 1 for factor in self.structure]) and grids is None:
# Место возможных проблем: сохранение/загрузка нормализованных данных
self.saved[normalize] = global_var.tensor_cache.add(self.cache_label, value, normalized=normalize)
Expand Down Expand Up @@ -580,7 +582,7 @@ def shifted_idx(idx):
def reset_state(self, reset_right_part: bool = True):
if reset_right_part:
self.right_part_selected = False
self.weights_internal_evald = False
# self.weights_internal_evald = False
self.weights_final_evald = False
self.fitness_calculated = False
self.stability_calculated = False
Expand Down Expand Up @@ -744,17 +746,28 @@ def state(self):

@property
def described_variables(self):
eps = 1e-7
described = set()
for term_idx, term in enumerate(self.structure):
cache_label = set()
if term_idx == self.target_idx:
described.update({factor.family_type for factor in term.structure
if factor.is_deriv and factor.deriv_code != [None]})
for factor in term.structure:
if len(factor.params) == 1:
factor_label = (factor.cache_label[0])
else:
factor_label = (factor.cache_label[0], (factor.cache_label[1][-1]))
cache_label.add(factor_label)
else:
weight_idx = term_idx if term_idx < term_idx else term_idx - 1
if np.abs(self.weights_final[weight_idx]) > eps:
described.update({factor.family_type for factor in term.structure
if factor.is_deriv and factor.deriv_code != [None]})
weight_idx = term_idx if term_idx < self.target_idx else term_idx - 1
if not np.isclose(self.weights_internal[weight_idx], 0):
for factor in term.structure:
if len(factor.params) == 1:
factor_label = (factor.cache_label[0])
else:
factor_label = (factor.cache_label[0], (factor.cache_label[1][-1]))
cache_label.add(factor_label)
if len(cache_label) > 0:
cache_label = frozenset(cache_label)
described.add(cache_label)
described = frozenset(described)
return described

Expand Down Expand Up @@ -1110,6 +1123,13 @@ def __iter__(self):
def fitness_calculated(self):
return all([equation.fitness_calculated for equation in self.vals])

@property
def described_variables(self):
equations_caches = set()
for equation in self.vals:
equations_caches.add(equation.described_variables)
return frozenset(equations_caches)


class SoEqIterator(object):
def __init__(self, system: SoEq):
Expand Down
Loading