Skip to content

Commit 8c49582

Browse files
authored
Merge pull request #61 from Gromwud/main
New logic
2 parents 317b368 + 7e33c8e commit 8c49582

25 files changed

Lines changed: 461 additions & 528 deletions

File tree

epde/eq_mo_objectives.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ def equation_fitness(system, equation_key = None):
3535
res = system.vals[equation_key].fitness_calculated
3636
else:
3737
for equation in system.vals:
38-
assert equation.fitness_value
39-
# res = np.mean([equation.fitness_value for equation in system.vals])
38+
assert equation.fitness_calculated
39+
# res = np.sum([equation.fitness_value for equation in system.vals])
4040
res = tuple([equation.fitness_value for equation in system.vals])
4141
return res
4242

@@ -110,7 +110,7 @@ def equation_terms_stability(system, equation_key = None):
110110
else:
111111
for equation in system.vals:
112112
assert equation.stability_calculated
113-
# res = np.mean([equation.coefficients_stability for equation in system.vals])
113+
# res = np.sum([equation.coefficients_stability for equation in system.vals])
114114
res = tuple([equation.coefficients_stability for equation in system.vals])
115115
return res
116116

epde/operators/common/coeff_calculation.py

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -45,47 +45,53 @@ def apply(self, objective : Equation, arguments : dict = None):
4545
# self_args, subop_args = self.parse_suboperator_args(arguments = arguments)
4646

4747
assert objective.weights_internal_evald, 'Trying to calculate final weights before evaluating intermeidate ones (no sparsity).'
48-
target = objective.structure[objective.target_idx]
49-
50-
target_vals = target.evaluate(False)
51-
features_vals = []
52-
nonzero_features_indexes = []
53-
for i in range(len(objective.structure)):
54-
if i == objective.target_idx:
55-
continue
56-
idx = i if i < objective.target_idx else i-1
57-
if objective.weights_internal[idx] != 0:
58-
features_vals.append(objective.structure[i].evaluate(False))
59-
nonzero_features_indexes.append(idx)
60-
61-
if len(features_vals) == 0:
62-
objective.weights_final = np.zeros(len(objective.structure))
63-
else:
64-
features = features_vals[0]
65-
if len(features_vals) > 1:
66-
for i in range(1, len(features_vals)):
67-
features = np.vstack([features, features_vals[i]])
68-
features = np.vstack([features, np.ones(features_vals[0].shape)]) # Добавляем константную фичу
69-
features = np.transpose(features)
70-
estimator = LinearRegression(copy_X=True, fit_intercept=False, n_jobs=-1,
71-
positive=False, tol=0.0001)
72-
# estimator = LinearRegression(fit_intercept=False)
73-
if features.ndim == 1:
74-
features = features.reshape(-1, 1)
75-
try:
76-
self.g_fun_vals = global_var.grid_cache.g_func[global_var.grid_cache.g_func != 0]
77-
except AttributeError:
78-
self.g_fun_vals = None
79-
estimator.fit(features, target_vals, sample_weight = self.g_fun_vals)
80-
81-
valueable_weights = estimator.coef_
82-
weights = np.zeros(len(objective.structure))
83-
for weight_idx in range(len(weights)-1):
84-
if weight_idx in nonzero_features_indexes:
85-
weights[weight_idx] = valueable_weights[nonzero_features_indexes.index(weight_idx)]
86-
weights[-1] = valueable_weights[-1]
87-
objective.weights_final = weights
88-
objective.weights_final_evald = True
48+
# target = objective.structure[objective.target_idx]
49+
#
50+
# target_vals = target.evaluate(False)
51+
# features_vals = []
52+
# nonzero_features_indexes = []
53+
# for i in range(len(objective.structure)):
54+
# if i == objective.target_idx:
55+
# continue
56+
# idx = i if i < objective.target_idx else i-1
57+
# if objective.weights_internal[idx] != 0:
58+
# features_vals.append(objective.structure[i].evaluate(False))
59+
# nonzero_features_indexes.append(idx)
60+
#
61+
# if len(features_vals) == 0:
62+
# objective.weights_final = np.zeros(len(objective.structure))
63+
# else:
64+
# features = features_vals[0]
65+
# if len(features_vals) > 1:
66+
# for i in range(1, len(features_vals)):
67+
# features = np.vstack([features, features_vals[i]])
68+
# features = np.vstack([features, np.ones(features_vals[0].shape)]) # Добавляем константную фичу
69+
# features = np.transpose(features)
70+
# estimator = LinearRegression(copy_X=True, fit_intercept=False, n_jobs=-1,
71+
# positive=False, tol=0.0001)
72+
# # estimator = LinearRegression(fit_intercept=False)
73+
# if features.ndim == 1:
74+
# features = features.reshape(-1, 1)
75+
# try:
76+
# self.g_fun_vals = global_var.grid_cache.g_func[global_var.grid_cache.g_func != 0]
77+
# except AttributeError:
78+
# self.g_fun_vals = None
79+
# estimator.fit(features, target_vals, sample_weight = self.g_fun_vals)
80+
#
81+
# valuable_weights = estimator.coef_
82+
# weights = np.zeros(len(objective.structure))
83+
# for weight_idx in range(len(weights)-1):
84+
# if weight_idx in nonzero_features_indexes:
85+
# weights[weight_idx] = valuable_weights[nonzero_features_indexes.index(weight_idx)]
86+
# weights[-1] = valuable_weights[-1]
87+
# objective.weights_final = weights
88+
# _, target, features = objective.evaluate(normalize=False, return_val=False)
89+
# self.g_fun_vals = global_var.grid_cache.g_func[global_var.grid_cache.g_func != 0]
90+
# estimator = LinearRegression(copy_X=True, fit_intercept=True, n_jobs=-1, positive=False, tol=0.0001)
91+
# estimator.fit(features, target, sample_weight=self.g_fun_vals)
92+
# valuable_weights = estimator.coef_
93+
# objective.weights_final = np.append(valuable_weights, estimator.intercept_)
94+
# objective.weights_final_evald = True
8995

