Norm.java

  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.  */
  17. package org.apache.commons.numbers.core;

  18. /**
  19.  * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)">Norm</a> functions.
  20.  *
  21.  * <p>The implementations provide increased numerical accuracy.
  22.  * Algorithms primary source is the 2005 paper
  23.  * <a href="https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.2.1547">
  24.  * Accurate Sum and Dot Product</a> by Takeshi Ogita, Siegfried M. Rump,
  25.  * and Shin'ichi Oishi published in <em>SIAM J. Sci. Comput</em>.
  26.  */
  27. public enum Norm {
  28.     /**
  29.      * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Taxicab_norm_or_Manhattan_norm">
  30.      *  Manhattan norm</a> (sum of the absolute values of the arguments).
  31.      */
  32.     L1(Norm::manhattan, Norm::manhattan, Norm::manhattan),
  33.     /** Alias for {@link #L1}. */
  34.     MANHATTAN(L1),
  35.     /** <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm">Euclidean norm</a>. */
  36.     L2(Norm::euclidean, Norm::euclidean, Norm::euclidean),
  37.     /** Alias for {@link #L2}. */
  38.     EUCLIDEAN(L2),
  39.     /**
  40.      * <a href="https://en.wikipedia.org/wiki/Norm_(mathematics)#Maximum_norm_(special_case_of:_infinity_norm,_uniform_norm,_or_supremum_norm)">
  41.      *  Maximum norm</a> (maximum of the absolute values of the arguments).
  42.      */
  43.     LINF(Norm::maximum, Norm::maximum, Norm::maximum),
  44.     /** Alias for {@link #LINF}. */
  45.     MAXIMUM(LINF);

  46.     /**
  47.      * Threshold for scaling small numbers. This value is chosen such that doubles
  48.      * set to this value can be squared without underflow. Values less than this must
  49.      * be scaled up.
  50.      */
  51.     private static final double SMALL_THRESH = 0x1.0p-511;
  52.     /**
  53.      * Threshold for scaling large numbers. This value is chosen such that 2^31 doubles
  54.      * set to this value can be squared and added without overflow. Values greater than
  55.      * this must be scaled down.
  56.      */
  57.     private static final double LARGE_THRESH = 0x1.0p+496;
  58.     /**
  59.      * Threshold for scaling up a single value by {@link #SCALE_UP} without risking
  60.      * overflow when the value is squared.
  61.      */
  62.     private static final double SAFE_SCALE_UP_THRESH = 0x1.0p-100;
  63.     /** Value used to scale down large numbers. */
  64.     private static final double SCALE_DOWN = 0x1.0p-600;
  65.     /** Value used to scale up small numbers. */
  66.     private static final double SCALE_UP = 0x1.0p+600;

  67.     /** Threshold for the difference between the exponents of two Euclidean 2D input values
  68.      * where the larger value dominates the calculation.
  69.      */
  70.     private static final int EXP_DIFF_THRESHOLD_2D = 54;

  71.     /** Function of 2 arguments. */
  72.     private final Two two;
  73.     /** Function of 3 arguments. */
  74.     private final Three three;
  75.     /** Function of array argument. */
  76.     private final Array array;

  77.     /** Function of 2 arguments. */
  78.     @FunctionalInterface
  79.     private interface Two {
  80.         /**
  81.          * @param x Argument.
  82.          * @param y Argument.
  83.          * @return the norm.
  84.          */
  85.         double of(double x, double y);
  86.     }
  87.     /** Function of 3 arguments. */
  88.     @FunctionalInterface
  89.     private interface Three {
  90.         /**
  91.          * @param x Argument.
  92.          * @param y Argument.
  93.          * @param z Argument.
  94.          * @return the norm.
  95.          */
  96.         double of(double x, double y, double z);
  97.     }
  98.     /** Function of array argument. */
  99.     @FunctionalInterface
  100.     private interface Array {
  101.         /**
  102.          * @param v Array of arguments.
  103.          * @return the norm.
  104.          */
  105.         double of(double[] v);
  106.     }

  107.     /**
  108.      * @param two Function of 2 arguments.
  109.      * @param three Function of 3 arguments.
  110.      * @param array Function of array argument.
  111.      */
  112.     Norm(Two two,
  113.          Three three,
  114.          Array array) {
  115.         this.two = two;
  116.         this.three = three;
  117.         this.array = array;
  118.     }

  119.     /**
  120.      * @param alias Alternative name.
  121.      */
  122.     Norm(Norm alias) {
  123.         this.two = alias.two;
  124.         this.three = alias.three;
  125.         this.array = alias.array;
  126.     }

  127.     /**
  128.      * Computes the norm.
  129.      *
  130.      * <p>Special cases:
  131.      * <ul>
  132.      *  <li>If either value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
  133.      *  <li>If either value is infinite and the other value is not {@link Double#NaN}, then
  134.      *   the result is {@link Double#POSITIVE_INFINITY}.</li>
  135.      * </ul>
  136.      *
  137.      * @param x Argument.
  138.      * @param y Argument.
  139.      * @return the norm.
  140.      */
  141.     public final double of(double x,
  142.                            double y) {
  143.         return two.of(x, y);
  144.     }

  145.     /**
  146.      * Computes the norm.
  147.      *
  148.      * <p>Special cases:
  149.      * <ul>
  150.      *  <li>If any value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
  151.      *  <li>If any value is infinite and no value is not {@link Double#NaN}, then the
  152.      *   result is {@link Double#POSITIVE_INFINITY}.</li>
  153.      * </ul>
  154.      *
  155.      * @param x Argument.
  156.      * @param y Argument.
  157.      * @param z Argument.
  158.      * @return the norm.
  159.      */
  160.     public final double of(double x,
  161.                            double y,
  162.                            double z) {
  163.         return three.of(x, y, z);
  164.     }

  165.     /**
  166.      * Computes the norm.
  167.      *
  168.      * <p>Special cases:
  169.      * <ul>
  170.      *  <li>If any value is {@link Double#NaN}, then the result is {@link Double#NaN}.</li>
  171.      *  <li>If any value is infinite and no value is not {@link Double#NaN}, then the
  172.      *   result is {@link Double#POSITIVE_INFINITY}.</li>
  173.      * </ul>
  174.      *
  175.      * @param v Argument.
  176.      * @return the norm.
  177.      * @throws IllegalArgumentException if the array is empty.
  178.      */
  179.     public final double of(double[] v) {
  180.         ensureNonEmpty(v);
  181.         return array.of(v);
  182.     }

  183.     /** Computes the Manhattan norm.
  184.      *
  185.      * @param x first input value
  186.      * @param y second input value
  187.      * @return \(|x| + |y|\).
  188.      *
  189.      * @see #L1
  190.      * @see #MANHATTAN
  191.      * @see #of(double,double)
  192.      */
  193.     private static double manhattan(final double x,
  194.                                     final double y) {
  195.         return Math.abs(x) + Math.abs(y);
  196.     }

  197.     /** Computes the Manhattan norm.
  198.      *
  199.      * @param x first input value
  200.      * @param y second input value
  201.      * @param z third input value
  202.      * @return \(|x| + |y| + |z|\)
  203.      *
  204.      * @see #L1
  205.      * @see #MANHATTAN
  206.      * @see #of(double,double,double)
  207.      */
  208.     private static double manhattan(final double x,
  209.                                     final double y,
  210.                                     final double z) {
  211.         return Sum.of(Math.abs(x))
  212.             .add(Math.abs(y))
  213.             .add(Math.abs(z))
  214.             .getAsDouble();
  215.     }

  216.     /** Computes the Manhattan norm.
  217.      *
  218.      * @param v input values
  219.      * @return \(|v_0| + ... + |v_i|\)
  220.      *
  221.      * @see #L1
  222.      * @see #MANHATTAN
  223.      * @see #of(double[])
  224.      */
  225.     private static double manhattan(final double[] v) {
  226.         final Sum sum = Sum.create();

  227.         for (final double d : v) {
  228.             sum.add(Math.abs(d));
  229.         }

  230.         return sum.getAsDouble();
  231.     }

  232.     /** Computes the Euclidean norm.
  233.      * This implementation handles possible overflow or underflow.
  234.      *
  235.      * <p><strong>Comparison with Math.hypot()</strong>
  236.      * While not guaranteed to return the same result, this method provides
  237.      * similar error bounds as {@link Math#hypot(double, double)} (and may run faster on
  238.      * some JVM).
  239.      *
  240.      * @param x first input
  241.      * @param y second input
  242.      * @return \(\sqrt{x^2 + y^2}\).
  243.      *
  244.      * @see #L2
  245.      * @see #EUCLIDEAN
  246.      * @see #of(double,double)
  247.      */
  248.     private static double euclidean(final double x,
  249.                                     final double y) {
  250.         final double xabs = Math.abs(x);
  251.         final double yabs = Math.abs(y);

  252.         final double max;
  253.         final double min;
  254.         // the compare method considers NaN greater than other values, meaning that our
  255.         // check for if the max is finite later on will detect NaNs correctly
  256.         if (Double.compare(xabs, yabs) > 0) {
  257.             max = xabs;
  258.             min = yabs;
  259.         } else {
  260.             max = yabs;
  261.             min = xabs;
  262.         }

  263.         // if the max is not finite, then one of the inputs must not have
  264.         // been finite
  265.         if (!Double.isFinite(max)) {
  266.             // let the standard multiply operation determine whether to return NaN or infinite
  267.             return xabs * yabs;
  268.         } else if (Math.getExponent(max) - Math.getExponent(min) > EXP_DIFF_THRESHOLD_2D) {
  269.             // value is completely dominated by max; just return max
  270.             return max;
  271.         }

  272.         // compute the scale and rescale values
  273.         final double scale;
  274.         final double rescale;
  275.         if (max > LARGE_THRESH) {
  276.             scale = SCALE_DOWN;
  277.             rescale = SCALE_UP;
  278.         } else if (max < SAFE_SCALE_UP_THRESH) {
  279.             scale = SCALE_UP;
  280.             rescale = SCALE_DOWN;
  281.         } else {
  282.             scale = 1d;
  283.             rescale = 1d;
  284.         }

  285.         // initialise sum and compensation using scaled x
  286.         final double sx = xabs * scale;
  287.         double sum = sx * sx;
  288.         double comp = DD.twoSquareLow(sx, sum);

  289.         // add scaled y
  290.         final double sy = yabs * scale;
  291.         final double py = sy * sy;
  292.         comp += DD.twoSquareLow(sy, py);
  293.         final double sumPy = sum + py;
  294.         comp += DD.twoSumLow(sum, py, sumPy);
  295.         sum = sumPy;

  296.         return Math.sqrt(sum + comp) * rescale;
  297.     }

  298.     /** Computes the Euclidean norm.
  299.      * This implementation handles possible overflow or underflow.
  300.      *
  301.      * @param x first input
  302.      * @param y second input
  303.      * @param z third input
  304.      * @return \(\sqrt{x^2 + y^2 + z^2}\)
  305.      *
  306.      * @see #L2
  307.      * @see #EUCLIDEAN
  308.      * @see #of(double,double,double)
  309.      */
  310.     private static double euclidean(final double x,
  311.                                     final double y,
  312.                                     final double z) {
  313.         final double xabs = Math.abs(x);
  314.         final double yabs = Math.abs(y);
  315.         final double zabs = Math.abs(z);

  316.         final double max = Math.max(Math.max(xabs, yabs), zabs);

  317.         // if the max is not finite, then one of the inputs must not have
  318.         // been finite
  319.         if (!Double.isFinite(max)) {
  320.             // let the standard multiply operation determine whether to
  321.             // return NaN or infinite
  322.             return xabs * yabs * zabs;
  323.         }

  324.         // compute the scale and rescale values
  325.         final double scale;
  326.         final double rescale;
  327.         if (max > LARGE_THRESH) {
  328.             scale = SCALE_DOWN;
  329.             rescale = SCALE_UP;
  330.         } else if (max < SAFE_SCALE_UP_THRESH) {
  331.             scale = SCALE_UP;
  332.             rescale = SCALE_DOWN;
  333.         } else {
  334.             scale = 1d;
  335.             rescale = 1d;
  336.         }


  337.         // initialise sum and compensation using scaled x
  338.         final double sx = xabs * scale;
  339.         double sum = sx * sx;
  340.         double comp = DD.twoSquareLow(sx, sum);

  341.         // add scaled y
  342.         final double sy = yabs * scale;
  343.         final double py = sy * sy;
  344.         comp += DD.twoSquareLow(sy, py);
  345.         final double sumPy = sum + py;
  346.         comp += DD.twoSumLow(sum, py, sumPy);
  347.         sum = sumPy;

  348.         // add scaled z
  349.         final double sz = zabs * scale;
  350.         final double pz = sz * sz;
  351.         comp += DD.twoSquareLow(sz, pz);
  352.         final double sumPz = sum + pz;
  353.         comp += DD.twoSumLow(sum, pz, sumPz);
  354.         sum = sumPz;

  355.         return Math.sqrt(sum + comp) * rescale;
  356.     }

  357.     /** Computes the Euclidean norm.
  358.      * This implementation handles possible overflow or underflow.
  359.      *
  360.      * @param v input values
  361.      * @return \(\sqrt{v_0^2 + ... + v_{n-1}^2}\).
  362.      *
  363.      * @see #L2
  364.      * @see #EUCLIDEAN
  365.      * @see #of(double[])
  366.      */
  367.     private static double euclidean(final double[] v) {
  368.         // sum of big, normal and small numbers
  369.         double s1 = 0;
  370.         double s2 = 0;
  371.         double s3 = 0;

  372.         // sum compensation values
  373.         double c1 = 0;
  374.         double c2 = 0;
  375.         double c3 = 0;

  376.         for (int i = 0; i < v.length; ++i) {
  377.             final double x = Math.abs(v[i]);
  378.             if (!Double.isFinite(x)) {
  379.                 // not finite; determine whether to return NaN or positive infinity
  380.                 return euclideanNormSpecial(v, i);
  381.             } else if (x > LARGE_THRESH) {
  382.                 // scale down
  383.                 final double sx = x * SCALE_DOWN;

  384.                 // compute the product and product compensation
  385.                 final double p = sx * sx;
  386.                 final double cp = DD.twoSquareLow(sx, p);

  387.                 // compute the running sum and sum compensation
  388.                 final double s = s1 + p;
  389.                 final double cs = DD.twoSumLow(s1, p, s);

  390.                 // update running totals
  391.                 c1 += cp + cs;
  392.                 s1 = s;
  393.             } else if (x < SMALL_THRESH) {
  394.                 // scale up
  395.                 final double sx = x * SCALE_UP;

  396.                 // compute the product and product compensation
  397.                 final double p = sx * sx;
  398.                 final double cp = DD.twoSquareLow(sx, p);

  399.                 // compute the running sum and sum compensation
  400.                 final double s = s3 + p;
  401.                 final double cs = DD.twoSumLow(s3, p, s);

  402.                 // update running totals
  403.                 c3 += cp + cs;
  404.                 s3 = s;
  405.             } else {
  406.                 // no scaling
  407.                 // compute the product and product compensation
  408.                 final double p = x * x;
  409.                 final double cp = DD.twoSquareLow(x, p);

  410.                 // compute the running sum and sum compensation
  411.                 final double s = s2 + p;
  412.                 final double cs = DD.twoSumLow(s2, p, s);

  413.                 // update running totals
  414.                 c2 += cp + cs;
  415.                 s2 = s;
  416.             }
  417.         }

  418.         // The highest sum is the significant component. Add the next significant.
  419.         // Note that the "x * SCALE_DOWN * SCALE_DOWN" expressions must be executed
  420.         // in the order given. If the two scale factors are multiplied together first,
  421.         // they will underflow to zero.
  422.         if (s1 != 0) {
  423.             // add s1, s2, c1, c2
  424.             final double s2Adj = s2 * SCALE_DOWN * SCALE_DOWN;
  425.             final double sum = s1 + s2Adj;
  426.             final double comp = DD.twoSumLow(s1, s2Adj, sum) +
  427.                 c1 + (c2 * SCALE_DOWN * SCALE_DOWN);
  428.             return Math.sqrt(sum + comp) * SCALE_UP;
  429.         } else if (s2 != 0) {
  430.             // add s2, s3, c2, c3
  431.             final double s3Adj = s3 * SCALE_DOWN * SCALE_DOWN;
  432.             final double sum = s2 + s3Adj;
  433.             final double comp = DD.twoSumLow(s2, s3Adj, sum) +
  434.                 c2 + (c3 * SCALE_DOWN * SCALE_DOWN);
  435.             return Math.sqrt(sum + comp);
  436.         }
  437.         // add s3, c3
  438.         return Math.sqrt(s3 + c3) * SCALE_DOWN;
  439.     }

  440.     /** Special cases of non-finite input.
  441.      *
  442.      * @param v input vector
  443.      * @param start index to start examining the input vector from
  444.      * @return Euclidean norm special value
  445.      */
  446.     private static double euclideanNormSpecial(final double[] v,
  447.                                                final int start) {
  448.         for (int i = start; i < v.length; ++i) {
  449.             if (Double.isNaN(v[i])) {
  450.                 return Double.NaN;
  451.             }
  452.         }
  453.         return Double.POSITIVE_INFINITY;
  454.     }

  455.     /** Computes the maximum norm.
  456.      *
  457.      * @param x first input
  458.      * @param y second input
  459.      * @return \(\max{(|x|, |y|)}\).
  460.      *
  461.      * @see #LINF
  462.      * @see #MAXIMUM
  463.      * @see #of(double,double)
  464.      */
  465.     private static double maximum(final double x,
  466.                                   final double y) {
  467.         return Math.max(Math.abs(x), Math.abs(y));
  468.     }

  469.     /** Computes the maximum norm.
  470.      *
  471.      * @param x first input
  472.      * @param y second input
  473.      * @param z third input
  474.      * @return \(\max{(|x|, |y|, |z|)}\).
  475.      *
  476.      * @see #LINF
  477.      * @see #MAXIMUM
  478.      * @see #of(double,double,double)
  479.      */
  480.     private static double maximum(final double x,
  481.                                   final double y,
  482.                                   final double z) {
  483.         return Math.max(Math.abs(x),
  484.                         Math.max(Math.abs(y),
  485.                                  Math.abs(z)));
  486.     }

  487.     /** Computes the maximum norm.
  488.      *
  489.      * @param v input values
  490.      * @return \(\max{(|v_0|, \ldots, |v_{n-1}|)}\)
  491.      *
  492.      * @see #LINF
  493.      * @see #MAXIMUM
  494.      * @see #of(double[])
  495.      */
  496.     private static double maximum(final double[] v) {
  497.         double max = 0d;
  498.         for (final double d : v) {
  499.             max = Math.max(max, Math.abs(d));
  500.         }
  501.         return max;
  502.     }

  503.     /**
  504.      * @param a Array.
  505.      * @throws IllegalArgumentException for zero-size array.
  506.      */
  507.     private static void ensureNonEmpty(double[] a) {
  508.         if (a.length == 0) {
  509.             throw new IllegalArgumentException("Empty array");
  510.         }
  511.     }
  512. }