00001 /*************************************************************************** 00002 * @file gnn_convergence.c 00003 * @brief gnn_convergence Implementation. 00004 * 00005 * @date : 28-09-03 13:41 00006 * @author : Pedro Ortega C. <peortega@dcc.uchile.cl> 00007 * Copyright 2003 Pedro Ortega C. 00008 ****************************************************************************/ 00009 /* 00010 * This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00023 */ 00024 00025 /** 00026 * @defgroup gnn_convergence_doc gnn_convergence : Input Convergence. 00027 * @ingroup gnn_atomic_doc 00028 * 00029 * The \ref gnn_convergence node is a special node that takes a big input 00030 * vector and slices it into mini-vectors that fit into the output. This 00031 * can be viewed a if the input where in reality a concatenation of subvectors 00032 * of the same size. 00033 * 00034 * The function implemented by this node is given by: 00035 * 00036 * \f[ y_j = 00037 * \frac{1}{S} \left ( x_j + x_{m+j} + x_{2m+j} + \ldots + x_{(S-1)m+j} \right ) 00038 * = \frac{1}{S} \sum_{k=0}^{S-1} x_{km+j} 00039 * \f] 00040 * 00041 * In other words, it slices the input vector \f$x\f$ into several subvectors 00042 * of size \f$m \times 1\f$ and sums them up, divided by the total amount 00043 * of resulting pieces \f$S\f$. Remember that \f$m\f$ is the output size. 00044 * 00045 * If the input vector's 00046 * size isn't a multiple of the output vector's size, 00047 * that is, if \f$n\f$ can't be written as \f$km\f$, then the last vector slice 00048 * will consider only the remaining terms, e.g. 00049 * if \f$x=[x_0, \ldots, x_5]^T\f$ and \f$y\f$ is of size 00050 * \f$4 \times 1\f$ then 00051 * 00052 * \f[ y = 1/2 \left [ \begin{array}{c} 00053 * (x_0 + x_4) \\ 00054 * (x_1 + x_5) \\ 00055 * x_2 \\ 00056 * x_3 \\ 00057 * \end{array} \right ] 00058 * \f] 00059 * 00060 * Schematically, this idea can be depicted as 00061 * 00062 * <img src="images/gnn_convergence1.png"> 00063 * 00064 * The function's gradient is: 00065 * \f[ \frac{\partial E}{\partial x_i} 00066 * = S \frac{\partial E}{\partial x_{km+j}} 00067 * = S \frac{\partial E}{\partial y_j} 00068 * \f] 00069 * 00070 * 00071 */ 00072 00073 00074 /******************************************/ 00075 /* Include Files */ 00076 /******************************************/ 00077 00078 #include "gnn_convergence.h" 00079 00080 00081 00082 /******************************************/ 00083 /* Static Declaration */ 00084 /******************************************/ 00085 00086 static int 00087 gnn_convergence_f (gnn_node *node, 00088 const gsl_vector *x, 00089 const gsl_vector *w, 00090 gsl_vector *y); 00091 00092 static int 00093 gnn_convergence_dx (gnn_node *node, 00094 const gsl_vector *x, 00095 const gsl_vector *w, 00096 const gsl_vector *dy, 00097 gsl_vector *dx); 00098 00099 static int 00100 gnn_convergence_dw (gnn_node *node, 00101 const gsl_vector *x, 00102 const gsl_vector *w, 00103 const gsl_vector *dy, 00104 gsl_vector *dw); 00105 00106 static void 00107 gnn_convergence_destroy (gnn_node *node); 00108 00109 00110 00111 /******************************************/ 00112 /* Static Implementation */ 00113 /******************************************/ 00114 00115 /** 00116 * @brief Computes the output. 00117 * @ingroup gnn_convergence_doc 00118 * 00119 * @param node A pointer to the \ref gnn_convergence node. 00120 * @param x The input vector \f$x\f$. 00121 * @param w The parameter vector \f$w\f$. 00122 * @param y The output buffer vector \f$y\f$. 00123 * @return Returns 0 on success. 00124 */ 00125 static int 00126 gnn_convergence_f (gnn_node *node, 00127 const gsl_vector *x, 00128 const gsl_vector *w, 00129 gsl_vector *y) 00130 { 00131 size_t n; 00132 size_t m; 00133 size_t k; 00134 gnn_convergence *cnode; 00135 00136 /* get views */ 00137 cnode = (gnn_convergence *) node; 00138 00139 /* get input and output size */ 00140 n = gnn_node_input_get_size (node); 00141 m = gnn_node_output_get_size (node); 00142 00143 /* evaluate */ 00144 gsl_vector_set_zero (y); 00145 for (k=0; k<n; ++k) 00146 { 00147 size_t j; 00148 double yj; 00149 00150 j = k % m; 00151 yj = gsl_vector_get (y, j); 00152 yj += 1.0/cnode->rep * gsl_vector_get (x, k); 00153 gsl_vector_set (y, j, yj); 00154 } 00155 00156 return 0; 00157 } 00158 00159 /** 00160 * @brief Computes \f$ \frac{\partial E}{\partial x} \f$. 00161 * @ingroup gnn_convergence_doc 00162 * 00163 * @param node A pointer to the \ref gnn_convergence node. 00164 * @param x The input vector \f$x\f$. 00165 * @param w The parameter vector \f$w\f$. 00166 * @param dy The vector \f$\frac{\partial E}{\partial y}\f$. 00167 * @param dx The output buffer vector \f$\frac{\partial E}{\partial x}\f$. 00168 * @return Returns 0 on success. 00169 */ 00170 static int 00171 gnn_convergence_dx (gnn_node *node, 00172 const gsl_vector *x, 00173 const gsl_vector *w, 00174 const gsl_vector *dy, 00175 gsl_vector *dx) 00176 { 00177 size_t n; 00178 size_t m; 00179 size_t k; 00180 gnn_convergence *cnode; 00181 00182 /* get views */ 00183 cnode = (gnn_convergence *) node; 00184 00185 /* get input and output size */ 00186 n = gnn_node_input_get_size (node); 00187 m = gnn_node_output_get_size (node); 00188 00189 /* evaluate */ 00190 for (k=0; k<n; ++k) 00191 { 00192 size_t j; 00193 double dxk; 00194 00195 j = k % m; 00196 dxk = cnode->rep * gsl_vector_get (dy, j); 00197 gsl_vector_set (dx, k, dxk); 00198 } 00199 00200 return 0; 00201 } 00202 00203 /** 00204 * @brief Computes \f$ \frac{\partial E}{\partial w} \f$. 00205 * @ingroup gnn_convergence_doc 00206 * 00207 * @param node A pointer to the \ref gnn_convergence node. 00208 * @param x The input vector \f$x\f$. 00209 * @param w The parameter vector \f$w\f$. 00210 * @param dy The vector \f$\frac{\partial E}{\partial y}\f$. 00211 * @param dx The output buffer vector \f$\frac{\partial E}{\partial w}\f$. 00212 * @return Returns 0 on success. 00213 */ 00214 static int 00215 gnn_convergence_dw (gnn_node *node, 00216 const gsl_vector *x, 00217 const gsl_vector *w, 00218 const gsl_vector *dy, 00219 gsl_vector *dw) 00220 { 00221 return 0; 00222 } 00223 00224 00225 00226 /******************************************/ 00227 /* Public Interface */ 00228 /******************************************/ 00229 00230 /** 00231 * @brief Creates an input convergence node. 00232 * @ingroup gnn_convergence_doc 00233 * 00234 * This function creates a node of the \ref gnn_convergence type. 00235 * 00236 * @param input_size The input size \f$n\f$. 00237 * @param output_size The output size \f$m\f$. 00238 * @return A pointer to a new \ref gnn_convergence node. 00239 */ 00240 gnn_node * 00241 gnn_convergence_new (size_t input_size, size_t output_size) 00242 { 00243 int status; 00244 size_t k; 00245 gnn_node *node; 00246 gnn_convergence *cnode; 00247 00248 /* check sizes */ 00249 if (output_size < 1) 00250 { 00251 GSL_ERROR_VAL ("output size should be strictly positive", 00252 GSL_EINVAL, NULL); 00253 } 00254 if (input_size < output_size) 00255 { 00256 GSL_ERROR_VAL ("input size should be greater than the output size", 00257 GSL_EINVAL, NULL); 00258 } 00259 00260 /* allocate the node */ 00261 cnode = (gnn_convergence *) malloc (sizeof (gnn_convergence)); 00262 if (cnode == NULL) 00263 { 00264 GSL_ERROR_VAL ("could not allocate memory for gnn_convergence node", 00265 GSL_ENOMEM, NULL); 00266 } 00267 00268 /* get view as a gnn_node */ 00269 node = (gnn_node *) cnode; 00270 00271 /* Initialize the node */ 00272 status = gnn_node_init (node, 00273 "gnn_convergence", 00274 gnn_convergence_f, 00275 gnn_convergence_dx, 00276 gnn_convergence_dw, 00277 NULL); 00278 if (status) 00279 { 00280 GSL_ERROR_VAL ("could not initialize gnn_convergence node", 00281 GSL_EFAILED, NULL); 00282 } 00283 00284 status = gnn_node_set_sizes (node, input_size, output_size, 0); 00285 if (status) 00286 { 00287 GSL_ERROR_VAL ("could not set sizes for gnn_convergence node", 00288 GSL_EFAILED, NULL); 00289 } 00290 00291 /* compute amount of replications */ 00292 cnode->rep = input_size / output_size; 00293 cnode->rep += (input_size % output_size == 0)? 0 : 1; 00294 00295 return node; 00296 } 00297 00298
1.2.18