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 */
017package org.apache.commons.math4.legacy.optim.nonlinear.scalar;
018
019import java.util.ArrayList;
020import java.util.Collections;
021import java.util.Comparator;
022import java.util.List;
023import java.util.function.Supplier;
024
025import org.apache.commons.math4.legacy.optim.BaseMultiStartMultivariateOptimizer;
026import org.apache.commons.math4.legacy.optim.PointValuePair;
027
028/**
029 * Multi-start optimizer.
030 *
031 * This class wraps an optimizer in order to use it several times in
032 * turn with different starting points (trying to avoid being trapped
033 * in a local extremum when looking for a global one).
034 *
035 * @since 3.0
036 */
037public class MultiStartMultivariateOptimizer
038    extends BaseMultiStartMultivariateOptimizer<PointValuePair> {
039    /** Underlying optimizer. */
040    private final MultivariateOptimizer optimizer;
041    /** Found optima. */
042    private final List<PointValuePair> optima = new ArrayList<>();
043
044    /**
045     * Create a multi-start optimizer from a single-start optimizer.
046     *
047     * @param optimizer Single-start optimizer to wrap.
048     * @param starts Number of starts to perform.
049     * If {@code starts == 1}, the result will be same as if {@code optimizer}
050     * is called directly.
051     * @param generator Generator to use for restarts.
052     * @throws org.apache.commons.math4.legacy.exception.NullArgumentException NullArgumentException if {@code optimizer} or {@code generator}
053     * is {@code null}.
054     * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException NotStrictlyPositiveException if {@code starts < 1}.
055     */
056    public MultiStartMultivariateOptimizer(final MultivariateOptimizer optimizer,
057                                           final int starts,
058                                           final Supplier<double[]> generator) {
059        super(optimizer, starts, generator);
060        this.optimizer = optimizer;
061    }
062
063    /**
064     * {@inheritDoc}
065     */
066    @Override
067    public PointValuePair[] getOptima() {
068        Collections.sort(optima, getPairComparator());
069        return optima.toArray(new PointValuePair[0]);
070    }
071
072    /**
073     * {@inheritDoc}
074     */
075    @Override
076    protected void store(PointValuePair optimum) {
077        optima.add(optimum);
078    }
079
080    /**
081     * {@inheritDoc}
082     */
083    @Override
084    protected void clear() {
085        optima.clear();
086    }
087
088    /**
089     * @return a comparator for sorting the optima.
090     */
091    private Comparator<PointValuePair> getPairComparator() {
092        return new Comparator<PointValuePair>() {
093            /** {@inheritDoc} */
094            @Override
095            public int compare(final PointValuePair o1,
096                               final PointValuePair o2) {
097                if (o1 == null) {
098                    return (o2 == null) ? 0 : 1;
099                } else if (o2 == null) {
100                    return -1;
101                }
102                final double v1 = o1.getValue();
103                final double v2 = o2.getValue();
104                return (optimizer.getGoalType() == GoalType.MINIMIZE) ?
105                    Double.compare(v1, v2) : Double.compare(v2, v1);
106            }
107        };
108    }
109}