View Javadoc
1   /*
2    * Licensed to the Hipparchus project under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.hipparchus.analysis.differentiation;
18  
19  import org.hipparchus.exception.LocalizedCoreFormats;
20  import org.hipparchus.exception.MathIllegalArgumentException;
21  import org.hipparchus.util.FastMath;
22  import org.hipparchus.util.MathArrays;
23  import org.hipparchus.util.MathUtils;
24  
25  /** Class representing both the value and the differentials of a function.
26   * <p>This class is a stripped-down version of {@link DerivativeStructure}
27   * with only one {@link DerivativeStructure#getFreeParameters() free parameter}
28   * and {@link DerivativeStructure#getOrder() derivation order} also limited to one.
29   * It should have less overhead than {@link DerivativeStructure} in its domain.</p>
30   * <p>This class is an implementation of Rall's numbers. Rall's numbers are an
31   * extension to the real numbers used throughout mathematical expressions; they hold
32   * the derivative together with the value of a function.</p>
33   * <p>{@link UnivariateDerivative1} instances can be used directly thanks to
34   * the arithmetic operators to the mathematical functions provided as
35   * methods by this class (+, -, *, /, %, sin, cos ...).</p>
36   * <p>Implementing complex expressions by hand using these classes is
37   * a tedious and error-prone task but has the advantage of having no limitation
38   * on the derivation order despite not requiring users to compute the derivatives by
39   * themselves.</p>
40   * <p>Instances of this class are guaranteed to be immutable.</p>
41   * @see DerivativeStructure
42   * @see UnivariateDerivative2
43   * @see Gradient
44   * @see FieldDerivativeStructure
45   * @see FieldUnivariateDerivative1
46   * @see FieldUnivariateDerivative2
47   * @see FieldGradient
48   * @since 1.7
49   */
50  public class UnivariateDerivative1 extends UnivariateDerivative<UnivariateDerivative1>
51          implements Derivative1<UnivariateDerivative1> {
52  
53      /** The constant value of π as a {@code UnivariateDerivative1}.
54       * @since 2.0
55       */
56      public static final UnivariateDerivative1 PI = new UnivariateDerivative1(FastMath.PI, 0.0);
57  
58      /** Serializable UID. */
59      private static final long serialVersionUID = 20200519L;
60  
61      /** Value of the function. */
62      private final double f0;
63  
64      /** First derivative of the function. */
65      private final double f1;
66  
67      /** Build an instance with values and derivative.
68       * @param f0 value of the function
69       * @param f1 first derivative of the function
70       */
71      public UnivariateDerivative1(final double f0, final double f1) {
72          this.f0 = f0;
73          this.f1 = f1;
74      }
75  
76      /** Build an instance from a {@link DerivativeStructure}.
77       * @param ds derivative structure
78       * @exception MathIllegalArgumentException if either {@code ds} parameters
79       * is not 1 or {@code ds} order is not 1
80       */
81      public UnivariateDerivative1(final DerivativeStructure ds) throws MathIllegalArgumentException {
82          MathUtils.checkDimension(ds.getFreeParameters(), 1);
83          MathUtils.checkDimension(ds.getOrder(), 1);
84          this.f0 = ds.getValue();
85          this.f1 = ds.getPartialDerivative(1);
86      }
87  
88      /** {@inheritDoc} */
89      @Override
90      public UnivariateDerivative1 newInstance(final double value) {
91          return new UnivariateDerivative1(value, 0.0);
92      }
93  
94      /** {@inheritDoc} */
95      @Override
96      public UnivariateDerivative1 withValue(final double value) {
97          return new UnivariateDerivative1(value, f1);
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     public double getValue() {
103         return f0;
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public double getDerivative(final int n) {
109         switch (n) {
110             case 0 :
111                 return f0;
112             case 1 :
113                 return f1;
114             default :
115                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, n);
116         }
117     }
118 
119     /** Get the first derivative.
120      * @return first derivative
121      * @see #getValue()
122      */
123     public double getFirstDerivative() {
124         return f1;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public DerivativeStructure toDerivativeStructure() {
130         return getField().getConversionFactory().build(f0, f1);
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public UnivariateDerivative1 add(final UnivariateDerivative1 a) {
136         return new UnivariateDerivative1(f0 + a.f0, f1 + a.f1);
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public UnivariateDerivative1 subtract(final UnivariateDerivative1 a) {
142         return new UnivariateDerivative1(f0 - a.f0, f1 - a.f1);
143     }
144 
145     /** {@inheritDoc} */
146     @Override
147     public UnivariateDerivative1 multiply(final int n) {
148         return new UnivariateDerivative1(f0 * n, f1 * n);
149     }
150 
151     /** {@inheritDoc} */
152     @Override
153     public UnivariateDerivative1 multiply(final double a) {
154         return new UnivariateDerivative1(f0 * a, f1 * a);
155     }
156 
157     /** {@inheritDoc} */
158     @Override
159     public UnivariateDerivative1 multiply(final UnivariateDerivative1 a) {
160         return new UnivariateDerivative1(f0 * a.f0,
161                                          MathArrays.linearCombination(f1, a.f0, f0, a.f1));
162     }
163 
164     /** {@inheritDoc} */
165     @Override
166     public UnivariateDerivative1 divide(final double a) {
167         final double inv1 = 1.0 / a;
168         return new UnivariateDerivative1(f0 * inv1, f1 * inv1);
169     }
170 
171     /** {@inheritDoc} */
172     @Override
173     public UnivariateDerivative1 divide(final UnivariateDerivative1 a) {
174         final double inv1 = 1.0 / a.f0;
175         final double inv2 = inv1 * inv1;
176         return new UnivariateDerivative1(f0 * inv1,
177                                          MathArrays.linearCombination(f1, a.f0, -f0, a.f1) * inv2);
178     }
179 
180     /** {@inheritDoc} */
181     @Override
182     public UnivariateDerivative1 remainder(final UnivariateDerivative1 a) {
183 
184         // compute k such that lhs % rhs = lhs - k rhs
185         final double rem = FastMath.IEEEremainder(f0, a.f0);
186         final double k   = FastMath.rint((f0 - rem) / a.f0);
187 
188         return new UnivariateDerivative1(rem, f1 - k * a.f1);
189 
190     }
191 
192     /** {@inheritDoc} */
193     @Override
194     public UnivariateDerivative1 negate() {
195         return new UnivariateDerivative1(-f0, -f1);
196     }
197 
198     /** {@inheritDoc} */
199     @Override
200     public UnivariateDerivative1 abs() {
201         if (Double.doubleToLongBits(f0) < 0) {
202             // we use the bits representation to also handle -0.0
203             return negate();
204         } else {
205             return this;
206         }
207     }
208 
209     /** {@inheritDoc} */
210     @Override
211     public UnivariateDerivative1 copySign(final UnivariateDerivative1 sign) {
212         long m = Double.doubleToLongBits(f0);
213         long s = Double.doubleToLongBits(sign.f0);
214         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
215             return this;
216         }
217         return negate(); // flip sign
218     }
219 
220     /** {@inheritDoc} */
221     @Override
222     public UnivariateDerivative1 copySign(final double sign) {
223         long m = Double.doubleToLongBits(f0);
224         long s = Double.doubleToLongBits(sign);
225         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
226             return this;
227         }
228         return negate(); // flip sign
229     }
230 
231     /** {@inheritDoc} */
232     @Override
233     public UnivariateDerivative1 scalb(final int n) {
234         return new UnivariateDerivative1(FastMath.scalb(f0, n), FastMath.scalb(f1, n));
235     }
236 
237     /** {@inheritDoc} */
238     @Override
239     public UnivariateDerivative1 hypot(final UnivariateDerivative1 y) {
240 
241         if (Double.isInfinite(f0) || Double.isInfinite(y.f0)) {
242             return new UnivariateDerivative1(Double.POSITIVE_INFINITY, 0.0);
243         } else if (Double.isNaN(f0) || Double.isNaN(y.f0)) {
244             return new UnivariateDerivative1(Double.NaN, 0.0);
245         } else {
246 
247             final int expX = getExponent();
248             final int expY = y.getExponent();
249             if (expX > expY + 27) {
250                 // y is negligible with respect to x
251                 return abs();
252             } else if (expY > expX + 27) {
253                 // x is negligible with respect to y
254                 return y.abs();
255             } else {
256 
257                 // find an intermediate scale to avoid both overflow and underflow
258                 final int middleExp = (expX + expY) / 2;
259 
260                 // scale parameters without losing precision
261                 final UnivariateDerivative1 scaledX = scalb(-middleExp);
262                 final UnivariateDerivative1 scaledY = y.scalb(-middleExp);
263 
264                 // compute scaled hypotenuse
265                 final UnivariateDerivative1 scaledH =
266                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
267 
268                 // remove scaling
269                 return scaledH.scalb(middleExp);
270 
271             }
272 
273         }
274     }
275 
276     /** {@inheritDoc} */
277     @Override
278     public UnivariateDerivative1 compose(final double... f) {
279         MathUtils.checkDimension(f.length, getOrder() + 1);
280         return compose(f[0], f[1]);
281     }
282 
283     /** {@inheritDoc} */
284     @Override
285     public UnivariateDerivative1 compose(final double ff0, final double ff1) {
286         return new UnivariateDerivative1(ff0, this.f1 * ff1);
287     }
288 
289     /** {@inheritDoc} */
290     @Override
291     public UnivariateDerivative1Field getField() {
292         return UnivariateDerivative1Field.getInstance();
293     }
294 
295     /** Compute a<sup>x</sup> where a is a double and x a {@link UnivariateDerivative1}
296      * @param a number to exponentiate
297      * @param x power to apply
298      * @return a<sup>x</sup>
299      */
300     public static UnivariateDerivative1 pow(final double a, final UnivariateDerivative1 x) {
301         if (a == 0) {
302             return x.getField().getZero();
303         } else {
304             final double aX = FastMath.pow(a, x.f0);
305             return new UnivariateDerivative1(aX, FastMath.log(a) * aX * x.f1);
306         }
307     }
308 
309     /** {@inheritDoc} */
310     @Override
311     public UnivariateDerivative1 pow(final double p) {
312         if (p == 0) {
313             return getField().getOne();
314         } else {
315             final double f0Pm1 = FastMath.pow(f0, p - 1);
316             return compose(f0Pm1 * f0, p * f0Pm1);
317         }
318     }
319 
320     /** {@inheritDoc} */
321     @Override
322     public UnivariateDerivative1 pow(final int n) {
323         if (n == 0) {
324             return getField().getOne();
325         } else {
326             final double f0Nm1 = FastMath.pow(f0, n - 1);
327             return compose(f0Nm1 * f0, n * f0Nm1);
328         }
329     }
330 
331     /** {@inheritDoc} */
332     @Override
333     public UnivariateDerivative1 atan2(final UnivariateDerivative1 x) {
334         final double inv = 1.0 / (f0 * f0 + x.f0 * x.f0);
335         return new UnivariateDerivative1(FastMath.atan2(f0, x.f0),
336                                          MathArrays.linearCombination(x.f0, f1, -x.f1, f0) * inv);
337     }
338 
339     /** {@inheritDoc} */
340     @Override
341     public UnivariateDerivative1 toDegrees() {
342         return new UnivariateDerivative1(FastMath.toDegrees(f0), FastMath.toDegrees(f1));
343     }
344 
345     /** {@inheritDoc} */
346     @Override
347     public UnivariateDerivative1 toRadians() {
348         return new UnivariateDerivative1(FastMath.toRadians(f0), FastMath.toRadians(f1));
349     }
350 
351     /** Evaluate Taylor expansion a univariate derivative.
352      * @param delta parameter offset Δx
353      * @return value of the Taylor expansion at x + Δx
354      */
355     public double taylor(final double delta) {
356         return f0 + delta * f1;
357     }
358 
359     /** {@inheritDoc} */
360     @Override
361     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1[] a, final UnivariateDerivative1[] b) {
362 
363         // extract values and first derivatives
364         final int      n  = a.length;
365         final double[] a0 = new double[n];
366         final double[] b0 = new double[n];
367         final double[] a1 = new double[2 * n];
368         final double[] b1 = new double[2 * n];
369         for (int i = 0; i < n; ++i) {
370             final UnivariateDerivative1 ai = a[i];
371             final UnivariateDerivative1 bi = b[i];
372             a0[i]         = ai.f0;
373             b0[i]         = bi.f0;
374             a1[2 * i]     = ai.f0;
375             a1[2 * i + 1] = ai.f1;
376             b1[2 * i]     = bi.f1;
377             b1[2 * i + 1] = bi.f0;
378         }
379 
380         return new UnivariateDerivative1(MathArrays.linearCombination(a0, b0),
381                                          MathArrays.linearCombination(a1, b1));
382 
383     }
384 
385     /** {@inheritDoc} */
386     @Override
387     public UnivariateDerivative1 linearCombination(final double[] a, final UnivariateDerivative1[] b) {
388 
389         // extract values and first derivatives
390         final int      n  = b.length;
391         final double[] b0 = new double[n];
392         final double[] b1 = new double[n];
393         for (int i = 0; i < n; ++i) {
394             b0[i] = b[i].f0;
395             b1[i] = b[i].f1;
396         }
397 
398         return new UnivariateDerivative1(MathArrays.linearCombination(a, b0),
399                                          MathArrays.linearCombination(a, b1));
400 
401     }
402 
403     /** {@inheritDoc} */
404     @Override
405     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1 a1, final UnivariateDerivative1 b1,
406                                                    final UnivariateDerivative1 a2, final UnivariateDerivative1 b2) {
407         return new UnivariateDerivative1(MathArrays.linearCombination(a1.f0, b1.f0,
408                                                                       a2.f0, b2.f0),
409                                          MathArrays.linearCombination(a1.f0, b1.f1,
410                                                                       a1.f1, b1.f0,
411                                                                       a2.f0, b2.f1,
412                                                                       a2.f1, b2.f0));
413     }
414 
415     /** {@inheritDoc} */
416     @Override
417     public UnivariateDerivative1 linearCombination(final double a1, final UnivariateDerivative1 b1,
418                                                    final double a2, final UnivariateDerivative1 b2) {
419         return new UnivariateDerivative1(MathArrays.linearCombination(a1, b1.f0,
420                                                                       a2, b2.f0),
421                                          MathArrays.linearCombination(a1, b1.f1,
422                                                                       a2, b2.f1));
423     }
424 
425     /** {@inheritDoc} */
426     @Override
427     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1 a1, final UnivariateDerivative1 b1,
428                                                    final UnivariateDerivative1 a2, final UnivariateDerivative1 b2,
429                                                    final UnivariateDerivative1 a3, final UnivariateDerivative1 b3) {
430         return new UnivariateDerivative1(MathArrays.linearCombination(a1.f0, b1.f0,
431                                                                       a2.f0, b2.f0,
432                                                                       a3.f0, b3.f0),
433                                          MathArrays.linearCombination(new double[] {
434                                                                           a1.f0, a1.f1,
435                                                                           a2.f0, a2.f1,
436                                                                           a3.f0, a3.f1
437                                                                       }, new double[] {
438                                                                           b1.f1, b1.f0,
439                                                                           b2.f1, b2.f0,
440                                                                           b3.f1, b3.f0
441                                                                       }));
442     }
443 
444     /** {@inheritDoc} */
445     @Override
446     public UnivariateDerivative1 linearCombination(final double a1, final UnivariateDerivative1 b1,
447                                                    final double a2, final UnivariateDerivative1 b2,
448                                                    final double a3, final UnivariateDerivative1 b3) {
449         return new UnivariateDerivative1(MathArrays.linearCombination(a1, b1.f0,
450                                                                       a2, b2.f0,
451                                                                       a3, b3.f0),
452                                          MathArrays.linearCombination(a1, b1.f1,
453                                                                       a2, b2.f1,
454                                                                       a3, b3.f1));
455     }
456 
457     /** {@inheritDoc} */
458     @Override
459     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1 a1, final UnivariateDerivative1 b1,
460                                                    final UnivariateDerivative1 a2, final UnivariateDerivative1 b2,
461                                                    final UnivariateDerivative1 a3, final UnivariateDerivative1 b3,
462                                                    final UnivariateDerivative1 a4, final UnivariateDerivative1 b4) {
463         return new UnivariateDerivative1(MathArrays.linearCombination(a1.f0, b1.f0,
464                                                                       a2.f0, b2.f0,
465                                                                       a3.f0, b3.f0,
466                                                                       a4.f0, b4.f0),
467                                          MathArrays.linearCombination(new double[] {
468                                                                           a1.f0, a1.f1,
469                                                                           a2.f0, a2.f1,
470                                                                           a3.f0, a3.f1,
471                                                                           a4.f0, a4.f1
472                                                                       }, new double[] {
473                                                                           b1.f1, b1.f0,
474                                                                           b2.f1, b2.f0,
475                                                                           b3.f1, b3.f0,
476                                                                           b4.f1, b4.f0
477                                                                       }));
478     }
479 
480     /** {@inheritDoc} */
481     @Override
482     public UnivariateDerivative1 linearCombination(final double a1, final UnivariateDerivative1 b1,
483                                                    final double a2, final UnivariateDerivative1 b2,
484                                                    final double a3, final UnivariateDerivative1 b3,
485                                                    final double a4, final UnivariateDerivative1 b4) {
486         return new UnivariateDerivative1(MathArrays.linearCombination(a1, b1.f0,
487                                                                       a2, b2.f0,
488                                                                       a3, b3.f0,
489                                                                       a4, b4.f0),
490                                          MathArrays.linearCombination(a1, b1.f1,
491                                                                       a2, b2.f1,
492                                                                       a3, b3.f1,
493                                                                       a4, b4.f1));
494     }
495 
496     /** {@inheritDoc} */
497     @Override
498     public UnivariateDerivative1 getPi() {
499         return PI;
500     }
501 
502     /** Test for the equality of two univariate derivatives.
503      * <p>
504      * univariate derivatives are considered equal if they have the same derivatives.
505      * </p>
506      * @param other Object to test for equality to this
507      * @return true if two univariate derivatives are equal
508      */
509     @Override
510     public boolean equals(Object other) {
511 
512         if (this == other) {
513             return true;
514         }
515 
516         if (other instanceof UnivariateDerivative1) {
517             final UnivariateDerivative1 rhs = (UnivariateDerivative1) other;
518             return f0 == rhs.f0 && f1 == rhs.f1;
519         }
520 
521         return false;
522 
523     }
524 
525     /** Get a hashCode for the univariate derivative.
526      * @return a hash code value for this object
527      */
528     @Override
529     public int hashCode() {
530         return 453 - 19 * Double.hashCode(f0) + 37 * Double.hashCode(f1);
531     }
532 
533     /** {@inheritDoc}
534      * <p>
535      * Comparison performed considering that derivatives are intrinsically linked to monomials in the corresponding
536      * Taylor expansion and that the higher the degree, the smaller the term.
537      * </p>
538      * @since 3.0
539      */
540     @Override
541     public int compareTo(final UnivariateDerivative1 o) {
542         final int cF0 = Double.compare(f0, o.getReal());
543         if (cF0 == 0) {
544             return Double.compare(f1, o.getFirstDerivative());
545         } else {
546             return cF0;
547         }
548     }
549 
550 }