public TqrEigenDecomposition(Vector diag, Vector sub, EigenVectorCalculation calc = EigenVectorCalculation.WithEigenVector,
                                     ShiftStrategy strategy = ShiftStrategy.CloseEigenValue)
        {
            iter_ = 0;
            d_    = new Vector(diag);

            int row = calc == EigenVectorCalculation.WithEigenVector ? d_.size() :
                      calc == EigenVectorCalculation.WithoutEigenVector ? 0 : 1;

            ev_ = new Matrix(row, d_.size(), 0.0);

            int n = diag.size();

            Utils.QL_REQUIRE(n == sub.size() + 1, () => "Wrong dimensions");

            Vector e = new Vector(n, 0.0);
            int    i;

            for (i = 1; i < e.Count; ++i)
            {
                e[i] = sub[i - 1];
            }


            for (i = 0; i < ev_.rows(); ++i)
            {
                ev_[i, i] = 1.0;
            }

            for (int k = n - 1; k >= 1; --k)
            {
                while (!offDiagIsZero(k, e))
                {
                    int l = k;
                    while (--l > 0 && !offDiagIsZero(l, e))
                    {
                        ;
                    }
                    iter_++;

                    double q = d_[l];
                    if (strategy != ShiftStrategy.NoShift)
                    {
                        // calculated eigenvalue of 2x2 sub matrix of
                        // [ d_[k-1] e_[k] ]
                        // [  e_[k]  d_[k] ]
                        // which is closer to d_[k+1].
                        // FLOATING_POINT_EXCEPTION
                        double t1 = Math.Sqrt(
                            0.25 * (d_[k] * d_[k] + d_[k - 1] * d_[k - 1])
                            - 0.5 * d_[k - 1] * d_[k] + e[k] * e[k]);
                        double t2 = 0.5 * (d_[k] + d_[k - 1]);

                        double lambda = (Math.Abs(t2 + t1 - d_[k]) < Math.Abs(t2 - t1 - d_[k]))?
                                        t2 + t1 : t2 - t1;

                        if (strategy == ShiftStrategy.CloseEigenValue)
                        {
                            q -= lambda;
                        }
                        else
                        {
                            q -= ((k == n - 1) ? 1.25 : 1.0) * lambda;
                        }
                    }

                    // the QR transformation
                    double sine   = 1.0;
                    double cosine = 1.0;
                    double u      = 0.0;

                    bool recoverUnderflow = false;
                    for (i = l + 1; i <= k && !recoverUnderflow; ++i)
                    {
                        double h = cosine * e[i];
                        double p = sine * e[i];

                        e[i - 1] = Math.Sqrt(p * p + q * q);
                        if (e[i - 1].IsNotEqual(0.0))
                        {
                            sine   = p / e[i - 1];
                            cosine = q / e[i - 1];

                            double g = d_[i - 1] - u;
                            double t = (d_[i] - g) * sine + 2 * cosine * h;

                            u         = sine * t;
                            d_[i - 1] = g + u;
                            q         = cosine * t - h;

                            for (int j = 0; j < ev_.rows(); ++j)
                            {
                                double tmp = ev_[j, i - 1];
                                ev_[j, i - 1] = sine * ev_[j, i] + cosine * tmp;
                                ev_[j, i]     = cosine * ev_[j, i] - sine * tmp;
                            }
                        }
                        else
                        {
                            // recover from underflow
                            d_[i - 1]       -= u;
                            e[l]             = 0.0;
                            recoverUnderflow = true;
                        }
                    }

                    if (!recoverUnderflow)
                    {
                        d_[k] -= u;
                        e[k]   = q;
                        e[l]   = 0.0;
                    }
                }
            }

            // sort (eigenvalues, eigenvectors),
            // code taken from symmetricSchureDecomposition.cpp
            List <KeyValuePair <double, List <double> > > temp = new  InitializedList <KeyValuePair <double, List <double> > >(n);
            List <double> eigenVector = new InitializedList <double>(ev_.rows());

            for (i = 0; i < n; i++)
            {
                if (ev_.rows() > 0)
                {
                    eigenVector = ev_.column(i);
                }

                temp[i] = new KeyValuePair <double, List <double> >(d_[i], eigenVector);
            }

            temp.Sort(KeyValuePairCompare);

            // first element is positive
            for (i = 0; i < n; i++)
            {
                d_[i] = temp[i].Key;
                double sign = 1.0;
                if (ev_.rows() > 0 && temp[i].Value[0] < 0.0)
                {
                    sign = -1.0;
                }
                for (int j = 0; j < ev_.rows(); ++j)
                {
                    ev_[j, i] = sign * temp[i].Value[j];
                }
            }
        }
