source: src/main/java/agents/anac/y2019/harddealer/math3/analysis/differentiation/SparseGradient.java

Last change on this file was 204, checked in by Katsuhide Fujita, 5 years ago

Fixed errors of ANAC2019 agents

  • Property svn:executable set to *
File size: 30.0 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package agents.anac.y2019.harddealer.math3.analysis.differentiation;
18
19import java.io.Serializable;
20import java.util.Collections;
21import java.util.HashMap;
22import java.util.Map;
23
24import agents.anac.y2019.harddealer.math3.Field;
25import agents.anac.y2019.harddealer.math3.FieldElement;
26import agents.anac.y2019.harddealer.math3.RealFieldElement;
27import agents.anac.y2019.harddealer.math3.exception.DimensionMismatchException;
28import agents.anac.y2019.harddealer.math3.util.FastMath;
29import agents.anac.y2019.harddealer.math3.util.MathArrays;
30import agents.anac.y2019.harddealer.math3.util.MathUtils;
31import agents.anac.y2019.harddealer.math3.util.Precision;
32
33/**
34 * First derivative computation with large number of variables.
35 * <p>
36 * This class plays a similar role to {@link DerivativeStructure}, with
37 * a focus on efficiency when dealing with large number of independent variables
38 * and most computation depend only on a few of them, and when only first derivative
39 * is desired. When these conditions are met, this class should be much faster than
40 * {@link DerivativeStructure} and use less memory.
41 * </p>
42 *
43 * @since 3.3
44 */
45public class SparseGradient implements RealFieldElement<SparseGradient>, Serializable {
46
47 /** Serializable UID. */
48 private static final long serialVersionUID = 20131025L;
49
50 /** Value of the calculation. */
51 private double value;
52
53 /** Stored derivative, each key representing a different independent variable. */
54 private final Map<Integer, Double> derivatives;
55
56 /** Internal constructor.
57 * @param value value of the function
58 * @param derivatives derivatives map, a deep copy will be performed,
59 * so the map given here will remain safe from changes in the new instance,
60 * may be null to create an empty derivatives map, i.e. a constant value
61 */
62 private SparseGradient(final double value, final Map<Integer, Double> derivatives) {
63 this.value = value;
64 this.derivatives = new HashMap<Integer, Double>();
65 if (derivatives != null) {
66 this.derivatives.putAll(derivatives);
67 }
68 }
69
70 /** Internal constructor.
71 * @param value value of the function
72 * @param scale scaling factor to apply to all derivatives
73 * @param derivatives derivatives map, a deep copy will be performed,
74 * so the map given here will remain safe from changes in the new instance,
75 * may be null to create an empty derivatives map, i.e. a constant value
76 */
77 private SparseGradient(final double value, final double scale,
78 final Map<Integer, Double> derivatives) {
79 this.value = value;
80 this.derivatives = new HashMap<Integer, Double>();
81 if (derivatives != null) {
82 for (final Map.Entry<Integer, Double> entry : derivatives.entrySet()) {
83 this.derivatives.put(entry.getKey(), scale * entry.getValue());
84 }
85 }
86 }
87
88 /** Factory method creating a constant.
89 * @param value value of the constant
90 * @return a new instance
91 */
92 public static SparseGradient createConstant(final double value) {
93 return new SparseGradient(value, Collections.<Integer, Double> emptyMap());
94 }
95
96 /** Factory method creating an independent variable.
97 * @param idx index of the variable
98 * @param value value of the variable
99 * @return a new instance
100 */
101 public static SparseGradient createVariable(final int idx, final double value) {
102 return new SparseGradient(value, Collections.singletonMap(idx, 1.0));
103 }
104
105 /**
106 * Find the number of variables.
107 * @return number of variables
108 */
109 public int numVars() {
110 return derivatives.size();
111 }
112
113 /**
114 * Get the derivative with respect to a particular index variable.
115 *
116 * @param index index to differentiate with.
117 * @return derivative with respect to a particular index variable
118 */
119 public double getDerivative(final int index) {
120 final Double out = derivatives.get(index);
121 return (out == null) ? 0.0 : out;
122 }
123
124 /**
125 * Get the value of the function.
126 * @return value of the function.
127 */
128 public double getValue() {
129 return value;
130 }
131
132 /** {@inheritDoc} */
133 public double getReal() {
134 return value;
135 }
136
137 /** {@inheritDoc} */
138 public SparseGradient add(final SparseGradient a) {
139 final SparseGradient out = new SparseGradient(value + a.value, derivatives);
140 for (Map.Entry<Integer, Double> entry : a.derivatives.entrySet()) {
141 final int id = entry.getKey();
142 final Double old = out.derivatives.get(id);
143 if (old == null) {
144 out.derivatives.put(id, entry.getValue());
145 } else {
146 out.derivatives.put(id, old + entry.getValue());
147 }
148 }
149
150 return out;
151 }
152
153 /**
154 * Add in place.
155 * <p>
156 * This method is designed to be faster when used multiple times in a loop.
157 * </p>
158 * <p>
159 * The instance is changed here, in order to not change the
160 * instance the {@link #add(SparseGradient)} method should
161 * be used.
162 * </p>
163 * @param a instance to add
164 */
165 public void addInPlace(final SparseGradient a) {
166 value += a.value;
167 for (final Map.Entry<Integer, Double> entry : a.derivatives.entrySet()) {
168 final int id = entry.getKey();
169 final Double old = derivatives.get(id);
170 if (old == null) {
171 derivatives.put(id, entry.getValue());
172 } else {
173 derivatives.put(id, old + entry.getValue());
174 }
175 }
176 }
177
178 /** {@inheritDoc} */
179 public SparseGradient add(final double c) {
180 final SparseGradient out = new SparseGradient(value + c, derivatives);
181 return out;
182 }
183
184 /** {@inheritDoc} */
185 public SparseGradient subtract(final SparseGradient a) {
186 final SparseGradient out = new SparseGradient(value - a.value, derivatives);
187 for (Map.Entry<Integer, Double> entry : a.derivatives.entrySet()) {
188 final int id = entry.getKey();
189 final Double old = out.derivatives.get(id);
190 if (old == null) {
191 out.derivatives.put(id, -entry.getValue());
192 } else {
193 out.derivatives.put(id, old - entry.getValue());
194 }
195 }
196 return out;
197 }
198
199 /** {@inheritDoc} */
200 public SparseGradient subtract(double c) {
201 return new SparseGradient(value - c, derivatives);
202 }
203
204 /** {@inheritDoc} */
205 public SparseGradient multiply(final SparseGradient a) {
206 final SparseGradient out =
207 new SparseGradient(value * a.value, Collections.<Integer, Double> emptyMap());
208
209 // Derivatives.
210 for (Map.Entry<Integer, Double> entry : derivatives.entrySet()) {
211 out.derivatives.put(entry.getKey(), a.value * entry.getValue());
212 }
213 for (Map.Entry<Integer, Double> entry : a.derivatives.entrySet()) {
214 final int id = entry.getKey();
215 final Double old = out.derivatives.get(id);
216 if (old == null) {
217 out.derivatives.put(id, value * entry.getValue());
218 } else {
219 out.derivatives.put(id, old + value * entry.getValue());
220 }
221 }
222 return out;
223 }
224
225 /**
226 * Multiply in place.
227 * <p>
228 * This method is designed to be faster when used multiple times in a loop.
229 * </p>
230 * <p>
231 * The instance is changed here, in order to not change the
232 * instance the {@link #add(SparseGradient)} method should
233 * be used.
234 * </p>
235 * @param a instance to multiply
236 */
237 public void multiplyInPlace(final SparseGradient a) {
238 // Derivatives.
239 for (Map.Entry<Integer, Double> entry : derivatives.entrySet()) {
240 derivatives.put(entry.getKey(), a.value * entry.getValue());
241 }
242 for (Map.Entry<Integer, Double> entry : a.derivatives.entrySet()) {
243 final int id = entry.getKey();
244 final Double old = derivatives.get(id);
245 if (old == null) {
246 derivatives.put(id, value * entry.getValue());
247 } else {
248 derivatives.put(id, old + value * entry.getValue());
249 }
250 }
251 value *= a.value;
252 }
253
254 /** {@inheritDoc} */
255 public SparseGradient multiply(final double c) {
256 return new SparseGradient(value * c, c, derivatives);
257 }
258
259 /** {@inheritDoc} */
260 public SparseGradient multiply(final int n) {
261 return new SparseGradient(value * n, n, derivatives);
262 }
263
264 /** {@inheritDoc} */
265 public SparseGradient divide(final SparseGradient a) {
266 final SparseGradient out = new SparseGradient(value / a.value, Collections.<Integer, Double> emptyMap());
267
268 // Derivatives.
269 for (Map.Entry<Integer, Double> entry : derivatives.entrySet()) {
270 out.derivatives.put(entry.getKey(), entry.getValue() / a.value);
271 }
272 for (Map.Entry<Integer, Double> entry : a.derivatives.entrySet()) {
273 final int id = entry.getKey();
274 final Double old = out.derivatives.get(id);
275 if (old == null) {
276 out.derivatives.put(id, -out.value / a.value * entry.getValue());
277 } else {
278 out.derivatives.put(id, old - out.value / a.value * entry.getValue());
279 }
280 }
281 return out;
282 }
283
284 /** {@inheritDoc} */
285 public SparseGradient divide(final double c) {
286 return new SparseGradient(value / c, 1.0 / c, derivatives);
287 }
288
289 /** {@inheritDoc} */
290 public SparseGradient negate() {
291 return new SparseGradient(-value, -1.0, derivatives);
292 }
293
294 /** {@inheritDoc} */
295 public Field<SparseGradient> getField() {
296 return new Field<SparseGradient>() {
297
298 /** {@inheritDoc} */
299 public SparseGradient getZero() {
300 return createConstant(0);
301 }
302
303 /** {@inheritDoc} */
304 public SparseGradient getOne() {
305 return createConstant(1);
306 }
307
308 /** {@inheritDoc} */
309 public Class<? extends FieldElement<SparseGradient>> getRuntimeClass() {
310 return SparseGradient.class;
311 }
312
313 };
314 }
315
316 /** {@inheritDoc} */
317 public SparseGradient remainder(final double a) {
318 return new SparseGradient(FastMath.IEEEremainder(value, a), derivatives);
319 }
320
321 /** {@inheritDoc} */
322 public SparseGradient remainder(final SparseGradient a) {
323
324 // compute k such that lhs % rhs = lhs - k rhs
325 final double rem = FastMath.IEEEremainder(value, a.value);
326 final double k = FastMath.rint((value - rem) / a.value);
327
328 return subtract(a.multiply(k));
329
330 }
331
332 /** {@inheritDoc} */
333 public SparseGradient abs() {
334 if (Double.doubleToLongBits(value) < 0) {
335 // we use the bits representation to also handle -0.0
336 return negate();
337 } else {
338 return this;
339 }
340 }
341
342 /** {@inheritDoc} */
343 public SparseGradient ceil() {
344 return createConstant(FastMath.ceil(value));
345 }
346
347 /** {@inheritDoc} */
348 public SparseGradient floor() {
349 return createConstant(FastMath.floor(value));
350 }
351
352 /** {@inheritDoc} */
353 public SparseGradient rint() {
354 return createConstant(FastMath.rint(value));
355 }
356
357 /** {@inheritDoc} */
358 public long round() {
359 return FastMath.round(value);
360 }
361
362 /** {@inheritDoc} */
363 public SparseGradient signum() {
364 return createConstant(FastMath.signum(value));
365 }
366
367 /** {@inheritDoc} */
368 public SparseGradient copySign(final SparseGradient sign) {
369 final long m = Double.doubleToLongBits(value);
370 final long s = Double.doubleToLongBits(sign.value);
371 if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
372 return this;
373 }
374 return negate(); // flip sign
375 }
376
377 /** {@inheritDoc} */
378 public SparseGradient copySign(final double sign) {
379 final long m = Double.doubleToLongBits(value);
380 final long s = Double.doubleToLongBits(sign);
381 if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
382 return this;
383 }
384 return negate(); // flip sign
385 }
386
387 /** {@inheritDoc} */
388 public SparseGradient scalb(final int n) {
389 final SparseGradient out = new SparseGradient(FastMath.scalb(value, n), Collections.<Integer, Double> emptyMap());
390 for (Map.Entry<Integer, Double> entry : derivatives.entrySet()) {
391 out.derivatives.put(entry.getKey(), FastMath.scalb(entry.getValue(), n));
392 }
393 return out;
394 }
395
396 /** {@inheritDoc} */
397 public SparseGradient hypot(final SparseGradient y) {
398 if (Double.isInfinite(value) || Double.isInfinite(y.value)) {
399 return createConstant(Double.POSITIVE_INFINITY);
400 } else if (Double.isNaN(value) || Double.isNaN(y.value)) {
401 return createConstant(Double.NaN);
402 } else {
403
404 final int expX = FastMath.getExponent(value);
405 final int expY = FastMath.getExponent(y.value);
406 if (expX > expY + 27) {
407 // y is negligible with respect to x
408 return abs();
409 } else if (expY > expX + 27) {
410 // x is negligible with respect to y
411 return y.abs();
412 } else {
413
414 // find an intermediate scale to avoid both overflow and underflow
415 final int middleExp = (expX + expY) / 2;
416
417 // scale parameters without losing precision
418 final SparseGradient scaledX = scalb(-middleExp);
419 final SparseGradient scaledY = y.scalb(-middleExp);
420
421 // compute scaled hypotenuse
422 final SparseGradient scaledH =
423 scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
424
425 // remove scaling
426 return scaledH.scalb(middleExp);
427
428 }
429
430 }
431 }
432
433 /**
434 * Returns the hypotenuse of a triangle with sides {@code x} and {@code y}
435 * - sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
436 * avoiding intermediate overflow or underflow.
437 *
438 * <ul>
439 * <li> If either argument is infinite, then the result is positive infinity.</li>
440 * <li> else, if either argument is NaN then the result is NaN.</li>
441 * </ul>
442 *
443 * @param x a value
444 * @param y a value
445 * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
446 */
447 public static SparseGradient hypot(final SparseGradient x, final SparseGradient y) {
448 return x.hypot(y);
449 }
450
451 /** {@inheritDoc} */
452 public SparseGradient reciprocal() {
453 return new SparseGradient(1.0 / value, -1.0 / (value * value), derivatives);
454 }
455
456 /** {@inheritDoc} */
457 public SparseGradient sqrt() {
458 final double sqrt = FastMath.sqrt(value);
459 return new SparseGradient(sqrt, 0.5 / sqrt, derivatives);
460 }
461
462 /** {@inheritDoc} */
463 public SparseGradient cbrt() {
464 final double cbrt = FastMath.cbrt(value);
465 return new SparseGradient(cbrt, 1.0 / (3 * cbrt * cbrt), derivatives);
466 }
467
468 /** {@inheritDoc} */
469 public SparseGradient rootN(final int n) {
470 if (n == 2) {
471 return sqrt();
472 } else if (n == 3) {
473 return cbrt();
474 } else {
475 final double root = FastMath.pow(value, 1.0 / n);
476 return new SparseGradient(root, 1.0 / (n * FastMath.pow(root, n - 1)), derivatives);
477 }
478 }
479
480 /** {@inheritDoc} */
481 public SparseGradient pow(final double p) {
482 return new SparseGradient(FastMath.pow(value, p), p * FastMath.pow(value, p - 1), derivatives);
483 }
484
485 /** {@inheritDoc} */
486 public SparseGradient pow(final int n) {
487 if (n == 0) {
488 return getField().getOne();
489 } else {
490 final double valueNm1 = FastMath.pow(value, n - 1);
491 return new SparseGradient(value * valueNm1, n * valueNm1, derivatives);
492 }
493 }
494
495 /** {@inheritDoc} */
496 public SparseGradient pow(final SparseGradient e) {
497 return log().multiply(e).exp();
498 }
499
500 /** Compute a<sup>x</sup> where a is a double and x a {@link SparseGradient}
501 * @param a number to exponentiate
502 * @param x power to apply
503 * @return a<sup>x</sup>
504 */
505 public static SparseGradient pow(final double a, final SparseGradient x) {
506 if (a == 0) {
507 if (x.value == 0) {
508 return x.compose(1.0, Double.NEGATIVE_INFINITY);
509 } else if (x.value < 0) {
510 return x.compose(Double.NaN, Double.NaN);
511 } else {
512 return x.getField().getZero();
513 }
514 } else {
515 final double ax = FastMath.pow(a, x.value);
516 return new SparseGradient(ax, ax * FastMath.log(a), x.derivatives);
517 }
518 }
519
520 /** {@inheritDoc} */
521 public SparseGradient exp() {
522 final double e = FastMath.exp(value);
523 return new SparseGradient(e, e, derivatives);
524 }
525
526 /** {@inheritDoc} */
527 public SparseGradient expm1() {
528 return new SparseGradient(FastMath.expm1(value), FastMath.exp(value), derivatives);
529 }
530
531 /** {@inheritDoc} */
532 public SparseGradient log() {
533 return new SparseGradient(FastMath.log(value), 1.0 / value, derivatives);
534 }
535
536 /** Base 10 logarithm.
537 * @return base 10 logarithm of the instance
538 */
539 public SparseGradient log10() {
540 return new SparseGradient(FastMath.log10(value), 1.0 / (FastMath.log(10.0) * value), derivatives);
541 }
542
543 /** {@inheritDoc} */
544 public SparseGradient log1p() {
545 return new SparseGradient(FastMath.log1p(value), 1.0 / (1.0 + value), derivatives);
546 }
547
548 /** {@inheritDoc} */
549 public SparseGradient cos() {
550 return new SparseGradient(FastMath.cos(value), -FastMath.sin(value), derivatives);
551 }
552
553 /** {@inheritDoc} */
554 public SparseGradient sin() {
555 return new SparseGradient(FastMath.sin(value), FastMath.cos(value), derivatives);
556 }
557
558 /** {@inheritDoc} */
559 public SparseGradient tan() {
560 final double t = FastMath.tan(value);
561 return new SparseGradient(t, 1 + t * t, derivatives);
562 }
563
564 /** {@inheritDoc} */
565 public SparseGradient acos() {
566 return new SparseGradient(FastMath.acos(value), -1.0 / FastMath.sqrt(1 - value * value), derivatives);
567 }
568
569 /** {@inheritDoc} */
570 public SparseGradient asin() {
571 return new SparseGradient(FastMath.asin(value), 1.0 / FastMath.sqrt(1 - value * value), derivatives);
572 }
573
574 /** {@inheritDoc} */
575 public SparseGradient atan() {
576 return new SparseGradient(FastMath.atan(value), 1.0 / (1 + value * value), derivatives);
577 }
578
579 /** {@inheritDoc} */
580 public SparseGradient atan2(final SparseGradient x) {
581
582 // compute r = sqrt(x^2+y^2)
583 final SparseGradient r = multiply(this).add(x.multiply(x)).sqrt();
584
585 final SparseGradient a;
586 if (x.value >= 0) {
587
588 // compute atan2(y, x) = 2 atan(y / (r + x))
589 a = divide(r.add(x)).atan().multiply(2);
590
591 } else {
592
593 // compute atan2(y, x) = +/- pi - 2 atan(y / (r - x))
594 final SparseGradient tmp = divide(r.subtract(x)).atan().multiply(-2);
595 a = tmp.add(tmp.value <= 0 ? -FastMath.PI : FastMath.PI);
596
597 }
598
599 // fix value to take special cases (+0/+0, +0/-0, -0/+0, -0/-0, +/-infinity) correctly
600 a.value = FastMath.atan2(value, x.value);
601
602 return a;
603
604 }
605
606 /** Two arguments arc tangent operation.
607 * @param y first argument of the arc tangent
608 * @param x second argument of the arc tangent
609 * @return atan2(y, x)
610 */
611 public static SparseGradient atan2(final SparseGradient y, final SparseGradient x) {
612 return y.atan2(x);
613 }
614
615 /** {@inheritDoc} */
616 public SparseGradient cosh() {
617 return new SparseGradient(FastMath.cosh(value), FastMath.sinh(value), derivatives);
618 }
619
620 /** {@inheritDoc} */
621 public SparseGradient sinh() {
622 return new SparseGradient(FastMath.sinh(value), FastMath.cosh(value), derivatives);
623 }
624
625 /** {@inheritDoc} */
626 public SparseGradient tanh() {
627 final double t = FastMath.tanh(value);
628 return new SparseGradient(t, 1 - t * t, derivatives);
629 }
630
631 /** {@inheritDoc} */
632 public SparseGradient acosh() {
633 return new SparseGradient(FastMath.acosh(value), 1.0 / FastMath.sqrt(value * value - 1.0), derivatives);
634 }
635
636 /** {@inheritDoc} */
637 public SparseGradient asinh() {
638 return new SparseGradient(FastMath.asinh(value), 1.0 / FastMath.sqrt(value * value + 1.0), derivatives);
639 }
640
641 /** {@inheritDoc} */
642 public SparseGradient atanh() {
643 return new SparseGradient(FastMath.atanh(value), 1.0 / (1.0 - value * value), derivatives);
644 }
645
646 /** Convert radians to degrees, with error of less than 0.5 ULP
647 * @return instance converted into degrees
648 */
649 public SparseGradient toDegrees() {
650 return new SparseGradient(FastMath.toDegrees(value), FastMath.toDegrees(1.0), derivatives);
651 }
652
653 /** Convert degrees to radians, with error of less than 0.5 ULP
654 * @return instance converted into radians
655 */
656 public SparseGradient toRadians() {
657 return new SparseGradient(FastMath.toRadians(value), FastMath.toRadians(1.0), derivatives);
658 }
659
660 /** Evaluate Taylor expansion of a sparse gradient.
661 * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
662 * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
663 */
664 public double taylor(final double ... delta) {
665 double y = value;
666 for (int i = 0; i < delta.length; ++i) {
667 y += delta[i] * getDerivative(i);
668 }
669 return y;
670 }
671
672 /** Compute composition of the instance by a univariate function.
673 * @param f0 value of the function at (i.e. f({@link #getValue()}))
674 * @param f1 first derivative of the function at
675 * the current point (i.e. f'({@link #getValue()}))
676 * @return f(this)
677 */
678 public SparseGradient compose(final double f0, final double f1) {
679 return new SparseGradient(f0, f1, derivatives);
680 }
681
682 /** {@inheritDoc} */
683 public SparseGradient linearCombination(final SparseGradient[] a,
684 final SparseGradient[] b)
685 throws DimensionMismatchException {
686
687 // compute a simple value, with all partial derivatives
688 SparseGradient out = a[0].getField().getZero();
689 for (int i = 0; i < a.length; ++i) {
690 out = out.add(a[i].multiply(b[i]));
691 }
692
693 // recompute an accurate value, taking care of cancellations
694 final double[] aDouble = new double[a.length];
695 for (int i = 0; i < a.length; ++i) {
696 aDouble[i] = a[i].getValue();
697 }
698 final double[] bDouble = new double[b.length];
699 for (int i = 0; i < b.length; ++i) {
700 bDouble[i] = b[i].getValue();
701 }
702 out.value = MathArrays.linearCombination(aDouble, bDouble);
703
704 return out;
705
706 }
707
708 /** {@inheritDoc} */
709 public SparseGradient linearCombination(final double[] a, final SparseGradient[] b) {
710
711 // compute a simple value, with all partial derivatives
712 SparseGradient out = b[0].getField().getZero();
713 for (int i = 0; i < a.length; ++i) {
714 out = out.add(b[i].multiply(a[i]));
715 }
716
717 // recompute an accurate value, taking care of cancellations
718 final double[] bDouble = new double[b.length];
719 for (int i = 0; i < b.length; ++i) {
720 bDouble[i] = b[i].getValue();
721 }
722 out.value = MathArrays.linearCombination(a, bDouble);
723
724 return out;
725
726 }
727
728 /** {@inheritDoc} */
729 public SparseGradient linearCombination(final SparseGradient a1, final SparseGradient b1,
730 final SparseGradient a2, final SparseGradient b2) {
731
732 // compute a simple value, with all partial derivatives
733 SparseGradient out = a1.multiply(b1).add(a2.multiply(b2));
734
735 // recompute an accurate value, taking care of cancellations
736 out.value = MathArrays.linearCombination(a1.value, b1.value, a2.value, b2.value);
737
738 return out;
739
740 }
741
742 /** {@inheritDoc} */
743 public SparseGradient linearCombination(final double a1, final SparseGradient b1,
744 final double a2, final SparseGradient b2) {
745
746 // compute a simple value, with all partial derivatives
747 SparseGradient out = b1.multiply(a1).add(b2.multiply(a2));
748
749 // recompute an accurate value, taking care of cancellations
750 out.value = MathArrays.linearCombination(a1, b1.value, a2, b2.value);
751
752 return out;
753
754 }
755
756 /** {@inheritDoc} */
757 public SparseGradient linearCombination(final SparseGradient a1, final SparseGradient b1,
758 final SparseGradient a2, final SparseGradient b2,
759 final SparseGradient a3, final SparseGradient b3) {
760
761 // compute a simple value, with all partial derivatives
762 SparseGradient out = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3));
763
764 // recompute an accurate value, taking care of cancellations
765 out.value = MathArrays.linearCombination(a1.value, b1.value,
766 a2.value, b2.value,
767 a3.value, b3.value);
768
769 return out;
770
771 }
772
773 /** {@inheritDoc} */
774 public SparseGradient linearCombination(final double a1, final SparseGradient b1,
775 final double a2, final SparseGradient b2,
776 final double a3, final SparseGradient b3) {
777
778 // compute a simple value, with all partial derivatives
779 SparseGradient out = b1.multiply(a1).add(b2.multiply(a2)).add(b3.multiply(a3));
780
781 // recompute an accurate value, taking care of cancellations
782 out.value = MathArrays.linearCombination(a1, b1.value,
783 a2, b2.value,
784 a3, b3.value);
785
786 return out;
787
788 }
789
790 /** {@inheritDoc} */
791 public SparseGradient linearCombination(final SparseGradient a1, final SparseGradient b1,
792 final SparseGradient a2, final SparseGradient b2,
793 final SparseGradient a3, final SparseGradient b3,
794 final SparseGradient a4, final SparseGradient b4) {
795
796 // compute a simple value, with all partial derivatives
797 SparseGradient out = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3)).add(a4.multiply(b4));
798
799 // recompute an accurate value, taking care of cancellations
800 out.value = MathArrays.linearCombination(a1.value, b1.value,
801 a2.value, b2.value,
802 a3.value, b3.value,
803 a4.value, b4.value);
804
805 return out;
806
807 }
808
809 /** {@inheritDoc} */
810 public SparseGradient linearCombination(final double a1, final SparseGradient b1,
811 final double a2, final SparseGradient b2,
812 final double a3, final SparseGradient b3,
813 final double a4, final SparseGradient b4) {
814
815 // compute a simple value, with all partial derivatives
816 SparseGradient out = b1.multiply(a1).add(b2.multiply(a2)).add(b3.multiply(a3)).add(b4.multiply(a4));
817
818 // recompute an accurate value, taking care of cancellations
819 out.value = MathArrays.linearCombination(a1, b1.value,
820 a2, b2.value,
821 a3, b3.value,
822 a4, b4.value);
823
824 return out;
825
826 }
827
828 /**
829 * Test for the equality of two sparse gradients.
830 * <p>
831 * Sparse gradients are considered equal if they have the same value
832 * and the same derivatives.
833 * </p>
834 * @param other Object to test for equality to this
835 * @return true if two sparse gradients are equal
836 */
837 @Override
838 public boolean equals(Object other) {
839
840 if (this == other) {
841 return true;
842 }
843
844 if (other instanceof SparseGradient) {
845 final SparseGradient rhs = (SparseGradient)other;
846 if (!Precision.equals(value, rhs.value, 1)) {
847 return false;
848 }
849 if (derivatives.size() != rhs.derivatives.size()) {
850 return false;
851 }
852 for (final Map.Entry<Integer, Double> entry : derivatives.entrySet()) {
853 if (!rhs.derivatives.containsKey(entry.getKey())) {
854 return false;
855 }
856 if (!Precision.equals(entry.getValue(), rhs.derivatives.get(entry.getKey()), 1)) {
857 return false;
858 }
859 }
860 return true;
861 }
862
863 return false;
864
865 }
866
867 /**
868 * Get a hashCode for the derivative structure.
869 * @return a hash code value for this object
870 * @since 3.2
871 */
872 @Override
873 public int hashCode() {
874 return 743 + 809 * MathUtils.hash(value) + 167 * derivatives.hashCode();
875 }
876
877}
Note: See TracBrowser for help on using the repository browser.