View Javadoc
1   /*
2    * Licensed to the Hipparchus project 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 Hipparchus project 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    *      https://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   */
17  package org.hipparchus.util;
18  
19  import java.util.Arrays;
20  
21  import org.hipparchus.CalculusFieldElement;
22  import org.hipparchus.Field;
23  import org.hipparchus.exception.MathIllegalArgumentException;
24  
25  /**
26   * This class allows to perform the same computation of all components of a Tuple at once.
27   * @param <T> the type of the field elements
28   * @since 1.2
29   */
30  public class FieldTuple<T extends CalculusFieldElement<T>> implements CalculusFieldElement<FieldTuple<T>> {
31  
32      /** Components of the tuple. */
33      private final T[] values;
34  
35      /** Field the instance belongs to. */
36      private final transient FieldTupleField<T> field;
37  
38      /** Creates a new instance from its components.
39       * @param x components of the tuple
40       */
41      @SafeVarargs
42      public FieldTuple(final T... x) {
43          this(new FieldTupleField<>(x[0].getField(), x.length), x.clone());
44      }
45  
46      /** Creates a new instance from its components.
47       * @param field field the instance belongs to
48       * @param x components of the tuple (beware, it is <em>not</em> copied, it is shared with caller)
49       */
50      private FieldTuple(final FieldTupleField<T> field, final T[] x) { // NOPMD - storing user-supplied array is intentional and documented here
51          this.values = x;
52          this.field  = field;
53      }
54  
55      /** {@inheritDoc} */
56      @Override
57      public FieldTuple<T> newInstance(final double value) {
58          return field.getZero().add(value);
59      }
60  
61      /** Get the dimension of the tuple.
62       * @return dimension of the tuple
63       */
64      public int getDimension() {
65          return values.length;
66      }
67  
68      /** Get one component of the tuple.
69       * @param index index of the component, between 0 and {@link #getDimension() getDimension()} - 1
70       * @return value of the component
71       */
72      public T getComponent(final int index) {
73          return values[index];
74      }
75  
76      /** Get all components of the tuple.
77       * @return all components
78       */
79      public T[] getComponents() {
80          return values.clone();
81      }
82  
83      /** {@inheritDoc} */
84      @Override
85      public Field<FieldTuple<T>> getField() {
86          return field;
87      }
88  
89      /** {@inheritDoc} */
90      @Override
91      public FieldTuple<T> add(final FieldTuple<T> a) {
92          final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
93          for (int i = 0; i < values.length; ++i) {
94              result.values[i] = values[i].add(a.values[i]);
95          }
96          return result;
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public FieldTuple<T> subtract(final FieldTuple<T> a) {
102         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
103         for (int i = 0; i < values.length; ++i) {
104             result.values[i] = values[i].subtract(a.values[i]);
105         }
106         return result;
107     }
108 
109     /** {@inheritDoc} */
110     @Override
111     public FieldTuple<T> negate() {
112         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
113         for (int i = 0; i < values.length; ++i) {
114             result.values[i] = values[i].negate();
115         }
116         return result;
117     }
118 
119     /** {@inheritDoc} */
120     @Override
121     public FieldTuple<T> multiply(final FieldTuple<T> a) {
122         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
123         for (int i = 0; i < values.length; ++i) {
124             result.values[i] = values[i].multiply(a.values[i]);
125         }
126         return result;
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public FieldTuple<T> multiply(final int n) {
132         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
133         for (int i = 0; i < values.length; ++i) {
134             result.values[i] = values[i].multiply(n);
135         }
136         return result;
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public FieldTuple<T> divide(final FieldTuple<T> a) {
142         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
143         for (int i = 0; i < values.length; ++i) {
144             result.values[i] = values[i].divide(a.values[i]);
145         }
146         return result;
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public FieldTuple<T> reciprocal() {
152         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
153         for (int i = 0; i < values.length; ++i) {
154             result.values[i] = values[i].reciprocal();
155         }
156         return result;
157     }
158 
159     /** {@inheritDoc} */
160     @Override
161     public boolean equals(final Object obj) {
162         if (obj instanceof FieldTuple<?> ) {
163             @SuppressWarnings("unchecked")
164             final FieldTuple<T> that = (FieldTuple<T>) obj;
165             if (getDimension() == that.getDimension()) {
166                 boolean equals = true;
167                 for (int i = 0; i < values.length; ++i) {
168                     equals &= values[i].equals(that.values[i]);
169                 }
170                 return equals;
171             }
172         }
173         return false;
174     }
175 
176     /** {@inheritDoc} */
177     @Override
178     public int hashCode() {
179         return  0x58f61de5 + Arrays.hashCode(values);
180     }
181 
182     /** {@inheritDoc} */
183     @Override
184     public double getReal() {
185         return values[0].getReal();
186     }
187 
188     /** {@inheritDoc} */
189     @Override
190     public FieldTuple<T> add(final double a) {
191         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
192         for (int i = 0; i < values.length; ++i) {
193             result.values[i] = values[i].add(a);
194         }
195         return result;
196     }
197 
198     /** {@inheritDoc} */
199     @Override
200     public FieldTuple<T> subtract(final double a) {
201         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
202         for (int i = 0; i < values.length; ++i) {
203             result.values[i] = values[i].subtract(a);
204         }
205         return result;
206     }
207 
208     /** {@inheritDoc} */
209     @Override
210     public FieldTuple<T> multiply(final double a) {
211         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
212         for (int i = 0; i < values.length; ++i) {
213             result.values[i] = values[i].multiply(a);
214         }
215         return result;
216     }
217 
218     /** {@inheritDoc} */
219     @Override
220     public FieldTuple<T> square() {
221         return multiply(this);
222     }
223 
224     /** {@inheritDoc} */
225     @Override
226     public FieldTuple<T> divide(final double a) {
227         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
228         for (int i = 0; i < values.length; ++i) {
229             result.values[i] = values[i].divide(a);
230         }
231         return result;
232     }
233 
234     /** {@inheritDoc} */
235     @Override
236     public FieldTuple<T> remainder(final double a) {
237         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
238         for (int i = 0; i < values.length; ++i) {
239             result.values[i] = values[i].remainder(a);
240         }
241         return result;
242     }
243 
244     /** {@inheritDoc} */
245     @Override
246     public FieldTuple<T> remainder(final FieldTuple<T> a) {
247         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
248         for (int i = 0; i < values.length; ++i) {
249             result.values[i] = values[i].remainder(a.values[i]);
250         }
251         return result;
252     }
253 
254     /** {@inheritDoc} */
255     @Override
256     public FieldTuple<T> abs() {
257         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
258         for (int i = 0; i < values.length; ++i) {
259             result.values[i] = values[i].abs();
260         }
261         return result;
262     }
263 
264     /** {@inheritDoc} */
265     @Override
266     public FieldTuple<T> ceil() {
267         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
268         for (int i = 0; i < values.length; ++i) {
269             result.values[i] = values[i].ceil();
270         }
271         return result;
272     }
273 
274     /** {@inheritDoc} */
275     @Override
276     public FieldTuple<T> floor() {
277         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
278         for (int i = 0; i < values.length; ++i) {
279             result.values[i] = values[i].floor();
280         }
281         return result;
282     }
283 
284     /** {@inheritDoc} */
285     @Override
286     public FieldTuple<T> rint() {
287         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
288         for (int i = 0; i < values.length; ++i) {
289             result.values[i] = values[i].rint();
290         }
291         return result;
292     }
293 
294     /** {@inheritDoc} */
295     @Override
296     public FieldTuple<T> sign() {
297         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
298         for (int i = 0; i < values.length; ++i) {
299             result.values[i] = values[i].sign();
300         }
301         return result;
302     }
303 
304     /** {@inheritDoc} */
305     @Override
306     public FieldTuple<T> copySign(final FieldTuple<T> sign) {
307         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
308         for (int i = 0; i < values.length; ++i) {
309             result.values[i] = values[i].copySign(sign.values[i]);
310         }
311         return result;
312     }
313 
314     /** {@inheritDoc} */
315     @Override
316     public FieldTuple<T> copySign(final double sign) {
317         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
318         for (int i = 0; i < values.length; ++i) {
319             result.values[i] = values[i].copySign(sign);
320         }
321         return result;
322     }
323 
324     /** {@inheritDoc} */
325     @Override
326     public FieldTuple<T> scalb(final int n) {
327         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
328         for (int i = 0; i < values.length; ++i) {
329             result.values[i] = values[i].scalb(n);
330         }
331         return result;
332     }
333 
334     /** {@inheritDoc} */
335     @Override
336     public FieldTuple<T> ulp() {
337         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
338         for (int i = 0; i < values.length; ++i) {
339             result.values[i] = values[i].ulp();
340         }
341         return result;
342     }
343 
344     /** {@inheritDoc} */
345     @Override
346     public FieldTuple<T> hypot(final FieldTuple<T> y) {
347         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
348         for (int i = 0; i < values.length; ++i) {
349             result.values[i] = values[i].hypot(y.values[i]);
350         }
351         return result;
352     }
353 
354     /** {@inheritDoc} */
355     @Override
356     public FieldTuple<T> sqrt() {
357         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
358         for (int i = 0; i < values.length; ++i) {
359             result.values[i] = values[i].sqrt();
360         }
361         return result;
362     }
363 
364     /** {@inheritDoc} */
365     @Override
366     public FieldTuple<T> cbrt() {
367         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
368         for (int i = 0; i < values.length; ++i) {
369             result.values[i] = values[i].cbrt();
370         }
371         return result;
372     }
373 
374     /** {@inheritDoc} */
375     @Override
376     public FieldTuple<T> rootN(final int n) {
377         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
378         for (int i = 0; i < values.length; ++i) {
379             result.values[i] = values[i].rootN(n);
380         }
381         return result;
382     }
383 
384     /** {@inheritDoc} */
385     @Override
386     public FieldTuple<T> pow(final double p) {
387         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
388         for (int i = 0; i < values.length; ++i) {
389             result.values[i] = values[i].pow(p);
390         }
391         return result;
392     }
393 
394     /** {@inheritDoc} */
395     @Override
396     public FieldTuple<T> pow(final int n) {
397         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
398         for (int i = 0; i < values.length; ++i) {
399             result.values[i] = values[i].pow(n);
400         }
401         return result;
402     }
403 
404     /** {@inheritDoc} */
405     @Override
406     public FieldTuple<T> pow(final FieldTuple<T> e) {
407         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
408         for (int i = 0; i < values.length; ++i) {
409             result.values[i] = values[i].pow(e.values[i]);
410         }
411         return result;
412     }
413 
414     /** {@inheritDoc} */
415     @Override
416     public FieldTuple<T> exp() {
417         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
418         for (int i = 0; i < values.length; ++i) {
419             result.values[i] = values[i].exp();
420         }
421         return result;
422     }
423 
424     /** {@inheritDoc} */
425     @Override
426     public FieldTuple<T> expm1() {
427         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
428         for (int i = 0; i < values.length; ++i) {
429             result.values[i] = values[i].expm1();
430         }
431         return result;
432     }
433 
434     /** {@inheritDoc} */
435     @Override
436     public FieldTuple<T> log() {
437         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
438         for (int i = 0; i < values.length; ++i) {
439             result.values[i] = values[i].log();
440         }
441         return result;
442     }
443 
444     /** {@inheritDoc} */
445     @Override
446     public FieldTuple<T> log1p() {
447         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
448         for (int i = 0; i < values.length; ++i) {
449             result.values[i] = values[i].log1p();
450         }
451         return result;
452     }
453 
454     /** {@inheritDoc} */
455     @Override
456     public FieldTuple<T> log10() {
457         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
458         for (int i = 0; i < values.length; ++i) {
459             result.values[i] = values[i].log10();
460         }
461         return result;
462     }
463 
464     /** {@inheritDoc} */
465     @Override
466     public FieldTuple<T> cos() {
467         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
468         for (int i = 0; i < values.length; ++i) {
469             result.values[i] = values[i].cos();
470         }
471         return result;
472     }
473 
474     /** {@inheritDoc} */
475     @Override
476     public FieldTuple<T> sin() {
477         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
478         for (int i = 0; i < values.length; ++i) {
479             result.values[i] = values[i].sin();
480         }
481         return result;
482     }
483 
484     /** {@inheritDoc} */
485     @Override
486     public FieldSinCos<FieldTuple<T>> sinCos() {
487         final FieldTuple<T> sin = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
488         final FieldTuple<T> cos = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
489         for (int i = 0; i < values.length; ++i) {
490             final FieldSinCos<T> sc = FastMath.sinCos(values[i]);
491             sin.values[i] = sc.sin();
492             cos.values[i] = sc.cos();
493         }
494         return new FieldSinCos<>(sin, cos);
495     }
496 
497     /** {@inheritDoc} */
498     @Override
499     public FieldTuple<T> tan() {
500         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
501         for (int i = 0; i < values.length; ++i) {
502             result.values[i] = values[i].tan();
503         }
504         return result;
505     }
506 
507     /** {@inheritDoc} */
508     @Override
509     public FieldTuple<T> acos() {
510         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
511         for (int i = 0; i < values.length; ++i) {
512             result.values[i] = values[i].acos();
513         }
514         return result;
515     }
516 
517     /** {@inheritDoc} */
518     @Override
519     public FieldTuple<T> asin() {
520         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
521         for (int i = 0; i < values.length; ++i) {
522             result.values[i] = values[i].asin();
523         }
524         return result;
525     }
526 
527     /** {@inheritDoc} */
528     @Override
529     public FieldTuple<T> atan() {
530         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
531         for (int i = 0; i < values.length; ++i) {
532             result.values[i] = values[i].atan();
533         }
534         return result;
535     }
536 
537     /** {@inheritDoc} */
538     @Override
539     public FieldTuple<T> atan2(final FieldTuple<T> x) {
540         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
541         for (int i = 0; i < values.length; ++i) {
542             result.values[i] = values[i].atan2(x.values[i]);
543         }
544         return result;
545     }
546 
547     /** {@inheritDoc} */
548     @Override
549     public FieldTuple<T> cosh() {
550         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
551         for (int i = 0; i < values.length; ++i) {
552             result.values[i] = values[i].cosh();
553         }
554         return result;
555     }
556 
557     /** {@inheritDoc} */
558     @Override
559     public FieldTuple<T> sinh() {
560         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
561         for (int i = 0; i < values.length; ++i) {
562             result.values[i] = values[i].sinh();
563         }
564         return result;
565     }
566 
567     /** {@inheritDoc} */
568     @Override
569     public FieldSinhCosh<FieldTuple<T>> sinhCosh() {
570         final FieldTuple<T> sinh = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
571         final FieldTuple<T> cosh = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
572         for (int i = 0; i < values.length; ++i) {
573             final FieldSinhCosh<T> sc = FastMath.sinhCosh(values[i]);
574             sinh.values[i] = sc.sinh();
575             cosh.values[i] = sc.cosh();
576         }
577         return new FieldSinhCosh<>(sinh, cosh);
578     }
579 
580     /** {@inheritDoc} */
581     @Override
582     public FieldTuple<T> tanh() {
583         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
584         for (int i = 0; i < values.length; ++i) {
585             result.values[i] = values[i].tanh();
586         }
587         return result;
588     }
589 
590     /** {@inheritDoc} */
591     @Override
592     public FieldTuple<T> acosh() {
593         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
594         for (int i = 0; i < values.length; ++i) {
595             result.values[i] = values[i].acosh();
596         }
597         return result;
598     }
599 
600     /** {@inheritDoc} */
601     @Override
602     public FieldTuple<T> asinh() {
603         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
604         for (int i = 0; i < values.length; ++i) {
605             result.values[i] = values[i].asinh();
606         }
607         return result;
608     }
609 
610     /** {@inheritDoc} */
611     @Override
612     public FieldTuple<T> atanh() {
613         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
614         for (int i = 0; i < values.length; ++i) {
615             result.values[i] = values[i].atanh();
616         }
617         return result;
618     }
619 
620     /** {@inheritDoc} */
621     @Override
622     public FieldTuple<T> toDegrees() {
623         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
624         for (int i = 0; i < values.length; ++i) {
625             result.values[i] = values[i].toDegrees();
626         }
627         return result;
628     }
629 
630     /** {@inheritDoc} */
631     @Override
632     public FieldTuple<T> toRadians() {
633         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
634         for (int i = 0; i < values.length; ++i) {
635             result.values[i] = values[i].toRadians();
636         }
637         return result;
638     }
639 
640     /** {@inheritDoc} */
641     @Override
642     public FieldTuple<T> linearCombination(final FieldTuple<T>[] a, final FieldTuple<T>[] b)
643         throws MathIllegalArgumentException {
644         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
645         MathUtils.checkDimension(a.length, b.length);
646         final T[] aT = MathArrays.buildArray(values[0].getField(), a.length);
647         final T[] bT = MathArrays.buildArray(values[0].getField(), b.length);
648         for (int i = 0; i < values.length; ++i) {
649             for (int j = 0; j < a.length; ++j) {
650                 aT[j] = a[j].values[i];
651                 bT[j] = b[j].values[i];
652             }
653             result.values[i] = aT[0].linearCombination(aT, bT);
654         }
655         return result;
656     }
657 
658     /** {@inheritDoc} */
659     @Override
660     public FieldTuple<T> linearCombination(final double[] a, final FieldTuple<T>[] b)
661         throws MathIllegalArgumentException {
662         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
663         MathUtils.checkDimension(a.length, b.length);
664         final T[] bT = MathArrays.buildArray(values[0].getField(), b.length);
665         for (int i = 0; i < values.length; ++i) {
666             for (int j = 0; j < a.length; ++j) {
667                 bT[j] = b[j].values[i];
668             }
669             result.values[i] = bT[0].linearCombination(a, bT);
670         }
671         return result;
672     }
673 
674     /** {@inheritDoc} */
675     @Override
676     public FieldTuple<T> linearCombination(final FieldTuple<T> a1, final FieldTuple<T> b1,
677                                            final FieldTuple<T> a2, final FieldTuple<T> b2) {
678         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
679         for (int i = 0; i < values.length; ++i) {
680             result.values[i] = a1.values[0].linearCombination(a1.values[i], b1.values[i],
681                                                               a2.values[i], b2.values[i]);
682         }
683         return result;
684     }
685 
686     /** {@inheritDoc} */
687     @Override
688     public FieldTuple<T> linearCombination(final double a1, final FieldTuple<T> b1,
689                                            final double a2, final FieldTuple<T> b2) {
690         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
691         for (int i = 0; i < values.length; ++i) {
692             result.values[i] = b1.values[0].linearCombination(a1, b1.values[i],
693                                                               a2, b2.values[i]);
694         }
695         return result;
696     }
697 
698     /** {@inheritDoc} */
699     @Override
700     public FieldTuple<T> linearCombination(final FieldTuple<T> a1, final FieldTuple<T> b1,
701                                            final FieldTuple<T> a2, final FieldTuple<T> b2,
702                                            final FieldTuple<T> a3, final FieldTuple<T> b3) {
703         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
704         for (int i = 0; i < values.length; ++i) {
705             result.values[i] = a1.values[0].linearCombination(a1.values[i], b1.values[i],
706                                                               a2.values[i], b2.values[i],
707                                                               a3.values[i], b3.values[i]);
708         }
709         return result;
710     }
711 
712     /** {@inheritDoc} */
713     @Override
714     public FieldTuple<T> linearCombination(final double a1, final FieldTuple<T> b1,
715                                            final double a2, final FieldTuple<T> b2,
716                                            final double a3, final FieldTuple<T> b3) {
717         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
718         for (int i = 0; i < values.length; ++i) {
719             result.values[i] = b1.values[0].linearCombination(a1, b1.values[i],
720                                                               a2, b2.values[i],
721                                                               a3, b3.values[i]);
722         }
723         return result;
724     }
725 
726     /** {@inheritDoc} */
727     @Override
728     public FieldTuple<T> linearCombination(final FieldTuple<T> a1, final FieldTuple<T> b1,
729                                            final FieldTuple<T> a2, final FieldTuple<T> b2,
730                                            final FieldTuple<T> a3, final FieldTuple<T> b3,
731                                            final FieldTuple<T> a4, final FieldTuple<T> b4) {
732         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
733         for (int i = 0; i < values.length; ++i) {
734             result.values[i] = a1.values[0].linearCombination(a1.values[i], b1.values[i],
735                                                               a2.values[i], b2.values[i],
736                                                               a3.values[i], b3.values[i],
737                                                               a4.values[i], b4.values[i]);
738         }
739         return result;
740     }
741 
742     /** {@inheritDoc} */
743     @Override
744     public FieldTuple<T> linearCombination(final double a1, final FieldTuple<T> b1,
745                                            final double a2, final FieldTuple<T> b2,
746                                            final double a3, final FieldTuple<T> b3,
747                                            final double a4, final FieldTuple<T> b4) {
748         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
749         for (int i = 0; i < values.length; ++i) {
750             result.values[i] = b1.values[0].linearCombination(a1, b1.values[i],
751                                                               a2, b2.values[i],
752                                                               a3, b3.values[i],
753                                                               a4, b4.values[i]);
754         }
755         return result;
756     }
757 
758     /** {@inheritDoc} */
759     @Override
760     public FieldTuple<T> getPi() {
761         final FieldTuple<T> result = new FieldTuple<>(field, MathArrays.buildArray(values[0].getField(), values.length));
762         Arrays.fill(result.values, values[0].getPi());
763         return result;
764     }
765 
766     /** Field for {link FieldTuple} instances.
767      * @param <T> the type of the field elements
768      */
769     private static class FieldTupleField<T extends CalculusFieldElement<T>> implements Field<FieldTuple<T>> {
770 
771         /** Constant function evaluating to 0.0. */
772         private final FieldTuple<T> zero;
773 
774         /** Constant function evaluating to 1.0. */
775         private final FieldTuple<T> one;
776 
777         /** Simple constructor.
778          * @param field field to which the elements belong
779          * @param dimension dimension of the tuple
780          */
781         FieldTupleField(final Field<T> field, final int dimension) {
782             final T[] zeroData = MathArrays.buildArray(field, dimension);
783             Arrays.fill(zeroData, field.getZero());
784             final T[] oneData  = MathArrays.buildArray(field, dimension);
785             Arrays.fill(oneData, field.getOne());
786             this.zero = new FieldTuple<>(this, zeroData);
787             this.one  = new FieldTuple<>(this, oneData);
788         }
789 
790         /** {@inheritDoc} */
791         @Override
792         public FieldTuple<T> getZero() {
793             return zero;
794         }
795 
796         /** {@inheritDoc} */
797         @Override
798         public FieldTuple<T> getOne() {
799             return one;
800         }
801 
802         /** {@inheritDoc} */
803         @SuppressWarnings("unchecked")
804         @Override
805         public Class<FieldTuple<T>> getRuntimeClass() {
806             return (Class<FieldTuple<T>>) zero.getClass();
807         }
808 
809         /** {@inheritDoc} */
810         @Override
811         public boolean equals(final Object other) {
812             if (other instanceof FieldTupleField) {
813                 @SuppressWarnings("unchecked")
814                 final FieldTupleField<T> that = (FieldTupleField<T>) other;
815                 return zero.getDimension() == that.zero.getDimension();
816             } else {
817                 return false;
818             }
819         }
820 
821         /** {@inheritDoc} */
822         @Override
823         public int hashCode() {
824             return 0xb4a533e1 ^ zero.getDimension();
825         }
826 
827     }
828 
829 }