View Javadoc
1   /*
2    * Copyright (C) 2016 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.numerical.polynomials.estimators;
17  
18  import com.irurueta.algebra.Matrix;
19  import com.irurueta.numerical.LockedException;
20  import com.irurueta.numerical.NotReadyException;
21  import com.irurueta.numerical.polynomials.Polynomial;
22  
23  import java.util.Arrays;
24  import java.util.List;
25  
26  /**
27   * This class defines the interface for an estimator of a polynomial of a given
28   * degree using points where polynomials are evaluated.
29   */
30  @SuppressWarnings("Duplicates")
31  public abstract class PolynomialEstimator {
32  
33      /**
34       * Minimum allowed degree to be estimated
35       */
36      public static final int MIN_DEGREE = 1;
37  
38      /**
39       * Default estimator type.
40       */
41      public static final PolynomialEstimatorType DEFAULT_ESTIMATOR_TYPE =
42              PolynomialEstimatorType.LMSE_POLYNOMIAL_ESTIMATOR;
43  
44      /**
45       * Degree of polynomial to be estimated.
46       */
47      protected int degree;
48  
49      /**
50       * Collection of polynomial evaluations and their corresponding point of
51       * evaluation used to determine a polynomial of required degree.
52       */
53      protected List<PolynomialEvaluation> evaluations;
54  
55      /**
56       * True when estimator is estimating radial distortion.
57       */
58      protected boolean locked;
59  
60      /**
61       * Listener to be notified of events such as when estimation starts, ends or
62       * estimation progress changes.
63       */
64      protected PolynomialEstimatorListener listener;
65  
66      /**
67       * Constructor.
68       */
69      protected PolynomialEstimator() {
70          degree = MIN_DEGREE;
71      }
72  
73      /**
74       * Constructor.
75       *
76       * @param degree degree of polynomial to be estimated.
77       * @throws IllegalArgumentException if provided degree is less than 1.
78       */
79      protected PolynomialEstimator(final int degree) {
80          internalSetDegree(degree);
81      }
82  
83      /**
84       * Constructor.
85       *
86       * @param evaluations collection of polynomial evaluations.
87       */
88      protected PolynomialEstimator(final List<PolynomialEvaluation> evaluations) {
89          this();
90          this.evaluations = evaluations;
91      }
92  
93      /**
94       * Constructor.
95       *
96       * @param listener listener to be notified of events.
97       */
98      protected PolynomialEstimator(final PolynomialEstimatorListener listener) {
99          this();
100         this.listener = listener;
101     }
102 
103     /**
104      * Constructor.
105      *
106      * @param degree      degree of polynomial to be estimated.
107      * @param evaluations collection of polynomial evaluations.
108      * @throws IllegalArgumentException if provided degree is less than 1.
109      */
110     protected PolynomialEstimator(final int degree, final List<PolynomialEvaluation> evaluations) {
111         this(degree);
112         this.evaluations = evaluations;
113     }
114 
115     /**
116      * Constructor.
117      *
118      * @param degree   degree of polynomial to be estimated.
119      * @param listener listener to be notified of events.
120      * @throws IllegalArgumentException if provided degree is less than 1.
121      */
122     protected PolynomialEstimator(final int degree, final PolynomialEstimatorListener listener) {
123         this(degree);
124         this.listener = listener;
125     }
126 
127     /**
128      * Constructor.
129      *
130      * @param evaluations collection of polynomial evaluations.
131      * @param listener    listener to be notified of events.
132      */
133     protected PolynomialEstimator(
134             final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener) {
135         this(evaluations);
136         this.listener = listener;
137     }
138 
139     /**
140      * Constructor.
141      *
142      * @param degree      degree of polynomial to be estimated.
143      * @param evaluations collection of polynomial evaluations.
144      * @param listener    listener to be notified of events.
145      * @throws IllegalArgumentException if provided degree is less than 1.
146      */
147     protected PolynomialEstimator(
148             final int degree, final List<PolynomialEvaluation> evaluations,
149             final PolynomialEstimatorListener listener) {
150         this(degree, evaluations);
151         this.listener = listener;
152     }
153 
154     /**
155      * Gets degree of polynomial to be estimated.
156      *
157      * @return degree of polynomial to be estimated.
158      */
159     public int getDegree() {
160         return degree;
161     }
162 
163     /**
164      * Sets degree of polynomial to be estimated.
165      *
166      * @param degree degree of polynomial to be estimated.
167      * @throws IllegalArgumentException if provided degree is less than 1.
168      * @throws LockedException          if this instance is locked.
169      */
170     public void setDegree(final int degree) throws LockedException {
171         if (isLocked()) {
172             throw new LockedException();
173         }
174 
175         internalSetDegree(degree);
176     }
177 
178     /**
179      * Gets collection of polynomial evaluations and their corresponding point
180      * of evaluation used to determine a polynomial of required degree.
181      *
182      * @return collection of polynomial evaluations.
183      */
184     public List<PolynomialEvaluation> getEvaluations() {
185         return evaluations;
186     }
187 
188     /**
189      * Sets collection of polynomial evaluations and their corresponding point
190      * of evaluation used to determine a polynomial of required degree.
191      *
192      * @param evaluations collection of polynomial evaluations.
193      * @throws LockedException if this instance is locked.
194      */
195     public void setEvaluations(final List<PolynomialEvaluation> evaluations) throws LockedException {
196         if (isLocked()) {
197             throw new LockedException();
198         }
199 
200         this.evaluations = evaluations;
201     }
202 
203     /**
204      * Sets degree of polynomial to be estimated and collection of polynomial
205      * evaluations and their corresponding point of evaluation used to determine
206      * a polynomial of specified degree.
207      *
208      * @param degree      degree of polynomial to be estimated.
209      * @param evaluations collection of polynomial evaluations.
210      * @throws IllegalArgumentException if provided degree is less than 1.
211      * @throws LockedException          if this instance is locked.
212      */
213     public void setDegreeAndEvaluations(
214             final int degree, final List<PolynomialEvaluation> evaluations) throws LockedException {
215         setDegree(degree);
216         setEvaluations(evaluations);
217     }
218 
219     /**
220      * Determines whether estimation is ready to start with the given data
221      * and required degree of polynomial to be estimated
222      *
223      * @return true if estimator is ready, false otherwise.
224      */
225     public boolean isReady() {
226 
227         final var nParams = degree + 1;
228         if (evaluations == null || evaluations.size() < nParams) {
229             return false;
230         }
231 
232         // also ensure that at least a direct or integral evaluation exists
233         var count = 0;
234         for (final var eval : evaluations) {
235             if (eval.getType() == PolynomialEvaluationType.DIRECT_EVALUATION
236                     || eval.getType() == PolynomialEvaluationType.INTEGRAL_EVALUATION
237                     || eval.getType() == PolynomialEvaluationType.INTEGRAL_INTERVAL) {
238                 count++;
239             }
240         }
241 
242         return count >= 1 && evaluations.size() >= nParams;
243     }
244 
245     /**
246      * Gets minimum number of evaluations required to estimate a polynomial of
247      * the specified degree.
248      *
249      * @param degree degree of polynomial to be estimated.
250      * @return number of required evaluations.
251      * @throws IllegalArgumentException if provided degree is less than 1.
252      */
253     public static int getMinNumberOfEvaluations(final int degree) {
254         if (degree < MIN_DEGREE) {
255             throw new IllegalArgumentException();
256         }
257 
258         return degree + 1;
259     }
260 
261     /**
262      * Gets minimum number of evaluations required to estimate a polynomial of
263      * the specified degree.
264      *
265      * @return number of required evaluations.
266      */
267     public int getMinNumberOfEvaluations() {
268         return getMinNumberOfEvaluations(degree);
269     }
270 
271     /**
272      * Indicates whether this instance is locked.
273      *
274      * @return true if this estimator is busy estimating a polynomial, false
275      * otherwise.
276      */
277     public boolean isLocked() {
278         return locked;
279     }
280 
281     /**
282      * Gets listener to be notified of events such as when estimation starts,
283      * ends or estimation progress changes.
284      *
285      * @return listener to be notified of events.
286      */
287     public PolynomialEstimatorListener getListener() {
288         return listener;
289     }
290 
291     /**
292      * Sets listener to be notified of events such as when estimation starts,
293      * ends or estimation progress changes.
294      *
295      * @param listener listener to be notified of events.
296      * @throws LockedException if estimator is locked.
297      */
298     public void setListener(final PolynomialEstimatorListener listener) throws LockedException {
299         if (isLocked()) {
300             throw new LockedException();
301         }
302 
303         this.listener = listener;
304     }
305 
306     /**
307      * Estimates a polynomial based on provided evaluations.
308      *
309      * @return estimated polynomial.
310      * @throws LockedException               if estimator is locked.
311      * @throws NotReadyException             if estimator is not ready.
312      * @throws PolynomialEstimationException if polynomial estimation fails.
313      */
314     public abstract Polynomial estimate() throws LockedException, NotReadyException, PolynomialEstimationException;
315 
316     /**
317      * Returns type of polynomial estimator.
318      *
319      * @return type of polynomial estimator.
320      */
321     public abstract PolynomialEstimatorType getType();
322 
323     /**
324      * Creates an instance of a polynomial estimator using default
325      * type.
326      *
327      * @return an instance of a polynomial estimator.
328      */
329     public static PolynomialEstimator create() {
330         return create(DEFAULT_ESTIMATOR_TYPE);
331     }
332 
333     /**
334      * Creates an instance of a polynomial estimator using provided degree and
335      * default type.
336      *
337      * @param degree degree of polynomial to be estimated.
338      * @return an instance of a polynomial estimator.
339      * @throws IllegalArgumentException if provided degree is less than 1.
340      */
341     public static PolynomialEstimator create(final int degree) {
342         return create(degree, DEFAULT_ESTIMATOR_TYPE);
343     }
344 
345     /**
346      * Creates an instance of a polynomial estimator using provided evaluations,
347      * and default type and degree.
348      *
349      * @param evaluations collection of polynomial evaluations.
350      * @return an instance of a polynomial estimator.
351      */
352     public static PolynomialEstimator create(final List<PolynomialEvaluation> evaluations) {
353         return create(evaluations, DEFAULT_ESTIMATOR_TYPE);
354     }
355 
356     /**
357      * Creates an instance of a polynomial estimator using provided listener
358      * and default type and degree.
359      *
360      * @param listener listener to be notified of events.
361      * @return an instance of a polynomial estimator.
362      */
363     public static PolynomialEstimator create(final PolynomialEstimatorListener listener) {
364         return create(listener, DEFAULT_ESTIMATOR_TYPE);
365     }
366 
367     /**
368      * Creates an instance of a polynomial estimator using provided degree,
369      * polynomial evaluations and default type.
370      *
371      * @param degree      degree of polynomial to be estimated.
372      * @param evaluations collection of polynomial evaluations.
373      * @return an instance of a polynomial estimator.
374      * @throws IllegalArgumentException if provided degree is less than 1.
375      */
376     public static PolynomialEstimator create(final int degree, final List<PolynomialEvaluation> evaluations) {
377         return create(degree, evaluations, DEFAULT_ESTIMATOR_TYPE);
378     }
379 
380     /**
381      * Creates an instance of a polynomial estimator using provided degree,
382      * listener and default type.
383      *
384      * @param degree   degree of polynomial to be estimated.
385      * @param listener listener to be notified of events.
386      * @return an instance of a polynomial estimator.
387      * @throws IllegalArgumentException if provided degree is less than 1.
388      */
389     public static PolynomialEstimator create(final int degree, final PolynomialEstimatorListener listener) {
390         return create(degree, listener, DEFAULT_ESTIMATOR_TYPE);
391     }
392 
393     /**
394      * Creates an instance of a polynomial estimator using provided evaluations,
395      * listener and default type.
396      *
397      * @param evaluations collection of polynomial evaluations.
398      * @param listener    listener to be notified of events.
399      * @return an instance of a polynomial estimator.
400      */
401     public static PolynomialEstimator create(
402             final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener) {
403         return create(evaluations, listener, DEFAULT_ESTIMATOR_TYPE);
404     }
405 
406     /**
407      * Creates an instance of a polynomial estimator using provided degree,
408      * evaluations, listener and default type.
409      *
410      * @param degree      degree of polynomial to be estimated.
411      * @param evaluations collection of polynomial evaluations.
412      * @param listener    listener to be notified of events.
413      * @return an instance of a polynomial estimator.
414      * @throws IllegalArgumentException if provided degree is less than 1.
415      */
416     public static PolynomialEstimator create(
417             final int degree, final List<PolynomialEvaluation> evaluations,
418             final PolynomialEstimatorListener listener) {
419         return create(degree, evaluations, listener, DEFAULT_ESTIMATOR_TYPE);
420     }
421 
422     /**
423      * Creates an instance of a polynomial estimator using provided type and
424      * default degree.
425      *
426      * @param type type of polynomial estimator
427      * @return an instance of a polynomial estimator.
428      */
429     public static PolynomialEstimator create(final PolynomialEstimatorType type) {
430         if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
431             return new WeightedPolynomialEstimator();
432         } else {
433             return new LMSEPolynomialEstimator();
434         }
435     }
436 
437     /**
438      * Creates an instance of a polynomial estimator using provided degree and
439      * type.
440      *
441      * @param degree degree of polynomial to be estimated.
442      * @param type   type of polynomial estimator.
443      * @return an instance of a polynomial estimator.
444      * @throws IllegalArgumentException if provided degree is less than 1.
445      */
446     public static PolynomialEstimator create(final int degree, final PolynomialEstimatorType type) {
447         if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
448             return new WeightedPolynomialEstimator(degree);
449         } else {
450             return new LMSEPolynomialEstimator(degree);
451         }
452     }
453 
454     /**
455      * Creates an instance of a polynomial estimator using provided evaluations
456      * and type.
457      *
458      * @param evaluations collection of polynomial evaluations.
459      * @param type        type of polynomial estimator.
460      * @return an instance of a polynomial estimator.
461      */
462     public static PolynomialEstimator create(
463             final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorType type) {
464         switch (type) {
465             case WEIGHTED_POLYNOMIAL_ESTIMATOR:
466                 final var weights = new double[evaluations.size()];
467                 Arrays.fill(weights, 1.0);
468                 return new WeightedPolynomialEstimator(evaluations, weights);
469             case LMSE_POLYNOMIAL_ESTIMATOR:
470             default:
471                 return new LMSEPolynomialEstimator(evaluations);
472         }
473     }
474 
475     /**
476      * Creates an instance of a polynomial estimator using provided listener
477      * and type.
478      *
479      * @param listener listener to be notified of events.
480      * @param type     type of polynomial estimator.
481      * @return an instance of a polynomial estimator.
482      */
483     public static PolynomialEstimator create(
484             final PolynomialEstimatorListener listener, final PolynomialEstimatorType type) {
485         if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
486             return new WeightedPolynomialEstimator(listener);
487         } else {
488             return new LMSEPolynomialEstimator(listener);
489         }
490     }
491 
492     /**
493      * Creates an instance of a polynomial estimator using provided degree,
494      * evaluations and type.
495      *
496      * @param degree      degree of polynomial to be estimated.
497      * @param evaluations collection of polynomial evaluations.
498      * @param type        type of polynomial estimator.
499      * @return an instance of a polynomial estimator.
500      * @throws IllegalArgumentException if provided degree is less than 1.
501      */
502     public static PolynomialEstimator create(
503             final int degree, final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorType type) {
504         switch (type) {
505             case WEIGHTED_POLYNOMIAL_ESTIMATOR:
506                 final var weights = new double[evaluations.size()];
507                 Arrays.fill(weights, 1.0);
508                 return new WeightedPolynomialEstimator(degree, evaluations, weights);
509             case LMSE_POLYNOMIAL_ESTIMATOR:
510             default:
511                 return new LMSEPolynomialEstimator(degree, evaluations);
512         }
513     }
514 
515     /**
516      * Creates an instance of a polynomial estimator using provided degree,
517      * listener and type.
518      *
519      * @param degree   degree of polynomial to be estimated.
520      * @param listener listener to be notified of events.
521      * @param type     type of polynomial estimator.
522      * @return an instance of a polynomial estimator.
523      * @throws IllegalArgumentException if provided degree is less than 1.
524      */
525     public static PolynomialEstimator create(
526             final int degree, final PolynomialEstimatorListener listener, final PolynomialEstimatorType type) {
527         if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
528             return new WeightedPolynomialEstimator(degree, listener);
529         } else {
530             return new LMSEPolynomialEstimator(degree, listener);
531         }
532     }
533 
534     /**
535      * Creates an instance of a polynomial estimator using provided evaluations,
536      * listener and type.
537      *
538      * @param evaluations collection of polynomial evaluations.
539      * @param listener    listener to be notified of events.
540      * @param type        type of polynomial estimator.
541      * @return an instance of a polynomial estimator.
542      */
543     public static PolynomialEstimator create(
544             final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener,
545             final PolynomialEstimatorType type) {
546         switch (type) {
547             case WEIGHTED_POLYNOMIAL_ESTIMATOR:
548                 final var weights = new double[evaluations.size()];
549                 Arrays.fill(weights, 1.0);
550                 return new WeightedPolynomialEstimator(evaluations, weights, listener);
551             case LMSE_POLYNOMIAL_ESTIMATOR:
552             default:
553                 return new LMSEPolynomialEstimator(evaluations, listener);
554         }
555     }
556 
557     /**
558      * Creates an instance of a polynomial estimator using provided degree,
559      * evaluations, listener and type.
560      *
561      * @param degree      degree of polynomial to be estimated.
562      * @param evaluations collection of polynomial evaluations.
563      * @param listener    listener to be notified of events.
564      * @param type        type of polynomial estimator.
565      * @return an instance of a polynomial estimator.
566      * @throws IllegalArgumentException if provided degree is less than 1.
567      */
568     public static PolynomialEstimator create(
569             final int degree, final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener,
570             final PolynomialEstimatorType type) {
571         switch (type) {
572             case WEIGHTED_POLYNOMIAL_ESTIMATOR:
573                 final var weights = new double[evaluations.size()];
574                 Arrays.fill(weights, 1.0);
575                 return new WeightedPolynomialEstimator(degree, evaluations, weights, listener);
576             case LMSE_POLYNOMIAL_ESTIMATOR:
577             default:
578                 return new LMSEPolynomialEstimator(degree, evaluations, listener);
579         }
580     }
581 
582     /**
583      * Fills row of system of equations for a direct polynomial evaluation.
584      *
585      * @param evaluation a direct polynomial evaluation.
586      * @param a          system matrix.
587      * @param b          values matrix.
588      * @param row        row to be filled.
589      */
590     protected void fillDirectEvaluation(
591             final DirectPolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row) {
592 
593         var powX = 1.0;
594         final var x = evaluation.getX();
595         for (var i = 0; i < a.getColumns(); i++) {
596             a.setElementAt(row, i, powX);
597             powX *= x;
598         }
599 
600         b.setElementAtIndex(row, evaluation.getEvaluation());
601     }
602 
603     /**
604      * Fills row of system of equations for a derivative polynomial evaluation.
605      *
606      * @param evaluation a derivative polynomial evaluation.
607      * @param a          system matrix.
608      * @param b          values matrix.
609      * @param row        row to be filled.
610      */
611     protected void fillDerivativeEvaluation(
612             final DerivativePolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row) {
613 
614         final var order = evaluation.getDerivativeOrder();
615 
616         for (var i = 0; i < order; i++) {
617             a.setElementAt(row, i, 0.0);
618         }
619 
620         var powX = 1.0;
621         final var x = evaluation.getX();
622         for (var i = order; i < a.getColumns(); i++) {
623             var param = i;
624             for (var j = 1; j < order; j++) {
625                 param *= i - j;
626             }
627             a.setElementAt(row, i, param * powX);
628             powX *= x;
629         }
630 
631         b.setElementAtIndex(row, evaluation.getEvaluation());
632     }
633 
634     /**
635      * Fills row of system of equations for an integral polynomial evaluation.
636      *
637      * @param evaluation an integral polynomial evaluation.
638      * @param a          system matrix.
639      * @param b          values matrix.
640      * @param row        row to be filled.
641      * @throws PolynomialEstimationException if constant terms does not have
642      *                                       proper size (it must be null or have order length).
643      */
644     protected void fillIntegralEvaluation(
645             final IntegralPolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row)
646             throws PolynomialEstimationException {
647 
648         final var order = evaluation.getIntegralOrder();
649         final var constants = evaluation.getConstants();
650         if (constants != null && constants.length != order) {
651             throw new PolynomialEstimationException();
652         }
653 
654         var accum = 0.0;
655         var powX = 1.0;
656         final var x = evaluation.getX();
657         for (var i = 0; i < order; i++) {
658             if (constants != null) {
659                 var param = 1;
660                 for (var k = 1; k <= i; k++) {
661                     param *= k;
662                 }
663                 accum += constants[i] / param * powX;
664             }
665             powX *= x;
666         }
667 
668         for (int i = 0, j = order; i < a.getColumns(); i++, j++) {
669             var param = j;
670             for (var k = 1; k < order; k++) {
671                 param *= j - k;
672             }
673             a.setElementAt(row, i, powX / param);
674             powX *= x;
675         }
676 
677         b.setElementAtIndex(row, evaluation.getEvaluation() - accum);
678     }
679 
680     /**
681      * Fills row of system of equations for a polynomial evaluation of an
682      * interval integration.
683      *
684      * @param evaluation an interval integration of a polynomial evaluation.
685      * @param a          system matrix.
686      * @param b          values matrix.
687      * @param row        row to be filled.
688      * @throws PolynomialEstimationException if constant terms does not have
689      *                                       proper size (it must be null or have order length).
690      */
691     protected void fillIntegralIntervalEvaluation(
692             final IntegralIntervalPolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row)
693             throws PolynomialEstimationException {
694 
695         final var order = evaluation.getIntegralOrder();
696         final var constants = evaluation.getConstants();
697         if (constants != null && constants.length != order) {
698             throw new PolynomialEstimationException();
699         }
700 
701         var accum = 0.0;
702         var powStartX = 1.0;
703         var powEndX = 1.0;
704         final var startX = evaluation.getStartX();
705         final var endX = evaluation.getEndX();
706         for (var i = 0; i < order; i++) {
707             if (constants != null) {
708                 var param = 1;
709                 for (var k = 1; k <= i; k++) {
710                     param *= k;
711                 }
712                 accum += constants[i] / param * (powEndX - powStartX);
713             }
714             powStartX *= startX;
715             powEndX *= endX;
716         }
717 
718         for (int i = 0, j = order; i < a.getColumns(); i++, j++) {
719             var param = j;
720             for (var k = 1; k < order; k++) {
721                 param *= j - k;
722             }
723             a.setElementAt(row, i, (powEndX - powStartX) / param);
724             powStartX *= startX;
725             powEndX *= endX;
726         }
727 
728         b.setElementAtIndex(row, evaluation.getEvaluation() - accum);
729     }
730 
731     /**
732      * Normalizes rows of system matrix and values matrix to increase accuracy
733      * of linear system of equations to be solved.
734      *
735      * @param a   system matrix.
736      * @param b   values matrix.
737      * @param row row to normalize.
738      */
739     protected void normalize(final Matrix a, final Matrix b, final int row) {
740         var sqrNorm = 0.0;
741         for (var i = 0; i < a.getColumns(); i++) {
742             sqrNorm += Math.pow(a.getElementAt(row, i), 2.0);
743         }
744         sqrNorm += Math.pow(b.getElementAtIndex(row), 2.0);
745 
746         final var norm = Math.sqrt(sqrNorm);
747 
748         for (var i = 0; i < a.getColumns(); i++) {
749             a.setElementAt(row, i, a.getElementAt(row, i) / norm);
750         }
751         b.setElementAtIndex(row, b.getElementAtIndex(row) / norm);
752     }
753 
754     /**
755      * Internal method to set degree of polynomial to be estimated.
756      *
757      * @param degree degree of polynomial to be estimated.
758      * @throws IllegalArgumentException if provided degree is less than 1.
759      */
760     private void internalSetDegree(final int degree) {
761         if (degree < MIN_DEGREE) {
762             throw new IllegalArgumentException("degree must be at least 1");
763         }
764         this.degree = degree;
765     }
766 }