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