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