View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv;
18  
19  import java.util.Arrays;
20  import org.apache.commons.rng.UniformRandomProvider;
21  import org.apache.commons.rng.simple.RandomSource;
22  import org.apache.commons.rng.simple.ThreadLocalRandomSource;
23  import org.apache.commons.rng.sampling.distribution.MarsagliaNormalizedGaussianSampler;
24  import org.apache.commons.rng.sampling.distribution.ContinuousUniformSampler;
25  import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
26  import org.apache.commons.math4.core.jdkmath.JdkMath;
27  
28  /**
29   * Utilities for testing the optimizers.
30   */
31  final class OptimTestUtils {
32  
33      /** No instances. */
34      private OptimTestUtils() {}
35  
36  
37      static class ElliRotated implements MultivariateFunction {
38          private Basis B = new Basis();
39          private double factor;
40  
41          ElliRotated() {
42              this(1e3);
43          }
44  
45          ElliRotated(double axisratio) {
46              factor = axisratio * axisratio;
47          }
48  
49          @Override
50          public double value(double[] x) {
51              double f = 0;
52              x = B.Rotate(x);
53              for (int i = 0; i < x.length; ++i) {
54                  f += JdkMath.pow(factor, i / (x.length - 1.)) * x[i] * x[i];
55              }
56              return f;
57          }
58      }
59  
60      static class FourExtrema implements MultivariateFunction {
61          // The following function has 4 local extrema.
62          static final double xM = -3.841947088256863675365;
63          static final double yM = -1.391745200270734924416;
64          static final double xP =  0.2286682237349059125691;
65          static final double yP = -yM;
66          static final double valueXmYm = 0.2373295333134216789769; // Local maximum.
67          static final double valueXmYp = -valueXmYm; // Local minimum.
68          static final double valueXpYm = -0.7290400707055187115322; // Global minimum.
69          static final double valueXpYp = -valueXpYm; // Global maximum.
70  
71          @Override
72          public double value(double[] variables) {
73              final double x = variables[0];
74              final double y = variables[1];
75              return (x == 0 || y == 0) ? 0 :
76                  JdkMath.atan(x) * JdkMath.atan(x + 2) * JdkMath.atan(y) * JdkMath.atan(y) / (x * y);
77          }
78      }
79  
80      static double[] point(int n, double value) {
81          final double[] ds = new double[n];
82          Arrays.fill(ds, value);
83          return ds;
84      }
85  
86      /**
87       * @param n Dimension.
88       * @param value Value.
89       * @param jitter Random noise to add to {@code value}.
90       */
91      static double[] point(int n,
92                            double value,
93                            double jitter) {
94          final double[] ds = new double[n];
95          Arrays.fill(ds, value);
96          return point(ds, jitter);
97      }
98  
99      /**
100      * @param point Point.
101      * @param jitter Random noise to add to each {@code value} element.
102      */
103     static double[] point(double[] value,
104                           double jitter) {
105         final ContinuousUniformSampler s = new ContinuousUniformSampler(rng(),
106                                                                         -jitter,
107                                                                         jitter);
108         final double[] ds = new double[value.length];
109         for (int i = 0; i < value.length; i++) {
110             ds[i] = value[i] + s.sample();
111         }
112         return ds;
113     }
114 
115     /** Creates a RNG instance. */
116     static UniformRandomProvider rng() {
117         return ThreadLocalRandomSource.current(RandomSource.MWC_256);
118     }
119 
120     private static final class Basis {
121         private double[][] basis;
122         private final MarsagliaNormalizedGaussianSampler rand = MarsagliaNormalizedGaussianSampler.of(rng()); // use not always the same basis
123 
124         double[] Rotate(double[] x) {
125             GenBasis(x.length);
126             double[] y = new double[x.length];
127             for (int i = 0; i < x.length; ++i) {
128                 y[i] = 0;
129                 for (int j = 0; j < x.length; ++j) {
130                     y[i] += basis[i][j] * x[j];
131                 }
132             }
133             return y;
134         }
135 
136         void GenBasis(int dim) {
137             if (basis != null ? basis.length == dim : false) {
138                 return;
139             }
140 
141             double sp;
142             int i;
143             int j;
144             int k;
145 
146             /* generate orthogonal basis */
147             basis = new double[dim][dim];
148             for (i = 0; i < dim; ++i) {
149                 /* sample components gaussian */
150                 for (j = 0; j < dim; ++j) {
151                     basis[i][j] = rand.sample();
152                 }
153                 /* substract projection of previous vectors */
154                 for (j = i - 1; j >= 0; --j) {
155                     for (sp = 0., k = 0; k < dim; ++k) {
156                         sp += basis[i][k] * basis[j][k]; /* scalar product */
157                     }
158                     for (k = 0; k < dim; ++k) {
159                         basis[i][k] -= sp * basis[j][k]; /* substract */
160                     }
161                 }
162                 /* normalize */
163                 for (sp = 0., k = 0; k < dim; ++k) {
164                     sp += basis[i][k] * basis[i][k]; /* squared norm */
165                 }
166                 for (k = 0; k < dim; ++k) {
167                     basis[i][k] /= JdkMath.sqrt(sp);
168                 }
169             }
170         }
171     }
172 }