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.analysis;
019
020import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
021import org.apache.commons.math3.analysis.differentiation.MultivariateDifferentiableFunction;
022import org.apache.commons.math3.analysis.differentiation.MultivariateDifferentiableVectorFunction;
023import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiableFunction;
024import org.apache.commons.math3.analysis.function.Identity;
025import org.apache.commons.math3.exception.DimensionMismatchException;
026import org.apache.commons.math3.exception.NotStrictlyPositiveException;
027import org.apache.commons.math3.exception.NumberIsTooLargeException;
028import org.apache.commons.math3.exception.util.LocalizedFormats;
029
030/**
031 * Utilities for manipulating function objects.
032 *
033 * @since 3.0
034 */
035public class FunctionUtils {
036    /**
037     * Class only contains static methods.
038     */
039    private FunctionUtils() {}
040
041    /**
042     * Composes functions.
043     * <p>
044     * The functions in the argument list are composed sequentially, in the
045     * given order.  For example, compose(f1,f2,f3) acts like f1(f2(f3(x))).</p>
046     *
047     * @param f List of functions.
048     * @return the composite function.
049     */
050    public static UnivariateFunction compose(final UnivariateFunction ... f) {
051        return new UnivariateFunction() {
052            /** {@inheritDoc} */
053            public double value(double x) {
054                double r = x;
055                for (int i = f.length - 1; i >= 0; i--) {
056                    r = f[i].value(r);
057                }
058                return r;
059            }
060        };
061    }
062
063    /**
064     * Composes functions.
065     * <p>
066     * The functions in the argument list are composed sequentially, in the
067     * given order.  For example, compose(f1,f2,f3) acts like f1(f2(f3(x))).</p>
068     *
069     * @param f List of functions.
070     * @return the composite function.
071     * @since 3.1
072     */
073    public static UnivariateDifferentiableFunction compose(final UnivariateDifferentiableFunction ... f) {
074        return new UnivariateDifferentiableFunction() {
075
076            /** {@inheritDoc} */
077            public double value(final double t) {
078                double r = t;
079                for (int i = f.length - 1; i >= 0; i--) {
080                    r = f[i].value(r);
081                }
082                return r;
083            }
084
085            /** {@inheritDoc} */
086            public DerivativeStructure value(final DerivativeStructure t) {
087                DerivativeStructure r = t;
088                for (int i = f.length - 1; i >= 0; i--) {
089                    r = f[i].value(r);
090                }
091                return r;
092            }
093
094        };
095    }
096
097    /**
098     * Composes functions.
099     * <p>
100     * The functions in the argument list are composed sequentially, in the
101     * given order.  For example, compose(f1,f2,f3) acts like f1(f2(f3(x))).</p>
102     *
103     * @param f List of functions.
104     * @return the composite function.
105     * @deprecated as of 3.1 replaced by {@link #compose(UnivariateDifferentiableFunction...)}
106     */
107    @Deprecated
108    public static DifferentiableUnivariateFunction compose(final DifferentiableUnivariateFunction ... f) {
109        return new DifferentiableUnivariateFunction() {
110            /** {@inheritDoc} */
111            public double value(double x) {
112                double r = x;
113                for (int i = f.length - 1; i >= 0; i--) {
114                    r = f[i].value(r);
115                }
116                return r;
117            }
118
119            /** {@inheritDoc} */
120            public UnivariateFunction derivative() {
121                return new UnivariateFunction() {
122                    /** {@inheritDoc} */
123                    public double value(double x) {
124                        double p = 1;
125                        double r = x;
126                        for (int i = f.length - 1; i >= 0; i--) {
127                            p *= f[i].derivative().value(r);
128                            r = f[i].value(r);
129                        }
130                        return p;
131                    }
132                };
133            }
134        };
135    }
136
137    /**
138     * Adds functions.
139     *
140     * @param f List of functions.
141     * @return a function that computes the sum of the functions.
142     */
143    public static UnivariateFunction add(final UnivariateFunction ... f) {
144        return new UnivariateFunction() {
145            /** {@inheritDoc} */
146            public double value(double x) {
147                double r = f[0].value(x);
148                for (int i = 1; i < f.length; i++) {
149                    r += f[i].value(x);
150                }
151                return r;
152            }
153        };
154    }
155
156    /**
157     * Adds functions.
158     *
159     * @param f List of functions.
160     * @return a function that computes the sum of the functions.
161     * @since 3.1
162     */
163    public static UnivariateDifferentiableFunction add(final UnivariateDifferentiableFunction ... f) {
164        return new UnivariateDifferentiableFunction() {
165
166            /** {@inheritDoc} */
167            public double value(final double t) {
168                double r = f[0].value(t);
169                for (int i = 1; i < f.length; i++) {
170                    r += f[i].value(t);
171                }
172                return r;
173            }
174
175            /** {@inheritDoc}
176             * @throws DimensionMismatchException if functions are not consistent with each other
177             */
178            public DerivativeStructure value(final DerivativeStructure t)
179                throws DimensionMismatchException {
180                DerivativeStructure r = f[0].value(t);
181                for (int i = 1; i < f.length; i++) {
182                    r = r.add(f[i].value(t));
183                }
184                return r;
185            }
186
187        };
188    }
189
190    /**
191     * Adds functions.
192     *
193     * @param f List of functions.
194     * @return a function that computes the sum of the functions.
195     * @deprecated as of 3.1 replaced by {@link #add(UnivariateDifferentiableFunction...)}
196     */
197    @Deprecated
198    public static DifferentiableUnivariateFunction add(final DifferentiableUnivariateFunction ... f) {
199        return new DifferentiableUnivariateFunction() {
200            /** {@inheritDoc} */
201            public double value(double x) {
202                double r = f[0].value(x);
203                for (int i = 1; i < f.length; i++) {
204                    r += f[i].value(x);
205                }
206                return r;
207            }
208
209            /** {@inheritDoc} */
210            public UnivariateFunction derivative() {
211                return new UnivariateFunction() {
212                    /** {@inheritDoc} */
213                    public double value(double x) {
214                        double r = f[0].derivative().value(x);
215                        for (int i = 1; i < f.length; i++) {
216                            r += f[i].derivative().value(x);
217                        }
218                        return r;
219                    }
220                };
221            }
222        };
223    }
224
225    /**
226     * Multiplies functions.
227     *
228     * @param f List of functions.
229     * @return a function that computes the product of the functions.
230     */
231    public static UnivariateFunction multiply(final UnivariateFunction ... f) {
232        return new UnivariateFunction() {
233            /** {@inheritDoc} */
234            public double value(double x) {
235                double r = f[0].value(x);
236                for (int i = 1; i < f.length; i++) {
237                    r *= f[i].value(x);
238                }
239                return r;
240            }
241        };
242    }
243
244    /**
245     * Multiplies functions.
246     *
247     * @param f List of functions.
248     * @return a function that computes the product of the functions.
249     * @since 3.1
250     */
251    public static UnivariateDifferentiableFunction multiply(final UnivariateDifferentiableFunction ... f) {
252        return new UnivariateDifferentiableFunction() {
253
254            /** {@inheritDoc} */
255            public double value(final double t) {
256                double r = f[0].value(t);
257                for (int i = 1; i < f.length; i++) {
258                    r  *= f[i].value(t);
259                }
260                return r;
261            }
262
263            /** {@inheritDoc} */
264            public DerivativeStructure value(final DerivativeStructure t) {
265                DerivativeStructure r = f[0].value(t);
266                for (int i = 1; i < f.length; i++) {
267                    r = r.multiply(f[i].value(t));
268                }
269                return r;
270            }
271
272        };
273    }
274
275    /**
276     * Multiplies functions.
277     *
278     * @param f List of functions.
279     * @return a function that computes the product of the functions.
280     * @deprecated as of 3.1 replaced by {@link #multiply(UnivariateDifferentiableFunction...)}
281     */
282    @Deprecated
283    public static DifferentiableUnivariateFunction multiply(final DifferentiableUnivariateFunction ... f) {
284        return new DifferentiableUnivariateFunction() {
285            /** {@inheritDoc} */
286            public double value(double x) {
287                double r = f[0].value(x);
288                for (int i = 1; i < f.length; i++) {
289                    r *= f[i].value(x);
290                }
291                return r;
292            }
293
294            /** {@inheritDoc} */
295            public UnivariateFunction derivative() {
296                return new UnivariateFunction() {
297                    /** {@inheritDoc} */
298                    public double value(double x) {
299                        double sum = 0;
300                        for (int i = 0; i < f.length; i++) {
301                            double prod = f[i].derivative().value(x);
302                            for (int j = 0; j < f.length; j++) {
303                                if (i != j) {
304                                    prod *= f[j].value(x);
305                                }
306                            }
307                            sum += prod;
308                        }
309                        return sum;
310                    }
311                };
312            }
313        };
314    }
315
316    /**
317     * Returns the univariate function
318     * {@code h(x) = combiner(f(x), g(x)).}
319     *
320     * @param combiner Combiner function.
321     * @param f Function.
322     * @param g Function.
323     * @return the composite function.
324     */
325    public static UnivariateFunction combine(final BivariateFunction combiner,
326                                             final UnivariateFunction f,
327                                             final UnivariateFunction g) {
328        return new UnivariateFunction() {
329            /** {@inheritDoc} */
330            public double value(double x) {
331                return combiner.value(f.value(x), g.value(x));
332            }
333        };
334    }
335
336    /**
337     * Returns a MultivariateFunction h(x[]) defined by <pre> <code>
338     * h(x[]) = combiner(...combiner(combiner(initialValue,f(x[0])),f(x[1]))...),f(x[x.length-1]))
339     * </code></pre>
340     *
341     * @param combiner Combiner function.
342     * @param f Function.
343     * @param initialValue Initial value.
344     * @return a collector function.
345     */
346    public static MultivariateFunction collector(final BivariateFunction combiner,
347                                                 final UnivariateFunction f,
348                                                 final double initialValue) {
349        return new MultivariateFunction() {
350            /** {@inheritDoc} */
351            public double value(double[] point) {
352                double result = combiner.value(initialValue, f.value(point[0]));
353                for (int i = 1; i < point.length; i++) {
354                    result = combiner.value(result, f.value(point[i]));
355                }
356                return result;
357            }
358        };
359    }
360
361    /**
362     * Returns a MultivariateFunction h(x[]) defined by <pre> <code>
363     * h(x[]) = combiner(...combiner(combiner(initialValue,x[0]),x[1])...),x[x.length-1])
364     * </code></pre>
365     *
366     * @param combiner Combiner function.
367     * @param initialValue Initial value.
368     * @return a collector function.
369     */
370    public static MultivariateFunction collector(final BivariateFunction combiner,
371                                                 final double initialValue) {
372        return collector(combiner, new Identity(), initialValue);
373    }
374
375    /**
376     * Creates a unary function by fixing the first argument of a binary function.
377     *
378     * @param f Binary function.
379     * @param fixed value to which the first argument of {@code f} is set.
380     * @return the unary function h(x) = f(fixed, x)
381     */
382    public static UnivariateFunction fix1stArgument(final BivariateFunction f,
383                                                    final double fixed) {
384        return new UnivariateFunction() {
385            /** {@inheritDoc} */
386            public double value(double x) {
387                return f.value(fixed, x);
388            }
389        };
390    }
391    /**
392     * Creates a unary function by fixing the second argument of a binary function.
393     *
394     * @param f Binary function.
395     * @param fixed value to which the second argument of {@code f} is set.
396     * @return the unary function h(x) = f(x, fixed)
397     */
398    public static UnivariateFunction fix2ndArgument(final BivariateFunction f,
399                                                    final double fixed) {
400        return new UnivariateFunction() {
401            /** {@inheritDoc} */
402            public double value(double x) {
403                return f.value(x, fixed);
404            }
405        };
406    }
407
408    /**
409     * Samples the specified univariate real function on the specified interval.
410     * <p>
411     * The interval is divided equally into {@code n} sections and sample points
412     * are taken from {@code min} to {@code max - (max - min) / n}; therefore
413     * {@code f} is not sampled at the upper bound {@code max}.</p>
414     *
415     * @param f Function to be sampled
416     * @param min Lower bound of the interval (included).
417     * @param max Upper bound of the interval (excluded).
418     * @param n Number of sample points.
419     * @return the array of samples.
420     * @throws NumberIsTooLargeException if the lower bound {@code min} is
421     * greater than, or equal to the upper bound {@code max}.
422     * @throws NotStrictlyPositiveException if the number of sample points
423     * {@code n} is negative.
424     */
425    public static double[] sample(UnivariateFunction f, double min, double max, int n)
426       throws NumberIsTooLargeException, NotStrictlyPositiveException {
427
428        if (n <= 0) {
429            throw new NotStrictlyPositiveException(
430                    LocalizedFormats.NOT_POSITIVE_NUMBER_OF_SAMPLES,
431                    Integer.valueOf(n));
432        }
433        if (min >= max) {
434            throw new NumberIsTooLargeException(min, max, false);
435        }
436
437        final double[] s = new double[n];
438        final double h = (max - min) / n;
439        for (int i = 0; i < n; i++) {
440            s[i] = f.value(min + i * h);
441        }
442        return s;
443    }
444
445    /**
446     * Convert a {@link UnivariateDifferentiableFunction} into a {@link DifferentiableUnivariateFunction}.
447     *
448     * @param f function to convert
449     * @return converted function
450     * @deprecated this conversion method is temporary in version 3.1, as the {@link
451     * DifferentiableUnivariateFunction} interface itself is deprecated
452     */
453    @Deprecated
454    public static DifferentiableUnivariateFunction toDifferentiableUnivariateFunction(final UnivariateDifferentiableFunction f) {
455        return new DifferentiableUnivariateFunction() {
456
457            /** {@inheritDoc} */
458            public double value(final double x) {
459                return f.value(x);
460            }
461
462            /** {@inheritDoc} */
463            public UnivariateFunction derivative() {
464                return new UnivariateFunction() {
465                    /** {@inheritDoc} */
466                    public double value(final double x) {
467                        return f.value(new DerivativeStructure(1, 1, 0, x)).getPartialDerivative(1);
468                    }
469                };
470            }
471
472        };
473    }
474
475    /**
476     * Convert a {@link DifferentiableUnivariateFunction} into a {@link UnivariateDifferentiableFunction}.
477     * <p>
478     * Note that the converted function is able to handle {@link DerivativeStructure} up to order one.
479     * If the function is called with higher order, a {@link NumberIsTooLargeException} is thrown.
480     * </p>
481     * @param f function to convert
482     * @return converted function
483     * @deprecated this conversion method is temporary in version 3.1, as the {@link
484     * DifferentiableUnivariateFunction} interface itself is deprecated
485     */
486    @Deprecated
487    public static UnivariateDifferentiableFunction toUnivariateDifferential(final DifferentiableUnivariateFunction f) {
488        return new UnivariateDifferentiableFunction() {
489
490            /** {@inheritDoc} */
491            public double value(final double x) {
492                return f.value(x);
493            }
494
495            /** {@inheritDoc}
496             * @exception NumberIsTooLargeException if derivation order is greater than 1
497             */
498            public DerivativeStructure value(final DerivativeStructure t)
499                throws NumberIsTooLargeException {
500                switch (t.getOrder()) {
501                    case 0 :
502                        return new DerivativeStructure(t.getFreeParameters(), 0, f.value(t.getValue()));
503                    case 1 : {
504                        final int parameters = t.getFreeParameters();
505                        final double[] derivatives = new double[parameters + 1];
506                        derivatives[0] = f.value(t.getValue());
507                        final double fPrime = f.derivative().value(t.getValue());
508                        int[] orders = new int[parameters];
509                        for (int i = 0; i < parameters; ++i) {
510                            orders[i] = 1;
511                            derivatives[i + 1] = fPrime * t.getPartialDerivative(orders);
512                            orders[i] = 0;
513                        }
514                        return new DerivativeStructure(parameters, 1, derivatives);
515                    }
516                    default :
517                        throw new NumberIsTooLargeException(t.getOrder(), 1, true);
518                }
519            }
520
521        };
522    }
523
524    /**
525     * Convert a {@link MultivariateDifferentiableFunction} into a {@link DifferentiableMultivariateFunction}.
526     *
527     * @param f function to convert
528     * @return converted function
529     * @deprecated this conversion method is temporary in version 3.1, as the {@link
530     * DifferentiableMultivariateFunction} interface itself is deprecated
531     */
532    @Deprecated
533    public static DifferentiableMultivariateFunction toDifferentiableMultivariateFunction(final MultivariateDifferentiableFunction f) {
534        return new DifferentiableMultivariateFunction() {
535
536            /** {@inheritDoc} */
537            public double value(final double[] x) {
538                return f.value(x);
539            }
540
541            /** {@inheritDoc} */
542            public MultivariateFunction partialDerivative(final int k) {
543                return new MultivariateFunction() {
544                    /** {@inheritDoc} */
545                    public double value(final double[] x) {
546
547                        final int n = x.length;
548
549                        // delegate computation to underlying function
550                        final DerivativeStructure[] dsX = new DerivativeStructure[n];
551                        for (int i = 0; i < n; ++i) {
552                            if (i == k) {
553                                dsX[i] = new DerivativeStructure(1, 1, 0, x[i]);
554                            } else {
555                                dsX[i] = new DerivativeStructure(1, 1, x[i]);
556                            }
557                        }
558                        final DerivativeStructure y = f.value(dsX);
559
560                        // extract partial derivative
561                        return y.getPartialDerivative(1);
562
563                    }
564                };
565            }
566
567            /** {@inheritDoc} */
568            public MultivariateVectorFunction gradient() {
569                return new MultivariateVectorFunction() {
570                    /** {@inheritDoc} */
571                    public double[] value(final double[] x) {
572
573                        final int n = x.length;
574
575                        // delegate computation to underlying function
576                        final DerivativeStructure[] dsX = new DerivativeStructure[n];
577                        for (int i = 0; i < n; ++i) {
578                            dsX[i] = new DerivativeStructure(n, 1, i, x[i]);
579                        }
580                        final DerivativeStructure y = f.value(dsX);
581
582                        // extract gradient
583                        final double[] gradient = new double[n];
584                        final int[] orders = new int[n];
585                        for (int i = 0; i < n; ++i) {
586                            orders[i]   = 1;
587                            gradient[i] = y.getPartialDerivative(orders);
588                            orders[i]   = 0;
589                        }
590
591                        return gradient;
592
593                    }
594                };
595            }
596
597        };
598    }
599
600    /**
601     * Convert a {@link DifferentiableMultivariateFunction} into a {@link MultivariateDifferentiableFunction}.
602     * <p>
603     * Note that the converted function is able to handle {@link DerivativeStructure} elements
604     * that all have the same number of free parameters and order, and with order at most 1.
605     * If the function is called with inconsistent numbers of free parameters or higher order, a
606     * {@link DimensionMismatchException} or a {@link NumberIsTooLargeException} will be thrown.
607     * </p>
608     * @param f function to convert
609     * @return converted function
610     * @deprecated this conversion method is temporary in version 3.1, as the {@link
611     * DifferentiableMultivariateFunction} interface itself is deprecated
612     */
613    @Deprecated
614    public static MultivariateDifferentiableFunction toMultivariateDifferentiableFunction(final DifferentiableMultivariateFunction f) {
615        return new MultivariateDifferentiableFunction() {
616
617            /** {@inheritDoc} */
618            public double value(final double[] x) {
619                return f.value(x);
620            }
621
622            /** {@inheritDoc}
623             * @exception NumberIsTooLargeException if derivation order is higher than 1
624             * @exception DimensionMismatchException if numbers of free parameters are inconsistent
625             */
626            public DerivativeStructure value(final DerivativeStructure[] t)
627                throws DimensionMismatchException, NumberIsTooLargeException {
628
629                // check parameters and orders limits
630                final int parameters = t[0].getFreeParameters();
631                final int order      = t[0].getOrder();
632                final int n          = t.length;
633                if (order > 1) {
634                    throw new NumberIsTooLargeException(order, 1, true);
635                }
636
637                // check all elements in the array are consistent
638                for (int i = 0; i < n; ++i) {
639                    if (t[i].getFreeParameters() != parameters) {
640                        throw new DimensionMismatchException(t[i].getFreeParameters(), parameters);
641                    }
642
643                    if (t[i].getOrder() != order) {
644                        throw new DimensionMismatchException(t[i].getOrder(), order);
645                    }
646                }
647
648                // delegate computation to underlying function
649                final double[] point = new double[n];
650                for (int i = 0; i < n; ++i) {
651                    point[i] = t[i].getValue();
652                }
653                final double value      = f.value(point);
654                final double[] gradient = f.gradient().value(point);
655
656                // merge value and gradient into one DerivativeStructure
657                final double[] derivatives = new double[parameters + 1];
658                derivatives[0] = value;
659                final int[] orders = new int[parameters];
660                for (int i = 0; i < parameters; ++i) {
661                    orders[i] = 1;
662                    for (int j = 0; j < n; ++j) {
663                        derivatives[i + 1] += gradient[j] * t[j].getPartialDerivative(orders);
664                    }
665                    orders[i] = 0;
666                }
667
668                return new DerivativeStructure(parameters, order, derivatives);
669
670            }
671
672        };
673    }
674
675    /**
676     * Convert a {@link MultivariateDifferentiableVectorFunction} into a {@link DifferentiableMultivariateVectorFunction}.
677     *
678     * @param f function to convert
679     * @return converted function
680     * @deprecated this conversion method is temporary in version 3.1, as the {@link
681     * DifferentiableMultivariateVectorFunction} interface itself is deprecated
682     */
683    @Deprecated
684    public static DifferentiableMultivariateVectorFunction toDifferentiableMultivariateVectorFunction(final MultivariateDifferentiableVectorFunction f) {
685        return new DifferentiableMultivariateVectorFunction() {
686
687            /** {@inheritDoc} */
688            public double[] value(final double[] x) {
689                return f.value(x);
690            }
691
692            /** {@inheritDoc} */
693            public MultivariateMatrixFunction jacobian() {
694                return new MultivariateMatrixFunction() {
695                    /** {@inheritDoc} */
696                    public double[][] value(final double[] x) {
697
698                        final int n = x.length;
699
700                        // delegate computation to underlying function
701                        final DerivativeStructure[] dsX = new DerivativeStructure[n];
702                        for (int i = 0; i < n; ++i) {
703                            dsX[i] = new DerivativeStructure(n, 1, i, x[i]);
704                        }
705                        final DerivativeStructure[] y = f.value(dsX);
706
707                        // extract Jacobian
708                        final double[][] jacobian = new double[y.length][n];
709                        final int[] orders = new int[n];
710                        for (int i = 0; i < y.length; ++i) {
711                            for (int j = 0; j < n; ++j) {
712                                orders[j]      = 1;
713                                jacobian[i][j] = y[i].getPartialDerivative(orders);
714                                orders[j]      = 0;
715                            }
716                        }
717
718                        return jacobian;
719
720                    }
721                };
722            }
723
724        };
725    }
726
727    /**
728     * Convert a {@link DifferentiableMultivariateVectorFunction} into a {@link MultivariateDifferentiableVectorFunction}.
729     * <p>
730     * Note that the converted function is able to handle {@link DerivativeStructure} elements
731     * that all have the same number of free parameters and order, and with order at most 1.
732     * If the function is called with inconsistent numbers of free parameters or higher order, a
733     * {@link DimensionMismatchException} or a {@link NumberIsTooLargeException} will be thrown.
734     * </p>
735     * @param f function to convert
736     * @return converted function
737     * @deprecated this conversion method is temporary in version 3.1, as the {@link
738     * DifferentiableMultivariateFunction} interface itself is deprecated
739     */
740    @Deprecated
741    public static MultivariateDifferentiableVectorFunction toMultivariateDifferentiableVectorFunction(final DifferentiableMultivariateVectorFunction f) {
742        return new MultivariateDifferentiableVectorFunction() {
743
744            /** {@inheritDoc} */
745            public double[] value(final double[] x) {
746                return f.value(x);
747            }
748
749            /** {@inheritDoc}
750             * @exception NumberIsTooLargeException if derivation order is higher than 1
751             * @exception DimensionMismatchException if numbers of free parameters are inconsistent
752             */
753            public DerivativeStructure[] value(final DerivativeStructure[] t)
754                throws DimensionMismatchException, NumberIsTooLargeException {
755
756                // check parameters and orders limits
757                final int parameters = t[0].getFreeParameters();
758                final int order      = t[0].getOrder();
759                final int n          = t.length;
760                if (order > 1) {
761                    throw new NumberIsTooLargeException(order, 1, true);
762                }
763
764                // check all elements in the array are consistent
765                for (int i = 0; i < n; ++i) {
766                    if (t[i].getFreeParameters() != parameters) {
767                        throw new DimensionMismatchException(t[i].getFreeParameters(), parameters);
768                    }
769
770                    if (t[i].getOrder() != order) {
771                        throw new DimensionMismatchException(t[i].getOrder(), order);
772                    }
773                }
774
775                // delegate computation to underlying function
776                final double[] point = new double[n];
777                for (int i = 0; i < n; ++i) {
778                    point[i] = t[i].getValue();
779                }
780                final double[] value      = f.value(point);
781                final double[][] jacobian = f.jacobian().value(point);
782
783                // merge value and Jacobian into a DerivativeStructure array
784                final DerivativeStructure[] merged = new DerivativeStructure[value.length];
785                for (int k = 0; k < merged.length; ++k) {
786                    final double[] derivatives = new double[parameters + 1];
787                    derivatives[0] = value[k];
788                    final int[] orders = new int[parameters];
789                    for (int i = 0; i < parameters; ++i) {
790                        orders[i] = 1;
791                        for (int j = 0; j < n; ++j) {
792                            derivatives[i + 1] += jacobian[k][j] * t[j].getPartialDerivative(orders);
793                        }
794                        orders[i] = 0;
795                    }
796                    merged[k] = new DerivativeStructure(parameters, order, derivatives);
797                }
798
799                return merged;
800
801            }
802
803        };
804    }
805
806}