예제 #1
0
/*****************************************************************
  call only this routine; this is the only one you're interested in
  for doing quadratical optimization

  the restart feature exists but it may not be of much use due to the
  fact that an initial setting, although close but not very close the
  the actual solution will result in very good starting diagnostics
  (primal and dual feasibility and small infeasibility gap) but incur
  later stalling of the optimizer afterwards as we have to enforce
  positivity of the slacks.
  ***************************************************************/
void CL2N2_prLOQO::SolveQP()
{
        
   int &n = dim;
   int &m = numOfConstraint;
   double r = -10000.0;        // the #r# variable in LOQO

   
   // check if pre allocated mem is enough
   if(n > cur_mem_n)
      reallocPrimalMem(n+gradSetSizeIncrement);
   if(m > cur_mem_m)
      reallocDualMem(m+gradSetSizeIncrement);
   
   
   /* the knobs to be tuned ... */
   double margin = -0.95;	/* we will go up to 95% of the
				   distance between old variables and zero */
   double bound = 10;		/* preset value for the start. small
				   values give good initial
				   feasibility but may result in slow
				   convergence afterwards: we're too
				   close to zero */
   
   // variable name change between wrapper and original pr_loqo impl
   double *c = f;
   
   // h_x get changed after each predictor-corrector pair call
   // alternatively, copy the upper triangle back to the lower one
   memcpy(h_x, Q, n*n*sizeof(double));
   
   // adjust range of constraint
   double base = (r<0) ? -r : r;
   for(int i=0; i<m; i++) {
      b_local[i] = base + b[i];
   }
   
   /* from the header - pointers into primal and dual */
   //double *x;  // using member variable #x#
   double *y;
   double *g;
   double *z;
   double *s;
   double *t;
   
   // for ineq constraint
   double *v;
   double *w;
   double *p;  
   double *q;


   /* auxiliary variables */
   double b_plus_1;
   double c_plus_1;
   
   double x_h_x;
   double primal_inf;
   double dual_inf;
   
   double sigfig;
   double primal_obj, dual_obj;
   double mu;
   double steplength = 0;
   int counter = 0;
   
   int status = 0;
   
   int i,j;
   
   // chteo: dont mix x with other primal variables anymore
   //x = primal;			/* n */
   //g = x + n;			/* n */
   
   
   g = primal;
   t = g + n;			/* n */
   z = t + n;			/* n */
   s = z + n;			/* n */
   
   y = dual;	            /* m */
   w = y + m;		    /* m */
   p = w + m;		    /* m */
   q = p + m;		    /* m */
   v = q + m;		    /* m */
   
   
   
   /* initial settings */
   c_plus_1 = 0;
   for(i=0; i<n; i++)
      c_plus_1 += c[i]*c[i];
   c_plus_1 = sqrt(c_plus_1) + 1;
   
   b_plus_1 = 0;
   for(i=0; i<m; i++)
      b_plus_1 += b[i]*b[i];
   b_plus_1 = sqrt(b_plus_1) + 1;
   
   
   /* get diagonal terms */
   for (i=0; i<n; i++) diag_h_x[i] = h_x[(n+1)*i]; 
   
   // chteo: no more restart, use default start settings
   for (i=0; i<m; i++)
      for (j=i; j<m; j++)
	 h_y[i*m + j] = (i==j) ? 1 : 0;
   
   for (i=0; i<n; i++) {
      c_x[i] = c[i];
      h_x[(n+1)*i] += 1;
   }
   
   for (i=0; i<m; i++)
      c_y[i] = b_local[i];
   
   /* and solve the system [-H_x A'; A H_y] [x, y] = [c_x; c_y] */
   solve_reduced(n, m, h_x, h_y, a, x, y, c_x, c_y, workspace,
		 PRLOQO::PREDICTOR);
   
   
   /* initialize the other variables (primal) */
   for (i=0; i<n; i++) {
      g[i] = std::max(SML::abs(x[i] - l[i]), bound);
      z[i] = std::max(SML::abs(x[i]), bound);
      t[i] = std::max(SML::abs(u[i] - x[i]), bound); 
      s[i] = std::max(SML::abs(x[i]), bound); 
   }
   
   // chteo:
   /* initialize the other variables (dual) */
   for (i=0; i<m; i++) {    
      v[i] = std::max(SML::abs(y[i]), bound);
      w[i] = std::max(SML::abs(y[i]), bound);
      q[i] = std::max(SML::abs(y[i]), bound); 
      p[i] = std::max(SML::abs(b_local[i] - w[i]), bound);  // the roles of r and b are swapped
   }
   
   mu = 0;
   for(i=0; i<n; i++)
      mu += z[i] * g[i] + s[i] * t[i];
   for(i=0; i<m; i++)
      mu += v[i] * w[i] + p[i] * q[i];
   mu = mu / (2*(m+n));
   sigfig = 0;
   steplength = 1;
   
   /* the main loop */
   if (verbosity >= PRLOQO::STATUS) {
      printf("counter | pri_inf  | dual_inf  | pri_obj   | dual_obj  | ");
      printf("sigfig | alpha  | nu \n");
      printf("-------------------------------------------------------");
      printf("---------------------------\n");
   }
   
   while (status == 0) {
      /* predictor */
      
      /* put back original diagonal values */
      for (i=0; i<n; i++) 
	 h_x[(n+1) * i] = diag_h_x[i];
      
      matrix_vector(n, h_x, x, h_dot_x); /* compute h_dot_x = h_x * x */
      
      for (i=0; i<m; i++) {
	 rho[i] = r + w[i];
	 for (j=0; j<n; j++)
	    rho[i] -= a[n*i + j] * x[j];
      }
      
      for (i=0; i<n; i++) {
	 nu[i] = l[i] - x[i] + g[i];
	 tau[i] = u[i] - x[i] - t[i];
	 
	 sigma[i] = c[i] - z[i] + s[i] + h_dot_x[i];
	 for (j=0; j<m; j++)
	    sigma[i] -= a[n*j + i] * y[j];
	 
	 gamma_z[i] = - z[i];
	 gamma_s[i] = - s[i];
      }
      
      for(i=0; i<m; i++) {
	 alpha[i] = b_local[i] - w[i] - p[i];  // the roles of r and b swapped 
	 beta[i]  = y[i] + q[i] - v[i];
	 
	 gamma_w[i] = - w[i];
	 gamma_q[i] = - q[i];
      }
      
      /* instrumentation */
      x_h_x = 0;
      primal_inf = 0;
      dual_inf = 0;
      
      for (i=0; i<n; i++) {
	 x_h_x += h_dot_x[i] * x[i];
	 primal_inf += SML::sqr(tau[i]);
	 primal_inf += SML::sqr(nu[i]);
	 dual_inf += SML::sqr(sigma[i]);
      }
      
      for (i=0; i<m; i++) {
	 primal_inf += SML::sqr(rho[i]);
	 primal_inf += SML::sqr(alpha[i]);
	 dual_inf += SML::sqr(beta[i]);
      }
      
      primal_inf = sqrt(primal_inf)/b_plus_1;
      dual_inf = sqrt(dual_inf)/c_plus_1;
      
      primal_obj = 0.5 * x_h_x;
      dual_obj = -0.5 * x_h_x;
      for (i=0; i<n; i++) {
	 primal_obj += c[i] * x[i];
	 dual_obj += l[i] * z[i] - u[i] * s[i];
      }
      for (i=0; i<m; i++) {
	 dual_obj += r * y[i];     // the roles of r and b swapped
	 dual_obj -= b_local[i] * q[i];
      }
      
      sigfig = log10(SML::abs(primal_obj) + 1) - log10(SML::abs(primal_obj - dual_obj));
      sigfig = std::max(sigfig, 0.0);
      
      /* the diagnostics - after we computed our results we will
       analyze them */
      
      if (counter > maxIntPointIter) status = PRLOQO::ITERATION_LIMIT;
      if (sigfig  > sigfig_max)  status = PRLOQO::OPTIMAL_SOLUTION;
      //if (sigfig  > -log10(tol))  status = PRLOQO::OPTIMAL_SOLUTION;
      if (primal_inf > 10e100)   status = PRLOQO::PRIMAL_INFEASIBLE;
      if (dual_inf > 10e100)     status = PRLOQO::DUAL_INFEASIBLE;
      if ((primal_inf > 10e100) & (dual_inf > 10e100)) status = PRLOQO::PRIMAL_AND_DUAL_INFEASIBLE;
      if (SML::abs(primal_obj) > 10e100) status = PRLOQO::PRIMAL_UNBOUNDED;
      if (SML::abs(dual_obj) > 10e100) status = PRLOQO::DUAL_UNBOUNDED;
      
      /* write some nice routine to enforce the time limit if you
	 _really_ want, however it's quite useless as you can compute
	 the time from the maximum number of iterations as every
	 iteration costs one cholesky decomposition plus a couple of 
	 backsubstitutions */
      
      /* generate report */
      if ((verbosity >= PRLOQO::FLOOD) | ((verbosity == PRLOQO::STATUS) & (status != 0)))
	 printf("%7i | %.2e | %.2e | % .2e | % .2e | %6.3f | %.4f | %.2e\n",
             counter, primal_inf, dual_inf, primal_obj, dual_obj,
		sigfig, steplength, mu);
      
      counter++;
      
      if (status == 0) {		
	 /* 
	    we may keep on going, otherwise it'll cost one loop extra plus a
	    messed up main diagonal of h_x 
	 */

	 /* intermediate variables (the ones with hat) */
	 for (i=0; i<n; i++) {
	    hat_nu[i]    = nu[i] + g[i] * gamma_z[i] / z[i];
	    hat_tau[i]   = tau[i] - t[i] * gamma_s[i] / s[i];
	    /* diagonal terms */
	    d[i] = z[i] / g[i] + s[i] / t[i];
	 }
	 for(i=0; i<m; i++) {
	    hat_beta[i]  = beta[i] - v[i] * gamma_w[i] / w[i];
	    hat_alpha[i] = alpha[i] - p[i] * gamma_q[i] / q[i];
	 }
	 
	 /* initialization before the cholesky solver */
	 for (i=0; i<n; i++) {
	    h_x[(n+1)*i] = diag_h_x[i] + d[i];
	    c_x[i] = sigma[i] - z[i] * hat_nu[i] / g[i] - 
	       s[i] * hat_tau[i] / t[i];
      }           
	 
	 memset(h_y, 0, m*m*sizeof(double));
	 for (i=0; i<m; i++) {
	    c_y[i] = rho[i];
	    e[i] = 1 / (v[i] / w[i] + q[i] / p[i]);
	    h_y[(m+1)*i] = e[i];
	 }
	 
         
      /* and do it */
	 solve_reduced(n, m, h_x, h_y, a, delta_x, delta_y, c_x, c_y, workspace,
		       PRLOQO::PREDICTOR);
	 
	 // chteo: for PRIMAL related var
	 for(i=0; i<n; i++) {
	    /* backsubstitution */
	    delta_s[i] = s[i] * (delta_x[i] - hat_tau[i]) / t[i];
	    delta_z[i] = z[i] * (hat_nu[i] - delta_x[i]) / g[i];        
	    delta_g[i] = g[i] * (gamma_z[i] - delta_z[i]) / z[i];
	    delta_t[i] = t[i] * (gamma_s[i] - delta_s[i]) / s[i];
	    
	    /* central path (corrector) */
	    gamma_z[i] = mu / g[i] - z[i] - delta_z[i] * delta_g[i] / g[i];
	    gamma_s[i] = mu / t[i] - s[i] - delta_s[i] * delta_t[i] / t[i];
	    
	    /* (some more intermediate variables) the hat variables */
	    hat_nu[i] = nu[i] + g[i] * gamma_z[i] / z[i];
	    hat_tau[i] = tau[i] - t[i] * gamma_s[i] / s[i];
	    
	    /* initialization before the cholesky */
	    c_x[i] = sigma[i] - z[i] * hat_nu[i] / g[i] - s[i] * hat_tau[i] / t[i];
	 }
	 
	 // chteo: for DUAL related var
	 for(i=0; i<m; i++) {
	    /* backsubstitution */
	    delta_w[i] = - e[i] * (hat_beta[i] - q[i] * hat_alpha[i] / p[i] + delta_y[i]);
	    delta_q[i] = q[i] * (delta_w[i] - hat_alpha[i]) / p[i];
	    
	    delta_v[i] = v[i] * (gamma_w[i] - delta_w[i]) / w[i];
	    delta_p[i] = p[i] * (gamma_q[i] - delta_q[i]) / q[i];
	    
	    
	    /* central path (corrector) */
	    gamma_w[i] = mu / v[i] - w[i] - delta_w[i] * delta_v[i] / v[i];
	    gamma_q[i] = mu / p[i] - q[i] - delta_q[i] * delta_p[i] / p[i];
	    
	    /* (some more intermediate variables) the hat variables */
	    hat_alpha[i] = alpha[i] - p[i] * gamma_q[i] / q[i];
	    hat_beta[i]  = beta[i] - v[i] * gamma_w[i] / w[i];
	    
	    /* initialization before the cholesky */
	    c_y[i] = rho[i] - e[i] * (hat_beta[i] - q[i] * hat_alpha[i] / p[i]);
	 }
	 
	 
	 /* and do it */
	 solve_reduced(n, m, h_x, h_y, a, delta_x, delta_y, c_x, c_y, workspace,
		       PRLOQO::CORRECTOR);
	 
	 // chteo: for primal related var
	 for (i=0; i<n; i++) {
	    /* backsubstitution */
	    delta_s[i] = s[i] * (delta_x[i] - hat_tau[i]) / t[i];
	    delta_z[i] = z[i] * (hat_nu[i] - delta_x[i]) / g[i];        
	    delta_g[i] = g[i] * (gamma_z[i] - delta_z[i]) / z[i];
	    delta_t[i] = t[i] * (gamma_s[i] - delta_s[i]) / s[i];
	 }
	 
	 // chteo: for dual related var
	 for(i=0; i<m; i++) {
	    /* backsubstitution */
	    delta_w[i] = - e[i] * (hat_beta[i] - q[i] * hat_alpha[i] / p[i] + delta_y[i]);
	    delta_q[i] = q[i] * (delta_w[i] - hat_alpha[i]) / p[i];
	    delta_v[i] = v[i] * (gamma_w[i] - delta_w[i]) / w[i];
	    delta_p[i] = p[i] * (gamma_q[i] - delta_q[i]) / q[i];
	 }
	 
	 steplength = -1;
	 for (i=0; i<n; i++) {
	    steplength = std::min(steplength, delta_g[i]/g[i]);
	    steplength = std::min(steplength, delta_t[i]/t[i]);
	    steplength = std::min(steplength, delta_s[i]/s[i]);
	    steplength = std::min(steplength, delta_z[i]/z[i]);
	 }
	 for (i=0; i<m; i++) {
	    steplength = std::min(steplength, delta_w[i]/w[i]);
	    steplength = std::min(steplength, delta_p[i]/p[i]);
	    steplength = std::min(steplength, delta_q[i]/q[i]);
	    steplength = std::min(steplength, delta_v[i]/v[i]);
	 }  
	 steplength = margin / steplength;
	 
	 /* compute mu */
	 mu = 0;
	 for(i=0; i<n; i++)
	    mu += z[i] * g[i] + s[i] * t[i];
	 for(i=0; i<m; i++)
	    mu += v[i] * w[i] + p[i] * q[i];            
	 mu = mu / (2*(m+n));
	 mu = mu * SML::sqr((steplength - 1) / (steplength + 10));
	 
	 for (i=0; i<n; i++) {
	    x[i] += steplength * delta_x[i];
	    g[i] += steplength * delta_g[i];
	    t[i] += steplength * delta_t[i];
	    z[i] += steplength * delta_z[i];
	    s[i] += steplength * delta_s[i];
	 }
	 
	 for (i=0; i<m; i++) {
	    y[i] += steplength * delta_y[i];
	    w[i] += steplength * delta_w[i];
	    p[i] += steplength * delta_p[i];
	    q[i] += steplength * delta_q[i];
	    v[i] += steplength * delta_v[i];
	 }
      }
   }
   if ((status == 1) && (verbosity >= PRLOQO::STATUS)) {
      printf("----------------------------------------------------------------------------------\n");
      printf("optimization converged\n");
   }
   
   // chteo:
   // h_x get changed after each predictor-corrector pair call
   // alternatively, copy the upper triangle back to the lower one
   memcpy(h_x, Q, n*n*sizeof(double));
}
예제 #2
0
int pr_loqo(int n, int m, double c[], double h_x[], double a[], double b[],
	    double l[], double u[], double primal[], double dual[], 
	    int verb, double sigfig_max, int counter_max, 
	    double margin, double bound, int restart) 
{
  /* the knobs to be tuned ... */
  /* double margin = -0.95;	   we will go up to 95% of the
				   distance between old variables and zero */
  /* double bound = 10;		   preset value for the start. small
				   values give good initial
				   feasibility but may result in slow
				   convergence afterwards: we're too
				   close to zero */
  /* to be allocated */
  double *workspace;
  double *diag_h_x;
  double *h_y;
  double *c_x;
  double *c_y;
  double *h_dot_x;
  double *rho;
  double *nu;
  double *tau;
  double *sigma;
  double *gamma_z;
  double *gamma_s;  

  double *hat_nu;
  double *hat_tau;

  double *delta_x;
  double *delta_y;
  double *delta_s;
  double *delta_z;
  double *delta_g;
  double *delta_t;

  double *d;

  /* from the header - pointers into primal and dual */
  double *x;
  double *y;
  double *g;
  double *z;
  double *s;
  double *t;  

  /* auxiliary variables */
  double b_plus_1;
  double c_plus_1;

  double x_h_x;
  double primal_inf;
  double dual_inf;

  double sigfig;
  double primal_obj, dual_obj;
  double mu;
  double alfa, step;
  int counter = 0;

  int status = STILL_RUNNING;

  int i,j,k;

  /* memory allocation */
  workspace = malloc((n*(m+2)+2*m)*sizeof(double));
  diag_h_x  = malloc(n*sizeof(double));
  h_y       = malloc(m*m*sizeof(double));
  c_x       = malloc(n*sizeof(double));
  c_y       = malloc(m*sizeof(double));
  h_dot_x   = malloc(n*sizeof(double));

  rho       = malloc(m*sizeof(double));
  nu        = malloc(n*sizeof(double));
  tau       = malloc(n*sizeof(double));
  sigma     = malloc(n*sizeof(double));

  gamma_z   = malloc(n*sizeof(double));
  gamma_s   = malloc(n*sizeof(double));

  hat_nu    = malloc(n*sizeof(double));
  hat_tau   = malloc(n*sizeof(double));

  delta_x   = malloc(n*sizeof(double));
  delta_y   = malloc(m*sizeof(double));
  delta_s   = malloc(n*sizeof(double));
  delta_z   = malloc(n*sizeof(double));
  delta_g   = malloc(n*sizeof(double));
  delta_t   = malloc(n*sizeof(double));

  d         = malloc(n*sizeof(double));

  /* pointers into the external variables */
  x = primal;			/* n */
  g = x + n;			/* n */
  t = g + n;			/* n */

  y = dual;			/* m */
  z = y + m;			/* n */
  s = z + n;			/* n */

  /* initial settings */
  b_plus_1 = 1;
  c_plus_1 = 0;
  for (i=0; i<n; i++) c_plus_1 += c[i];

  /* get diagonal terms */
  for (i=0; i<n; i++) diag_h_x[i] = h_x[(n+1)*i]; 
  
  /* starting point */
  if (restart == 1) {
				/* x, y already preset */
    for (i=0; i<n; i++) {	/* compute g, t for primal feasibility */
      g[i] = max(ABS(x[i] - l[i]), bound);
      t[i] = max(ABS(u[i] - x[i]), bound); 
    }

    matrix_vector(n, h_x, x, h_dot_x); /* h_dot_x = h_x * x */

    for (i=0; i<n; i++) {	/* sigma is a dummy variable to calculate z, s */
      sigma[i] = c[i] + h_dot_x[i];
      for (j=0; j<m; j++)
	sigma[i] -= a[n*j + i] * y[j];

      if (sigma[i] > 0) {
	s[i] = bound;
	z[i] = sigma[i] + bound;
      }
      else {
	s[i] = bound - sigma[i];
	z[i] = bound;
      }
    }
  }
  else {			/* use default start settings */
    for (i=0; i<m; i++)
      for (j=i; j<m; j++)
	h_y[i*m + j] = (i==j) ? 1 : 0;
    
    for (i=0; i<n; i++) {
      c_x[i] = c[i];
      h_x[(n+1)*i] += 1;
    }
    
    for (i=0; i<m; i++)
      c_y[i] = b[i];
    
    /* and solve the system [-H_x A'; A H_y] [x, y] = [c_x; c_y] */
    solve_reduced(n, m, h_x, h_y, a, x, y, c_x, c_y, workspace,
		  PREDICTOR);
    
    /* initialize the other variables */
    for (i=0; i<n; i++) {
      g[i] = max(ABS(x[i] - l[i]), bound);
      z[i] = max(ABS(x[i]), bound);
      t[i] = max(ABS(u[i] - x[i]), bound); 
      s[i] = max(ABS(x[i]), bound); 
    }
  }

  for (i=0, mu=0; i<n; i++)
    mu += z[i] * g[i] + s[i] * t[i];
  mu = mu / (2*n);

  /* the main loop */
  if (verb >= STATUS) {
    printf("counter | pri_inf  | dual_inf  | pri_obj   | dual_obj  | ");
    printf("sigfig | alpha  | nu \n");
    printf("-------------------------------------------------------");
    printf("---------------------------\n");
  }
  
  while (status == STILL_RUNNING) {
    /* predictor */
    
    /* put back original diagonal values */
    for (i=0; i<n; i++) 
      h_x[(n+1) * i] = diag_h_x[i];

    matrix_vector(n, h_x, x, h_dot_x); /* compute h_dot_x = h_x * x */

    for (i=0; i<m; i++) {
      rho[i] = b[i];
      for (j=0; j<n; j++)
	rho[i] -= a[n*i + j] * x[j];
    }
    
    for (i=0; i<n; i++) {
      nu[i] = l[i] - x[i] + g[i];
      tau[i] = u[i] - x[i] - t[i];

      sigma[i] = c[i] - z[i] + s[i] + h_dot_x[i];
      for (j=0; j<m; j++)
	sigma[i] -= a[n*j + i] * y[j];

      gamma_z[i] = - z[i];
      gamma_s[i] = - s[i];
    }

    /* instrumentation */
    x_h_x = 0;
    primal_inf = 0;
    dual_inf = 0;
    
    for (i=0; i<n; i++) {
      x_h_x += h_dot_x[i] * x[i];
      primal_inf += sqr(tau[i]);
      primal_inf += sqr(nu[i]);
      dual_inf += sqr(sigma[i]);
    }
    for (i=0; i<m; i++) 
      primal_inf += sqr(rho[i]);
    primal_inf = sqrt(primal_inf)/b_plus_1;
    dual_inf = sqrt(dual_inf)/c_plus_1;

    primal_obj = 0.5 * x_h_x;
    dual_obj = -0.5 * x_h_x;
    for (i=0; i<n; i++) {
      primal_obj += c[i] * x[i];
      dual_obj += l[i] * z[i] - u[i] * s[i];
    }
    for (i=0; i<m; i++)
      dual_obj += b[i] * y[i];

    sigfig = log10(ABS(primal_obj) + 1) -
             log10(ABS(primal_obj - dual_obj));
    sigfig = max(sigfig, 0);
		   
    /* the diagnostics - after we computed our results we will
       analyze them */

    if (counter > counter_max) status = ITERATION_LIMIT;
    if (sigfig  > sigfig_max)  status = OPTIMAL_SOLUTION;
    if (primal_inf > 10e100)   status = PRIMAL_INFEASIBLE;
    if (dual_inf > 10e100)     status = DUAL_INFEASIBLE;
    if ((primal_inf > 10e100) & (dual_inf > 10e100)) status = PRIMAL_AND_DUAL_INFEASIBLE;
    if (ABS(primal_obj) > 10e100) status = PRIMAL_UNBOUNDED;
    if (ABS(dual_obj) > 10e100) status = DUAL_UNBOUNDED;

    /* write some nice routine to enforce the time limit if you
       _really_ want, however it's quite useless as you can compute
       the time from the maximum number of iterations as every
       iteration costs one cholesky decomposition plus a couple of 
       backsubstitutions */

    /* generate report */
    if ((verb >= FLOOD) | ((verb == STATUS) & (status != 0)))
      printf("%7i | %.2e | %.2e | % .2e | % .2e | %6.3f | %.4f | %.2e\n",
	     counter, primal_inf, dual_inf, primal_obj, dual_obj,
	     sigfig, alfa, mu);

    counter++;

    if (status == 0) {		/* we may keep on going, otherwise
				   it'll cost one loop extra plus a
				   messed up main diagonal of h_x */
      /* intermediate variables (the ones with hat) */
      for (i=0; i<n; i++) {
	hat_nu[i] = nu[i] + g[i] * gamma_z[i] / z[i];
	hat_tau[i] = tau[i] - t[i] * gamma_s[i] / s[i];
	/* diagonal terms */
	d[i] = z[i] / g[i] + s[i] / t[i];
      }
      
      /* initialization before the cholesky solver */
      for (i=0; i<n; i++) {
	h_x[(n+1)*i] = diag_h_x[i] + d[i];
	c_x[i] = sigma[i] - z[i] * hat_nu[i] / g[i] - 
	  s[i] * hat_tau[i] / t[i];
      }
      for (i=0; i<m; i++) {
	c_y[i] = rho[i];
	for (j=i; j<m; j++) 
	  h_y[m*i + j] = 0;
      }
      
      /* and do it */
      solve_reduced(n, m, h_x, h_y, a, delta_x, delta_y, c_x, c_y, workspace,
		    PREDICTOR);
      
      for (i=0; i<n; i++) {
	/* backsubstitution */
	delta_s[i] = s[i] * (delta_x[i] - hat_tau[i]) / t[i];
	delta_z[i] = z[i] * (hat_nu[i] - delta_x[i]) / g[i];
	
	delta_g[i] = g[i] * (gamma_z[i] - delta_z[i]) / z[i];
	delta_t[i] = t[i] * (gamma_s[i] - delta_s[i]) / s[i];
	
	/* central path (corrector) */
	gamma_z[i] = mu / g[i] - z[i] - delta_z[i] * delta_g[i] / g[i];
	gamma_s[i] = mu / t[i] - s[i] - delta_s[i] * delta_t[i] / t[i];
	
	/* (some more intermediate variables) the hat variables */
	hat_nu[i] = nu[i] + g[i] * gamma_z[i] / z[i];
	hat_tau[i] = tau[i] - t[i] * gamma_s[i] / s[i];
	
	/* initialization before the cholesky */
	c_x[i] = sigma[i] - z[i] * hat_nu[i] / g[i] - s[i] * hat_tau[i] / t[i];
      }
      
      for (i=0; i<m; i++) {	/* comput c_y and rho */
	c_y[i] = rho[i];
	for (j=i; j<m; j++)
	  h_y[m*i + j] = 0;
      }
      
      /* and do it */
      solve_reduced(n, m, h_x, h_y, a, delta_x, delta_y, c_x, c_y, workspace,
		    CORRECTOR);
      
      for (i=0; i<n; i++) {
	/* backsubstitution */
	delta_s[i] = s[i] * (delta_x[i] - hat_tau[i]) / t[i];
	delta_z[i] = z[i] * (hat_nu[i] - delta_x[i]) / g[i];
	
	delta_g[i] = g[i] * (gamma_z[i] - delta_z[i]) / z[i];
	delta_t[i] = t[i] * (gamma_s[i] - delta_s[i]) / s[i];
      }
      
      alfa = -1;
      for (i=0; i<n; i++) {
	alfa = min(alfa, delta_g[i]/g[i]);
	alfa = min(alfa, delta_t[i]/t[i]);
	alfa = min(alfa, delta_s[i]/s[i]);
	alfa = min(alfa, delta_z[i]/z[i]);
      }
      alfa = (margin - 1) / alfa;
      
      /* compute mu */
      for (i=0, mu=0; i<n; i++)
	mu += z[i] * g[i] + s[i] * t[i];
      mu = mu / (2*n);
      mu = mu * sqr((alfa - 1) / (alfa + 10));
      
      for (i=0; i<n; i++) {
	x[i] += alfa * delta_x[i];
	g[i] += alfa * delta_g[i];
	t[i] += alfa * delta_t[i];
	z[i] += alfa * delta_z[i];
	s[i] += alfa * delta_s[i];
      }
      
      for (i=0; i<m; i++) 
	y[i] += alfa * delta_y[i];
    }
  }
  if ((status == 1) && (verb >= STATUS)) {
    printf("----------------------------------------------------------------------------------\n");
    printf("optimization converged\n");
  }
  
  /* free memory */
  free(workspace);
  free(diag_h_x);
  free(h_y);
  free(c_x);
  free(c_y);
  free(h_dot_x);
  
  free(rho);
  free(nu);
  free(tau);
  free(sigma);
  free(gamma_z);
  free(gamma_s);
  
  free(hat_nu);
  free(hat_tau);
    
  free(delta_x);
  free(delta_y);
  free(delta_s);
  free(delta_z);
  free(delta_g);
  free(delta_t);
    
  free(d);

  /* and return to sender */
  return status;
}