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