1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.hipparchus.analysis.differentiation;
18
19 import java.io.Serializable;
20 import java.util.Arrays;
21
22 import org.hipparchus.exception.LocalizedCoreFormats;
23 import org.hipparchus.exception.MathIllegalArgumentException;
24 import org.hipparchus.util.FastMath;
25 import org.hipparchus.util.FieldSinCos;
26 import org.hipparchus.util.FieldSinhCosh;
27 import org.hipparchus.util.MathArrays;
28 import org.hipparchus.util.MathUtils;
29 import org.hipparchus.util.SinCos;
30 import org.hipparchus.util.SinhCosh;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class Gradient implements Derivative1<Gradient>, Serializable {
58
59
60 private static final long serialVersionUID = 20200520L;
61
62
63 private final double value;
64
65
66 private final double[] grad;
67
68
69
70
71
72 private Gradient(final double value, int freeParameters) {
73 this.value = value;
74 this.grad = new double[freeParameters];
75 }
76
77
78
79
80
81
82 private Gradient(final double[] gradient, final double value) {
83 this.value = value;
84 this.grad = gradient;
85 }
86
87
88
89
90
91 public Gradient(final double value, final double... gradient) {
92 this(value, gradient.length);
93 System.arraycopy(gradient, 0, grad, 0, grad.length);
94 }
95
96
97
98
99
100
101 public Gradient(final DerivativeStructure ds) throws MathIllegalArgumentException {
102 this(ds.getValue(), ds.getFreeParameters());
103 MathUtils.checkDimension(ds.getOrder(), 1);
104 System.arraycopy(ds.getAllDerivatives(), 1, grad, 0, grad.length);
105 }
106
107
108
109
110
111
112 public static Gradient constant(final int freeParameters, final double value) {
113 return new Gradient(value, freeParameters);
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127 public static Gradient variable(final int freeParameters, final int index, final double value) {
128 final Gradient g = new Gradient(value, freeParameters);
129 g.grad[index] = 1.0;
130 return g;
131 }
132
133
134 @Override
135 public Gradient newInstance(final double c) {
136 return new Gradient(c, new double[grad.length]);
137 }
138
139
140 @Override
141 public Gradient withValue(final double v) {
142 return new Gradient(v, grad);
143 }
144
145
146 @Override
147 public Gradient getAddendum() {
148 return new Gradient(0, grad);
149 }
150
151
152
153
154 @Override
155 public double getValue() {
156 return value;
157 }
158
159
160
161
162
163 public double[] getGradient() {
164 return grad.clone();
165 }
166
167
168 @Override
169 public int getFreeParameters() {
170 return grad.length;
171 }
172
173
174 @Override
175 public double getPartialDerivative(final int ... orders)
176 throws MathIllegalArgumentException {
177
178
179 if (orders.length != grad.length) {
180 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
181 orders.length, grad.length);
182 }
183
184
185
186 int selected = -1;
187 for (int i = 0; i < orders.length; ++i) {
188 if (orders[i] != 0) {
189 if (selected >= 0 || orders[i] != 1) {
190 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED,
191 orders[i]);
192 }
193
194 selected = i;
195 }
196 }
197
198 return (selected < 0) ? value : grad[selected];
199
200 }
201
202
203
204
205
206
207
208 public double getPartialDerivative(final int n) throws MathIllegalArgumentException {
209 if (n < 0 || n >= grad.length) {
210 throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, n, 0, grad.length - 1);
211 }
212 return grad[n];
213 }
214
215
216
217
218 public DerivativeStructure toDerivativeStructure() {
219 final double[] derivatives = new double[1 + grad.length];
220 derivatives[0] = value;
221 System.arraycopy(grad, 0, derivatives, 1, grad.length);
222 return getField().getConversionFactory().build(derivatives);
223 }
224
225
226 @Override
227 public Gradient add(final Gradient a) {
228 final double[] gradient = new double[grad.length];
229 for (int i = 0; i < grad.length; ++i) {
230 gradient[i] = grad[i] + a.grad[i];
231 }
232 return new Gradient(gradient, value + a.value);
233 }
234
235
236 @Override
237 public Gradient subtract(final Gradient a) {
238 final double[] gradient = new double[grad.length];
239 for (int i = 0; i < grad.length; ++i) {
240 gradient[i] = grad[i] - a.grad[i];
241 }
242 return new Gradient(gradient, value - a.value);
243 }
244
245
246 @Override
247 public Gradient multiply(final int n) {
248 final double[] gradient = new double[grad.length];
249 for (int i = 0; i < grad.length; ++i) {
250 gradient[i] = grad[i] * n;
251 }
252 return new Gradient(gradient, value * n);
253 }
254
255
256 @Override
257 public Gradient multiply(final double a) {
258 final double[] gradient = new double[grad.length];
259 for (int i = 0; i < grad.length; ++i) {
260 gradient[i] = grad[i] * a;
261 }
262 return new Gradient(gradient, value * a);
263 }
264
265
266 @Override
267 public Gradient multiply(final Gradient a) {
268 final double[] gradient = new double[grad.length];
269 for (int i = 0; i < grad.length; ++i) {
270 gradient[i] = grad[i] * a.value + value * a.grad[i];
271 }
272 return new Gradient(gradient, value * a.value);
273 }
274
275
276 @Override
277 public Gradient divide(final double a) {
278 final double[] gradient = new double[grad.length];
279 for (int i = 0; i < grad.length; ++i) {
280 gradient[i] = grad[i] / a;
281 }
282 return new Gradient(gradient, value / a);
283 }
284
285
286 @Override
287 public Gradient divide(final Gradient a) {
288 final double inv1 = 1.0 / a.value;
289 final double inv2 = inv1 * inv1;
290 final double[] gradient = new double[grad.length];
291 for (int i = 0; i < grad.length; ++i) {
292 gradient[i] = (grad[i] * a.value - value * a.grad[i]) * inv2;
293 }
294 return new Gradient(gradient, value * inv1);
295 }
296
297
298 @Override
299 public Gradient remainder(final Gradient a) {
300
301
302 final double rem = FastMath.IEEEremainder(value, a.value);
303 final double k = FastMath.rint((value - rem) / a.value);
304
305 final double[] gradient = new double[grad.length];
306 for (int i = 0; i < grad.length; ++i) {
307 gradient[i] = grad[i] - k * a.grad[i];
308 }
309 return new Gradient(gradient, rem);
310
311 }
312
313
314 @Override
315 public Gradient negate() {
316 final double[] gradient = new double[grad.length];
317 for (int i = 0; i < grad.length; ++i) {
318 gradient[i] = -grad[i];
319 }
320 return new Gradient(gradient, -value);
321 }
322
323
324 @Override
325 public Gradient abs() {
326 if (Double.doubleToLongBits(value) < 0) {
327
328 return negate();
329 } else {
330 return this;
331 }
332 }
333
334
335 @Override
336 public Gradient copySign(final Gradient sign) {
337 long m = Double.doubleToLongBits(value);
338 long s = Double.doubleToLongBits(sign.value);
339 if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) {
340 return this;
341 }
342 return negate();
343 }
344
345
346 @Override
347 public Gradient copySign(final double sign) {
348 long m = Double.doubleToLongBits(value);
349 long s = Double.doubleToLongBits(sign);
350 if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) {
351 return this;
352 }
353 return negate();
354 }
355
356
357 @Override
358 public Gradient scalb(final int n) {
359 final double[] gradient = new double[grad.length];
360 for (int i = 0; i < grad.length; ++i) {
361 gradient[i] = FastMath.scalb(grad[i], n);
362 }
363 return new Gradient(gradient, FastMath.scalb(value, n));
364 }
365
366
367 @Override
368 public Gradient hypot(final Gradient y) {
369
370 if (Double.isInfinite(value) || Double.isInfinite(y.value)) {
371 return newInstance(Double.POSITIVE_INFINITY);
372 } else if (Double.isNaN(value) || Double.isNaN(y.value)) {
373 return newInstance(Double.NaN);
374 } else {
375
376 final int expX = getExponent();
377 final int expY = y.getExponent();
378 if (expX > expY + 27) {
379
380 return abs();
381 } else if (expY > expX + 27) {
382
383 return y.abs();
384 } else {
385
386
387 final int middleExp = (expX + expY) / 2;
388
389
390 final Gradient scaledX = scalb(-middleExp);
391 final Gradient scaledY = y.scalb(-middleExp);
392
393
394 final Gradient scaledH =
395 scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
396
397
398 return scaledH.scalb(middleExp);
399
400 }
401
402 }
403 }
404
405
406 @Override
407 public Gradient compose(final double... f) {
408 MathUtils.checkDimension(f.length, getOrder() + 1);
409 return compose(f[0], f[1]);
410 }
411
412
413 @Override
414 public Gradient compose(final double f0, final double f1) {
415 final double[] gradient = new double[grad.length];
416 for (int i = 0; i < grad.length; ++i) {
417 gradient[i] = f1 * grad[i];
418 }
419 return new Gradient(gradient, f0);
420 }
421
422
423 @Override
424 public GradientField getField() {
425 return GradientField.getField(getFreeParameters());
426 }
427
428
429
430
431
432
433 public static Gradient pow(final double a, final Gradient x) {
434 if (a == 0) {
435 return x.getField().getZero();
436 } else {
437 final double aX = FastMath.pow(a, x.value);
438 final double aXlnA = aX * FastMath.log(a);
439 final double[] gradient = new double[x.getFreeParameters()];
440 for (int i = 0; i < gradient.length; ++i) {
441 gradient[i] = aXlnA * x.grad[i];
442 }
443 return new Gradient(gradient, aX);
444 }
445 }
446
447
448 @Override
449 public Gradient pow(final double p) {
450 if (p == 0) {
451 return getField().getOne();
452 } else {
453 final double valuePm1 = FastMath.pow(value, p - 1);
454 return compose(valuePm1 * value, p * valuePm1);
455 }
456 }
457
458
459 @Override
460 public Gradient pow(final int n) {
461 if (n == 0) {
462 return getField().getOne();
463 } else {
464 final double valueNm1 = FastMath.pow(value, n - 1);
465 return compose(valueNm1 * value, n * valueNm1);
466 }
467 }
468
469
470 @Override
471 public FieldSinCos<Gradient> sinCos() {
472 final SinCos sinCos = FastMath.sinCos(value);
473 final double[] gradSin = new double[grad.length];
474 final double[] gradCos = new double[grad.length];
475 for (int i = 0; i < grad.length; ++i) {
476 gradSin[i] = grad[i] * sinCos.cos();
477 gradCos[i] = -grad[i] * sinCos.sin();
478 }
479 final Gradient sin = new Gradient(gradSin, sinCos.sin());
480 final Gradient cos = new Gradient(gradCos, sinCos.cos());
481 return new FieldSinCos<>(sin, cos);
482 }
483
484
485 @Override
486 public Gradient atan2(final Gradient x) {
487 final double inv = 1.0 / (value * value + x.value * x.value);
488 final double[] gradient = new double[grad.length];
489 for (int i = 0; i < grad.length; ++i) {
490 gradient[i] = (x.value * grad[i] - x.grad[i] * value) * inv;
491 }
492 return new Gradient(gradient, FastMath.atan2(value, x.value));
493 }
494
495
496 @Override
497 public FieldSinhCosh<Gradient> sinhCosh() {
498 final SinhCosh sinhCosh = FastMath.sinhCosh(value);
499 final double[] gradSinh = new double[grad.length];
500 final double[] gradCosh = new double[grad.length];
501 for (int i = 0; i < grad.length; ++i) {
502 gradSinh[i] = grad[i] * sinhCosh.cosh();
503 gradCosh[i] = grad[i] * sinhCosh.sinh();
504 }
505 final Gradient sinh = new Gradient(gradSinh, sinhCosh.sinh());
506 final Gradient cosh = new Gradient(gradCosh, sinhCosh.cosh());
507 return new FieldSinhCosh<>(sinh, cosh);
508 }
509
510
511 @Override
512 public Gradient toDegrees() {
513 final double[] gradient = new double[grad.length];
514 for (int i = 0; i < grad.length; ++i) {
515 gradient[i] = FastMath.toDegrees(grad[i]);
516 }
517 return new Gradient(gradient, FastMath.toDegrees(value));
518 }
519
520
521 @Override
522 public Gradient toRadians() {
523 final double[] gradient = new double[grad.length];
524 for (int i = 0; i < grad.length; ++i) {
525 gradient[i] = FastMath.toRadians(grad[i]);
526 }
527 return new Gradient(gradient, FastMath.toRadians(value));
528 }
529
530
531
532
533
534 public double taylor(final double... delta) {
535 double result = value;
536 for (int i = 0; i < grad.length; ++i) {
537 result += delta[i] * grad[i];
538 }
539 return result;
540 }
541
542
543 @Override
544 public Gradient linearCombination(final Gradient[] a, final Gradient[] b) {
545
546
547 final int n = a.length;
548 final double[] a0 = new double[n];
549 final double[] b0 = new double[n];
550 final double[] a1 = new double[2 * n];
551 final double[] b1 = new double[2 * n];
552 for (int i = 0; i < n; ++i) {
553 final Gradient ai = a[i];
554 final Gradient bi = b[i];
555 a0[i] = ai.value;
556 b0[i] = bi.value;
557 a1[2 * i] = ai.value;
558 b1[2 * i + 1] = bi.value;
559 }
560
561 final Gradient result = newInstance(MathArrays.linearCombination(a0, b0));
562 for (int k = 0; k < grad.length; ++k) {
563 for (int i = 0; i < n; ++i) {
564 a1[2 * i + 1] = a[i].grad[k];
565 b1[2 * i] = b[i].grad[k];
566 }
567 result.grad[k] = MathArrays.linearCombination(a1, b1);
568 }
569 return result;
570
571 }
572
573
574 @Override
575 public Gradient linearCombination(final double[] a, final Gradient[] b) {
576
577
578 final int n = b.length;
579 final double[] b0 = new double[n];
580 final double[] b1 = new double[n];
581 for (int i = 0; i < n; ++i) {
582 b0[i] = b[i].value;
583 }
584
585 final Gradient result = newInstance(MathArrays.linearCombination(a, b0));
586 for (int k = 0; k < grad.length; ++k) {
587 for (int i = 0; i < n; ++i) {
588 b1[i] = b[i].grad[k];
589 }
590 result.grad[k] = MathArrays.linearCombination(a, b1);
591 }
592 return result;
593
594 }
595
596
597 @Override
598 public Gradient linearCombination(final Gradient a1, final Gradient b1,
599 final Gradient a2, final Gradient b2) {
600 final Gradient result = newInstance(MathArrays.linearCombination(a1.value, b1.value,
601 a2.value, b2.value));
602 for (int i = 0; i < b1.grad.length; ++i) {
603 result.grad[i] = MathArrays.linearCombination(a1.value, b1.grad[i],
604 a1.grad[i], b1.value,
605 a2.value, b2.grad[i],
606 a2.grad[i], b2.value);
607 }
608 return result;
609 }
610
611
612 @Override
613 public Gradient linearCombination(final double a1, final Gradient b1,
614 final double a2, final Gradient b2) {
615 final Gradient result = newInstance(MathArrays.linearCombination(a1, b1.value,
616 a2, b2.value));
617 for (int i = 0; i < b1.grad.length; ++i) {
618 result.grad[i] = MathArrays.linearCombination(a1, b1.grad[i],
619 a2, b2.grad[i]);
620 }
621 return result;
622 }
623
624
625 @Override
626 public Gradient linearCombination(final Gradient a1, final Gradient b1,
627 final Gradient a2, final Gradient b2,
628 final Gradient a3, final Gradient b3) {
629 final double[] a = {
630 a1.value, 0, a2.value, 0, a3.value, 0
631 };
632 final double[] b = {
633 0, b1.value, 0, b2.value, 0, b3.value
634 };
635 final Gradient result = newInstance(MathArrays.linearCombination(a1.value, b1.value,
636 a2.value, b2.value,
637 a3.value, b3.value));
638 for (int i = 0; i < b1.grad.length; ++i) {
639 a[1] = a1.grad[i];
640 a[3] = a2.grad[i];
641 a[5] = a3.grad[i];
642 b[0] = b1.grad[i];
643 b[2] = b2.grad[i];
644 b[4] = b3.grad[i];
645 result.grad[i] = MathArrays.linearCombination(a, b);
646 }
647 return result;
648 }
649
650
651 @Override
652 public Gradient linearCombination(final double a1, final Gradient b1,
653 final double a2, final Gradient b2,
654 final double a3, final Gradient b3) {
655 final Gradient result = newInstance(MathArrays.linearCombination(a1, b1.value,
656 a2, b2.value,
657 a3, b3.value));
658 for (int i = 0; i < b1.grad.length; ++i) {
659 result.grad[i] = MathArrays.linearCombination(a1, b1.grad[i],
660 a2, b2.grad[i],
661 a3, b3.grad[i]);
662 }
663 return result;
664 }
665
666
667 @Override
668 public Gradient linearCombination(final Gradient a1, final Gradient b1,
669 final Gradient a2, final Gradient b2,
670 final Gradient a3, final Gradient b3,
671 final Gradient a4, final Gradient b4) {
672 final double[] a = {
673 a1.value, 0, a2.value, 0, a3.value, 0, a4.value, 0
674 };
675 final double[] b = {
676 0, b1.value, 0, b2.value, 0, b3.value, 0, b4.value
677 };
678 final Gradient result = newInstance(MathArrays.linearCombination(a1.value, b1.value,
679 a2.value, b2.value,
680 a3.value, b3.value,
681 a4.value, b4.value));
682 for (int i = 0; i < b1.grad.length; ++i) {
683 a[1] = a1.grad[i];
684 a[3] = a2.grad[i];
685 a[5] = a3.grad[i];
686 a[7] = a4.grad[i];
687 b[0] = b1.grad[i];
688 b[2] = b2.grad[i];
689 b[4] = b3.grad[i];
690 b[6] = b4.grad[i];
691 result.grad[i] = MathArrays.linearCombination(a, b);
692 }
693 return result;
694 }
695
696
697 @Override
698 public Gradient linearCombination(final double a1, final Gradient b1,
699 final double a2, final Gradient b2,
700 final double a3, final Gradient b3,
701 final double a4, final Gradient b4) {
702 final Gradient result = newInstance(MathArrays.linearCombination(a1, b1.value,
703 a2, b2.value,
704 a3, b3.value,
705 a4, b4.value));
706 for (int i = 0; i < b1.grad.length; ++i) {
707 result.grad[i] = MathArrays.linearCombination(a1, b1.grad[i],
708 a2, b2.grad[i],
709 a3, b3.grad[i],
710 a4, b4.grad[i]);
711 }
712 return result;
713 }
714
715
716
717
718
719
720 public Gradient stackVariable() {
721 final double[] gradient = new double[this.getFreeParameters() + 1];
722 System.arraycopy(this.grad, 0, gradient, 0, this.getFreeParameters());
723 return new Gradient(gradient, this.getValue());
724 }
725
726
727
728
729
730
731
732
733 @Override
734 public boolean equals(Object other) {
735
736 if (this == other) {
737 return true;
738 }
739
740 if (other instanceof Gradient) {
741 final Gradient rhs = (Gradient) other;
742 return value == rhs.value && MathArrays.equals(grad, rhs.grad);
743 }
744
745 return false;
746
747 }
748
749
750
751
752 @Override
753 public int hashCode() {
754 return 129 + 7 * Double.hashCode(value) - 15 * Arrays.hashCode(grad);
755 }
756
757 }