Skip to content

Commit 1f26cf9

Browse files
authored
Merge pull request #66 from Gromwud/main
Cumulitive update
2 parents bf4460e + cd14e93 commit 1f26cf9

2 files changed

Lines changed: 52 additions & 7 deletions

File tree

epde/globals.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class VerboseManager:
104104
def init_verbose(plot_DE_solutions : bool = False, show_iter_idx : bool = True,
105105
show_iter_fitness : bool = False, show_iter_stats : bool = False,
106106
show_ann_loss : bool = False, show_warnings : bool = False,
107-
candidate_objectives : bool = False):
107+
candidate_objectives : bool = True):
108108
"""
109109
Method for initialized of manager for output in text form
110110

epde/operators/common/sparsity.py

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,15 @@ def fit(self, X, y, sample_weights):
5555
residual = y - (X @ self.coef_ + self.intercept_)
5656

5757
iteration = 0
58-
max_change = np.inf
5958

6059
# 2. Coordinate Descent Loop
6160
while iteration < self.max_iter and not all(self.coef_ == 0):
61+
max_change = 0
62+
max_abs_coef = 0.0
63+
6264
# Sort features by instability (highest CV first)
63-
for j in np.argsort(cv)[::-1]:
65+
indices = np.argsort(cv)[::-1]
66+
for j in indices:
6467
old_coef = self.coef_[j]
6568

6669
if old_coef == 0:
@@ -91,15 +94,57 @@ def fit(self, X, y, sample_weights):
9194
self.intercept_ = weights.mean(axis=0)[-1]
9295
residual = y - (X @ self.coef_ + self.intercept_)
9396
iteration = 0
97+
max_change = np.inf
9498
break
9599

96100
residual -= (new_coef - old_coef) * X[:, j]
97-
change = abs(new_coef - old_coef) / abs(old_coef)
101+
change = abs(new_coef - old_coef)
102+
if change > max_change:
103+
max_change = change
104+
# change = abs(new_coef - old_coef) / abs(old_coef)
98105
# change = abs(self.intercept_ - old_intercept) / abs(old_intercept)
99-
max_change = max(max_change, change)
106+
# max_change = max(max_change, change)
107+
108+
max_abs_coef = np.max(np.abs(self.coef_))
109+
110+
# Критерий 1: max_j |w_new - w_old| <= tol * max_j |w_j|
111+
if max_change <= self.tol * max_abs_coef:
112+
# Критерий 2: Dual Gap <= tol * ||y||^2 / n_samples
113+
# Вычисляем компоненты дуального зазора
114+
# Примечание: Для Lasso с весами lambda_j = threshold_j
115+
116+
# 1. Вычисляем корреляции признаков с остатками
117+
xt_residual = X.T @ residual
118+
y_sq_sum = np.sum((y - self.intercept_) ** 2)
119+
120+
# 2. Масштабирующий фактор для обеспечения дуальной допустимости
121+
# В sklearn: dual_scale = min(1, alpha / max(|X.T @ res|))
122+
# Здесь используем ваши индивидуальные threshold_j
123+
dual_norm = 0
124+
for j in range(self.n_features):
125+
if cv[j] * y_sq_sum > 0:
126+
dual_norm = max(dual_norm, abs(xt_residual[j]) / cv[j] * y_sq_sum)
127+
128+
if dual_norm > 1.0:
129+
const_residual = residual / dual_norm
130+
else:
131+
const_residual = residual
132+
133+
# 3. Вычисление Gap: Primal Objective - Dual Objective
134+
# Primal = 0.5 * ||res||^2 + sum(threshold_j * |w_j|)
135+
# Dual = 0.5 * ||y-intercept||^2 - 0.5 * ||y-intercept - const_residual||^2
136+
primal_obj = 0.5 * np.sum(residual ** 2) + np.sum(cv * y_sq_sum * np.abs(self.coef_))
137+
dual_obj = 0.5 * y_sq_sum - 0.5 * np.sum((y - self.intercept_ - const_residual) ** 2)
138+
139+
dual_gap = primal_obj - dual_obj
140+
141+
# Итоговая проверка по формуле со скрина
142+
if dual_gap <= self.tol * (y_sq_sum / self.n_samples):
143+
break
144+
145+
# if max_change < self.tol:
146+
# break
100147

101-
if max_change < self.tol:
102-
break
103148
iteration += 1
104149
# print(iteration)
105150
return self

0 commit comments

Comments
 (0)