| 1 | /* $Id$ $Revision$ */ |
| 2 | /* vim:set shiftwidth=4 ts=8: */ |
| 3 | |
| 4 | /************************************************************************* |
| 5 | * Copyright (c) 2011 AT&T Intellectual Property |
| 6 | * All rights reserved. This program and the accompanying materials |
| 7 | * are made available under the terms of the Eclipse Public License v1.0 |
| 8 | * which accompanies this distribution, and is available at |
| 9 | * http://www.eclipse.org/legal/epl-v10.html |
| 10 | * |
| 11 | * Contributors: See CVS logs. Details at http://www.graphviz.org/ |
| 12 | *************************************************************************/ |
| 13 | |
| 14 | #include "general.h" |
| 15 | #include "SparseMatrix.h" |
| 16 | #include "spring_electrical.h" |
| 17 | #include "post_process.h" |
| 18 | #include "sparse_solve.h" |
| 19 | #include <time.h> |
| 20 | #include "uniform_stress.h" |
| 21 | |
| 22 | /* uniform stress solves the model: |
| 23 | |
| 24 | \Sum_{i<->j} (||x_i-x_j||-1)^2 + alpha * \Sum_{i!=j} (||x_i-x_j||^2-M)^2 |
| 25 | |
| 26 | This is somewhat similar to the binary stress model |
| 27 | |
| 28 | */ |
| 29 | |
| 30 | UniformStressSmoother UniformStressSmoother_new(int dim, SparseMatrix A, real *x, real alpha, real M, int *flag){ |
| 31 | UniformStressSmoother sm; |
| 32 | int i, j, k, m = A->m, *ia = A->ia, *ja = A->ja, *iw, *jw, *id, *jd; |
| 33 | int nz; |
| 34 | real *d, *w, *a = (real*) A->a; |
| 35 | real diag_d, diag_w, dist, epsilon = 0.01; |
| 36 | |
| 37 | assert(SparseMatrix_is_symmetric(A, FALSE)); |
| 38 | |
| 39 | sm = MALLOC(sizeof(struct StressMajorizationSmoother_struct)); |
| 40 | sm->data = NULL; |
| 41 | sm->scheme = SM_SCHEME_UNIFORM_STRESS; |
| 42 | sm->lambda = NULL; |
| 43 | sm->data = MALLOC(sizeof(real)*2); |
| 44 | ((real*) sm->data)[0] = alpha; |
| 45 | ((real*) sm->data)[1] = M; |
| 46 | sm->data_deallocator = FREE; |
| 47 | sm->tol_cg = 0.01; |
| 48 | sm->maxit_cg = (int)sqrt((double) A->m); |
| 49 | |
| 50 | /* Lw and Lwd have diagonals */ |
| 51 | sm->Lw = SparseMatrix_new(m, m, A->nz + m, MATRIX_TYPE_REAL, FORMAT_CSR); |
| 52 | sm->Lwd = SparseMatrix_new(m, m, A->nz + m, MATRIX_TYPE_REAL, FORMAT_CSR); |
| 53 | iw = sm->Lw->ia; jw = sm->Lw->ja; |
| 54 | id = sm->Lwd->ia; jd = sm->Lwd->ja; |
| 55 | w = (real*) sm->Lw->a; d = (real*) sm->Lwd->a; |
| 56 | |
| 57 | if (!(sm->Lw) || !(sm->Lwd)) { |
| 58 | StressMajorizationSmoother_delete(sm); |
| 59 | return NULL; |
| 60 | } |
| 61 | |
| 62 | iw = sm->Lw->ia; jw = sm->Lw->ja; |
| 63 | id = sm->Lwd->ia; jd = sm->Lwd->ja; |
| 64 | w = (real*) sm->Lw->a; d = (real*) sm->Lwd->a; |
| 65 | iw[0] = id[0] = 0; |
| 66 | |
| 67 | nz = 0; |
| 68 | for (i = 0; i < m; i++){ |
| 69 | diag_d = diag_w = 0; |
| 70 | for (j = ia[i]; j < ia[i+1]; j++){ |
| 71 | k = ja[j]; |
| 72 | if (k != i){ |
| 73 | dist = MAX(ABS(a[j]), epsilon); |
| 74 | jd[nz] = jw[nz] = k; |
| 75 | w[nz] = -1/(dist*dist); |
| 76 | w[nz] = -1.; |
| 77 | d[nz] = w[nz]*dist; |
| 78 | diag_w += w[nz]; |
| 79 | diag_d += d[nz]; |
| 80 | nz++; |
| 81 | } |
| 82 | } |
| 83 | jd[nz] = jw[nz] = i; |
| 84 | w[nz] = -diag_w; |
| 85 | d[nz] = -diag_d; |
| 86 | nz++; |
| 87 | |
| 88 | iw[i+1] = nz; |
| 89 | id[i+1] = nz; |
| 90 | |
| 91 | } |
| 92 | |
| 93 | sm->Lw->nz = nz; |
| 94 | sm->Lwd->nz = nz; |
| 95 | |
| 96 | return sm; |
| 97 | } |
| 98 | |
| 99 | |
| 100 | void UniformStressSmoother_delete(UniformStressSmoother sm){ |
| 101 | |
| 102 | StressMajorizationSmoother_delete(sm); |
| 103 | |
| 104 | } |
| 105 | |
| 106 | real UniformStressSmoother_smooth(UniformStressSmoother sm, int dim, real *x, int maxit_sm) { |
| 107 | |
| 108 | return StressMajorizationSmoother_smooth(sm, dim, x, maxit_sm, 0.001); |
| 109 | |
| 110 | } |
| 111 | |
| 112 | SparseMatrix get_distance_matrix(SparseMatrix A, real scaling){ |
| 113 | /* get a distance matrix from a graph, at the moment we just symmetrize the matrix. At the moment if the matrix is not real, |
| 114 | we just assume distance of 1 among edges. Then we apply scaling to the entire matrix */ |
| 115 | SparseMatrix B; |
| 116 | real *val; |
| 117 | int i; |
| 118 | |
| 119 | if (A->type == MATRIX_TYPE_REAL){ |
| 120 | B = SparseMatrix_symmetrize(A, FALSE); |
| 121 | } else { |
| 122 | B = SparseMatrix_get_real_adjacency_matrix_symmetrized(A); |
| 123 | } |
| 124 | val = (real*) B->a; |
| 125 | if (scaling != 1) for (i = 0; i < B->nz; i++) val[i] *= scaling; |
| 126 | return B; |
| 127 | } |
| 128 | |
| 129 | extern void scale_to_box(real xmin, real ymin, real xmax, real ymax, int n, int dim, real *x); |
| 130 | |
| 131 | void uniform_stress(int dim, SparseMatrix A, real *x, int *flag){ |
| 132 | UniformStressSmoother sm; |
| 133 | real lambda0 = 10.1, M = 100, scaling = 1.; |
| 134 | int maxit = 300, samepoint = TRUE, i, k, n = A->m; |
| 135 | SparseMatrix B = NULL; |
| 136 | |
| 137 | *flag = 0; |
| 138 | |
| 139 | /* just set random initial for now */ |
| 140 | for (i = 0; i < dim*n; i++) { |
| 141 | x[i] = M*drand(); |
| 142 | } |
| 143 | |
| 144 | /* make sure x is not all at the same point */ |
| 145 | for (i = 1; i < n; i++){ |
| 146 | for (k = 0; k < dim; k++) { |
| 147 | if (ABS(x[0*dim+k] - x[i*dim+k]) > MACHINEACC){ |
| 148 | samepoint = FALSE; |
| 149 | i = n; |
| 150 | break; |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | if (samepoint){ |
| 156 | srand(1); |
| 157 | #ifdef DEBUG_PRINT |
| 158 | fprintf(stderr,"input coordinates to uniform_stress are the same, use random coordinates as initial input" ); |
| 159 | #endif |
| 160 | for (i = 0; i < dim*n; i++) x[i] = M*drand(); |
| 161 | } |
| 162 | |
| 163 | B = get_distance_matrix(A, scaling); |
| 164 | assert(SparseMatrix_is_symmetric(B, FALSE)); |
| 165 | |
| 166 | sm = UniformStressSmoother_new(dim, B, x, 1000000*lambda0, M, flag); |
| 167 | UniformStressSmoother_smooth(sm, dim, x, maxit); |
| 168 | UniformStressSmoother_delete(sm); |
| 169 | |
| 170 | sm = UniformStressSmoother_new(dim, B, x, 10000*lambda0, M, flag); |
| 171 | UniformStressSmoother_smooth(sm, dim, x, maxit); |
| 172 | UniformStressSmoother_delete(sm); |
| 173 | |
| 174 | sm = UniformStressSmoother_new(dim, B, x, 100*lambda0, M, flag); |
| 175 | UniformStressSmoother_smooth(sm, dim, x, maxit); |
| 176 | UniformStressSmoother_delete(sm); |
| 177 | |
| 178 | sm = UniformStressSmoother_new(dim, B, x, lambda0, M, flag); |
| 179 | UniformStressSmoother_smooth(sm, dim, x, maxit); |
| 180 | UniformStressSmoother_delete(sm); |
| 181 | |
| 182 | scale_to_box(0,0,7*70,10*70,A->m,dim,x);; |
| 183 | |
| 184 | SparseMatrix_delete(B); |
| 185 | |
| 186 | } |
| 187 | |