예제 #1
0
    public static int zgbfa(ref Complex[] abd, int lda, int n, int ml, int mu, ref int[] ipvt)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZGBFA factors a complex band matrix by elimination.
    //
    //  Discussion:
    //
    //    ZGBFA is usually called by ZGBCO, but it can be called
    //    directly with a saving in time if RCOND is not needed.
    //
    //  Band storage:
    //
    //    If A is a band matrix, the following program segment
    //    will set up the input.
    //
    //      ml = (band width below the diagonal)
    //      mu = (band width above the diagonal)
    //      m = ml + mu + 1
    //      do j = 1, n
    //        i1 = max ( 1, j - mu )
    //        i2 = min ( n, j + ml )
    //        do i = i1, i2
    //          k = i - j + m
    //          abd(k,j) = a(i,j)
    //        end do
    //      end do
    //
    //    This uses rows ML+1 through 2*ML+MU+1 of ABD.
    //    In addition, the first ML rows in ABD are used for
    //    elements generated during the triangularization.
    //    The total number of rows needed in ABD is 2*ML+MU+1.
    //    The ML+MU by ML+MU upper left triangle and the
    //    ML by ML lower right triangle are not referenced.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, new Complex ABD[LDA*N], on input, contains the matrix in
    //    band storage.  The columns of the matrix are stored in the columns
    //    of ABD and the diagonals of the matrix are stored in rows ML+1
    //    through 2*ML+MU+1 of ABD.  On output, an upper triangular matrix
    //    in band storage and the multipliers which were used to obtain it.
    //    The factorization can be written A = L*U where L is a product of
    //    permutation and unit lower triangular matrices and U is upper triangular.
    //
    //    Input, int LDA, the leading dimension of ABD.
    //    LDA must be at least 2*ML+MU+1.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int ML, the number of diagonals below the main diagonal.
    //    0 <= ML < N.
    //
    //    Input, int MU, the number of diagonals above the main diagonal.
    //    0 <= MU < N.  More efficient if ML <= MU.
    //
    //    Output, int IPVT[N], the pivot indices.
    //
    //    Output, int ZGBFA.
    //    0, normal value.
    //    K, if U(K,K) == 0.0.  This is not an error condition for this
    //    subroutine, but it does indicate that ZGBSL will divide by zero if
    //    called.  Use RCOND in ZGBCO for a reliable indication of singularity.
    //
    {
        int i;
        int jz;
        int k;

        int m    = ml + mu + 1;
        int info = 0;
        //
        //  Zero initial fill-in columns.
        //
        int j0 = mu + 2;
        int j1 = Math.Min(n, m) - 1;

        for (jz = j0; jz <= j1; jz++)
        {
            int i0 = m + 1 - jz;
            for (i = i0; i <= ml; i++)
            {
                abd[i - 1 + (jz - 1) * lda] = new Complex(0.0, 0.0);
            }
        }

        jz = j1;
        int ju = 0;

        //
        //  Gaussian elimination with partial pivoting.
        //
        for (k = 1; k <= n - 1; k++)
        {
            //
            //  Zero next fill-in column
            //
            jz += 1;
            if (jz <= n)
            {
                for (i = 1; i <= ml; i++)
                {
                    abd[i - 1 + (jz - 1) * lda] = new Complex(0.0, 0.0);
                }
            }

            //
            //  Find L = pivot index.
            //
            int lm = Math.Min(ml, n - k);
            int l  = BLAS1Z.izamax(lm + 1, abd, 1, index: +m - 1 + (k - 1) * lda) + m - 1;
            ipvt[k - 1] = l + k - m;
            //
            //  Zero pivot implies this column already triangularized.
            //
            if (typeMethods.zabs1(abd[l - 1 + (k - 1) * lda]) == 0.0)
            {
                info = k;
                continue;
            }

            //
            //  Interchange if necessary.
            //
            Complex t;
            if (l != m)
            {
                t = abd[l - 1 + (k - 1) * lda];
                abd[l - 1 + (k - 1) * lda] = abd[m - 1 + (k - 1) * lda];
                abd[m - 1 + (k - 1) * lda] = t;
            }

            //
            //  Compute multipliers.
            //
            t = -new Complex(1.0, 0.0) / abd[m - 1 + (k - 1) * lda];
            BLAS1Z.zscal(lm, t, ref abd, 1, index: +m + (k - 1) * lda);
            //
            //  Row elimination with column indexing.
            //
            ju = Math.Min(Math.Max(ju, mu + ipvt[k - 1]), n);
            int mm = m;

            int j;
            for (j = k + 1; j <= ju; j++)
            {
                l  -= 1;
                mm -= 1;
                t   = abd[l - 1 + (j - 1) * lda];
                if (l != mm)
                {
                    abd[l - 1 + (j - 1) * lda]  = abd[mm - 1 + (j - 1) * lda];
                    abd[mm - 1 + (j - 1) * lda] = t;
                }

                BLAS1Z.zaxpy(lm, t, abd, 1, ref abd, 1, xIndex: +m + (k - 1) * lda, yIndex: +mm + (j - 1) * lda);
            }
        }

        ipvt[n - 1] = n;

        if (typeMethods.zabs1(abd[m - 1 + (n - 1) * lda]) == 0.0)
        {
            info = n;
        }

        return(info);
    }