Example #2
0
      public TqrEigenDecomposition(Vector diag, Vector sub, EigenVectorCalculation calc = EigenVectorCalculation.WithEigenVector,
                            ShiftStrategy strategy = ShiftStrategy.CloseEigenValue)
      {
         iter_ = 0;
         d_ = new Vector(diag);
         
         int row = calc == EigenVectorCalculation.WithEigenVector ? d_.size() :
            calc == EigenVectorCalculation.WithoutEigenVector ? 0 : 1;

         ev_ = new Matrix(row, d_.size(), 0.0);
         
         int n = diag.size();

         Utils.QL_REQUIRE( n == sub.size() + 1, () => "Wrong dimensions" );

         Vector e = new Vector(sub);

         int i;
         for (i=0; i < ev_.rows(); ++i) 
         {
            ev_[i,i] = 1.0;
         }

         for (int k=n-1; k >=1; --k) 
         {
            while (!offDiagIsZero(k, e)) 
            {
                int l = k;
                while (--l > 0 && !offDiagIsZero(l,e));
                iter_++;

                double q = d_[l];
                if (strategy != ShiftStrategy.NoShift) 
                {
                    // calculated eigenvalue of 2x2 sub matrix of
                    // [ d_[k-1] e_[k] ]
                    // [  e_[k]  d_[k] ]
                    // which is closer to d_[k+1].
                    // FLOATING_POINT_EXCEPTION
                    double t1 = Math.Sqrt(
                                          0.25*(d_[k]*d_[k] + d_[k-1]*d_[k-1])
                                          - 0.5*d_[k-1]*d_[k] + e[k]*e[k]);
                    double t2 = 0.5*(d_[k]+d_[k-1]);

                    double lambda = (Math.Abs(t2+t1 - d_[k]) < Math.Abs(t2-t1 - d_[k]))?
                                     t2+t1 : t2-t1;

                    if (strategy == ShiftStrategy.CloseEigenValue) 
                    {
                        q-=lambda;
                    } 
                    else 
                    {
                        q-=((k==n-1)? 1.25 : 1.0)*lambda;
                    }
                }

                // the QR transformation
                double sine = 1.0;
                double cosine = 1.0;
                double u = 0.0;

                bool recoverUnderflow = false;
                for (i=l+1; i <= k && !recoverUnderflow; ++i) 
                {
                    double h = cosine*e[i];
                    double p = sine*e[i];

                    e[i-1] = Math.Sqrt(p*p+q*q);
                    if (e[i-1] != 0.0) {
                        sine = p/e[i-1];
                        cosine = q/e[i-1];

                        double g = d_[i-1]-u;
                        double t = (d_[i]-g)*sine+2*cosine*h;

                        u = sine*t;
                        d_[i-1] = g + u;
                        q = cosine*t - h;

                        for (int j=0; j < ev_.rows(); ++j) 
                        {
                            double tmp = ev_[j,i-1];
                            ev_[j,i-1] = sine*ev_[j,i] + cosine*tmp;
                            ev_[j,i] = cosine*ev_[j,i] - sine*tmp;
                        }
                    } 
                    else 
                    {
                        // recover from underflow
                        d_[i-1] -= u;
                        e[l] = 0.0;
                        recoverUnderflow = true;
                    }
                }

                if (!recoverUnderflow) {
                    d_[k] -= u;
                    e[k] = q;
                    e[l] = 0.0;
                }
            }
        }

        // sort (eigenvalues, eigenvectors),
        // code taken from symmetricSchureDecomposition.cpp
        List<KeyValuePair<double, List<double> > > temp = new List<KeyValuePair<double,List<double>>>(n);
        List<double> eigenVector = new List<double>(ev_.rows());
        for (i=0; i<n; i++) 
        {
            if (ev_.rows() > 0)
                //std::copy(ev_.column_begin(i),ev_.column_end(i), eigenVector.begin());
                eigenVector = ev_.column(i) ;

            temp[i] = new KeyValuePair<double,List<double>>(d_[i], eigenVector);
        }
       
        //std::sort(temp.begin(), temp.end(), std::greater<std::pair<Real, std::vector<Real> > >());
        temp.Sort();

        // first element is positive
        for (i=0; i<n; i++) {
            d_[i] = temp[i].Key;
            double sign = 1.0;
            if (ev_.rows() > 0 && temp[i].Value[0]<0.0)
                sign = -1.0;
            for (int j=0; j<ev_.rows(); ++j) {
                ev_[j,i] = sign * temp[i].Value[j];
            }
        }

      }