sp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1994 by Lieven Vandenberghe and Stephen Boyd.
00003  * Permission to use, copy, modify, and distribute this software for 
00004  * any purpose without fee is hereby granted, provided that this entire 
00005  * notice is included in all copies of any software which is or includes
00006  * a copy or modification of this software and in all copies of the 
00007  * supporting documentation for such software.
00008  * This software is being provided "as is", without any express or 
00009  * implied warranty.  In particular, the authors do not make any
00010  * representation or warranty of any kind concerning the merchantability
00011  * of this software or its fitness for any particular purpose.
00012  */
00013  
00014 #include <stdio.h> 
00015 #include <math.h>
00016 #include <string.h>
00017 #include "spd.h"
00018 
00019 #ifdef _MSC_VER 
00020 extern void Scistring (char *str);
00021 #endif
00022 
00023 void cngrncb(itype,n,AP,B,CP,temp)
00024  int itype;
00025  int n;
00026  double *AP;
00027  double *B;
00028  double *CP;
00029  double *temp;
00030 
00031 /* 
00032  * if itype = 1, computes C = B*A*B', otherwise, computes C = B'*A*B 
00033  * A and B are nxn with A symmetric.
00034  *
00035  * Arguments:
00036  * - itype  = 1: compute C = B*A*B'
00037  *          = any other integer: computes C = B'*A*B
00038  * - n      dimension of A and B
00039  * - AP     (input) double array of size n*(n+1)2;
00040  *          the lower triangle of A in packed storage
00041  * - B      (input) double array of size n*n;
00042  * - CP     (output) double array of size n*(n+1)/2; 
00043  *          the lower triangle of C in packed storage
00044  * - temp:  n-array, workspace
00045  */
00046 
00047 
00048 {
00049  int j, pos, lngth = n*(n+1)/2;
00050  int int1=1;
00051  double dbl0=0.0, dbl1=1.0; 
00052 
00053  /* C := 0 */
00054  F2C(dscal)(&lngth, &dbl0, CP, &int1);
00055 
00056  if (itype == 1){
00057 
00058    for (j=0, pos=0;  j<n;  pos+=n-j, j++){
00059 
00060       /* temp = A*B(j,:)' */
00061       F2C(dspmv)("L", &n, &dbl1, AP, B+j, &n, &dbl0, temp, &int1);
00062 
00063       /* C(j:n,j) = B(j:n,:)*temp */
00064       lngth = n-j;
00065       F2C(dgemv)("N", &lngth, &n, &dbl1, B+j, &n, temp, &int1, &dbl0,
00066              CP+pos, &int1);
00067 
00068    }
00069 
00070  } else {
00071  
00072    for (j=0, pos=0;  j<n;  pos+=n-j, j++){
00073 
00074       /* temp = A*B(:,j) */
00075       F2C(dspmv)("L", &n, &dbl1, AP, B+j*n, &int1, &dbl0, temp, &int1);
00076 
00077       /* C(j:n,j) = B(:,j:n)'*temp */
00078       lngth = n-j;
00079       F2C(dgemv)("T", &n, &lngth, &dbl1, B+j*n, &n, temp, &int1, &dbl0,
00080              CP+pos, &int1);
00081 
00082    }
00083  } 
00084  
00085 }
00086 
00087 
00088 double inprd(X,Z,L,blck_szs)
00089  double *X;
00090  double *Z;
00091  int L;
00092  int *blck_szs;
00093 
00094 /*
00095  * Computes Tr X*Z
00096  *
00097  * Arguments:
00098  * X,Z:       block diagonal matrices with L blocks X^0, ..., X^{L-1},
00099  *            and Z^0, ..., Z^{L-1}.  X^j and Z^j have size 
00100  *            blck_szs[j] times blck_szs[j].  Every block is stored 
00101  *            using packed storage of the lower triangle.
00102  * L:         number of blocks
00103  * blck_szs:  integer vector of length L 
00104  *            blck_szs[i], i=0,...,L-1 is the size of block i
00105  *
00106  */
00107 
00108 {
00109  double result;
00110  int i, j, k, lngth, pos, sz, int1=1;
00111  
00112  /* sz = length of Z and X */  
00113  for (i=0, sz=0;  i<L;  i++)  sz += (blck_szs[i]*(blck_szs[i]+1))/2;
00114 
00115  /* result = Tr X Z + contributions of diagonal elements */
00116  result = 2.0*F2C(ddot)(&sz, X, &int1, Z, &int1);
00117 
00118  /* correct for diagonal elements 
00119   * loop over blocks, j=0,...,L-1  */
00120  for (j=0, pos=0;  j<L;  j++)
00121 
00122     /* loop over columns, k=0,...,blck_szs[j]-1 
00123      * pos is position of (k,k) element of block j 
00124      * lngth is length of column k */
00125     for (k=0, lngth=blck_szs[j];  k<blck_szs[j];  pos+=lngth, 
00126          lngth-=1, k++) 
00127     
00128        /* subtract Z^j_{kk}*X^j_{kk} from result */
00129        result -= Z[pos]*X[pos];
00130 
00131  return result;
00132 }
00133 
00134 int C2F(spf)(m,L,F,blck_szs,c,x,Z,ul,nu,abstol,reltol,tv,iters, 
00135              work,lwork,iwork,info)
00136  int *m;                /* no of variables */
00137  int *L;                /* no of blocks in F */
00138  double *F;            /* F_i's in packed storage */
00139  int *blck_szs;        /* L-vector, dimensions of diagonal blocks */
00140  double *c;            /* m-vector */
00141  double *x;            /* m-vector */
00142  double *Z;            /* block diagonal matrix in packed storage */
00143  double *ul;           /* ul[0] = pr. obj, ul[1] = du. obj */ 
00144  double *nu;            /* >= 1.0 */
00145  double *abstol;        /* absolute accuracy */
00146  double *reltol;        /* relative accuracy */
00147  double *tv;            /* target value */ 
00148  int *iters;           /* on entry: the maximum number of iterations,
00149                         * on exit: the number of iterations taken */
00150  double *work;         /* work array */
00151  int *lwork;            /* size of work */
00152  int *iwork;           /* work array of m integers */
00153  int *info;            /* status on termination */
00154 {
00155  return(sp(*m,*L,F,blck_szs,c,x,Z,ul,*nu,*abstol,*reltol,*tv,iters, work,
00156            *lwork,iwork,info));
00157 }
00158 
00159 int sp(m,L,F,blck_szs,c,x,Z,ul,nu,abstol,reltol,tv,iters,work,
00160        lwork,iwork,info)
00161 
00162  int m;                /* no of variables */
00163  int L;                /* no of blocks in F */
00164  double *F;            /* F_i's in packed storage */
00165  int *blck_szs;        /* L-vector, dimensions of diagonal blocks */
00166  double *c;            /* m-vector */
00167  double *x;            /* m-vector */
00168  double *Z;            /* block diagonal matrix in packed storage */
00169  double *ul;           /* ul[0] = pr. obj, ul[1] = du. obj */ 
00170  double nu;            /* >= 1.0 */
00171  double abstol;        /* absolute accuracy */
00172  double reltol;        /* relative accuracy */
00173  double tv;            /* target value */ 
00174  int *iters;           /* on entry: the maximum number of iterations,
00175                         * on exit: the number of iterations taken */
00176  double *work;         /* work array */
00177  int lwork;            /* size of work */
00178  int *iwork;           /* work array of m integers */
00179  int *info;             /* status on termination */
00180 
00181 /*
00182  * Solves semidefinite program 
00183  *
00184  *  minimize    c'*x 
00185  *  subject to  F_0 + x_1*F_1 + ... + x_m*F_m  >= 0
00186  * 
00187  * and its dual
00188  * 
00189  *  maximize    -Tr F_0*Z 
00190  *  subject to  Z >= 0
00191  *              Tr F_i*Z = c_i, i=1,...,m
00192  *
00193  *
00194  * Convergence criteria: 
00195  * (1) maxiters is exceeded
00196  * (2) duality gap is less than abstol 
00197  * (3) primal and dual objective are both positive and 
00198  *     duality gap is less than reltol * dual objective         
00199  *     or primal and dual objective are both negative and
00200  *     duality gap is less than reltol * minus the primal objective
00201  * (4) reltol is negative and primal objective is less than tv 
00202  * (5) reltol is negative and dual objective is greater than tv
00203  * 
00204  * Arguments:
00205  * - m:        number of variables x_i. m >= 1.
00206  * - L:        number of diagonal blocks in F_i. L >= 1.
00207  * - F:        the block diagonal matrices F_i, i=0,...,m. 
00208  *             it is assumed that the matrices F_i are linearly 
00209  *             independent. 
00210  *             let F_i^j, i=0,..,m, j=0,...,L-1 denote the jth 
00211  *             diagonal block of F_i, 
00212  *             the array F contains F_0^0, ..., F_0^{L-1}, F_1^0, ..., 
00213  *             F_1^{L-1}, ..., F_m^0, ..., F_m^{L-1}, in this order, 
00214  *             using packed storage for the lower triangular part of 
00215  *             F_i^j.
00216  * - blck_szs: an integer L-vector. blck_szs[j], j=0,....L-1 gives the 
00217  *             size of block j, ie, F_i^j has size blck_szs[j] 
00218  *             times blck_szs[j].
00219  * - c:        m-vector, primal objective.
00220  * - x:        m-vector.  On entry, a strictly primal feasible point. 
00221  *             On exit, the last iterate for x.
00222  * - Z:        block diagonal matrix with L blocks Z^0, ..., Z^{L-1}.
00223  *             Z^j has size blck_szs[j] times blck_szs[j].
00224  *             Every block is stored using packed storage of the lower 
00225  *             triangular part.
00226  *             On entry, a strictly dual feasible point.  On exit, the 
00227  *             last dual iterate.
00228  * - ul:       two-vector.  On exit, ul[0] is the primal objective value
00229  *             c'*x;  ul[1] is the dual objective value -Tr F_0*Z.
00230  * - nu:       >= 1.0. Controls the rate of convergence.
00231  * - abstol:   absolute tolerance, >= MINABSTOL.
00232  * - reltol:   relative tolerance.  Has a special meaning when negative.
00233  * - tv:       target value, only referenced if reltol < 0.
00234  * - iters:    on entry: maximum number of iterations >= 0,
00235  *             on exit: the number of iterations taken.
00236  * - work:     work array of size lwork.
00237  * - lwork:    size of work, must be at least:
00238  *             (m+2)*sz + up_sz + 2*n + ltemp, with 
00239  *             ltemp = max( m+sz*nb, 3max_n + max_n*(max_n+1), 3*m )
00240  *             (sz: space needed to store one matrix F_i in packed
00241  *             storage, ie, 
00242  *                sum_{j=0}^{L-1} blck_szs[j]*(blck_szs[j]+1)/2;
00243  *             up_sz: space needed to store one matrix F_i in 
00244  *             unpacked storage, ie, 
00245  *                sum_{j=0}^{L-1} blck_szs[j]*blck_szs[j];
00246  *             max_n: max block size;
00247  *             n: sum of the block sizes.
00248  *             nb >= 1, for best performance, nb should be at least
00249  *             equal to the optimal block size for dgels.
00250  * - iwork:    work array of m integers
00251  * - info:     returns 1 if maxiters exceeded,  2 if absolute accuracy
00252  *             is reached, 3 if relative accuracy is reached,
00253  *             4 if target value is reached, 5 if target value is
00254  *             not achievable; 
00255  *             negative values indicate errors: -i means argument i 
00256  *             has an illegal value, -18 stands for all other errors.
00257  *
00258  *         
00259  * Returns 0 for normal exit, 1 if an error occurred.
00260  *
00261  */
00262  
00263 
00264 {
00265  int i, j, k, n, sz, up_sz, max_n, lngth, pos, pos2, pos3, pos4, ltemp, 
00266      maxiters, info2, minlwork; 
00267  double q, *rhs, *Fsc, *R, *X, rho, *dx, *sigx, *sigz, *dZ, *temp, scal,
00268         scal2, XdZ, ZdX, alphax, alphaz, lambda_ls, gradx, hessx,
00269         gradz, hessz, dalphax, dalphaz, gap, newgap=0.0, newu=0.0, 
00270         newl=0.0, maxpossigx, minnegsigx, maxpossigz, minnegsigz, nrmc,
00271         nrmx, nrmz, nrmmax, rcond; 
00272  int int2=2, int1=1;  
00273  double dbl1=1.0, dbl0=0.0, sqrt2=sqrt(2.0);
00274  char str[100];
00275  double dbl_epsilon;
00276 
00277  if (m < 1){
00278     sprintf(str, "m must be at least one. \n");
00279     Scistring(str);
00280     *info = -1;
00281     return 1;
00282  }
00283  if (L < 1){
00284     sprintf(str, "L must be at least one. \n");
00285     Scistring(str);
00286     *info = -2;
00287     return 1;
00288  }
00289  for (i=0; i<L; i++) if (blck_szs[i] < 1){
00290     sprintf(str, "blck_szs[%d] must be at least one.\n", i);
00291     Scistring(str);
00292     *info = -4;
00293     return 1;
00294  }
00295  if (nu < 1.0){
00296     sprintf(str, "nu must be at least 1.0. \n");
00297     Scistring(str);
00298     *info = -9;
00299     return 1;
00300  }
00301  
00302 
00303  /*
00304   * calculate dimensions:
00305   * n:      total size of semidefinite program
00306   * sz:     length of one block-diagonal matrix in packed storage
00307   * up_sz:  length of one block-diagonal matrix in unpacked storage
00308   * max_n:  size of biggest block
00309   */
00310 
00311  for (i=0, n=0, sz=0, up_sz=0, max_n=0;  i<L;  i++){
00312     n     += blck_szs[i];
00313     sz    += blck_szs[i]*(blck_szs[i]+1)/2;
00314     up_sz += blck_szs[i]*blck_szs[i];
00315     max_n  = MAX(max_n, blck_szs[i]);
00316  } 
00317  if (m > sz){
00318      sprintf(str, "The matrices Fi, i=1,...,m are linearly dependent.\n");
00319      Scistring(str);
00320     *info = -3;  return 1;
00321  }
00322 
00323  q = (double)n + nu*sqrt((double)n); 
00324 
00325 
00326  /*
00327   * check if Tr Fi*Z = c_i, i=1,...,m
00328   */
00329 
00330  nrmc = F2C(dnrm2)(&m, c, &int1);
00331  for (i=0; i<m; i++) 
00332  if (fabs(inprd(F+(i+1)*sz, Z, L, blck_szs) - c[i]) > nrmc*TOLC){
00333      sprintf(str, "Z0 does not satisfy equality conditions\
00334  for dual feasibility.\n");
00335      Scistring(str);
00336     *info = -7;
00337     return 1;
00338  }
00339 
00340 
00341  /*
00342   * organize workspace
00343   *
00344   * work:  (m+2)*sz + up_sz + 2*n + ltemp
00345   * minimum ltemp: the maximum of 
00346   *         m+sz*nb, 3*max_n + max_n*(max_n+1), and 3*m  
00347   *         (nb is at least one)
00348   * 
00349   * for dgels:        m + sz*nb, nb at least 1 
00350   * for dspev("N"):   3*max_n + max_n*(max_n+1)
00351   * for dspgv("N"):   3*max_n + max_n*(max_n+1)
00352   * for dspgv("V"):   3*max_n + max_n*(max_n+1)/2  
00353   * for cngrncb:      max_n
00354   * for dtrcon:       3*m
00355   * 
00356   * rhs  (sz):        work[0 ... sz-1] 
00357   * Fsc  (m*sz):      work[sz ... (m+1)*sz-1]
00358   * R    (up_sz):     work[(m+1)*sz ... (m+1)*sz+up_sz-1]
00359   * X    (sz):        work[(m+1)*sz+up_sz ... (m+2)*sz+up_sz-1]
00360   * sigx (n):         work[(m+2)*sz+up_sz ... (m+2)*sz+up_sz+n-1]
00361   * sigz (n):         work[(m+2)*sz+up_sz+n ... (m+2)*sz+up_sz+2*n-1]
00362   * temp (remainder): work[(m+2)*sz+up_sz+2*n ... lwork-1]
00363   */
00364 
00365  /* check lwork */
00366  minlwork = (m+2)*sz + up_sz + 2*n + 
00367             MAX( MAX( m+sz, 3*max_n + max_n*(max_n+1) ), 3*m ); 
00368  if (lwork < minlwork){
00369     sprintf(str, "Work space is too small.  Need at least\
00370  %d*sizeof(double).\n", minlwork);
00371     Scistring(str);
00372     *info = -15;
00373     return 1;
00374  } 
00375 
00376  rhs   = work;        /* rhs for ls problem */
00377  dx    = work;        /* solution of ls system; overlaps with rhs  */
00378  Fsc   = rhs + sz;    /* scaled matrices */
00379  dZ    = rhs + sz;    /* overlaps with first column of Fsc */
00380  R     = Fsc + m*sz;  /* eigenvectors of Z*F */
00381  X     = R + up_sz;   /* F(x) */
00382  sigx  = X + sz;      /* generalized eigenvalues of (dX,X) */
00383  sigz  = sigx + n;    /* generalized eigenvalues of (dZ,Z) */
00384  temp  = sigz + n;
00385  ltemp = lwork - (m+2)*sz - up_sz - 2*n; 
00386 
00387 
00388  maxiters = (*iters >= 0) ? *iters : MAXITERS;
00389  for (*iters=0; *iters <= maxiters; (*iters)++){
00390 
00391 
00392     /* compute F(x) = F_0 + x_1*F_1 + ... + x_m*F_m, store in X */
00393     F2C(dcopy)(&sz, F, &int1, X, &int1);
00394     F2C(dgemv)("N", &sz, &m, &dbl1, F+sz, &sz, x, &int1, &dbl1, X, &int1);
00395 
00396 
00397     /* 
00398      * compute generalized eigendecomp  Z*F*x = lambda*x
00399      * loop over blocks, i=0,...,L-1 
00400      * pos:  position of (0,0) element of block i in packed storage
00401      * pos2: position of (0,0) element of block i in unpacked
00402      *       storage
00403      * pos3: position of first eigenvalue of block i in sigx
00404      */
00405 
00406     for (i=0, pos=0, pos2=0, pos3=0, gap=0.0;  i<L; 
00407          pos += blck_szs[i]*(blck_szs[i]+1)/2, 
00408          pos2 += blck_szs[i]*blck_szs[i], 
00409          pos3 += blck_szs[i], i++){
00410 
00411        lngth = blck_szs[i]*(blck_szs[i]+1)/2;
00412 
00413        /* copy block i of Z in temp (need max_n*(max_n+1)/2) */
00414        F2C(dcopy)(&lngth, Z+pos, &int1, temp, &int1); 
00415 
00416        /* generalized eigenvalue decomposition Z*F*x = lambda*x
00417         * - eigenvectors V are normalized s.t. V^T*F*V = I
00418         * - store block i of V in R+pos2
00419         * - store eigenvalues of block i in sigx+pos3
00420         * - dspgv replaces X+pos by cholesky factor L of ith 
00421         *   block of F (F = L*L^T) 
00422         * use temp+lngth as workspace (need at least 3*max_n) */
00423        F2C(dspgv)(&int2, "V", "L", blck_szs+i, temp, X+pos, sigx+pos3, 
00424               R+pos2, blck_szs+i, temp+lngth, &info2);
00425        if (info2){
00426           sprintf(str,"Error in dspgv, info = %d.\n", info2);
00427           Scistring(str);
00428           if (*iters == 0 && info2 > blck_szs[i]){
00429              sprintf(str, "x0 is not strictly primal feasible.\n");
00430              Scistring(str);
00431              *info = -6;
00432           } else *info = -18;  
00433           return 1;
00434        }
00435 
00436        /* - replace sigx+pos3 by lambda^(1/2)
00437         * - normalize block i of V (stored in R+pos2) s.t. 
00438         *   V^T*F*V = Lambda^(1/2) */
00439        for (k=0; k<blck_szs[i]; k++){
00440           scal = sigx[pos3+k];
00441           if (scal < 0.0){       
00442              if (*iters == 0){ 
00443                 sprintf(str, "Z0 is not positive definite.\n");
00444                 Scistring(str);
00445                 *info = 7;
00446              } else {
00447                 sprintf(str, "F(x)*Z has a negative eigenvalue.\n");
00448                 Scistring(str);
00449                 *info = -18;
00450              }
00451              return 1;
00452           }
00453           gap += scal;    /* duality gap is sum of eigenvalues of ZF */
00454           scal2 = sqrt(scal);
00455           scal = sqrt(scal2);
00456           sigx[pos3+k] = scal2; 
00457           F2C(dscal)(blck_szs+i, &scal, R+pos2+k*blck_szs[i], &int1);
00458        }
00459 
00460     }
00461 
00462 
00463     /* 
00464      * check convergence 
00465      */
00466 
00467     ul[1] = -inprd(F,Z,L,blck_szs);         /* -Tr F_0 Z */
00468     ul[0] = F2C(ddot)(&m, c, &int1, x, &int1);  /* c^T x */
00469     if (*iters == 0){
00470         sprintf(str,"\n    primal obj.  dual obj.  dual. gap  \n");
00471         Scistring(str);
00472     }
00473     sprintf(str,"% 13.2e % 12.2e %10.2e \n", ul[0], ul[1], gap);
00474     Scistring(str);
00475     if (gap <= MAX(abstol, MINABSTOL))  *info = 2;
00476     else if ( (ul[1] > 0.0 && gap <= reltol*ul[1]) ||
00477               (ul[0] < 0.0 && gap <= reltol*(-ul[0])) ) *info = 3;
00478     else if ( reltol < 0.0 && ul[0] <= tv ) *info = 4;
00479     else if ( reltol < 0.0 && ul[1] >= tv ) *info = 5;
00480     else if ( *iters == maxiters ) *info = 1;
00481     else *info = 0;
00482     if (*info) return 0; 
00483 
00484 
00485 
00486     /* 
00487      * compute scaled matrices F 
00488      */
00489 
00490     for (j=0, pos=0;  j<m;  j++) for (i=0, pos2=0;  i<L; 
00491          pos += blck_szs[i]*(blck_szs[i]+1)/2, 
00492          pos2 += blck_szs[i]*blck_szs[i], i++) {
00493 
00494        /* compute R' * Fj(i) * R, store in Fsc+pos */
00495        cngrncb(2, blck_szs[i], F+sz+pos, R+pos2, Fsc+pos, temp);
00496 
00497        /* correct diagonal elements */
00498        for (k=0, pos4=pos;  k<blck_szs[i];  pos4 += blck_szs[i]-k, k++)
00499           Fsc[pos4] /= sqrt2;
00500 
00501     }
00502 
00503 
00504     /* 
00505      * form rhs = Lambda^(-1/2) - (q/gap) * Lambda^(1/2) 
00506      */
00507 
00508     F2C(dscal)(&sz, &dbl0, rhs, &int1);    /* rhs := 0 */
00509     rho = -q/gap;
00510     for (i=0, pos=0, pos3=0;  i<L;  
00511          pos += blck_szs[i]*(blck_szs[i]+1)/2, 
00512          pos3 += blck_szs[i], i++)
00513        for (k=0, pos4=pos;  k<blck_szs[i];  pos4+=blck_szs[i]-k, k++){
00514           scal = sigx[pos3+k];
00515           rhs[pos4] = (1.0/scal + rho*scal)/sqrt2; 
00516     }
00517 
00518 
00519     /*
00520      * solve least-squares problem; need workspace of size m + nb*sz
00521      * - rhs is overwritten by dx
00522      * - in first iteration, estimate condition number of Fsc
00523      */
00524   
00525     F2C(dgels)("N", &sz, &m, &int1, Fsc, &sz, rhs, &sz, temp, &ltemp, 
00526            &info2);
00527     if (info2){
00528        sprintf(str,"Error in dgels, info = %d.\n", info2);
00529        Scistring(str);
00530        *info = -18; return 1;
00531     }
00532 
00533     if (*iters == 0){
00534        
00535        /* estimate the condition number in 1-norm of the R-factor of 
00536         * the qr-decomposition of Fsc (is stored in Fsc) 
00537         * need work space of size 3*m */
00538        F2C(dtrcon)("1", "U", "N", &m, Fsc, &sz, &rcond, temp, iwork, 
00539                 &info2);
00540        if (info2 < 0){
00541           sprintf(str,"Error in dtrcon, info = %d.\n", info2);
00542           Scistring(str);
00543           *info = -18; return 1;
00544        }
00545        if (rcond < MINRCOND) {
00546           sprintf(str,"The matrices F_i, i=1,...,m are linearly\
00547  dependent (or the initial points are very badly conditioned).\n");
00548           Scistring(str);
00549           *info = -3; return 1;
00550        }
00551 
00552     }
00553     
00554 
00555 
00556     /*
00557      * - compute dZ = 
00558      *   R*((q/gap)*Lambda^(1/2) - Lambda^(-1/2) + R^T*dF*R )*R^T
00559      * - compute generalized eigenvalues of (dF, F), store in sigx
00560      * - compute generalized eigenvalues of (dZ, Z), store in sigz
00561      * 
00562      * loop over blocks i=0,...,L-1
00563      * pos:  position of (0,0) element of block i in packed storage
00564      * pos2: position of (0,0) element of block i in unpacked storage 
00565      * pos3: position of first eigenvalue of in sigx and sigz
00566      */
00567 
00568     for (i=0, pos=0, pos2=0, pos3=0;  i<L; 
00569          pos  += blck_szs[i]*(blck_szs[i]+1)/2, 
00570          pos2 += blck_szs[i]*blck_szs[i], 
00571          pos3 += blck_szs[i], i++){
00572 
00573        lngth = blck_szs[i]*(blck_szs[i]+1)/2;
00574 
00575        /* compute ith block of dF = \sum \delta x_i F_i, 
00576         * store in temp */
00577        F2C(dgemv)("N", &lngth, &m, &dbl1, F+sz+pos, &sz, dx, &int1, 
00578               &dbl0, temp, &int1);
00579 
00580        /* scale dF as R'*dF*R, store in temp + lngth */
00581        cngrncb(2, blck_szs[i], temp, R+pos2, temp+lngth, temp+2*lngth);
00582 
00583        /* add (q/gap)*Lambda^(1/2) - Lambda^(-1/2) */
00584        for (k=0, pos4=lngth;  k<blck_szs[i];  pos4+=blck_szs[i]-k, k++)
00585           temp[pos4] -= rho*sigx[pos3+k] + 1.0/sigx[pos3+k];
00586 
00587        /* replace dF in temp by L^{-1}*dF*L^{-T},
00588         * (L: cholesky factor of F, stored in X)
00589         * and compute eigenvalues of L^{-1}*dF*L^{-T}  */
00590        F2C(dspgst)(&int1, "L", blck_szs+i, temp, X+pos, &info2);
00591        if (info2){ 
00592           sprintf(str,"Error in dspst, info = %d.\n", info2);
00593           Scistring(str);
00594           *info = -18;  return 1; 
00595        }
00596        /* temp has to be of size max_n*(max_n+1)+3*max_n */
00597        F2C(dspev)("N", "L", blck_szs+i, temp, sigx+pos3, NULL, &int1,
00598               temp+2*lngth, &info2);
00599        if (info2){
00600            sprintf(str,"Error in dspev, info = %d.\n", info2);
00601            Scistring(str);
00602           *info = -18;  return 1;
00603        }
00604 
00605        /* dZ := R*((q/gap)*Lambda^(1/2) - Lambda^(-1/2) + R'*dF*R)*R' */
00606        cngrncb(1, blck_szs[i], temp+lngth, R+pos2, dZ+pos, 
00607                temp+2*lngth);
00608 
00609        /* copy ith block of dZ to temp */
00610        F2C(dcopy)(&lngth, dZ+pos, &int1, temp, &int1);
00611 
00612        /* copy ith block of Z to temp + lngth */
00613        F2C(dcopy)(&lngth, Z+pos, &int1, temp+lngth, &int1);
00614 
00615        /* sigz: generalized eigenvalues of (dZ,Z)
00616         * required size of temp: 3*max_n + max_n*(max_n+1) */
00617        F2C(dspgv)(&int1, "N", "L", blck_szs+i, temp, temp+lngth, sigz+pos3,
00618               NULL, &int1, temp+2*lngth, &info2);
00619        if (info2){
00620            sprintf(str,"Error in dspgv, info = %d.\n", info2);Scistring(str);
00621           *info = -18;  return 1; 
00622        }
00623 
00624     }
00625     
00626 
00627     /* 
00628      * compute feasible rectangle for plane search
00629      */ 
00630  
00631     maxpossigx = 0.0;  minnegsigx = 0.0;
00632     maxpossigz = 0.0;  minnegsigz = 0.0;
00633     for (i=0; i<n; i++) {
00634        if ( sigx[i] > maxpossigx ) 
00635           maxpossigx = sigx[i];  /* max pos eigenvalue in sigx */
00636        else if ( sigx[i] < minnegsigx ) 
00637           minnegsigx = sigx[i];  /* min neg eigenvalue in sigx */
00638        if ( sigz[i] > maxpossigz ) 
00639           maxpossigz = sigz[i];  /* max pos eigenvalue in sigz */
00640        else if ( sigz[i] < minnegsigz ) 
00641           minnegsigz = sigz[i];  /* min neg eigenvalue in sigz */
00642     }
00643     nrmx = F2C(dnrm2)(&n, sigx, &int1);        /* norm of scaled dx */ 
00644     nrmz = F2C(dnrm2)(&n, sigz, &int1);        /* norm of scaled dZ */
00645     nrmmax = MAX( nrmx, nrmz);
00646 
00647     XdZ = inprd(F,dZ,L,blck_szs);          /* Tr F0*dZ */ 
00648     ZdX = F2C(ddot)(&m, c, &int1, dx, &int1);  /* c^T*dx */ 
00649 
00650 
00651     /*
00652      * check corners of feasible rectangle
00653      */
00654 
00655    dbl_epsilon = F2C(dlamch)("e"); 
00656    if (nrmx > SIGTOL*nrmmax)
00657       if (ZdX < 0.0) 
00658           alphax = (minnegsigx < -dbl_epsilon) ? -1.0/minnegsigx : 0.0;
00659       else 
00660           alphax = (maxpossigx >  dbl_epsilon) ? -1.0/maxpossigx : 0.0;
00661     else alphax = 0.0;
00662     
00663     if (nrmz > SIGTOL*nrmmax)
00664        if (XdZ < 0.0)
00665           alphaz = (minnegsigz < -dbl_epsilon) ? -1.0/minnegsigz : 0.0;
00666        else 
00667           alphaz = (maxpossigz >  dbl_epsilon) ? -1.0/maxpossigz : 0.0;
00668     else alphaz = 0.0;
00669 
00670     newgap = gap + alphax*ZdX + alphaz*XdZ;
00671     newu = ul[0] + alphax*ZdX;
00672     newl = ul[1] - alphaz*XdZ;
00673 
00674     if (newgap <= MAX(abstol, MINABSTOL))  *info = 2;
00675     else if ( (newl > 0.0 && newgap <= reltol*newl) ||
00676               (newu < 0.0 && newgap <= -reltol*newu) ) *info = 3;
00677     else if ( reltol < 0.0 && newu <= tv ) *info = 4;
00678     else if ( reltol < 0.0 && newl >= tv ) *info = 5;
00679     else if ( *iters == maxiters ) *info = 1;
00680     else *info = 0;
00681     
00682     if (*info) {   
00683        F2C(daxpy)(&m, &alphax, dx, &int1, x, &int1);
00684        F2C(daxpy)(&sz, &alphaz, dZ, &int1, Z, &int1);
00685        gap = newgap;  ul[0] = newu;   ul[1] = newl;
00686        sprintf(str,"% 13.2e % 12.2e %10.2e \n", ul[0], ul[1], gap);
00687        Scistring(str);
00688        (*iters)++;
00689        return 0;
00690     }
00691 
00692 
00693     /*
00694      * plane search 
00695      *  minimize   phi(alphax,alphaz) = 
00696      *    q*log(dual_gap + alphax*c^T*dx + alphaz* Tr F_0 dZ)
00697      *  - sum log (1+alphax*sigx_i) - sum log (1+alphaz*sigz)
00698      */
00699 
00700     alphax = 0.0;  alphaz = 0.0;  lambda_ls = 1.0;
00701 
00702     if (nrmx > SIGTOL*nrmmax)
00703        if (nrmz > SIGTOL*nrmmax)    /* compute primal and dual steps */
00704           while ( lambda_ls > 1e-4 ) {
00705 
00706              /* compute 1st and 2nd derivatives of phi */
00707              rho = q/(gap + alphax*ZdX + alphaz*XdZ);
00708              gradx = rho*ZdX;  hessx = 0.0;
00709              gradz = rho*XdZ;  hessz = 0.0;
00710              for (i=0; i<n; i++){
00711                 gradx -= sigx[i] / (1.0+alphax*sigx[i]);
00712                 hessx += SQR( sigx[i] / (1.0+alphax*sigx[i]) );
00713                 gradz -= sigz[i] / (1.0+alphaz*sigz[i]);
00714                 hessz += SQR( sigz[i] / (1.0+alphaz*sigz[i]) );
00715              }
00716 
00717              /* newton step */
00718              dalphax = -gradx/hessx;  dalphaz = -gradz/hessz;
00719              lambda_ls = sqrt( SQR(gradx)/hessx + SQR(gradz)/hessz ); 
00720              alphax += (lambda_ls > 0.25) ? 
00721                        dalphax/(1.0+lambda_ls) : dalphax;
00722              alphaz += (lambda_ls > 0.25) ? 
00723                        dalphaz/(1.0+lambda_ls) : dalphaz;
00724 
00725          }
00726          
00727        else while ( lambda_ls > 1e-4 ) {  /* primal step only */
00728 
00729              /* compute 1st and 2nd derivatives of phi */
00730              rho = q/(gap + alphax*ZdX);
00731              gradx = rho*ZdX;  hessx = 0.0;
00732              for (i=0; i<n; i++){
00733                 gradx -= sigx[i] / (1.0+alphax*sigx[i]);
00734                 hessx += SQR( sigx[i] / (1.0+alphax*sigx[i]) );
00735              }
00736 
00737              /* newton step */
00738              dalphax = -gradx/hessx;
00739              lambda_ls = fabs(gradx)/sqrt(hessx);
00740              alphax += (lambda_ls > 0.25) ? 
00741                        dalphax/(1.0+lambda_ls) : dalphax;
00742 
00743        }
00744 
00745        else if (nrmz > SIGTOL*nrmmax)        /* dual step only */
00746           while ( lambda_ls > 1e-4 ) {
00747 
00748              /* compute 1st and 2nd derivatives of phi */
00749              rho = q/(gap + alphaz*XdZ);
00750              gradz = rho*XdZ;  hessz = 0.0;
00751              for (i=0; i<n; i++){
00752                 gradz -= sigz[i] / (1.0+alphaz*sigz[i]);
00753                 hessz += SQR( sigz[i] / (1.0+alphaz*sigz[i]) );
00754              }
00755        
00756              /* newton step */
00757              dalphaz = -gradz/hessz;
00758              lambda_ls = fabs(gradz)/sqrt(hessz);
00759              alphaz += (lambda_ls > 0.25) ? 
00760                        dalphaz/(1.0+lambda_ls) : dalphaz;
00761         }
00762     
00763 
00764 
00765     /* update x and Z */
00766     F2C(daxpy)(&m, &alphax, dx, &int1, x, &int1);
00767     F2C(daxpy)(&sz, &alphaz, dZ, &int1, Z, &int1);
00768 
00769  }
00770  
00771  return -1;   /* should never happen */
00772 }
00773 

Generated on Sun Mar 4 15:03:58 2007 for Scilab [trunk] by  doxygen 1.5.1