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