001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.numbers.core;
018
019/**
020 * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)">Norm</a> functions.
021 *
022 * <p>The implementations provide increased numerical accuracy.
023 * Algorithms primary source is the 2005 paper
024 * <a href="https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
025 * Accurate Sum and Dot Product</a> by Takeshi Ogita, Siegfried M. Rump,
026 * and Shin'ichi Oishi published in <em>SIAM J. Sci. Comput</em>.
027 */
028public enum Norm {
029    /**
030     * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Taxicab_norm_or_Manhattan_norm">
031     *  Manhattan norm</a> (sum of the absolute values of the arguments).
032     */
033    L1(Norm::manhattan, Norm::manhattan, Norm::manhattan),
034    /** Alias for {@link #L1}. */
035    MANHATTAN(L1),
036    /** <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm">Euclidean norm</a>. */
037    L2(Norm::euclidean, Norm::euclidean, Norm::euclidean),
038    /** Alias for {@link #L2}. */
039    EUCLIDEAN(L2),
040    /**
041     * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Maximum_norm_(special_case_of:_infinity_norm,_uniform_norm,_or_supremum_norm)">
042     *  Maximum norm</a> (maximum of the absolute values of the arguments).
043     */
044    LINF(Norm::maximum, Norm::maximum, Norm::maximum),
045    /** Alias for {@link #LINF}. */
046    MAXIMUM(LINF);
047
048    /**
049     * Threshold for scaling small numbers. This value is chosen such that doubles
050     * set to this value can be squared without underflow. Values less than this must
051     * be scaled up.
052     */
053    private static final double SMALL_THRESH = 0x1.0p-511;
054    /**
055     * Threshold for scaling large numbers. This value is chosen such that 2^31 doubles
056     * set to this value can be squared and added without overflow. Values greater than
057     * this must be scaled down.
058     */
059    private static final double LARGE_THRESH = 0x1.0p+496;
060    /**
061     * Threshold for scaling up a single value by {@link #SCALE_UP} without risking
062     * overflow when the value is squared.
063     */
064    private static final double SAFE_SCALE_UP_THRESH = 0x1.0p-100;
065    /** Value used to scale down large numbers. */
066    private static final double SCALE_DOWN = 0x1.0p-600;
067    /** Value used to scale up small numbers. */
068    private static final double SCALE_UP = 0x1.0p+600;
069
070    /** Threshold for the difference between the exponents of two Euclidean 2D input values
071     * where the larger value dominates the calculation.
072     */
073    private static final int EXP_DIFF_THRESHOLD_2D = 54;
074
075    /** Function of 2 arguments. */
076    private final Two two;
077    /** Function of 3 arguments. */
078    private final Three three;
079    /** Function of array argument. */
080    private final Array array;
081
082    /** Function of 2 arguments. */
083    @FunctionalInterface
084    private interface Two {
085        /**
086         * @param x Argument.
087         * @param y Argument.
088         * @return the norm.
089         */
090        double of(double x, double y);
091    }
092    /** Function of 3 arguments. */
093    @FunctionalInterface
094    private interface Three {
095        /**
096         * @param x Argument.
097         * @param y Argument.
098         * @param z Argument.
099         * @return the norm.
100         */
101        double of(double x, double y, double z);
102    }
103    /** Function of array argument. */
104    @FunctionalInterface
105    private interface Array {
106        /**
107         * @param v Array of arguments.
108         * @return the norm.
109         */
110        double of(double[] v);
111    }
112
113    /**
114     * @param two Function of 2 arguments.
115     * @param three Function of 3 arguments.
116     * @param array Function of array argument.
117     */
118    Norm(Two two,
119         Three three,
120         Array array) {
121        this.two = two;
122        this.three = three;
123        this.array = array;
124    }
125
126    /**
127     * @param alias Alternative name.
128     */
129    Norm(Norm alias) {
130        this.two = alias.two;
131        this.three = alias.three;
132        this.array = alias.array;
133    }
134
135    /**
136     * Computes the norm.
137     *
138     * <p>Special cases:
139     * <ul>
140     *  <li>If either value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
141     *  <li>If either value is infinite and the other value is not {@link Double#NaN}, then
142     *   the result is {@link Double#POSITIVE_INFINITY}.</li>
143     * </ul>
144     *
145     * @param x Argument.
146     * @param y Argument.
147     * @return the norm.
148     */
149    public final double of(double x,
150                           double y) {
151        return two.of(x, y);
152    }
153
154    /**
155     * Computes the norm.
156     *
157     * <p>Special cases:
158     * <ul>
159     *  <li>If any value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
160     *  <li>If any value is infinite and no value is not {@link Double#NaN}, then the
161     *   result is {@link Double#POSITIVE_INFINITY}.</li>
162     * </ul>
163     *
164     * @param x Argument.
165     * @param y Argument.
166     * @param z Argument.
167     * @return the norm.
168     */
169    public final double of(double x,
170                           double y,
171                           double z) {
172        return three.of(x, y, z);
173    }
174
175    /**
176     * Computes the norm.
177     *
178     * <p>Special cases:
179     * <ul>
180     *  <li>If any value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
181     *  <li>If any value is infinite and no value is not {@link Double#NaN}, then the
182     *   result is {@link Double#POSITIVE_INFINITY}.</li>
183     * </ul>
184     *
185     * @param v Argument.
186     * @return the norm.
187     * @throws IllegalArgumentException if the array is empty.
188     */
189    public final double of(double[] v) {
190        ensureNonEmpty(v);
191        return array.of(v);
192    }
193
194    /** Computes the Manhattan norm.
195     *
196     * @param x first input value
197     * @param y second input value
198     * @return \(|x| + |y|\).
199     *
200     * @see #L1
201     * @see #MANHATTAN
202     * @see #of(double,double)
203     */
204    private static double manhattan(final double x,
205                                    final double y) {
206        return Math.abs(x) + Math.abs(y);
207    }
208
209    /** Computes the Manhattan norm.
210     *
211     * @param x first input value
212     * @param y second input value
213     * @param z third input value
214     * @return \(|x| + |y| + |z|\)
215     *
216     * @see #L1
217     * @see #MANHATTAN
218     * @see #of(double,double,double)
219     */
220    private static double manhattan(final double x,
221                                    final double y,
222                                    final double z) {
223        return Sum.of(Math.abs(x))
224            .add(Math.abs(y))
225            .add(Math.abs(z))
226            .getAsDouble();
227    }
228
229    /** Computes the Manhattan norm.
230     *
231     * @param v input values
232     * @return \(|v_0| + ... + |v_i|\)
233     *
234     * @see #L1
235     * @see #MANHATTAN
236     * @see #of(double[])
237     */
238    private static double manhattan(final double[] v) {
239        final Sum sum = Sum.create();
240
241        for (final double d : v) {
242            sum.add(Math.abs(d));
243        }
244
245        return sum.getAsDouble();
246    }
247
248    /** Computes the Euclidean norm.
249     * This implementation handles possible overflow or underflow.
250     *
251     * <p><strong>Comparison with Math.hypot()</strong>
252     * While not guaranteed to return the same result, this method provides
253     * similar error bounds as {@link Math#hypot(double, double)} (and may run faster on
254     * some JVM).
255     *
256     * @param x first input
257     * @param y second input
258     * @return \(\sqrt{x^2 + y^2}\).
259     *
260     * @see #L2
261     * @see #EUCLIDEAN
262     * @see #of(double,double)
263     */
264    private static double euclidean(final double x,
265                                    final double y) {
266        final double xabs = Math.abs(x);
267        final double yabs = Math.abs(y);
268
269        final double max;
270        final double min;
271        // the compare method considers NaN greater than other values, meaning that our
272        // check for if the max is finite later on will detect NaNs correctly
273        if (Double.compare(xabs, yabs) > 0) {
274            max = xabs;
275            min = yabs;
276        } else {
277            max = yabs;
278            min = xabs;
279        }
280
281        // if the max is not finite, then one of the inputs must not have
282        // been finite
283        if (!Double.isFinite(max)) {
284            // let the standard multiply operation determine whether to return NaN or infinite
285            return xabs * yabs;
286        } else if (Math.getExponent(max) - Math.getExponent(min) > EXP_DIFF_THRESHOLD_2D) {
287            // value is completely dominated by max; just return max
288            return max;
289        }
290
291        // compute the scale and rescale values
292        final double scale;
293        final double rescale;
294        if (max > LARGE_THRESH) {
295            scale = SCALE_DOWN;
296            rescale = SCALE_UP;
297        } else if (max < SAFE_SCALE_UP_THRESH) {
298            scale = SCALE_UP;
299            rescale = SCALE_DOWN;
300        } else {
301            scale = 1d;
302            rescale = 1d;
303        }
304
305        // initialise sum and compensation using scaled x
306        final double sx = xabs * scale;
307        double sum = sx * sx;
308        double comp = DD.twoSquareLow(sx, sum);
309
310        // add scaled y
311        final double sy = yabs * scale;
312        final double py = sy * sy;
313        comp += DD.twoSquareLow(sy, py);
314        final double sumPy = sum + py;
315        comp += DD.twoSumLow(sum, py, sumPy);
316        sum = sumPy;
317
318        return Math.sqrt(sum + comp) * rescale;
319    }
320
321    /** Computes the Euclidean norm.
322     * This implementation handles possible overflow or underflow.
323     *
324     * @param x first input
325     * @param y second input
326     * @param z third input
327     * @return \(\sqrt{x^2 + y^2 + z^2}\)
328     *
329     * @see #L2
330     * @see #EUCLIDEAN
331     * @see #of(double,double,double)
332     */
333    private static double euclidean(final double x,
334                                    final double y,
335                                    final double z) {
336        final double xabs = Math.abs(x);
337        final double yabs = Math.abs(y);
338        final double zabs = Math.abs(z);
339
340        final double max = Math.max(Math.max(xabs, yabs), zabs);
341
342        // if the max is not finite, then one of the inputs must not have
343        // been finite
344        if (!Double.isFinite(max)) {
345            // let the standard multiply operation determine whether to
346            // return NaN or infinite
347            return xabs * yabs * zabs;
348        }
349
350        // compute the scale and rescale values
351        final double scale;
352        final double rescale;
353        if (max > LARGE_THRESH) {
354            scale = SCALE_DOWN;
355            rescale = SCALE_UP;
356        } else if (max < SAFE_SCALE_UP_THRESH) {
357            scale = SCALE_UP;
358            rescale = SCALE_DOWN;
359        } else {
360            scale = 1d;
361            rescale = 1d;
362        }
363
364
365        // initialise sum and compensation using scaled x
366        final double sx = xabs * scale;
367        double sum = sx * sx;
368        double comp = DD.twoSquareLow(sx, sum);
369
370        // add scaled y
371        final double sy = yabs * scale;
372        final double py = sy * sy;
373        comp += DD.twoSquareLow(sy, py);
374        final double sumPy = sum + py;
375        comp += DD.twoSumLow(sum, py, sumPy);
376        sum = sumPy;
377
378        // add scaled z
379        final double sz = zabs * scale;
380        final double pz = sz * sz;
381        comp += DD.twoSquareLow(sz, pz);
382        final double sumPz = sum + pz;
383        comp += DD.twoSumLow(sum, pz, sumPz);
384        sum = sumPz;
385
386        return Math.sqrt(sum + comp) * rescale;
387    }
388
389    /** Computes the Euclidean norm.
390     * This implementation handles possible overflow or underflow.
391     *
392     * @param v input values
393     * @return \(\sqrt{v_0^2 + ... + v_{n-1}^2}\).
394     *
395     * @see #L2
396     * @see #EUCLIDEAN
397     * @see #of(double[])
398     */
399    private static double euclidean(final double[] v) {
400        // sum of big, normal and small numbers
401        double s1 = 0;
402        double s2 = 0;
403        double s3 = 0;
404
405        // sum compensation values
406        double c1 = 0;
407        double c2 = 0;
408        double c3 = 0;
409
410        for (int i = 0; i < v.length; ++i) {
411            final double x = Math.abs(v[i]);
412            if (!Double.isFinite(x)) {
413                // not finite; determine whether to return NaN or positive infinity
414                return euclideanNormSpecial(v, i);
415            } else if (x > LARGE_THRESH) {
416                // scale down
417                final double sx = x * SCALE_DOWN;
418
419                // compute the product and product compensation
420                final double p = sx * sx;
421                final double cp = DD.twoSquareLow(sx, p);
422
423                // compute the running sum and sum compensation
424                final double s = s1 + p;
425                final double cs = DD.twoSumLow(s1, p, s);
426
427                // update running totals
428                c1 += cp + cs;
429                s1 = s;
430            } else if (x < SMALL_THRESH) {
431                // scale up
432                final double sx = x * SCALE_UP;
433
434                // compute the product and product compensation
435                final double p = sx * sx;
436                final double cp = DD.twoSquareLow(sx, p);
437
438                // compute the running sum and sum compensation
439                final double s = s3 + p;
440                final double cs = DD.twoSumLow(s3, p, s);
441
442                // update running totals
443                c3 += cp + cs;
444                s3 = s;
445            } else {
446                // no scaling
447                // compute the product and product compensation
448                final double p = x * x;
449                final double cp = DD.twoSquareLow(x, p);
450
451                // compute the running sum and sum compensation
452                final double s = s2 + p;
453                final double cs = DD.twoSumLow(s2, p, s);
454
455                // update running totals
456                c2 += cp + cs;
457                s2 = s;
458            }
459        }
460
461        // The highest sum is the significant component. Add the next significant.
462        // Note that the "x * SCALE_DOWN * SCALE_DOWN" expressions must be executed
463        // in the order given. If the two scale factors are multiplied together first,
464        // they will underflow to zero.
465        if (s1 != 0) {
466            // add s1, s2, c1, c2
467            final double s2Adj = s2 * SCALE_DOWN * SCALE_DOWN;
468            final double sum = s1 + s2Adj;
469            final double comp = DD.twoSumLow(s1, s2Adj, sum) +
470                c1 + (c2 * SCALE_DOWN * SCALE_DOWN);
471            return Math.sqrt(sum + comp) * SCALE_UP;
472        } else if (s2 != 0) {
473            // add s2, s3, c2, c3
474            final double s3Adj = s3 * SCALE_DOWN * SCALE_DOWN;
475            final double sum = s2 + s3Adj;
476            final double comp = DD.twoSumLow(s2, s3Adj, sum) +
477                c2 + (c3 * SCALE_DOWN * SCALE_DOWN);
478            return Math.sqrt(sum + comp);
479        }
480        // add s3, c3
481        return Math.sqrt(s3 + c3) * SCALE_DOWN;
482    }
483
484    /** Special cases of non-finite input.
485     *
486     * @param v input vector
487     * @param start index to start examining the input vector from
488     * @return Euclidean norm special value
489     */
490    private static double euclideanNormSpecial(final double[] v,
491                                               final int start) {
492        for (int i = start; i < v.length; ++i) {
493            if (Double.isNaN(v[i])) {
494                return Double.NaN;
495            }
496        }
497        return Double.POSITIVE_INFINITY;
498    }
499
500    /** Computes the maximum norm.
501     *
502     * @param x first input
503     * @param y second input
504     * @return \(\max{(|x|, |y|)}\).
505     *
506     * @see #LINF
507     * @see #MAXIMUM
508     * @see #of(double,double)
509     */
510    private static double maximum(final double x,
511                                  final double y) {
512        return Math.max(Math.abs(x), Math.abs(y));
513    }
514
515    /** Computes the maximum norm.
516     *
517     * @param x first input
518     * @param y second input
519     * @param z third input
520     * @return \(\max{(|x|, |y|, |z|)}\).
521     *
522     * @see #LINF
523     * @see #MAXIMUM
524     * @see #of(double,double,double)
525     */
526    private static double maximum(final double x,
527                                  final double y,
528                                  final double z) {
529        return Math.max(Math.abs(x),
530                        Math.max(Math.abs(y),
531                                 Math.abs(z)));
532    }
533
534    /** Computes the maximum norm.
535     *
536     * @param v input values
537     * @return \(\max{(|v_0|, \ldots, |v_{n-1}|)}\)
538     *
539     * @see #LINF
540     * @see #MAXIMUM
541     * @see #of(double[])
542     */
543    private static double maximum(final double[] v) {
544        double max = 0d;
545        for (final double d : v) {
546            max = Math.max(max, Math.abs(d));
547        }
548        return max;
549    }
550
551    /**
552     * @param a Array.
553     * @throws IllegalArgumentException for zero-size array.
554     */
555    private static void ensureNonEmpty(double[] a) {
556        if (a.length == 0) {
557            throw new IllegalArgumentException("Empty array");
558        }
559    }
560}