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.util.Arrays;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.Field;
23 import org.hipparchus.exception.LocalizedCoreFormats;
24 import org.hipparchus.exception.MathIllegalArgumentException;
25 import org.hipparchus.util.FastMath;
26 import org.hipparchus.util.FieldSinCos;
27 import org.hipparchus.util.FieldSinhCosh;
28 import org.hipparchus.util.MathArrays;
29 import org.hipparchus.util.MathUtils;
30
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 FieldGradient<T extends CalculusFieldElement<T>> implements FieldDerivative1<T, FieldGradient<T>> {
57
58
59 private final T value;
60
61
62 private final T[] grad;
63
64
65
66
67
68 private FieldGradient(final T value, int freeParameters) {
69 this.value = value;
70 this.grad = MathArrays.buildArray(value.getField(), freeParameters);
71 }
72
73
74
75
76
77 @SafeVarargs
78 public FieldGradient(final T value, final T... gradient) {
79 this(value, gradient.length);
80 System.arraycopy(gradient, 0, grad, 0, grad.length);
81 }
82
83
84
85
86
87
88 public FieldGradient(final FieldDerivativeStructure<T> ds) throws MathIllegalArgumentException {
89 this(ds.getValue(), ds.getFreeParameters());
90 MathUtils.checkDimension(ds.getOrder(), 1);
91 System.arraycopy(ds.getAllDerivatives(), 1, grad, 0, grad.length);
92 }
93
94
95
96
97
98
99
100 public static <T extends CalculusFieldElement<T>> FieldGradient<T> constant(final int freeParameters, final T value) {
101 final FieldGradient<T> g = new FieldGradient<>(value, freeParameters);
102 Arrays.fill(g.grad, value.getField().getZero());
103 return g;
104 }
105
106
107
108
109
110
111
112
113
114
115
116
117
118 public static <T extends CalculusFieldElement<T>> FieldGradient<T> variable(final int freeParameters,
119 final int index, final T value) {
120 final FieldGradient<T> g = new FieldGradient<>(value, freeParameters);
121 final Field<T> field = value.getField();
122 Arrays.fill(g.grad, field.getZero());
123 g.grad[index] = field.getOne();
124 return g;
125 }
126
127
128
129
130 public Field<T> getValueField() {
131 return value.getField();
132 }
133
134
135 @Override
136 public FieldGradient<T> newInstance(final double c) {
137 return newInstance(getValueField().getZero().newInstance(c));
138 }
139
140
141 @Override
142 public FieldGradient<T> newInstance(final T c) {
143 return new FieldGradient<>(c, MathArrays.buildArray(value.getField(), grad.length));
144 }
145
146
147 @Override
148 public FieldGradient<T> withValue(final T v) {
149 return new FieldGradient<>(v, grad);
150 }
151
152
153
154
155 @Override
156 public T getValue() {
157 return value;
158 }
159
160
161
162
163 public T[] getGradient() {
164 return grad.clone();
165 }
166
167
168
169
170 @Override
171 public int getFreeParameters() {
172 return grad.length;
173 }
174
175
176 @Override
177 public T getPartialDerivative(final int ... orders)
178 throws MathIllegalArgumentException {
179
180
181 if (orders.length != grad.length) {
182 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
183 orders.length, grad.length);
184 }
185
186
187
188 int selected = -1;
189 for (int i = 0; i < orders.length; ++i) {
190 if (orders[i] != 0) {
191 if (selected >= 0 || orders[i] != 1) {
192 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED,
193 orders[i]);
194 }
195
196 selected = i;
197 }
198 }
199
200 return (selected < 0) ? value : grad[selected];
201
202 }
203
204
205
206
207
208
209
210 public T getPartialDerivative(final int n) throws MathIllegalArgumentException {
211 if (n < 0 || n >= grad.length) {
212 throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, n, 0, grad.length - 1);
213 }
214 return grad[n];
215 }
216
217
218
219
220 public FieldDerivativeStructure<T> toDerivativeStructure() {
221 final T[] derivatives = MathArrays.buildArray(getValueField(), 1 + grad.length);
222 derivatives[0] = value;
223 System.arraycopy(grad, 0, derivatives, 1, grad.length);
224 return getField().getConversionFactory().build(derivatives);
225 }
226
227
228 @Override
229 public FieldGradient<T> add(final double a) {
230 return new FieldGradient<>(value.add(a), grad);
231 }
232
233
234 @Override
235 public FieldGradient<T> add(final FieldGradient<T> a) {
236 final FieldGradient<T> result = newInstance(value.add(a.value));
237 for (int i = 0; i < grad.length; ++i) {
238 result.grad[i] = grad[i].add(a.grad[i]);
239 }
240 return result;
241 }
242
243
244 @Override
245 public FieldGradient<T> subtract(final double a) {
246 return new FieldGradient<>(value.subtract(a), grad);
247 }
248
249
250 @Override
251 public FieldGradient<T> subtract(final FieldGradient<T> a) {
252 final FieldGradient<T> result = newInstance(value.subtract(a.value));
253 for (int i = 0; i < grad.length; ++i) {
254 result.grad[i] = grad[i].subtract(a.grad[i]);
255 }
256 return result;
257 }
258
259
260
261
262
263 public FieldGradient<T> multiply(final T n) {
264 final FieldGradient<T> result = newInstance(value.multiply(n));
265 for (int i = 0; i < grad.length; ++i) {
266 result.grad[i] = grad[i].multiply(n);
267 }
268 return result;
269 }
270
271
272 @Override
273 public FieldGradient<T> multiply(final int n) {
274 final FieldGradient<T> result = newInstance(value.multiply(n));
275 for (int i = 0; i < grad.length; ++i) {
276 result.grad[i] = grad[i].multiply(n);
277 }
278 return result;
279 }
280
281
282 @Override
283 public FieldGradient<T> multiply(final double a) {
284 final FieldGradient<T> result = newInstance(value.multiply(a));
285 for (int i = 0; i < grad.length; ++i) {
286 result.grad[i] = grad[i].multiply(a);
287 }
288 return result;
289 }
290
291
292 @Override
293 public FieldGradient<T> multiply(final FieldGradient<T> a) {
294 final FieldGradient<T> result = newInstance(value.multiply(a.value));
295 for (int i = 0; i < grad.length; ++i) {
296 result.grad[i] = grad[i].multiply(a.value).add(value.multiply(a.grad[i]));
297 }
298 return result;
299 }
300
301
302
303
304
305 public FieldGradient<T> divide(final T a) {
306 final FieldGradient<T> result = newInstance(value.divide(a));
307 for (int i = 0; i < grad.length; ++i) {
308 result.grad[i] = grad[i].divide(a);
309 }
310 return result;
311 }
312
313
314 @Override
315 public FieldGradient<T> divide(final double a) {
316 final FieldGradient<T> result = newInstance(value.divide(a));
317 for (int i = 0; i < grad.length; ++i) {
318 result.grad[i] = grad[i].divide(a);
319 }
320 return result;
321 }
322
323
324 @Override
325 public FieldGradient<T> divide(final FieldGradient<T> a) {
326 final T inv1 = a.value.reciprocal();
327 final T inv2 = inv1.multiply(inv1);
328 final FieldGradient<T> result = newInstance(value.multiply(inv1));
329 for (int i = 0; i < grad.length; ++i) {
330 result.grad[i] = grad[i].multiply(a.value).subtract(value.multiply(a.grad[i])).multiply(inv2);
331 }
332 return result;
333 }
334
335
336
337
338
339
340 public FieldGradient<T> remainder(final T a) {
341 return new FieldGradient<>(FastMath.IEEEremainder(value, a), grad);
342 }
343
344
345 @Override
346 public FieldGradient<T> remainder(final double a) {
347 return new FieldGradient<>(FastMath.IEEEremainder(value, a), grad);
348 }
349
350
351 @Override
352 public FieldGradient<T> remainder(final FieldGradient<T> a) {
353
354
355 final T rem = FastMath.IEEEremainder(value, a.value);
356 final T k = FastMath.rint(value.subtract(rem).divide(a.value));
357
358 final FieldGradient<T> result = newInstance(rem);
359 for (int i = 0; i < grad.length; ++i) {
360 result.grad[i] = grad[i].subtract(k.multiply(a.grad[i]));
361 }
362 return result;
363
364 }
365
366
367 @Override
368 public FieldGradient<T> negate() {
369 final FieldGradient<T> result = newInstance(value.negate());
370 for (int i = 0; i < grad.length; ++i) {
371 result.grad[i] = grad[i].negate();
372 }
373 return result;
374 }
375
376
377 @Override
378 public FieldGradient<T> abs() {
379 if (Double.doubleToLongBits(value.getReal()) < 0) {
380
381 return negate();
382 } else {
383 return this;
384 }
385 }
386
387
388
389
390
391
392
393
394 public FieldGradient<T> copySign(final T sign) {
395 long m = Double.doubleToLongBits(value.getReal());
396 long s = Double.doubleToLongBits(sign.getReal());
397 if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) {
398 return this;
399 }
400 return negate();
401 }
402
403
404 @Override
405 public FieldGradient<T> copySign(final FieldGradient<T> sign) {
406 long m = Double.doubleToLongBits(value.getReal());
407 long s = Double.doubleToLongBits(sign.value.getReal());
408 if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) {
409 return this;
410 }
411 return negate();
412 }
413
414
415 @Override
416 public FieldGradient<T> copySign(final double sign) {
417 long m = Double.doubleToLongBits(value.getReal());
418 long s = Double.doubleToLongBits(sign);
419 if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) {
420 return this;
421 }
422 return negate();
423 }
424
425
426 @Override
427 public FieldGradient<T> scalb(final int n) {
428 final FieldGradient<T> result = newInstance(FastMath.scalb(value, n));
429 for (int i = 0; i < grad.length; ++i) {
430 result.grad[i] = FastMath.scalb(grad[i], n);
431 }
432 return result;
433 }
434
435
436 @Override
437 public FieldGradient<T> hypot(final FieldGradient<T> y) {
438
439 if (Double.isInfinite(value.getReal()) || Double.isInfinite(y.value.getReal())) {
440 return newInstance(Double.POSITIVE_INFINITY);
441 } else if (Double.isNaN(value.getReal()) || Double.isNaN(y.value.getReal())) {
442 return newInstance(Double.NaN);
443 } else {
444
445 final int expX = getExponent();
446 final int expY = y.getExponent();
447 if (expX > expY + 27) {
448
449 return abs();
450 } else if (expY > expX + 27) {
451
452 return y.abs();
453 } else {
454
455
456 final int middleExp = (expX + expY) / 2;
457
458
459 final FieldGradient<T> scaledX = scalb(-middleExp);
460 final FieldGradient<T> scaledY = y.scalb(-middleExp);
461
462
463 final FieldGradient<T> scaledH =
464 scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
465
466
467 return scaledH.scalb(middleExp);
468
469 }
470
471 }
472 }
473
474
475
476
477
478
479 @Override
480 public FieldGradient<T> compose(final T g0, final T g1) {
481 final FieldGradient<T> result = newInstance(g0);
482 for (int i = 0; i < grad.length; ++i) {
483 result.grad[i] = g1.multiply(grad[i]);
484 }
485 return result;
486 }
487
488
489 @Override
490 public FieldGradient<T> rootN(final int n) {
491 if (n == 2) {
492 return sqrt();
493 } else if (n == 3) {
494 return cbrt();
495 } else {
496 final T r = FastMath.pow(value, 1.0 / n);
497 return compose(r, FastMath.pow(r, n - 1).multiply(n).reciprocal());
498 }
499 }
500
501
502 @Override
503 public FieldGradientField<T> getField() {
504 return FieldGradientField.getField(getValueField(), getFreeParameters());
505 }
506
507
508
509
510
511
512
513 public static <T extends CalculusFieldElement<T>> FieldGradient<T> pow(final double a, final FieldGradient<T> x) {
514 if (a == 0) {
515 return x.getField().getZero();
516 } else {
517 final T aX = FastMath.pow(x.value.newInstance(a), x.value);
518 final T aXlnA = aX.multiply(FastMath.log(a));
519 final FieldGradient<T> result = x.newInstance(aX);
520 for (int i = 0; i < x.grad.length; ++i) {
521 result.grad[i] = aXlnA.multiply(x.grad[i]);
522 }
523 return result;
524 }
525 }
526
527
528 @Override
529 public FieldGradient<T> pow(final double p) {
530 if (p == 0) {
531 return getField().getOne();
532 } else {
533 final T f0Pm1 = FastMath.pow(value, p - 1);
534 return compose(f0Pm1.multiply(value), f0Pm1.multiply(p));
535 }
536 }
537
538
539 @Override
540 public FieldGradient<T> pow(final int n) {
541 if (n == 0) {
542 return getField().getOne();
543 } else {
544 final T f0Nm1 = FastMath.pow(value, n - 1);
545 return compose(f0Nm1.multiply(value), f0Nm1.multiply(n));
546 }
547 }
548
549
550 @Override
551 public FieldSinCos<FieldGradient<T>> sinCos() {
552 final FieldSinCos<T> sinCos = FastMath.sinCos(value);
553 final FieldGradient<T> sin = newInstance(sinCos.sin());
554 final FieldGradient<T> cos = newInstance(sinCos.cos());
555 final T mSin = sinCos.sin().negate();
556 for (int i = 0; i < grad.length; ++i) {
557 sin.grad[i] = grad[i].multiply(sinCos.cos());
558 cos.grad[i] = grad[i].multiply(mSin);
559 }
560 return new FieldSinCos<>(sin, cos);
561 }
562
563
564 @Override
565 public FieldGradient<T> atan2(final FieldGradient<T> x) {
566 final T inv = value.square().add(x.value.multiply(x.value)).reciprocal();
567 final FieldGradient<T> result = newInstance(FastMath.atan2(value, x.value));
568 final T xValueInv = x.value.multiply(inv);
569 final T mValueInv = value.negate().multiply(inv);
570 for (int i = 0; i < grad.length; ++i) {
571 result.grad[i] = xValueInv.multiply(grad[i]).add(x.grad[i].multiply(mValueInv));
572 }
573 return result;
574 }
575
576
577 @Override
578 public FieldSinhCosh<FieldGradient<T>> sinhCosh() {
579 final FieldSinhCosh<T> sinhCosh = FastMath.sinhCosh(value);
580 final FieldGradient<T> sinh = newInstance(sinhCosh.sinh());
581 final FieldGradient<T> cosh = newInstance(sinhCosh.cosh());
582 for (int i = 0; i < grad.length; ++i) {
583 sinh.grad[i] = grad[i].multiply(sinhCosh.cosh());
584 cosh.grad[i] = grad[i].multiply(sinhCosh.sinh());
585 }
586 return new FieldSinhCosh<>(sinh, cosh);
587 }
588
589
590 @Override
591 public FieldGradient<T> toDegrees() {
592 final FieldGradient<T> result = newInstance(FastMath.toDegrees(value));
593 for (int i = 0; i < grad.length; ++i) {
594 result.grad[i] = FastMath.toDegrees(grad[i]);
595 }
596 return result;
597 }
598
599
600 @Override
601 public FieldGradient<T> toRadians() {
602 final FieldGradient<T> result = newInstance(FastMath.toRadians(value));
603 for (int i = 0; i < grad.length; ++i) {
604 result.grad[i] = FastMath.toRadians(grad[i]);
605 }
606 return result;
607 }
608
609
610
611
612
613 public T taylor(final double... delta) {
614 T result = value;
615 for (int i = 0; i < grad.length; ++i) {
616 result = result.add(grad[i].multiply(delta[i]));
617 }
618 return result;
619 }
620
621
622
623
624
625 public T taylor(@SuppressWarnings("unchecked") final T... delta) {
626 T result = value;
627 for (int i = 0; i < grad.length; ++i) {
628 result = result.add(grad[i].multiply(delta[i]));
629 }
630 return result;
631 }
632
633
634 @Override
635 public FieldGradient<T> linearCombination(final FieldGradient<T>[] a, final FieldGradient<T>[] b) {
636
637
638 final Field<T> field = a[0].value.getField();
639 final int n = a.length;
640 final T[] a0 = MathArrays.buildArray(field, n);
641 final T[] b0 = MathArrays.buildArray(field, n);
642 final T[] a1 = MathArrays.buildArray(field, 2 * n);
643 final T[] b1 = MathArrays.buildArray(field, 2 * n);
644 for (int i = 0; i < n; ++i) {
645 final FieldGradient<T> ai = a[i];
646 final FieldGradient<T> bi = b[i];
647 a0[i] = ai.value;
648 b0[i] = bi.value;
649 a1[2 * i] = ai.value;
650 b1[2 * i + 1] = bi.value;
651 }
652
653 final FieldGradient<T> result = newInstance(a[0].value.linearCombination(a0, b0));
654 for (int k = 0; k < grad.length; ++k) {
655 for (int i = 0; i < n; ++i) {
656 a1[2 * i + 1] = a[i].grad[k];
657 b1[2 * i] = b[i].grad[k];
658 }
659 result.grad[k] = a[0].value.linearCombination(a1, b1);
660 }
661 return result;
662
663 }
664
665
666
667
668
669
670
671
672 public FieldGradient<T> linearCombination(final T[] a, final FieldGradient<T>[] b) {
673
674
675 final Field<T> field = b[0].value.getField();
676 final int n = b.length;
677 final T[] b0 = MathArrays.buildArray(field, n);
678 final T[] b1 = MathArrays.buildArray(field, n);
679 for (int i = 0; i < n; ++i) {
680 b0[i] = b[i].value;
681 }
682
683 final FieldGradient<T> result = newInstance(b[0].value.linearCombination(a, b0));
684 for (int k = 0; k < grad.length; ++k) {
685 for (int i = 0; i < n; ++i) {
686 b1[i] = b[i].grad[k];
687 }
688 result.grad[k] = b[0].value.linearCombination(a, b1);
689 }
690 return result;
691
692 }
693
694
695 @Override
696 public FieldGradient<T> linearCombination(final double[] a, final FieldGradient<T>[] b) {
697
698
699 final Field<T> field = b[0].value.getField();
700 final int n = b.length;
701 final T[] b0 = MathArrays.buildArray(field, n);
702 final T[] b1 = MathArrays.buildArray(field, n);
703 for (int i = 0; i < n; ++i) {
704 b0[i] = b[i].value;
705 }
706
707 final FieldGradient<T> result = newInstance(b[0].value.linearCombination(a, b0));
708 for (int k = 0; k < grad.length; ++k) {
709 for (int i = 0; i < n; ++i) {
710 b1[i] = b[i].grad[k];
711 }
712 result.grad[k] = b[0].value.linearCombination(a, b1);
713 }
714 return result;
715
716 }
717
718
719 @Override
720 public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
721 final FieldGradient<T> a2, final FieldGradient<T> b2) {
722 final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
723 a2.value, b2.value));
724 for (int i = 0; i < b1.grad.length; ++i) {
725 result.grad[i] = a1.value.linearCombination(a1.value, b1.grad[i],
726 a1.grad[i], b1.value,
727 a2.value, b2.grad[i],
728 a2.grad[i], b2.value);
729 }
730 return result;
731 }
732
733
734 @Override
735 public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
736 final double a2, final FieldGradient<T> b2) {
737 final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
738 a2, b2.value));
739 for (int i = 0; i < b1.grad.length; ++i) {
740 result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
741 a2, b2.grad[i]);
742 }
743 return result;
744 }
745
746
747 @Override
748 public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
749 final FieldGradient<T> a2, final FieldGradient<T> b2,
750 final FieldGradient<T> a3, final FieldGradient<T> b3) {
751 final Field<T> field = a1.value.getField();
752 final T[] a = MathArrays.buildArray(field, 6);
753 final T[] b = MathArrays.buildArray(field, 6);
754 a[0] = a1.value;
755 a[2] = a2.value;
756 a[4] = a3.value;
757 b[1] = b1.value;
758 b[3] = b2.value;
759 b[5] = b3.value;
760 final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
761 a2.value, b2.value,
762 a3.value, b3.value));
763 for (int i = 0; i < b1.grad.length; ++i) {
764 a[1] = a1.grad[i];
765 a[3] = a2.grad[i];
766 a[5] = a3.grad[i];
767 b[0] = b1.grad[i];
768 b[2] = b2.grad[i];
769 b[4] = b3.grad[i];
770 result.grad[i] = a1.value.linearCombination(a, b);
771 }
772 return result;
773 }
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789 public FieldGradient<T> linearCombination(final T a1, final FieldGradient<T> b1,
790 final T a2, final FieldGradient<T> b2,
791 final T a3, final FieldGradient<T> b3) {
792 final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
793 a2, b2.value,
794 a3, b3.value));
795 for (int i = 0; i < b1.grad.length; ++i) {
796 result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
797 a2, b2.grad[i],
798 a3, b3.grad[i]);
799 }
800 return result;
801 }
802
803
804 @Override
805 public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
806 final double a2, final FieldGradient<T> b2,
807 final double a3, final FieldGradient<T> b3) {
808 final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
809 a2, b2.value,
810 a3, b3.value));
811 for (int i = 0; i < b1.grad.length; ++i) {
812 result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
813 a2, b2.grad[i],
814 a3, b3.grad[i]);
815 }
816 return result;
817 }
818
819
820 @Override
821 public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
822 final FieldGradient<T> a2, final FieldGradient<T> b2,
823 final FieldGradient<T> a3, final FieldGradient<T> b3,
824 final FieldGradient<T> a4, final FieldGradient<T> b4) {
825 final Field<T> field = a1.value.getField();
826 final T[] a = MathArrays.buildArray(field, 8);
827 final T[] b = MathArrays.buildArray(field, 8);
828 a[0] = a1.value;
829 a[2] = a2.value;
830 a[4] = a3.value;
831 a[6] = a4.value;
832 b[1] = b1.value;
833 b[3] = b2.value;
834 b[5] = b3.value;
835 b[7] = b4.value;
836 final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
837 a2.value, b2.value,
838 a3.value, b3.value,
839 a4.value, b4.value));
840 for (int i = 0; i < b1.grad.length; ++i) {
841 a[1] = a1.grad[i];
842 a[3] = a2.grad[i];
843 a[5] = a3.grad[i];
844 a[7] = a4.grad[i];
845 b[0] = b1.grad[i];
846 b[2] = b2.grad[i];
847 b[4] = b3.grad[i];
848 b[6] = b4.grad[i];
849 result.grad[i] = a1.value.linearCombination(a, b);
850 }
851 return result;
852 }
853
854
855 @Override
856 public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
857 final double a2, final FieldGradient<T> b2,
858 final double a3, final FieldGradient<T> b3,
859 final double a4, final FieldGradient<T> b4) {
860 final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
861 a2, b2.value,
862 a3, b3.value,
863 a4, b4.value));
864 for (int i = 0; i < b1.grad.length; ++i) {
865 result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
866 a2, b2.grad[i],
867 a3, b3.grad[i],
868 a4, b4.grad[i]);
869 }
870 return result;
871 }
872
873
874 @Override
875 public FieldGradient<T> getPi() {
876 return new FieldGradient<>(getValueField().getZero().getPi(), getFreeParameters());
877 }
878
879
880
881
882
883
884
885
886 @Override
887 public boolean equals(Object other) {
888
889 if (this == other) {
890 return true;
891 }
892
893 if (other instanceof FieldGradient) {
894 @SuppressWarnings("unchecked")
895 final FieldGradient<T> rhs = (FieldGradient<T>) other;
896 if (!value.equals(rhs.value) || grad.length != rhs.grad.length) {
897 return false;
898 }
899 for (int i = 0; i < grad.length; ++i) {
900 if (!grad[i].equals(rhs.grad[i])) {
901 return false;
902 }
903 }
904 return true;
905 }
906
907 return false;
908
909 }
910
911
912
913
914 @Override
915 public int hashCode() {
916 return 129 + 7 *value.hashCode() - 15 * Arrays.hashCode(grad);
917 }
918
919 }