예제 #2
0
    public static void zhpdi(ref Complex[] ap, int n, int[] ipvt, ref double[] det,
                             ref int[] inert, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZHPDI: determinant, inertia and inverse of a complex hermitian matrix.
    //
    //  Discussion:
    //
    //    The routine uses the factors from ZHPFA.
    //
    //    The matrix is stored in packed form.
    //
    //    A division by zero will occur if the inverse is requested and ZHPCO has
    //    set RCOND == 0.0 or ZHPFA has set INFO != 0.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex AP[N*(N+1)/2]; on input, the factored matrix
    //    from ZHPFA.  If the inverse was requested, then on output, AP contains
    //    the upper triangle of the inverse of the original matrix, stored in packed
    //    form.  The columns of the upper triangle are stored sequentially in a
    //    one-dimensional array.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int IPVT[N], the pivot vector from ZHPFA.
    //
    //    Output, double DET[2], if requested, the determinant of the original
    //    matrix.  Determinant = DET(1) * 10.0**DET(2) with
    //    1.0 <= abs ( DET(1) ) < 10.0 or DET(1) = 0.0.
    //
    //    Output, int INERT[3], if requested, the inertia of the original matrix.
    //    INERT(1) = number of positive eigenvalues.
    //    INERT(2) = number of negative eigenvalues.
    //    INERT(3) = number of zero eigenvalues.
    //
    //    Input, int JOB, has the decimal expansion ABC where:
    //    if C != 0, the inverse is computed,
    //    if B != 0, the determinant is computed,
    //    if A != 0, the inertia is computed.
    //    For example, JOB = 111 gives all three.
    //
    {
        double d;
        int    ik;
        int    ikp1;
        int    k;
        int    kk;
        int    kkp1;
        double t;

        bool noinv = job % 10 == 0;
        bool nodet = job % 100 / 10 == 0;
        bool noert = job % 1000 / 100 == 0;

        if (!nodet || !noert)
        {
            switch (noert)
            {
            case false:
                inert[0] = 0;
                inert[1] = 0;
                inert[2] = 0;
                break;
            }

            switch (nodet)
            {
            case false:
                det[0] = 1.0;
                det[1] = 0.0;
                break;
            }

            t  = 0.0;
            ik = 0;

            for (k = 1; k <= n; k++)
            {
                kk = ik + k;
                d  = ap[kk - 1].Real;
                switch (ipvt[k - 1])
                {
                //
                //  Check if 1 by 1
                //
                //
                //  2 by 2 block
                //  Use DET (D  S; S  C)  =  ( D / T * C - T ) * T, T = abs ( S )
                //  to avoid underflow/overflow troubles.
                //  Take two passes through scaling.  Use T for flag.
                //
                case <= 0 when t == 0.0:
                    ikp1 = ik + k;
                    kkp1 = ikp1 + k;
                    t    = Complex.Abs(ap[kkp1 - 1]);
                    d    = d / t * ap[kkp1].Real - t;
                    break;

                case <= 0:
                    d = t;
                    t = 0.0;
                    break;
                }

                switch (noert)
                {
                case false:
                    switch (d)
                    {
                    case > 0.0:
                        inert[0] += 1;
                        break;

                    case < 0.0:
                        inert[1] += 1;
                        break;

                    case 0.0:
                        inert[2] += 1;
                        break;
                    }

                    break;
                }

                switch (nodet)
                {
                case false:
                {
                    det[0] *= d;

                    if (det[0] != 0.0)
                    {
                        while (Math.Abs(det[0]) < 1.0)
                        {
                            det[0] *= 10.0;
                            det[1] -= 1.0;
                        }

                        while (10.0 <= Math.Abs(det[0]))
                        {
                            det[0] /= 10.0;
                            det[1] += 1.0;
                        }
                    }

                    break;
                }
                }

                ik += k;
            }
        }

        switch (noinv)
        {
        //
        //  Compute inverse(A).
        //
        case false:
        {
            Complex[] work = new Complex [n];

            k  = 1;
            ik = 0;

            while (k <= n)
            {
                int km1 = k - 1;
                kk   = ik + k;
                ikp1 = ik + k;
                kkp1 = ikp1 + k;
                int kstep;
                int jk;
                int j;
                int ij;
                switch (ipvt[k - 1])
                {
                //
                //  1 by 1
                //
                case >= 0:
                {
                    ap[kk - 1] = new Complex(1.0 / ap[kk - 1].Real, 0.0);

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (j = 1; j <= km1; j++)
                        {
                            work[j - 1] = ap[ik + j - 1];
                        }

                        ij = 0;
                        for (j = 1; j <= km1; j++)
                        {
                            jk         = ik + j;
                            ap[jk - 1] = BLAS1Z.zdotc(j, ap, 1, work, 1, xIndex: +ij);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ik);
                            ij += j;
                        }

                        ap[kk - 1] += new Complex
                                          (BLAS1Z.zdotc(km1, work, 1, ap, 1, yIndex: +ik).Real, 0.0);
                        break;
                    }
                    }

                    kstep = 1;
                    break;
                }

                //
                default:
                {
                    t = Complex.Abs(ap[kkp1 - 1]);
                    double  ak    = ap[kk - 1].Real / t;
                    double  akp1  = ap[kkp1].Real / t;
                    Complex akkp1 = ap[kkp1 - 1] / t;
                    d            = t * (ak * akp1 - 1.0);
                    ap[kk - 1]   = new Complex(akp1 / d, 0.0);
                    ap[kkp1]     = new Complex(ak / d, 0.0);
                    ap[kkp1 - 1] = -akkp1 / d;

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (j = 1; j <= km1; j++)
                        {
                            work[j - 1] = ap[ikp1 + j - 1];
                        }

                        ij = 0;
                        for (j = 1; j <= km1; j++)
                        {
                            int jkp1 = ikp1 + j;
                            ap[jkp1 - 1] = BLAS1Z.zdotc(j, ap, 1, work, 1, xIndex: +ij);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ikp1);
                            ij += j;
                        }

                        ap[kkp1] += new Complex
                                        (BLAS1Z.zdotc(km1, work, 1, ap, 1, xIndex: +ikp1).Real, 0.0);

                        ap[kkp1 - 1] += BLAS1Z.zdotc(km1, ap, 1, ap, 1, xIndex: +ik, yIndex: +ikp1);
                        for (j = 1; j <= km1; j++)
                        {
                            work[j - 1] = ap[ik + j - 1];
                        }

                        ij = 0;

                        for (j = 1; j <= km1; j++)
                        {
                            jk         = ik + j;
                            ap[jk - 1] = BLAS1Z.zdotc(j, ap, 1, work, 1, xIndex: +ij);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ik);
                            ij += j;
                        }

                        ap[kk - 1] += new Complex
                                          (BLAS1Z.zdotc(km1, work, 1, ap, 1, yIndex: +ik).Real, 0.0);
                        break;
                    }
                    }

                    kstep = 2;
                    break;
                }
                }

                //
                //  Swap
                //
                int ks = Math.Abs(ipvt[k - 1]);

                if (ks != k)
                {
                    int iks = ks * (ks - 1) / 2;

                    BLAS1Z.zswap(ks, ref ap, 1, ref ap, 1, xIndex: +iks, yIndex: +ik);
                    int ksj = ik + ks;

                    Complex t2;
                    int     jb;
                    for (jb = ks; jb <= k; jb++)
                    {
                        j  = k + ks - jb;
                        jk = ik + j;

                        t2          = Complex.Conjugate(ap[jk - 1]);
                        ap[jk - 1]  = Complex.Conjugate(ap[ksj - 1]);
                        ap[ksj - 1] = t2;

                        ksj -= j - 1;
                    }

                    if (kstep != 1)
                    {
                        int kskp1 = ikp1 + ks;

                        t2            = ap[kskp1 - 1];
                        ap[kskp1 - 1] = ap[kkp1 - 1];
                        ap[kkp1 - 1]  = t2;
                    }
                }

                ik += k;

                ik = kstep switch
                {
                    2 => ik + k + 1,
                    _ => ik
                };

                k += kstep;
            }

            break;
        }
        }
    }
}
예제 #3
0
    public static int zspfa(ref Complex[] ap, int n, ref int[] ipvt)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZSPFA factors a complex symmetric matrix stored in packed form.
    //
    //  Discussion:
    //
    //    The factorization is done by elimination with symmetric pivoting.
    //
    //    To solve A*X = B, follow ZSPFA by ZSPSL.
    //
    //    To compute inverse(A)*C, follow ZSPFA by ZSPSL.
    //
    //    To compute determinant(A), follow ZSPFA by ZSPDI.
    //
    //    To compute inverse(A), follow ZSPFA by ZSPDI.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex AP[N*(N+1)/2]; On input, the packed form of a
    //    symmetric matrix A.  The columns of the upper triangle are stored
    //    sequentially in a one-dimensional array.  On output, a block diagonal
    //    matrix and the multipliers which were used to obtain it stored in
    //    packed form.  The factorization can be written A = U*D*U' where U
    //    is a product of permutation and unit upper triangular matrices,
    //    U' is the transpose of U, and D is block diagonal with 1 by 1 and
    //    2 by 2 blocks.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Output, int IPVT[N], the pivot indices.
    //
    //    Output, int ZSPFA.
    //    0, normal value.
    //    K, if the K-th pivot block is singular.  This is not an error condition
    //    for this subroutine, but it does indicate that ZSPSL or ZSPDI may
    //    divide by zero if called.
    //
    {
        int im = 0;
        //
        //  Initialize.
        //
        //  ALPHA is used in choosing pivot block size.
        //
        double alpha = (1.0 + Math.Sqrt(17.0)) / 8.0;

        int info = 0;
        //
        //  Main loop on K, which goes from N to 1.
        //
        int k  = n;
        int ik = n * (n - 1) / 2;

        for (;;)
        {
            //
            //  Leave the loop if K = 0 or K = 1.
            //
            if (k == 0)
            {
                break;
            }

            if (k == 1)
            {
                ipvt[0] = 1;
                if (typeMethods.zabs1(ap[0]) == 0.0)
                {
                    info = 1;
                }

                break;
            }

            //
            //  This section of code determines the kind of
            //  elimination to be performed.  When it is completed,
            //  KSTEP will be set to the size of the pivot block, and
            //  SWAP will be set to .true. if an interchange is
            //  required.
            //
            int    km1    = k - 1;
            int    kk     = ik + k;
            double absakk = typeMethods.zabs1(ap[kk - 1]);
            //
            //  Determine the largest off-diagonal element in column K.
            //
            int    imax   = BLAS1Z.izamax(k - 1, ap, 1, index: +ik);
            int    imk    = ik + imax;
            double colmax = typeMethods.zabs1(ap[imk - 1]);

            int  kstep;
            bool swap;
            int  j;
            int  imj;
            if (alpha * colmax <= absakk)
            {
                kstep = 1;
                swap  = false;
            }
            //
            //  Determine the largest off-diagonal element in row IMAX.
            //
            else
            {
                double rowmax = 0.0;
                im  = imax * (imax - 1) / 2;
                imj = im + 2 * imax;

                for (j = imax + 1; j <= k; j++)
                {
                    rowmax = Math.Max(rowmax, typeMethods.zabs1(ap[imj - 1]));
                    imj   += j;
                }

                if (imax != 1)
                {
                    int jmax = BLAS1Z.izamax(imax - 1, ap, 1, index: +im);
                    int jmim = jmax + im;
                    rowmax = Math.Max(rowmax, typeMethods.zabs1(ap[jmim - 1]));
                }

                int imim = imax + im;

                if (alpha * rowmax <= typeMethods.zabs1(ap[imim - 1]))
                {
                    kstep = 1;
                    swap  = true;
                }
                else if (alpha * colmax * (colmax / rowmax) <= absakk)
                {
                    kstep = 1;
                    swap  = false;
                }
                else
                {
                    kstep = 2;
                    swap  = imax != km1;
                }
            }

            switch (Math.Max(absakk, colmax))
            {
            //
            //  Column K is zero.  Set INFO and iterate the loop.
            //
            case 0.0:
            {
                ipvt[k - 1] = k;
                info        = k;
                ik         -= k - 1;
                switch (kstep)
                {
                case 2:
                    ik -= k - 2;
                    break;
                }

                k -= kstep;
                continue;
            }
            }

            Complex mulk;
            Complex t;
            int     jk;
            int     jj;
            int     ij;
            if (kstep != 2)
            {
                switch (swap)
                {
                //
                //  1 x 1 pivot block.
                //
                case true:
                {
                    BLAS1Z.zswap(imax, ref ap, 1, ref ap, 1, xIndex: +im, yIndex: +ik);
                    imj = ik + imax;

                    for (jj = imax; jj <= k; jj++)
                    {
                        j  = k + imax - jj;
                        jk = ik + j;

                        t           = ap[jk - 1];
                        ap[jk - 1]  = ap[imj - 1];
                        ap[imj - 1] = t;

                        imj -= j - 1;
                    }

                    break;
                }
                }

                //
                //  Perform the elimination.
                //
                ij = ik - (k - 1);

                for (jj = 1; jj <= km1; jj++)
                {
                    j    = k - jj;
                    jk   = ik + j;
                    mulk = -ap[jk - 1] / ap[kk - 1];
                    t    = mulk;
                    BLAS1Z.zaxpy(j, t, ap, 1, ref ap, 1, xIndex: +ik, yIndex: +ij);
                    ap[jk - 1] = mulk;
                    ij        -= j - 1;
                }

                ipvt[k - 1] = swap switch
                {
                    //
                    //  Set the pivot array.
                    //
                    true => imax,
                    _ => k
                };
            }
            //
            //  2 x 2 pivot block.
            //
            else
            {
                int km1k = ik + k - 1;
                int ikm1 = ik - (k - 1);

                int jkm1;
                switch (swap)
                {
                case true:
                {
                    BLAS1Z.zswap(imax, ref ap, 1, ref ap, 1, xIndex: +im, yIndex: +ikm1);
                    imj = ikm1 + imax;

                    for (jj = imax; jj <= km1; jj++)
                    {
                        j    = km1 + imax - jj;
                        jkm1 = ikm1 + j;

                        t            = ap[jkm1 - 1];
                        ap[jkm1 - 1] = ap[imj - 1];
                        ap[imj - 1]  = t;

                        imj -= j - 1;
                    }

                    t            = ap[km1k - 1];
                    ap[km1k - 1] = ap[imk - 1];
                    ap[imk - 1]  = t;
                    break;
                }
                }

                //
                //  Perform the elimination.
                //
                int km2 = k - 2;

                if (km2 != 0)
                {
                    Complex ak     = ap[kk - 1] / ap[km1k - 1];
                    int     km1km1 = ikm1 + k - 1;
                    Complex akm1   = ap[km1km1 - 1] / ap[km1k - 1];
                    Complex denom  = new Complex(1.0, 0.0) - ak * akm1;
                    ij = ik - (k - 1) - (k - 2);

                    for (jj = 1; jj <= km2; jj++)
                    {
                        j  = km1 - jj;
                        jk = ik + j;
                        Complex bk = ap[jk - 1] / ap[km1k - 1];
                        jkm1 = ikm1 + j;
                        Complex bkm1 = ap[jkm1 - 1] / ap[km1k - 1];
                        mulk = (akm1 * bk - bkm1) / denom;
                        Complex mulkm1 = (ak * bkm1 - bk) / denom;
                        t = mulk;
                        BLAS1Z.zaxpy(j, t, ap, 1, ref ap, 1, xIndex: +ik, yIndex: +ij);
                        t = mulkm1;
                        BLAS1Z.zaxpy(j, t, ap, 1, ref ap, 1, xIndex: +ikm1, yIndex: +ij);
                        ap[jk - 1]   = mulk;
                        ap[jkm1 - 1] = mulkm1;
                        ij          -= j - 1;
                    }
                }

                ipvt[k - 1] = swap switch
                {
                    //
                    //  Set the pivot array.
                    //
                    true => - imax,
                    _ => 1 - k
                };

                ipvt[k - 2] = ipvt[k - 1];
            }

            ik -= k - 1;

            switch (kstep)
            {
            case 2:
                ik -= k - 2;
                break;
            }

            k -= kstep;
        }

        return(info);
    }
}
예제 #4
0
    public static void zpodi(ref Complex[] a, int lda, int n, ref double[] det, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZPODI: determinant, inverse of a complex hermitian positive definite matrix.
    //
    //  Discussion:
    //
    //    The matrix is assumed to have been factored by ZPOCO, ZPOFA or ZQRDC.
    //
    //    A division by zero will occur if the input factor contains
    //    a zero on the diagonal and the inverse is requested.
    //    It will not occur if the subroutines are called correctly
    //    and if ZPOCO or ZPOFA has set INFO == 0.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex A[LDA*N]; on input, the output A from ZPOCO or
    //    ZPOFA, or the output X from ZQRDC.  On output, if ZPOCO or ZPOFA was
    //    used to factor A, then ZPODI produces the upper half of inverse(A).
    //    If ZQRDC was used to decompose X, then ZPODI produces the upper half
    //    of inverse(hermitian(X)*X) where hermitian(X) is the conjugate transpose.
    //    Elements of A below the diagonal are unchanged.
    //    If the units digit of JOB is zero, A is unchanged.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Output, double DET[2], if requested, the determinant of A or of
    //    hermitian(X)*X.  Determinant = DET(1) * 10.0**DET(2) with
    //    1.0 <= abs ( DET(1) ) < 10.0 or DET(1) = 0.0.
    //
    //    Input, int JOB.
    //    11, both determinant and inverse.
    //    01, inverse only.
    //    10, determinant only.
    //
    {
        //
        //  Compute determinant
        //
        if (job / 10 != 0)
        {
            det[0] = 1.0;
            det[1] = 0.0;

            int i;
            for (i = 0; i < n; i++)
            {
                det[0] = det[0] * a[i + i * lda].Real * a[i + i * lda].Real;

                if (det[0] == 0.0)
                {
                    break;
                }

                while (det[0] < 1.0)
                {
                    det[0] *= 10.0;
                    det[1] -= 1.0;
                }

                while (10.0 <= det[0])
                {
                    det[0] /= 10.0;
                    det[1] += 1.0;
                }
            }
        }

        //
        //  Compute inverse(R).
        //
        if (job % 10 == 0)
        {
            return;
        }

        int     j;
        int     k;
        Complex t;

        for (k = 1; k <= n; k++)
        {
            a[k - 1 + (k - 1) * lda] = new Complex(1.0, 0.0) / a[k - 1 + (k - 1) * lda];
            t = -a[k - 1 + (k - 1) * lda];
            BLAS1Z.zscal(k - 1, t, ref a, 1, index: +0 + (k - 1) * lda);

            for (j = k + 1; j <= n; j++)
            {
                t = a[k - 1 + (j - 1) * lda];
                a[k - 1 + (j - 1) * lda] = new Complex(0.0, 0.0);
                BLAS1Z.zaxpy(k, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda);
            }
        }

        //
        //  Form inverse(R) * hermitian(inverse(R)).
        //
        for (j = 1; j <= n; j++)
        {
            for (k = 1; k <= j - 1; k++)
            {
                t = Complex.Conjugate(a[k - 1 + (j - 1) * lda]);
                BLAS1Z.zaxpy(k, t, a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda, yIndex: +0 + (k - 1) * lda);
            }

            t = Complex.Conjugate(a[j - 1 + (j - 1) * lda]);
            BLAS1Z.zscal(j, t, ref a, 1, index: +0 + (j - 1) * lda);
        }
    }
예제 #5
0
    public static double zgeco(ref Complex[] a, int lda, int n, ref int[] ipvt)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZGECO factors a complex matrix and estimates its condition.
    //
    //  Discussion:
    //
    //    If RCOND is not needed, ZGEFA is slightly faster.
    //
    //    To solve A*X = B, follow ZGECO by ZGESL.
    //
    //    To compute inverse(A)*C, follow ZGECO by ZGESL.
    //
    //    To compute determinant(A), follow ZGECO by ZGEDI.
    //
    //    To compute inverse(A), follow ZGECO by ZGEDI.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex A[LDA*N], on input, the matrix to be
    //    factored.  On output, an upper triangular matrix and the multipliers
    //    used to obtain it.  The factorization can be written A = L*U where
    //    L is a product of permutation and unit lower triangular matrices
    //    and U is upper triangular.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Output, int IPVT[N], the pivot indices.
    //
    //    Output, double SGECO, an estimate of the reciprocal condition of A.
    //    For the system A*X = B, relative perturbations in A and B of size
    //    EPSILON may cause relative perturbations in X of size (EPSILON/RCOND).
    //    If RCOND is so small that the logical expression
    //      1.0 + RCOND == 1.0
    //    is true, then A may be singular to working precision.  In particular,
    //    RCOND is zero if exact singularity is detected or the estimate
    //    underflows.
    //
    //  Local Parameters:
    //
    //    Workspace, Complex Z[N], a work vector whose contents are usually
    //    unimportant.  If A is close to a singular matrix, then Z is
    //    an approximate null vector in the sense that
    //      norm ( A * Z ) = RCOND * norm ( A ) * norm ( Z ).
    //
    {
        int     i;
        int     j;
        int     k;
        int     l;
        double  rcond;
        double  s;
        Complex t;

        Complex[] z = new Complex [n];
        //
        //  Compute the 1-norm of A.
        //
        double anorm = 0.0;

        for (j = 0; j < n; j++)
        {
            anorm = Math.Max(anorm, BLAS1Z.dzasum(n, a, 1, index: +0 + j * lda));
        }

        //
        //  Factor.
        //
        ZGEFA.zgefa(ref a, lda, n, ref ipvt);
        //
        //  RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))).
        //
        //  Estimate = norm(Z)/norm(Y) where A*Z = Y and hermitian(A)*Y = E.
        //
        //  Hermitian(A) is the Complex.Conjugateugate transpose of A.
        //
        //  The components of E are chosen to cause maximum local
        //  growth in the elements of W where hermitian(U)*W = E.
        //
        //  The vectors are frequently rescaled to avoid overflow.
        //
        //  Solve hermitian(U)*W = E.
        //
        Complex ek = new(1.0, 0.0);

        for (i = 0; i < n; i++)
        {
            z[i] = new Complex(0.0, 0.0);
        }

        for (k = 1; k <= n; k++)
        {
            if (typeMethods.zabs1(z[k - 1]) != 0.0)
            {
                ek = typeMethods.zsign1(ek, -z[k - 1]);
            }

            if (typeMethods.zabs1(a[k - 1 + (k - 1) * lda]) < typeMethods.zabs1(ek - z[k - 1]))
            {
                s = typeMethods.zabs1(a[k - 1 + (k - 1) * lda]) / typeMethods.zabs1(ek - z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ek = new Complex(s, 0.0) * ek;
            }

            Complex wk  = ek - z[k - 1];
            Complex wkm = -ek - z[k - 1];
            s = typeMethods.zabs1(wk);
            double sm = typeMethods.zabs1(wkm);

            if (typeMethods.zabs1(a[k - 1 + (k - 1) * lda]) != 0.0)
            {
                wk  /= Complex.Conjugate(a[k - 1 + (k - 1) * lda]);
                wkm /= Complex.Conjugate(a[k - 1 + (k - 1) * lda]);
            }
            else
            {
                wk  = new Complex(1.0, 0.0);
                wkm = new Complex(1.0, 0.0);
            }

            for (j = k + 1; j <= n; j++)
            {
                sm       += typeMethods.zabs1(z[j - 1] + wkm * Complex.Conjugate(a[k - 1 + (j - 1) * lda]));
                z[j - 1] += wk * Complex.Conjugate(a[k - 1 + (j - 1) * lda]);
                s        += typeMethods.zabs1(z[j - 1]);
            }

            if (s < sm)
            {
                t  = wkm - wk;
                wk = wkm;
                for (j = k + 1; j <= n; j++)
                {
                    z[j - 1] += t * Complex.Conjugate(a[k - 1 + (j - 1) * lda]);
                }
            }

            z[k - 1] = wk;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        //
        //  Solve hermitian(L) * Y = W.
        //
        for (k = n; 1 <= k; k--)
        {
            if (k < n)
            {
                z[k - 1] += BLAS1Z.zdotc(n - k, a, 1, z, 1, xIndex: +k + (k - 1) * lda, yIndex: +k);
            }

            if (1.0 < typeMethods.zabs1(z[k - 1]))
            {
                s = 1.0 / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
            }

            l = ipvt[k - 1];

            t        = z[l - 1];
            z[l - 1] = z[k - 1];
            z[k - 1] = t;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);

        double ynorm = 1.0;

        //
        //  Solve L * V = Y.
        //
        for (k = 1; k <= n; k++)
        {
            l = ipvt[k - 1];

            t        = z[l - 1];
            z[l - 1] = z[k - 1];
            z[k - 1] = t;

            if (k < n)
            {
                BLAS1Z.zaxpy(n - k, t, a, 1, ref z, 1, xIndex: +k + (k - 1) * lda, yIndex: +k);
            }

            if (!(1.0 < typeMethods.zabs1(z[k - 1])))
            {
                continue;
            }

            s = 1.0 / typeMethods.zabs1(z[k - 1]);
            BLAS1Z.zdscal(n, s, ref z, 1);
            ynorm = s * ynorm;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;
        //
        //  Solve U * Z = V.
        //
        for (k = n; 1 <= k; k--)
        {
            if (typeMethods.zabs1(a[k - 1 + (k - 1) * lda]) < typeMethods.zabs1(z[k - 1]))
            {
                s = typeMethods.zabs1(a[k - 1 + (k - 1) * lda]) / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ynorm = s * ynorm;
            }

            if (typeMethods.zabs1(a[k - 1 + (k - 1) * lda]) != 0.0)
            {
                z[k - 1] /= a[k - 1 + (k - 1) * lda];
            }
            else
            {
                z[k - 1] = new Complex(1.0, 0.0);
            }

            t = -z[k - 1];
            BLAS1Z.zaxpy(k - 1, t, a, 1, ref z, 1, xIndex: +0 + (k - 1) * lda);
        }

        //
        //  Make ZNORM = 1.
        //
        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;

        if (anorm != 0.0)
        {
            rcond = ynorm / anorm;
        }
        else
        {
            rcond = 0.0;
        }

        return(rcond);
    }
예제 #6
0
    public static int zchdc(ref Complex[] a, int lda, int p, ref int[] ipvt, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZCHDC: Cholesky decomposition of a Hermitian positive definite matrix.
    //
    //  Discussion:
    //
    //    A pivoting option allows the user to estimate the condition of a
    //    Hermitian positive definite matrix or determine the rank of a
    //    Hermitian positive semidefinite matrix.
    //
    //    For Hermitian positive definite matrices, INFO = P is the normal return.
    //
    //    For pivoting with Hermitian positive semidefinite matrices, INFO will
    //    in general be less than P.  However, INFO may be greater than
    //    the rank of A, since rounding error can cause an otherwise zero
    //    element to be positive.  Indefinite systems will always cause
    //    INFO to be less than P.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, complex <double> A[LDA*P].  On input, A contains the matrix
    //    whose decomposition is to be computed.  Only the upper half of A
    //    need be stored.  The lower part of the array A is not referenced.
    //    On output, A contains in its upper half the Cholesky factor
    //    of the matrix A as it has been permuted by pivoting.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int P, the order of the matrix.
    //
    //    Input/output, int IPVT[P].  IPVT is not referenced if JOB == 0.
    //    On input, IPVT contains integers that control the selection of the
    //    pivot elements, if pivoting has been requested.  Each diagonal element
    //    A(K,K) is placed in one of three classes according to the input
    //    value of IPVT(K):
    //      IPVT(K) >  0, X(K) is an initial element.
    //      IPVT(K) == 0, X(K) is a free element.
    //      IPVT(K) <  0, X(K) is a final element.
    //    Before the decomposition is computed, initial elements are moved by
    //    symmetric row and column interchanges to the beginning of the array A
    //    and final elements to the end.  Both initial and final elements
    //    are frozen in place during the computation and only free elements
    //    are moved.  At the K-th stage of the reduction, if A(K,K) is occupied
    //    by a free element, it is interchanged with the largest free element
    //    A(L,L) with K <= L.
    //    On output, IPVT(K) contains the index of the diagonal element
    //    of A that was moved into the J-th position, if pivoting was requested.
    //
    //    Input, int JOB, specifies whether column pivoting is to be done.
    //    0, no pivoting is done.
    //    nonzero, pivoting is done.
    //
    //    Output, int ZCHDC, contains the index of the last positive
    //    diagonal element of the Cholesky factor.
    //
    {
        int     i_temp;
        int     j;
        int     k;
        Complex temp;

        int pl   = 1;
        int pu   = 0;
        int info = p;

        Complex[] work = new Complex[p];

        if (job != 0)
        {
            //
            //  Pivoting has been requested.  Rearrange the elements according to IPVT.
            //
            for (k = 1; k <= p; k++)
            {
                bool swapk = 0 < ipvt[k - 1];
                bool negk  = ipvt[k - 1] < 0;

                ipvt[k - 1] = negk switch
                {
                    true => - k,
                    _ => k
                };

                switch (swapk)
                {
                case true:
                {
                    if (k != pl)
                    {
                        BLAS1Z.zswap(pl - 1, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda,
                                     yIndex: +0 + (pl - 1) * lda);

                        temp = a[k - 1 + (k - 1) * lda];
                        a[k - 1 + (k - 1) * lda]   = a[pl - 1 + (pl - 1) * lda];
                        a[pl - 1 + (pl - 1) * lda] = temp;

                        a[pl - 1 + (k - 1) * lda] = Complex.Conjugate(a[pl - 1 + (k - 1) * lda]);
                        int plp1 = pl + 1;

                        for (j = plp1; j <= p; j++)
                        {
                            if (j < k)
                            {
                                temp = Complex.Conjugate(a[pl - 1 + (j - 1) * lda]);
                                a[pl - 1 + (j - 1) * lda] = Complex.Conjugate(a[j - 1 + (k - 1) * lda]);
                                a[j - 1 + (k - 1) * lda]  = temp;
                            }
                            else if (j != k)
                            {
                                temp = a[pl - 1 + (j - 1) * lda];
                                a[pl - 1 + (j - 1) * lda] = a[k - 1 + (j - 1) * lda];
                                a[k - 1 + (j - 1) * lda]  = temp;
                            }
                        }

                        ipvt[k - 1]  = ipvt[pl - 1];
                        ipvt[pl - 1] = k;
                    }

                    pl += 1;
                    break;
                }
                }
            }

            pu = p;

            int kb;
            for (kb = pl; kb <= p; kb++)
            {
                k = p - kb + pl;

                switch (ipvt[k - 1])
                {
                case < 0:
                {
                    ipvt[k - 1] = -ipvt[k - 1];

                    if (pu != k)
                    {
                        BLAS1Z.zswap(k - 1, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda,
                                     yIndex: +0 + (pu - 1) * lda);

                        temp = a[k - 1 + (k - 1) * lda];
                        a[k - 1 + (k - 1) * lda]   = a[pu - 1 + (pu - 1) * lda];
                        a[pu - 1 + (pu - 1) * lda] = temp;

                        a[k - 1 + (pu - 1) * lda] = Complex.Conjugate(a[k - 1 + (pu - 1) * lda]);

                        for (j = k + 1; j <= p; j++)
                        {
                            if (j < pu)
                            {
                                temp = Complex.Conjugate(a[k - 1 + (j - 1) * lda]);
                                a[k - 1 + (j - 1) * lda]  = Complex.Conjugate(a[j - 1 + (pu - 1) * lda]);
                                a[j - 1 + (pu - 1) * lda] = temp;
                            }
                            else if (j != pu)
                            {
                                temp = a[k - 1 + (j - 1) * lda];
                                a[k - 1 + (j - 1) * lda]  = a[pu - 1 + (j - 1) * lda];
                                a[pu - 1 + (j - 1) * lda] = temp;
                            }
                        }

                        i_temp       = ipvt[k - 1];
                        ipvt[k - 1]  = ipvt[pu - 1];
                        ipvt[pu - 1] = i_temp;
                    }

                    pu -= 1;
                    break;
                }
                }
            }
        }

        for (k = 1; k <= p; k++)
        {
            //
            //  Reduction loop.
            //
            double maxdia = a[k - 1 + (k - 1) * lda].Real;
            int    maxl   = k;
            //
            //  Determine the pivot element.
            //
            if (pl <= k && k < pu)
            {
                int l;
                for (l = k + 1; l <= pu; l++)
                {
                    if (!(maxdia < a[l - 1 + (l - 1) * lda].Real))
                    {
                        continue;
                    }

                    maxdia = a[l - 1 + (l - 1) * lda].Real;
                    maxl   = l;
                }
            }

            switch (maxdia)
            {
            //
            //  Quit if the pivot element is not positive.
            //
            case <= 0.0:
                info = k - 1;
                return(info);
            }

            //
            //  Start the pivoting and update IPVT.
            //
            if (k != maxl)
            {
                BLAS1Z.zswap(k - 1, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (maxl - 1) * lda);
                a[maxl - 1 + (maxl - 1) * lda] = a[k - 1 + (k - 1) * lda];
                a[k - 1 + (k - 1) * lda]       = new Complex(maxdia, 0.0);

                i_temp         = ipvt[maxl - 1];
                ipvt[maxl - 1] = ipvt[k - 1];
                ipvt[k - 1]    = i_temp;

                a[k - 1 + (maxl - 1) * lda] = Complex.Conjugate(a[k - 1 + (maxl - 1) * lda]);
            }

            //
            //  Reduction step.  Pivoting is contained across the rows.
            //
            work[k - 1] = new Complex(Math.Sqrt(a[k - 1 + (k - 1) * lda].Real), 0.0);
            a[k - 1 + (k - 1) * lda] = work[k - 1];

            for (j = k + 1; j <= p; j++)
            {
                if (k != maxl)
                {
                    if (j < maxl)
                    {
                        temp = Complex.Conjugate(a[k - 1 + (j - 1) * lda]);
                        a[k - 1 + (j - 1) * lda]    = Complex.Conjugate(a[j - 1 + (maxl - 1) * lda]);
                        a[j - 1 + (maxl - 1) * lda] = temp;
                    }
                    else if (j != maxl)
                    {
                        temp = a[k - 1 + (j - 1) * lda];
                        a[k - 1 + (j - 1) * lda]    = a[maxl - 1 + (j - 1) * lda];
                        a[maxl - 1 + (j - 1) * lda] = temp;
                    }
                }

                a[k - 1 + (j - 1) * lda] /= work[k - 1];
                work[j - 1] = Complex.Conjugate(a[k - 1 + (j - 1) * lda]);
                temp        = -a[k - 1 + (j - 1) * lda];
                BLAS1Z.zaxpy(j - k, temp, work, 1, ref a, 1, xIndex: +k, yIndex: +k + (j - 1) * lda);
            }
        }

        return(info);
    }
}
예제 #7
0
    public static double zppco(ref Complex[] ap, int n, ref int info)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZPPCO factors a complex <double> hermitian positive definite matrix.
    //
    //  Discussion:
    //
    //    The routine also estimates the condition of the matrix.
    //
    //    The matrix is stored in packed form.
    //
    //    If RCOND is not needed, ZPPFA is slightly faster.
    //
    //    To solve A*X = B, follow ZPPCO by ZPPSL.
    //
    //    To compute inverse(A)*C, follow ZPPCO by ZPPSL.
    //
    //    To compute determinant(A), follow ZPPCO by ZPPDI.
    //
    //    To compute inverse(A), follow ZPPCO by ZPPDI.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, complex <double> AP[N*(N+1)/2]; on input, the packed form of a
    //    hermitian matrix.  The columns of the upper triangle are stored
    //    sequentially in a one-dimensional array.  On output, an upper
    //    triangular matrix R, stored in packed form, so that A = hermitian(R) * R.
    //    If INFO != 0 , the factorization is not complete.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Output, double ZPPCO, an estimate of RCOND, the reciprocal condition of
    //    the matrix.  For the system A*X = B, relative perturbations in A and B
    //    of size EPSILON may cause relative perturbations in X of size
    //    (EPSILON/RCOND).  If RCOND is so small that the logical expression
    //      1.0 + RCOND == 1.0
    //    is true, then A may be singular to working precision.  In particular,
    //    RCOND is zero if exact singularity is detected or the estimate underflows.
    //
    //    Output, int *INFO.
    //    0, for normal return.
    //    K, signals an error condition.  The leading minor of order K is not
    //    positive definite.
    //
    //  Local Parameters:
    //
    //    Local, complex <double> Z[N], a work vector whose contents are usually
    //    unimportant.  If A is close to a singular matrix, then Z is an
    //    approximate null vector in the sense that
    //      norm(A*Z) = RCOND * norm(A) * norm(Z).
    //
    {
        int     j;
        int     k;
        double  rcond;
        double  s;
        Complex t;

        //
        //  Find norm of A.
        //
        Complex[] z = new Complex [n];

        int j1 = 1;

        for (j = 1; j <= n; j++)
        {
            z[j - 1] = new Complex(BLAS1Z.dzasum(j, ap, 1, index: +j1 - 1), 0.0);
            int ij = j1;
            j1 += j;

            int i;
            for (i = 1; i <= j - 1; i++)
            {
                z[i - 1] = new Complex(z[i - 1].Real + typeMethods.zabs1(ap[ij - 1]), 0.0);
                ij      += 1;
            }
        }

        double anorm = 0.0;

        for (j = 0; j < n; j++)
        {
            anorm = Math.Max(anorm, z[j].Real);
        }

        //
        //  Factor.
        //
        info = ZPPFA.zppfa(ref ap, n);

        if (info != 0)
        {
            rcond = 0.0;
            return(rcond);
        }

        //
        //  RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))).
        //
        //  Estimate = norm(Z)/norm(Y) where A*Z = Y and A*Y = E.
        //
        //  The components of E are chosen to cause maximum local
        //  growth in the elements of W where hermitian(R)*W = E.
        //
        //  The vectors are frequently rescaled to avoid overflow.
        //
        //  Solve hermitian(R)*W = E.
        //
        Complex ek = new(1.0, 0.0);

        for (j = 0; j < n; j++)
        {
            z[j] = new Complex(0.0, 0.0);
        }

        int kk = 0;

        for (k = 1; k <= n; k++)
        {
            kk += k;

            if (typeMethods.zabs1(z[k - 1]) != 0.0)
            {
                ek = typeMethods.zsign1(ek, -z[k - 1]);
            }

            if (ap[kk - 1].Real < typeMethods.zabs1(ek - z[k - 1]))
            {
                s = ap[kk - 1].Real / typeMethods.zabs1(ek - z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ek = new Complex(s, 0.0) * ek;
            }

            Complex wk  = ek - z[k - 1];
            Complex wkm = -ek - z[k - 1];
            s = typeMethods.zabs1(wk);
            double sm = typeMethods.zabs1(wkm);
            wk  /= ap[kk - 1];
            wkm /= ap[kk - 1];
            int kj = kk + k;

            if (k + 1 <= n)
            {
                for (j = k + 1; j <= n; j++)
                {
                    sm       += typeMethods.zabs1(z[j - 1] + wkm * Complex.Conjugate(ap[kj - 1]));
                    z[j - 1] += wk * Complex.Conjugate(ap[kj - 1]);
                    s        += typeMethods.zabs1(z[j - 1]);
                    kj       += j;
                }

                if (s < sm)
                {
                    t  = wkm - wk;
                    wk = wkm;
                    kj = kk + k;
                    for (j = k + 1; j <= n; j++)
                    {
                        z[j - 1] += t * Complex.Conjugate(ap[kj - 1]);
                        kj       += j;
                    }
                }
            }

            z[k - 1] = wk;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        //
        //  Solve R * Y = W.
        //
        for (k = n; 1 <= k; k--)
        {
            if (ap[kk - 1].Real < typeMethods.zabs1(z[k - 1]))
            {
                s = ap[kk - 1].Real / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
            }

            z[k - 1] /= ap[kk - 1];
            kk       -= k;
            t         = -z[k - 1];
            BLAS1Z.zaxpy(k - 1, t, ap, 1, ref z, 1, xIndex: +kk);
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        double ynorm = 1.0;

        //
        //  Solve hermitian(R) * V = Y.
        //
        for (k = 1; k <= n; k++)
        {
            z[k - 1] -= BLAS1Z.zdotc(k - 1, ap, 1, z, 1, xIndex: +kk);
            kk       += k;

            if (ap[kk - 1].Real < typeMethods.zabs1(z[k - 1]))
            {
                s = ap[kk - 1].Real / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ynorm = s * ynorm;
            }

            z[k - 1] /= ap[kk - 1];
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;
        //
        //  Solve R * Z = V.
        //
        for (k = n; 1 <= k; k--)
        {
            if (ap[kk - 1].Real < typeMethods.zabs1(z[k - 1]))
            {
                s = ap[kk - 1].Real / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ynorm = s * ynorm;
            }

            z[k - 1] /= ap[kk - 1];
            kk       -= k;
            t         = -z[k - 1];
            BLAS1Z.zaxpy(k - 1, t, ap, 1, ref z, 1, xIndex: +kk);
        }

        //
        //  Make ZNORM = 1.
        //
        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;

        if (anorm != 0.0)
        {
            rcond = ynorm / anorm;
        }
        else
        {
            rcond = 0.0;
        }
        return(rcond);
    }
예제 #8
0
    public static double zgbco(ref Complex[] abd, int lda, int n, int ml, int mu,
                               ref int[] ipvt)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZGBCO factors a complex band matrix and estimates its condition.
    //
    //  Discussion:
    //
    //    If RCOND is not needed, ZGBFA is slightly faster.
    //
    //    To solve A*X = B, follow ZGBCO by ZGBSL.
    //
    //    To compute inverse(A)*C, follow ZGBCO by ZGBSL.
    //
    //    To compute determinant(A), follow ZGBCO by ZGBDI.
    //
    //  Band storage:
    //
    //    If A is a band matrix, the following program segment
    //    will set up the input.
    //
    //      ml = (band width below the diagonal)
    //      mu = (band width above the diagonal)
    //      m = ml + mu + 1
    //      do j = 1, n
    //        i1 = max ( 1, j - mu )
    //        i2 = min ( n, j + ml )
    //        do i = i1, i2
    //          k = i - j + m
    //          abd(k,j) = a(i,j)
    //        }
    //      }
    //
    //    This uses rows ML+1 through 2*ML+MU+1 of ABD.
    //    In addition, the first ML rows in ABD are used for
    //    elements generated during the triangularization.
    //    The total number of rows needed in ABD is 2*ML+MU+1.
    //    The ML+MU by ML+MU upper left triangle and the
    //    ML by ML lower right triangle are not referenced.
    //
    //  Example:
    //
    //    If the original matrix A is
    //
    //      11 12 13  0  0  0
    //      21 22 23 24  0  0
    //       0 32 33 34 35  0
    //       0  0 43 44 45 46
    //       0  0  0 54 55 56
    //       0  0  0  0 65 66
    //
    //     Then N = 6, ML = 1, MU = 2, 5 <= LDA and ABD should contain
    //
    //       *  *  *  +  +  +
    //       *  * 13 24 35 46
    //       * 12 23 34 45 56
    //      11 22 33 44 55 66
    //      21 32 43 54 65  *
    //
    //    * = not used,
    //    + = used for pivoting.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex ABD[LDA*N], on input, contains the matrix in
    //    band storage.  The columns of the matrix are stored in the columns
    //    of ABD and the diagonals of the matrix are stored in rows ML+1
    //    through 2*ML+MU+1 of ABD.  On output, an upper triangular matrix
    //    in band storage and the multipliers which were used to obtain it.
    //    The factorization can be written A = L*U where L is a product of
    //    permutation and unit lower triangular matrices and U is upper triangular.
    //
    //    Input, int LDA, the leading dimension of ABD.
    //    LDA must be at least 2*ML+MU+1.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int ML, the number of diagonals below the main diagonal.
    //    0 <= ML < N.
    //
    //    Input, int MU, the number of diagonals above the main diagonal.
    //    0 <= MU < N.
    //    More efficient if ML <= MU.
    //
    //    Output, int IPVT[N], the pivot indices.
    //
    //    Output, double ZGBCO, an estimate of the reciprocal condition RCOND of A.
    //    For the system A*X = B, relative perturbations in A and B of size
    //    epsilon may cause relative perturbations in X of size (EPSILON/RCOND).
    //    If RCOND is so small that the logical expression
    //      1.0 + RCOND == 1.0
    //    is true, then A may be singular to working precision.  In particular,
    //    RCOND is zero if exact singularity is detected or the estimate
    //    underflows.
    //
    //  Local Parameters:
    //
    //    Workspace, Complex Z[N], a work vector whose contents are usually
    //    unimportant.  If A is close to a singular matrix, then Z is an
    //    approximate null vector in the sense that
    //      norm ( A * Z ) = RCOND * norm ( A ) * norm ( Z ).
    //
    {
        int     j;
        int     k;
        int     lm;
        double  rcond;
        double  s;
        Complex t;

        Complex[] z = new Complex [n];
        //
        //  Compute 1-norm of A.
        //
        double anorm = 0.0;
        int    l     = ml + 1;
        int    is_   = l + mu;

        for (j = 1; j <= n; j++)
        {
            anorm = Math.Max(anorm, BLAS1Z.dzasum(l, abd, 1, index: +is_ - 1 + (j - 1) * lda));

            if (ml + 1 < is_)
            {
                is_ -= 1;
            }

            if (j <= mu)
            {
                l += 1;
            }

            if (n - ml <= j)
            {
                l -= 1;
            }
        }

        //
        //  Factor
        //
        ZGBFA.zgbfa(ref abd, lda, n, ml, mu, ref ipvt);
        //
        //  RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))).
        //
        //  Estimate = norm(Z)/norm(Y) where A*Z = Y and hermitian(A)*Y = E.
        //
        //  Hermitian(A) is the Complex.Conjugateugate transpose of A.
        //
        //  The components of E are chosen to cause maximum local
        //  growth in the elements of W where hermitian(U)*W = E.
        //
        //  The vectors are frequently rescaled to avoid overflow.
        //
        //  Solve hermitian(U) * W = E.
        //
        Complex ek = new(1.0, 0.0);

        for (j = 1; j <= n; j++)
        {
            z[j - 1] = new Complex(0.0, 0.0);
        }

        int m  = ml + mu + 1;
        int ju = 0;

        for (k = 1; k <= n; k++)
        {
            if (typeMethods.zabs1(z[k - 1]) != 0.0)
            {
                ek = typeMethods.zsign1(ek, -z[k - 1]);
            }

            if (typeMethods.zabs1(abd[m - 1 + (k - 1) * lda]) < typeMethods.zabs1(ek - z[k - 1]))
            {
                s = typeMethods.zabs1(abd[m - 1 + (k - 1) * lda]) / typeMethods.zabs1(ek - z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ek = new Complex(s, 0.0) * ek;
            }

            Complex wk  = ek - z[k - 1];
            Complex wkm = -ek - z[k - 1];
            s = typeMethods.zabs1(wk);
            double sm = typeMethods.zabs1(wkm);

            if (typeMethods.zabs1(abd[m - 1 + (k - 1) * lda]) != 0.0)
            {
                wk  /= Complex.Conjugate(abd[m - 1 + (k - 1) * lda]);
                wkm /= Complex.Conjugate(abd[m - 1 + (k - 1) * lda]);
            }
            else
            {
                wk  = new Complex(1.0, 0.0);
                wkm = new Complex(1.0, 0.0);
            }

            ju = Math.Min(Math.Max(ju, mu + ipvt[k - 1]), n);
            int mm = m;

            if (k + 1 <= ju)
            {
                for (j = k + 1; j <= ju; j++)
                {
                    mm       -= 1;
                    sm       += typeMethods.zabs1(z[j - 1] + wkm * Complex.Conjugate(abd[mm - 1 + (j - 1) * lda]));
                    z[j - 1] += wk * Complex.Conjugate(abd[mm - 1 + (j - 1) * lda]);
                    s        += typeMethods.zabs1(z[j - 1]);
                }

                if (s < sm)
                {
                    t  = wkm - wk;
                    wk = wkm;
                    mm = m;
                    for (j = k + 1; j <= ju; j++)
                    {
                        mm       -= 1;
                        z[j - 1] += t * Complex.Conjugate(abd[mm - 1 + (j - 1) * lda]);
                    }
                }
            }

            z[k - 1] = wk;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        //
        //  Solve hermitian(L) * Y = W.
        //
        for (k = n; 1 <= k; k--)
        {
            lm = Math.Min(ml, n - k);

            if (k < n)
            {
                z[k - 1] += BLAS1Z.zdotc(lm, abd, 1, z, 1, xIndex: +m + (k - 1) * lda, yIndex: +k);
            }

            if (1.0 < typeMethods.zabs1(z[k - 1]))
            {
                s = 1.0 / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
            }

            l = ipvt[k - 1];

            t        = z[l - 1];
            z[l - 1] = z[k - 1];
            z[k - 1] = t;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        double ynorm = 1.0;

        //
        //  Solve L * V = Y.
        //
        for (k = 1; k <= n; k++)
        {
            l = ipvt[k - 1];

            t        = z[l - 1];
            z[l - 1] = z[k - 1];
            z[k - 1] = t;

            lm = Math.Min(ml, n - k);

            if (k < n)
            {
                BLAS1Z.zaxpy(lm, t, abd, 1, ref z, 1, xIndex: +m + (k - 1) * lda, yIndex: +k);
            }

            if (!(1.0 < typeMethods.zabs1(z[k - 1])))
            {
                continue;
            }

            s = 1.0 / typeMethods.zabs1(z[k - 1]);
            BLAS1Z.zdscal(n, s, ref z, 1);
            ynorm = s * ynorm;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;
        //
        //  Solve U * Z = W.
        //
        for (k = n; 1 <= k; k--)
        {
            if (typeMethods.zabs1(abd[m - 1 + (k - 1) * lda]) < typeMethods.zabs1(z[k - 1]))
            {
                s = typeMethods.zabs1(abd[m - 1 + (k - 1) * lda]) / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ynorm = s * ynorm;
            }

            if (typeMethods.zabs1(abd[m - 1 + (k - 1) * lda]) != 0.0)
            {
                z[k - 1] /= abd[m - 1 + (k - 1) * lda];
            }
            else
            {
                z[k - 1] = new Complex(1.0, 0.0);
            }

            lm = Math.Min(k, m) - 1;
            int la = m - lm;
            int lz = k - lm;
            t = -z[k - 1];
            BLAS1Z.zaxpy(lm, t, abd, 1, ref z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lz - 1);
        }

        //
        //  Make ZNORM = 1.
        //
        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;

        if (anorm != 0.0)
        {
            rcond = ynorm / anorm;
        }
        else
        {
            rcond = 0.0;
        }

        return(rcond);
    }
예제 #9
0
    public static int zhifa(ref Complex[] a, int lda, int n, ref int[] ipvt)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZHIFA factors a complex hermitian matrix.
    //
    //  Discussion:
    //
    //    ZHIFA performs the factoring by elimination with symmetric pivoting.
    //
    //    To solve A*X = B, follow ZHIFA by ZHISL.
    //
    //    To compute inverse(A)*C, follow ZHIFA by ZHISL.
    //
    //    To compute determinant(A), follow ZHIFA by ZHIDI.
    //
    //    To compute inertia(A), follow ZHIFA by ZHIDI.
    //
    //    To compute inverse(A), follow ZHIFA by ZHIDI.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, complex <double> A[LDA*N]; on input, the hermitian matrix to be
    //    factored.  On output, a block diagonal matrix and the multipliers which
    //    were used to obtain it.  The factorization can be written
    //    A = U*D*hermitian(U) where U is a product of permutation and unit upper
    //    triangular matrices, hermitian(U) is the Complex.Conjugateugate transpose of U, and
    //    D is block diagonal with 1 by 1 and 2 by 2 blocks.  Only the diagonal
    //    and upper triangle are used.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Output, int IPVT[N], the pivot indices.
    //
    //    Output, int ZHIFA.
    //    0, normal value.
    //    K, if the K-th pivot block is singular.  This is not an error condition
    //    for this subroutine, but it does indicate that ZHISL or ZHIDI may
    //    divide by zero if called.
    //
    {
        //
        //  Initialize.
        //
        //  ALPHA is used in choosing pivot block size.
        //
        double alpha = (1.0 + Math.Sqrt(17.0)) / 8.0;

        int info = 0;
        //
        //  Main loop on K, which goes from N to 1.
        //
        int k = n;

        for (;;)
        {
            //
            //  Leave the loop if K = 0 or K = 1.
            //
            if (k == 0)
            {
                break;
            }

            if (k == 1)
            {
                ipvt[0] = 1;
                if (typeMethods.zabs1(a[0 + 0 * lda]) == 0.0)
                {
                    info = 1;
                }

                break;
            }

            //
            //  This section of code determines the kind of
            //  elimination to be performed.  When it is completed,
            //  KSTEP will be set to the size of the pivot block, and
            //  SWAP will be set to .true. if an interchange is
            //  required.
            //
            int    km1    = k - 1;
            double absakk = typeMethods.zabs1(a[k - 1 + (k - 1) * lda]);
            //
            //  Determine the largest off-diagonal element in column K.
            //
            int    imax   = BLAS1Z.izamax(k - 1, a, 1, index: +0 + (k - 1) * lda);
            double colmax = typeMethods.zabs1(a[imax - 1 + (k - 1) * lda]);

            int  j;
            int  kstep;
            bool swap;
            if (alpha * colmax <= absakk)
            {
                kstep = 1;
                swap  = false;
            }
            else
            {
                //
                //  Determine the largest off-diagonal element in row IMAX.
                //
                double rowmax = 0.0;
                for (j = imax + 1; j <= k; j++)
                {
                    rowmax = Math.Max(rowmax, typeMethods.zabs1(a[imax - 1 + (j - 1) * lda]));
                }

                if (imax != 1)
                {
                    int jmax = BLAS1Z.izamax(imax - 1, a, 1, index: +0 + (imax - 1) * lda);
                    rowmax = Math.Max(rowmax, typeMethods.zabs1(a[jmax - 1 + (imax - 1) * lda]));
                }

                if (alpha * rowmax <= typeMethods.zabs1(a[imax - 1 + (imax - 1) * lda]))
                {
                    kstep = 1;
                    swap  = true;
                }
                else if (alpha * colmax * (colmax / rowmax) <= absakk)
                {
                    kstep = 1;
                    swap  = false;
                }
                else
                {
                    kstep = 2;
                    swap  = imax != km1;
                }
            }

            switch (Math.Max(absakk, colmax))
            {
            //
            //  Column K is zero.  Set INFO and iterate the loop.
            //
            case 0.0:
                ipvt[k - 1] = k;
                info        = k;
                k          -= kstep;
                continue;
            }

            int     jj;
            Complex mulk;
            Complex t;
            if (kstep != 2)
            {
                switch (swap)
                {
                //
                //  1 x 1 pivot block.
                //
                case true:
                {
                    BLAS1Z.zswap(imax, ref a, 1, ref a, 1, xIndex: +0 + (imax - 1) * lda, yIndex: +0 + (k - 1) * lda);

                    for (jj = imax; jj <= k; jj++)
                    {
                        j = k + imax - jj;
                        t = Complex.Conjugate(a[j - 1 + (k - 1) * lda]);
                        a[j - 1 + (k - 1) * lda]    = Complex.Conjugate(a[imax - 1 + (j - 1) * lda]);
                        a[imax - 1 + (j - 1) * lda] = t;
                    }

                    break;
                }
                }

                //
                //  Perform the elimination.
                //
                for (jj = 1; jj <= km1; jj++)
                {
                    j    = k - jj;
                    mulk = -a[j - 1 + (k - 1) * lda] / a[k - 1 + (k - 1) * lda];
                    t    = Complex.Conjugate(mulk);
                    BLAS1Z.zaxpy(j, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda);
                    a[j - 1 + (j - 1) * lda] = new Complex(a[j - 1 + (j - 1) * lda].Real, 0.0);
                    a[j - 1 + (k - 1) * lda] = mulk;
                }

                ipvt[k - 1] = swap switch
                {
                    true => imax,
                    //
                    //  Set the pivot array.
                    //
                    _ => k
                };
            }
            else
            {
                switch (swap)
                {
                //
                //  2 x 2 pivot block.
                //
                case true:
                {
                    BLAS1Z.zswap(imax, ref a, 1, ref a, 1, xIndex: +0 + (imax - 1) * lda, yIndex: +0 + (k - 2) * lda);

                    for (jj = imax; jj <= km1; jj++)
                    {
                        j = km1 + imax - jj;

                        t = Complex.Conjugate(a[j - 1 + (k - 2) * lda]);
                        a[j - 1 + (k - 2) * lda]    = Complex.Conjugate(a[imax - 1 + (j - 1) * lda]);
                        a[imax - 1 + (j - 1) * lda] = t;
                    }

                    t = a[k - 2 + (k - 1) * lda];
                    a[k - 2 + (k - 1) * lda]    = a[imax - 1 + (k - 1) * lda];
                    a[imax - 1 + (k - 1) * lda] = t;
                    break;
                }
                }

                switch (k - 2)
                {
                //
                //  Perform the elimination.
                //
                case > 0:
                {
                    Complex ak    = a[k - 1 + (k - 1) * lda] / a[k - 2 + (k - 1) * lda];
                    Complex akm1  = a[k - 2 + (k - 2) * lda] / Complex.Conjugate(a[k - 2 + (k - 1) * lda]);
                    Complex denom = new Complex(1.0, 0.0) - ak * akm1;

                    for (jj = 1; jj <= k - 2; jj++)
                    {
                        j = km1 - jj;
                        Complex bk   = a[j - 1 + (k - 1) * lda] / a[k - 2 + (k - 1) * lda];
                        Complex bkm1 = a[j - 1 + (k - 2) * lda] / Complex.Conjugate(a[k - 2 + (k - 1) * lda]);
                        mulk = (akm1 * bk - bkm1) / denom;
                        Complex mulkm1 = (ak * bkm1 - bk) / denom;
                        t = Complex.Conjugate(mulk);
                        BLAS1Z.zaxpy(j, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda);
                        t = Complex.Conjugate(mulkm1);
                        BLAS1Z.zaxpy(j, t, a, 1, ref a, 1, xIndex: +0 + (k - 2) * lda, yIndex: +0 + (j - 1) * lda);
                        a[j - 1 + (k - 1) * lda] = mulk;
                        a[j - 1 + (k - 2) * lda] = mulkm1;
                        a[j - 1 + (j - 1) * lda] = new Complex(a[j - 1 + (j - 1) * lda].Real, 0.0);
                    }

                    break;
                }
                }

                ipvt[k - 1] = swap switch
                {
                    //
                    //  Set the pivot array.
                    //
                    true => - imax,
                    _ => 1 - k
                };

                ipvt[k - 2] = ipvt[k - 1];
            }

            k -= kstep;
        }

        return(info);
    }
}
예제 #10
0
    public static void zgedi(ref Complex[] a, int lda, int n, int[] ipvt,
                             ref Complex[] det, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZGEDI computes the determinant and inverse of a matrix.
    //
    //  Discussion:
    //
    //    The matrix must have been factored by ZGECO or ZGEFA.
    //
    //    A division by zero will occur if the input factor contains
    //    a zero on the diagonal and the inverse is requested.
    //    It will not occur if the subroutines are called correctly
    //    and if ZGECO has set 0.0 < RCOND or ZGEFA has set
    //    INFO == 0.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex A[LDA*N]; on input, the factor information
    //    from ZGECO or ZGEFA.  On output, the inverse matrix, if it
    //    was requested,
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int IPVT[N], the pivot vector from ZGECO or ZGEFA.
    //
    //    Output, Complex DET[2], the determinant of the original matrix,
    //    if requested.  Otherwise not referenced.
    //    Determinant = DET(1) * 10.0**DET(2) with
    //    1.0 <= typeMethods.zabs1 ( DET(1) ) < 10.0 or DET(1) == 0.0.
    //    Also, DET(2) is strictly real.
    //
    //    Input, int JOB.
    //    11, both determinant and inverse.
    //    01, inverse only.
    //    10, determinant only.
    //
    {
        int i;

        //
        //  Compute the determinant.
        //
        if (job / 10 != 0)
        {
            det[0] = new Complex(1.0, 0.0);
            det[1] = new Complex(0.0, 0.0);

            for (i = 1; i <= n; i++)
            {
                if (ipvt[i - 1] != i)
                {
                    det[0] = -det[0];
                }

                det[0] = a[i - 1 + (i - 1) * lda] * det[0];

                if (typeMethods.zabs1(det[0]) == 0.0)
                {
                    break;
                }

                while (typeMethods.zabs1(det[0]) < 1.0)
                {
                    det[0] *= new Complex(10.0, 0.0);
                    det[1] -= new Complex(1.0, 0.0);
                }

                while (10.0 <= typeMethods.zabs1(det[0]))
                {
                    det[0] /= new Complex(10.0, 0.0);
                    det[1] += new Complex(1.0, 0.0);
                }
            }
        }

        //
        //  Compute inverse(U).
        //
        if (job % 10 == 0)
        {
            return;
        }

        Complex[] work = new Complex[n];

        int     j;
        Complex t;
        int     k;

        for (k = 1; k <= n; k++)
        {
            a[k - 1 + (k - 1) * lda] = new Complex(1.0, 0.0) / a[k - 1 + (k - 1) * lda];
            t = -a[k - 1 + (k - 1) * lda];
            BLAS1Z.zscal(k - 1, t, ref a, 1, index: +0 + (k - 1) * lda);

            for (j = k + 1; j <= n; j++)
            {
                t = a[k - 1 + (j - 1) * lda];
                a[k - 1 + (j - 1) * lda] = new Complex(0.0, 0.0);
                BLAS1Z.zaxpy(k, t, a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (j - 1) * lda);
            }
        }

        //
        //  Form inverse(U) * inverse(L).
        //
        for (k = n - 1; 1 <= k; k--)
        {
            for (i = k + 1; i <= n; i++)
            {
                work[i - 1] = a[i - 1 + (k - 1) * lda];
                a[i - 1 + (k - 1) * lda] = new Complex(0.0, 0.0);
            }

            for (j = k + 1; j <= n; j++)
            {
                t = work[j - 1];
                BLAS1Z.zaxpy(n, t, a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda, yIndex: +0 + (k - 1) * lda);
            }

            int l = ipvt[k - 1];

            if (l != k)
            {
                BLAS1Z.zswap(n, ref a, 1, ref a, 1, xIndex: +0 + (k - 1) * lda, yIndex: +0 + (l - 1) * lda);
            }
        }
    }
예제 #11
0
    public static double ztrco(Complex[] t, int ldt, int n, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZTRCO estimates the condition of a complex triangular matrix.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex T[LDT*N], the triangular matrix.  The zero
    //    elements of the matrix are not referenced, and the corresponding
    //    elements of the array can be used to store other information.
    //
    //    Input, int LDT, the leading dimension of T.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int JOB, indicates if matrix is upper or lower triangular.
    //    0, lower triangular.
    //    nonzero, upper triangular.
    //
    //    Output, double ZTRCO, an estimate of RCOND, the reciprocal condition of T.
    //    For the system T*X = B, relative perturbations in T and B of size
    //    EPSILON may cause relative perturbations in X of size (EPSILON/RCOND).
    //    If RCOND is so small that the logical expression
    //      1.0 + RCOND == 1.0
    //    is true, then T may be singular to working precision.  In particular,
    //    RCOND is zero if exact singularity is detected or the estimate
    //    underflows.
    //
    //  Local Parameters:
    //
    //    Workspace, Complex Z[N], a work vector whose contents are usually
    //    unimportant.  If T is close to a singular matrix, then Z is
    //    an approximate null vector in the sense that
    //      norm(A*Z) = RCOND * norm(A) * norm(Z).
    //
    {
        int     i;
        int     i1;
        int     j;
        int     k;
        int     kk;
        double  rcond;
        double  s;
        Complex w;

        bool lower = job == 0;
        //
        //  Compute 1-norm of T
        //
        double tnorm = 0.0;

        for (j = 1; j <= n; j++)
        {
            int l;
            switch (lower)
            {
            case true:
                l  = n + 1 - j;
                i1 = j;
                break;

            default:
                l  = j;
                i1 = 1;
                break;
            }

            tnorm = Math.Max(tnorm,
                             BLAS1Z.dzasum(l, t, 1, index: +i1 - 1 + (j - 1) * ldt));
        }

        //
        //  RCOND = 1/(norm(T)*(estimate of norm(inverse(T)))).
        //
        //  Estimate = norm(Z)/norm(Y) where T*Z = Y and hermitian(T)*Y = E.
        //
        //  Hermitian(T) is the Complex.Conjugateugate transpose of T.
        //
        //  The components of E are chosen to cause maximum local
        //  growth in the elements of Y.
        //
        //  The vectors are frequently rescaled to avoid overflow.
        //
        //  Solve hermitian(T)*Y = E.
        //
        Complex ek = new(1.0, 0.0);

        Complex[] z = new Complex[n];
        for (i = 0; i < n; i++)
        {
            z[i] = new Complex(0.0, 0.0);
        }

        for (kk = 1; kk <= n; kk++)
        {
            k = lower switch
            {
                true => n + 1 - kk,
                _ => kk
            };

            if (typeMethods.zabs1(z[k - 1]) != 0.0)
            {
                ek = typeMethods.zsign1(ek, -z[k - 1]);
            }

            if (typeMethods.zabs1(t[k - 1 + (k - 1) * ldt]) < typeMethods.zabs1(ek - z[k - 1]))
            {
                s = typeMethods.zabs1(t[k - 1 + (k - 1) * ldt]) / typeMethods.zabs1(ek - z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ek = new Complex(s, 0.0) * ek;
            }

            Complex wk  = ek - z[k - 1];
            Complex wkm = -ek - z[k - 1];
            s = typeMethods.zabs1(wk);
            double sm = typeMethods.zabs1(wkm);

            if (typeMethods.zabs1(t[k - 1 + (k - 1) * ldt]) != 0.0)
            {
                wk  /= Complex.Conjugate(t[k - 1 + (k - 1) * ldt]);
                wkm /= Complex.Conjugate(t[k - 1 + (k - 1) * ldt]);
            }
            else
            {
                wk  = new Complex(1.0, 0.0);
                wkm = new Complex(1.0, 0.0);
            }

            if (kk != n)
            {
                int j2;
                int j1;
                switch (lower)
                {
                case true:
                    j1 = 1;
                    j2 = k - 1;
                    break;

                default:
                    j1 = k + 1;
                    j2 = n;
                    break;
                }

                for (j = j1; j <= j2; j++)
                {
                    sm       += typeMethods.zabs1(z[j - 1] + wkm * Complex.Conjugate(t[k - 1 + (j - 1) * ldt]));
                    z[j - 1] += wk * Complex.Conjugate(t[k - 1 + (j - 1) * ldt]);
                    s        += typeMethods.zabs1(z[j - 1]);
                }

                if (s < sm)
                {
                    w  = wkm - wk;
                    wk = wkm;
                    for (j = j1; j <= j2; j++)
                    {
                        z[j - 1] += w * Complex.Conjugate(t[k - 1 + (j - 1) * ldt]);
                    }
                }
            }

            z[k - 1] = wk;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        double ynorm = 1.0;

        //
        //  Solve T*Z = Y.
        //
        for (kk = 1; kk <= n; kk++)
        {
            k = lower switch
            {
                true => kk,
                _ => n + 1 - kk
            };

            if (typeMethods.zabs1(t[k - 1 + (k - 1) * ldt]) < typeMethods.zabs1(z[k - 1]))
            {
                s = typeMethods.zabs1(t[k - 1 + (k - 1) * ldt]) / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ynorm = s * ynorm;
            }

            if (typeMethods.zabs1(t[k - 1 + (k - 1) * ldt]) != 0.0)
            {
                z[k - 1] /= t[k - 1 + (k - 1) * ldt];
            }
            else
            {
                z[k - 1] = new Complex(1.0, 0.0);
            }

            i1 = lower switch
            {
                true => k + 1,
                _ => 1
            };

            if (kk >= n)
            {
                continue;
            }

            w = -z[k - 1];
            BLAS1Z.zaxpy(n - kk, w, t, 1, ref z, 1, xIndex: +i1 - 1 + (k - 1) * ldt, yIndex: +i1 - 1);
        }

        //
        //  Make ZNORM = 1.
        //
        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;

        if (tnorm != 0.0)
        {
            rcond = ynorm / tnorm;
        }
        else
        {
            rcond = 0.0;
        }

        return(rcond);
    }
}
예제 #12
0
    public static int ztrdi(ref Complex[] t, int ldt, int n, ref Complex[] det,
                            int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZTRDI computes the determinant and inverse of a complex triangular matrix.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex T[LDT*N], the triangular matrix.  The zero
    //    elements of the matrix are not referenced, and the corresponding
    //    elements of the array can be used to store other information.
    //    On output, if an inverse was requested, then T has been overwritten
    //    by its inverse.
    //
    //    Input, int LDT, the leading dimension of T.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int JOB.
    //    010, no determinant,    inverse, matrix is lower triangular.
    //    011, no determinant,    inverse, matrix is upper triangular.
    //    100,    determinant, no inverse.
    //    110,    determinant,    inverse, matrix is lower triangular.
    //    111,    determinant,    inverse, matrix is upper triangular.
    //
    //    Output, Complex DET[2], the determinant of the original matrix,
    //    if requested.  Otherwise not referenced.
    //    Determinant = DET(1) * 10.0**DET(2) with 1.0 <= typeMethods.zabs1 ( DET(1) ) < 10.0
    //    or DET(1) == 0.0.  Also, DET(2) is strictly real.
    //
    //    Output, int ZTRDI.
    //    0, an inverse was requested and the matrix is nonsingular.
    //    K, an inverse was requested, but the K-th diagonal element
    //    of T is zero.
    //
    {
        int info = 0;

        if (job / 100 != 0)
        {
            det[0] = new Complex(1.0, 0.0);
            det[1] = new Complex(0.0, 0.0);

            int i;
            for (i = 0; i < n; i++)
            {
                det[0] *= t[i + i * ldt];

                if (typeMethods.zabs1(det[0]) == 0.0)
                {
                    break;
                }

                while (typeMethods.zabs1(det[0]) < 1.0)
                {
                    det[0] *= new Complex(10.0, 0.0);
                    det[1] -= new Complex(1.0, 0.0);
                }

                while (10.0 <= typeMethods.zabs1(det[0]))
                {
                    det[0] /= new Complex(10.0, 0.0);
                    det[1] += new Complex(1.0, 0.0);
                }
            }
        }

        //
        //  Compute inverse of upper triangular matrix.
        //
        if (job / 10 % 10 == 0)
        {
            return(info);
        }

        Complex temp;
        int     j;
        int     k;

        if (job % 10 != 0)
        {
            info = 0;

            for (k = 0; k < n; k++)
            {
                if (typeMethods.zabs1(t[k + k * ldt]) == 0.0)
                {
                    info = k + 1;
                    break;
                }

                t[k + k * ldt] = new Complex(1.0, 0.0) / t[k + k * ldt];
                temp           = -t[k + k * ldt];
                BLAS1Z.zscal(k, temp, ref t, 1, index: +0 + k * ldt);

                for (j = k + 1; j < n; j++)
                {
                    temp           = t[k + j * ldt];
                    t[k + j * ldt] = new Complex(0.0, 0.0);
                    BLAS1Z.zaxpy(k + 1, temp, t, 1, ref t, 1, xIndex: +0 + k * ldt, yIndex: +0 + j * ldt);
                }
            }
        }
        //
        //  Compute inverse of lower triangular matrix.
        //
        else
        {
            info = 0;

            for (k = n - 1; 0 <= k; k--)
            {
                if (typeMethods.zabs1(t[k + k * ldt]) == 0.0)
                {
                    info = k + 1;
                    break;
                }

                t[k + k * ldt] = new Complex(1.0, 0.0) / t[k + k * ldt];

                if (k != n - 1)
                {
                    temp = -t[k + k * ldt];
                    BLAS1Z.zscal(n - k - 1, temp, ref t, 1, index: +k + 1 + k * ldt);
                }

                for (j = 0; j < k; j++)
                {
                    temp           = t[k + j * ldt];
                    t[k + j * ldt] = new Complex(0.0, 0.0);
                    BLAS1Z.zaxpy(n - k, temp, t, 1, ref t, 1, xIndex: +k + k * ldt, yIndex: +k + j * ldt);
                }
            }
        }

        return(info);
    }
예제 #13
0
    public static int ztrsl(Complex[] t, int ldt, int n, ref Complex[] b,
                            int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZTRSL solves triangular systems T*X=B or Hermitian(T)*X=B.
    //
    //  Discussion:
    //
    //    Hermitian ( T ) denotes the Complex.Conjugateugate transpose of the matrix T.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex T[LDT*N], the matrix of the system.  The zero
    //    elements of the matrix are not referenced, and the corresponding
    //    elements of the array can be used to store other information.
    //
    //    Input, int LDT, the leading dimension of T.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input/output, Complex B[N].  On input, the right hand side.
    //    On output, the solution.
    //
    //    Input, int JOB, specifies what kind of system is to be solved.
    //    00, solve T*X=B, T lower triangular,
    //    01, solve T*X=B, T upper triangular,
    //    10, solve hermitian(T)*X=B, T lower triangular,
    //    11, solve hermitian(T)*X=B, T upper triangular.
    //
    //    Output, int ZTRSL.
    //    0, the system is nonsingular.
    //    K, the index of the first zero diagonal element of T.
    //
    {
        int     i;
        int     info;
        int     j;
        int     jj;
        Complex temp;

        //
        //  Check for zero diagonal elements.
        //
        for (i = 0; i < n; i++)
        {
            if (typeMethods.zabs1(t[i + i * ldt]) != 0.0)
            {
                continue;
            }

            info = i + 1;
            return(info);
        }

        info = 0;
        //
        //  Determine the task and go to it.
        //
        int kase = 1;

        if (job % 10 != 0)
        {
            kase = 2;
        }

        if (job % 100 / 10 != 0)
        {
            kase += 2;
        }

        switch (kase)
        {
        //
        //  Solve T * X = B for T lower triangular.
        //
        case 1:
        {
            b[0] /= t[0 + 0 * ldt];

            for (j = 2; j <= n; j++)
            {
                temp = -b[j - 2];
                BLAS1Z.zaxpy(n - j + 1, temp, t, 1, ref b, 1, xIndex: +j - 1 + (j - 2) * ldt, yIndex: +j - 1);
                b[j - 1] /= t[j - 1 + (j - 1) * ldt];
            }

            break;
        }

        //
        //  Solve T * X = B for T upper triangular.
        //
        case 2:
        {
            b[n - 1] /= t[n - 1 + (n - 1) * ldt];

            for (jj = 2; jj <= n; jj++)
            {
                j    = n - jj + 1;
                temp = -b[j];
                BLAS1Z.zaxpy(j, temp, t, 1, ref b, 1, xIndex: +0 + j * ldt);
                b[j - 1] /= t[j - 1 + (j - 1) * ldt];
            }

            break;
        }

        //
        //  Solve hermitian(T) * X = B for T lower triangular.
        //
        case 3:
        {
            b[n - 1] /= Complex.Conjugate(t[n - 1 + (n - 1) * ldt]);

            for (jj = 2; jj <= n; jj++)
            {
                j         = n - jj + 1;
                b[j - 1] -= BLAS1Z.zdotc(jj - 1, t, 1, b, 1, xIndex: +j + (j - 1) * ldt, yIndex: +j);
                b[j - 1] /= Complex.Conjugate(t[j - 1 + (j - 1) * ldt]);
            }

            break;
        }

        //
        //  Solve hermitian(T) * X = B for T upper triangular.
        //
        case 4:
        {
            b[0] /= Complex.Conjugate(t[0 + 0 * ldt]);

            for (j = 2; j <= n; j++)
            {
                b[j - 1] -= BLAS1Z.zdotc(j - 1, t, 1, b, 1, xIndex: +0 + (j - 1) * ldt);
                b[j - 1] /= Complex.Conjugate(t[j - 1 + (j - 1) * ldt]);
            }

            break;
        }
        }

        return(info);
    }
예제 #14
0
    public static void zppsl(Complex[] ap, int n, ref Complex[] b)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZPPSL solves a complex hermitian positive definite linear system.
    //
    //  Discussion:
    //
    //    The matrix is assumed to have been factored by ZPPCO or ZPPFA.
    //
    //    A division by zero will occur if the input factor contains
    //    a zero on the diagonal.  Technically this indicates
    //    singularity but it is usually caused by improper subroutine
    //    arguments.  It will not occur if the subroutines are called
    //    correctly and INFO == 0.
    //
    //    To compute inverse(A) * C where C is a matrix with P columns:
    //
    //      call zppco(ap,n,rcond,z,info)
    //
    //      if (rcond is too small .or. info /= 0) then
    //        error
    //      end if
    //
    //      do j = 1, p
    //        call zppsl(ap,n,c(1,j))
    //      end do
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex AP[N*(N+1)/2], the output from ZPPCO or ZPPFA.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input/output, Complex B[N].  On input, the right hand side.
    //    On output, the solution.
    //
    {
        int     k;
        Complex t;

        int kk = 0;

        for (k = 1; k <= n; k++)
        {
            t        = BLAS1Z.zdotc(k - 1, ap, 1, b, 1, xIndex: +kk);
            kk      += k;
            b[k - 1] = (b[k - 1] - t) / ap[kk - 1];
        }

        for (k = n; 1 <= k; k--)
        {
            b[k - 1] /= ap[kk - 1];
            kk       -= k;
            t         = -b[k - 1];
            BLAS1Z.zaxpy(k - 1, t, ap, 1, ref b, 1, xIndex: +kk);
        }
    }
예제 #15
0
    public static void zpbsl(Complex[] abd, int lda, int n, int m,
                             ref Complex[] b)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZPBSL solves a complex hermitian positive definite band system.
    //
    //  Discussion:
    //
    //    The system matrix must have been factored by ZPBCO or ZPBFA.
    //
    //    A division by zero will occur if the input factor contains
    //    a zero on the diagonal.  Technically this indicates
    //    singularity but it is usually caused by improper subroutine
    //    arguments.  It will not occur if the subroutines are called
    //    correctly and INFO == 0.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex ABD[LDA*N], the output from ZPBCO or ZPBFA.
    //
    //    Input, int LDA, the leading dimension of ABD.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int M, the number of diagonals above the main diagonal.
    //
    //    Input/output, Complex B[N].  On input, the right hand side.
    //    On output, the solution.
    //
    {
        int     k;
        int     la;
        int     lb;
        int     lm;
        Complex t;

        //
        //  Solve hermitian(R) * Y = B.
        //
        for (k = 1; k <= n; k++)
        {
            lm       = Math.Min(k - 1, m);
            la       = m + 1 - lm;
            lb       = k - lm;
            t        = BLAS1Z.zdotc(lm, abd, 1, b, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1);
            b[k - 1] = (b[k - 1] - t) / abd[m + (k - 1) * lda];
        }

        //
        //  Solve R * X = Y.
        //
        for (k = n; 1 <= k; k--)
        {
            lm        = Math.Min(k - 1, m);
            la        = m + 1 - lm;
            lb        = k - lm;
            b[k - 1] /= abd[m + (k - 1) * lda];
            t         = -b[k - 1];
            BLAS1Z.zaxpy(lm, t, abd, 1, ref b, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1);
        }
    }
예제 #16
0
    public static int zgefa(ref Complex[] a, int lda, int n, ref int[] ipvt)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZGEFA factors a complex matrix by Gaussian elimination.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex A[LDA*N]; on input, the matrix to be factored.
    //    On output, an upper triangular matrix and the multipliers which were
    //    used to obtain it.  The factorization can be written A = L*U where
    //    L is a product of permutation and unit lower triangular matrices and
    //    U is upper triangular.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Output, int IPVT[N], the pivot indices.
    //
    //    Output, int ZGEFA,
    //    0, normal value.
    //    K, if U(K,K) == 0.0.  This is not an error condition for this
    //    subroutine, but it does indicate that ZGESL or ZGEDI will divide by zero
    //    if called.  Use RCOND in ZGECO for a reliable indication of singularity.
    //
    {
        int k;
        //
        //  Gaussian elimination with partial pivoting.
        //
        int info = 0;

        for (k = 1; k <= n - 1; k++)
        {
            //
            //  Find L = pivot index.
            //
            int l = BLAS1Z.izamax(n - k + 1, a, 1, index: +(k - 1) + (k - 1) * lda) + k - 1;
            ipvt[k - 1] = l;
            //
            //  Zero pivot implies this column already triangularized.
            //
            if (typeMethods.zabs1(a[l - 1 + (k - 1) * lda]) == 0.0)
            {
                info = k;
                continue;
            }

            //
            //  Interchange if necessary.
            //
            Complex t;
            if (l != k)
            {
                t = a[l - 1 + (k - 1) * lda];
                a[l - 1 + (k - 1) * lda] = a[k - 1 + (k - 1) * lda];
                a[k - 1 + (k - 1) * lda] = t;
            }

            //
            //  Compute multipliers
            //
            t = -new Complex(1.0, 0.0) / a[k - 1 + (k - 1) * lda];
            BLAS1Z.zscal(n - k, t, ref a, 1, index: +k + (k - 1) * lda);
            //
            //  Row elimination with column indexing
            //
            int j;
            for (j = k + 1; j <= n; j++)
            {
                t = a[l - 1 + (j - 1) * lda];
                if (l != k)
                {
                    a[l - 1 + (j - 1) * lda] = a[k - 1 + (j - 1) * lda];
                    a[k - 1 + (j - 1) * lda] = t;
                }

                BLAS1Z.zaxpy(n - k, t, a, 1, ref a, 1, xIndex: +k + (k - 1) * lda, yIndex: +k + (j - 1) * lda);
            }
        }

        ipvt[n - 1] = n;

        if (typeMethods.zabs1(a[n - 1 + (n - 1) * lda]) == 0.0)
        {
            info = n;
        }

        return(info);
    }
예제 #17
0
    public static double zpbco(ref Complex[] abd, int lda, int n, int m, ref int info)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZPBCO factors a Complex hermitian positive definite band matrix.
    //
    //  Discussion:
    //
    //    The routine also estimates the condition number of the matrix.
    //
    //    If RCOND is not needed, ZPBFA is slightly faster.
    //
    //    To solve A*X = B, follow ZPBCO by ZPBSL.
    //
    //    To compute inverse(A)*C, follow ZPBCO by ZPBSL.
    //
    //    To compute determinant(A), follow ZPBCO by ZPBDI.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex ABD[LDA*N]; on input, the matrix to be factored.
    //    The columns of the upper triangle are stored in the columns of ABD,
    //    and the diagonals of the upper triangle are stored in the rows of ABD.
    //    On output, an upper triangular matrix R, stored in band form, so that
    //    A = hermitian(R) * R.  If INFO != 0, the factorization is not complete.
    //
    //    Input, int LDA, the leading dimension of ABD.
    //    LDA must be at least M+1.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int M, the number of diagonals above the main diagonal.
    //    0 <= M < N.
    //
    //    Output, double ZPBCO, an estimate of RCOND, the reciprocal condition of
    //    the matrix.  For the system A*X = B, relative perturbations in A and B
    //    of size EPSILON may cause relative perturbations in X of size
    //    (EPSILON/RCOND).  If RCOND is so small that the logical expression
    //      1.0 + RCOND == 1.0
    //    is true, then A may be singular to working precision.  In particular,
    //    RCOND is zero if exact singularity is detected or the estimate underflows.
    //
    //    Output, int *INFO.
    //    0, for normal return.
    //    K, signals an error condition.  The leading minor of order K is not
    //    positive definite.
    //
    //  Local Parameter:
    //
    //    Workspace, Complex Z[N], a work vector whose contents are usually
    //    unimportant.  If A is singular to working precision, then Z is
    //    an approximate null vector in the sense that
    //    norm ( A * Z ) = RCOND * norm ( A ) * norm ( Z ).
    //    If INFO != 0, Z is unchanged.
    //
    {
        int     i;
        int     j;
        int     k;
        int     la;
        int     lb;
        int     lm;
        double  rcond;
        double  s;
        Complex t;

        //
        //  Find the norm of A.
        //
        Complex[] z = new Complex [n];

        for (j = 1; j <= n; j++)
        {
            int l  = Math.Min(j, m + 1);
            int mu = Math.Max(m + 2 - j, 1);
            z[j - 1] = new Complex(BLAS1Z.dzasum(l, abd, 1, index: +mu - 1 + (j - 1) * lda), 0.0);
            k        = j - l;

            for (i = mu; i <= m; i++)
            {
                k       += 1;
                z[k - 1] = new Complex(z[k - 1].Real
                                       + typeMethods.zabs1(abd[i - 1 + (j - 1) * lda]), 0.0);
            }
        }

        double anorm = 0.0;

        for (j = 0; j < n; j++)
        {
            anorm = Math.Max(anorm, z[j].Real);
        }

        //
        //  Factor.
        //
        info = ZPBFA.zpbfa(ref abd, lda, n, m);

        if (info != 0)
        {
            rcond = 0.0;
            return(rcond);
        }

        //
        //  RCOND = 1/(norm(A)*(estimate of norm(inverse(A)))).
        //
        //  Estimate = norm(Z)/norm(Y) where A*Z = Y and A*Y = E.
        //
        //  The components of E are chosen to cause maximum local
        //  growth in the elements of W where hermitian(R)*W = E.
        //
        //  The vectors are frequently rescaled to avoid overflow.
        //
        //  Solve hermitian(R)*W = E.
        //
        Complex ek = new(1.0, 0.0);

        for (i = 0; i < n; i++)
        {
            z[i] = new Complex(0.0, 0.0);
        }

        for (k = 1; k <= n; k++)
        {
            if (typeMethods.zabs1(z[k - 1]) != 0.0)
            {
                ek = typeMethods.zsign1(ek, -z[k - 1]);
            }

            if (abd[m + (k - 1) * lda].Real < typeMethods.zabs1(ek - z[k - 1]))
            {
                s = abd[m + (k - 1) * lda].Real / typeMethods.zabs1(ek - z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ek = new Complex(s, 0.0) * ek;
            }

            Complex wk  = ek - z[k - 1];
            Complex wkm = -ek - z[k - 1];
            s = typeMethods.zabs1(wk);
            double sm = typeMethods.zabs1(wkm);
            wk  /= abd[m + (k - 1) * lda];
            wkm /= abd[m + (k - 1) * lda];
            int j2 = Math.Min(k + m, n);
            i = m + 1;

            if (k + 1 <= j2)
            {
                for (j = k + 1; j <= j2; j++)
                {
                    i        -= 1;
                    sm       += typeMethods.zabs1(z[j - 1] + wkm * Complex.Conjugate(abd[i - 1 + (j - 1) * lda]));
                    z[j - 1] += wk * Complex.Conjugate(abd[i - 1 + (j - 1) * lda]);
                    s        += typeMethods.zabs1(z[j - 1]);
                }

                if (s < sm)
                {
                    t  = wkm - wk;
                    wk = wkm;
                    i  = m + 1;
                    for (j = k + 1; j <= j2; j++)
                    {
                        i        -= 1;
                        z[j - 1] += t * Complex.Conjugate(abd[i - 1 + (j - 1) * lda]);
                    }
                }
            }

            z[k - 1] = wk;
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        //
        //  Solve R * Y = W.
        //
        for (k = n; 1 <= k; k--)
        {
            if (abd[m + (k - 1) * lda].Real < typeMethods.zabs1(z[k - 1]))
            {
                s = abd[m + (k - 1) * lda].Real / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
            }

            z[k - 1] /= abd[m + (k - 1) * lda];
            lm        = Math.Min(k - 1, m);
            la        = m + 1 - lm;
            lb        = k - lm;
            t         = -z[k - 1];
            BLAS1Z.zaxpy(lm, t, abd, 1, ref z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1);
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        double ynorm = 1.0;

        //
        //  Solve hermitian(R)*V = Y.
        //
        for (k = 1; k <= n; k++)
        {
            lm        = Math.Min(k - 1, m);
            la        = m + 1 - lm;
            lb        = k - lm;
            z[k - 1] -= BLAS1Z.zdotc(lm, abd, 1, z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1);

            if (abd[m + (k - 1) * lda].Real < typeMethods.zabs1(z[k - 1]))
            {
                s = abd[m + (k - 1) * lda].Real / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ynorm = s * ynorm;
            }

            z[k - 1] /= abd[m + (k - 1) * lda];
        }

        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;
        //
        //  Solve R * Z = W.
        //
        for (k = n; 1 <= k; k--)
        {
            if (abd[m + (k - 1) * lda].Real < typeMethods.zabs1(z[k - 1]))
            {
                s = abd[m + (k - 1) * lda].Real / typeMethods.zabs1(z[k - 1]);
                BLAS1Z.zdscal(n, s, ref z, 1);
                ynorm = s * ynorm;
            }

            z[k - 1] /= abd[m + (k - 1) * lda];
            lm        = Math.Min(k - 1, m);
            la        = m + 1 - lm;
            lb        = k - lm;
            t         = -z[k - 1];
            BLAS1Z.zaxpy(lm, t, abd, 1, ref z, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1);
        }

        //
        //  Make ZNORM = 1.
        //
        s = 1.0 / BLAS1Z.dzasum(n, z, 1);
        BLAS1Z.zdscal(n, s, ref z, 1);
        ynorm = s * ynorm;

        if (anorm != 0.0)
        {
            rcond = ynorm / anorm;
        }
        else
        {
            rcond = 0.0;
        }

        return(rcond);
    }
예제 #18
0
    public static int zqrsl(Complex[] x, int ldx, int n, int k,
                            Complex[] qraux, Complex[] y, ref Complex[] qy,
                            ref Complex[] qty, ref Complex[] b, ref Complex[] rsd,
                            ref Complex[] xb, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZQRSL solves, transforms or projects systems factored by ZQRDC.
    //
    //  Discussion:
    //
    //    The routine applies the output of ZQRDC to compute coordinate
    //    transformations, projections, and least squares solutions.
    //
    //    For K <= min ( N, P ), let XK be the matrix
    //
    //      XK = ( X(IPVT(1)), X(IPVT(2)), ... ,X(IPVT(k)) )
    //
    //    formed from columnns IPVT(1), ... ,IPVT(K) of the original
    //    N by P matrix X that was input to ZQRDC (if no pivoting was
    //    done, XK consists of the first K columns of X in their
    //    original order).  ZQRDC produces a factored unitary matrix Q
    //    and an upper triangular matrix R such that
    //
    //      XK = Q * ( R )
    //               ( 0 )
    //
    //    This information is contained in coded form in the arrays
    //    X and QRAUX.
    //
    //    The parameters QY, QTY, B, RSD, and XB are not referenced
    //    if their computation is not requested and in this case
    //    can be replaced by dummy variables in the calling program.
    //
    //    To save storage, the user may in some cases use the same
    //    array for different parameters in the calling sequence.  A
    //    frequently occuring example is when one wishes to compute
    //    any of B, RSD, or XB and does not need Y or QTY.  In this
    //    case one may identify Y, QTY, and one of B, RSD, or XB, while
    //    providing separate arrays for anything else that is to be
    //    computed.  Thus the calling sequence
    //
    //      zqrsl ( x, ldx, n, k, qraux, y, dum, y, b, y, dum, 110, info )
    //
    //    will result in the computation of B and RSD, with RSD
    //    overwriting Y.  More generally, each item in the following
    //    list contains groups of permissible identifications for
    //    a single callinng sequence.
    //
    //    1. ( Y, QTY, B )   ( RSD )      ( XB )  ( QY )
    //    2. ( Y, QTY, RSD ) ( B )        ( XB )  ( QY )
    //    3. ( Y, QTY, XB )  ( B )        ( RSD ) ( QY )
    //    4. ( Y, QY )       ( QTY, B )   ( RSD ) ( XB )
    //    5. ( Y, QY )       ( QTY, RSD ) ( B )   ( XB )
    //    6. ( Y, QY )       ( QTY, XB )  ( B )   ( RSD )
    //
    //    In any group the value returned in the array allocated to
    //    the group corresponds to the last member of the group.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex X[LDX*P], the output of ZQRDC.
    //
    //    Input, int LDX, the leading dimension of X.
    //
    //    Input, int N, the number of rows of the matrix XK, which
    //    must have the same value as N in ZQRDC.
    //
    //    Input, int K, the number of columns of the matrix XK.  K must not
    //    be greater than min ( N, P), where P is the same as in the calling
    //    sequence to ZQRDC.
    //
    //    Input, Complex QRAUX[P], the auxiliary output from ZQRDC.
    //
    //    Input, Complex Y[N], a vector that is to be manipulated by ZQRSL.
    //
    //    Output, Complex QY[N], contains Q*Y, if it has been requested.
    //
    //    Output, Complex QTY[N], contains hermitian(Q)*Y, if it has
    //    been requested.  Here hermitian(Q) is the conjugate transpose
    //    of the matrix Q.
    //
    //    Output, Complex B[K], the solution of the least squares problem
    //      minimize norm2 ( Y - XK * B ),
    //    if it has been requested.  If pivoting was requested in ZQRDC,
    //    the J-th component of B will be associated with column IPVT(J)
    //    of the original matrix X that was input into ZQRDC.
    //
    //    Output, Complex RSD[N], the least squares residual Y - XK*B,
    //    if it has been requested.  RSD is also the orthogonal projection
    //    of Y onto the orthogonal complement of the column space of XK.
    //
    //    Output, Complex XB[N], the least squares approximation XK*N,
    //    if its computation has been requested.  XB is also the orthogonal
    //    projection of Y onto the column space of X.
    //
    //    Input, int JOB, specifies what is to be computed.  JOB has
    //    the decimal expansion ABCDE, meaning:
    //    if A != 0, compute QY.
    //    if B, D, D, or E != 0, compute QTY.
    //    if C != 0, compute B.
    //    if D != 0, compute RSD.
    //    if E != 0, compute XB.
    //    A request to compute B, RSD, or XB automatically triggers the
    //    computation of QTY, for which an array must be provided in the
    //    calling sequence.
    //
    //    Output, int ZQRSL, the value of INFO, which is zero unless
    //    the computation of B has been requested and R is exactly singular.
    //    In this case, INFO is the index of the first zero diagonal element
    //    of R and B is left unaltered.
    //
    {
        int     i;
        int     j;
        int     jj;
        Complex t;
        Complex temp;

        int info = 0;
        //
        //  Determine what is to be computed.
        //
        bool cqy  = job / 10000 != 0;
        bool cqty = job % 10000 != 0;
        bool cb   = job % 1000 / 100 != 0;
        bool cr   = job % 100 / 10 != 0;
        bool cxb  = job % 10 != 0;

        int ju = Math.Min(k, n - 1);

        switch (ju)
        {
        //
        //  Special action when N=1.
        //
        case 0:
        {
            qy[0] = cqy switch
            {
                true => y[0],
                _ => qy[0]
            };

            qty[0] = cqty switch
            {
                true => y[0],
                _ => qty[0]
            };

            xb[0] = cxb switch
            {
                true => y[0],
                _ => xb[0]
            };

            switch (cb)
            {
            case true when typeMethods.zabs1(x[0 + 0 * ldx]) == 0.0:
                info = 1;

                break;

            case true:
                b[0] = y[0] / x[0 + 0 * ldx];
                break;
            }

            rsd[0] = cr switch
            {
                true => new Complex(0.0, 0.0),
                _ => rsd[0]
            };

            return(info);
        }
        }

        switch (cqy)
        {
        //
        //  Set up to compute QY or QTY.
        //
        case true:
        {
            for (i = 0; i < n; i++)
            {
                qy[i] = y[i];
            }

            break;
        }
        }

        switch (cqty)
        {
        case true:
        {
            for (i = 0; i < n; i++)
            {
                qty[i] = y[i];
            }

            break;
        }
        }

        switch (cqy)
        {
        //
        //  Compute QY.
        //
        case true:
        {
            for (jj = 1; jj <= ju; jj++)
            {
                j = ju - jj + 1;

                if (typeMethods.zabs1(qraux[j - 1]) == 0.0)
                {
                    continue;
                }

                temp = x[j - 1 + (j - 1) * ldx];
                x[j - 1 + (j - 1) * ldx] = qraux[j - 1];
                t = -BLAS1Z.zdotc(n - j + 1, x, 1, qy, 1, xIndex: +j - 1 + (j - 1) * ldx, yIndex: +j - 1) /
                    x[j - 1 + (j - 1) * ldx];
                BLAS1Z.zaxpy(n - j + 1, t, x, 1, ref qy, 1, xIndex: +j - 1 + (j - 1) * ldx, yIndex: +j - 1);
                x[j - 1 + (j - 1) * ldx] = temp;
            }

            break;
        }
        }

        switch (cqty)
        {
        //
        //  Compute hermitian ( A ) * Y.
        //
        case true:
        {
            for (j = 1; j <= ju; j++)
            {
                if (typeMethods.zabs1(qraux[j - 1]) == 0.0)
                {
                    continue;
                }

                temp = x[j - 1 + (j - 1) * ldx];
                x[j - 1 + (j - 1) * ldx] = qraux[j - 1];
                t = -BLAS1Z.zdotc(n - j + 1, x, 1, qty, 1, xIndex: +j - 1 + (j - 1) * ldx, yIndex: +j - 1) /
                    x[j - 1 + (j - 1) * ldx];
                BLAS1Z.zaxpy(n - j + 1, t, x, 1, ref qty, 1, xIndex: +j - 1 + (j - 1) * ldx, yIndex: +j - 1);
                x[j - 1 + (j - 1) * ldx] = temp;
            }

            break;
        }
        }

        switch (cb)
        {
        //
        //  Set up to compute B, RSD, or XB.
        //
        case true:
        {
            for (i = 0; i < k; i++)
            {
                b[i] = qty[i];
            }

            break;
        }
        }

        switch (cxb)
        {
        case true:
        {
            for (i = 0; i < k; i++)
            {
                xb[i] = qty[i];
            }

            break;
        }
        }

        switch (cr)
        {
        case true when k < n:
        {
            for (i = k; i < n; i++)
            {
                rsd[i] = qty[i];
            }

            break;
        }
        }

        switch (cxb)
        {
        case true:
        {
            for (i = k; i < n; i++)
            {
                xb[i] = new Complex(0.0, 0.0);
            }

            break;
        }
        }

        switch (cr)
        {
        case true:
        {
            for (i = 0; i < k; i++)
            {
                rsd[i] = new Complex(0.0, 0.0);
            }

            break;
        }
        }

        switch (cb)
        {
        //
        //  Compute B.
        //
        case true:
        {
            for (jj = 1; jj <= k; jj++)
            {
                j = k - jj + 1;

                if (typeMethods.zabs1(x[j - 1 + (j - 1) * ldx]) == 0.0)
                {
                    info = j;
                    break;
                }

                b[j - 1] /= x[j - 1 + (j - 1) * ldx];

                if (j == 1)
                {
                    continue;
                }

                t = -b[j - 1];
                BLAS1Z.zaxpy(j - 1, t, x, 1, ref b, 1, xIndex: +0 + (j - 1) * ldx);
            }

            break;
        }
        }

        if (!cr && !cxb)
        {
            return(info);
        }

        //
        //  Compute RSD or XB as required.
        //
        for (jj = 1; jj <= ju; jj++)
        {
            j = ju - jj + 1;

            if (typeMethods.zabs1(qraux[j - 1]) == 0.0)
            {
                continue;
            }

            temp = x[j - 1 + (j - 1) * ldx];
            x[j - 1 + (j - 1) * ldx] = qraux[j - 1];

            switch (cr)
            {
            case true:
                t = -BLAS1Z.zdotc(n - j + 1, x, 1, rsd, 1, xIndex: +j - 1 + (j - 1) * ldx, yIndex: +j - 1)
                    / x[j - 1 + (j - 1) * ldx];
                BLAS1Z.zaxpy(n - j + 1, t, x, 1, ref rsd, 1, xIndex: +j - 1 + (j - 1) * ldx,
                             yIndex: +j - 1);
                break;
            }

            switch (cxb)
            {
            case true:
                t = -BLAS1Z.zdotc(n - j + 1, x, 1, xb, 1, xIndex: +j - 1 + (j - 1) * ldx, yIndex: +j - 1)
                    / x[j - 1 + (j - 1) * ldx];
                BLAS1Z.zaxpy(n - j + 1, t, x, 1, ref xb, 1, xIndex: +j - 1 + (j - 1) * ldx, yIndex: +j - 1);
                break;
            }

            x[j - 1 + (j - 1) * ldx] = temp;
        }

        return(info);
    }
}
예제 #19
0
    public static void zsisl(Complex[] a, int lda, int n, int[] ipvt,
                             ref Complex[] b)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZSISL solves a complex symmetric system that was factored by ZSIFA.
    //
    //  Discussion:
    //
    //    A division by zero may occur if ZSICO has set RCOND == 0.0
    //    or ZSIFA has set INFO != 0.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex A[LDA*N], the output from ZSICO or ZSIFA.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int IPVT[N], the pivot vector from ZSICO or ZSIFA.
    //
    //    Input/output, Complex B[N].  On input, the right hand side.
    //    On output, the solution.
    //
    {
        int     kp;
        Complex t;
        //
        //  Loop backward applying the transformations and D inverse to B.
        //
        int k = n;

        while (0 < k)
        {
            switch (ipvt[k - 1])
            {
            //
            //  1 x 1 pivot block.
            //
            case >= 0:
            {
                if (k != 1)
                {
                    kp = ipvt[k - 1];

                    if (kp != k)
                    {
                        t         = b[k - 1];
                        b[k - 1]  = b[kp - 1];
                        b[kp - 1] = t;
                    }

                    BLAS1Z.zaxpy(k - 1, b[k - 1], a, 1, ref b, 1, xIndex: +0 + (k - 1) * lda);
                }

                b[k - 1] /= a[k - 1 + (k - 1) * lda];
                k        -= 1;
                break;
            }

            //
            default:
            {
                if (k != 2)
                {
                    kp = Math.Abs(ipvt[k - 1]);

                    if (kp != k - 1)
                    {
                        t         = b[k - 2];
                        b[k - 2]  = b[kp - 1];
                        b[kp - 1] = t;
                    }

                    BLAS1Z.zaxpy(k - 2, b[k - 1], a, 1, ref b, 1, xIndex: +0 + (k - 1) * lda);
                    BLAS1Z.zaxpy(k - 2, b[k - 2], a, 1, ref b, 1, xIndex: +0 + (k - 2) * lda);
                }

                Complex ak    = a[k - 1 + (k - 1) * lda] / a[k - 2 + (k - 1) * lda];
                Complex akm1  = a[k - 2 + (k - 2) * lda] / a[k - 2 + (k - 1) * lda];
                Complex bk    = b[k - 1] / a[k - 2 + (k - 1) * lda];
                Complex bkm1  = b[k - 2] / a[k - 2 + (k - 1) * lda];
                Complex denom = ak * akm1 - new Complex(1.0, 0.0);
                b[k - 1] = (akm1 * bk - bkm1) / denom;
                b[k - 2] = (ak * bkm1 - bk) / denom;
                k       -= 2;
                break;
            }
            }
        }

        //
        //  Loop forward applying the transformations.
        //
        k = 1;

        while (k <= n)
        {
            switch (ipvt[k - 1])
            {
            case >= 0:
            {
                //
                //  1 x 1 pivot block.
                //
                if (k != 1)
                {
                    b[k - 1] += BLAS1Z.zdotu(k - 1, a, 1, b, 1, xIndex: +0 + (k - 1) * lda);
                    kp        = ipvt[k - 1];

                    if (kp != k)
                    {
                        t         = b[k - 1];
                        b[k - 1]  = b[kp - 1];
                        b[kp - 1] = t;
                    }
                }

                k += 1;
                break;
            }

            //
            default:
            {
                if (k != 1)
                {
                    b[k - 1] += BLAS1Z.zdotu(k - 1, a, 1, b, 1, xIndex: +0 + (k - 1) * lda);
                    b[k]     += BLAS1Z.zdotu(k - 1, a, 1, b, 1, xIndex: +0 + k * lda);
                    kp        = Math.Abs(ipvt[k - 1]);

                    if (kp != k)
                    {
                        t         = b[k - 1];
                        b[k - 1]  = b[kp - 1];
                        b[kp - 1] = t;
                    }
                }

                k += 2;
                break;
            }
            }
        }
    }
예제 #20
0
    public static void zsidi(ref Complex[] a, int lda, int n, int[] ipvt,
                             ref Complex[] det, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZSIDI computes the determinant and inverse of a matrix factored by ZSIFA.
    //
    //  Discussion:
    //
    //    It is assumed the complex symmetric matrix has already been factored
    //    by ZSIFA.
    //
    //    A division by zero may occur if the inverse is requested
    //    and ZSICO set RCOND == 0.0 or ZSIFA set INFO nonzero.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex A[LDA*N]; on input, the output from ZSIFA.
    //    If the inverse was requested, then on output, A contains the upper triangle
    //    of the inverse of the original matrix.  The strict lower triangle
    //    is never referenced.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int IPVT[N], the pivot vector from ZSIFA.
    //
    //    Output, Complex DET[2], if requested, the determinant of the matrix.
    //    Determinant = DET(1) * 10.0**DET(2) with 1.0 <= abs ( DET(1) ) < 10.0
    //    or DET(1) = 0.0.  Also, DET(2) is strictly real.
    //
    //    Input, int JOB, has the decimal expansion AB where
    //    if B != 0, the inverse is computed,
    //    if A != 0, the determinant is computed,
    //    For example, JOB = 11 gives both.
    //
    {
        Complex d;
        int     k;
        Complex t;

        bool noinv = job % 10 == 0;
        bool nodet = job % 100 / 10 == 0;

        switch (nodet)
        {
        case false:
        {
            det[0] = new Complex(1.0, 0.0);
            det[1] = new Complex(0.0, 0.0);
            t      = new Complex(0.0, 0.0);

            for (k = 1; k <= n; k++)
            {
                d = a[k - 1 + (k - 1) * lda];
                switch (ipvt[k - 1])
                {
                //
                //   2 by 2 block.
                //   Use det ( D  T ) = ( D / T * C - T ) * T
                //           ( T  C )
                //   to avoid underflow/overflow troubles.
                //   Take two passes through scaling.  Use T for flag.
                //
                case <= 0 when typeMethods.zabs1(t) == 0.0:
                    t = a[k - 1 + k * lda];

                    d = d / t * a[k + k * lda] - t;
                    break;

                case <= 0:
                    d = t;
                    t = new Complex(0.0, 0.0);
                    break;
                }

                det[0] *= d;

                if (typeMethods.zabs1(det[0]) == 0.0)
                {
                    continue;
                }

                while (typeMethods.zabs1(det[0]) < 1.0)
                {
                    det[0] *= new Complex(10.0, 0.0);
                    det[1] -= new Complex(1.0, 0.0);
                }

                while (10.0 <= typeMethods.zabs1(det[0]))
                {
                    det[0] /= new Complex(10.0, 0.0);
                    det[1] += new Complex(1.0, 0.0);
                }
            }

            break;
        }
        }

        switch (noinv)
        {
        //
        //  Compute inverse ( A ).
        //
        case false:
        {
            Complex[] work = new Complex [n];

            k = 1;

            while (k <= n)
            {
                int km1 = k - 1;
                int kstep;
                int j;
                int i;
                switch (ipvt[k - 1])
                {
                //
                //  1 by 1
                //
                case >= 0:
                {
                    a[k - 1 + (k - 1) * lda] = new Complex(1.0, 0.0) / a[k - 1 + (k - 1) * lda];

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = a[i - 1 + (k - 1) * lda];
                        }

                        for (j = 1; j <= km1; j++)
                        {
                            a[j - 1 + (k - 1) * lda] = BLAS1Z.zdotu(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda,
                                         yIndex: +0 + (k - 1) * lda);
                        }

                        a[k - 1 + (k - 1) * lda] += BLAS1Z.zdotu(km1, work, 1, a, 1, yIndex: +0 + (k - 1) * lda);
                        break;
                    }
                    }

                    kstep = 1;
                    break;
                }

                //
                default:
                {
                    t = a[k - 1 + k * lda];
                    Complex ak    = a[k - 1 + (k - 1) * lda] / t;
                    Complex akp1  = a[k + k * lda] / t;
                    Complex akkp1 = a[k - 1 + k * lda] / t;
                    d = t * (ak * akp1 - new Complex(1.0, 0.0));
                    a[k - 1 + (k - 1) * lda] = akp1 / d;
                    a[k + k * lda]           = ak / d;
                    a[k - 1 + k * lda]       = -akkp1 / d;

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = a[i - 1 + k * lda];
                        }

                        for (j = 1; j <= km1; j++)
                        {
                            a[j - 1 + k * lda] = BLAS1Z.zdotu(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda,
                                         yIndex: +0 + k * lda);
                        }

                        a[k + k * lda]     += BLAS1Z.zdotu(km1, work, 1, a, 1, yIndex: +0 + k * lda);
                        a[k - 1 + k * lda] += BLAS1Z.zdotu(km1, a, 1, a, 1, xIndex: +0 + (k - 1) * lda,
                                                           yIndex: +0 + k * lda);

                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = a[i - 1 + (k - 1) * lda];
                        }

                        for (j = 1; j <= km1; j++)
                        {
                            a[j - 1 + (k - 1) * lda] = BLAS1Z.zdotu(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda,
                                         yIndex: +0 + (k - 1) * lda);
                        }

                        a[k - 1 + (k - 1) * lda] += BLAS1Z.zdotu(km1, work, 1, a, 1, yIndex: +0 + (k - 1) * lda);
                        break;
                    }
                    }

                    kstep = 2;
                    break;
                }
                }

                //
                //  Swap.
                //
                int ks = Math.Abs(ipvt[k - 1]);

                if (ks != k)
                {
                    BLAS1Z.zswap(ks, ref a, 1, ref a, 1, xIndex: +0 + (ks - 1) * lda, yIndex: +0 + (k - 1) * lda);

                    int jb;
                    for (jb = ks; jb <= k; jb++)
                    {
                        j = k + ks - jb;

                        t = a[j - 1 + (k - 1) * lda];
                        a[j - 1 + (k - 1) * lda]  = a[ks - 1 + (j - 1) * lda];
                        a[ks - 1 + (j - 1) * lda] = t;
                    }

                    if (kstep != 1)
                    {
                        t = a[ks - 1 + k * lda];
                        a[ks - 1 + k * lda] = a[k - 1 + k * lda];
                        a[k - 1 + k * lda]  = t;
                    }
                }

                k += kstep;
            }

            break;
        }
        }
    }
예제 #21
0
    public static void zppdi(ref Complex[] ap, int n, ref double[] det, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZPPDI: determinant, inverse of a complex hermitian positive definite matrix.
    //
    //  Discussion:
    //
    //    The matrix is assumed to have been factored by ZPPCO or ZPPFA.
    //
    //    A division by zero will occur if the input factor contains
    //    a zero on the diagonal and the inverse is requested.
    //    It will not occur if the subroutines are called correctly
    //    and if ZPOCO or ZPOFA has set INFO == 0.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, complex <double> A[(N*(N+1))/2]; on input, the output from ZPPCO
    //    or ZPPFA.  On output, the upper triangular half of the inverse.
    //    The strict lower triangle is unaltered.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Output, double DET[2], the determinant of original matrix if requested.
    //    Otherwise not referenced.  Determinant = DET(1) * 10.0**DET(2)
    //    with 1.0 <= DET(1) < 10.0 or DET(1) == 0.0.
    //
    //    Input, int JOB.
    //    11, both determinant and inverse.
    //    01, inverse only.
    //    10, determinant only.
    //
    {
        //
        //  Compute determinant.
        //
        if (job / 10 != 0)
        {
            det[0] = 1.0;
            det[1] = 0.0;
            int ii = 0;

            int i;
            for (i = 1; i <= n; i++)
            {
                ii    += i;
                det[0] = det[0] * ap[ii - 1].Real * ap[ii - 1].Real;

                if (det[0] == 0.0)
                {
                    break;
                }

                while (det[0] < 1.0)
                {
                    det[0] *= 10.0;
                    det[1] -= 1.0;
                }

                while (10.0 <= det[0])
                {
                    det[0] /= 10.0;
                    det[1] += 1.0;
                }
            }
        }

        //
        //  Compute inverse ( R ).
        //
        if (job % 10 == 0)
        {
            return;
        }

        int kk = 0;

        int     k1;
        int     kj;
        int     k;
        Complex t;
        int     j;
        int     j1;

        for (k = 1; k <= n; k++)
        {
            k1         = kk + 1;
            kk        += k;
            ap[kk - 1] = new Complex(1.0, 0.0) / ap[kk - 1];
            t          = -ap[kk - 1];
            BLAS1Z.zscal(k - 1, t, ref ap, 1, index: +k1 - 1);
            int kp1 = k + 1;
            j1 = kk + 1;
            kj = kk + k;

            for (j = kp1; j <= n; j++)
            {
                t          = ap[kj - 1];
                ap[kj - 1] = new Complex(0.0, 0.0);
                BLAS1Z.zaxpy(k, t, ap, 1, ref ap, 1, xIndex: +k1 - 1, yIndex: +j1 - 1);
                j1 += j;
                kj += j;
            }
        }

        //
        //  Form inverse ( R ) * hermitian ( inverse ( R ) ).
        //
        int jj = 0;

        for (j = 1; j <= n; j++)
        {
            j1  = jj + 1;
            jj += j;
            k1  = 1;
            kj  = j1;

            for (k = 1; k <= j - 1; k++)
            {
                t = Complex.Conjugate(ap[kj - 1]);
                BLAS1Z.zaxpy(k, t, ap, 1, ref ap, 1, xIndex: +j1 - 1, yIndex: k1 - 1);
                k1 += k;
                kj += 1;
            }

            t = Complex.Conjugate(ap[jj - 1]);
            BLAS1Z.zscal(j, t, ref ap, 1, index: +j1 - 1);
        }
    }
예제 #22
0
    public static void zhidi(ref Complex[] a, int lda, int n, int[] ipvt, ref double[] det,
                             ref int[] inert, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZHIDI computes the determinant and inverse of a matrix factored by ZHIFA.
    //
    //  Discussion:
    //
    //    ZHIDI computes the determinant, inertia (number of positive, zero,
    //    and negative eigenvalues) and inverse of a complex hermitian matrix
    //    using the factors from ZHIFA.
    //
    //    A division by zero may occur if the inverse is requested
    //    and ZHICO has set RCOND == 0.0 or ZHIFA has set INFO /= 0.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex A[LDA*N]; on input, the factored matrix
    //    from ZHIFA.  On output, if the inverse was requested, A contains
    //    the inverse matrix.  The strict lower triangle of A is never
    //    referenced.
    //
    //    Input, int LDA, the leading dimension of A.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int IPVT[N], the pivot vector from ZHIFA.
    //
    //    Output, double DET[2], the determinant of the original matrix.
    //    Determinant = det[0] * 10.0**det[1] with 1.0 <= Math.Abs ( det[0] ) < 10.0
    //    or det[0] = 0.0.
    //
    //    Output, int INERT[3], the inertia of the original matrix.
    //    INERT(1) = number of positive eigenvalues.
    //    INERT(2) = number of negative eigenvalues.
    //    INERT(3) = number of zero eigenvalues.
    //
    //    Input, int JOB, has the decimal expansion ABC where:
    //    if C /= 0, the inverse is computed,
    //    if B /= 0, the determinant is computed,
    //    if A /= 0, the inertia is computed.
    //    For example, JOB = 111 gives all three.
    //
    {
        double d;
        int    i;
        int    k;
        double t;

        bool noinv = job % 10 == 0;
        bool nodet = job % 100 / 10 == 0;
        bool noert = job % 1000 / 100 == 0;

        if (!nodet || !noert)
        {
            switch (noert)
            {
            case false:
            {
                for (i = 0; i < 3; i++)
                {
                    inert[i] = 0;
                }

                break;
            }
            }

            switch (nodet)
            {
            case false:
                det[0] = 1.0;
                det[1] = 0.0;
                break;
            }

            t = 0.0;

            for (k = 0; k < n; k++)
            {
                d = a[k + k * lda].Real;
                switch (ipvt[k])
                {
                //
                //  Check if 1 by 1.
                //
                //
                //  2 by 2 block
                //  Use DET = ( D / T * C - T ) * T, T = Math.Abs ( S )
                //  to avoid underflow/overflow troubles.
                //  Take two passes through scaling.  Use T for flag.
                //
                case <= 0 when t == 0.0:
                    t = Complex.Abs(a[k + (k + 1) * lda]);
                    d = d / t * a[k + 1 + (k + 1) * lda].Real - t;
                    break;

                case <= 0:
                    d = t;
                    t = 0.0;
                    break;
                }

                switch (noert)
                {
                case false:
                    switch (d)
                    {
                    case > 0.0:
                        inert[0] += 1;
                        break;

                    case < 0.0:
                        inert[1] += 1;
                        break;

                    case 0.0:
                        inert[2] += 1;
                        break;
                    }

                    break;
                }

                switch (nodet)
                {
                case false:
                {
                    det[0] *= d;

                    if (det[0] != 0.0)
                    {
                        while (Math.Abs(det[0]) < 1.0)
                        {
                            det[0] *= 10.0;
                            det[1] -= 1.0;
                        }

                        while (10.0 <= Math.Abs(det[0]))
                        {
                            det[0] /= 10.0;
                            det[1] += 1.0;
                        }
                    }

                    break;
                }
                }
            }
        }

        switch (noinv)
        {
        //
        //  Compute inverse(A).
        //
        case false:
        {
            Complex[] work = new Complex [n];

            k = 1;

            while (k <= n)
            {
                int km1 = k - 1;

                int kstep;
                int j;
                switch (ipvt[k - 1])
                {
                case >= 0:
                {
                    //
                    //  1 by 1
                    //
                    a[k - 1 + (k - 1) * lda] =
                        new Complex(1.0 / a[k - 1 + (k - 1) * lda].Real, 0.0);

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = a[i - 1 + (k - 1) * lda];
                        }

                        for (j = 1; j <= km1; j++)
                        {
                            a[j - 1 + (k - 1) * lda] = BLAS1Z.zdotc(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda,
                                         yIndex: +0 + (k - 1) * lda);
                        }

                        a[k - 1 + (k - 1) * lda] += new Complex(
                            BLAS1Z.zdotc(km1, work, 1, a, 1, yIndex: +0 + (k - 1) * lda).Real, 0.0);
                        break;
                    }
                    }

                    kstep = 1;
                    break;
                }

                default:
                {
                    //
                    //  2 by 2
                    //
                    t = Complex.Abs(a[k - 1 + k * lda]);
                    double  ak    = a[k - 1 + (k - 1) * lda].Real / t;
                    double  akp1  = a[k + k * lda].Real / t;
                    Complex akkp1 = a[k - 1 + k * lda] / t;
                    d = t * (ak * akp1 - 1.0);
                    a[k - 1 + (k - 1) * lda] = new Complex(akp1 / d, 0.0);
                    a[k + k * lda]           = new Complex(ak / d, 0.0);
                    a[k - 1 + k * lda]       = -akkp1 / d;

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = a[i - 1 + k * lda];
                        }

                        for (j = 1; j <= km1; j++)
                        {
                            a[j - 1 + k * lda] = BLAS1Z.zdotc(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda,
                                         yIndex: +0 + k * lda);
                        }

                        a[k + k * lda] += new Complex(
                            BLAS1Z.zdotc(km1, work, 1, a, 1, yIndex: +0 + k * lda).Real, 0.0);

                        a[k - 1 + k * lda] += BLAS1Z.zdotc(km1, a, 1, a, 1, xIndex: +0 + (k - 1) * lda,
                                                           yIndex: +0 + k * lda);

                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = a[i - 1 + (k - 1) * lda];
                        }

                        for (j = 1; j <= km1; j++)
                        {
                            a[j - 1 + (k - 1) * lda] = BLAS1Z.zdotc(j, a, 1, work, 1, xIndex: +0 + (j - 1) * lda);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], a, 1, ref a, 1, xIndex: +0 + (j - 1) * lda,
                                         yIndex: +0 + (k - 1) * lda);
                        }

                        a[k - 1 + (k - 1) * lda] += new Complex(
                            BLAS1Z.zdotc(km1, work, 1, a, 1, yIndex: +0 + (k - 1) * lda).Real, 0.0);
                        break;
                    }
                    }

                    kstep = 2;
                    break;
                }
                }

                //
                //  Swap
                //
                int ks = Math.Abs(ipvt[k - 1]);

                if (ks != k)
                {
                    BLAS1Z.zswap(ks, ref a, 1, ref a, 1, xIndex: +0 + (ks - 1) * lda, yIndex: +0 + (k - 1) * lda);

                    Complex t2;
                    for (j = k; ks <= j; j--)
                    {
                        t2 = Complex.Conjugate(a[j - 1 + (k - 1) * lda]);
                        a[j - 1 + (k - 1) * lda]  = Complex.Conjugate(a[ks - 1 + (j - 1) * lda]);
                        a[ks - 1 + (j - 1) * lda] = t2;
                    }

                    if (kstep != 1)
                    {
                        t2 = a[ks - 1 + k * lda];
                        a[ks - 1 + k * lda] = a[k - 1 + k * lda];
                        a[k - 1 + k * lda]  = t2;
                    }
                }

                k += kstep;
            }

            break;
        }
        }
    }
예제 #23
0
    public static void zgbsl(Complex[] abd, int lda, int n, int ml, int mu,
                             int[] ipvt, ref Complex[] b, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZGBSL solves a complex band system factored by ZGBCO or ZGBFA.
    //
    //  Discussion:
    //
    //    ZGBSL can solve A * X = B or hermitan ( A ) * X = B.
    //
    //    A division by zero will occur if the input factor contains a
    //    zero on the diagonal.  Technically this indicates singularity
    //    but it is often caused by improper arguments or improper
    //    setting of LDA.  It will not occur if the subroutines are
    //    called correctly and if ZGBCO has set 0.0 < RCOND
    //    or ZGBFA has set INFO = 0.
    //
    //    To compute inverse ( A ) * C where C is a matrix with P columns:
    //
    //      call zgbco(abd,lda,n,ml,mu,ipvt,rcond,z)
    //
    //      if ( rcond is not too small ) then
    //        do j = 1, p
    //          call zgbsl(abd,lda,n,ml,mu,ipvt,c(1,j),0)
    //        end do
    //      end if
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex ABD[LDA*N], the output from ZGBCO or ZGBFA.
    //
    //    Input, int LDA, the leading dimension of ABD.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int ML, the number of diagonals below the main diagonal.
    //
    //    Input, int MU, the number of diagonals above the main diagonal.
    //
    //    Input, int IPVT[N], the pivot vector from ZGBCO or ZGBFA.
    //
    //    Input/output, Complex B[N].  On input, the right hand side.
    //    On output, the solution.
    //
    //    Input, int JOB.
    //    0, to solve A*x = b,
    //    nonzero, to solve hermitian(A)*x = b, where hermitian(A) is the
    //    conjugate transpose.
    //
    {
        int     k;
        int     l;
        int     la;
        int     lb;
        int     lm;
        Complex t;

        int m = mu + ml + 1;

        switch (job)
        {
        //
        //  JOB = 0, solve A * X = B.
        //
        case 0:
        {
            //
            //  First solve L * Y = B.
            //
            if (ml != 0)
            {
                for (k = 1; k <= n - 1; k++)
                {
                    lm = Math.Min(ml, n - k);
                    l  = ipvt[k - 1];
                    t  = b[l - 1];

                    if (l != k)
                    {
                        b[l - 1] = b[k - 1];
                        b[k - 1] = t;
                    }

                    BLAS1Z.zaxpy(lm, t, abd, 1, ref b, 1, xIndex: +m + (k - 1) * lda, yIndex: +k);
                }
            }

            //
            //  Now solve U * X = Y.
            //
            for (k = n; 1 <= k; k--)
            {
                b[k - 1] /= abd[m - 1 + (k - 1) * lda];
                lm        = Math.Min(k, m) - 1;
                la        = m - lm;
                lb        = k - lm;
                t         = -b[k - 1];
                BLAS1Z.zaxpy(lm, t, abd, 1, ref b, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1);
            }

            break;
        }

        //
        default:
        {
            //
            //  First solve hermitian ( U ) * Y = B.
            //
            for (k = 1; k <= n; k++)
            {
                lm       = Math.Min(k, m) - 1;
                la       = m - lm;
                lb       = k - lm;
                t        = BLAS1Z.zdotc(lm, abd, 1, b, 1, xIndex: +la - 1 + (k - 1) * lda, yIndex: +lb - 1);
                b[k - 1] = (b[k - 1] - t) / Complex.Conjugate(abd[m - 1 + (k - 1) * lda]);
            }

            //
            //  Now solve hermitian ( L ) * X = Y.
            //
            if (ml != 0)
            {
                for (k = n - 1; 1 <= k; k--)
                {
                    lm        = Math.Min(ml, n - k);
                    b[k - 1] += BLAS1Z.zdotc(lm, abd, 1, b, 1, xIndex: +m + (k - 1) * lda, yIndex: +k);
                    l         = ipvt[k - 1];

                    if (l == k)
                    {
                        continue;
                    }

                    t        = b[l - 1];
                    b[l - 1] = b[k - 1];
                    b[k - 1] = t;
                }
            }

            break;
        }
        }
    }
예제 #24
0
    public static void zqrdc(ref Complex[] x, int ldx, int n, int p,
                             ref Complex[] qraux, ref int[] ipvt, int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZQRDC computes the QR factorization of an N by P complex <double> matrix.
    //
    //  Discussion:
    //
    //    ZQRDC uses Householder transformations to compute the QR factorization
    //    of an N by P matrix X.  Column pivoting based on the 2-norms of the
    //    reduced columns may be performed at the user's option.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, complex <double> X[LDX*P]; on input, the matrix whose decomposition
    //    is to be computed.  On output, the upper triangle contains the upper
    //    triangular matrix R of the QR factorization.  Below its diagonal, X
    //    contains information from which the unitary part of the decomposition
    //    can be recovered.  If pivoting has been requested, the decomposition is
    //    not that of the original matrix X, but that of X with its columns
    //    permuted as described by IPVT.
    //
    //    Input, int LDX, the leading dimension of X.  N <= LDX.
    //
    //    Input, int N, the number of rows of the matrix.
    //
    //    Input, int P, the number of columns in the matrix X.
    //
    //    Output, complex <double> QRAUX[P], further information required to recover
    //    the unitary part of the decomposition.
    //
    //    Input/output, int IPVT[P]; on input, ints that control the
    //    selection of the pivot columns.  The K-th column X(K) of X is placed
    //    in one of three classes according to the value of IPVT(K):
    //      IPVT(K) > 0, then X(K) is an initial column.
    //      IPVT(K) == 0, then X(K) is a free column.
    //      IPVT(K) < 0, then X(K) is a final column.
    //    Before the decomposition is computed, initial columns are moved to the
    //    beginning of the array X and final columns to the end.  Both initial
    //    and final columns are frozen in place during the computation and only
    //    free columns are moved.  At the K-th stage of the reduction, if X(K)
    //    is occupied by a free column it is interchanged with the free column
    //    of largest reduced norm.
    //    On output, IPVT(K) contains the index of the column of the
    //    original matrix that has been interchanged into
    //    the K-th column, if pivoting was requested.
    //    IPVT is not referenced if JOB == 0.
    //
    //    Input, int JOB, initiates column pivoting.
    //    0, no pivoting is done.
    //    nonzero, pivoting is done.
    //
    {
        int itemp;
        int j;
        int l;

        int pl = 1;
        int pu = 0;

        Complex[] work = new Complex [p];

        if (job != 0)
        {
            //
            //  Pivoting has been requested.  Rearrange the columns according to IPVT.
            //
            for (j = 1; j <= p; j++)
            {
                bool swapj = 0 < ipvt[j - 1];
                bool negj  = ipvt[j - 1] < 0;

                ipvt[j - 1] = negj switch
                {
                    true => - j,
                    _ => j
                };

                switch (swapj)
                {
                case true:
                {
                    if (j != pl)
                    {
                        BLAS1Z.zswap(n, ref x, 1, ref x, 1, xIndex: +0 + (pl - 1) * ldx, yIndex: +0 + (j - 1) * ldx);
                    }

                    ipvt[j - 1]  = ipvt[pl - 1];
                    ipvt[pl - 1] = j;
                    pl          += 1;
                    break;
                }
                }
            }

            pu = p;

            int jj;
            for (jj = 1; jj <= p; jj++)
            {
                j = p - jj + 1;

                switch (ipvt[j - 1])
                {
                case < 0:
                {
                    ipvt[j - 1] = -ipvt[j - 1];

                    if (j != pu)
                    {
                        BLAS1Z.zswap(n, ref x, 1, ref x, 1, xIndex: +0 + (pu - 1) * ldx, yIndex: +0 + (j - 1) * ldx);

                        itemp        = ipvt[pu - 1];
                        ipvt[pu - 1] = ipvt[j - 1];
                        ipvt[j - 1]  = itemp;
                    }

                    pu -= 1;
                    break;
                }
                }
            }
        }

        //
        //  Compute the norms of the free columns.
        //
        for (j = pl; j <= pu; j++)
        {
            qraux[j - 1] = new Complex(BLAS1Z.dznrm2(n, x, 1, index: +0 + (j - 1) * ldx), 0.0);
            work[j - 1]  = qraux[j - 1];
        }

        //
        //  Perform the Householder reduction of X.
        //
        int lup = Math.Min(n, p);

        for (l = 1; l <= lup; l++)
        {
            //
            //  Locate the column of largest norm and bring it
            //  into the pivot position.
            //
            if (pl <= l && l < pu)
            {
                double maxnrm = 0.0;
                int    maxj   = l;

                for (j = l; j <= pu; j++)
                {
                    if (!(maxnrm < qraux[j - 1].Real))
                    {
                        continue;
                    }

                    maxnrm = qraux[j - 1].Real;
                    maxj   = j;
                }

                if (maxj != l)
                {
                    BLAS1Z.zswap(n, ref x, 1, ref x, 1, xIndex: +0 + (l - 1) * ldx, yIndex: +0 + (maxj - 1) * ldx);
                    qraux[maxj - 1] = qraux[l - 1];
                    work[maxj - 1]  = work[l - 1];

                    itemp          = ipvt[maxj - 1];
                    ipvt[maxj - 1] = ipvt[l - 1];
                    ipvt[l - 1]    = itemp;
                }
            }

            qraux[l - 1] = new Complex(0.0, 0.0);

            if (l == n)
            {
                continue;
            }

            //
            //  Compute the Householder transformation for column L.
            //
            Complex nrmxl = new(BLAS1Z.dznrm2(n - l + 1, x, 1, index: +l - 1 + (l - 1) * ldx), 0.0);

            if (typeMethods.zabs1(nrmxl) == 0.0)
            {
                continue;
            }

            if (typeMethods.zabs1(x[l - 1 + (l - 1) * ldx]) != 0.0)
            {
                nrmxl = typeMethods.zsign2(nrmxl, x[l - 1 + (l - 1) * ldx]);
            }

            Complex t = new Complex(1.0, 0.0) / nrmxl;
            BLAS1Z.zscal(n - l + 1, t, ref x, 1, index: +l - 1 + (l - 1) * ldx);
            x[l - 1 + (l - 1) * ldx] = new Complex(1.0, 0.0) + x[l - 1 + (l - 1) * ldx];
            //
            //  Apply the transformation to the remaining columns,
            //  updating the norms.
            //
            for (j = l + 1; j <= p; j++)
            {
                t = -BLAS1Z.zdotc(n - l + 1, x, 1, x, 1, xIndex: +l - 1 + (l - 1) * ldx, yIndex: +l - 1 + (j - 1) * ldx)
                    / x[l - 1 + (l - 1) * ldx];
                BLAS1Z.zaxpy(n - l + 1, t, x, 1, ref x, 1, xIndex: +l - 1 + (l - 1) * ldx, yIndex: +l - 1 + (j - 1) * ldx);

                if (j < pl || pu < j)
                {
                    continue;
                }

                if (typeMethods.zabs1(qraux[j - 1]) == 0.0)
                {
                    continue;
                }

                double tt = 1.0 - Math.Pow(Complex.Abs(x[l - 1 + (j - 1) * ldx]) / qraux[j - 1].Real, 2);
                tt = Math.Max(tt, 0.0);
                t  = new Complex(tt, 0.0);
                tt = 1.0 + 0.05 * tt
                     * Math.Pow(qraux[j - 1].Real / work[j - 1].Real, 2);

                if (Math.Abs(tt - 1.0) > double.Epsilon)
                {
                    qraux[j - 1] *= Complex.Sqrt(t);
                }
                else
                {
                    qraux[j - 1] =
                        new Complex(BLAS1Z.dznrm2(n - l, x, 1, index: +l + (j - 1) * ldx), 0.0);
                    work[j - 1] = qraux[j - 1];
                }
            }

            //
            //  Save the transformation.
            //
            qraux[l - 1]             = x[l - 1 + (l - 1) * ldx];
            x[l - 1 + (l - 1) * ldx] = -nrmxl;
        }
    }
}
예제 #25
0
    public static void zspdi(ref Complex[] ap, int n, int[] ipvt, ref Complex[] det,
                             int job)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZSPDI sets the determinant and inverse of a complex symmetric packed matrix.
    //
    //  Discussion:
    //
    //    ZSPDI uses the factors from ZSPFA.
    //
    //    The matrix is stored in packed form.
    //
    //    A division by zero will occur if the inverse is requested and ZSPCO has
    //    set RCOND to 0.0 or ZSPFA has set INFO nonzero.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input/output, Complex AP[N*(N+1)/2]; on input, the matrix factors
    //    from ZSPFA.  On output, if the inverse was requested, the upper
    //    triangle of the inverse of the original matrix, stored in packed
    //    form.  The columns of the upper triangle are stored sequentially
    //    in a one-dimensional array.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int IPVT[N], the pivot vector from ZSPFA.
    //
    //    Output, Complex DET[2], the determinant of the original matrix.
    //    Determinant = DET(1) * 10.0**DET(2) with 1.0 <= abs ( DET(1) ) < 10.0
    //    or DET(1) = 0.0.  Also, DET(2) is strictly real.
    //
    //    Input, int JOB, has the decimal expansion AB where
    //    if B != 0, the inverse is computed,
    //    if A != 0, the determinant is computed,
    //    For example, JOB = 11 gives both.
    //
    {
        Complex d;
        int     ik;
        int     ikp1;
        int     k;
        int     kk;
        int     kkp1 = 0;
        Complex t;

        bool noinv = job % 10 == 0;
        bool nodet = job % 100 / 10 == 0;

        switch (nodet)
        {
        case false:
        {
            det[0] = new Complex(1.0, 0.0);
            det[1] = new Complex(0.0, 0.0);
            t      = new Complex(0.0, 0.0);
            ik     = 0;

            for (k = 1; k <= n; k++)
            {
                kk = ik + k;
                d  = ap[kk - 1];
                switch (ipvt[k - 1])
                {
                //
                //  2 by 2 block
                //  Use det (D  T)  =  ( D / T * C - T ) * T
                //          (T  C)
                //  to avoid underflow/overflow troubles.
                //  Take two passes through scaling.  Use T for flag.
                //
                case <= 0 when typeMethods.zabs1(t) == 0.0:
                    ikp1 = ik + k;

                    kkp1 = ikp1 + k;
                    t    = ap[kkp1 - 1];
                    d    = d / t * ap[kkp1] - t;
                    break;

                case <= 0:
                    d = t;
                    t = new Complex(0.0, 0.0);
                    break;
                }

                switch (nodet)
                {
                case false:
                {
                    det[0] *= d;

                    if (typeMethods.zabs1(det[0]) != 0.0)
                    {
                        while (typeMethods.zabs1(det[0]) < 1.0)
                        {
                            det[0] *= new Complex(10.0, 0.0);
                            det[1] -= new Complex(1.0, 0.0);
                        }

                        while (10.0 <= typeMethods.zabs1(det[0]))
                        {
                            det[0] /= new Complex(10.0, 0.0);
                            det[1] += new Complex(1.0, 0.0);
                        }
                    }

                    break;
                }
                }

                ik += k;
            }

            break;
        }
        }

        switch (noinv)
        {
        //
        //  Compute inverse ( A ).
        //
        case false:
        {
            Complex[] work = new Complex[n];
            k  = 1;
            ik = 0;

            while (k <= n)
            {
                int km1 = k - 1;
                kk   = ik + k;
                ikp1 = ik + k;

                int j;
                int jk;
                int i;
                int ij;
                int kstep;
                switch (ipvt[k - 1])
                {
                case >= 0:
                {
                    //
                    //  1 by 1
                    //
                    ap[kk - 1] = new Complex(1.0, 0.0) / ap[kk - 1];

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = ap[ik + i - 1];
                        }

                        ij = 0;

                        for (j = 1; j <= km1; j++)
                        {
                            jk         = ik + j;
                            ap[jk - 1] = BLAS1Z.zdotu(j, ap, 1, work, 1, xIndex: +ij);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ik);
                            ij += j;
                        }

                        ap[kk - 1] += BLAS1Z.zdotu(km1, work, 1, ap, 1, yIndex: +ik);
                        break;
                    }
                    }

                    kstep = 1;
                    break;
                }

                //
                default:
                {
                    kkp1 = ikp1 + k;
                    t    = ap[kkp1 - 1];
                    Complex ak    = ap[kk - 1] / t;
                    Complex akp1  = ap[kkp1] / t;
                    Complex akkp1 = ap[kkp1 - 1] / t;
                    d            = t * (ak * akp1 - new Complex(1.0, 0.0));
                    ap[kk - 1]   = akp1 / d;
                    ap[kkp1]     = ak / d;
                    ap[kkp1 - 1] = -akkp1 / d;

                    switch (km1)
                    {
                    case >= 1:
                    {
                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = ap[ikp1 - 1];
                        }

                        ij = 0;

                        for (j = 1; j <= km1; j++)
                        {
                            int jkp1 = ikp1 + j;
                            ap[jkp1 - 1] = BLAS1Z.zdotu(j, ap, 1, work, 1, xIndex: +ij);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ikp1);
                            ij += j;
                        }

                        ap[kkp1]     += BLAS1Z.zdotu(km1, work, 1, ap, 1, yIndex: +ikp1);
                        ap[kkp1 - 1] += BLAS1Z.zdotu(km1, ap, 1, ap, 1, xIndex: +ik, yIndex: +ikp1);

                        for (i = 1; i <= km1; i++)
                        {
                            work[i - 1] = ap[ik + i - 1];
                        }

                        ij = 0;

                        for (j = 1; j <= km1; j++)
                        {
                            jk         = ik + j;
                            ap[jk - 1] = BLAS1Z.zdotu(j, ap, 1, work, 1, xIndex: +ij);
                            BLAS1Z.zaxpy(j - 1, work[j - 1], ap, 1, ref ap, 1, xIndex: +ij, yIndex: +ik);
                            ij += j;
                        }

                        ap[kk - 1] += BLAS1Z.zdotu(km1, work, 1, ap, 1, yIndex: +ik);
                        break;
                    }
                    }

                    kstep = 2;
                    break;
                }
                }

                //
                //  Swap.
                //
                int ks = Math.Abs(ipvt[k - 1]);

                if (ks != k)
                {
                    int iks = ks * (ks - 1) / 2;
                    BLAS1Z.zswap(ks, ref ap, 1, ref ap, 1, xIndex: +iks, yIndex: +ik);
                    int ksj = ik + ks;

                    int jb;
                    for (jb = ks; jb <= k; jb++)
                    {
                        j  = k + ks - jb;
                        jk = ik + j;

                        t           = ap[jk - 1];
                        ap[jk - 1]  = ap[ksj - 1];
                        ap[ksj - 1] = t;

                        ksj -= j - 1;
                    }

                    if (kstep != 1)
                    {
                        int kskp1 = ikp1 + ks;

                        t             = ap[kskp1 - 1];
                        ap[kskp1 - 1] = ap[kkp1 - 1];
                        ap[kkp1 - 1]  = t;
                    }
                }

                ik += k;

                ik = kstep switch
                {
                    2 => ik + k + 1,
                    _ => ik
                };

                k += kstep;
            }

            break;
        }
        }
    }
}
예제 #26
0
    public static void zhpsl(Complex[] ap, int n, int[] ipvt, ref Complex[] b)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    ZHPSL solves a complex hermitian system factored by ZHPFA.
    //
    //  Discussion:
    //
    //    A division by zero may occur if ZHPCO set RCOND to 0.0
    //    or ZHPFA set INFO nonzero.
    //
    //    To compute
    //
    //      inverse ( A ) * C
    //
    //    where C is a matrix with P columns
    //
    //      call zhpfa(ap,n,ipvt,info)
    //
    //      if ( info == 0 )
    //        do j = 1, p
    //          call zhpsl(ap,n,ipvt,c(1,j))
    //        end do
    //      }
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    21 May 2006
    //
    //  Author:
    //
    //    C++ version by John Burkardt
    //
    //  Reference:
    //
    //    Jack Dongarra, Cleve Moler, Jim Bunch and Pete Stewart,
    //    LINPACK User's Guide,
    //    SIAM, (Society for Industrial and Applied Mathematics),
    //    3600 University City Science Center,
    //    Philadelphia, PA, 19104-2688.
    //
    //  Parameters:
    //
    //    Input, Complex AP[N*(N+1)/2], the output from ZHPFA.
    //
    //    Input, int N, the order of the matrix.
    //
    //    Input, int IPVT[N], the pivot vector from ZHPFA.
    //
    //    Input/output, Complex B[N].  On input, the right hand side.
    //    On output, the solution.
    //
    {
        int     kp;
        Complex t;
        //
        //  Loop backward applying the transformations and inverse ( D ) to B.
        //
        int k  = n;
        int ik = n * (n - 1) / 2;

        while (0 < k)
        {
            int kk = ik + k;
            switch (ipvt[k - 1])
            {
            //
            //  1 x 1 pivot block.
            //
            case >= 0:
            {
                if (k != 1)
                {
                    kp = ipvt[k - 1];

                    if (kp != k)
                    {
                        t         = b[k - 1];
                        b[k - 1]  = b[kp - 1];
                        b[kp - 1] = t;
                    }

                    BLAS1Z.zaxpy(k - 1, b[k - 1], ap, 1, ref b, 1, xIndex: +ik);
                }

                //
                //  Apply D inverse.
                //
                b[k - 1] /= ap[kk - 1];
                k        -= 1;
                ik       -= k;
                break;
            }

            default:
            {
                //
                //  2 x 2 pivot block.
                //
                int ikm1 = ik - (k - 1);

                if (k != 2)
                {
                    kp = Math.Abs(ipvt[k - 1]);

                    if (kp != k - 1)
                    {
                        t         = b[k - 2];
                        b[k - 2]  = b[kp - 1];
                        b[kp - 1] = t;
                    }

                    BLAS1Z.zaxpy(k - 2, b[k - 1], ap, 1, ref b, 1, xIndex: +ik);
                    BLAS1Z.zaxpy(k - 2, b[k - 2], ap, 1, ref b, 1, xIndex: +ikm1);
                }

                //
                //  Apply D inverse.
                //
                int km1k = ik + k - 1;
                kk = ik + k;
                Complex ak     = ap[kk - 1] / Complex.Conjugate(ap[km1k - 1]);
                int     km1km1 = ikm1 + k - 1;
                Complex akm1   = ap[km1km1 - 1] / ap[km1k - 1];
                Complex bk     = b[k - 1] / Complex.Conjugate(ap[km1k - 1]);
                Complex bkm1   = b[k - 2] / ap[km1k - 1];
                Complex denom  = ak * akm1 - new Complex(1.0, 0.0);
                b[k - 1] = (akm1 * bk - bkm1) / denom;
                b[k - 2] = (ak * bkm1 - bk) / denom;
                k       -= 2;
                ik       = ik - (k + 1) - k;
                break;
            }
            }
        }

        //
        //  Loop forward applying the transformations.
        //
        k  = 1;
        ik = 0;

        while (k <= n)
        {
            switch (ipvt[k - 1])
            {
            //
            //  1 x 1 pivot block.
            //
            case >= 0:
            {
                if (k != 1)
                {
                    b[k - 1] += BLAS1Z.zdotc(k - 1, ap, 1, b, 1, xIndex: +ik);
                    kp        = ipvt[k - 1];

                    if (kp != k)
                    {
                        t         = b[k - 1];
                        b[k - 1]  = b[kp - 1];
                        b[kp - 1] = t;
                    }
                }

                ik += k;
                k  += 1;
                break;
            }

            //
            default:
            {
                if (k != 1)
                {
                    b[k - 1] += BLAS1Z.zdotc(k - 1, ap, 1, b, 1, xIndex: +ik);
                    int ikp1 = ik + k;
                    b[k] += BLAS1Z.zdotc(k - 1, ap, 1, b, 1, xIndex: +ikp1);
                    kp    = Math.Abs(ipvt[k - 1]);

                    if (kp != k)
                    {
                        t         = b[k - 1];
                        b[k - 1]  = b[kp - 1];
                        b[kp - 1] = t;
                    }
                }

                ik = ik + k + k + 1;
                k += 2;
                break;
            }
            }
        }
    }