1 /**********************************************************************
2   FILE           : %W%
3 
4   SHORTNAME      :
5   SNNS VERSION   : 4.2
6 
7   PURPOSE        : Implement Kindermann/Linden-inversion-method
8 
9   NOTES          : The functions implemented here closely resemble the
10                    the functions propagateNetForward and propagateNetBackward2
11 		   in the file learn_f.c.
12   FUNCTIONS      : -- kr_initInversion
13                       Purpose : initialize net for inversion algorithm
14 	               Calls   : int kr_topoCheck();
15 		                 int kr_IOCheck();
16 		            	  int kr_topoSort();
17 
18                    -- kr_inv_forwardPass
19  	              Purpose : topological forward propagation
20 	              Calls   : nothing
21 
22 	           -- kr_inv_backwardPass
23                       Purpose : Backward error propagation (topological)
24 	              Calls   : nothing
25 
26   AUTHOR         : Guenter Mamier
27   DATE           : 04.02.92
28 
29   CHANGED BY     : Sven Doering, Michael Vogt
30   RCS VERSION    : $Revision: 2.8 $
31   LAST CHANGE    : $Date: 1998/03/13 16:23:56 $
32 
33     Copyright (c) 1990-1995  SNNS Group, IPVR, Univ. Stuttgart, FRG
34     Copyright (c) 1996-1998  SNNS Group, WSI, Univ. Tuebingen, FRG
35 
36 **********************************************************************/
37 #include <config.h>
38 #include <stdio.h>
39 #include <math.h>
40 #ifdef HAVE_VALUES_H
41 #include <values.h>
42 #endif
43 
44 #include "kr_typ.h"
45 #include "kr_const.h"
46 #include "kernel.h"
47 #include "kr_def.h"
48 #include "kr_mac.h"
49 #include "kr_inversion.ph"
50 
51 extern FlintType ACT_Custom_Python(struct Unit * unit_ptr);
52 extern FlintType ACT_DERIV_Custom_Python(struct Unit * unit_ptr);
53 extern FlintType ACT_2_DERIV_Custom_Python(struct Unit * unit_ptr);
54 
55 
56 
57 /*****************************************************************************
58   FUNCTION : kr_initInversion
59 
60   PURPOSE  : initialize net for inversion algorithm
61   NOTES    :
62   UPDATE   : 06.02.92
63 ******************************************************************************/
kr_initInversion(void)64 int kr_initInversion(void)
65 {
66     int ret_code = KRERR_NO_ERROR;
67 
68     if (NetModified || (TopoSortID != TOPOLOGICAL_FF &&
69 			TopoSortID != TOPOLOGIC_LOGICAL)){
70        /*  Net has been modified or topologic array isn't initialized */
71        /*  check the topology of the network  */
72       ret_code = kr_topoCheck();
73     if (ret_code < KRERR_NO_ERROR)
74        return( ret_code );  /*  an error has occured  */
75     if (ret_code < 2)
76        return( KRERR_NET_DEPTH );  /*  the network has less then 2 layers  */
77 
78 
79     /*  count the no. of I/O units and check the patterns  */
80     ret_code = kr_IOCheck();
81     if(ret_code < KRERR_NO_ERROR)
82        return( ret_code );
83 
84     /*  sort units by topology and by topologic type  */
85 
86     ret_code = kr_topoSort( TOPOLOGICAL_FF );
87   }
88   return(ret_code);
89 }
90 
91 
92 
93 /*****************************************************************************
94   FUNCTION : kr_inv_forwardPass
95 
96   PURPOSE  : topological forward propagation
97   NOTES    :
98   UPDATE   : 29.01.92
99 ******************************************************************************/
100 extern FlintType OUT_Custom_Python(FlintType act);
101 
kr_inv_forwardPass(struct UnitList * inputs)102 void  kr_inv_forwardPass(struct UnitList *inputs)
103 {
104 
105    register struct Unit   *unit_ptr;
106    register TopoPtrArray  topo_ptr;    /* points to a topological sorted    */
107 				       /* unit stucture (input units first) */
108    struct UnitList        *IUnit;      /* working list of input units       */
109 
110 
111    /* initialize the topological pointer */
112 
113    topo_ptr = topo_ptr_array;
114 
115 
116    /*  calculate the activation and output value of the input units */
117 
118    IUnit = inputs;
119    while((unit_ptr = *++topo_ptr) != NULL){
120 
121      /*  clear error values  */
122      unit_ptr->Aux.flint_no = 0.0;
123 
124      if(unit_ptr->out_func == OUT_IDENTITY)
125         unit_ptr->Out.output = unit_ptr->act = IUnit->act;
126      else if(unit_ptr->out_func == OUT_Custom_Python)  /* no identity output function: calculate unit's output also  */
127      	unit_ptr->Out.output =
128 		kr_PythonOutFunction(unit_ptr->python_out_func,
129 				unit_ptr->act = IUnit->act);
130      else  /* no identity output function: calculate unit's output also  */
131        unit_ptr->Out.output = (*unit_ptr->out_func)(unit_ptr->act = IUnit->act);
132      IUnit = IUnit->next;
133    }
134 
135 
136    /*  popagate hidden units  */
137 
138    while((unit_ptr = *++topo_ptr) != NULL){
139 
140      /*  clear error values  */
141      unit_ptr->Aux.flint_no = 0.0;
142 
143      /*  calculate the activation value of the unit:
144 	 call the activation function if needed  */
145      unit_ptr->act = ((unit_ptr->act_func == ACT_Custom_Python) ?
146 			kr_PythonActFunction(unit_ptr->python_act_func,
147 						unit_ptr) :
148 			(unit_ptr->act_func) (unit_ptr)) ;
149 
150      if(unit_ptr->out_func == OUT_IDENTITY)
151        unit_ptr->Out.output = unit_ptr->act;
152      else if(unit_ptr->out_func == OUT_Custom_Python)
153      	unit_ptr->Out.output =
154 		kr_PythonOutFunction(unit_ptr->python_out_func,
155 				unit_ptr->act);
156      else
157        /*  no identity output function: calculate unit's output also  */
158        unit_ptr->Out.output = (*unit_ptr->out_func) (unit_ptr->act);
159    }
160 
161 
162    /*  popagate output units  */
163 
164    while((unit_ptr = *++topo_ptr) != NULL){
165 
166      /*  clear error values  */
167      unit_ptr->Aux.flint_no = 0.0;
168 
169      /*  calculate the activation value of the unit:
170 	 call the activation function if needed  */
171      unit_ptr->act = ((unit_ptr->act_func == ACT_Custom_Python) ?
172 			kr_PythonActFunction(unit_ptr->python_act_func,
173 						unit_ptr) :
174 			(unit_ptr->act_func) (unit_ptr)) ;
175 
176      if(unit_ptr->out_func == OUT_IDENTITY)
177        unit_ptr->Out.output = unit_ptr->act;
178      else if(unit_ptr->out_func == OUT_Custom_Python)      /*  no identity output function: calculate unit's output also  */
179      	unit_ptr->Out.output =
180 		kr_PythonOutFunction(unit_ptr->python_out_func,
181 				unit_ptr->act);
182      else      /*  no identity output function: calculate unit's output also  */
183        unit_ptr->Out.output = (*unit_ptr->out_func) (unit_ptr->act);
184    }
185 }
186 
187 
188 
189 /*****************************************************************************
190   FUNCTION : kr_inv_backwardPass
191 
192   PURPOSE  : Backward error propagation (topological)
193   NOTES    :
194   UPDATE   : 04.02.92
195 *****************************************************************************/
kr_inv_backwardPass(float learn,float delta_max,int * err_units,float ratio,struct UnitList * inputs,struct UnitList * outputs)196 double kr_inv_backwardPass(float learn, float delta_max, int *err_units,
197 			   float ratio, struct UnitList *inputs,
198 			   struct UnitList *outputs)
199 {
200    register struct Link   *link_ptr;
201    register struct Site   *site_ptr;
202    register struct Unit   *unit_ptr;
203    register float         error,  sum_error,  eta,  devit;
204    register TopoPtrArray  topo_ptr;
205    struct UnitList        *IUnit, *OUnit;
206 
207 
208    sum_error = 0.0;    /*  reset network error  */
209    *err_units = 0;     /*  reset error units */
210    eta = learn;        /*  store learn_parameter in CPU register  */
211 
212 
213    /* add 3 to no_of_topo_units because topologic array contains 4 NULL
214       pointers  */
215 
216    topo_ptr = topo_ptr_array + (no_of_topo_units + 3);
217 
218 
219    /*  calculate output units only  */
220 
221    OUnit = outputs;
222    while(OUnit->next != NULL)OUnit = OUnit->next;
223    while((unit_ptr = *--topo_ptr) != NULL){
224 
225 
226      /*  calc. devitation */
227      devit = OUnit->i_act - unit_ptr->Out.output;
228      OUnit->act = unit_ptr->Out.output;
229      OUnit = OUnit->prev;
230      if ( (devit > -delta_max) && (devit < delta_max) ){
231        continue;
232      }else{
233        *err_units += 1;
234      }
235 
236      /*  sum up the error of the network  */
237      sum_error += devit * devit;
238 
239      /*	calc. error for output units	 */
240      error = devit * ((unit_ptr->act_deriv_func == ACT_DERIV_Custom_Python) ?
241 			kr_PythonActFunction(unit_ptr->python_act_deriv_func,
242 						unit_ptr) :
243 			(unit_ptr->act_deriv_func) (unit_ptr)) ;
244      /*     error = devit;*/
245 
246      /* Calculate sum of errors of predecessor units  */
247      if(UNIT_HAS_DIRECT_INPUTS( unit_ptr )){
248        FOR_ALL_LINKS( unit_ptr, link_ptr )
249          link_ptr->to->Aux.flint_no += link_ptr->weight * error;
250      }else{        /*	the unit has sites  */
251        FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr )
252          link_ptr->to->Aux.flint_no += link_ptr->weight * error;
253      }
254    }
255 
256 
257    /*  calculate hidden units only  */
258 
259    while((unit_ptr = *--topo_ptr) != NULL){
260 
261      /*	calc. the error of the (hidden) unit  */
262      error = ((unit_ptr->act_deriv_func == ACT_DERIV_Custom_Python) ?
263 			kr_PythonActFunction(unit_ptr->python_act_deriv_func,
264 						unit_ptr) :
265 			(unit_ptr->act_deriv_func) (unit_ptr))  * unit_ptr->Aux.flint_no;
266      error = unit_ptr->Aux.flint_no;
267 
268      /* Calculate sum of errors of predecessor units  */
269      if(UNIT_HAS_DIRECT_INPUTS( unit_ptr )){
270        FOR_ALL_LINKS( unit_ptr, link_ptr )
271 	  link_ptr->to->Aux.flint_no += link_ptr->weight * error;
272      }else{       /*  the unit has sites  */
273        FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr )
274   	  link_ptr->to->Aux.flint_no += link_ptr->weight * error;
275      }
276      unit_ptr->act = unit_ptr->i_act;
277    }
278 
279 
280    /*  calculate input units only  */
281 
282    IUnit = inputs;
283    while(IUnit->next != NULL)IUnit = IUnit->next;
284    while((unit_ptr = *--topo_ptr) != NULL){
285 
286      /*	calc. the error of the (input) unit  */
287      error = ((unit_ptr->act_deriv_func == ACT_DERIV_Custom_Python) ?
288 			kr_PythonActFunction(unit_ptr->python_act_deriv_func,
289 						unit_ptr) :
290 			(unit_ptr->act_deriv_func) (unit_ptr))  * unit_ptr->Aux.flint_no;
291      error = unit_ptr->Aux.flint_no;
292 
293      /* Calculate the new activation for the input units */
294      IUnit->im_act += eta * error + ratio*(IUnit->i_act - (float)unit_ptr->act);
295      unit_ptr->act = 1.0 / (1.0 + exp((double)(-IUnit->im_act)));
296      IUnit->act = unit_ptr->act;
297      IUnit = IUnit->prev;
298    }
299 
300 
301    /*  return the error of the network */
302 
303    sum_error *= 0.5;
304    return( sum_error );
305 
306 
307 }
308 
309 
310 
311 
312 
313