00001 /*************************************************************************** 00002 * @file gnn_phandle.c 00003 * @brief gnn_phandle Implementation. 00004 * 00005 * @date : 15-08-03 01:44 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 00027 /** 00028 * @brief Handle for managing a set of parameters. 00029 * @defgroup gnn_phandle_doc gnn_phandle : A Handle for Parameters. 00030 * @ingroup gnn_node_doc 00031 * 00032 * The \ref gnn_phandle provides a data structure for encapsulating the 00033 * necessary information for handling shareable parameters. A \ref gnn_phandle 00034 * knows about the number of free (not fixed) parameters, its values, and 00035 * if they are actually used. 00036 * 00037 * The following scheme shows a \ref gnn_phandle. It is important to note that: 00038 * - A reference counter manages the number of clients that are using the 00039 * the parameter handle. If this counter decreases to zero, the handle is 00040 * deallocated with its three vectors. Every client should register the use 00041 * with \ref gnn_phandle_ref and unregister with \ref gnn_phandle_unref. 00042 * 00043 * <img src="images/gnn_phandle1.png"> 00044 * 00045 * - Three vectors are used to store the parameter values, the gradient, 00046 * and the frozen flags. 00047 * - Additional fields keep track of the number of parameters and the 00048 * number of free (not frozen) paramters. 00049 * 00050 * The manipulation of a handle is simple. The handle's vectors w, dw and 00051 * f can be accessed freely through \ref gnn_phandle_get_w, 00052 * \ref gnn_phandle_get_dw and \ref gnn_phandle_get_f respectivelly. After 00053 * changing them, call \ref gnn_phandle_update. This will update the fields 00054 * to reflect the changes that have been made. 00055 * 00056 * Also, the \ref gnn_pbundle interface can be used to manipulate a set 00057 * of related parameter handles. 00058 * 00059 * @warning Currently, the handling of parameters isn't thread safe. 00060 */ 00061 00062 00063 00064 /******************************************/ 00065 /* Include Files */ 00066 /******************************************/ 00067 00068 #include <assert.h> 00069 #include <gsl/gsl_vector.h> 00070 #include <gsl/gsl_errno.h> 00071 #include "gnn_phandle.h" 00072 #include "chunkallocator.h" 00073 00074 00075 00076 /******************************************/ 00077 /* Global variables */ 00078 /******************************************/ 00079 00080 /** 00081 * @brief The internal memory chunk allocator for parameter handles. 00082 * @ingroup gnn_phandle_doc 00083 * 00084 * This variable points to the parameter handle memory allocator. A first 00085 * call to \ref gnn_phandle_new instanciates it. 00086 */ 00087 static chunkallocator *_phallocator = NULL; 00088 00089 00090 00091 /******************************************/ 00092 /* Static Declaration */ 00093 /******************************************/ 00094 00095 static void 00096 gnn_phandle_destroy (gnn_phandle *ph); 00097 00098 static int 00099 gnn_vector_use_flags (gsl_vector *v, const gsl_vector_int *f); 00100 00101 static int 00102 gnn_vector_int_count_frozen_flags (const gsl_vector_int *f); 00103 00104 00105 00106 /******************************************/ 00107 /* Static Implementation */ 00108 /******************************************/ 00109 00110 /** 00111 * @brief Destroys a parameter handle. 00112 * @ingroup gnn_phandle_doc 00113 * 00114 * This static function deallocates the parameter handle's memory, including 00115 * its referenced data blocks for parameters. It can't be called publically, 00116 * because it is only triggered (by \ref gnn_phandle_unref) when the reference 00117 * counter falls to zero. 00118 * 00119 * @param ph The parameter handle to be deallocated. 00120 */ 00121 static void 00122 gnn_phandle_destroy (gnn_phandle *ph) 00123 { 00124 if (ph == NULL) 00125 return; 00126 00127 /* free vectors if any */ 00128 if (ph->w != NULL) 00129 gsl_vector_free (ph->w); 00130 if (ph->dw != NULL) 00131 gsl_vector_free (ph->dw); 00132 if (ph->f != NULL) 00133 gsl_vector_int_free (ph->f); 00134 00135 /* free handle */ 00136 chunkallocator_free (_phallocator, ph); 00137 } 00138 00139 /** 00140 * @brief Set the frozen parameters to zero. 00141 * @ingroup gnn_phandle_doc 00142 * 00143 * This function takes a real vector and an integer vector. The integer vector 00144 * should have binary {0,1} values, that are used as frozen flags. All elements 00145 * of v whose corresponding frozen flag in f is non-zero is set to zero. 00146 * 00147 * @param v A real vector. 00148 * @param f An integer vector of binary values. 00149 * @return 0 if succeeded. 00150 */ 00151 static int 00152 gnn_vector_use_flags (gsl_vector *v, const gsl_vector_int *f) 00153 { 00154 int size; 00155 int i; 00156 double *vptr; 00157 int *fptr; 00158 00159 assert (v != NULL); 00160 assert (f != NULL); 00161 assert (v->size == f->size); 00162 00163 /* copy values */ 00164 size = v->size; 00165 for (i=0, vptr=v->data, fptr=f->data; i<v->size; i++, vptr++, fptr++) 00166 if (*fptr) *vptr = 0.0; 00167 00168 return 0; 00169 } 00170 00171 /** 00172 * @brief Counts the amount of frozen flags. 00173 * @ingroup gnn_phandle_doc 00174 * 00175 * This function takes an integer vector with binary values {0,1} and counts 00176 * the amount of non-zero values, which correspond to frozen flags. 00177 * 00178 * @param f An integer vector of binary values. 00179 * @return 0 if succeeded. 00180 */ 00181 static int 00182 gnn_vector_int_count_frozen_flags (const gsl_vector_int *f) 00183 { 00184 int i; 00185 int *fptr; 00186 int count; 00187 int size; 00188 00189 assert (f != NULL); 00190 00191 /* count frozen flags */ 00192 size = f->size; 00193 for (i=0, fptr=f->data, count=0; i<size; i++, fptr++) 00194 if (*fptr) count++; 00195 return count; 00196 } 00197 00198 00199 00200 /******************************************/ 00201 /* Public Interface Implementation */ 00202 /******************************************/ 00203 00204 /** 00205 * @brief Creates a new parameter handle. 00206 * @ingroup gnn_phandle_doc 00207 * 00208 * This function allocates a new parameter handle for the given number of 00209 * parameters. It creates the underlying blocks of parameters, parameter 00210 * gradients and freeze flags. It's fields are appropiately initialized. 00211 * 00212 * Of course, the number of parameters can perfectly be zero. In this case, 00213 * the creation of the underlying data blocks is ommitted. 00214 * 00215 * @param size The number of parameters that the handle should actually handle. 00216 * @return A pointer to a new parameter handle. 00217 */ 00218 gnn_phandle * 00219 gnn_phandle_new (size_t size) 00220 { 00221 gnn_phandle *ph; 00222 00223 assert (size >= 0); 00224 00225 /* create chunkallocator */ 00226 if (_phallocator == NULL) 00227 { 00228 _phallocator = chunkallocator_new (sizeof (gnn_phandle)); 00229 if (_phallocator == NULL) 00230 GSL_ERROR_VAL ("could not create phandle chunkallocator", 00231 GSL_ENOMEM, NULL); 00232 } 00233 00234 /* create phandle */ 00235 ph = (gnn_phandle *) chunkallocator_alloc (_phallocator); 00236 if (ph == NULL) 00237 GSL_ERROR_VAL ("could not allocate phandle", GSL_ENOMEM, NULL); 00238 00239 /* set fields */ 00240 ph->l = size; 00241 ph->free = size; 00242 ph->modified = 0; 00243 ph->w = NULL; 00244 ph->dw = NULL; 00245 ph->f = NULL; 00246 ph->rc = 1; 00247 00248 /* if there are params, then create them */ 00249 if (size > 0) 00250 { 00251 /* allocate vectors */ 00252 ph->w = gsl_vector_alloc (size); 00253 ph->dw = gsl_vector_alloc (size); 00254 ph->f = gsl_vector_int_calloc (size); 00255 if ((ph->w == NULL) || (ph->dw == NULL) || (ph->f == NULL)) 00256 { 00257 gnn_phandle_destroy (ph); 00258 GSL_ERROR_VAL ("could not allocate phandle vectors", 00259 GSL_ENOMEM, NULL); 00260 } 00261 } 00262 00263 return ph; 00264 } 00265 00266 /** 00267 * @brief Unreferences a parameter handle. 00268 * @ingroup gnn_phandle_doc 00269 * 00270 * This function decreases the reference count of the parameter handle. It 00271 * should be called when the parameters aren't used anymore. 00272 * 00273 * If the reference count drops to zero, then the associated parameters 00274 * aren't used by anyone, triggering the real deallocation of the handle. 00275 * 00276 * @param ph The parameter handle to be unreferenced. 00277 */ 00278 int 00279 gnn_phandle_unref (gnn_phandle *ph) 00280 { 00281 /* check if there is a handle */ 00282 if (ph == NULL) 00283 GSL_ERROR ("cannot unref NULL phandle", GSL_EINVAL); 00284 00285 /* decrease reference counter */ 00286 ph->rc--; 00287 00288 /* free if zero */ 00289 if (ph->rc == 0) 00290 gnn_phandle_destroy (ph); 00291 00292 return 0; 00293 } 00294 00295 /** 00296 * @brief References a parameter handle. 00297 * @ingroup gnn_phandle_doc 00298 * 00299 * This function increases the reference count of the parameter handle. It 00300 * should be called when the parameters are being shared. 00301 * 00302 * @param ph The parameter handle to be referenced. 00303 */ 00304 int 00305 gnn_phandle_ref (gnn_phandle *ph) 00306 { 00307 /* check if there is a handle */ 00308 if (ph == NULL) 00309 GSL_ERROR ("cannot reference NULL phandle", GSL_EINVAL); 00310 00311 /* increase reference counter */ 00312 ph->rc++; 00313 00314 return 0; 00315 } 00316 00317 /** 00318 * @brief Returns the total number of parameters. 00319 * @ingroup gnn_phandle_doc 00320 * 00321 * @param ph A pointer to a parameter handle. 00322 * @return The number of total (free + frozen) parameters. 00323 */ 00324 size_t 00325 gnn_phandle_get_size (gnn_phandle *ph) 00326 { 00327 assert (ph != NULL); 00328 return ph->l; 00329 } 00330 00331 /** 00332 * @brief Returns the number of free parameters. 00333 * @ingroup gnn_phandle_doc 00334 * 00335 * @param ph A pointer to a parameter handle. 00336 * @return The number of free (not fixed) parameters. 00337 */ 00338 size_t 00339 gnn_phandle_get_free (gnn_phandle *ph) 00340 { 00341 assert (ph != NULL); 00342 return ph->free; 00343 } 00344 00345 /** 00346 * @brief Returns a pointer to the internal parameter vector. 00347 * @ingroup gnn_phandle_doc 00348 * 00349 * This function returns a pointer to the internal parameter vector \f$w\f$. 00350 * The user can modify its values at will. After changes are made, the 00351 * \ref gnn_phandle_update function should be called to recompute the 00352 * auxiliary information and reflect the changes. 00353 * 00354 * @param ph The parameter handle to be referenced. 00355 * @return A pointer to the parameter vector. 00356 */ 00357 gsl_vector * 00358 gnn_phandle_get_w (gnn_phandle *ph) 00359 { 00360 assert (ph != NULL); 00361 return ph->w; 00362 } 00363 00364 /** 00365 * @brief Returns a pointer to the internal parameter gradient. 00366 * @ingroup gnn_phandle_doc 00367 * 00368 * This function returns a pointer to the internal parameter gradient 00369 * \f$\frac{\partial E}{\partial w}\f$. 00370 * The user can modify its values at will. After changes are made, the 00371 * \ref gnn_phandle_update function should be called to recompute the 00372 * auxiliary information and reflect the changes. 00373 * 00374 * @param ph The parameter handle to be referenced. 00375 * @return A pointer to the parameter gradient. 00376 */ 00377 gsl_vector * 00378 gnn_phandle_get_dw (gnn_phandle *ph) 00379 { 00380 assert (ph != NULL); 00381 00382 /* set update flag */ 00383 ph->modified |= PHandleUseFlags; 00384 00385 return ph->dw; 00386 } 00387 00388 /** 00389 * @brief Returns a pointer to the internal frozen flags. 00390 * @ingroup gnn_phandle_doc 00391 * 00392 * This function returns a pointer to the internal frozen flags \f$f\f$. 00393 * The user can modify its values at will. After changes are made, the 00394 * \ref gnn_phandle_update function should be called to recompute the 00395 * auxiliary information and reflect the changes. 00396 * 00397 * It should be remembered that the vector's element have binary values. 00398 * That is, 0 means "free" parameter, 1 means "frozen" or "fixed" parameter. 00399 * 00400 * @param ph The parameter handle to be referenced. 00401 * @return A pointer to the frozen flags. 00402 */ 00403 gsl_vector_int * 00404 gnn_phandle_get_f (gnn_phandle *ph) 00405 { 00406 assert (ph != NULL); 00407 00408 /* set update flag */ 00409 ph->modified |= PHandleCountFlags; 00410 00411 return ph->f; 00412 } 00413 00414 /** 00415 * @brief Updates the handle's fields. 00416 * @ingroup gnn_phandle_doc 00417 * 00418 * This function should be called after changes have made to the handle's 00419 * vectors w, dw or f, to update the fields and check for consistency. 00420 * 00421 * @note Only the necessary values are updated. 00422 * 00423 * @param ph The parameter handle to be updated. 00424 * @return 0 if succeeded. 00425 */ 00426 int 00427 gnn_phandle_update (gnn_phandle *ph) 00428 { 00429 assert (ph != NULL); 00430 00431 if (ph->l > 0) 00432 { 00433 /* Count number of flags */ 00434 if (ph->modified & PHandleCountFlags) 00435 { 00436 ph->free = ph->l - gnn_vector_int_count_frozen_flags (ph->f); 00437 ph->modified &= ~PHandleCountFlags; 00438 } 00439 00440 /* Use the flags and set dw to zero where necessary */ 00441 if (ph->modified & PHandleUseFlags) 00442 { 00443 gnn_vector_use_flags (ph->dw, ph->f); 00444 ph->modified &= ~PHandleUseFlags; 00445 } 00446 } 00447 00448 return 0; 00449 } 00450 00451 00452 00453
1.2.18