cobyla.f90 Source File


This file depends on

sourcefile~~cobyla.f90~~EfferentGraph sourcefile~cobyla.f90 cobyla.f90 sourcefile~kind_module.f90 kind_module.f90 sourcefile~cobyla.f90->sourcefile~kind_module.f90

Files dependent on this one

sourcefile~~cobyla.f90~~AfferentGraph sourcefile~cobyla.f90 cobyla.f90 sourcefile~powellopt.f90 powellopt.f90 sourcefile~powellopt.f90->sourcefile~cobyla.f90

Source Code

!*****************************************************************************************
!>
!  COBYLA: **C**onstrained **O**ptimization **BY** **L**inear **A**pproximations.
!
!  Minimize an objective function F([X1,X2,...,XN]) subject to M inequality constraints.
!
!# References
!  * "[A direct search optimization method that models the objective and constraint
!    functions by linear interpolation](http://link.springer.com/chapter/10.1007/978-94-015-8330-5_4)",
!    *Advances in Optimization and Numerical Analysis*
!    (eds. Susana Gomez and Jean-Pierre Hennart), Kluwer Academic Publishers (1994).
!
!# History
!  * Mike Powell (May 7th, 1992) -- There are no restrictions on the use of the
!    software, nor do I offer any guarantees of success.
!  * Jacob Williams, July 2015 : refactoring of the code into modern Fortran.
!
!@note There is a need for a linear programming problem to be solved subject to a
!      Euclidean norm trust region constraint. Therefore SUBROUTINE TRSTLP is provided,
!      but you may have some software that you prefer to use instead.

module cobyla_module

    use kind_module, only: wp

    private

    abstract interface
        subroutine func (n, m, x, f, con)  !! calcfc interface
            import :: wp
            implicit none
            integer,intent(in)                :: n
            integer,intent(in)                :: m
            real(wp),dimension(*),intent(in)  :: x
            real(wp),intent(out)              :: f
            real(wp),dimension(*),intent(out) :: con
        end subroutine func
    end interface

    public :: cobyla
    public :: cobyla_test

contains

!*****************************************************************************************
!>
!  This subroutine minimizes an objective function F(X) subject to M
!  inequality constraints on X, where X is a vector of variables that has
!  N components. The algorithm employs linear approximations to the
!  objective and constraint functions, the approximations being formed by
!  linear interpolation at N+1 points in the space of the variables.
!  We regard these interpolation points as vertices of a simplex. The
!  parameter RHO controls the size of the simplex and it is reduced
!  automatically from RHOBEG to RHOEND. For each RHO the subroutine tries
!  to achieve a good vector of variables for the current size, and then
!  RHO is reduced until the value RHOEND is reached. Therefore RHOBEG and
!  RHOEND should be set to reasonable initial changes to and the required
!  accuracy in the variables respectively, but this accuracy should be
!  viewed as a subject for experimentation because it is not guaranteed.
!
!  The subroutine has an advantage over many of its competitors, however,
!  which is that it treats each constraint individually when calculating
!  a change to the variables, instead of lumping the constraints together
!  into a single penalty function.

    subroutine cobyla (n, m, x, rhobeg, rhoend, iprint, maxfun, calcfc)

        implicit none

        integer,intent(in)                  :: n      !! number of variables
        integer,intent(in)                  :: m      !! number of inequality constraints
        real(wp),dimension(*),intent(inout) :: x      !! Initial values of the variables must be set in X(1),X(2),...,X(N).
                                                      !! On return they will be changed to the solution.
        real(wp),intent(in)                 :: rhobeg !! reasonable initial change to variables (see description of RHO)
        real(wp),intent(in)                 :: rhoend !! required accuracy (see description of RHO)
        integer,intent(in)                  :: iprint !! IPRINT should be set to 0, 1, 2 or 3, which controls the amount of
                                                      !! printing during the calculation. Specifically, there is no output if
                                                      !! IPRINT=0 and there is output only at the end of the calculation if
                                                      !! IPRINT=1. Otherwise each new value of RHO and SIGMA is printed.
                                                      !! Further, the vector of variables and some function information are
                                                      !! given either when RHO is reduced or when each new value of F(X) is
                                                      !! computed in the cases IPRINT=2 or IPRINT=3 respectively. Here SIGMA
                                                      !! is a penalty parameter, it being assumed that a change to X is an
                                                      !! improvement if it reduces the merit function
                                                      !!     F(X)+SIGMA*MAX(0.0,-C1(X),-C2(X),...,-CM(X)),
                                                      !! where C1,C2,...,CM denote the constraint functions that should become
                                                      !! nonnegative eventually, at least to the precision of RHOEND. In the
                                                      !! printed output the displayed term that is multiplied by SIGMA is
                                                      !! called MAXCV, which stands for 'MAXimum Constraint Violation'.
        integer,intent(inout)               :: maxfun !! MAXFUN is an integer variable that must be set by the user to a
                                                      !! limit on the number of calls of CALCFC.
                                                      !! The value of MAXFUN will be altered to the number of calls
                                                      !! of CALCFC that are made.
        procedure (func)                    :: calcfc !! In order to define the objective and constraint functions, we require
                                                      !! a subroutine that has the name and arguments
                                                      !!     SUBROUTINE CALCFC (N,M,X,F,CON)
                                                      !!     DIMENSION X(*),CON(*)
                                                      !! The values of N and M are fixed and have been defined already, while
                                                      !! X is now the current vector of variables. The subroutine should return
                                                      !! the objective and constraint functions at X in F and CON(1),CON(2),
                                                      !! ...,CON(M). Note that we are trying to adjust X so that F(X) is as
                                                      !! small as possible subject to the constraint functions being nonnegative.


        integer,dimension(:),allocatable  :: iact
        real(wp),dimension(:),allocatable :: w
        integer :: mpp,icon,isim,isimi,idatm,ia,ivsig,iveta,isigb,idx,iwork

        !W and IACT provide real and integer arrays that are used as working space.
        allocate(w(N*(3*N+2*M+11)+4*M+6))
        allocate(iact(M+1))

        ! Partition the working space array W to provide the storage that is needed
        ! for the main calculation.

        mpp = m + 2
        icon = 1
        isim = icon + mpp
        isimi = isim + n * n + n
        idatm = isimi + n * n
        ia = idatm + n * mpp + mpp
        ivsig = ia + m * n + n
        iveta = ivsig + n
        isigb = iveta + n
        idx = isigb + n
        iwork = idx + n

        call cobylb (n, m, mpp, x, rhobeg, rhoend, iprint, maxfun, w(icon), w(isim), &
                     w(isimi), w(idatm), w(ia), w(ivsig), w(iveta), w(isigb), w(idx), &
                     w(iwork), iact, calcfc)

        deallocate(iact)
        deallocate(w)

    end subroutine cobyla
!*****************************************************************************************

    subroutine cobylb (n, m, mpp, x, rhobeg, rhoend, iprint, maxfun, con, sim, simi, &
                       datmat, a, vsig, veta, sigbar, dx, w, iact, calcfc)

        implicit real (wp) (a-h, o-z)

        dimension x (*), con (*), sim (n,*), simi (n,*), datmat (mpp,*), a (n,*), vsig(*),&
         veta (*), sigbar (*), dx (*), w (*), iact (*)
        procedure (func) :: calcfc
!
!     Set the initial values of some parameters. The last column of SIM holds
!     the optimal vertex of the current simplex, and the preceding N columns
!     hold the displacements from the optimal vertex to the other vertices.
!     Further, SIMI holds the inverse of the matrix that is contained in the
!     first N columns of SIM.
!
        iptem = min (n, 5)
        iptemp = iptem + 1
        np = n + 1
        mp = m + 1
        alpha = 0.25_wp
        beta = 2.1_wp
        gamma = 0.5_wp
        delta = 1.1_wp
        rho = rhobeg
        parmu = 0.0_wp
        if (iprint >= 2) print 10, rho
10      format (/ 3 x, 'The initial value of RHO is', 1 pe13.6, 2 x,&
        'and PARMU is set to zero.')
        nfvals = 0
        temp = 1.0_wp / rho
        do i = 1, n
            sim (i, np) = x (i)
            do j = 1, n
                sim (i, j) = 0.0_wp
                simi (i, j) = 0.0_wp
            end do
            sim (i, i) = rho
            simi (i, i) = temp
        end do
        jdrop = np
        ibrnch = 0
!
!     Make the next call of the user-supplied subroutine CALCFC. These
!     instructions are also used for calling CALCFC during the iterations of
!     the algorithm.
!
40      if (nfvals >= maxfun .and. nfvals > 0) then
            if (iprint >= 1) print 50
50          format (/ 3 x, 'Return from subroutine COBYLA because the ',&
            'MAXFUN limit has been reached.')
            go to 600
        end if
        nfvals = nfvals + 1
        call calcfc (n, m, x, f, con)
        resmax = 0.0_wp
        if (m > 0) then
            do k = 1, m
                resmax = max (resmax,-con(k))
            end do
        end if
        if (nfvals == iprint-1 .or. iprint == 3) then
            print 70, nfvals, f, resmax, (x(i), i=1, iptem)
70          format (/ 3 x, 'NFVALS =', i5, 3 x, 'F =', 1 pe13.6, 4 x, 'MAXCV =', 1 pe13.6 &
           & / 3 x, 'X =', 1 pe13.6, 1 p4e15.6)
            if (iptem < n) print 80, (x(i), i=iptemp, n)
80          format (1 pe19.6, 1 p4e15.6)
        end if
        con (mp) = f
        con (mpp) = resmax
        if (ibrnch == 1) go to 440
!
!     Set the recently calculated function values in a column of DATMAT. This
!     array has a column for each vertex of the current simplex, the entries of
!     each column being the values of the constraint functions (if any)
!     followed by the objective function and the greatest constraint violation
!     at the vertex.
!
        do k = 1, mpp
            datmat (k, jdrop) = con (k)
        end do
        if (nfvals > np) go to 130
!
!     Exchange the new vertex of the initial simplex with the optimal vertex if
!     necessary. Then, if the initial simplex is not complete, pick its next
!     vertex and calculate the function values there.
!
        if (jdrop <= n) then
            if (datmat(mp, np) <= f) then
                x (jdrop) = sim (jdrop, np)
            else
                sim (jdrop, np) = x (jdrop)
                do k = 1, mpp
                    datmat (k, jdrop) = datmat (k, np)
                    datmat (k, np) = con (k)
                end do
                do k = 1, jdrop
                    sim (jdrop, k) = - rho
                    temp = 0.0_wp
                    do i = k, jdrop
                        temp = temp - simi (i, k)
                    end do
                    simi (jdrop, k) = temp
                end do
            end if
        end if
        if (nfvals <= n) then
            jdrop = nfvals
            x (jdrop) = x (jdrop) + rho
            go to 40
        end if
130     ibrnch = 1
!
!     Identify the optimal vertex of the current simplex.
!
140     phimin = datmat (mp, np) + parmu * datmat (mpp, np)
        nbest = np
        do j = 1, n
            temp = datmat (mp, j) + parmu * datmat (mpp, j)
            if (temp < phimin) then
                nbest = j
                phimin = temp
            else if (temp == phimin .and. parmu == 0.0_wp) then
                if (datmat(mpp, j) < datmat(mpp, nbest)) nbest = j
            end if
        end do
!
!     Switch the best vertex into pole position if it is not there already,
!     and also update SIM, SIMI and DATMAT.
!
        if (nbest <= n) then
            do i = 1, mpp
                temp = datmat (i, np)
                datmat (i, np) = datmat (i, nbest)
                datmat (i, nbest) = temp
            end do
            do i = 1, n
                temp = sim (i, nbest)
                sim (i, nbest) = 0.0_wp
                sim (i, np) = sim (i, np) + temp
                tempa = 0.0_wp
                do k = 1, n
                    sim (i, k) = sim (i, k) - temp
                    tempa = tempa - simi (k, i)
                end do
                simi (nbest, i) = tempa
            end do
        end if
!
!     Make an error return if SIGI is a poor approximation to the inverse of
!     the leading N by N submatrix of SIG.
!
        error = 0.0_wp
        do i = 1, n
            do j = 1, n
                temp = 0.0_wp
                if (i == j) temp = temp - 1.0_wp
                do k = 1, n
                    temp = temp + simi (i, k) * sim (k, j)
                end do
                error = max (error, abs(temp))
            end do
        end do
        if (error > 0.1_wp) then
            if (iprint >= 1) print 210
210         format (/ 3 x, 'Return from subroutine COBYLA because ',&
            'rounding errors are becoming damaging.')
            go to 600
        end if
!
!     Calculate the coefficients of the linear approximations to the objective
!     and constraint functions, placing minus the objective function gradient
!     after the constraint gradients in the array A. The vector W is used for
!     working space.
!
        do k = 1, mp
            con (k) = - datmat (k, np)
            do j = 1, n
                w (j) = datmat (k, j) + con (k)
            end do
            do i = 1, n
                temp = 0.0_wp
                do j = 1, n
                    temp = temp + w (j) * simi (j, i)
                end do
                if (k == mp) temp = - temp
                a (i, k) = temp
            end do
        end do
!
!     Calculate the values of sigma and eta, and set IFLAG=0 if the current
!     simplex is not acceptable.
!
        iflag = 1
        parsig = alpha * rho
        pareta = beta * rho
        do j = 1, n
            wsig = 0.0_wp
            weta = 0.0_wp
            do i = 1, n
                wsig = wsig + simi (j, i) ** 2
                weta = weta + sim (i, j) ** 2
            end do
            vsig (j) = 1.0_wp / sqrt (wsig)
            veta (j) = sqrt (weta)
            if (vsig(j) < parsig .or. veta(j) > pareta) iflag = 0
        end do
!
!     If a new vertex is needed to improve acceptability, then decide which
!     vertex to drop from the simplex.
!
        if (ibrnch == 1 .or. iflag == 1) go to 370
        jdrop = 0
        temp = pareta
        do j = 1, n
            if (veta(j) > temp) then
                jdrop = j
                temp = veta (j)
            end if
        end do
        if (jdrop == 0) then
            do j = 1, n
                if (vsig(j) < temp) then
                    jdrop = j
                    temp = vsig (j)
                end if
            end do
        end if
!
!     Calculate the step to the new vertex and its sign.
!
        temp = gamma * rho * vsig (jdrop)
        do i = 1, n
            dx (i) = temp * simi (jdrop, i)
        end do
        cvmaxp = 0.0_wp
        cvmaxm = 0.0_wp
        do k = 1, mp
            sum = 0.0_wp
            do i = 1, n
                sum = sum + a (i, k) * dx (i)
            end do
            if (k < mp) then
                temp = datmat (k, np)
                cvmaxp = max (cvmaxp,-sum-temp)
                cvmaxm = max (cvmaxm, sum-temp)
            end if
        end do
        dxsign = 1.0_wp
        if (parmu*(cvmaxp-cvmaxm) > sum+sum) dxsign = - 1.0_wp
!
!     Update the elements of SIM and SIMI, and set the next X.
!
        temp = 0.0_wp
        do i = 1, n
            dx (i) = dxsign * dx (i)
            sim (i, jdrop) = dx (i)
            temp = temp + simi (jdrop, i) * dx (i)
        end do
        do i = 1, n
            simi (jdrop, i) = simi (jdrop, i) / temp
        end do
        do j = 1, n
            if (j /= jdrop) then
                temp = 0.0_wp
                do i = 1, n
                    temp = temp + simi (j, i) * dx (i)
                end do
                do i = 1, n
                    simi (j, i) = simi (j, i) - temp * simi (jdrop, i)
                end do
            end if
            x (j) = sim (j, np) + dx (j)
        end do
        go to 40
!
!     Calculate DX=x(*)-x(0). Branch if the length of DX is less than 0.5*RHO.
!
370     iz = 1
        izdota = iz + n * n
        ivmc = izdota + n
        isdirn = ivmc + mp
        idxnew = isdirn + n
        ivmd = idxnew + n
        call trstlp (n, m, a, con, rho, dx, ifull, iact, w(iz), w(izdota), w(ivmc), &
       & w(isdirn), w(idxnew), w(ivmd))
        if (ifull == 0) then
            temp = 0.0_wp
            do i = 1, n
                temp = temp + dx (i) ** 2
            end do
            if (temp < 0.25_wp*rho*rho) then
                ibrnch = 1
                go to 550
            end if
        end if
!
!     Predict the change to F and the new maximum constraint violation if the
!     variables are altered from x(0) to x(0)+DX.
!
        resnew = 0.0_wp
        con (mp) = 0.0_wp
        do k = 1, mp
            sum = con (k)
            do i = 1, n
                sum = sum - a (i, k) * dx (i)
            end do
            if (k < mp) resnew = max (resnew, sum)
        end do
!
!     Increase PARMU if necessary and branch back if this change alters the
!     optimal vertex. Otherwise PREREM and PREREC will be set to the predicted
!     reductions in the merit function and the maximum constraint violation
!     respectively.
!
        barmu = 0.0_wp
        prerec = datmat (mpp, np) - resnew
        if (prerec > 0.0_wp) barmu = sum / prerec
        if (parmu < 1.5_wp*barmu) then
            parmu = 2.0_wp * barmu
            if (iprint >= 2) print 410, parmu
410         format (/ 3 x, 'Increase in PARMU to', 1 pe13.6)
            phi = datmat (mp, np) + parmu * datmat (mpp, np)
            do j = 1, n
                temp = datmat (mp, j) + parmu * datmat (mpp, j)
                if (temp < phi) go to 140
                if (temp == phi .and. parmu == 0.0_wp) then
                    if (datmat(mpp, j) < datmat(mpp, np)) go to 140
                end if
            end do
        end if
        prerem = parmu * prerec - sum
!
!     Calculate the constraint and objective functions at x(*). Then find the
!     actual reduction in the merit function.
!
        do i = 1, n
            x (i) = sim (i, np) + dx (i)
        end do
        ibrnch = 1
        go to 40
440     vmold = datmat (mp, np) + parmu * datmat (mpp, np)
        vmnew = f + parmu * resmax
        trured = vmold - vmnew
        if (parmu == 0.0_wp .and. f == datmat(mp, np)) then
            prerem = prerec
            trured = datmat (mpp, np) - resmax
        end if
!
!     Begin the operations that decide whether x(*) should replace one of the
!     vertices of the current simplex, the change being mandatory if TRURED is
!     positive. Firstly, JDROP is set to the index of the vertex that is to be
!     replaced.
!
        ratio = 0.0_wp
        if (trured <= 0.0_wp) ratio = 1.0_wp
        jdrop = 0
        do j = 1, n
            temp = 0.0_wp
            do i = 1, n
                temp = temp + simi (j, i) * dx (i)
            end do
            temp = abs (temp)
            if (temp > ratio) then
                jdrop = j
                ratio = temp
            end if
            sigbar (j) = temp * vsig (j)
        end do
!
!     Calculate the value of ell.
!
        edgmax = delta * rho
        l = 0
        do j = 1, n
            if (sigbar(j) >= parsig .or. sigbar(j) >= vsig(j)) then
                temp = veta (j)
                if (trured > 0.0_wp) then
                    temp = 0.0_wp
                    do i = 1, n
                        temp = temp + (dx(i)-sim(i, j)) ** 2
                    end do
                    temp = sqrt (temp)
                end if
                if (temp > edgmax) then
                    l = j
                    edgmax = temp
                end if
            end if
        end do
        if (l > 0) jdrop = l
        if (jdrop == 0) go to 550
!
!     Revise the simplex by updating the elements of SIM, SIMI and DATMAT.
!
        temp = 0.0_wp
        do i = 1, n
            sim (i, jdrop) = dx (i)
            temp = temp + simi (jdrop, i) * dx (i)
        end do
        do i = 1, n
            simi (jdrop, i) = simi (jdrop, i) / temp
        end do
        do j = 1, n
            if (j /= jdrop) then
                temp = 0.0_wp
                do i = 1, n
                    temp = temp + simi (j, i) * dx (i)
                end do
                do i = 1, n
                    simi (j, i) = simi (j, i) - temp * simi (jdrop, i)
                end do
            end if
        end do
        do k = 1, mpp
            datmat (k, jdrop) = con (k)
        end do
!
!     Branch back for further iterations with the current RHO.
!
        if (trured > 0.0_wp .and. trured >= 0.1_wp*prerem) go to 140
550     if (iflag == 0) then
            ibrnch = 0
            go to 140
        end if
!
!     Otherwise reduce RHO if it is not at its least value and reset PARMU.
!
        if (rho > rhoend) then
            rho = 0.5_wp * rho
            if (rho <= 1.5_wp*rhoend) rho = rhoend
            if (parmu > 0.0_wp) then
                denom = 0.0_wp
                do k = 1, mp
                    cmin = datmat (k, np)
                    cmax = cmin
                    do i = 1, n
                        cmin = min (cmin, datmat(k, i))
                        cmax = max (cmax, datmat(k, i))
                    end do
                    if (k <= m .and. cmin < 0.5_wp*cmax) then
                        temp = max (cmax, 0.0_wp) - cmin
                        if (denom <= 0.0_wp) then
                            denom = temp
                        else
                            denom = min (denom, temp)
                        end if
                    end if
                end do
                if (denom == 0.0_wp) then
                    parmu = 0.0_wp
                else if (cmax-cmin < parmu*denom) then
                    parmu = (cmax-cmin) / denom
                end if
            end if
            if (iprint >= 2) print 580, rho, parmu
580         format (/ 3 x, 'Reduction in RHO to', 1 pe13.6, '  and PARMU =', 1 pe13.6)
            if (iprint == 2) then
                print 70, nfvals, datmat (mp, np), datmat (mpp, np), (sim(i, np), i=1, &
               & iptem)
                if (iptem < n) print 80, (x(i), i=iptemp, n)
            end if
            go to 140
        end if
!
!     Return the best calculated values of the variables.
!
        if (iprint >= 1) print 590
590     format (/ 3 x, 'Normal return from subroutine COBYLA')
        if (ifull == 1) go to 620
600     do i = 1, n
            x (i) = sim (i, np)
        end do
        f = datmat (mp, np)
        resmax = datmat (mpp, np)
620     if (iprint >= 1) then
            print 70, nfvals, f, resmax, (x(i), i=1, iptem)
            if (iptem < n) print 80, (x(i), i=iptemp, n)
        end if
        maxfun = nfvals

    end subroutine cobylb

    subroutine trstlp (n, m, a, b, rho, dx, ifull, iact, z, zdota, vmultc, sdirn, dxnew, &
                       vmultd)

        implicit real (wp) (a-h, o-z)

        dimension a (n,*), b (*), dx (*), iact (*), z (n,*), zdota (*), vmultc (*), &
                  sdirn (*), dxnew (*), vmultd (*)
!
!     This subroutine calculates an N-component vector DX by applying the
!     following two stages. In the first stage, DX is set to the shortest
!     vector that minimizes the greatest violation of the constraints
!       A(1,K)*DX(1)+A(2,K)*DX(2)+...+A(N,K)*DX(N) .GE. B(K), K=2,3,...,M,
!     subject to the Euclidean length of DX being at most RHO. If its length is
!     strictly less than RHO, then we use the resultant freedom in DX to
!     minimize the objective function
!              -A(1,M+1)*DX(1)-A(2,M+1)*DX(2)-...-A(N,M+1)*DX(N)
!     subject to no increase in any greatest constraint violation. This
!     notation allows the gradient of the objective function to be regarded as
!     the gradient of a constraint. Therefore the two stages are distinguished
!     by MCON .EQ. M and MCON .GT. M respectively. It is possible that a
!     degeneracy may prevent DX from attaining the target length RHO. Then the
!     value IFULL=0 would be set, but usually IFULL=1 on return.
!
!     In general NACT is the number of constraints in the active set and
!     IACT(1),...,IACT(NACT) are their indices, while the remainder of IACT
!     contains a permutation of the remaining constraint indices. Further, Z is
!     an orthogonal matrix whose first NACT columns can be regarded as the
!     result of Gram-Schmidt applied to the active constraint gradients. For
!     J=1,2,...,NACT, the number ZDOTA(J) is the scalar product of the J-th
!     column of Z with the gradient of the J-th active constraint. DX is the
!     current vector of variables and here the residuals of the active
!     constraints should be zero. Further, the active constraints have
!     nonnegative Lagrange multipliers that are held at the beginning of
!     VMULTC. The remainder of this vector holds the residuals of the inactive
!     constraints at DX, the ordering of the components of VMULTC being in
!     agreement with the permutation of the indices of the constraints that is
!     in IACT. All these residuals are nonnegative, which is achieved by the
!     shift RESMAX that makes the least residual zero.
!
!     Initialize Z and some other variables. The value of RESMAX will be
!     appropriate to DX=0, while ICON will be the index of a most violated
!     constraint if RESMAX is positive. Usually during the first stage the
!     vector SDIRN gives a search direction that reduces all the active
!     constraint violations by one simultaneously.
!
        ifull = 1
        mcon = m
        nact = 0
        resmax = 0.0_wp
        do i = 1, n
            do j = 1, n
                z (i, j) = 0.0_wp
            end do
            z (i, i) = 1.0_wp
            dx (i) = 0.0_wp
        end do
        if (m >= 1) then
            do k = 1, m
                if (b(k) > resmax) then
                    resmax = b (k)
                    icon = k
                end if
            end do
            do k = 1, m
                iact (k) = k
                vmultc (k) = resmax - b (k)
            end do
        end if
        if (resmax == 0.0_wp) go to 480
        do i = 1, n
            sdirn (i) = 0.0_wp
        end do
!
!     End the current stage of the calculation if 3 consecutive iterations
!     have either failed to reduce the best calculated value of the objective
!     function or to increase the number of active constraints since the best
!     value was calculated. This strategy prevents cycling, but there is a
!     remote possibility that it will cause premature termination.
!
60      optold = 0.0_wp
        icount = 0
70      if (mcon == m) then
            optnew = resmax
        else
            optnew = 0.0_wp
            do i = 1, n
                optnew = optnew - dx (i) * a (i, mcon)
            end do
        end if
        if (icount == 0 .or. optnew < optold) then
            optold = optnew
            nactx = nact
            icount = 3
        else if (nact > nactx) then
            nactx = nact
            icount = 3
        else
            icount = icount - 1
            if (icount == 0) go to 490
        end if
!
!     If ICON exceeds NACT, then we add the constraint with index IACT(ICON) to
!     the active set. Apply Givens rotations so that the last N-NACT-1 columns
!     of Z are orthogonal to the gradient of the new constraint, a scalar
!     product being set to zero if its nonzero value could be due to computer
!     rounding errors. The array DXNEW is used for working space.
!
        if (icon <= nact) go to 260
        kk = iact (icon)
        do i = 1, n
            dxnew (i) = a (i, kk)
        end do
        tot = 0.0_wp
        k = n
100     if (k > nact) then
            sp = 0.0_wp
            spabs = 0.0_wp
            do i = 1, n
                temp = z (i, k) * dxnew (i)
                sp = sp + temp
                spabs = spabs + abs (temp)
            end do
            acca = spabs + 0.1_wp * abs (sp)
            accb = spabs + 0.2_wp * abs (sp)
            if (spabs >= acca .or. acca >= accb) sp = 0.0_wp
            if (tot == 0.0_wp) then
                tot = sp
            else
                kp = k + 1
                temp = sqrt (sp*sp+tot*tot)
                alpha = sp / temp
                beta = tot / temp
                tot = temp
                do i = 1, n
                    temp = alpha * z (i, k) + beta * z (i, kp)
                    z (i, kp) = alpha * z (i, kp) - beta * z (i, k)
                    z (i, k) = temp
                end do
            end if
            k = k - 1
            go to 100
        end if
!
!     Add the new constraint if this can be done without a deletion from the
!     active set.
!
        if (tot /= 0.0_wp) then
            nact = nact + 1
            zdota (nact) = tot
            vmultc (icon) = vmultc (nact)
            vmultc (nact) = 0.0_wp
            go to 210
        end if
!
!     The next instruction is reached if a deletion has to be made from the
!     active set in order to make room for the new active constraint, because
!     the new constraint gradient is a linear combination of the gradients of
!     the old active constraints. Set the elements of VMULTD to the multipliers
!     of the linear combination. Further, set IOUT to the index of the
!     constraint to be deleted, but branch if no suitable index can be found.
!
        ratio = - 1.0_wp
        k = nact
130     zdotv = 0.0_wp
        zdvabs = 0.0_wp
        do i = 1, n
            temp = z (i, k) * dxnew (i)
            zdotv = zdotv + temp
            zdvabs = zdvabs + abs (temp)
        end do
        acca = zdvabs + 0.1_wp * abs (zdotv)
        accb = zdvabs + 0.2_wp * abs (zdotv)
        if (zdvabs < acca .and. acca < accb) then
            temp = zdotv / zdota (k)
            if (temp > 0.0_wp .and. iact(k) <= m) then
                tempa = vmultc (k) / temp
                if (ratio < 0.0_wp .or. tempa < ratio) then
                    ratio = tempa
                    iout = k
                end if
            end if
            if (k >= 2) then
                kw = iact (k)
                do i = 1, n
                    dxnew (i) = dxnew (i) - temp * a (i, kw)
                end do
            end if
            vmultd (k) = temp
        else
            vmultd (k) = 0.0_wp
        end if
        k = k - 1
        if (k > 0) go to 130
        if (ratio < 0.0_wp) go to 490
!
!     Revise the Lagrange multipliers and reorder the active constraints so
!     that the one to be replaced is at the end of the list. Also calculate the
!     new value of ZDOTA(NACT) and branch if it is not acceptable.
!
        do k = 1, nact
            vmultc (k) = max (0.0_wp, vmultc(k)-ratio*vmultd(k))
        end do
        if (icon < nact) then
            isave = iact (icon)
            vsave = vmultc (icon)
            k = icon
170         kp = k + 1
            kw = iact (kp)
            sp = 0.0_wp
            do i = 1, n
                sp = sp + z (i, k) * a (i, kw)
            end do
            temp = sqrt (sp*sp+zdota(kp)**2)
            alpha = zdota (kp) / temp
            beta = sp / temp
            zdota (kp) = alpha * zdota (k)
            zdota (k) = temp
            do i = 1, n
                temp = alpha * z (i, kp) + beta * z (i, k)
                z (i, kp) = alpha * z (i, k) - beta * z (i, kp)
                z (i, k) = temp
            end do
            iact (k) = kw
            vmultc (k) = vmultc (kp)
            k = kp
            if (k < nact) go to 170
            iact (k) = isave
            vmultc (k) = vsave
        end if
        temp = 0.0_wp
        do i = 1, n
            temp = temp + z (i, nact) * a (i, kk)
        end do
        if (temp == 0.0_wp) go to 490
        zdota (nact) = temp
        vmultc (icon) = 0.0_wp
        vmultc (nact) = ratio
!
!     Update IACT and ensure that the objective function continues to be
!     treated as the last active constraint when MCON>M.
!
210     iact (icon) = iact (nact)
        iact (nact) = kk
        if (mcon > m .and. kk /= mcon) then
            k = nact - 1
            sp = 0.0_wp
            do i = 1, n
                sp = sp + z (i, k) * a (i, kk)
            end do
            temp = sqrt (sp*sp+zdota(nact)**2)
            alpha = zdota (nact) / temp
            beta = sp / temp
            zdota (nact) = alpha * zdota (k)
            zdota (k) = temp
            do i = 1, n
                temp = alpha * z (i, nact) + beta * z (i, k)
                z (i, nact) = alpha * z (i, k) - beta * z (i, nact)
                z (i, k) = temp
            end do
            iact (nact) = iact (k)
            iact (k) = kk
            temp = vmultc (k)
            vmultc (k) = vmultc (nact)
            vmultc (nact) = temp
        end if
!
!     If stage one is in progress, then set SDIRN to the direction of the next
!     change to the current vector of variables.
!
        if (mcon > m) go to 320
        kk = iact (nact)
        temp = 0.0_wp
        do i = 1, n
            temp = temp + sdirn (i) * a (i, kk)
        end do
        temp = temp - 1.0_wp
        temp = temp / zdota (nact)
        do i = 1, n
            sdirn (i) = sdirn (i) - temp * z (i, nact)
        end do
        go to 340
!
!     Delete the constraint that has the index IACT(ICON) from the active set.
!
260     if (icon < nact) then
            isave = iact (icon)
            vsave = vmultc (icon)
            k = icon
270         kp = k + 1
            kk = iact (kp)
            sp = 0.0_wp
            do i = 1, n
                sp = sp + z (i, k) * a (i, kk)
            end do
            temp = sqrt (sp*sp+zdota(kp)**2)
            alpha = zdota (kp) / temp
            beta = sp / temp
            zdota (kp) = alpha * zdota (k)
            zdota (k) = temp
            do i = 1, n
                temp = alpha * z (i, kp) + beta * z (i, k)
                z (i, kp) = alpha * z (i, k) - beta * z (i, kp)
                z (i, k) = temp
            end do
            iact (k) = kk
            vmultc (k) = vmultc (kp)
            k = kp
            if (k < nact) go to 270
            iact (k) = isave
            vmultc (k) = vsave
        end if
        nact = nact - 1
!
!     If stage one is in progress, then set SDIRN to the direction of the next
!     change to the current vector of variables.
!
        if (mcon > m) go to 320
        temp = 0.0_wp
        do i = 1, n
            temp = temp + sdirn (i) * z (i, nact+1)
        end do
        do i = 1, n
            sdirn (i) = sdirn (i) - temp * z (i, nact+1)
        end do
        go to 340
!
!     Pick the next search direction of stage two.
!
320     temp = 1.0_wp / zdota (nact)
        do i = 1, n
            sdirn (i) = temp * z (i, nact)
        end do
!
!     Calculate the step to the boundary of the trust region or take the step
!     that reduces RESMAX to zero. The two statements below that include the
!     factor 1.0E-6 prevent some harmless underflows that occurred in a test
!     calculation. Further, we skip the step if it could be zero within a
!     reasonable tolerance for computer rounding errors.
!
340     dd = rho * rho
        sd = 0.0_wp
        ss = 0.0_wp
        do i = 1, n
            if (abs(dx(i)) >= 1.0e-6_wp*rho) dd = dd - dx (i) ** 2
            sd = sd + dx (i) * sdirn (i)
            ss = ss + sdirn (i) ** 2
        end do
        if (dd <= 0.0_wp) go to 490
        temp = sqrt (ss*dd)
        if (abs(sd) >= 1.0e-6_wp*temp) temp = sqrt (ss*dd+sd*sd)
        stpful = dd / (temp+sd)
        step = stpful
        if (mcon == m) then
            acca = step + 0.1_wp * resmax
            accb = step + 0.2_wp * resmax
            if (step >= acca .or. acca >= accb) go to 480
            step = min (step, resmax)
        end if
!
!     Set DXNEW to the new variables if STEP is the steplength, and reduce
!     RESMAX to the corresponding maximum residual if stage one is being done.
!     Because DXNEW will be changed during the calculation of some Lagrange
!     multipliers, it will be restored to the following value later.
!
        do i = 1, n
            dxnew (i) = dx (i) + step * sdirn (i)
        end do
        if (mcon == m) then
            resold = resmax
            resmax = 0.0_wp
            do k = 1, nact
                kk = iact (k)
                temp = b (kk)
                do i = 1, n
                    temp = temp - a (i, kk) * dxnew (i)
                end do
                resmax = max (resmax, temp)
            end do
        end if
!
!     Set VMULTD to the VMULTC vector that would occur if DX became DXNEW. A
!     device is included to force VMULTD(K)=0.0 if deviations from this value
!     can be attributed to computer rounding errors. First calculate the new
!     Lagrange multipliers.
!
        k = nact
390     zdotw = 0.0_wp
        zdwabs = 0.0_wp
        do i = 1, n
            temp = z (i, k) * dxnew (i)
            zdotw = zdotw + temp
            zdwabs = zdwabs + abs (temp)
        end do
        acca = zdwabs + 0.1_wp * abs (zdotw)
        accb = zdwabs + 0.2_wp * abs (zdotw)
        if (zdwabs >= acca .or. acca >= accb) zdotw = 0.0_wp
        vmultd (k) = zdotw / zdota (k)
        if (k >= 2) then
            kk = iact (k)
            do i = 1, n
                dxnew (i) = dxnew (i) - vmultd (k) * a (i, kk)
            end do
            k = k - 1
            go to 390
        end if
        if (mcon > m) vmultd (nact) = max (0.0_wp, vmultd(nact))
!
!     Complete VMULTC by finding the new constraint residuals.
!
        do i = 1, n
            dxnew (i) = dx (i) + step * sdirn (i)
        end do
        if (mcon > nact) then
            kl = nact + 1
            do k = kl, mcon
                kk = iact (k)
                sum = resmax - b (kk)
                sumabs = resmax + abs (b(kk))
                do i = 1, n
                    temp = a (i, kk) * dxnew (i)
                    sum = sum + temp
                    sumabs = sumabs + abs (temp)
                end do
                acca = sumabs + 0.1_wp * abs (sum)
                accb = sumabs + 0.2_wp * abs (sum)
                if (sumabs >= acca .or. acca >= accb) sum = 0.0_wp
                vmultd (k) = sum
            end do
        end if
!
!     Calculate the fraction of the step from DX to DXNEW that will be taken.
!
        ratio = 1.0_wp
        icon = 0
        do k = 1, mcon
            if (vmultd(k) < 0.0_wp) then
                temp = vmultc (k) / (vmultc(k)-vmultd(k))
                if (temp < ratio) then
                    ratio = temp
                    icon = k
                end if
            end if
        end do
!
!     Update DX, VMULTC and RESMAX.
!
        temp = 1.0_wp - ratio
        do i = 1, n
            dx (i) = temp * dx (i) + ratio * dxnew (i)
        end do
        do k = 1, mcon
            vmultc (k) = max (0.0_wp, temp*vmultc(k)+ratio*vmultd(k))
        end do
        if (mcon == m) resmax = resold + ratio * (resmax-resold)
!
!     If the full step is not acceptable then begin another iteration.
!     Otherwise switch to stage two or end the calculation.
!
        if (icon > 0) go to 70
        if (step == stpful) return
480     mcon = m + 1
        icon = mcon
        iact (mcon) = mcon
        vmultc (mcon) = 0.0_wp
        go to 60
!
!     We employ any freedom that may be available to reduce the objective
!     function before returning a DX whose length is less than RHO.
!
490     if (mcon == m) go to 480
        ifull = 0

    end subroutine trstlp

!*****************************************************************************************
!>
!  Test routine for [[cobyla]].
!
!  From: Report DAMTP 1992/NA5.

    subroutine cobyla_test ()

        implicit none

        real(wp),dimension(10) :: x,xopt
        integer :: nprob,n,m,i,icase,iprint,maxfun
        real(wp) :: rhobeg,rhoend,temp,tempa,tempb,tempc,tempd

        do nprob = 1, 10

            if (nprob == 1) then
    !
    !     minimization of a simple quadratic function of two variables.
    !
                print 10
10              format (/ 7 x, 'Output from test problem 1 (Simple quadratic)')
                n = 2
                m = 0
                xopt (1) = - 1.0_wp
                xopt (2) = 0.0_wp

            else if (nprob == 2) then
    !
    !     Easy two dimensional minimization in unit circle.
    !
                print 20
20              format (/ 7 x, 'Output from test problem 2 (2D unit circle ',&
                'calculation)')
                n = 2
                m = 1
                xopt (1) = sqrt (0.5_wp)
                xopt (2) = - xopt (1)

            else if (nprob == 3) then
    !
    !     Easy three dimensional minimization in ellipsoid.
    !
                print 30
30              format (/ 7 x, 'Output from test problem 3 (3D ellipsoid ',&
                'calculation)')
                n = 3
                m = 1
                xopt (1) = 1.0_wp / sqrt (3.0_wp)
                xopt (2) = 1.0_wp / sqrt (6.0_wp)
                xopt (3) = - 1.0_wp / 3.0_wp

            else if (nprob == 4) then
    !
    !     Weak version of Rosenbrock's problem.
    !
                print 40
40              format (/ 7 x, 'Output from test problem 4 (Weak Rosenbrock)')
                n = 2
                m = 0
                xopt (1) = - 1.0_wp
                xopt (2) = 1.0_wp

            else if (nprob == 5) then
    !
    !     Intermediate version of Rosenbrock's problem.
    !
                print 50
50              format (/ 7 x, 'Output from test problem 5 (Intermediate ', 'Rosenbrock)')
                n = 2
                m = 0
                xopt (1) = - 1.0_wp
                xopt (2) = 1.0_wp

            else if (nprob == 6) then
    !
    !     This problem is taken from Fletcher's book Practical Methods of
    !     Optimization and has the equation number (9.1.15).
    !
                print 60
60              format (/ 7 x, 'Output from test problem 6 (Equation ',&
                '(9.1.15) in Fletcher)')
                n = 2
                m = 2
                xopt (1) = sqrt (0.5_wp)
                xopt (2) = xopt (1)

            else if (nprob == 7) then
    !
    !     This problem is taken from Fletcher's book Practical Methods of
    !     Optimization and has the equation number (14.4.2).
    !
                print 70
70              format (/ 7 x, 'Output from test problem 7 (Equation ',&
                '(14.4.2) in Fletcher)')
                n = 3
                m = 3
                xopt (1) = 0.0_wp
                xopt (2) = - 3.0_wp
                xopt (3) = - 3.0_wp

            else if (nprob == 8) then
    !
    !     This problem is taken from page 66 of Hock and Schittkowski's book Test
    !     Examples for Nonlinear Programming Codes. It is their test problem Number
    !     43, and has the name Rosen-Suzuki.
    !
                print 80
80              format (/ 7 x, 'Output from test problem 8 (Rosen-Suzuki)')
                n = 4
                m = 3
                xopt (1) = 0.0_wp
                xopt (2) = 1.0_wp
                xopt (3) = 2.0_wp
                xopt (4) = - 1.0_wp

            else if (nprob == 9) then
    !
    !     This problem is taken from page 111 of Hock and Schittkowski's
    !     book Test Examples for Nonlinear Programming Codes. It is their
    !     test problem Number 100.
    !
                print 90
90              format (/ 7 x, 'Output from test problem 9 (Hock and ',&
                'Schittkowski 100)')
                n = 7
                m = 4
                xopt (1) = 2.330499_wp
                xopt (2) = 1.951372_wp
                xopt (3) = - 0.4775414_wp
                xopt (4) = 4.365726_wp
                xopt (5) = - 0.624487_wp
                xopt (6) = 1.038131_wp
                xopt (7) = 1.594227_wp

            else if (nprob == 10) then
    !
    !     This problem is taken from page 415 of Luenberger's book Applied
    !     Nonlinear Programming. It is to maximize the area of a hexagon of
    !     unit diameter.
    !
                print 100
100             format (/ 7 x, 'Output from test problem 10 (Hexagon area)')
                n = 9
                m = 14
            end if
            do icase = 1, 2
                do i = 1, n
                    x (i) = 1.0_wp
                end do
                rhobeg = 0.5_wp
                rhoend = 0.001_wp
                if (icase == 2) rhoend = 0.0001_wp
                iprint = 1
                maxfun = 2000
                call cobyla (n, m, x, rhobeg, rhoend, iprint, maxfun, calcfc)
                if (nprob == 10) then
                    tempa = x (1) + x (3) + x (5) + x (7)
                    tempb = x (2) + x (4) + x (6) + x (8)
                    tempc = 0.5_wp / sqrt (tempa*tempa+tempb*tempb)
                    tempd = tempc * sqrt (3.0_wp)
                    xopt (1) = tempd * tempa + tempc * tempb
                    xopt (2) = tempd * tempb - tempc * tempa
                    xopt (3) = tempd * tempa - tempc * tempb
                    xopt (4) = tempd * tempb + tempc * tempa
                    do i = 1, 4
                        xopt (i+4) = xopt (i)
                    end do
                    xopt (9) = 0.0_wp
                end if
                temp = 0.0_wp
                do i = 1, n
                    temp = temp + (x(i)-xopt(i)) ** 2
                end do
                print 150, sqrt (temp)
150             format (/ 5 x, 'Least squares error in variables =', 1 pe16.6)
            end do
            print 170
170         format (2 x, '----------------------------------------------',&
            '--------------------')

        end do

    contains

        subroutine calcfc (n, m, x, f, con)

            implicit none

            integer,intent(in)                :: n
            integer,intent(in)                :: m
            real(wp),dimension(*),intent(in)  :: x
            real(wp),intent(out)              :: f
            real(wp),dimension(*),intent(out) :: con

            if (nprob == 1) then
    !
    !     Test problem 1 (Simple quadratic)
    !
                f = 10.0_wp * (x(1)+1.0_wp) ** 2 + x (2) ** 2

            else if (nprob == 2) then
    !
    !    Test problem 2 (2D unit circle calculation)
    !
                f = x (1) * x (2)
                con (1) = 1.0_wp - x (1) ** 2 - x (2) ** 2

            else if (nprob == 3) then
    !
    !     Test problem 3 (3D ellipsoid calculation)
    !
                f = x (1) * x (2) * x (3)
                con (1) = 1.0_wp - x (1) ** 2 - 2.0_wp * x (2) ** 2 - 3.0_wp * x (3) ** 2

            else if (nprob == 4) then
    !
    !     Test problem 4 (Weak Rosenbrock)
    !
                f = (x(1)**2-x(2)) ** 2 + (1.0_wp+x(1)) ** 2

            else if (nprob == 5) then
    !
    !     Test problem 5 (Intermediate Rosenbrock)
    !
                f = 10.0_wp * (x(1)**2-x(2)) ** 2 + (1.0_wp+x(1)) ** 2

            else if (nprob == 6) then
    !
    !     Test problem 6 (Equation (9.1.15) in Fletcher's book)
    !
                f = - x (1) - x (2)
                con (1) = x (2) - x (1) ** 2
                con (2) = 1.0_wp - x (1) ** 2 - x (2) ** 2

            else if (nprob == 7) then
    !
    !     Test problem 7 (Equation (14.4.2) in Fletcher's book)
    !
                f = x (3)
                con (1) = 5.0_wp * x (1) - x (2) + x (3)
                con (2) = x (3) - x (1) ** 2 - x (2) ** 2 - 4.0_wp * x (2)
                con (3) = x (3) - 5.0_wp * x (1) - x (2)

            else if (nprob == 8) then
    !
    !     Test problem 8 (Rosen-Suzuki)
    !
                f = x (1) ** 2 + x (2) ** 2 + 2.0_wp * x (3) ** 2 + x (4) ** 2 - 5.0_wp * &
               & x (1) - 5.0_wp * x (2) - 21.0_wp * x (3) + 7.0_wp * x (4)
                con (1) = 8.0_wp - x (1) ** 2 - x (2) ** 2 - x (3) ** 2 - x (4) ** 2 - x &
               & (1) + x (2) - x (3) + x (4)
                con (2) = 10.0_wp - x (1) ** 2 - 2.0_wp * x (2) ** 2 - x (3) ** 2 - &
               & 2.0_wp * x (4) ** 2 + x (1) + x (4)
                con (3) = 5.0_wp - 2.0_wp * x (1) ** 2 - x (2) ** 2 - x (3) ** 2 - 2.0_wp &
               & * x (1) + x (2) + x (4)

            else if (nprob == 9) then
    !
    !     Test problem 9 (Hock and Schittkowski 100)
    !
                f = (x(1)-10.0_wp) ** 2 + 5.0_wp * (x(2)-12.0_wp) ** 2 + x (3) ** 4 + &
               & 3.0_wp * (x(4)-11.0_wp) ** 2 + 10.0_wp * x (5) ** 6 + 7.0_wp * x (6) ** &
               & 2 + x (7) ** 4 - 4.0_wp * x (6) * x (7) - 10.0_wp * x (6) - 8.0_wp * x &
               & (7)
                con (1) = 127.0_wp - 2.0_wp * x (1) ** 2 - 3.0_wp * x (2) ** 4 - x (3) - &
               & 4.0_wp * x (4) ** 2 - 5.0_wp * x (5)
                con (2) = 282.0_wp - 7.0_wp * x (1) - 3.0_wp * x (2) - 10.0_wp * x (3) ** &
               & 2 - x (4) + x (5)
                con (3) = 196.0_wp - 23.0_wp * x (1) - x (2) ** 2 - 6.0_wp * x (6) ** 2 + &
               & 8.0_wp * x (7)
                con (4) = - 4.0_wp * x (1) ** 2 - x (2) ** 2 + 3.0_wp * x (1) * x (2) - &
               & 2.0_wp * x (3) ** 2 - 5.0_wp * x (6) + 11.0_wp * x (7)

            else if (nprob == 10) then
    !
    !     Test problem 10 (Hexagon area)
    !
                f = - 0.5_wp * &
                   (x(1)*x(4)-x(2)*x(3)+x(3)*x(9)-x(5)*x(9)+x(5)*x(8)-x(6)*x(7))
                con (1) = 1.0_wp - x (3) ** 2 - x (4) ** 2
                con (2) = 1.0_wp - x (9) ** 2
                con (3) = 1.0_wp - x (5) ** 2 - x (6) ** 2
                con (4) = 1.0_wp - x (1) ** 2 - (x(2)-x(9)) ** 2
                con (5) = 1.0_wp - (x(1)-x(5)) ** 2 - (x(2)-x(6)) ** 2
                con (6) = 1.0_wp - (x(1)-x(7)) ** 2 - (x(2)-x(8)) ** 2
                con (7) = 1.0_wp - (x(3)-x(5)) ** 2 - (x(4)-x(6)) ** 2
                con (8) = 1.0_wp - (x(3)-x(7)) ** 2 - (x(4)-x(8)) ** 2
                con (9) = 1.0_wp - x (7) ** 2 - (x(8)-x(9)) ** 2
                con (10) = x (1) * x (4) - x (2) * x (3)
                con (11) = x (3) * x (9)
                con (12) = - x (5) * x (9)
                con (13) = x (5) * x (8) - x (6) * x (7)
                con (14) = x (9)

            end if

        end subroutine calcfc

    end subroutine cobyla_test
!*****************************************************************************************

end module cobyla_module