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    
018    package org.apache.commons.math3.optimization.direct;
019    
020    import org.apache.commons.math3.analysis.MultivariateFunction;
021    import org.apache.commons.math3.analysis.UnivariateFunction;
022    import org.apache.commons.math3.analysis.function.Logit;
023    import org.apache.commons.math3.analysis.function.Sigmoid;
024    import org.apache.commons.math3.exception.DimensionMismatchException;
025    import org.apache.commons.math3.exception.NumberIsTooSmallException;
026    import org.apache.commons.math3.util.FastMath;
027    import org.apache.commons.math3.util.MathUtils;
028    
029    /**
030     * <p>Adapter for mapping bounded {@link MultivariateFunction} to unbounded ones.</p>
031     *
032     * <p>
033     * This adapter can be used to wrap functions subject to simple bounds on
034     * parameters so they can be used by optimizers that do <em>not</em> directly
035     * support simple bounds.
036     * </p>
037     * <p>
038     * The principle is that the user function that will be wrapped will see its
039     * parameters bounded as required, i.e when its {@code value} method is called
040     * with argument array {@code point}, the elements array will fulfill requirement
041     * {@code lower[i] <= point[i] <= upper[i]} for all i. Some of the components
042     * may be unbounded or bounded only on one side if the corresponding bound is
043     * set to an infinite value. The optimizer will not manage the user function by
044     * itself, but it will handle this adapter and it is this adapter that will take
045     * care the bounds are fulfilled. The adapter {@link #value(double[])} method will
046     * be called by the optimizer with unbound parameters, and the adapter will map
047     * the unbounded value to the bounded range using appropriate functions like
048     * {@link Sigmoid} for double bounded elements for example.
049     * </p>
050     * <p>
051     * As the optimizer sees only unbounded parameters, it should be noted that the
052     * start point or simplex expected by the optimizer should be unbounded, so the
053     * user is responsible for converting his bounded point to unbounded by calling
054     * {@link #boundedToUnbounded(double[])} before providing them to the optimizer.
055     * For the same reason, the point returned by the {@link
056     * org.apache.commons.math3.optimization.BaseMultivariateOptimizer#optimize(int,
057     * MultivariateFunction, org.apache.commons.math3.optimization.GoalType, double[])}
058     * method is unbounded. So to convert this point to bounded, users must call
059     * {@link #unboundedToBounded(double[])} by themselves!</p>
060     * <p>
061     * This adapter is only a poor man solution to simple bounds optimization constraints
062     * that can be used with simple optimizers like {@link SimplexOptimizer} with {@link
063     * NelderMeadSimplex} or {@link MultiDirectionalSimplex}. A better solution is to use
064     * an optimizer that directly supports simple bounds like {@link CMAESOptimizer} or
065     * {@link BOBYQAOptimizer}. One caveat of this poor man solution is that behavior near
066     * the bounds may be numerically unstable as bounds are mapped from infinite values.
067     * Another caveat is that convergence values are evaluated by the optimizer with respect
068     * to unbounded variables, so there will be scales differences when converted to bounded
069     * variables.
070     * </p>
071     *
072     * @see MultivariateFunctionPenaltyAdapter
073     *
074     * @version $Id: MultivariateFunctionMappingAdapter.java 1422230 2012-12-15 12:11:13Z erans $
075     * @deprecated As of 3.1 (to be removed in 4.0).
076     * @since 3.0
077     */
078    
079    @Deprecated
080    public class MultivariateFunctionMappingAdapter implements MultivariateFunction {
081    
082        /** Underlying bounded function. */
083        private final MultivariateFunction bounded;
084    
085        /** Mapping functions. */
086        private final Mapper[] mappers;
087    
088        /** Simple constructor.
089         * @param bounded bounded function
090         * @param lower lower bounds for each element of the input parameters array
091         * (some elements may be set to {@code Double.NEGATIVE_INFINITY} for
092         * unbounded values)
093         * @param upper upper bounds for each element of the input parameters array
094         * (some elements may be set to {@code Double.POSITIVE_INFINITY} for
095         * unbounded values)
096         * @exception DimensionMismatchException if lower and upper bounds are not
097         * consistent, either according to dimension or to values
098         */
099        public MultivariateFunctionMappingAdapter(final MultivariateFunction bounded,
100                                                      final double[] lower, final double[] upper) {
101    
102            // safety checks
103            MathUtils.checkNotNull(lower);
104            MathUtils.checkNotNull(upper);
105            if (lower.length != upper.length) {
106                throw new DimensionMismatchException(lower.length, upper.length);
107            }
108            for (int i = 0; i < lower.length; ++i) {
109                // note the following test is written in such a way it also fails for NaN
110                if (!(upper[i] >= lower[i])) {
111                    throw new NumberIsTooSmallException(upper[i], lower[i], true);
112                }
113            }
114    
115            this.bounded = bounded;
116            this.mappers = new Mapper[lower.length];
117            for (int i = 0; i < mappers.length; ++i) {
118                if (Double.isInfinite(lower[i])) {
119                    if (Double.isInfinite(upper[i])) {
120                        // element is unbounded, no transformation is needed
121                        mappers[i] = new NoBoundsMapper();
122                    } else {
123                        // element is simple-bounded on the upper side
124                        mappers[i] = new UpperBoundMapper(upper[i]);
125                    }
126                } else {
127                    if (Double.isInfinite(upper[i])) {
128                        // element is simple-bounded on the lower side
129                        mappers[i] = new LowerBoundMapper(lower[i]);
130                    } else {
131                        // element is double-bounded
132                        mappers[i] = new LowerUpperBoundMapper(lower[i], upper[i]);
133                    }
134                }
135            }
136    
137        }
138    
139        /** Map an array from unbounded to bounded.
140         * @param point unbounded value
141         * @return bounded value
142         */
143        public double[] unboundedToBounded(double[] point) {
144    
145            // map unbounded input point to bounded point
146            final double[] mapped = new double[mappers.length];
147            for (int i = 0; i < mappers.length; ++i) {
148                mapped[i] = mappers[i].unboundedToBounded(point[i]);
149            }
150    
151            return mapped;
152    
153        }
154    
155        /** Map an array from bounded to unbounded.
156         * @param point bounded value
157         * @return unbounded value
158         */
159        public double[] boundedToUnbounded(double[] point) {
160    
161            // map bounded input point to unbounded point
162            final double[] mapped = new double[mappers.length];
163            for (int i = 0; i < mappers.length; ++i) {
164                mapped[i] = mappers[i].boundedToUnbounded(point[i]);
165            }
166    
167            return mapped;
168    
169        }
170    
171        /** Compute the underlying function value from an unbounded point.
172         * <p>
173         * This method simply bounds the unbounded point using the mappings
174         * set up at construction and calls the underlying function using
175         * the bounded point.
176         * </p>
177         * @param point unbounded value
178         * @return underlying function value
179         * @see #unboundedToBounded(double[])
180         */
181        public double value(double[] point) {
182            return bounded.value(unboundedToBounded(point));
183        }
184    
185        /** Mapping interface. */
186        private interface Mapper {
187    
188            /** Map a value from unbounded to bounded.
189             * @param y unbounded value
190             * @return bounded value
191             */
192            double unboundedToBounded(double y);
193    
194            /** Map a value from bounded to unbounded.
195             * @param x bounded value
196             * @return unbounded value
197             */
198            double boundedToUnbounded(double x);
199    
200        }
201    
202        /** Local class for no bounds mapping. */
203        private static class NoBoundsMapper implements Mapper {
204    
205            /** Simple constructor.
206             */
207            public NoBoundsMapper() {
208            }
209    
210            /** {@inheritDoc} */
211            public double unboundedToBounded(final double y) {
212                return y;
213            }
214    
215            /** {@inheritDoc} */
216            public double boundedToUnbounded(final double x) {
217                return x;
218            }
219    
220        }
221    
222        /** Local class for lower bounds mapping. */
223        private static class LowerBoundMapper implements Mapper {
224    
225            /** Low bound. */
226            private final double lower;
227    
228            /** Simple constructor.
229             * @param lower lower bound
230             */
231            public LowerBoundMapper(final double lower) {
232                this.lower = lower;
233            }
234    
235            /** {@inheritDoc} */
236            public double unboundedToBounded(final double y) {
237                return lower + FastMath.exp(y);
238            }
239    
240            /** {@inheritDoc} */
241            public double boundedToUnbounded(final double x) {
242                return FastMath.log(x - lower);
243            }
244    
245        }
246    
247        /** Local class for upper bounds mapping. */
248        private static class UpperBoundMapper implements Mapper {
249    
250            /** Upper bound. */
251            private final double upper;
252    
253            /** Simple constructor.
254             * @param upper upper bound
255             */
256            public UpperBoundMapper(final double upper) {
257                this.upper = upper;
258            }
259    
260            /** {@inheritDoc} */
261            public double unboundedToBounded(final double y) {
262                return upper - FastMath.exp(-y);
263            }
264    
265            /** {@inheritDoc} */
266            public double boundedToUnbounded(final double x) {
267                return -FastMath.log(upper - x);
268            }
269    
270        }
271    
272        /** Local class for lower and bounds mapping. */
273        private static class LowerUpperBoundMapper implements Mapper {
274    
275            /** Function from unbounded to bounded. */
276            private final UnivariateFunction boundingFunction;
277    
278            /** Function from bounded to unbounded. */
279            private final UnivariateFunction unboundingFunction;
280    
281            /** Simple constructor.
282             * @param lower lower bound
283             * @param upper upper bound
284             */
285            public LowerUpperBoundMapper(final double lower, final double upper) {
286                boundingFunction   = new Sigmoid(lower, upper);
287                unboundingFunction = new Logit(lower, upper);
288            }
289    
290            /** {@inheritDoc} */
291            public double unboundedToBounded(final double y) {
292                return boundingFunction.value(y);
293            }
294    
295            /** {@inheritDoc} */
296            public double boundedToUnbounded(final double x) {
297                return unboundingFunction.value(x);
298            }
299    
300        }
301    
302    }