1dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/*
2dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Licensed to the Apache Software Foundation (ASF) under one or more
3dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * contributor license agreements.  See the NOTICE file distributed with
4dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * this work for additional information regarding copyright ownership.
5dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The ASF licenses this file to You under the Apache License, Version 2.0
6dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * (the "License"); you may not use this file except in compliance with
7dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * the License.  You may obtain a copy of the License at
8dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
9dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *      http://www.apache.org/licenses/LICENSE-2.0
10dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
11dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Unless required by applicable law or agreed to in writing, software
12dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * distributed under the License is distributed on an "AS IS" BASIS,
13dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * See the License for the specific language governing permissions and
15dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * limitations under the License.
16dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
17dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
18dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpackage org.apache.commons.math.optimization;
19dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
20dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.ConvergenceException;
21dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.FunctionEvaluationException;
22dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.MathRuntimeException;
23dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.analysis.UnivariateRealFunction;
24dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.exception.util.LocalizedFormats;
25dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.random.RandomGenerator;
26dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.util.FastMath;
27dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
28dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/**
29dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Special implementation of the {@link UnivariateRealOptimizer} interface adding
30dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * multi-start features to an existing optimizer.
31dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
32dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * This class wraps a classical optimizer to use it several times in
33dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * turn with different starting points in order to avoid being trapped
34dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * into a local extremum when looking for a global one.
35dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * </p>
36dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
37dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @since 2.0
38dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
39dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpublic class MultiStartUnivariateRealOptimizer implements UnivariateRealOptimizer {
40dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
41dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Serializable version identifier. */
42dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final long serialVersionUID = 5983375963110961019L;
43dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
44dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Underlying classical optimizer. */
45dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private final UnivariateRealOptimizer optimizer;
46dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
47dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Maximal number of iterations allowed. */
48dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int maxIterations;
49dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
50dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Maximal number of evaluations allowed. */
51dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int maxEvaluations;
52dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
53dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Number of iterations already performed for all starts. */
54dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int totalIterations;
55dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
56dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Number of evaluations already performed for all starts. */
57dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int totalEvaluations;
58dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
59dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Number of starts to go. */
60dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int starts;
61dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
62dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Random generator for multi-start. */
63dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private RandomGenerator generator;
64dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
65dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Found optima. */
66dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private double[] optima;
67dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
68dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Found function values at optima. */
69dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private double[] optimaValues;
70dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
71dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
72dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create a multi-start optimizer from a single-start optimizer
73dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param optimizer single-start optimizer to wrap
74dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param starts number of starts to perform (including the
75dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * first one), multi-start is disabled if value is less than or
76dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * equal to 1
77dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param generator random generator to use for restarts
78dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
79dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public MultiStartUnivariateRealOptimizer(final UnivariateRealOptimizer optimizer,
80dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                             final int starts,
81dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                             final RandomGenerator generator) {
82dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.optimizer        = optimizer;
83dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.totalIterations  = 0;
84dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.starts           = starts;
85dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.generator        = generator;
86dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.optima           = null;
87dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        setMaximalIterationCount(Integer.MAX_VALUE);
88dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        setMaxEvaluations(Integer.MAX_VALUE);
89dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
90dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
91dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
92dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double getFunctionValue() {
93dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optimaValues[0];
94dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
95dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
96dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
97dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double getResult() {
98dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optima[0];
99dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double getAbsoluteAccuracy() {
103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optimizer.getAbsoluteAccuracy();
104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getIterationCount() {
108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return totalIterations;
109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getMaximalIterationCount() {
113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return maxIterations;
114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getMaxEvaluations() {
118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return maxEvaluations;
119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public int getEvaluations() {
123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return totalEvaluations;
124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double getRelativeAccuracy() {
128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optimizer.getRelativeAccuracy();
129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void resetAbsoluteAccuracy() {
133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        optimizer.resetAbsoluteAccuracy();
134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void resetMaximalIterationCount() {
138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        optimizer.resetMaximalIterationCount();
139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void resetRelativeAccuracy() {
143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        optimizer.resetRelativeAccuracy();
144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setAbsoluteAccuracy(double accuracy) {
148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        optimizer.setAbsoluteAccuracy(accuracy);
149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setMaximalIterationCount(int count) {
153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.maxIterations = count;
154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setMaxEvaluations(int maxEvaluations) {
158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this.maxEvaluations = maxEvaluations;
159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setRelativeAccuracy(double accuracy) {
163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        optimizer.setRelativeAccuracy(accuracy);
164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Get all the optima found during the last call to {@link
167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * #optimize(UnivariateRealFunction, GoalType, double, double) optimize}.
168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>The optimizer stores all the optima found during a set of
169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * restarts. The {@link #optimize(UnivariateRealFunction, GoalType,
170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * double, double) optimize} method returns the best point only. This
171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * method returns all the points found at the end of each starts,
172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * including the best one already returned by the {@link
173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * #optimize(UnivariateRealFunction, GoalType, double, double) optimize}
174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * method.
175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </p>
176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The returned array as one element for each start as specified
178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * in the constructor. It is ordered with the results from the
179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * runs that did converge first, sorted from best to worst
180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * objective value (i.e in ascending order if minimizing and in
181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * descending order if maximizing), followed by Double.NaN elements
182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * corresponding to the runs that did not converge. This means all
183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * elements will be NaN if the {@link #optimize(UnivariateRealFunction,
184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * GoalType, double, double) optimize} method did throw a {@link
185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * ConvergenceException ConvergenceException}). This also means that
186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * if the first element is not NaN, it is the best point found across
187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * all starts.</p>
188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return array containing the optima
189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @exception IllegalStateException if {@link #optimize(UnivariateRealFunction,
190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * GoalType, double, double) optimize} has not been called
191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see #getOptimaValues()
192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double[] getOptima() throws IllegalStateException {
194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (optima == null) {
195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optima.clone();
198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Get all the function values at optima found during the last call to {@link
201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * #optimize(UnivariateRealFunction, GoalType, double, double) optimize}.
202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The returned array as one element for each start as specified
204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * in the constructor. It is ordered with the results from the
205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * runs that did converge first, sorted from best to worst
206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * objective value (i.e in ascending order if minimizing and in
207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * descending order if maximizing), followed by Double.NaN elements
208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * corresponding to the runs that did not converge. This means all
209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * elements will be NaN if the {@link #optimize(UnivariateRealFunction,
210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * GoalType, double, double) optimize} method did throw a {@link
211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * ConvergenceException ConvergenceException}). This also means that
212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * if the first element is not NaN, it is the best point found across
213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * all starts.</p>
214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return array containing the optima
215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @exception IllegalStateException if {@link #optimize(UnivariateRealFunction,
216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * GoalType, double, double) optimize} has not been called
217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see #getOptima()
218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double[] getOptimaValues() throws IllegalStateException {
220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (optimaValues == null) {
221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optimaValues.clone();
224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double optimize(final UnivariateRealFunction f, final GoalType goalType,
228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                           final double min, final double max)
229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        throws ConvergenceException, FunctionEvaluationException {
230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        optima           = new double[starts];
232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        optimaValues     = new double[starts];
233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        totalIterations  = 0;
234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        totalEvaluations = 0;
235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // multi-start loop
237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < starts; ++i) {
238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            try {
240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimizer.setMaximalIterationCount(maxIterations - totalIterations);
241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final double bound1 = (i == 0) ? min : min + generator.nextDouble() * (max - min);
243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final double bound2 = (i == 0) ? max : min + generator.nextDouble() * (max - min);
244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optima[i]       = optimizer.optimize(f, goalType,
245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                                     FastMath.min(bound1, bound2),
246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                                     FastMath.max(bound1, bound2));
247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimaValues[i] = optimizer.getFunctionValue();
248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } catch (FunctionEvaluationException fee) {
249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optima[i]       = Double.NaN;
250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimaValues[i] = Double.NaN;
251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } catch (ConvergenceException ce) {
252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optima[i]       = Double.NaN;
253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimaValues[i] = Double.NaN;
254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            totalIterations  += optimizer.getIterationCount();
257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            totalEvaluations += optimizer.getEvaluations();
258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // sort the optima from best to worst, followed by NaN elements
262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int lastNaN = optima.length;
263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int i = 0; i < lastNaN; ++i) {
264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (Double.isNaN(optima[i])) {
265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optima[i] = optima[--lastNaN];
266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optima[lastNaN + 1] = Double.NaN;
267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimaValues[i] = optimaValues[--lastNaN];
268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimaValues[lastNaN + 1] = Double.NaN;
269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double currX = optima[0];
273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double currY = optimaValues[0];
274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int j = 1; j < lastNaN; ++j) {
275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final double prevY = currY;
276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            currX = optima[j];
277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            currY = optimaValues[j];
278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if ((goalType == GoalType.MAXIMIZE) ^ (currY < prevY)) {
279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // the current element should be inserted closer to the beginning
280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                int i = j - 1;
281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                double mIX = optima[i];
282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                double mIY = optimaValues[i];
283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                while ((i >= 0) && ((goalType == GoalType.MAXIMIZE) ^ (currY < mIY))) {
284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    optima[i + 1]       = mIX;
285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    optimaValues[i + 1] = mIY;
286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    if (i-- != 0) {
287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        mIX = optima[i];
288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        mIY = optimaValues[i];
289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    } else {
290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        mIX = Double.NaN;
291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                        mIY = Double.NaN;
292dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    }
293dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
294dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optima[i + 1]       = currX;
295dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                optimaValues[i + 1] = currY;
296dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                currX = optima[j];
297dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                currY = optimaValues[j];
298dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
299dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
300dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
301dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (Double.isNaN(optima[0])) {
302dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw new OptimizationException(
303dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
304dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    starts);
305dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
306dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
307dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // return the found point given the best objective function value
308dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optima[0];
309dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
310dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
311dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
312dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
313dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double optimize(final UnivariateRealFunction f, final GoalType goalType,
314dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                           final double min, final double max, final double startValue)
315dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throws ConvergenceException, FunctionEvaluationException {
316dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return optimize(f, goalType, min, max);
317dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
318dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond}
319