Skip to content

Commit 9c42b80

Browse files
committed
Recovered (and deprecated) BFGSUpdater.
1 parent c13ab4a commit 9c42b80

3 files changed

Lines changed: 334 additions & 137 deletions

File tree

hipparchus-optim/src/main/java/org/hipparchus/optim/nonlinear/vector/constrained/BFGSUpdater.java

Lines changed: 37 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
package org.hipparchus.optim.nonlinear.vector.constrained;
1818

19-
2019
import org.hipparchus.linear.Array2DRowRealMatrix;
2120
import org.hipparchus.linear.ArrayRealVector;
2221
import org.hipparchus.linear.CholeskyDecomposition;
@@ -38,60 +37,37 @@
3837
* <li>Automatic Hessian reset after configurable failures</li>
3938
* </ul>
4039
*
41-
* @since 4.1
40+
* @deprecated as of 4.1, replaced by {@link BFGSUpdater2}
4241
*/
42+
@Deprecated
4343
public class BFGSUpdater {
4444

45-
/**
46-
* Damping factor.
47-
*/
45+
/** Damping factor. */
4846
private static final double GAMMA = 0.2;
4947

50-
/**
51-
* AutoScaling Flag.
52-
*/
53-
private final boolean scale;
54-
55-
/**
56-
* EPS.
57-
*/
58-
private final double eps;
48+
/** Regularization factor for diagonal of Hessian. */
49+
private final double regFactor;
5950

60-
/**
61-
* trigger skip update for diagonal of Hessian.
62-
*/
63-
private final double sqrtEPSmachine = FastMath.sqrt(Precision.EPSILON);
64-
65-
/**
66-
* Tolerance for symmetric matrices decomposition.
67-
*
51+
/** Tolerance for symmetric matrices decomposition.
6852
* @since 4.1
6953
*/
7054
private final double decompositionEpsilon;
7155

72-
/**
73-
* Stored initial Hessian for resets.
74-
*/
56+
/** Stored initial Hessian for resets. */
7557
private final RealMatrix initialH;
7658

77-
/**
78-
* Current Cholesky factor L such that H = L·Lᵀ.
79-
*/
59+
/** Current Cholesky factor L such that H = L·Lᵀ. */
8060
private RealMatrix L;
8161

8262
/**
8363
* Creates a new updater.
84-
*
85-
* @param initialHess initial positive‐definite Hessian matrix
86-
* @param eps treshold to apply auto scale sty<sqrt(eps)
87-
* @param autoScale true apply auto hessian rescaling
88-
* @param decompositionEpsilon tolerance for symmetric matrices
89-
* decomposition
64+
* @param initialHess initial positive‐definite Hessian matrix
65+
* @param regFactor regularization factor to add on diagonal
66+
* @param decompositionEpsilon tolerance for symmetric matrices decomposition
9067
*/
91-
public BFGSUpdater(final RealMatrix initialHess, final double eps, final boolean autoScale, final double decompositionEpsilon) {
92-
this.initialH = new Array2DRowRealMatrix(initialHess.getData());
93-
this.eps = eps;
94-
this.scale = autoScale;
68+
public BFGSUpdater(final RealMatrix initialHess, final double regFactor, final double decompositionEpsilon) {
69+
this.initialH = new Array2DRowRealMatrix(initialHess.getData());
70+
this.regFactor = regFactor;
9571
this.decompositionEpsilon = decompositionEpsilon;
9672
resetHessian();
9773
}
@@ -109,61 +85,20 @@ public RealMatrix getHessian() {
10985
* Updates the Hessian approximation using the BFGS formula.
11086
* <p>
11187
* If curvature condition fails, applies damping or regularization.
112-
* </p>
88+
*</p>
11389
*
11490
* @param s displacement vector (x_{k+1} − x_k)
11591
* @param y1 gradient difference (∇f_{k+1} − ∇f_k)
116-
* @return type of update
117-
* 0: update is done
118-
* 1:sHs too small skip update
119-
* 2:sty<gamma*sHs skipped update
120-
* 3:sty<sqrt(eps)auto scale gamma*Hini
121-
* 4:singulatity detected during downdate reset to gamma*Hinit
12292
*/
123-
public int update(RealVector s, RealVector y1) {
124-
RealVector Hs = L.operate(L.preMultiply(s)); // al posto di getHessian().operate(s)
125-
double sHs = s.dotProduct(Hs);
126-
if (sHs <= 0.0) {
127-
128-
// double sty = s.dotProduct(y1);
129-
// double yy = y1.dotProduct(y1);
130-
// double gamma =yy /sty;
131-
// if (sty>0) {
132-
// gamma = FastMath.max(sqrtEPSmachine, FastMath.min(1/sqrtEPSmachine, gamma));
133-
// this.resetHessian(gamma);
134-
// return 1;
135-
// }
136-
// this.resetHessian();
137-
return 1;
138-
}
139-
140-
RealVector y = damp(s, y1, Hs, sHs);
141-
if (y == null ) {
142-
143-
return 2;//damp failed
93+
public void update(RealVector s, RealVector y1) {
94+
RealVector y = damp(s, y1);
95+
if (y == null) {
96+
return;
14497
}
145-
146-
147-
148-
149-
if (scale) {
150-
double sty = s.dotProduct(y);
151-
double yy = y.dotProduct(y);
152-
double gamma =yy /sty;
153-
if (gamma < FastMath.sqrt(eps)) {
154-
gamma = FastMath.max(sqrtEPSmachine, FastMath.min(1/sqrtEPSmachine, gamma));
155-
this.resetHessian(gamma);
156-
return 3;
157-
}
158-
}
159-
16098
// Attempt rank‐one BFGS update; regularize on failure
161-
if (rankOneUpdate(s, y, Hs, sHs)) return 0;
162-
163-
return 4;
99+
rankOneUpdate(s, y);
164100
}
165101

166-
167102
/**
168103
* Resets the Hessian approximation to its initial value.
169104
*/
@@ -172,80 +107,54 @@ public void resetHessian() {
172107
L = ch.getL();
173108
}
174109

175-
/**
176-
* Resets the Hessian approximation with information on the curvature.
177-
*
178-
* @param gamma scale factor
179-
*/
180-
public void resetHessian(double gamma) {
181-
final CholeskyDecomposition ch = new CholeskyDecomposition(initialH.scalarMultiply(gamma), decompositionEpsilon, decompositionEpsilon);
182-
L = ch.getL();
183-
}
184-
185110
/**
186111
* Applies dynamic damping to y to satisfy curvature condition sᵀy ≥ γ sᵀHs.
187112
*
188113
* @param s search direction
189114
* @param y1 raw gradient difference
190-
* @param Hs vector
191-
* @param sHs value
192115
* @return damped y, or null if update should be skipped
193116
*/
194-
public RealVector damp(RealVector s, RealVector y1, RealVector Hs, double sHs) {
117+
public RealVector damp(RealVector s, RealVector y1) {
195118
RealVector y = new ArrayRealVector(y1);
196119
double sty = s.dotProduct(y1);
197-
120+
RealVector Hs = getHessian().operate(s);
121+
double sHs = s.dotProduct(Hs);
122+
if (sty <= Precision.EPSILON) {
123+
return null;
124+
}
198125
if (sty < GAMMA * sHs) {
199126
double phi = (1.0 - GAMMA) * sHs / (sHs - sty);
200-
if (phi >= 1.0) return y1;
201-
else if (phi <= 0.0) return Hs;
202-
//
203-
y = (y1.mapMultiply(phi)).add(Hs.mapMultiply(1.0 - phi));
127+
// clamp phi to [0,1]
128+
phi = FastMath.max(0.0, FastMath.min(1.0, phi));
129+
y = y1.mapMultiply(phi).add(Hs.mapMultiply(1.0 - phi));
204130
sty = s.dotProduct(y);
205-
206-
207131
if (sty < GAMMA * sHs) {
208-
209132
return null;
210133
}
211-
212134
}
213135
return y;
214136
}
215137

216-
217-
218138
/**
219139
* Performs a BFGS rank‐one update on L.
220140
*
221141
* @param s displacement vector
222142
* @param y gradient difference vector
223-
* @param Hs vector
224-
* @param sHs value
225143
* @return true if update succeeded, false otherwise
226144
*/
227-
private boolean rankOneUpdate(RealVector s, RealVector y, RealVector Hs, double sHs) {
145+
private boolean rankOneUpdate(RealVector s, RealVector y) {
228146
RealMatrix Lcopy = new Array2DRowRealMatrix(L.getData());
147+
RealVector Hs = L.operate(L.preMultiply(s));
229148
double rho = 1.0 / FastMath.sqrt(s.dotProduct(y));
230-
double theta = 1.0 / FastMath.sqrt(sHs);
149+
double theta = 1.0 / FastMath.sqrt(s.dotProduct(Hs));
231150
RealVector v = y.mapMultiply(rho);
232151
RealVector w = Hs.mapMultiply(theta);
233-
cholupdateLower(v,+1);//upgrade
234-
if (!cholupdateLower(w,-1)) { //downdate
235-
double gamma = 1.0;
236-
double sty = s.dotProduct(y);
237-
double yy = y.dotProduct(y);
238-
if (sty> Precision.SAFE_MIN) {
239-
gamma =yy /sty;
240-
gamma = FastMath.max(sqrtEPSmachine, FastMath.min(1/sqrtEPSmachine, gamma));
241-
this.resetHessian(gamma);
242-
}
243-
else this.resetHessian();
244-
152+
cholupdateLower(v, +1) ;
245153

246-
return false;
154+
if (!cholupdateLower(w, -1)) {
155+
//try to regularize
156+
L.setSubMatrix(Lcopy.getData(), 0, 0);
247157
}
248-
249158
return true;
250159
}
251160

@@ -266,13 +175,9 @@ private boolean cholupdateLower(RealVector u, int sigma) {
266175
double lii = L.getEntry(i, i);
267176
double ui = temp.getEntry(i);
268177
double r2 = lii * lii + sigma * ui * ui;
269-
270-
//skip or update
271-
if (sigma < 0 && r2 < this.sqrtEPSmachine * lii * lii) {
272-
// if (sigma < 0 && r2 < Precision.EPSILON) {
178+
if (r2 < regFactor) {
273179
return false;
274180
}
275-
276181
double r = Math.sqrt(r2);
277182
double c = r / lii;
278183
double s = ui / lii;
@@ -289,8 +194,4 @@ private boolean cholupdateLower(RealVector u, int sigma) {
289194
return true;
290195
}
291196

292-
293-
294-
295-
296197
}

0 commit comments

Comments
 (0)