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