1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.optim.nonlinear.scalar.noderiv;
23
24 import org.hipparchus.analysis.MultivariateFunction;
25 import org.hipparchus.exception.MathIllegalArgumentException;
26 import org.hipparchus.exception.MathIllegalStateException;
27 import org.hipparchus.optim.InitialGuess;
28 import org.hipparchus.optim.MaxEval;
29 import org.hipparchus.optim.PointValuePair;
30 import org.hipparchus.optim.SimpleBounds;
31 import org.hipparchus.optim.nonlinear.scalar.GoalType;
32 import org.hipparchus.optim.nonlinear.scalar.ObjectiveFunction;
33 import org.hipparchus.util.FastMath;
34 import org.junit.jupiter.api.Test;
35
36 import java.util.Arrays;
37 import java.util.Random;
38
39 import static org.junit.jupiter.api.Assertions.assertEquals;
40 import static org.junit.jupiter.api.Assertions.assertThrows;
41
42
43
44
45 class BOBYQAOptimizerTest {
46
47 static final int DIM = 13;
48
49 @Test
50 void testInitOutOfBounds() {
51 assertThrows(MathIllegalArgumentException.class, () -> {
52 double[] startPoint = point(DIM, 3);
53 double[][] boundaries = boundaries(DIM, -1, 2);
54 doTest(new Rosen(), startPoint, boundaries,
55 GoalType.MINIMIZE,
56 1e-13, 1e-6, 2000, null);
57 });
58 }
59
60 @Test
61 void testBoundariesDimensionMismatch() {
62 assertThrows(MathIllegalArgumentException.class, () -> {
63 double[] startPoint = point(DIM, 0.5);
64 double[][] boundaries = boundaries(DIM + 1, -1, 2);
65 doTest(new Rosen(), startPoint, boundaries,
66 GoalType.MINIMIZE,
67 1e-13, 1e-6, 2000, null);
68 });
69 }
70
71 @Test
72 void testProblemDimensionTooSmall() {
73 assertThrows(MathIllegalArgumentException.class, () -> {
74 double[] startPoint = point(1, 0.5);
75 doTest(new Rosen(), startPoint, null,
76 GoalType.MINIMIZE,
77 1e-13, 1e-6, 2000, null);
78 });
79 }
80
81 @Test
82 void testMaxEvaluations() {
83 assertThrows(MathIllegalStateException.class, () -> {
84 final int lowMaxEval = 2;
85 double[] startPoint = point(DIM, 0.1);
86 double[][] boundaries = null;
87 doTest(new Rosen(), startPoint, boundaries,
88 GoalType.MINIMIZE,
89 1e-13, 1e-6, lowMaxEval, null);
90 });
91 }
92
93 @Test
94 void testRosen() {
95 double[] startPoint = point(DIM,0.1);
96 double[][] boundaries = null;
97 PointValuePair expected = new PointValuePair(point(DIM,1.0),0.0);
98 doTest(new Rosen(), startPoint, boundaries,
99 GoalType.MINIMIZE,
100 1e-13, 1e-6, 2000, expected);
101 }
102
103 @Test
104 void testMaximize() {
105 double[] startPoint = point(DIM,1.0);
106 double[][] boundaries = null;
107 PointValuePair expected = new PointValuePair(point(DIM,0.0),1.0);
108 doTest(new MinusElli(), startPoint, boundaries,
109 GoalType.MAXIMIZE,
110 2e-10, 5e-6, 1000, expected);
111 boundaries = boundaries(DIM,-0.3,0.3);
112 startPoint = point(DIM,0.1);
113 doTest(new MinusElli(), startPoint, boundaries,
114 GoalType.MAXIMIZE,
115 2e-10, 5e-6, 1000, expected);
116 }
117
118 @Test
119 void testEllipse() {
120 double[] startPoint = point(DIM,1.0);
121 double[][] boundaries = null;
122 PointValuePair expected =
123 new PointValuePair(point(DIM,0.0),0.0);
124 doTest(new Elli(), startPoint, boundaries,
125 GoalType.MINIMIZE,
126 1e-13, 1e-6, 1000, expected);
127 }
128
129 @Test
130 void testElliRotated() {
131 double[] startPoint = point(DIM,1.0);
132 double[][] boundaries = null;
133 PointValuePair expected =
134 new PointValuePair(point(DIM,0.0),0.0);
135 doTest(new ElliRotated(), startPoint, boundaries,
136 GoalType.MINIMIZE,
137 1e-12, 1e-6, 10000, expected);
138 }
139
140 @Test
141 void testCigar() {
142 double[] startPoint = point(DIM,1.0);
143 double[][] boundaries = null;
144 PointValuePair expected =
145 new PointValuePair(point(DIM,0.0),0.0);
146 doTest(new Cigar(), startPoint, boundaries,
147 GoalType.MINIMIZE,
148 1e-13, 1e-6, 100, expected);
149 }
150
151 @Test
152 void testTwoAxes() {
153 double[] startPoint = point(DIM,1.0);
154 double[][] boundaries = null;
155 PointValuePair expected =
156 new PointValuePair(point(DIM,0.0),0.0);
157 doTest(new TwoAxes(), startPoint, boundaries,
158 GoalType.MINIMIZE, 2*
159 1e-13, 1e-6, 100, expected);
160 }
161
162 @Test
163 void testCigTab() {
164 double[] startPoint = point(DIM,1.0);
165 double[][] boundaries = null;
166 PointValuePair expected =
167 new PointValuePair(point(DIM,0.0),0.0);
168 doTest(new CigTab(), startPoint, boundaries,
169 GoalType.MINIMIZE,
170 1e-13, 5e-5, 100, expected);
171 }
172
173 @Test
174 void testSphere() {
175 double[] startPoint = point(DIM,1.0);
176 double[][] boundaries = null;
177 PointValuePair expected =
178 new PointValuePair(point(DIM,0.0),0.0);
179 doTest(new Sphere(), startPoint, boundaries,
180 GoalType.MINIMIZE,
181 1e-13, 1e-6, 100, expected);
182 }
183
184 @Test
185 void testTablet() {
186 double[] startPoint = point(DIM,1.0);
187 double[][] boundaries = null;
188 PointValuePair expected =
189 new PointValuePair(point(DIM,0.0),0.0);
190 doTest(new Tablet(), startPoint, boundaries,
191 GoalType.MINIMIZE,
192 1e-13, 1e-6, 100, expected);
193 }
194
195 @Test
196 void testDiffPow() {
197 double[] startPoint = point(DIM/2,1.0);
198 double[][] boundaries = null;
199 PointValuePair expected =
200 new PointValuePair(point(DIM/2,0.0),0.0);
201 doTest(new DiffPow(), startPoint, boundaries,
202 GoalType.MINIMIZE,
203 1e-8, 1e-1, 21000, expected);
204 }
205
206 @Test
207 void testSsDiffPow() {
208 double[] startPoint = point(DIM/2,1.0);
209 double[][] boundaries = null;
210 PointValuePair expected =
211 new PointValuePair(point(DIM/2,0.0),0.0);
212 doTest(new SsDiffPow(), startPoint, boundaries,
213 GoalType.MINIMIZE,
214 1e-2, 1.3e-1, 50000, expected);
215 }
216
217 @Test
218 void testAckley() {
219 double[] startPoint = point(DIM,0.1);
220 double[][] boundaries = null;
221 PointValuePair expected =
222 new PointValuePair(point(DIM,0.0),0.0);
223 doTest(new Ackley(), startPoint, boundaries,
224 GoalType.MINIMIZE,
225 1e-7, 1e-5, 1000, expected);
226 }
227
228 @Test
229 void testRastrigin() {
230 double[] startPoint = point(DIM,1.0);
231
232 double[][] boundaries = null;
233 PointValuePair expected =
234 new PointValuePair(point(DIM,0.0),0.0);
235 doTest(new Rastrigin(), startPoint, boundaries,
236 GoalType.MINIMIZE,
237 1e-13, 1e-6, 1000, expected);
238 }
239
240 @Test
241 void testConstrainedRosen() {
242 double[] startPoint = point(DIM,0.1);
243
244 double[][] boundaries = boundaries(DIM,-1,2);
245 PointValuePair expected =
246 new PointValuePair(point(DIM,1.0),0.0);
247 doTest(new Rosen(), startPoint, boundaries,
248 GoalType.MINIMIZE,
249 1e-13, 1e-6, 2000, expected);
250 }
251
252
253
254
255
256
257
258
259
260
261
262 private void doTest(MultivariateFunction func,
263 double[] startPoint,
264 double[][] boundaries,
265 GoalType goal,
266 double fTol,
267 double pointTol,
268 int maxEvaluations,
269 PointValuePair expected) {
270 doTest(func,
271 startPoint,
272 boundaries,
273 goal,
274 fTol,
275 pointTol,
276 maxEvaluations,
277 0,
278 expected,
279 "");
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294 private void doTest(MultivariateFunction func,
295 double[] startPoint,
296 double[][] boundaries,
297 GoalType goal,
298 double fTol,
299 double pointTol,
300 int maxEvaluations,
301 int additionalInterpolationPoints,
302 PointValuePair expected,
303 String assertMsg) {
304
305
306
307 int dim = startPoint.length;
308 final int numIterpolationPoints = 2 * dim + 1 + additionalInterpolationPoints;
309 BOBYQAOptimizer optim = new BOBYQAOptimizer(numIterpolationPoints);
310 PointValuePair result = boundaries == null ?
311 optim.optimize(new MaxEval(maxEvaluations),
312 new ObjectiveFunction(func),
313 goal,
314 SimpleBounds.unbounded(dim),
315 new InitialGuess(startPoint)) :
316 optim.optimize(new MaxEval(maxEvaluations),
317 new ObjectiveFunction(func),
318 goal,
319 new InitialGuess(startPoint),
320 new SimpleBounds(boundaries[0],
321 boundaries[1]));
322
323
324
325
326 assertEquals(expected.getValue(), result.getValue(), fTol, assertMsg);
327 for (int i = 0; i < dim; i++) {
328 assertEquals(expected.getPoint()[i],
329 result.getPoint()[i], pointTol);
330 }
331
332
333 }
334
335 private static double[] point(int n, double value) {
336 double[] ds = new double[n];
337 Arrays.fill(ds, value);
338 return ds;
339 }
340
341 private static double[][] boundaries(int dim,
342 double lower, double upper) {
343 double[][] boundaries = new double[2][dim];
344 for (int i = 0; i < dim; i++)
345 boundaries[0][i] = lower;
346 for (int i = 0; i < dim; i++)
347 boundaries[1][i] = upper;
348 return boundaries;
349 }
350
351 private static class Sphere implements MultivariateFunction {
352
353 public double value(double[] x) {
354 double f = 0;
355 for (int i = 0; i < x.length; ++i)
356 f += x[i] * x[i];
357 return f;
358 }
359 }
360
361 private static class Cigar implements MultivariateFunction {
362 private double factor;
363
364 Cigar() {
365 this(1e3);
366 }
367
368 Cigar(double axisratio) {
369 factor = axisratio * axisratio;
370 }
371
372 public double value(double[] x) {
373 double f = x[0] * x[0];
374 for (int i = 1; i < x.length; ++i)
375 f += factor * x[i] * x[i];
376 return f;
377 }
378 }
379
380 private static class Tablet implements MultivariateFunction {
381 private double factor;
382
383 Tablet() {
384 this(1e3);
385 }
386
387 Tablet(double axisratio) {
388 factor = axisratio * axisratio;
389 }
390
391 public double value(double[] x) {
392 double f = factor * x[0] * x[0];
393 for (int i = 1; i < x.length; ++i)
394 f += x[i] * x[i];
395 return f;
396 }
397 }
398
399 private static class CigTab implements MultivariateFunction {
400 private double factor;
401
402 CigTab() {
403 this(1e4);
404 }
405
406 CigTab(double axisratio) {
407 factor = axisratio;
408 }
409
410 public double value(double[] x) {
411 int end = x.length - 1;
412 double f = x[0] * x[0] / factor + factor * x[end] * x[end];
413 for (int i = 1; i < end; ++i)
414 f += x[i] * x[i];
415 return f;
416 }
417 }
418
419 private static class TwoAxes implements MultivariateFunction {
420
421 private double factor;
422
423 TwoAxes() {
424 this(1e6);
425 }
426
427 TwoAxes(double axisratio) {
428 factor = axisratio * axisratio;
429 }
430
431 public double value(double[] x) {
432 double f = 0;
433 for (int i = 0; i < x.length; ++i)
434 f += (i < x.length / 2 ? factor : 1) * x[i] * x[i];
435 return f;
436 }
437 }
438
439 private static class ElliRotated implements MultivariateFunction {
440 private Basis B = new Basis();
441 private double factor;
442
443 ElliRotated() {
444 this(1e3);
445 }
446
447 ElliRotated(double axisratio) {
448 factor = axisratio * axisratio;
449 }
450
451 public double value(double[] x) {
452 double f = 0;
453 x = B.Rotate(x);
454 for (int i = 0; i < x.length; ++i)
455 f += FastMath.pow(factor, i / (x.length - 1.)) * x[i] * x[i];
456 return f;
457 }
458 }
459
460 private static class Elli implements MultivariateFunction {
461
462 private double factor;
463
464 Elli() {
465 this(1e3);
466 }
467
468 Elli(double axisratio) {
469 factor = axisratio * axisratio;
470 }
471
472 public double value(double[] x) {
473 double f = 0;
474 for (int i = 0; i < x.length; ++i)
475 f += FastMath.pow(factor, i / (x.length - 1.)) * x[i] * x[i];
476 return f;
477 }
478 }
479
480 private static class MinusElli implements MultivariateFunction {
481 private final Elli elli = new Elli();
482 public double value(double[] x) {
483 return 1.0 - elli.value(x);
484 }
485 }
486
487 private static class DiffPow implements MultivariateFunction {
488
489 public double value(double[] x) {
490 double f = 0;
491 for (int i = 0; i < x.length; ++i)
492 f += FastMath.pow(FastMath.abs(x[i]), 2. + 10 * (double) i
493 / (x.length - 1.));
494
495
496
497
498 return f;
499 }
500 }
501
502 private static class SsDiffPow implements MultivariateFunction {
503
504 public double value(double[] x) {
505 double f = FastMath.pow(new DiffPow().value(x), 0.25);
506 return f;
507 }
508 }
509
510 private static class Rosen implements MultivariateFunction {
511
512 public double value(double[] x) {
513 double f = 0;
514 for (int i = 0; i < x.length - 1; ++i)
515 f += 1e2 * (x[i] * x[i] - x[i + 1]) * (x[i] * x[i] - x[i + 1])
516 + (x[i] - 1.) * (x[i] - 1.);
517 return f;
518 }
519 }
520
521 private static class Ackley implements MultivariateFunction {
522 private double axisratio;
523
524 Ackley(double axra) {
525 axisratio = axra;
526 }
527
528 public Ackley() {
529 this(1);
530 }
531
532 public double value(double[] x) {
533 double f = 0;
534 double res2 = 0;
535 double fac = 0;
536 for (int i = 0; i < x.length; ++i) {
537 fac = FastMath.pow(axisratio, (i - 1.) / (x.length - 1.));
538 f += fac * fac * x[i] * x[i];
539 res2 += FastMath.cos(2. * FastMath.PI * fac * x[i]);
540 }
541 f = (20. - 20. * FastMath.exp(-0.2 * FastMath.sqrt(f / x.length))
542 + FastMath.exp(1.) - FastMath.exp(res2 / x.length));
543 return f;
544 }
545 }
546
547 private static class Rastrigin implements MultivariateFunction {
548
549 private double axisratio;
550 private double amplitude;
551
552 Rastrigin() {
553 this(1, 10);
554 }
555
556 Rastrigin(double axisratio, double amplitude) {
557 this.axisratio = axisratio;
558 this.amplitude = amplitude;
559 }
560
561 public double value(double[] x) {
562 double f = 0;
563 double fac;
564 for (int i = 0; i < x.length; ++i) {
565 fac = FastMath.pow(axisratio, (i - 1.) / (x.length - 1.));
566 if (i == 0 && x[i] < 0)
567 fac *= 1.;
568 f += fac * fac * x[i] * x[i] + amplitude
569 * (1. - FastMath.cos(2. * FastMath.PI * fac * x[i]));
570 }
571 return f;
572 }
573 }
574
575 private static class Basis {
576 double[][] basis;
577 Random rand = new Random(2);
578
579 double[] Rotate(double[] x) {
580 GenBasis(x.length);
581 double[] y = new double[x.length];
582 for (int i = 0; i < x.length; ++i) {
583 y[i] = 0;
584 for (int j = 0; j < x.length; ++j)
585 y[i] += basis[i][j] * x[j];
586 }
587 return y;
588 }
589
590 void GenBasis(int DIM) {
591 if (basis != null ? basis.length == DIM : false)
592 return;
593
594 double sp;
595 int i, j, k;
596
597
598 basis = new double[DIM][DIM];
599 for (i = 0; i < DIM; ++i) {
600
601 for (j = 0; j < DIM; ++j)
602 basis[i][j] = rand.nextGaussian();
603
604 for (j = i - 1; j >= 0; --j) {
605 for (sp = 0., k = 0; k < DIM; ++k)
606 sp += basis[i][k] * basis[j][k];
607 for (k = 0; k < DIM; ++k)
608 basis[i][k] -= sp * basis[j][k];
609 }
610
611 for (sp = 0., k = 0; k < DIM; ++k)
612 sp += basis[i][k] * basis[i][k];
613 for (k = 0; k < DIM; ++k)
614 basis[i][k] /= FastMath.sqrt(sp);
615 }
616 }
617 }
618 }