libeblearn
/home/rex/ebltrunk/core/libeblearn/include/ebl_tester.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2008 by Yann LeCun, Pierre Sermanet, Koray Kavukcuoglu *
00003  *   yann@cs.nyu.edu, pierre.sermanet@gmail.com, koray@cs.nyu.edu *
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *     * Redistributions of source code must retain the above copyright
00008  *       notice, this list of conditions and the following disclaimer.
00009  *     * Redistributions in binary form must reproduce the above copyright
00010  *       notice, this list of conditions and the following disclaimer in the
00011  *       documentation and/or other materials provided with the distribution.
00012  *     * Redistribution under a license not approved by the Open Source
00013  *       Initiative (http://www.opensource.org) must display the
00014  *       following acknowledgement in all advertising material:
00015  *        This product includes software developed at the Courant
00016  *        Institute of Mathematical Sciences (http://cims.nyu.edu).
00017  *     * The names of the authors may not be used to endorse or promote products
00018  *       derived from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00021  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY
00024  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00027  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  ***************************************************************************/
00031 
00032 using namespace std;
00033 
00034 namespace ebl {
00035 
00036   template <class T>
00037   module_tester<T>::module_tester(double thres_, T rrange_min_, T rrange_max_,
00038                                   FILE* out_)  
00039     : acc_thres(thres_), rrange_min(rrange_min_), rrange_max(rrange_max_), 
00040       out(out_),
00041       jac_fprop(1,1), jac_bprop(1,1), jac_pfprop(1,1), jac_pbprop(1,1),
00042       hes_fprop(1,1), hes_bprop(1,1), hes_pfprop(1,1), hes_pbprop(1,1) {
00043     dynamic_init_drand();
00044   }
00045 
00046   template <class T>
00047   module_tester<T>::~module_tester() {
00048   }
00049 
00050   template <class T>
00051   idx<double> module_tester<T>::
00052   test_jacobian(module_1_1<T>  &module, bbstate_idx<T> &in, 
00053                 bbstate_idx<T> &out) {
00054     forget_param_linear fp(2,0.5);
00055     idx_random(in.x, rrange_min, rrange_max); // randomize input for fprop
00056     module.fprop(in,out); // just to resize states
00057     module.forget(fp); // randomize parametes if there are any
00058     // clear all input and output
00059     in.clear();
00060     in.clear_dx();
00061     in.clear_ddx();
00062     out.clear();
00063     out.clear_dx();
00064     out.clear_ddx();
00065     idx_random(in.x, rrange_min, rrange_max); // randomize input for fprop
00066     // EDEBUG("in: " << in.x.str() << " out: " << out.x.str());
00067     get_jacobian_fprop(module, in, out, jac_fprop);
00068     get_jacobian_bprop(module, in, out, jac_bprop);
00069     // EDEBUG(" jac_fprop: " << jac_fprop.str()
00070     //    << " jac_bprop " << jac_bprop.str());
00071     return get_errs(jac_fprop,jac_bprop);
00072   }
00073 
00074   template <class T>
00075   idx<double> module_tester<T>::
00076   test_jacobian_param(parameter<bbstate_idx<T> > &p, module_1_1<T> &module,
00077                       bbstate_idx<T> &in, bbstate_idx<T> &out) {
00078     forget_param_linear fp(2,0);
00079     idx_random(in.x, rrange_min, rrange_max); // randomize input for fprop
00080     module.fprop(in,out); // just to resize states
00081     module.forget(fp); // randomize parametes if there are any
00082     // clear all input and output
00083     in.clear();
00084     in.clear_dx();
00085     in.clear_ddx();
00086     out.clear();
00087     out.clear_dx();
00088     out.clear_ddx();
00089     idx_random(p.x, rrange_min, rrange_max); // randomize input for fprop
00090     idx_random(in.x, rrange_min, rrange_max);
00091     get_jacobian_fprop_param(p, module, in, out, jac_pfprop);
00092     in.clear_dx();
00093     get_jacobian_bprop_param(p, module, in, out, jac_pbprop);
00094     return get_errs(jac_pfprop, jac_pbprop);
00095   }
00096 
00097 
00098   template <class T>
00099   idx<double> module_tester<T>::
00100   test_hessian(module_1_1<T>  &module, bbstate_idx<T> &in, 
00101                bbstate_idx<T> &out) {
00102     forget_param_linear fp(2,0.5);
00103     idx_random(in.x, rrange_min, rrange_max); // randomize input for fprop
00104     module.fprop(in,out); // just to resize states
00105     module.forget(fp); // randomize parametes if there are any
00106     // clear all input and output
00107     in.clear();
00108     in.clear_dx();
00109     in.clear_ddx();
00110     out.clear();
00111     out.clear_dx();
00112     out.clear_ddx();
00113     idx_random(in.x, rrange_min, rrange_max); // randomize input for fprop
00114     get_hessian_fprop(module, in, out, hes_fprop);
00115     get_hessian_bprop(module, in, out, hes_bprop);
00116     return get_errs(hes_fprop, hes_bprop);
00117   }
00118 
00119   template <class T>
00120   idx<double> module_tester<T>::
00121   test_hessian_param(parameter<bbstate_idx<T> > &p, module_1_1<T> &module,
00122                      bbstate_idx<T> &in, bbstate_idx<T> &out) {
00123     forget_param_linear fp(2,0);
00124     idx_random(in.x, rrange_min, rrange_max); // randomize input for fprop
00125     module.fprop(in,out); // just to resize states
00126     module.forget(fp); // randomize parametes if there are any
00127     // clear all input and output
00128     in.clear();
00129     in.clear_dx();
00130     in.clear_ddx();
00131     out.clear();
00132     out.clear_dx();
00133     out.clear_ddx();
00134     idx_random(p.x, rrange_min, rrange_max); // randomize input for fprop
00135     idx_random(in.x, rrange_min, rrange_max);
00136     get_hessian_fprop_param(p, module, in, out, hes_pfprop);
00137     in.clear_dx();
00138     get_hessian_bprop_param(p, module, in, out, hes_pbprop);
00139     return get_errs(hes_pfprop, hes_pbprop);
00140   }
00141 
00142   template <class T>
00143   double module_tester<T>::get_acc_thres() const {
00144     return acc_thres;
00145   }
00146 
00147   template <class T>
00148   void module_tester<T>::set_acc_thres(double acc_thres_) {
00149     acc_thres = acc_thres_;
00150   }
00151 
00152   template <class T>
00153   T module_tester<T>::get_rrange() const {
00154     return rrange_max;
00155   }
00156 
00157   template <class T>
00158   void module_tester<T>::set_rrange(T rrange) {
00159     rrange_min = -rrange;
00160     rrange_max = rrange;
00161   }
00162 
00163   template <class T>
00164   FILE* module_tester<T>::get_out() const {
00165     return out;
00166   }
00167 
00168   template <class T>
00169   void module_tester<T>::set_out(FILE* out) {
00170     this->out = out;
00171   }
00172   
00173   // protected members /////////////////////////////////////////////////////////
00174 
00175   template <class T>
00176   void module_tester<T>::
00177   get_jacobian_fprop(module_1_1<T> &module, bbstate_idx<T> &in,
00178                      bbstate_idx<T> &out, idx<T>& jac) {
00179     bbstate_idx<T> sina = in.make_copy(); //x-small
00180     bbstate_idx<T> sinb = in.make_copy(); //x+small
00181     bbstate_idx<T> souta = out.make_copy(); //f(x-small)
00182     bbstate_idx<T> soutb = out.make_copy(); //f(x+small)
00183     T small = 1e-6;
00184     int cnt = 0;
00185     // clear out jacobian matrix
00186     jac.resize(in.size(), out.size());
00187     idx_clear(jac);
00188     idx_aloop3(sx, in.x, T, sxa, sina.x, T, sxb, sinb.x, T) {
00189       idx_copy(in.x, sina.x);
00190       idx_copy(in.x, sinb.x);
00191       // perturb
00192       *sxa = *sx - small;
00193       *sxb = *sx + small;
00194       
00195       // idx_addc(in.x, -small, sina.x);
00196       // idx_addc(in.x, small, sinb.x);
00197       // perturb
00198       // T t0 = *sx;
00199       // T t1 = t0 - small;
00200       // T t2 = t0 + small;
00201       // double t3 = (double) t2 - (double) t1;
00202       // cout << "t0 " << t0 << " t1 " << t1 << " t2 " << t2 << " t3 " << t3 << endl;
00203       // *sxa = *sx - small;
00204       // cout << "sina: " << sina.x.gget() << " souta: " << souta.x.gget() <<endl;
00205       // cout << "sinb: " << sinb.x.gget() << " soutb: " << soutb.x.gget() <<endl;
00206       //      idx_sub(sinb.x, sina.x, soutb.x);
00207       // //      cout << "diff: " << soutb.x.gget() <<endl;
00208       // idx_clear(souta.x);
00209       // idx_clear(soutb.x);
00210       
00211       module.fprop(sina, souta);
00212       //      *sxb = *sxa + 2 * small;
00213       module.fprop(sinb, soutb);
00214       idx_sub(soutb.x, souta.x, soutb.x);
00215       // cout << "diff: " << soutb.x.gget() <<endl;
00216       idx<T> j = jac.select(0, cnt);
00217       idx_dotc(soutb.x, (T) (1.0 / (2 * small)), j);
00218       // cout << "1/2small: " << (T) (1.0 / (2 * small)) <<endl;
00219       // cout << "soutbx: " << soutb.x.gget() <<endl;
00220       // cout << "soutbx/2small: " << (soutb.x.gget() / (2 * small)) <<endl;
00221       // cout << "jac: " << (T) jac.gget() << endl;
00222       cnt++;
00223     }
00224   }
00225 
00226   template <class T>
00227   void module_tester<T>::
00228   get_jacobian_fprop_param(parameter<bbstate_idx<T> > &p, module_1_1<T> &module,
00229                            bbstate_idx<T> &in, bbstate_idx<T> &out,
00230                            idx<T>& jac) {
00231     bbstate_idx<T> souta = out.make_copy(); //f(x-small)
00232     bbstate_idx<T> soutb = out.make_copy(); //f(x+small)
00233     T small = 1e-6;
00234     int cnt = 0;
00235     // clear out jacobian matrix
00236     idx_clear(jac);
00237     { idx_aloop1(px, p.x, T) {
00238         // perturb
00239         *px = *px - small;
00240         module.fprop(in, souta);
00241         *px = *px + 2*small;
00242         module.fprop(in, soutb);
00243         *px = *px - small;
00244         idx_sub(soutb.x,souta.x,soutb.x);
00245         idx<T> j = jac.select(0,cnt);
00246         idx_dotc(soutb.x,1.0/(2*small),j);
00247         cnt++;
00248       }}
00249   }
00250 
00251   template <class T>
00252   void module_tester<T>::
00253   get_jacobian_bprop(module_1_1<T> &module, bbstate_idx<T> &in,
00254                      bbstate_idx<T> &out, idx<T>& jac) {
00255     jac.resize(in.size(), out.size());
00256     idx_clear(jac);
00257     int cnt = 0;
00258     idx_aloop1(dx, out.dx,T) {
00259       idx_clear(out.dx);
00260       idx_clear(in.dx);
00261       *dx = (T) 1.0;
00262       module.bprop(in, out);
00263       idx<T> j = jac.select(1, cnt);
00264       idx_copy(in.dx, j);
00265       cnt++;
00266     }
00267     //cout << "jac bprop: " << (T) jac.gget() << endl;
00268   }
00269 
00270   template <class T>
00271   void module_tester<T>::
00272   get_jacobian_bprop_param(parameter<bbstate_idx<T> > &p, module_1_1<T> &module,
00273                            bbstate_idx<T> &in, bbstate_idx<T> &out,
00274                            idx<T>& jac) {
00275     eblerror("not implemented");
00276   }
00277 
00278   template <class T>
00279   void module_tester<T>::
00280   get_hessian_fprop(module_1_1<T> &module, bbstate_idx<T> &in,
00281                     bbstate_idx<T> &out, idx<T> &jac) {
00282     bbstate_idx<T> sina = in.make_copy(); //x-small
00283     bbstate_idx<T> sinb = in.make_copy(); //x+small
00284     bbstate_idx<T> souta = out.make_copy(); //f(x-small)
00285     bbstate_idx<T> soutb = out.make_copy(); //f(x+small)
00286     double small = 1e-6;
00287     int cnt = 0;
00288     // clear out hessian matrix
00289     jac.resize(in.size(), out.size());
00290     idx_clear(jac);
00291     idx_aloop3(sx, in.x, T, sxa, sina.x, T, sxb, sinb.x, T) {
00292       idx_copy(in.x, sina.x);
00293       idx_copy(in.x, sinb.x);
00294       // perturb
00295       *sxa = *sx - small;
00296       *sxb = *sx + small;
00297       module.fprop(sina, souta);
00298       module.fprop(sinb, soutb);
00299       idx<T> ad(souta.x.get_idxdim());
00300       idx<T> dot(souta.x.get_idxdim());
00301       idx<T> sub(souta.x.get_idxdim());
00302       idx_add(souta.x, soutb.x, ad);
00303       idx_dotc(out.x, 2, dot);
00304       idx_sub(ad, dot, sub);
00305       idx<T> j = jac.select(0, cnt);
00306       idx_dotc(sub, 1.0 / small, j);
00307       cnt++;
00308     }
00309   }
00310 
00311   template <class T>
00312   void module_tester<T>::
00313   get_hessian_fprop_param(parameter<bbstate_idx<T> > &p, module_1_1<T> &module,
00314                           bbstate_idx<T> &in, bbstate_idx<T> &out, idx<T>& jac){
00315     bbstate_idx<T> souta = out.make_copy(); //f(x-small)
00316     bbstate_idx<T> soutb = out.make_copy(); //f(x+small)
00317     double small = 1e-6;
00318     int cnt = 0;
00319     // clear out hessian matrix
00320     idx_clear(jac);
00321     { idx_aloop1(px, p.x, T) {
00322         // perturb
00323         *px = *px - small;
00324         module.fprop(in, souta);
00325         *px = *px + 2*small;
00326         module.fprop(in, soutb);
00327         *px = *px - small;
00328         idx_sub(soutb.x,souta.x,soutb.x);
00329         idx<T> j = jac.select(0,cnt);
00330         idx_dotc(soutb.x,1.0/(2*small),j);
00331         cnt++;
00332       }}
00333   }
00334 
00335   template <class T>
00336   void module_tester<T>::
00337   get_hessian_bprop(module_1_1<T> &module, bbstate_idx<T> &in,
00338                     bbstate_idx<T> &out, idx<T>& jac) {
00339     jac.resize(in.size(), out.size());
00340     idx_clear(jac);
00341 //     module.fprop(in, out);
00342 //     module.bprop(in, out);
00343 //     module.bbprop(in, out);
00344 //     idx_copy(in.ddx, jac);
00345 
00346     int cnt = 0;
00347     idx_aloop1(ddx, out.ddx,T) {
00348       idx_clear(out.ddx);
00349       idx_clear(in.ddx);
00350       //      *ddx = 1.0;
00351       module.bbprop(in, out);
00352       idx<T> j = jac.select(1, cnt);
00353       idx_copy(in.ddx, j);
00354       cnt++;
00355     }
00356   }
00357 
00358   template <class T>
00359   void module_tester<T>::
00360   get_hessian_bprop_param(parameter<bbstate_idx<T> > &p, module_1_1<T> &module,
00361                           bbstate_idx<T> &in, bbstate_idx<T> &out, idx<T>& jac){
00362     eblerror("not implemented");
00363   }
00364 
00365   template <class T>
00366   idx<double> module_tester<T>::get_errs(idx<T>& a, idx<T>& b) {
00367     double maxdist;
00368     // max distance
00369     idx_sub(a,b,a);
00370     idx_abs(a,a);
00371     double totdist = idx_sum(a);
00372     maxdist = (double) idx_max(a);
00373     idx<double> errs(2);
00374     errs.set(maxdist, 0);
00375     errs.set(totdist, 1);
00376     return errs;
00377   }
00378 
00379   template <class T>
00380   void module_tester<T>::report_err(idx<T>& a, idx<T>& b, const char* msg) {
00381     idx<double> errs = get_errs(a, b);
00382     stringstream ss(stringstream::in | stringstream::out);
00383     // report results
00384     ss << "Max " << msg << " distance";
00385     fprintf(this->out,"%-40s = %-15g %15s\n",ss.str().c_str(), errs.get(0),
00386             ((errs.get(0) < this->acc_thres)?"OK":"NOT OK"));
00387     ss.str("");
00388     ss << "Total " << msg << "distance";
00389     fprintf(this->out,"%-40s = %-15g %15s\n",ss.str().c_str(), errs.get(1),
00390             ((errs.get(1) < this->acc_thres)?"OK":"NOT OK"));
00391     fflush(this->out);
00392   }
00393 
00395 
00396   template <class T>
00397   void Jacobian_tester<T>::test(module_1_1<T> &module) {
00398     int insize = 16;
00399     bbstate_idx<T> in(insize, 1, 1);
00400     bbstate_idx<T> out(insize, 1, 1);
00401 
00402     //init
00403     dseed(2);  // 2 is chosen randomly... feel free to change it
00404     module.fprop(in, out); // used to resize the outputs
00405     { idx_bloop1( i, in.x, T)
00406         { idx_bloop1 (ii, i, T)
00407             { idx_bloop1( iii, ii, T)
00408                 { iii.set(drand(2)); }
00409             }
00410         }
00411     }
00412     { idx_bloop1( o, out.x, T)
00413         { idx_bloop1 (oo, o, T)
00414             { idx_bloop1( ooo, oo, T)
00415                 { ooo.set(drand(2)); }
00416             }
00417         }
00418     }
00419 
00420     // check the Jacobian
00421     int ndim_in = in.x.nelements();
00422     int ndim_out = in.x.nelements();
00423     // used to store the jacobian calculated via bprop
00424     idx<T> jac_fprop(ndim_in, ndim_out); 
00425     //  used to store the jacobian calculated via prturbations
00426     idx<T> jac_bprop(ndim_in, ndim_out); 
00427 
00428     // creation of jac_fprop
00429     module.fprop(in, out);
00430     int cnt = 0;
00431     { idx_bloop1(o, out.x, T)
00432         { idx_bloop1(oo, o, T)
00433             { idx_bloop1(ooo, oo, T)
00434                 {
00435                   out.clear_dx();
00436                   in.clear_dx();
00437                   ooo.set(1);
00438                   module.bprop(in, out);
00439                   idx<T> bla = jac_bprop.select(1, cnt);
00440                   idx_copy(in.dx, bla);
00441                   cnt++;
00442                 }
00443             }
00444         }
00445     }
00446 
00447     // creation of jac_bprop
00448     cnt = 0;
00449     double small = pow(10.0, -6);
00450     bbstate_idx<T> in1(in.x.dim(0), in.x.dim(1), in.x.dim(2));
00451     bbstate_idx<T> in2(in.x.dim(0), in.x.dim(1), in.x.dim(2));
00452     bbstate_idx<T> out1(1, 1, 1);
00453     bbstate_idx<T> out2(1, 1, 1);
00454     for(int d1 = 0; d1 < in.x.dim(0); d1++){
00455       for(int d2 = 0; d2 < in.x.dim(1); d2++){
00456         for(int d3 = 0; d3 < in.x.dim(2); d3++){
00457           idx_copy(in.x, in1.x);
00458           idx_copy(in.x, in2.x);
00459           in1.x.set(in1.x.get( d1, d2, d3) + small, d1, d2, d3);
00460           in2.x.set(in2.x.get( d1, d2, d3) - small, d1, d2, d3);
00461           module.fprop(in1, out1);
00462           module.fprop(in2, out2);
00463           idx<T> sub(new srg<T>(), out1.x.spec);
00464           idx<T> dot(new srg<T>(), out1.x.spec);
00465           idx_sub(out1.x, out2.x, sub);
00466           idx_dotc(sub, 0.5/small, dot);
00467           idx<T> bla2 = jac_fprop.select(0, cnt);
00468           idx_copy(dot, bla2);
00469           cnt++;
00470         }
00471       }
00472     }
00473 
00474     // comparison
00475     printf("Jacobian error: %8.7e\n", idx_sqrdist(jac_fprop, jac_bprop));
00476   }
00477 
00479 
00480   template <class T>
00481   void Bbprop_tester<T>::test(module_1_1<T> &module){
00482 
00483     int insize = 16;
00484     bbstate_idx<T> in(insize, 1, 1);
00485     bbstate_idx<T> out(insize, 1, 1);
00486 
00487     //init
00488     dseed(2);  // 2 is chosen randomly... feel free to change it
00489     module.fprop(in, out); // used to resize the outputs
00490     { idx_bloop1( i, in.x, T)
00491         { idx_bloop1 (ii, i, T)
00492             { idx_bloop1( iii, ii, T)
00493                 { iii.set(drand(2)); }
00494             }
00495         }
00496     }
00497     { idx_bloop1( o, out.x, T)
00498         { idx_bloop1 (oo, o, T)
00499             { idx_bloop1( ooo, oo, T)
00500                 { ooo.set(drand(2)); }
00501             }
00502         }
00503     }
00504 
00505     module.fprop(in, out);
00506     module.bprop(in, out);
00507     module.bbprop(in, out);
00508 
00509     // used to store the bbprop calculated via perturbation
00510     idx<T> bbprop_p(in.x.dim(0), in.x.dim(1), in.x.dim(2)); 
00511 
00512     // creation of bbprop_p
00513     int cnt = 0;
00514     double small = pow(10.0, -6);
00515     bbstate_idx<T> in1(in.x.dim(0), in.x.dim(1), in.x.dim(2));
00516     bbstate_idx<T> in2(in.x.dim(0), in.x.dim(1), in.x.dim(2));
00517     bbstate_idx<T> out1( 1, 1, 1);
00518     bbstate_idx<T> out2( 1, 1, 1);
00519     for(int d1 = 0; d1 < in.x.dim(0); d1++){
00520       for(int d2 = 0; d2 < in.x.dim(1); d2++){
00521         for(int d3 = 0; d3 < in.x.dim(2); d3++){
00522           idx_copy(in.x, in1.x);
00523           idx_copy(in.x, in2.x);
00524           in1.x.set(in1.x.get( d1, d2, d3) + small, d1, d2, d3);
00525           in2.x.set(in2.x.get( d1, d2, d3) - small, d1, d2, d3);
00526           module.fprop(in1, out1);
00527           module.fprop(in2, out2);
00528           // here we calculate a in aX²+bX+c as a model for the 3 points 
00529           // calculated via
00530           // fprop(...), fprop(...+small) and fprop(...-small). the second 
00531           // derivative is then 2*a
00532           idx<T> ad(new srg<T>(), out1.x.spec);
00533           idx<T> sub(new srg<T>(), out1.x.spec);
00534           idx<T> dot(new srg<T>(), out1.x.spec);
00535           idx<T> dot2(new srg<T>(), out1.x.spec);
00536           idx_add(out1.x, out2.x, ad);
00537           idx_dotc(out.x, 2, dot);
00538           idx_sub(ad, dot, sub);
00539           idx_dotc(sub, 1/small, dot2);
00540           bbprop_p.set(dot2.get( d1, d2, d3), d1, d2, d3);
00541           cnt++;
00542         }
00543       }
00544     }
00545 
00546     // comparison
00547     printf("bbprop error: %8.7e \n", idx_sqrdist(in.ddx, bbprop_p));
00548   }
00549 
00551 
00552   template <class T>
00553   void Bprop_tester<T>::test(module_1_1<T> &module){
00554 
00555     int insize = 16;
00556     bbstate_idx<T> in(insize, 1, 1);
00557     bbstate_idx<T> out(insize, 1, 1);
00558 
00559     //init
00560     dseed(2);  // 2 is chosen randomly... feel free to change it
00561     module.fprop(in, out); // used to resize the outputs
00562     { idx_bloop1( i, in.x, T)
00563         { idx_bloop1 (ii, i, T)
00564             { idx_bloop1( iii, ii, T)
00565                 { iii.set(drand(2)); }
00566             }
00567         }
00568     }
00569     { idx_bloop1( o, out.x, T)
00570         { idx_bloop1 (oo, o, T)
00571             { idx_bloop1( ooo, oo, T)
00572                 { ooo.set(drand(2)); }
00573             }
00574         }
00575     }
00576 
00577     // used to store the bbprop calculated via perturbation
00578     idx<T> bprop_p(in.x.dim(0), in.x.dim(1), in.x.dim(2)); 
00579 
00580     // creation of bprop_p
00581     int cnt = 0;
00582     double small = pow(10.0, -6);
00583     bbstate_idx<T> in1(in.x.dim(0), in.x.dim(1), in.x.dim(2));
00584     bbstate_idx<T> in2(in.x.dim(0), in.x.dim(1), in.x.dim(2));
00585     bbstate_idx<T> out1(1, 1, 1);
00586     bbstate_idx<T> out2(1, 1, 1);
00587     for(int d1 = 0; d1 < in.x.dim(0); d1++){
00588       for(int d2 = 0; d2 < in.x.dim(1); d2++){
00589         for(int d3 = 0; d3 < in.x.dim(2); d3++){
00590           idx_copy(in.x, in1.x);
00591           idx_copy(in.x, in2.x);
00592           in1.x.set(in1.x.get( d1, d2, d3) + small, d1, d2, d3);
00593           in2.x.set(in2.x.get( d1, d2, d3) - small, d1, d2, d3);
00594           module.fprop(in1, out1);
00595           module.fprop(in2, out2);
00596 
00597           idx<T> sub(new srg<T>(), out1.x.spec);
00598           idx<T> dot(new srg<T>(), out1.x.spec);
00599           idx_sub(out1.x, out2.x, sub);
00600           idx_dotc(sub, 0.5/small, dot);
00601           bprop_p.set(dot.get( d1, d2, d3), d1, d2, d3);
00602           cnt++;
00603         }
00604       }
00605     }
00606 
00607     printf("Bprop error : %8.7e \n", idx_sqrdist(in.dx, bprop_p));
00608   }
00609 
00610 } // end namespace ebl