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