/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/neatogen/smart_ini_x.c

Go to the documentation of this file.
00001 /* $Id: smart_ini_x.c,v 1.5 2006/12/07 22:49:37 erg Exp $ $Revision: 1.5 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #include "digcola.h"
00018 #ifdef DIGCOLA
00019 #include "kkutils.h"
00020 #include "matrix_ops.h"
00021 #include "conjgrad.h"
00022 
00023 static void
00024 standardize(double* orthog, int nvtxs) 
00025 {
00026         double len, avg = 0;
00027     int i;
00028         for (i=0; i<nvtxs; i++)
00029                 avg+=orthog[i];
00030         avg/=nvtxs;
00031         
00032         /* centralize: */
00033         for (i=0; i<nvtxs; i++)
00034                 orthog[i]-=avg;
00035         
00036         /* normalize: */
00037         len = norm(orthog, 0, nvtxs-1);
00038         vecscale(orthog, 0, nvtxs-1, 1.0 / len, orthog);
00039 }
00040 
00041 static void
00042 mat_mult_vec_orthog(float** mat, int dim1, int dim2, double* vec, 
00043     double* result, double* orthog)
00044 {
00045         /* computes mat*vec, where mat is a dim1*dim2 matrix */
00046         int i,j;
00047         double sum;
00048         
00049         for (i=0; i<dim1; i++) {
00050                 sum=0;
00051                 for (j=0; j<dim2; j++) {
00052                         sum += mat[i][j]*vec[j];
00053                 }
00054                 result[i]=sum;
00055         }
00056         if (orthog!=NULL) {
00057                 double alpha=-dot(result,0,dim1-1,orthog);
00058                 scadd(result, 0, dim1-1, alpha, orthog);        
00059         }               
00060 }
00061 
00062 static void
00063 power_iteration_orthog(float** square_mat, int n, int neigs, 
00064      double** eigs, double* evals, double* orthog, double p_iteration_threshold)
00065 {
00066         /*
00067          * Power-Iteration with (I-orthog*orthog^T)*square_mat*(I-orthog*orthog^T)
00068      */
00069 
00070         int i,j;
00071         double *tmp_vec = N_GNEW(n, double);
00072         double *last_vec = N_GNEW(n, double);
00073         double *curr_vector;
00074         double len;
00075         double angle;
00076         double alpha;
00077         int iteration;
00078         int largest_index;
00079         double largest_eval;
00080 
00081         double tol=1-p_iteration_threshold;
00082 
00083         if (neigs>=n) {
00084                 neigs=n;
00085         }
00086 
00087         for (i=0; i<neigs; i++) {
00088                 curr_vector = eigs[i];
00089                 /* guess the i-th eigen vector */
00090 choose:
00091                 for (j=0; j<n; j++) {
00092                         curr_vector[j] = rand()%100;
00093                 }
00094 
00095                 if (orthog!=NULL) {
00096                         alpha=-dot(orthog,0,n-1,curr_vector);
00097                         scadd(curr_vector, 0, n-1, alpha, orthog);      
00098                 }
00099                         // orthogonalize against higher eigenvectors
00100                 for (j=0; j<i; j++) {
00101                         alpha = -dot(eigs[j], 0, n-1, curr_vector);
00102                         scadd(curr_vector, 0, n-1, alpha, eigs[j]);
00103             }
00104                 len = norm(curr_vector, 0, n-1);
00105                 if (len<1e-10) {
00106                         /* We have chosen a vector colinear with prvious ones */
00107                         goto choose;
00108                 }
00109                 vecscale(curr_vector, 0, n-1, 1.0 / len, curr_vector);  
00110                 iteration=0;
00111                 do {
00112                         iteration++;
00113                         cpvec(last_vec,0,n-1,curr_vector);
00114                         
00115                         mat_mult_vec_orthog(square_mat,n,n,curr_vector,tmp_vec,orthog);
00116                         cpvec(curr_vector,0,n-1,tmp_vec);
00117                                                 
00118                         /* orthogonalize against higher eigenvectors */
00119                         for (j=0; j<i; j++) {
00120                                 alpha = -dot(eigs[j], 0, n-1, curr_vector);
00121                                 scadd(curr_vector, 0, n-1, alpha, eigs[j]);
00122                         }
00123                         len = norm(curr_vector, 0, n-1);
00124                         if (len<1e-10) {
00125                             /* We have reached the null space (e.vec. associated 
00126                  * with e.val. 0)
00127                  */
00128                                 goto exit;
00129                         }
00130 
00131                         vecscale(curr_vector, 0, n-1, 1.0 / len, curr_vector);
00132                         angle = dot(curr_vector, 0, n-1, last_vec);
00133                 } while (fabs(angle)<tol);
00134         /* the Rayleigh quotient (up to errors due to orthogonalization):
00135          * u*(A*u)/||A*u||)*||A*u||, where u=last_vec, and ||u||=1
00136          */
00137                 evals[i]=angle*len;
00138         }
00139 exit:
00140         for (; i<neigs; i++) {
00141                 /* compute the smallest eigenvector, which are 
00142                  * probably associated with eigenvalue 0 and for
00143                  * which power-iteration is dangerous
00144          */
00145                 curr_vector = eigs[i];
00146                 /* guess the i-th eigen vector */
00147                 for (j=0; j<n; j++)
00148                         curr_vector[j] = rand()%100;
00149                 /* orthogonalize against higher eigenvectors */
00150                 for (j=0; j<i; j++) {
00151                         alpha = -dot(eigs[j], 0, n-1, curr_vector);
00152                         scadd(curr_vector, 0, n-1, alpha, eigs[j]);
00153             }
00154                 len = norm(curr_vector, 0, n-1);
00155                 vecscale(curr_vector, 0, n-1, 1.0 / len, curr_vector);
00156                 evals[i]=0;
00157                 
00158         }
00159 
00160         /* sort vectors by their evals, for overcoming possible mis-convergence: */
00161         for (i=0; i<neigs-1; i++) {
00162                 largest_index=i;
00163                 largest_eval=evals[largest_index];
00164                 for (j=i+1; j<neigs; j++) {
00165                         if (largest_eval<evals[j]) {
00166                                 largest_index=j;
00167                                 largest_eval=evals[largest_index];
00168                         }
00169                 }
00170                 if (largest_index!=i) { // exchange eigenvectors:
00171                         cpvec(tmp_vec,0,n-1,eigs[i]);
00172                         cpvec(eigs[i],0,n-1,eigs[largest_index]);
00173                         cpvec(eigs[largest_index],0,n-1,tmp_vec);
00174 
00175                         evals[largest_index]=evals[i];
00176                         evals[i]=largest_eval;
00177                 }
00178         }
00179         
00180         free (tmp_vec); free (last_vec);
00181 
00182 }
00183 
00184 static float* 
00185 compute_avgs(DistType** Dij, int n, float* all_avg) 
00186 {
00187         float* row_avg = N_GNEW(n, float);
00188         int i,j;
00189         double sum=0, sum_row;
00190 
00191         for (i=0; i<n; i++) {
00192                 sum_row=0;
00193                 for (j=0; j<n; j++) {
00194                         sum+=(double)Dij[i][j]*(double)Dij[i][j];
00195                         sum_row+=(double)Dij[i][j]*(double)Dij[i][j];
00196                 }
00197                 row_avg[i]=(float)sum_row/n;
00198         }
00199         *all_avg=(float)sum/(n*n);
00200     return row_avg;
00201 }
00202 
00203 static float**
00204 compute_Bij(DistType** Dij, int n)
00205 {
00206         int i,j;
00207         float* storage = N_GNEW(n*n,float);
00208         float** Bij = N_GNEW(n, float*);
00209         float* row_avg; 
00210     float all_avg;
00211 
00212         for (i=0; i<n; i++) 
00213                 Bij[i] = storage+i*n;
00214 
00215         row_avg = compute_avgs(Dij, n, &all_avg);       
00216         for (i=0; i<n; i++) {
00217                 for (j=0; j<=i; j++) {
00218                         Bij[i][j]=-(float)Dij[i][j]*Dij[i][j]+row_avg[i]+row_avg[j]-all_avg;
00219                         Bij[j][i]=Bij[i][j];
00220                 }
00221         }
00222     free (row_avg);
00223     return Bij;
00224 }
00225 
00226 static void
00227 CMDS_orthog(vtx_data* graph, int n, int dim, double** eigs, double tol, 
00228             double* orthog, DistType** Dij)
00229 {
00230         int i,j;
00231         float** Bij = compute_Bij(Dij, n);
00232         double* evals= N_GNEW(dim, double);
00233         
00234         double * orthog_aux = NULL;
00235         if (orthog!=NULL) {
00236                 orthog_aux = N_GNEW(n, double);
00237                 for (i=0; i<n; i++) {
00238                         orthog_aux[i]=orthog[i];
00239                 }
00240                 standardize(orthog_aux,n);
00241         }
00242     power_iteration_orthog(Bij, n, dim, eigs, evals, orthog_aux, tol);
00243         
00244         for (i=0; i<dim; i++) {
00245                 for (j=0; j<n; j++) {
00246                         eigs[i][j]*=sqrt(fabs(evals[i])); 
00247                 }
00248         }
00249         free (Bij[0]); free (Bij);
00250         free (evals); free (orthog_aux);
00251 }
00252 
00253 #define SCALE_FACTOR 256
00254 
00255 void IMDS_given_dim(vtx_data* graph, int n, double* given_coords, 
00256        double* new_coords, double conj_tol)
00257 {
00258         int iterations2;
00259         int i,j;
00260         DistType** Dij;
00261         float* f_storage = NULL;        
00262         double* x = given_coords;       
00263         double uniLength;
00264         double* orthog_aux = NULL;
00265         double* y = new_coords;
00266         float** lap = N_GNEW(n, float*);
00267         float degree;
00268         double pos_i;
00269         double* balance = N_GNEW(n, double);
00270         double b;
00271         boolean converged;
00272 
00273 #if 0
00274         iterations1=mat_mult_count1=0; /* We don't compute the x-axis at all. */
00275 #endif
00276 
00277         Dij = compute_apsp(graph, n);
00278         
00279         /* scaling up the distances to enable an 'sqrt' operation later 
00280      * (in case distances are integers)
00281      */
00282         for (i=0; i<n; i++)
00283                 for (j=0; j<n; j++)
00284                         Dij[i][j]*=SCALE_FACTOR;
00285         
00286         assert(x!=NULL);
00287         {
00288                 double sum1, sum2;
00289                 /* scale x (given axis) to minimize the stress */
00290                 orthog_aux = N_GNEW(n, double);
00291                 for (i=0; i<n; i++) {
00292                         orthog_aux[i]=x[i];
00293                 }
00294                 standardize(orthog_aux,n);
00295         
00296                 for (sum1=sum2=0,i=1; i<n; i++) {
00297                         for (j=0; j<i; j++) {           
00298                                 sum1+=1.0/(Dij[i][j])*fabs(x[i]-x[j]);
00299                                 sum2+=1.0/(Dij[i][j]*Dij[i][j])*fabs(x[i]-x[j])*fabs(x[i]-x[j]);
00300                         }
00301                 }
00302                 uniLength=sum1/sum2;
00303                 for (i=0; i<n; i++)
00304                         x[i]*=uniLength;
00305         }
00306 
00307         /* smart ini: */
00308         CMDS_orthog(graph, n, 1, &y, conj_tol, x, Dij);
00309         
00310         /* Compute Laplacian: */
00311         f_storage = N_GNEW(n*n, float);
00312         
00313         for (i=0; i<n; i++) {
00314                 lap[i]=f_storage+i*n;
00315                 degree=0;
00316                 for (j=0; j<n; j++) {
00317                         if (j==i)
00318                                 continue;
00319                         degree-=lap[i][j]=-1.0f/((float)Dij[i][j]*(float)Dij[i][j]); // w_{ij}
00320                         
00321                 }
00322                 lap[i][i]=degree;
00323         }
00324         
00325 
00326         /* compute residual distances */
00327         /* if (x!=NULL)  */
00328     {
00329                 double diff;
00330                 for (i=1; i<n; i++) {
00331                         pos_i=x[i];             
00332                         for (j=0; j<i; j++) {
00333                                 diff=(double)Dij[i][j]*(double)Dij[i][j]-(pos_i-x[j])*(pos_i-x[j]);
00334                                 Dij[i][j]=Dij[j][i]=diff>0 ? (DistType)sqrt(diff) : 0;
00335                         }
00336                 }
00337         }
00338         
00339         /* Compute the balance vector: */
00340         for (i=0; i<n; i++) {
00341                 pos_i=y[i];
00342                 balance[i]=0;
00343                 for (j=0; j<n; j++) {
00344                         if (j==i)
00345                                 continue;
00346                         if (pos_i>=y[j]) {
00347                                 balance[i]+=Dij[i][j]*(-lap[i][j]); // w_{ij}*delta_{ij}
00348                         }
00349                         else {
00350                                 balance[i]-=Dij[i][j]*(-lap[i][j]); // w_{ij}*delta_{ij}
00351                         }
00352                 }
00353         }
00354 
00355         for (converged=FALSE,iterations2=0; iterations2<200 && !converged; iterations2++) {
00356                 conjugate_gradient_f(lap, y, balance, n, conj_tol, n, TRUE);
00357                 converged=TRUE;
00358                 for (i=0; i<n; i++) {
00359                         pos_i=y[i];
00360                         b=0;
00361                         for (j=0; j<n; j++) {
00362                                 if (j==i)
00363                                         continue;
00364                                 if (pos_i>=y[j]) {
00365                                         b+=Dij[i][j]*(-lap[i][j]);
00366                                         
00367                                 }
00368                                 else {
00369                                         b-=Dij[i][j]*(-lap[i][j]);
00370                                         
00371                                 }
00372                         }
00373                         if ((b != balance[i]) && (fabs(1-b/balance[i])>1e-5)) {
00374                                 converged=FALSE;
00375                                 balance[i]=b;
00376                         }
00377                 }
00378         }
00379         
00380         for (i=0; i<n; i++) {
00381                 x[i] /= uniLength;
00382                 y[i] /= uniLength;
00383         }
00384         
00385 
00386         free (Dij[0]); free (Dij);      
00387         free (lap[0]); free (lap);      
00388         free (orthog_aux); free (balance);      
00389 }
00390 
00391 #endif /* DIGCOLA */
00392 

Generated on Mon Mar 31 19:03:27 2008 for Graphviz by  doxygen 1.5.1