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