pr_loqo.c
上传用户:xfjled
上传日期:2007-05-06
资源大小:150k
文件大小:16k
源码类别:

matlab例程

开发平台:

Matlab

  1. /*
  2.  * File:        pr_loqo.c
  3.  * Purpose:     solves quadratic programming problem for pattern recognition
  4.  *              for support vectors
  5.  *
  6.  * Author:      Alex J. Smola
  7.  * Created:     10/14/97
  8.  * Updated:     11/08/97
  9.  * Updated:     13/08/98 (removed exit(1) as it crashes svm lite when the margin
  10.  *                        in a not sufficiently conservative manner)
  11.  *
  12.  * 
  13.  * Copyright (c) 1997  GMD Berlin - All rights reserved
  14.  * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of GMD Berlin
  15.  * The copyright notice above does not evidence any
  16.  * actual or intended publication of this work.
  17.  *
  18.  * Unauthorized commercial use of this software is not allowed
  19.  */
  20. #include <math.h>
  21. #include <time.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include "pr_loqo.h"
  25. #define max(A, B) ((A) > (B) ? (A) : (B))
  26. #define min(A, B) ((A) < (B) ? (A) : (B))
  27. #define sqr(A)          ((A) * (A))
  28. #define ABS(A)   ((A) > 0 ? (A) : (-(A)))
  29. #define PREDICTOR 1
  30. #define CORRECTOR 2
  31. /*****************************************************************
  32.   replace this by any other function that will exit gracefully
  33.   in a larger system
  34.   ***************************************************************/
  35. void nrerror(char error_text[])
  36. {
  37.   printf("ERROR: terminating optimizer - %sn", error_text);
  38.   /* exit(1); */
  39. }
  40. /*****************************************************************
  41.    taken from numerical recipes and modified to accept pointers
  42.    moreover numerical recipes code seems to be buggy (at least the
  43.    ones on the web)
  44.    cholesky solver and backsubstitution
  45.    leaves upper right triangle intact (rows first order)
  46.    ***************************************************************/
  47. void choldc(double a[], int n, double p[])
  48. {
  49.   void nrerror(char error_text[]);
  50.   int i, j, k;
  51.   double sum;
  52.   for (i = 0; i < n; i++){
  53.     for (j = i; j < n; j++) {
  54.       sum=a[n*i + j];
  55.       for (k=i-1; k>=0; k--) sum -= a[n*i + k]*a[n*j + k];
  56.       if (i == j) {
  57. if (sum <= 0.0) {
  58.   nrerror("choldc failed, matrix not positive definite");
  59.   sum = 0.0;
  60. }
  61. p[i]=sqrt(sum);
  62.       } else a[n*j + i] = sum/p[i];
  63.     }
  64.   }
  65. }
  66. void cholsb(double a[], int n, double p[], double b[], double x[])
  67. {
  68.   int i, k;
  69.   double sum;
  70.   for (i=0; i<n; i++) {
  71.     sum=b[i];
  72.     for (k=i-1; k>=0; k--) sum -= a[n*i + k]*x[k];
  73.     x[i]=sum/p[i];
  74.   }
  75.   for (i=n-1; i>=0; i--) {
  76.     sum=x[i];
  77.     for (k=i+1; k<n; k++) sum -= a[n*k + i]*x[k];
  78.     x[i]=sum/p[i];
  79.   }
  80. }
  81. /*****************************************************************
  82.   sometimes we only need the forward or backward pass of the
  83.   backsubstitution, hence we provide these two routines separately 
  84.   ***************************************************************/
  85. void chol_forward(double a[], int n, double p[], double b[], double x[])
  86. {
  87.   int i, k;
  88.   double sum;
  89.   for (i=0; i<n; i++) {
  90.     sum=b[i];
  91.     for (k=i-1; k>=0; k--) sum -= a[n*i + k]*x[k];
  92.     x[i]=sum/p[i];
  93.   }
  94. }
  95. void chol_backward(double a[], int n, double p[], double b[], double x[])
  96. {
  97.   int i, k;
  98.   double sum;
  99.   for (i=n-1; i>=0; i--) {
  100.     sum=b[i];
  101.     for (k=i+1; k<n; k++) sum -= a[n*k + i]*x[k];
  102.     x[i]=sum/p[i];
  103.   }
  104. }
  105. /*****************************************************************
  106.   solves the system | -H_x A' | |x_x| = |c_x|
  107.                     |  A   H_y| |x_y|   |c_y|
  108.   with H_x (and H_y) positive (semidefinite) matrices
  109.   and n, m the respective sizes of H_x and H_y
  110.   for variables see pg. 48 of notebook or do the calculations on a
  111.   sheet of paper again
  112.   predictor solves the whole thing, corrector assues that H_x didn't
  113.   change and relies on the results of the predictor. therefore do
  114.   _not_ modify workspace
  115.   if you want to speed tune anything in the code here's the right
  116.   place to do so: about 95% of the time is being spent in
  117.   here. something like an iterative refinement would be nice,
  118.   especially when switching from double to single precision. if you
  119.   have a fast parallel cholesky use it instead of the numrec
  120.   implementations.
  121.   side effects: changes H_y (but this is just the unit matrix or zero anyway
  122.   in our case)
  123.   ***************************************************************/
  124. void solve_reduced(int n, int m, double h_x[], double h_y[], 
  125.    double a[], double x_x[], double x_y[],
  126.    double c_x[], double c_y[],
  127.    double workspace[], int step)
  128. {
  129.   int i,j,k;
  130.   double *p_x;
  131.   double *p_y;
  132.   double *t_a;
  133.   double *t_c;
  134.   double *t_y;
  135.   p_x = workspace; /* together n + m + n*m + n + m = n*(m+2)+2*m */
  136.   p_y = p_x + n;
  137.   t_a = p_y + m;
  138.   t_c = t_a + n*m;
  139.   t_y = t_c + n;
  140.   if (step == PREDICTOR) {
  141.     choldc(h_x, n, p_x); /* do cholesky decomposition */
  142.     for (i=0; i<m; i++)         /* forward pass for A' */
  143.       chol_forward(h_x, n, p_x, a+i*n, t_a+i*n);
  144.     for (i=0; i<m; i++)         /* compute (h_y + a h_x^-1A') */
  145.       for (j=i; j<m; j++)
  146. for (k=0; k<n; k++) 
  147.   h_y[m*i + j] += t_a[n*j + k] * t_a[n*i + k];
  148.     choldc(h_y, m, p_y); /* and cholesky decomposition */
  149.   }
  150.   
  151.   chol_forward(h_x, n, p_x, c_x, t_c);
  152. /* forward pass for c */
  153.   for (i=0; i<m; i++) { /* and solve for x_y */
  154.     t_y[i] = c_y[i];
  155.     for (j=0; j<n; j++)
  156.       t_y[i] += t_a[i*n + j] * t_c[j];
  157.   }
  158.   cholsb(h_y, m, p_y, t_y, x_y);
  159.   for (i=0; i<n; i++) { /* finally solve for x_x */
  160.     t_c[i] = -t_c[i];
  161.     for (j=0; j<m; j++)
  162.       t_c[i] += t_a[j*n + i] * x_y[j];
  163.   }
  164.   chol_backward(h_x, n, p_x, t_c, x_x);
  165. }
  166. /*****************************************************************
  167.   matrix vector multiplication (symmetric matrix but only one triangle
  168.   given). computes m*x = y
  169.   no need to tune it as it's only of O(n^2) but cholesky is of
  170.   O(n^3). so don't waste your time _here_ although it isn't very
  171.   elegant. 
  172.   ***************************************************************/
  173. void matrix_vector(int n, double m[], double x[], double y[])
  174. {
  175.   int i, j;
  176.   for (i=0; i<n; i++) {
  177.     y[i] = m[(n+1) * i] * x[i];
  178.     for (j=0; j<i; j++)
  179.       y[i] += m[i + n*j] * x[j];
  180.     for (j=i+1; j<n; j++) 
  181.       y[i] += m[n*i + j] * x[j]; 
  182.   }
  183. }
  184. /*****************************************************************
  185.   call only this routine; this is the only one you're interested in
  186.   for doing quadratical optimization
  187.   the restart feature exists but it may not be of much use due to the
  188.   fact that an initial setting, although close but not very close the
  189.   the actual solution will result in very good starting diagnostics
  190.   (primal and dual feasibility and small infeasibility gap) but incur
  191.   later stalling of the optimizer afterwards as we have to enforce
  192.   positivity of the slacks.
  193.   ***************************************************************/
  194. int pr_loqo(int n, int m, double c[], double h_x[], double a[], double b[],
  195.     double l[], double u[], double primal[], double dual[], 
  196.     int verb, double sigfig_max, int counter_max, 
  197.     double margin, double bound, int restart) 
  198. {
  199.   /* the knobs to be tuned ... */
  200.   /* double margin = -0.95;    we will go up to 95% of the
  201.    distance between old variables and zero */
  202.   /* double bound = 10;    preset value for the start. small
  203.    values give good initial
  204.    feasibility but may result in slow
  205.    convergence afterwards: we're too
  206.    close to zero */
  207.   /* to be allocated */
  208.   double *workspace;
  209.   double *diag_h_x;
  210.   double *h_y;
  211.   double *c_x;
  212.   double *c_y;
  213.   double *h_dot_x;
  214.   double *rho;
  215.   double *nu;
  216.   double *tau;
  217.   double *sigma;
  218.   double *gamma_z;
  219.   double *gamma_s;  
  220.   double *hat_nu;
  221.   double *hat_tau;
  222.   double *delta_x;
  223.   double *delta_y;
  224.   double *delta_s;
  225.   double *delta_z;
  226.   double *delta_g;
  227.   double *delta_t;
  228.   double *d;
  229.   /* from the header - pointers into primal and dual */
  230.   double *x;
  231.   double *y;
  232.   double *g;
  233.   double *z;
  234.   double *s;
  235.   double *t;  
  236.   /* auxiliary variables */
  237.   double b_plus_1;
  238.   double c_plus_1;
  239.   double x_h_x;
  240.   double primal_inf;
  241.   double dual_inf;
  242.   double sigfig;
  243.   double primal_obj, dual_obj;
  244.   double mu;
  245.   double alfa, step;
  246.   int counter = 0;
  247.   int status = STILL_RUNNING;
  248.   int i,j,k;
  249.   /* memory allocation */
  250.   workspace = malloc((n*(m+2)+2*m)*sizeof(double));
  251.   diag_h_x  = malloc(n*sizeof(double));
  252.   h_y       = malloc(m*m*sizeof(double));
  253.   c_x       = malloc(n*sizeof(double));
  254.   c_y       = malloc(m*sizeof(double));
  255.   h_dot_x   = malloc(n*sizeof(double));
  256.   rho       = malloc(m*sizeof(double));
  257.   nu        = malloc(n*sizeof(double));
  258.   tau       = malloc(n*sizeof(double));
  259.   sigma     = malloc(n*sizeof(double));
  260.   gamma_z   = malloc(n*sizeof(double));
  261.   gamma_s   = malloc(n*sizeof(double));
  262.   hat_nu    = malloc(n*sizeof(double));
  263.   hat_tau   = malloc(n*sizeof(double));
  264.   delta_x   = malloc(n*sizeof(double));
  265.   delta_y   = malloc(m*sizeof(double));
  266.   delta_s   = malloc(n*sizeof(double));
  267.   delta_z   = malloc(n*sizeof(double));
  268.   delta_g   = malloc(n*sizeof(double));
  269.   delta_t   = malloc(n*sizeof(double));
  270.   d         = malloc(n*sizeof(double));
  271.   /* pointers into the external variables */
  272.   x = primal; /* n */
  273.   g = x + n; /* n */
  274.   t = g + n; /* n */
  275.   y = dual; /* m */
  276.   z = y + m; /* n */
  277.   s = z + n; /* n */
  278.   /* initial settings */
  279.   b_plus_1 = 1;
  280.   c_plus_1 = 0;
  281.   for (i=0; i<n; i++) c_plus_1 += c[i];
  282.   /* get diagonal terms */
  283.   for (i=0; i<n; i++) diag_h_x[i] = h_x[(n+1)*i]; 
  284.   
  285.   /* starting point */
  286.   if (restart == 1) {
  287. /* x, y already preset */
  288.     for (i=0; i<n; i++) { /* compute g, t for primal feasibility */
  289.       g[i] = max(ABS(x[i] - l[i]), bound);
  290.       t[i] = max(ABS(u[i] - x[i]), bound); 
  291.     }
  292.     matrix_vector(n, h_x, x, h_dot_x); /* h_dot_x = h_x * x */
  293.     for (i=0; i<n; i++) { /* sigma is a dummy variable to calculate z, s */
  294.       sigma[i] = c[i] + h_dot_x[i];
  295.       for (j=0; j<m; j++)
  296. sigma[i] -= a[n*j + i] * y[j];
  297.       if (sigma[i] > 0) {
  298. s[i] = bound;
  299. z[i] = sigma[i] + bound;
  300.       }
  301.       else {
  302. s[i] = bound - sigma[i];
  303. z[i] = bound;
  304.       }
  305.     }
  306.   }
  307.   else { /* use default start settings */
  308.     for (i=0; i<m; i++)
  309.       for (j=i; j<m; j++)
  310. h_y[i*m + j] = (i==j) ? 1 : 0;
  311.     
  312.     for (i=0; i<n; i++) {
  313.       c_x[i] = c[i];
  314.       h_x[(n+1)*i] += 1;
  315.     }
  316.     
  317.     for (i=0; i<m; i++)
  318.       c_y[i] = b[i];
  319.     
  320.     /* and solve the system [-H_x A'; A H_y] [x, y] = [c_x; c_y] */
  321.     solve_reduced(n, m, h_x, h_y, a, x, y, c_x, c_y, workspace,
  322.   PREDICTOR);
  323.     
  324.     /* initialize the other variables */
  325.     for (i=0; i<n; i++) {
  326.       g[i] = max(ABS(x[i] - l[i]), bound);
  327.       z[i] = max(ABS(x[i]), bound);
  328.       t[i] = max(ABS(u[i] - x[i]), bound); 
  329.       s[i] = max(ABS(x[i]), bound); 
  330.     }
  331.   }
  332.   for (i=0, mu=0; i<n; i++)
  333.     mu += z[i] * g[i] + s[i] * t[i];
  334.   mu = mu / (2*n);
  335.   /* the main loop */
  336.   if (verb >= STATUS) {
  337.     printf("counter | pri_inf  | dual_inf  | pri_obj   | dual_obj  | ");
  338.     printf("sigfig | alpha  | nu n");
  339.     printf("-------------------------------------------------------");
  340.     printf("---------------------------n");
  341.   }
  342.   
  343.   while (status == STILL_RUNNING) {
  344.     /* predictor */
  345.     
  346.     /* put back original diagonal values */
  347.     for (i=0; i<n; i++) 
  348.       h_x[(n+1) * i] = diag_h_x[i];
  349.     matrix_vector(n, h_x, x, h_dot_x); /* compute h_dot_x = h_x * x */
  350.     for (i=0; i<m; i++) {
  351.       rho[i] = b[i];
  352.       for (j=0; j<n; j++)
  353. rho[i] -= a[n*i + j] * x[j];
  354.     }
  355.     
  356.     for (i=0; i<n; i++) {
  357.       nu[i] = l[i] - x[i] + g[i];
  358.       tau[i] = u[i] - x[i] - t[i];
  359.       sigma[i] = c[i] - z[i] + s[i] + h_dot_x[i];
  360.       for (j=0; j<m; j++)
  361. sigma[i] -= a[n*j + i] * y[j];
  362.       gamma_z[i] = - z[i];
  363.       gamma_s[i] = - s[i];
  364.     }
  365.     /* instrumentation */
  366.     x_h_x = 0;
  367.     primal_inf = 0;
  368.     dual_inf = 0;
  369.     
  370.     for (i=0; i<n; i++) {
  371.       x_h_x += h_dot_x[i] * x[i];
  372.       primal_inf += sqr(tau[i]);
  373.       primal_inf += sqr(nu[i]);
  374.       dual_inf += sqr(sigma[i]);
  375.     }
  376.     for (i=0; i<m; i++) 
  377.       primal_inf += sqr(rho[i]);
  378.     primal_inf = sqrt(primal_inf)/b_plus_1;
  379.     dual_inf = sqrt(dual_inf)/c_plus_1;
  380.     primal_obj = 0.5 * x_h_x;
  381.     dual_obj = -0.5 * x_h_x;
  382.     for (i=0; i<n; i++) {
  383.       primal_obj += c[i] * x[i];
  384.       dual_obj += l[i] * z[i] - u[i] * s[i];
  385.     }
  386.     for (i=0; i<m; i++)
  387.       dual_obj += b[i] * y[i];
  388.     sigfig = log10(ABS(primal_obj) + 1) -
  389.              log10(ABS(primal_obj - dual_obj));
  390.     sigfig = max(sigfig, 0);
  391.    
  392.     /* the diagnostics - after we computed our results we will
  393.        analyze them */
  394.     if (counter > counter_max) status = ITERATION_LIMIT;
  395.     if (sigfig  > sigfig_max)  status = OPTIMAL_SOLUTION;
  396.     if (primal_inf > 10e100)   status = PRIMAL_INFEASIBLE;
  397.     if (dual_inf > 10e100)     status = DUAL_INFEASIBLE;
  398.     if ((primal_inf > 10e100) & (dual_inf > 10e100)) status = PRIMAL_AND_DUAL_INFEASIBLE;
  399.     if (ABS(primal_obj) > 10e100) status = PRIMAL_UNBOUNDED;
  400.     if (ABS(dual_obj) > 10e100) status = DUAL_UNBOUNDED;
  401.     /* write some nice routine to enforce the time limit if you
  402.        _really_ want, however it's quite useless as you can compute
  403.        the time from the maximum number of iterations as every
  404.        iteration costs one cholesky decomposition plus a couple of 
  405.        backsubstitutions */
  406.     /* generate report */
  407.     if ((verb >= FLOOD) | ((verb == STATUS) & (status != 0)))
  408.       printf("%7i | %.2e | %.2e | % .2e | % .2e | %6.3f | %.4f | %.2en",
  409.      counter, primal_inf, dual_inf, primal_obj, dual_obj,
  410.      sigfig, alfa, mu);
  411.     counter++;
  412.     if (status == 0) { /* we may keep on going, otherwise
  413.    it'll cost one loop extra plus a
  414.    messed up main diagonal of h_x */
  415.       /* intermediate variables (the ones with hat) */
  416.       for (i=0; i<n; i++) {
  417. hat_nu[i] = nu[i] + g[i] * gamma_z[i] / z[i];
  418. hat_tau[i] = tau[i] - t[i] * gamma_s[i] / s[i];
  419. /* diagonal terms */
  420. d[i] = z[i] / g[i] + s[i] / t[i];
  421.       }
  422.       
  423.       /* initialization before the cholesky solver */
  424.       for (i=0; i<n; i++) {
  425. h_x[(n+1)*i] = diag_h_x[i] + d[i];
  426. c_x[i] = sigma[i] - z[i] * hat_nu[i] / g[i] - 
  427.   s[i] * hat_tau[i] / t[i];
  428.       }
  429.       for (i=0; i<m; i++) {
  430. c_y[i] = rho[i];
  431. for (j=i; j<m; j++) 
  432.   h_y[m*i + j] = 0;
  433.       }
  434.       
  435.       /* and do it */
  436.       solve_reduced(n, m, h_x, h_y, a, delta_x, delta_y, c_x, c_y, workspace,
  437.     PREDICTOR);
  438.       
  439.       for (i=0; i<n; i++) {
  440. /* backsubstitution */
  441. delta_s[i] = s[i] * (delta_x[i] - hat_tau[i]) / t[i];
  442. delta_z[i] = z[i] * (hat_nu[i] - delta_x[i]) / g[i];
  443. delta_g[i] = g[i] * (gamma_z[i] - delta_z[i]) / z[i];
  444. delta_t[i] = t[i] * (gamma_s[i] - delta_s[i]) / s[i];
  445. /* central path (corrector) */
  446. gamma_z[i] = mu / g[i] - z[i] - delta_z[i] * delta_g[i] / g[i];
  447. gamma_s[i] = mu / t[i] - s[i] - delta_s[i] * delta_t[i] / t[i];
  448. /* (some more intermediate variables) the hat variables */
  449. hat_nu[i] = nu[i] + g[i] * gamma_z[i] / z[i];
  450. hat_tau[i] = tau[i] - t[i] * gamma_s[i] / s[i];
  451. /* initialization before the cholesky */
  452. c_x[i] = sigma[i] - z[i] * hat_nu[i] / g[i] - s[i] * hat_tau[i] / t[i];
  453.       }
  454.       
  455.       for (i=0; i<m; i++) { /* comput c_y and rho */
  456. c_y[i] = rho[i];
  457. for (j=i; j<m; j++)
  458.   h_y[m*i + j] = 0;
  459.       }
  460.       
  461.       /* and do it */
  462.       solve_reduced(n, m, h_x, h_y, a, delta_x, delta_y, c_x, c_y, workspace,
  463.     CORRECTOR);
  464.       
  465.       for (i=0; i<n; i++) {
  466. /* backsubstitution */
  467. delta_s[i] = s[i] * (delta_x[i] - hat_tau[i]) / t[i];
  468. delta_z[i] = z[i] * (hat_nu[i] - delta_x[i]) / g[i];
  469. delta_g[i] = g[i] * (gamma_z[i] - delta_z[i]) / z[i];
  470. delta_t[i] = t[i] * (gamma_s[i] - delta_s[i]) / s[i];
  471.       }
  472.       
  473.       alfa = -1;
  474.       for (i=0; i<n; i++) {
  475. alfa = min(alfa, delta_g[i]/g[i]);
  476. alfa = min(alfa, delta_t[i]/t[i]);
  477. alfa = min(alfa, delta_s[i]/s[i]);
  478. alfa = min(alfa, delta_z[i]/z[i]);
  479.       }
  480.       alfa = (margin - 1) / alfa;
  481.       
  482.       /* compute mu */
  483.       for (i=0, mu=0; i<n; i++)
  484. mu += z[i] * g[i] + s[i] * t[i];
  485.       mu = mu / (2*n);
  486.       mu = mu * sqr((alfa - 1) / (alfa + 10));
  487.       
  488.       for (i=0; i<n; i++) {
  489. x[i] += alfa * delta_x[i];
  490. g[i] += alfa * delta_g[i];
  491. t[i] += alfa * delta_t[i];
  492. z[i] += alfa * delta_z[i];
  493. s[i] += alfa * delta_s[i];
  494.       }
  495.       
  496.       for (i=0; i<m; i++) 
  497. y[i] += alfa * delta_y[i];
  498.     }
  499.   }
  500.   if ((status == 1) && (verb >= STATUS)) {
  501.     printf("----------------------------------------------------------------------------------n");
  502.     printf("optimization convergedn");
  503.   }
  504.   
  505.   /* free memory */
  506.   free(workspace);
  507.   free(diag_h_x);
  508.   free(h_y);
  509.   free(c_x);
  510.   free(c_y);
  511.   free(h_dot_x);
  512.   
  513.   free(rho);
  514.   free(nu);
  515.   free(tau);
  516.   free(sigma);
  517.   free(gamma_z);
  518.   free(gamma_s);
  519.   
  520.   free(hat_nu);
  521.   free(hat_tau);
  522.     
  523.   free(delta_x);
  524.   free(delta_y);
  525.   free(delta_s);
  526.   free(delta_z);
  527.   free(delta_g);
  528.   free(delta_t);
  529.     
  530.   free(d);
  531.   /* and return to sender */
  532.   return status;
  533. }