/************************************************************************* This function calculates inexact rank-K preconditioner for Hessian matrix H=D+W'*C*W, where: * H is a Hessian matrix, which is approximated by D/W/C * D is a diagonal matrix with positive entries * W is a rank-K correction * C is a diagonal factor of rank-K correction This preconditioner is inexact but fast - it requires O(N*K) time to be applied. Its main purpose - to be used in barrier/penalty/AUL methods, where ill-conditioning is created by combination of two factors: * simple bounds on variables => ill-conditioned D * general barrier/penalty => correction W with large coefficient C (makes problem ill-conditioned) but W itself is well conditioned. Preconditioner P is calculated by artificially constructing a set of BFGS updates which tries to reproduce behavior of H: * Sk = Wk (k-th row of W) * Yk = (D+Wk'*Ck*Wk)*Sk * Yk/Sk are reordered by ascending of C[k]*norm(Wk)^2 Here we assume that rows of Wk are orthogonal or nearly orthogonal, which allows us to have O(N*K+K^2) update instead of O(N*K^2) one. Reordering of updates is essential for having good performance on non-orthogonal problems (updates which do not add much of curvature are added first, and updates which add very large eigenvalues are added last and override effect of the first updates). On input this function takes direction S and components of H. On output it returns inv(H)*S -- ALGLIB -- Copyright 30.06.2014 by Bochkanov Sergey *************************************************************************/ public static void inexactlbfgspreconditioner(double[] s, int n, double[] d, double[] c, double[,] w, int k, precbuflbfgs buf) { int idx = 0; int i = 0; int j = 0; double v = 0; double v0 = 0; double v1 = 0; double vx = 0; double vy = 0; int i_ = 0; apserv.rvectorsetlengthatleast(ref buf.norms, k); apserv.rvectorsetlengthatleast(ref buf.alpha, k); apserv.rvectorsetlengthatleast(ref buf.rho, k); apserv.rmatrixsetlengthatleast(ref buf.yk, k, n); apserv.ivectorsetlengthatleast(ref buf.idx, k); // // Check inputs // for(i=0; i<=n-1; i++) { alglib.ap.assert((double)(d[i])>(double)(0), "InexactLBFGSPreconditioner: D[]<=0"); } for(i=0; i<=k-1; i++) { alglib.ap.assert((double)(c[i])>=(double)(0), "InexactLBFGSPreconditioner: C[]<0"); } // // Reorder linear terms according to increase of second derivative. // Fill Norms[] array. // for(idx=0; idx<=k-1; idx++) { v = 0.0; for(i_=0; i_<=n-1;i_++) { v += w[idx,i_]*w[idx,i_]; } buf.norms[idx] = v*c[idx]; buf.idx[idx] = idx; } tsort.tagsortfasti(ref buf.norms, ref buf.idx, ref buf.bufa, ref buf.bufb, k); // // Apply updates // for(idx=0; idx<=k-1; idx++) { // // Select update to perform (ordered by ascending of second derivative) // i = buf.idx[idx]; // // Calculate YK and Rho // v = 0.0; for(i_=0; i_<=n-1;i_++) { v += w[i,i_]*w[i,i_]; } v = v*c[i]; for(j=0; j<=n-1; j++) { buf.yk[i,j] = (d[j]+v)*w[i,j]; } v = 0.0; v0 = 0.0; v1 = 0.0; for(j=0; j<=n-1; j++) { vx = w[i,j]; vy = buf.yk[i,j]; v = v+vx*vy; v0 = v0+vx*vx; v1 = v1+vy*vy; } if( ((double)(v)>(double)(0) && (double)(v0*v1)>(double)(0)) && (double)(v/Math.Sqrt(v0*v1))>(double)(n*10*math.machineepsilon) ) { buf.rho[i] = 1/v; } else { buf.rho[i] = 0.0; } } for(idx=k-1; idx>=0; idx--) { // // Select update to perform (ordered by ascending of second derivative) // i = buf.idx[idx]; // // Calculate Alpha[] according to L-BFGS algorithm // and update S[] // v = 0.0; for(i_=0; i_<=n-1;i_++) { v += w[i,i_]*s[i_]; } v = buf.rho[i]*v; buf.alpha[i] = v; for(i_=0; i_<=n-1;i_++) { s[i_] = s[i_] - v*buf.yk[i,i_]; } } for(j=0; j<=n-1; j++) { s[j] = s[j]/d[j]; } for(idx=0; idx<=k-1; idx++) { // // Select update to perform (ordered by ascending of second derivative) // i = buf.idx[idx]; // // Calculate Beta according to L-BFGS algorithm // and update S[] // v = 0.0; for(i_=0; i_<=n-1;i_++) { v += buf.yk[i,i_]*s[i_]; } v = buf.alpha[i]-buf.rho[i]*v; for(i_=0; i_<=n-1;i_++) { s[i_] = s[i_] + v*w[i,i_]; } } }
public override alglib.apobject make_copy() { precbuflbfgs _result = new precbuflbfgs(); _result.norms = (double[])norms.Clone(); _result.alpha = (double[])alpha.Clone(); _result.rho = (double[])rho.Clone(); _result.yk = (double[,])yk.Clone(); _result.idx = (int[])idx.Clone(); _result.bufa = (double[])bufa.Clone(); _result.bufb = (int[])bufb.Clone(); return _result; }