Graphviz  2.29.20120523.0446
lib/neatogen/conjgrad.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 
00015 #include "matrix_ops.h"
00016 #include "conjgrad.h"
00017 /* #include <math.h> */
00018 #include <stdlib.h>
00019 
00020 
00021 /*************************
00022 ** C.G. method - SPARSE  *
00023 *************************/
00024 
00025 int conjugate_gradient
00026     (vtx_data * A, double *x, double *b, int n, double tol,
00027      int max_iterations) {
00028     /* Solves Ax=b using Conjugate-Gradients method */
00029     /* 'x' and 'b' are orthogonalized against 1 */
00030 
00031     int i, rv = 0;
00032 
00033     double alpha, beta, r_r, r_r_new, p_Ap;
00034     double *r = N_GNEW(n, double);
00035     double *p = N_GNEW(n, double);
00036     double *Ap = N_GNEW(n, double);
00037     double *Ax = N_GNEW(n, double);
00038     double *alphap = N_GNEW(n, double);
00039 
00040     double *orth_b = N_GNEW(n, double);
00041     copy_vector(n, b, orth_b);
00042     orthog1(n, orth_b);
00043     orthog1(n, x);
00044     right_mult_with_vector(A, n, x, Ax);
00045     vectors_subtraction(n, orth_b, Ax, r);
00046     copy_vector(n, r, p);
00047     r_r = vectors_inner_product(n, r, r);
00048 
00049     for (i = 0; i < max_iterations && max_abs(n, r) > tol; i++) {
00050         right_mult_with_vector(A, n, p, Ap);
00051         p_Ap = vectors_inner_product(n, p, Ap);
00052         if (p_Ap == 0)
00053             break;              /*exit(1); */
00054         alpha = r_r / p_Ap;
00055 
00056         /* derive new x: */
00057         vectors_scalar_mult(n, p, alpha, alphap);
00058         vectors_addition(n, x, alphap, x);
00059 
00060         /* compute values for next iteration: */
00061         if (i < max_iterations - 1) {   /* not last iteration */
00062             vectors_scalar_mult(n, Ap, alpha, Ap);
00063             vectors_subtraction(n, r, Ap, r);   /* fast computation of r, the residual */
00064 
00065             /* Alternaive accurate, but slow, computation of the residual - r */
00066             /* right_mult_with_vector(A, n, x, Ax); */
00067             /* vectors_subtraction(n,b,Ax,r); */
00068 
00069             r_r_new = vectors_inner_product(n, r, r);
00070             if (r_r == 0) {
00071                 agerr (AGERR, "conjugate_gradient: unexpected length 0 vector\n");
00072                 rv = 1;
00073                 goto cleanup0;
00074             }
00075             beta = r_r_new / r_r;
00076             r_r = r_r_new;
00077             vectors_scalar_mult(n, p, beta, p);
00078             vectors_addition(n, r, p, p);
00079         }
00080     }
00081 
00082 cleanup0 :
00083     free(r);
00084     free(p);
00085     free(Ap);
00086     free(Ax);
00087     free(alphap);
00088     free(orth_b);
00089 
00090     return rv;
00091 }
00092 
00093 
00094 /****************************
00095 ** C.G. method - DENSE      *
00096 ****************************/
00097 
00098 int conjugate_gradient_f
00099     (float **A, double *x, double *b, int n, double tol,
00100      int max_iterations, boolean ortho1) {
00101     /* Solves Ax=b using Conjugate-Gradients method */
00102     /* 'x' and 'b' are orthogonalized against 1 if 'ortho1=true' */
00103 
00104     int i, rv = 0;
00105 
00106     double alpha, beta, r_r, r_r_new, p_Ap;
00107     double *r = N_GNEW(n, double);
00108     double *p = N_GNEW(n, double);
00109     double *Ap = N_GNEW(n, double);
00110     double *Ax = N_GNEW(n, double);
00111     double *alphap = N_GNEW(n, double);
00112 
00113     double *orth_b = N_GNEW(n, double);
00114     copy_vector(n, b, orth_b);
00115     if (ortho1) {
00116         orthog1(n, orth_b);
00117         orthog1(n, x);
00118     }
00119     right_mult_with_vector_f(A, n, x, Ax);
00120     vectors_subtraction(n, orth_b, Ax, r);
00121     copy_vector(n, r, p);
00122     r_r = vectors_inner_product(n, r, r);
00123 
00124     for (i = 0; i < max_iterations && max_abs(n, r) > tol; i++) {
00125         right_mult_with_vector_f(A, n, p, Ap);
00126         p_Ap = vectors_inner_product(n, p, Ap);
00127         if (p_Ap == 0)
00128             break;              /*exit(1); */
00129         alpha = r_r / p_Ap;
00130 
00131         /* derive new x: */
00132         vectors_scalar_mult(n, p, alpha, alphap);
00133         vectors_addition(n, x, alphap, x);
00134 
00135         /* compute values for next iteration: */
00136         if (i < max_iterations - 1) {   /* not last iteration */
00137             vectors_scalar_mult(n, Ap, alpha, Ap);
00138             vectors_subtraction(n, r, Ap, r);   /* fast computation of r, the residual */
00139 
00140             /* Alternaive accurate, but slow, computation of the residual - r */
00141             /* right_mult_with_vector(A, n, x, Ax); */
00142             /* vectors_subtraction(n,b,Ax,r); */
00143 
00144             r_r_new = vectors_inner_product(n, r, r);
00145             if (r_r == 0) {
00146                 rv = 1;
00147                 agerr (AGERR, "conjugate_gradient: unexpected length 0 vector\n");
00148                 goto cleanup1;
00149             }
00150             beta = r_r_new / r_r;
00151             r_r = r_r_new;
00152             vectors_scalar_mult(n, p, beta, p);
00153             vectors_addition(n, r, p, p);
00154         }
00155     }
00156 cleanup1:
00157     free(r);
00158     free(p);
00159     free(Ap);
00160     free(Ax);
00161     free(alphap);
00162     free(orth_b);
00163 
00164     return rv;
00165 }
00166 
00167 int
00168 conjugate_gradient_mkernel(float *A, float *x, float *b, int n,
00169                            double tol, int max_iterations)
00170 {
00171     /* Solves Ax=b using Conjugate-Gradients method */
00172     /* A is a packed symmetric matrix */
00173     /* matrux A is "packed" (only upper triangular portion exists, row-major); */
00174 
00175     int i, rv = 0;
00176 
00177     double alpha, beta, r_r, r_r_new, p_Ap;
00178     float *r = N_NEW(n, float);
00179     float *p = N_NEW(n, float);
00180     float *Ap = N_NEW(n, float);
00181     float *Ax = N_NEW(n, float);
00182 
00183     /* centering x and b  */
00184     orthog1f(n, x);
00185     orthog1f(n, b);
00186 
00187     right_mult_with_vector_ff(A, n, x, Ax);
00188     /* centering Ax */
00189     orthog1f(n, Ax);
00190 
00191 
00192     vectors_substractionf(n, b, Ax, r);
00193     copy_vectorf(n, r, p);
00194 
00195     r_r = vectors_inner_productf(n, r, r);
00196 
00197     for (i = 0; i < max_iterations && max_absf(n, r) > tol; i++) {
00198         orthog1f(n, p);
00199         orthog1f(n, x);
00200         orthog1f(n, r);
00201 
00202         right_mult_with_vector_ff(A, n, p, Ap);
00203         /* centering Ap */
00204         orthog1f(n, Ap);
00205 
00206         p_Ap = vectors_inner_productf(n, p, Ap);
00207         if (p_Ap == 0)
00208             break;
00209         alpha = r_r / p_Ap;
00210 
00211         /* derive new x: */
00212         vectors_mult_additionf(n, x, (float) alpha, p);
00213 
00214         /* compute values for next iteration: */
00215         if (i < max_iterations - 1) {   /* not last iteration */
00216             vectors_mult_additionf(n, r, (float) -alpha, Ap);
00217 
00218 
00219             r_r_new = vectors_inner_productf(n, r, r);
00220 
00221             if (r_r == 0) {
00222                 rv = 1;
00223                 agerr (AGERR, "conjugate_gradient: unexpected length 0 vector\n");
00224                 goto cleanup2;
00225             }
00226             beta = r_r_new / r_r;
00227             r_r = r_r_new;
00228 
00229             vectors_scalar_multf(n, p, (float) beta, p);
00230 
00231             vectors_additionf(n, r, p, p);
00232         }
00233     }
00234 
00235 cleanup2 :
00236     free(r);
00237     free(p);
00238     free(Ap);
00239     free(Ax);
00240     return rv;
00241 }