Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

gnn_phandle.c

Go to the documentation of this file.
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 

Generated on Sun Jun 13 20:50:12 2004 for libgnn Gradient Retropropagation Machine Library by doxygen1.2.18