9096
def use_default_tags(self):
9197
self._tags = {'coefficient calculation', 'gene level', 'no suboperators', 'inplace'}

epde/operators/common/fitness.py

Lines changed: 23 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from sklearn.linear_model import LinearRegression, Ridge
2121
from scipy.optimize import minimize
2222
from epde.supplementary import minmax_normalize
23+
from epde.supplementary import calculate_weights
2324

2425
LOSS_NAN_VAL = 1e7
2526

@@ -119,17 +120,22 @@ def apply(self, objective: Equation, arguments: dict, force_out_of_place: bool =
119120
# self.suboperators['sparsity'].apply(objective, subop_args['sparsity'])
120121
if force_out_of_place:
121122
self.suboperators['sparsity'].apply(objective, subop_args['sparsity'])
123+
if all(objective.weights_internal == 0):
124+
return None
122125
self.suboperators['coeff_calc'].apply(objective, subop_args['coeff_calc'])
123126

124-
_, target, features = objective.evaluate(normalize=False, return_val=False)
127+
if force_out_of_place:
128+
_, target, features = objective.evaluate(normalize=False, return_val=False)
129+
else:
130+
_, target, features = objective.evaluate(normalize=True, return_val=False)
131+
# _, target, features = objective.evaluate(normalize=False, return_val=False)
125132

126133
self.get_g_fun_vals()
127-
data_shape = global_var.grid_cache.inner_shape
128134

129135
if features is None:
130136
discr = target - target.mean()
131137
else:
132-
discr_feats = np.dot(features, objective.weights_final[:-1][objective.weights_internal != 0])
138+
discr_feats = np.dot(features, objective.weights_final[:-1])
133139
discr_feats = discr_feats + objective.weights_final[-1]
134140
discr = target - discr_feats
135141

@@ -146,46 +152,24 @@ def apply(self, objective: Equation, arguments: dict, force_out_of_place: bool =
146152
objective.aic = None
147153
objective.aic_calculated = True
148154

149-
# Calculate r-loss
150-
target_vals = target.reshape(*data_shape)
151-
slices = [slice(None) for _ in range(target_vals.ndim)]
152-
features_vals = features.reshape(*data_shape, -1)
153-
sample_weights_vals = self.g_fun_vals.reshape(*data_shape)
154-
155-
lr = 0
156-
for dim in range(target_vals.ndim):
157-
horizons_default = 30
158-
window_size = target_vals.shape[dim] // 2
159-
num_horizons = window_size + 1
160-
if num_horizons < horizons_default:
161-
step_size = 1
162-
else:
163-
step_size = num_horizons // horizons_default
164-
eq_window_weights = []
165-
166-
# Compute coefficients and collect statistics over horizons
167-
slices_window = slices.copy()
168-
for start_idx in range(0, num_horizons, step_size):
169-
end_idx = start_idx + window_size
170-
slices_window[dim] = slice(start_idx, end_idx)
171-
target_window = target_vals[*slices_window].reshape(-1)
172-
feature_window = features_vals[*slices_window, :].reshape(-1, features.shape[-1])
173-
sample_weights_window = sample_weights_vals[*slices_window].reshape(-1)
174-
estimator = LinearRegression(fit_intercept=True)
175-
estimator.fit(feature_window, target_window, sample_weight=sample_weights_window)
176-
valuable_weights = estimator.coef_
177-
eq_window_weights.append(valuable_weights)
178-
std = np.array(eq_window_weights).std(axis=0, ddof=1)
179-
mu = np.array(eq_window_weights).mean(axis=0)
180-
eq_cv = std ** 2 / (mu ** 2)
181-
lr += np.nan_to_num(eq_cv).sum()
182-
183-
lr = lr / (len(objective.structure) - 1) / target_vals.ndim
155+
data_shape = global_var.grid_cache.inner_shape
156+
weights = calculate_weights(features, target, self.g_fun_vals, data_shape)
157+
weights_arr = np.array(weights)
158+
std = weights_arr.std(axis=0, ddof=1)
159+
mu = weights_arr.mean(axis=0)
160+
161+
# Safe division
162+
with np.errstate(divide='ignore', invalid='ignore'):
163+
cv = (std ** 2) / (mu ** 2)
164+
cv[mu == 0] = 0.0 # Handle zero mean
165+
166+
total_lr = sum(cv[:-1]) / len(data_shape)
167+
# total_lr = sum(dim_results) / target_vals.ndim
184168

185169
objective.fitness_calculated = True
186170
objective.fitness_value = fitness_value
187171
objective.stability_calculated = True
188-
objective.coefficients_stability = lr
172+
objective.coefficients_stability = total_lr
189173

190174
def get_g_fun_vals(self):
191175
try:

epde/operators/common/right_part_selection.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class EqRightPartSelector(CompoundOperator):
4646
def apply(self, objective : Equation, arguments : dict):
4747
self_args, subop_args = self.parse_suboperator_args(arguments = arguments)
4848

49+
assert len(objective.structure) == len(objective.terms_labels)
50+
4951
while not (objective.simplified and objective.is_correct_right_part):
5052
objective.reset_state(True)
5153
min_fitness = np.inf
@@ -61,37 +63,42 @@ def apply(self, objective : Equation, arguments : dict):
6163
continue
6264
objective.target_idx = target_idx
6365
fitness = self.suboperators['fitness_calculation'].apply(objective, arguments = subop_args['fitness_calculation'], force_out_of_place = True)
64-
if fitness < min_fitness and not all(objective.weights_internal == 0):
66+
if fitness is not None and fitness < min_fitness:
6567
min_fitness = fitness
6668
min_idx = target_idx
6769
weights_internal = objective.weights_internal
68-
else:
69-
pass
70+
weights_final = [weight for weight in objective.weights_final if weight != 0]
71+
72+
objective.weights_internal_evald = False
73+
objective.weights_final_evald = False
7074

71-
if all(weights_internal == 0) or np.isinf(min_fitness):
75+
if np.isinf(min_fitness):
7276
objective.randomize()
7377
continue
7478

7579
objective.weights_internal = weights_internal
80+
objective.weights_final = weights_final
7681
objective.weights_internal_evald = True
82+
objective.weights_final_evald = True
7783
objective.target_idx = min_idx
84+
7885
if not self.simplify_equation(objective):
7986
objective.simplified = True
8087
if objective.structure[objective.target_idx].contains_deriv(objective.main_var_to_explain):
8188
# if objective.structure[objective.target_idx].contains_deriv():
8289
objective.is_correct_right_part = True
8390
else:
8491
objective.right_part_selected = True
85-
objective.reset_state(False)
92+
objective.remove_zero_terms()
8693

8794
def simplify_equation(self, objective: Equation):
8895
# Get nonzero terms
8996
nonzero_terms_mask = np.array([False if weight == 0 else True for weight in objective.weights_internal], dtype=np.int32)
9097
nonrs_terms = [term for i, term in enumerate(objective.structure) if i != objective.target_idx]
9198
nonzero_terms = [item for item, keep in zip(nonrs_terms, nonzero_terms_mask) if keep]
9299
nonzero_terms.append(objective.structure[objective.target_idx])
100+
equation_terms = [term.term_label_without_power for term in nonzero_terms]
93101

94-
equation_terms = objective.described_variables
95102
# If amount nonzero terms is more than one -- get their intersection
96103
if len(equation_terms) > 1:
97104
common_factors = list(frozenset.intersection(*equation_terms))
@@ -130,13 +137,11 @@ def simplify_equation(self, objective: Equation):
130137
continue
131138
term.structure = [factor for factor in term.structure if factor not in factors_simplified]
132139
term.reset_saved_state()
140+
133141
# If term's order became zero -- replace term
134-
if len(term.structure) == 0 or not term.contains_meaningful():
135-
term.randomize()
136-
term.reset_saved_state()
137-
while len(objective.described_variables_full) != len(objective.structure):
142+
while len(term.structure) == 0 or not term.contains_meaningful() or len(objective.terms_labels) != len(objective.structure):
138143
term.randomize()
139-
term.reset_saved_state()
144+
140145
return True
141146
return False
142147

0 commit comments

Comments
 (0)