Beispiel #1
0
        // A Householder reflection matrix is a rank-1 update to the identity.
        //   P = I - b v v^T
        // Unitarity requires b = 2 / |v|^2. To anihilate all but the first components of vector x,
        //   P x = a e_1
        // we must have
        //   v = x +/- |x| e_1
        // that is, all elements the same except the first, from which we have either added or subtracted |x|. This makes
        //   a = -/+ |x|
        // There are two way to handle the sign. One is to simply choose the sign that avoids cancelation when calculating v_1,
        // i.e. + for positive x_1 and - for negative x_1. This works fine, but makes a negative for positive x_1, which is
        // weird-looking (1 0 0 gets turned into -1 0 0). An alternative is to choose the negative sign even for positive x_1,
        // but to avoid cancelation write
        //   v_1 = x_1 - |x| = ( x_1 - |x| ) ( x_1 + |x|) / ( x_1 + |x|) = ( x_1^2 - |x|^2 ) / ( x_1 + |x| )
        //       = - ( x_2^2 + \cdots + x_n^2 ) / ( x_1 + |x| )
        // We have now moved to the second method. Note that v is the same as x except for the first element.

        public static void GenerateHouseholderReflection(double[] store, int offset, int stride, int count, out double a)
        {
            double x0 = store[offset];

            // Compute |x| and u_0.
            double xm, u0;

            if (x0 < 0.0)
            {
                xm = Blas1.dNrm2(store, offset, stride, count);
                u0 = x0 - xm;
            }
            else
            {
                // This method of computing ym and xm does incur and extra square root compared to naively computing x_2 + \cdots + x_n^2,
                // but doing it this way allows us to use dNrm2's over/under-flow prevention when we have large/small elements.
                double ym = Blas1.dNrm2(store, offset + stride, stride, count - 1);
                xm = MoreMath.Hypot(x0, ym);
                // Writing ym / (x0 + xm) * ym instead of ym * ym / (x0 + xm) prevents over/under-flow for large/small ym. Note this will
                // be 0 / 0 = NaN when xm = 0.
                u0 = -ym / (x0 + xm) * ym;
            }

            // Set result element.
            a = xm;

            // If |x| = 0 there is nothing to do; we could have done this a little earlier but the compiler requires us to set a before returning.
            if (xm == 0.0)
            {
                return;
            }

            // Set the new value of u_0
            store[offset] = u0;

            // Rescale to make b = 1.
            double um = Math.Sqrt(xm * Math.Abs(u0));

            if (um > 0.0)
            {
                Blas1.dScal(1.0 / um, store, offset, stride, count);
            }
        }
Beispiel #2
0
 /// <summary>
 /// Computes the magnitude of the vector.
 /// </summary>
 /// <returns>The Euclidean norm of the vector.</returns>
 public virtual double Norm()
 {
     return(Blas1.dNrm2(store, offset, stride, dimension));
 }