001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.math3.optimization.univariate; 019 020import java.util.Arrays; 021import java.util.Comparator; 022 023import org.apache.commons.math3.analysis.UnivariateFunction; 024import org.apache.commons.math3.exception.MathIllegalStateException; 025import org.apache.commons.math3.exception.NotStrictlyPositiveException; 026import org.apache.commons.math3.exception.NullArgumentException; 027import org.apache.commons.math3.exception.util.LocalizedFormats; 028import org.apache.commons.math3.random.RandomGenerator; 029import org.apache.commons.math3.optimization.GoalType; 030import org.apache.commons.math3.optimization.ConvergenceChecker; 031 032/** 033 * Special implementation of the {@link UnivariateOptimizer} interface 034 * adding multi-start features to an existing optimizer. 035 * 036 * This class wraps a classical optimizer to use it several times in 037 * turn with different starting points in order to avoid being trapped 038 * into a local extremum when looking for a global one. 039 * 040 * @param <FUNC> Type of the objective function to be optimized. 041 * 042 * @deprecated As of 3.1 (to be removed in 4.0). 043 * @since 3.0 044 */ 045@Deprecated 046public class UnivariateMultiStartOptimizer<FUNC extends UnivariateFunction> 047 implements BaseUnivariateOptimizer<FUNC> { 048 /** Underlying classical optimizer. */ 049 private final BaseUnivariateOptimizer<FUNC> optimizer; 050 /** Maximal number of evaluations allowed. */ 051 private int maxEvaluations; 052 /** Number of evaluations already performed for all starts. */ 053 private int totalEvaluations; 054 /** Number of starts to go. */ 055 private int starts; 056 /** Random generator for multi-start. */ 057 private RandomGenerator generator; 058 /** Found optima. */ 059 private UnivariatePointValuePair[] optima; 060 061 /** 062 * Create a multi-start optimizer from a single-start optimizer. 063 * 064 * @param optimizer Single-start optimizer to wrap. 065 * @param starts Number of starts to perform. If {@code starts == 1}, 066 * the {@code optimize} methods will return the same solution as 067 * {@code optimizer} would. 068 * @param generator Random generator to use for restarts. 069 * @throws NullArgumentException if {@code optimizer} or {@code generator} 070 * is {@code null}. 071 * @throws NotStrictlyPositiveException if {@code starts < 1}. 072 */ 073 public UnivariateMultiStartOptimizer(final BaseUnivariateOptimizer<FUNC> optimizer, 074 final int starts, 075 final RandomGenerator generator) { 076 if (optimizer == null || 077 generator == null) { 078 throw new NullArgumentException(); 079 } 080 if (starts < 1) { 081 throw new NotStrictlyPositiveException(starts); 082 } 083 084 this.optimizer = optimizer; 085 this.starts = starts; 086 this.generator = generator; 087 } 088 089 /** 090 * {@inheritDoc} 091 */ 092 public ConvergenceChecker<UnivariatePointValuePair> getConvergenceChecker() { 093 return optimizer.getConvergenceChecker(); 094 } 095 096 /** {@inheritDoc} */ 097 public int getMaxEvaluations() { 098 return maxEvaluations; 099 } 100 101 /** {@inheritDoc} */ 102 public int getEvaluations() { 103 return totalEvaluations; 104 } 105 106 /** 107 * Get all the optima found during the last call to {@link 108 * #optimize(int,UnivariateFunction,GoalType,double,double) optimize}. 109 * The optimizer stores all the optima found during a set of 110 * restarts. The {@link #optimize(int,UnivariateFunction,GoalType,double,double) optimize} 111 * method returns the best point only. This method returns all the points 112 * found at the end of each starts, including the best one already 113 * returned by the {@link #optimize(int,UnivariateFunction,GoalType,double,double) optimize} 114 * method. 115 * <br/> 116 * The returned array as one element for each start as specified 117 * in the constructor. It is ordered with the results from the 118 * runs that did converge first, sorted from best to worst 119 * objective value (i.e in ascending order if minimizing and in 120 * descending order if maximizing), followed by {@code null} elements 121 * corresponding to the runs that did not converge. This means all 122 * elements will be {@code null} if the {@link 123 * #optimize(int,UnivariateFunction,GoalType,double,double) optimize} 124 * method did throw an exception. 125 * This also means that if the first element is not {@code null}, it is 126 * the best point found across all starts. 127 * 128 * @return an array containing the optima. 129 * @throws MathIllegalStateException if {@link 130 * #optimize(int,UnivariateFunction,GoalType,double,double) optimize} 131 * has not been called. 132 */ 133 public UnivariatePointValuePair[] getOptima() { 134 if (optima == null) { 135 throw new MathIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET); 136 } 137 return optima.clone(); 138 } 139 140 /** {@inheritDoc} */ 141 public UnivariatePointValuePair optimize(int maxEval, final FUNC f, 142 final GoalType goal, 143 final double min, final double max) { 144 return optimize(maxEval, f, goal, min, max, min + 0.5 * (max - min)); 145 } 146 147 /** {@inheritDoc} */ 148 public UnivariatePointValuePair optimize(int maxEval, final FUNC f, 149 final GoalType goal, 150 final double min, final double max, 151 final double startValue) { 152 RuntimeException lastException = null; 153 optima = new UnivariatePointValuePair[starts]; 154 totalEvaluations = 0; 155 156 // Multi-start loop. 157 for (int i = 0; i < starts; ++i) { 158 // CHECKSTYLE: stop IllegalCatch 159 try { 160 final double s = (i == 0) ? startValue : min + generator.nextDouble() * (max - min); 161 optima[i] = optimizer.optimize(maxEval - totalEvaluations, f, goal, min, max, s); 162 } catch (RuntimeException mue) { 163 lastException = mue; 164 optima[i] = null; 165 } 166 // CHECKSTYLE: resume IllegalCatch 167 168 totalEvaluations += optimizer.getEvaluations(); 169 } 170 171 sortPairs(goal); 172 173 if (optima[0] == null) { 174 throw lastException; // cannot be null if starts >=1 175 } 176 177 // Return the point with the best objective function value. 178 return optima[0]; 179 } 180 181 /** 182 * Sort the optima from best to worst, followed by {@code null} elements. 183 * 184 * @param goal Goal type. 185 */ 186 private void sortPairs(final GoalType goal) { 187 Arrays.sort(optima, new Comparator<UnivariatePointValuePair>() { 188 /** {@inheritDoc} */ 189 public int compare(final UnivariatePointValuePair o1, 190 final UnivariatePointValuePair o2) { 191 if (o1 == null) { 192 return (o2 == null) ? 0 : 1; 193 } else if (o2 == null) { 194 return -1; 195 } 196 final double v1 = o1.getValue(); 197 final double v2 = o2.getValue(); 198 return (goal == GoalType.MINIMIZE) ? 199 Double.compare(v1, v2) : Double.compare(v2, v1); 200 } 201 }); 202 } 203}